summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.circleci/config.yml68
-rw-r--r--.circleci/qt-installer-script.js75
-rw-r--r--.gitignore11
-rw-r--r--BUILD.md419
-rw-r--r--CHANGELOG.md2
-rw-r--r--MANIFEST.in13
-rw-r--r--README.md2
-rw-r--r--RELEASE.md234
-rw-r--r--apparmor/abstractions/onionshare29
-rw-r--r--apparmor/local/usr.bin.onionshare2
-rw-r--r--apparmor/local/usr.bin.onionshare-gui2
-rw-r--r--apparmor/usr.bin.onionshare10
-rw-r--r--apparmor/usr.bin.onionshare-gui28
-rwxr-xr-xbuild-source.sh (renamed from install/build_source.sh)5
-rw-r--r--cli/.circleci/config.yml38
-rw-r--r--cli/README.md68
-rw-r--r--cli/onionshare_cli/__init__.py (renamed from onionshare/__init__.py)16
-rw-r--r--cli/onionshare_cli/common.py (renamed from onionshare/common.py)82
-rw-r--r--cli/onionshare_cli/mode_settings.py (renamed from onionshare/mode_settings.py)2
-rw-r--r--cli/onionshare_cli/onion.py (renamed from onionshare/onion.py)82
-rw-r--r--cli/onionshare_cli/onionshare.py (renamed from onionshare/onionshare.py)4
-rw-r--r--cli/onionshare_cli/resources/static/css/style.css (renamed from share/static/css/style.css)0
-rw-r--r--cli/onionshare_cli/resources/static/img/ajax.gif (renamed from share/static/img/ajax.gif)bin847 -> 847 bytes
-rw-r--r--cli/onionshare_cli/resources/static/img/favicon.ico (renamed from share/static/img/favicon.ico)bin4286 -> 4286 bytes
-rw-r--r--cli/onionshare_cli/resources/static/img/logo.png (renamed from share/images/logo.png)bin3824 -> 3824 bytes
-rw-r--r--cli/onionshare_cli/resources/static/img/logo_large.png (renamed from share/static/img/logo_large.png)bin9663 -> 9663 bytes
-rw-r--r--cli/onionshare_cli/resources/static/img/web_file.png (renamed from share/static/img/web_file.png)bin251 -> 251 bytes
-rw-r--r--cli/onionshare_cli/resources/static/img/web_folder.png (renamed from share/static/img/web_folder.png)bin338 -> 338 bytes
-rw-r--r--cli/onionshare_cli/resources/static/js/chat.js (renamed from share/static/js/chat.js)0
-rw-r--r--cli/onionshare_cli/resources/static/js/jquery-3.5.1.min.js (renamed from share/static/js/jquery-3.5.1.min.js)0
-rw-r--r--cli/onionshare_cli/resources/static/js/receive.js (renamed from share/static/js/receive.js)0
-rw-r--r--cli/onionshare_cli/resources/static/js/send.js (renamed from share/static/js/send.js)0
-rw-r--r--cli/onionshare_cli/resources/static/js/socket.io.min.js (renamed from share/static/js/socket.io.min.js)0
-rw-r--r--cli/onionshare_cli/resources/templates/401.html (renamed from share/templates/401.html)0
-rw-r--r--cli/onionshare_cli/resources/templates/403.html (renamed from share/templates/403.html)0
-rw-r--r--cli/onionshare_cli/resources/templates/404.html (renamed from share/templates/404.html)0
-rw-r--r--cli/onionshare_cli/resources/templates/405.html (renamed from share/templates/405.html)0
-rw-r--r--cli/onionshare_cli/resources/templates/chat.html (renamed from share/templates/chat.html)0
-rw-r--r--cli/onionshare_cli/resources/templates/denied.html (renamed from share/templates/denied.html)0
-rw-r--r--cli/onionshare_cli/resources/templates/listing.html (renamed from share/templates/listing.html)0
-rw-r--r--cli/onionshare_cli/resources/templates/receive.html (renamed from share/templates/receive.html)0
-rw-r--r--cli/onionshare_cli/resources/templates/send.html (renamed from share/templates/send.html)0
-rw-r--r--cli/onionshare_cli/resources/templates/thankyou.html (renamed from share/templates/thankyou.html)0
-rw-r--r--cli/onionshare_cli/resources/torrc_template (renamed from share/torrc_template)0
-rw-r--r--cli/onionshare_cli/resources/torrc_template-meek_lite_amazon (renamed from share/torrc_template-meek_lite_amazon)0
-rw-r--r--cli/onionshare_cli/resources/torrc_template-meek_lite_azure (renamed from share/torrc_template-meek_lite_azure)0
-rw-r--r--cli/onionshare_cli/resources/torrc_template-obfs4 (renamed from share/torrc_template-obfs4)0
-rw-r--r--cli/onionshare_cli/resources/version.txt1
-rw-r--r--cli/onionshare_cli/resources/wordlist.txt (renamed from share/wordlist.txt)0
-rw-r--r--cli/onionshare_cli/settings.py (renamed from onionshare/settings.py)2
-rw-r--r--cli/onionshare_cli/web/__init__.py (renamed from onionshare/web/__init__.py)0
-rw-r--r--cli/onionshare_cli/web/chat_mode.py (renamed from onionshare/web/chat_mode.py)0
-rw-r--r--cli/onionshare_cli/web/receive_mode.py (renamed from onionshare/web/receive_mode.py)4
-rw-r--r--cli/onionshare_cli/web/send_base_mode.py (renamed from onionshare/web/send_base_mode.py)2
-rw-r--r--cli/onionshare_cli/web/share_mode.py (renamed from onionshare/web/share_mode.py)1
-rw-r--r--cli/onionshare_cli/web/web.py (renamed from onionshare/web/web.py)2
-rw-r--r--cli/onionshare_cli/web/website_mode.py (renamed from onionshare/web/website_mode.py)1
-rw-r--r--cli/poetry.lock603
-rw-r--r--cli/pyproject.toml (renamed from pyproject.toml)58
-rw-r--r--cli/setup.py70
-rw-r--r--cli/tests/__init__.py (renamed from tests/__init__.py)0
-rw-r--r--cli/tests/conftest.py (renamed from tests/conftest.py)13
-rw-r--r--cli/tests/pytest.ini (renamed from tests/pytest.ini)0
-rw-r--r--cli/tests/test_cli.py (renamed from tests/test_cli.py)10
-rw-r--r--cli/tests/test_cli_common.py (renamed from tests/test_cli_common.py)32
-rw-r--r--cli/tests/test_cli_settings.py (renamed from tests/test_cli_settings.py)4
-rw-r--r--cli/tests/test_cli_web.py (renamed from tests/test_cli_web.py)10
-rw-r--r--desktop/README.md113
-rwxr-xr-xdesktop/check_lacked_trans.py (renamed from install/check_lacked_trans.py)0
-rwxr-xr-xdesktop/package/linux/build-appimage.py47
-rw-r--r--desktop/package/linux/org.onionshare.OnionShare.desktop (renamed from install/org.onionshare.OnionShare.desktop)0
-rw-r--r--desktop/package/macos/ChildEntitlements.plist (renamed from install/macos_sandbox/child.plist)0
-rw-r--r--desktop/package/macos/Entitlements.plist (renamed from install/macos_sandbox/parent.plist)4
-rwxr-xr-xdesktop/package/macos/build.py131
-rw-r--r--desktop/package/windows/build.py66
-rw-r--r--desktop/pyproject.toml42
-rw-r--r--desktop/screenshots/appdata-onionshare-receive-client.png (renamed from screenshots/appdata-onionshare-receive-client.png)bin361337 -> 361337 bytes
-rw-r--r--desktop/screenshots/appdata-onionshare-receive-server.png (renamed from screenshots/appdata-onionshare-receive-server.png)bin340924 -> 340924 bytes
-rw-r--r--desktop/screenshots/appdata-onionshare-share-client.png (renamed from screenshots/appdata-onionshare-share-client.png)bin372511 -> 372511 bytes
-rw-r--r--desktop/screenshots/appdata-onionshare-share-server.png (renamed from screenshots/appdata-onionshare-share-server.png)bin526914 -> 526914 bytes
-rw-r--r--desktop/screenshots/onionshare-receive-client.png (renamed from screenshots/onionshare-receive-client.png)bin589481 -> 589481 bytes
-rw-r--r--desktop/screenshots/onionshare-receive-server.png (renamed from screenshots/onionshare-receive-server.png)bin569260 -> 569260 bytes
-rw-r--r--desktop/screenshots/onionshare-share-client.png (renamed from screenshots/onionshare-share-client.png)bin43404 -> 43404 bytes
-rw-r--r--desktop/screenshots/onionshare-share-server.png (renamed from screenshots/onionshare-share-server.png)bin57758 -> 57758 bytes
-rw-r--r--desktop/screenshots/onionshare-website-server.png (renamed from screenshots/onionshare-website-server.png)bin148709 -> 148709 bytes
-rwxr-xr-x[-rw-r--r--]desktop/scripts/get-tor-osx.py (renamed from install/get-tor-osx.py)43
-rw-r--r--desktop/scripts/get-tor-windows.py (renamed from install/get-tor-windows.py)54
-rw-r--r--desktop/src/onionshare/__init__.py (renamed from onionshare_gui/__init__.py)8
-rw-r--r--[-rwxr-xr-x]desktop/src/onionshare/__main__.py (renamed from install/scripts/onionshare)7
-rw-r--r--desktop/src/onionshare/gui_common.py (renamed from onionshare_gui/gui_common.py)50
-rw-r--r--desktop/src/onionshare/main_window.py (renamed from onionshare_gui/main_window.py)27
-rw-r--r--desktop/src/onionshare/resources/__init__.py0
-rw-r--r--desktop/src/onionshare/resources/images/close_tab.png (renamed from share/images/close_tab.png)bin688 -> 688 bytes
-rw-r--r--desktop/src/onionshare/resources/images/file_delete.png (renamed from share/images/file_delete.png)bin182 -> 182 bytes
-rw-r--r--desktop/src/onionshare/resources/images/history_completed.png (renamed from share/images/history_completed.png)bin646 -> 646 bytes
-rw-r--r--desktop/src/onionshare/resources/images/history_completed_none.png (renamed from share/images/history_completed_none.png)bin437 -> 437 bytes
-rw-r--r--desktop/src/onionshare/resources/images/history_in_progress.png (renamed from share/images/history_in_progress.png)bin638 -> 638 bytes
-rw-r--r--desktop/src/onionshare/resources/images/history_in_progress_none.png (renamed from share/images/history_in_progress_none.png)bin412 -> 412 bytes
-rw-r--r--desktop/src/onionshare/resources/images/history_requests.png (renamed from share/images/history_requests.png)bin738 -> 738 bytes
-rw-r--r--desktop/src/onionshare/resources/images/history_requests_none.png (renamed from share/images/history_requests_none.png)bin754 -> 754 bytes
-rw-r--r--desktop/src/onionshare/resources/images/info.png (renamed from share/images/info.png)bin435 -> 435 bytes
-rw-r--r--desktop/src/onionshare/resources/images/logo.png (renamed from share/static/img/logo.png)bin3824 -> 3824 bytes
-rw-r--r--desktop/src/onionshare/resources/images/logo_grayscale.png (renamed from share/images/logo_grayscale.png)bin2258 -> 2258 bytes
-rw-r--r--desktop/src/onionshare/resources/images/logo_text.png (renamed from share/images/logo_text.png)bin3798 -> 3798 bytes
-rw-r--r--desktop/src/onionshare/resources/images/logo_transparent.png (renamed from share/images/logo_transparent.png)bin3740 -> 3740 bytes
-rw-r--r--desktop/src/onionshare/resources/images/mode_chat.png (renamed from share/images/mode_chat.png)bin27306 -> 27306 bytes
-rw-r--r--desktop/src/onionshare/resources/images/mode_chat.svg (renamed from share/images/mode_chat.svg)0
-rw-r--r--desktop/src/onionshare/resources/images/mode_new_tab_chat.png (renamed from share/images/mode_new_tab_chat.png)bin5213 -> 5213 bytes
-rw-r--r--desktop/src/onionshare/resources/images/mode_new_tab_receive.png (renamed from share/images/mode_new_tab_receive.png)bin6470 -> 6470 bytes
-rw-r--r--desktop/src/onionshare/resources/images/mode_new_tab_share.png (renamed from share/images/mode_new_tab_share.png)bin4485 -> 4485 bytes
-rw-r--r--desktop/src/onionshare/resources/images/mode_new_tab_website.png (renamed from share/images/mode_new_tab_website.png)bin3860 -> 3860 bytes
-rw-r--r--desktop/src/onionshare/resources/images/mode_receive.png (renamed from share/images/mode_receive.png)bin37288 -> 37288 bytes
-rw-r--r--desktop/src/onionshare/resources/images/mode_receive.svg (renamed from share/images/mode_receive.svg)0
-rw-r--r--desktop/src/onionshare/resources/images/mode_share.png (renamed from share/images/mode_share.png)bin9472 -> 9472 bytes
-rw-r--r--desktop/src/onionshare/resources/images/mode_share.svg (renamed from share/images/mode_share.svg)0
-rw-r--r--desktop/src/onionshare/resources/images/mode_website.png (renamed from share/images/mode_website.png)bin8126 -> 8126 bytes
-rw-r--r--desktop/src/onionshare/resources/images/mode_website.svg (renamed from share/images/mode_website.svg)0
-rw-r--r--desktop/src/onionshare/resources/images/open_folder.png (renamed from share/images/open_folder.png)bin221 -> 221 bytes
-rw-r--r--desktop/src/onionshare/resources/images/persistent_enabled.png (renamed from share/images/persistent_enabled.png)bin3398 -> 3398 bytes
-rw-r--r--desktop/src/onionshare/resources/images/receive_icon_toggle.png (renamed from share/images/receive_icon_toggle.png)bin380 -> 380 bytes
-rw-r--r--desktop/src/onionshare/resources/images/receive_icon_toggle_selected.png (renamed from share/images/receive_icon_toggle_selected.png)bin468 -> 468 bytes
-rw-r--r--desktop/src/onionshare/resources/images/receive_icon_transparent.png (renamed from share/images/receive_icon_transparent.png)bin2138 -> 2138 bytes
-rw-r--r--desktop/src/onionshare/resources/images/server_started.png (renamed from share/images/server_started.png)bin347 -> 347 bytes
-rw-r--r--desktop/src/onionshare/resources/images/server_stopped.png (renamed from share/images/server_stopped.png)bin342 -> 342 bytes
-rw-r--r--desktop/src/onionshare/resources/images/server_working.png (renamed from share/images/server_working.png)bin349 -> 349 bytes
-rw-r--r--desktop/src/onionshare/resources/images/settings.png (renamed from share/images/settings.png)bin1157 -> 1157 bytes
-rw-r--r--desktop/src/onionshare/resources/images/share_icon_toggle.png (renamed from share/images/share_icon_toggle.png)bin389 -> 389 bytes
-rw-r--r--desktop/src/onionshare/resources/images/share_icon_toggle_selected.png (renamed from share/images/share_icon_toggle_selected.png)bin473 -> 473 bytes
-rw-r--r--desktop/src/onionshare/resources/images/share_icon_transparent.png (renamed from share/images/share_icon_transparent.png)bin2096 -> 2096 bytes
-rw-r--r--desktop/src/onionshare/resources/locale/af.json (renamed from share/locale/af.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/am.json (renamed from share/locale/am.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/ar.json (renamed from share/locale/ar.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/bg.json (renamed from share/locale/bg.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/bn.json (renamed from share/locale/bn.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/ca.json (renamed from share/locale/ca.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/cs.json (renamed from share/locale/cs.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/da.json (renamed from share/locale/da.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/de.json (renamed from share/locale/de.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/el.json (renamed from share/locale/el.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/en.json (renamed from share/locale/en.json)12
-rw-r--r--desktop/src/onionshare/resources/locale/eo.json (renamed from share/locale/eo.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/es.json (renamed from share/locale/es.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/fa.json (renamed from share/locale/fa.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/fi.json (renamed from share/locale/fi.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/fr.json (renamed from share/locale/fr.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/ga.json (renamed from share/locale/ga.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/gu.json (renamed from share/locale/gu.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/he.json (renamed from share/locale/he.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/hi.json (renamed from share/locale/hi.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/hr.json (renamed from share/locale/hr.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/hu.json (renamed from share/locale/hu.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/id.json (renamed from share/locale/id.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/is.json (renamed from share/locale/is.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/it.json (renamed from share/locale/it.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/ja.json (renamed from share/locale/ja.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/ka.json (renamed from share/locale/ka.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/km.json (renamed from share/locale/km.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/ko.json (renamed from share/locale/ko.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/lg.json (renamed from share/locale/lg.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/lt.json (renamed from share/locale/lt.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/mk.json (renamed from share/locale/mk.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/ms.json (renamed from share/locale/ms.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/nb_NO.json (renamed from share/locale/nb_NO.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/nl.json (renamed from share/locale/nl.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/pa.json (renamed from share/locale/pa.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/pl.json (renamed from share/locale/pl.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/pt_BR.json (renamed from share/locale/pt_BR.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/pt_PT.json (renamed from share/locale/pt_PT.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/ro.json (renamed from share/locale/ro.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/ru.json (renamed from share/locale/ru.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/sk.json (renamed from share/locale/sk.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/sl.json (renamed from share/locale/sl.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/sn.json (renamed from share/locale/sn.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/sr_Latn.json (renamed from share/locale/sr_Latn.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/sv.json (renamed from share/locale/sv.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/sw.json (renamed from share/locale/sw.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/te.json (renamed from share/locale/te.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/tr.json (renamed from share/locale/tr.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/uk.json (renamed from share/locale/uk.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/wo.json (renamed from share/locale/wo.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/yo.json (renamed from share/locale/yo.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/zh_Hans.json (renamed from share/locale/zh_Hans.json)0
-rw-r--r--desktop/src/onionshare/resources/locale/zh_Hant.json (renamed from share/locale/zh_Hant.json)0
-rw-r--r--desktop/src/onionshare/resources/onionshare-128.pngbin0 -> 12788 bytes
-rw-r--r--desktop/src/onionshare/resources/onionshare-16.pngbin0 -> 2437 bytes
-rw-r--r--desktop/src/onionshare/resources/onionshare-256.pngbin0 -> 19034 bytes
-rw-r--r--desktop/src/onionshare/resources/onionshare-32.pngbin0 -> 4051 bytes
-rw-r--r--desktop/src/onionshare/resources/onionshare-512.png (renamed from install/org.onionshare.OnionShare.png)bin24613 -> 24613 bytes
-rw-r--r--desktop/src/onionshare/resources/onionshare-64.pngbin0 -> 8486 bytes
-rw-r--r--desktop/src/onionshare/resources/onionshare.icns (renamed from install/onionshare.icns)bin34168 -> 34168 bytes
-rw-r--r--desktop/src/onionshare/resources/onionshare.ico (renamed from install/onionshare.ico)bin15086 -> 15086 bytes
-rw-r--r--desktop/src/onionshare/resources/onionshare.pngbin0 -> 24613 bytes
-rw-r--r--desktop/src/onionshare/settings_dialog.py (renamed from onionshare_gui/settings_dialog.py)29
-rw-r--r--desktop/src/onionshare/strings.py (renamed from onionshare/strings.py)3
-rw-r--r--desktop/src/onionshare/tab/__init__.py (renamed from onionshare_gui/tab/__init__.py)0
-rw-r--r--desktop/src/onionshare/tab/mode/__init__.py (renamed from onionshare_gui/tab/mode/__init__.py)22
-rw-r--r--desktop/src/onionshare/tab/mode/chat_mode/__init__.py (renamed from onionshare_gui/tab/mode/chat_mode/__init__.py)17
-rw-r--r--desktop/src/onionshare/tab/mode/file_selection.py (renamed from onionshare_gui/tab/mode/file_selection.py)14
-rw-r--r--desktop/src/onionshare/tab/mode/history.py (renamed from onionshare_gui/tab/mode/history.py)19
-rw-r--r--desktop/src/onionshare/tab/mode/mode_settings_widget.py (renamed from onionshare_gui/tab/mode/mode_settings_widget.py)6
-rw-r--r--desktop/src/onionshare/tab/mode/receive_mode/__init__.py (renamed from onionshare_gui/tab/mode/receive_mode/__init__.py)18
-rw-r--r--desktop/src/onionshare/tab/mode/share_mode/__init__.py (renamed from onionshare_gui/tab/mode/share_mode/__init__.py)21
-rw-r--r--desktop/src/onionshare/tab/mode/share_mode/threads.py (renamed from onionshare_gui/tab/mode/share_mode/threads.py)6
-rw-r--r--desktop/src/onionshare/tab/mode/website_mode/__init__.py (renamed from onionshare_gui/tab/mode/website_mode/__init__.py)23
-rw-r--r--desktop/src/onionshare/tab/server_status.py (renamed from onionshare_gui/tab/server_status.py)36
-rw-r--r--desktop/src/onionshare/tab/tab.py (renamed from onionshare_gui/tab/tab.py)30
-rw-r--r--desktop/src/onionshare/tab_widget.py (renamed from onionshare_gui/tab_widget.py)49
-rw-r--r--desktop/src/onionshare/threads.py (renamed from onionshare_gui/threads.py)25
-rw-r--r--desktop/src/onionshare/tor_connection_dialog.py (renamed from onionshare_gui/tor_connection_dialog.py)21
-rw-r--r--desktop/src/onionshare/update_checker.py (renamed from onionshare_gui/update_checker.py)24
-rw-r--r--desktop/src/onionshare/widgets.py (renamed from onionshare_gui/widgets.py)14
-rw-r--r--desktop/src/org.onionshare.OnionShare.appdata.xml (renamed from install/org.onionshare.OnionShare.appdata.xml)2
-rw-r--r--desktop/src/setup.py72
-rw-r--r--desktop/tests/__init__.py0
-rw-r--r--desktop/tests/conftest.py222
-rw-r--r--desktop/tests/gui_base_test.py (renamed from tests/gui_base_test.py)32
-rw-r--r--desktop/tests/run.bat4
-rwxr-xr-xdesktop/tests/run.sh5
-rw-r--r--desktop/tests/test_gui_receive.py (renamed from tests/test_gui_receive.py)14
-rw-r--r--desktop/tests/test_gui_share.py (renamed from tests/test_gui_share.py)38
-rw-r--r--desktop/tests/test_gui_tabs.py (renamed from tests/test_gui_tabs.py)21
-rw-r--r--desktop/tests/test_gui_website.py (renamed from tests/test_gui_website.py)8
-rwxr-xr-xdev_scripts/onionshare30
-rwxr-xr-xdev_scripts/onionshare-gui30
-rw-r--r--docs/pyproject.toml2
-rw-r--r--docs/source/conf.py2
-rw-r--r--docs/source/install.rst20
-rw-r--r--flatpak/org.onionshare.OnionShare.yaml321
-rw-r--r--git-hooks/README.md3
-rwxr-xr-xgit-hooks/pre-push4
-rwxr-xr-xinstall/build_deb.sh25
-rw-r--r--install/build_exe.bat17
-rwxr-xr-xinstall/build_osx.sh55
-rwxr-xr-xinstall/build_rpm.sh17
-rw-r--r--install/onionshare.nsi111
-rw-r--r--install/onionshare80.xpm257
-rw-r--r--install/org.onionshare.OnionShare.svg2154
-rwxr-xr-xinstall/ppa_release.sh18
-rw-r--r--install/pyinstaller.spec67
-rwxr-xr-xinstall/scripts/onionshare-gui23
-rw-r--r--install/scripts/onionshare-nautilus.py105
-rw-r--r--install/scripts/onionshare-pyinstaller47
-rw-r--r--licenses/license-jquery.txt (renamed from install/licenses/license-jquery.txt)0
-rw-r--r--licenses/license-obfs4.txt (renamed from install/licenses/license-obfs4.txt)0
-rw-r--r--licenses/license-onionshare.txt (renamed from install/licenses/license-onionshare.txt)0
-rw-r--r--licenses/license-tor.txt (renamed from install/licenses/license-tor.txt)0
-rw-r--r--licenses/readme.txt (renamed from install/licenses/readme.txt)0
-rw-r--r--poetry.lock956
-rw-r--r--setup.cfg2
-rw-r--r--setup.py98
-rw-r--r--share/version.txt1
-rw-r--r--snap/snapcraft.yaml147
-rw-r--r--stdeb.cfg6
-rw-r--r--tests/run.bat9
-rwxr-xr-xtests/run.sh26
-rw-r--r--tests/test_cli_strings.py46
256 files changed, 2730 insertions, 5273 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 67d8ab0e..3be131b3 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -8,14 +8,13 @@ workflows:
version: 2
test:
jobs:
- - test-3.6
- - test-3.7
- - test-3.8
+ - test-cli
+ - test-gui
jobs:
- test-3.6: &test-template
+ test-cli:
docker:
- - image: circleci/python:3.6-buster
+ - image: circleci/python:3.8-buster
working_directory: ~/repo
@@ -23,42 +22,45 @@ jobs:
- checkout
- run:
- name: Install Qt5 binaries
- command: |
- sudo apt-get update
- sudo apt-get install xvfb libdbus-1-3 libxkbcommon-x11-0 libxkbcommon-x11-dev
- cd ~/
- wget https://download.qt.io/official_releases/qt/5.14/5.14.0/qt-opensource-linux-x64-5.14.0.run
- chmod +x qt-opensource-linux-x64-5.14.0.run
- xvfb-run ./qt-opensource-linux-x64-5.14.0.run --script ~/repo/.circleci/qt-installer-script.js --platform minimal --verbose
-
- - run:
name: Install dependencies
command: |
sudo apt-get update
- sudo apt-get install -y python3-pip xvfb tor obfs4proxy
- sudo pip3 install poetry flake8
+ sudo apt-get -y install tor obfs4proxy
+ pip install poetry
+ cd ~/repo/cli
poetry install
- run:
- name: Run flake tests
+ name: Run tests
command: |
- # stop the build if there are Python syntax errors or undefined names
- flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics
- # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
- flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
+ cd ~/repo/cli
+ poetry run pytest -v ./tests
+
+ test-gui:
+ docker:
+ - image: circleci/python:3.8-buster
+
+ working_directory: ~/repo
+
+ steps:
+ - checkout
- run:
- name: Run unit tests
+ name: Install dependencies
command: |
- xvfb-run -s "-screen 0 1280x1024x24" poetry run ./tests/run.sh --rungui
-
- test-3.7:
- <<: *test-template
- docker:
- - image: circleci/python:3.7-buster
+ sudo apt-get update
+ sudo apt-get install -y tor obfs4proxy gcc python3-dev python3-pyside2.qtcore python3-pyside2.qtwidgets python3-pyside2.qtgui
+ sudo apt-get install -y xvfb x11-utils libxkbcommon-x11-0 libxcb-randr0-dev libxcb-xtest0-dev libxcb-xinerama0-dev libxcb-shape0-dev libxcb-xkb-dev libxcb-render-util0 libxcb-icccm4 libxcb-keysyms1 libxcb-image0
+ cd ~/repo/cli
+ poetry install
+ poetry build
+ cp dist/onionshare_cli-*.whl ~/repo/desktop
+ cd ~/repo/desktop
+ pip install briefcase pytest pytest-briefcase pytest-faulthandler pytest-qt pytest-xvfb
+ pip install $(python -c 'import toml; print(" ".join(toml.loads(open("pyproject.toml").read())["tool"]["briefcase"]["app"]["onionshare"]["requires"]))')
- test-3.8:
- <<: *test-template
- docker:
- - image: circleci/python:3.8-buster
+ - run:
+ name: Run tests
+ command: |
+ cd ~/repo/desktop
+ ./tests/run.sh
diff --git a/.circleci/qt-installer-script.js b/.circleci/qt-installer-script.js
deleted file mode 100644
index d5860b68..00000000
--- a/.circleci/qt-installer-script.js
+++ /dev/null
@@ -1,75 +0,0 @@
-function Controller() {
- installer.installationFinished.connect(proceed)
-}
-
-function logCurrentPage() {
- var pageName = page().objectName
- var pagePrettyTitle = page().title
- console.log("At page: " + pageName + " ('" + pagePrettyTitle + "')")
-}
-
-function page() {
- return gui.currentPageWidget()
-}
-
-function proceed(button, delay) {
- gui.clickButton(button || buttons.NextButton, delay)
-}
-
-Controller.prototype.WelcomePageCallback = function() {
- logCurrentPage()
- proceed(buttons.NextButton, 2000)
-}
-
-Controller.prototype.CredentialsPageCallback = function() {
- logCurrentPage()
- page().loginWidget.EmailLineEdit.text = installer.environmentVariable("QT_EMAIL");
- page().loginWidget.PasswordLineEdit.text = installer.environmentVariable("QT_PASSWORD");
- proceed()
-}
-
-Controller.prototype.IntroductionPageCallback = function() {
- logCurrentPage()
- proceed()
-}
-
-Controller.prototype.TargetDirectoryPageCallback = function() {
- logCurrentPage()
- proceed()
-}
-
-Controller.prototype.ComponentSelectionPageCallback = function() {
- logCurrentPage()
- page().deselectAll()
- page().selectComponent("qt.qt5.5140.gcc_64")
- proceed()
-}
-
-Controller.prototype.LicenseAgreementPageCallback = function() {
- logCurrentPage()
- page().AcceptLicenseRadioButton.checked = true
- gui.clickButton(buttons.NextButton)
-}
-
-Controller.prototype.ReadyForInstallationPageCallback = function() {
- logCurrentPage()
- proceed()
-}
-
-Controller.prototype.PerformInstallationPageCallback = function() {
- logCurrentPage()
-}
-
-Controller.prototype.FinishedPageCallback = function() {
- logCurrentPage()
- page().LaunchQtCreatorCheckBoxForm.launchQtCreatorCheckBox.checked = false
- proceed(buttons.FinishButton)
-}
-
-Controller.prototype.DynamicTelemetryPluginFormCallback = function() {
- logCurrentPage()
- console.log(Object.keys(page().TelemetryPluginForm.statisticGroupBox))
- var radioButtons = page().TelemetryPluginForm.statisticGroupBox
- radioButtons.disableStatisticRadioButton.checked = true
- proceed()
-}
diff --git a/.gitignore b/.gitignore
index 4f84c508..c96d9d1d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,6 +21,9 @@ develop-eggs
MANIFEST
env
onionshare-*.tar.gz
+onionshare_*.snap
+.flatpak-builder
+OnionShare.flatpak
# Installer logs
pip-log.txt
@@ -55,3 +58,11 @@ venv
# other
.vscode
+onionshare.dist-info
+desktop/src/onionshare/resources/tor
+desktop/*.whl
+desktop/linux
+desktop/windows
+desktop/macOS
+# gets added automatically when building for Windows or macOS
+desktop/include \ No newline at end of file
diff --git a/BUILD.md b/BUILD.md
deleted file mode 100644
index c49f70be..00000000
--- a/BUILD.md
+++ /dev/null
@@ -1,419 +0,0 @@
-# Index
-* [Building OnionShare](#building-onionshare)
- * [Linux](#linux)
- * [Use newest software](#use-newest-software)
- * [Use package managers](#use-package-managers)
- * [macOS](#macos)
- * [Windows](#windows)
- * [Setting up your dev environment](#setting-up-your-dev-environment)
- * [To make a .exe](#to-make-a-exe)
- * [To build the installer](#to-build-the-installer)
-* [Running tests](#running-tests)
-* [Documentation]
-* [Making releases](#making-releases)
- * [Changelog, version, and signed git tag](#changelog-version-and-signed-git-tag)
- * [Linux release](#linux-release)
- * [macOS release](#macos-release)
- * [Windows release](#windows-release)
- * [Source package](#source-package)
- * [Publishing the release](#publishing-the-release)
-
-# Building OnionShare
-
-Start by getting the source code:
-
-```sh
-git clone https://github.com/micahflee/onionshare.git
-cd onionshare
-```
-
-## Linux
-
-### Use newest software
-
-The recommended way to develop OnionShare is to use the latest versions of all dependencies.
-
-First, install `tor` and `obfs4proxy` from either the [official Debian repository](https://support.torproject.org/apt/tor-deb-repo/), or from your package manager.
-
-Then download Qt 5.14.0 for Linux:
-
-```sh
-cd ~/Downloads
-wget https://download.qt.io/official_releases/qt/5.14/5.14.0/qt-opensource-linux-x64-5.14.0.run
-```
-
-If you'd like to check to make sure you have the exact installer I have, here is the sha256 checksum:
-
-```sh
-sha256sum qt-opensource-linux-x64-5.14.0.run
-4379f147c6793ec7e7349d2f9ee7d53b8ab6ea4e4edf8ee0574a75586a6a6e0e qt-opensource-linux-x64-5.14.0.run
-```
-
-Then make it executable and install Qt:
-
-```sh
-chmod +x qt-opensource-linux-x64-5.14.0.run
-./qt-opensource-linux-x64-5.14.0.run
-```
-
-You have to create a Qt account and login to install Qt. Choose the default installation folder in your home directory. The only component you need is `Qt 5.14.0` > `Desktop gcc 64-bit`.
-
-Install [poetry](https://python-poetry.org/docs/) from your package manager, or by doing `pip install --user poetry`. Then install dependencies:
-
-```sh
-poetry install
-```
-
-You can run the CLI and the GUI versions of OnionShare like this:
-
-```sh
-poetry run ./dev_scripts/onionshare
-poetry run ./dev_scripts/onionshare-gui
-```
-
-### Use package managers
-
-Alternatively, you can install dependencies from package managers.
-
-Install the needed dependencies:
-
-**For Debian-like distros:**
-
-```
-apt install -y python3-flask python3-stem python3-pyqt5 python3-crypto python3-socks python3-nautilus tor obfs4proxy python3-pytest python3-pytestqt build-essential fakeroot python3-all python3-stdeb dh-python python3-flask-httpauth python3-distutils python3-psutil python3-socketio python3-flask-socketio python3-qrcode
-```
-
-**For Fedora-like distros:**
-
-```
-dnf install -y python3-flask python3-flask-httpauth python3-stem python3-qt5 python3-crypto python3-pysocks nautilus-python tor obfs4 python3-pytest rpm-build python3-psutil python3-socketio python3-flask-socketio python3-qrcode
-```
-
-After that you can try both the CLI and the GUI version of OnionShare:
-
-```sh
-./dev_scripts/onionshare
-./dev_scripts/onionshare-gui
-```
-
-You can also build OnionShare packages to install:
-
-Create a .deb on Debian-like distros: `./install/build_deb.sh`
-
-Create a .rpm on Fedora-like distros: `./install/build_rpm.sh`
-
-For openSUSE: There are instructions for building [in the wiki](https://github.com/micahflee/onionshare/wiki/Linux-Distribution-Support#opensuse-leap-150).
-
-For ArchLinux: There is a PKBUILD available [here](https://www.archlinux.org/packages/community/any/onionshare/) that can be used to install OnionShare.
-
-If you find that these instructions don't work for your Linux distribution or version, consult the [Linux Distribution Support wiki guide](https://github.com/micahflee/onionshare/wiki/Linux-Distribution-Support), which might contain extra instructions.
-
-## macOS
-
-Install Xcode from the Mac App Store. Once it's installed, run it for the first time to set it up. Also, run this to make sure command line tools are installed: `xcode-select --install`. And finally, open Xcode, go to Preferences > Locations, and make sure under Command Line Tools you select an installed version from the dropdown. (This is required for installing Qt5.)
-
-Download and install Python 3.7.4 from https://www.python.org/downloads/release/python-374/. I downloaded `python-3.7.4-macosx10.9.pkg`.
-
-You may also need to run the command `/Applications/Python\ 3.7/Install\ Certificates.command` to update Python 3.6's internal certificate store. Otherwise, you may find that fetching the Tor Browser .dmg file fails later due to a certificate validation error.
-
-Install Qt 5.14.0 for macOS from https://www.qt.io/offline-installers. I downloaded `qt-opensource-mac-x64-5.14.0.dmg`. In the installer, you can skip making an account, and all you need is `Qt` > `Qt 5.14.0` > `macOS`.
-
-If you don't have it already, install poetry (`pip3 install --user poetry`). Then install dependencies:
-
-```sh
-poetry install
-```
-
-#### You can run both the CLI and GUI versions of OnionShare without building an bundle
-
-```sh
-poetry run ./dev_scripts/onionshare
-poetry run ./dev_scripts/onionshare-gui
-```
-
-#### To build the app bundle
-
-```sh
-install/build_osx.sh
-```
-
-Now you should have `dist/OnionShare.app`.
-
-#### To codesign and build a pkg for distribution
-
-```sh
-install/build_osx.sh --release
-```
-
-Now you should have `dist/OnionShare.pkg`.
-
-## Windows
-
-### Setting up your dev environment
-
-These instructions include adding folders to the path in Windows. To do this, go to Start and type "advanced system settings", and open "View advanced system settings" in the Control Panel. Click Environment Variables. Under "System variables" double-click on Path. From there you can add and remove folders that are available in the PATH.
-
-Download Python 3.7.4, 32-bit (x86) from https://www.python.org/downloads/release/python-374/. I downloaded `python-3.7.4.exe`. When installing it, make sure to check the "Add Python 3.7 to PATH" checkbox on the first page of the installer.
-
-Install the Qt 5.14.0 from https://www.qt.io/offline-installers. I downloaded `qt-opensource-windows-x86-5.14.0.exe`. In the installer, you can skip making an account, and all you need `Qt` > `Qt 5.14.0` > `MSVC 2017 32-bit`.
-
-Install [poetry](https://python-poetry.org/). Open PowerShell, and run:
-
-```
-(Invoke-WebRequest -Uri https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py -UseBasicParsing).Content | python
-```
-
-Then open a Command Prompt and cd to the `onionshare` folder, and install the poetry dependencies:
-
-```
-poetry install
-```
-
-After that you can try both the CLI and the GUI version of OnionShare:
-
-```
-poetry run python dev_scripts\onionshare
-poetry run python dev_scripts\onionshare-gui
-```
-
-#### If you want to build a .exe
-
-Download and install 7-Zip from http://www.7-zip.org/download.html. I downloaded `7z1900.exe`.
-
-Download and install the standalone [Windows 10 SDK](https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk). Note that you may not need this if you already have Visual Studio.
-
-Add the following directories (you might want to make sure these are exact on your computer) to the path:
-
-* `C:\Program Files (x86)\Windows Kits\10\bin\10.0.18362.0\x86`
-* `C:\Program Files (x86)\Windows Kits\10\Redist\10.0.18362.0\ucrt\DLLs\x86`
-* `C:\Program Files (x86)\7-Zip`
-* `C:\Users\user\AppData\Local\Programs\Python\Python37-32\Lib\site-packages\PyQt5\Qt\bin`
-
-#### If you want the .exe to not get falsely flagged as malicious by anti-virus software
-
-OnionShare uses PyInstaller to turn the python source code into Windows executable `.exe` file. Apparently, malware developers also use PyInstaller, and some anti-virus vendors have included snippets of PyInstaller code in their virus definitions. To avoid this, you have to compile the Windows PyInstaller bootloader yourself instead of using the pre-compiled one that comes with PyInstaller.
-
-(If you don't care about this, you can install PyInstaller with `pip install PyInstaller==3.5`.)
-
-Here's how to compile the PyInstaller bootloader:
-
-Download and install [Microsoft Build Tools for Visual Studio 2019](https://www.visualstudio.com/downloads/#build-tools-for-visual-studio-2019). I downloaded `vs_buildtools__1285639570.1568593053.exe`. In the installer, check the box next to "Visual C++ build tools". Click "Individual components", and under "Compilers, build tools and runtimes", check "Windows Universal CRT SDK". Then click install. When installation is done, you may have to reboot your computer.
-
-Then, enable the 32-bit Visual C++ Toolset on the Command Line like this:
-
-```
-cd "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Auxiliary\Build"
-vcvars32.bat
-```
-
-Change to a folder where you keep source code, and clone the PyInstaller git repo and checkout the `v3.5` tag:
-
-```
-git clone https://github.com/pyinstaller/pyinstaller.git
-cd pyinstaller
-git tag -v v3.5
-```
-
-(Note that ideally you would verify the git tag, but the PGP key that has signed the `v3.5` git tag for is not published anywhere, so this isn't possible. See [this issue](https://github.com/pyinstaller/pyinstaller/issues/4430).)
-
-The next step is to compile the bootloader. We should do this all in dangerzone's poetry shell:
-
-```
-cd onionshare
-poetry shell
-cd ..\pyinstaller
-```
-
-And compile the bootloader, following [these instructions](https://pythonhosted.org/PyInstaller/bootloader-building.html). To compile, run this:
-
-```
-cd bootloader
-python waf distclean all --target-arch=32bit --msvc_targets=x86
-```
-
-Finally, install the PyInstaller module into your poetry environment:
-
-```
-cd ..
-python setup.py install
-exit
-```
-
-Now the next time you use PyInstaller to build OnionShare, the `.exe` file should not be flagged as malicious by anti-virus.
-
-#### If you want to build the installer
-
-* Go to http://nsis.sourceforge.net/Download and download the latest NSIS. I downloaded `nsis-3.04-setup.exe`.
-* Add `C:\Program Files (x86)\NSIS` to the path.
-
-#### If you want to sign binaries with Authenticode
-
-* You'll need a code signing certificate. I got an open source code signing certificate from [Certum](https://www.certum.eu/certum/cert,offer_en_open_source_cs.xml).
-* Once you get a code signing key and certificate and covert it to a pfx file, import it into your certificate store.
-
-### To make a .exe:
-
-* Open a command prompt, cd into the onionshare directory, and type: `pyinstaller install\pyinstaller.spec`. `onionshare-gui.exe` and all of their supporting files will get created inside the `dist` folder.
-
-### To build the installer:
-
-Note that you must have a codesigning certificate installed in order to use the `install\build_exe.bat` script, because it codesigns `onionshare-gui.exe`, `uninstall.exe`, and `onionshare-setup.exe`.
-
-Open a command prompt, cd to the onionshare directory, and type: `install\build_exe.bat`
-
-This will prompt you to codesign three binaries and execute one unsigned binary. When you're done clicking through everything you will have `dist\onionshare-setup.exe`.
-
-# Running tests
-
-## Tests in macOS and Linux
-
-OnionShare includes PyTest unit tests. To run tests, you can run `pytest` against the `tests/` directory.
-
-```sh
-poetry run ./tests/run.sh
-```
-
-You can run GUI tests like this:
-
-```sh
-poetry run ./tests/run.sh --rungui
-```
-
-If you're using Linux, you can also choose to wrap the tests in `xvfb-run` so that a ton of OnionShare windows don't pop up on your desktop (you may need to install the `xorg-x11-server-Xvfb` package), like this:
-
-```sh
-xvfb-run poetry run ./tests/run.sh --rungui
-```
-
-## Tests in Windows
-
-You can run this Windows batch script to run all of the CLI and GUI tests.
-
-```
-poetry run tests\run.bat
-```
-
-# Documentation
-
-To edit and build the documentation, see the [docs readme](/docs/README.md).
-
-# Making releases
-
-This section documents the release process. Unless you're a core OnionShare developer making a release, you'll probably never need to follow it.
-
-## Changelog, version, docs, and signed git tag
-
-Before making a release, you must update the version in these places:
-
-* `share/version.txt` should have the correct version
-* `pyproject.toml` should have the correct version
-* `docs/source/conf.py` should have the correct version
-* `install/org.onionshare.OnionShare.appdata.xml` should have the correct version
-* `install/onionshare.nsi` should have the correct version, for the Windows installer
-
-In addition to that, you must:
-
-* `install/org.onionshare.OnionShare.appdata.xml` should have the correct release date, and links to correct screenshots
-* `CHANGELOG.md` should be updated to include a list of all major changes since the last release
-* Update all of the documentation to cover new features, including taking new screenshots if necessary
-* There must be a PGP-signed git tag for the version, e.g. for OnionShare 2.1, the tag must be `v2.1`
-
-The first step for the Linux, macOS, and Windows releases is the same:
-
-Verify the release git tag:
-
-```
-git fetch
-git tag -v v$VERSION
-```
-
-If the tag verifies successfully, check it out:
-
-```
-git checkout v$VERSION
-```
-
-## Linux release
-
-TODO: Write Flatpak instructions (see [this issue](https://github.com/micahflee/onionshare/issues/910)).
-
-To make a PPA release:
-
-- Go to Ubuntu build machine, which must have `~/.dput.cf` with the correct PPA info in it, and with the correct PGP signing key
-- Verify and checkout the git tag for this release
-- Run `./install/ppa_release.sh`, which builds a source package and uploads to the PPA build server
-- Login to Launchpad to monitor the build and make sure it is successful; if not, make minor patches and try the release again
-- After build is successful, from Launchpad, copy the binary from `cosmic` into other suites
-
-## macOS release
-
-To make a macOS release, go to macOS build machine:
-
-- Build machine should be running macOS 10.11.6, and must have the Apple-trusted `Developer ID Application: Micah Lee` and `Developer ID Installer: Micah Lee` code-signing certificates installed
-- Verify and checkout the git tag for this release
-- Run `./install/build_osx.sh --release`; this will make a codesigned installer package called `dist/OnionShare-$VERSION.pkg`
-- Copy `OnionShare-$VERSION.pkg` to developer machine
-
-Then move back to the developer machine:
-
-- PGP-sign the macOS installer, `gpg -a --detach-sign OnionShare-$VERSION.pkg`
-
-Note that once we support notarizing the macOS installer (see [this issue](https://github.com/micahflee/onionshare/issues/953)), these will be the steps instead:
-
-- Developer machine, running the latest macOS, must have an app-specific Apple ID password saved in the login keychain called `onionshare-notarize`
-- Notarize it: `xcrun altool --notarize-app --primary-bundle-id "com.micahflee.onionshare" -u "micah@micahflee.com" -p "@keychain:onionshare-notarize" --file OnionShare-$VERSION.pkg`
-- Wait for it to get approved, check status with: `xcrun altool --notarization-history 0 -u "micah@micahflee.com" -p "@keychain:onionshare-notarize"`
-- After it's approved, staple the ticket: `xcrun stapler staple OnionShare-$VERSION.pkg`
-- PGP-sign the final, notarized and stapled, `gpg -a --detach-sign OnionShare-$VERSION.pkg`
-
-This process ends up with two final files:
-
-```
-OnionShare-$VERSION.pkg
-OnionShare-$VERSION.pkg.asc
-```
-
-## Windows release
-
-To make a Windows release, go to Windows build machine:
-
-- Build machine should be running Windows 10, and have the Windows codesigning certificate installed
-- Verify and checkout the git tag for this release
-- Run `install\build_exe.bat`; this will make a codesigned installer package called `dist\onionshare-$VERSION-setup.exe`
-- Copy `onionshare-$VERSION-setup.exe` to developer machine
-
-Then move back to the developer machine:
-
-- PGP-sign the Windows installer, `gpg -a --detach-sign onionshare-$VERSION-setup.exe`
-
-This process ends up with two final files:
-
-```
-onionshare-$VERSION-setup.exe
-onionshare-$VERSION-setup.exe.asc
-```
-
-## Source package
-
-To make a source package, run `./install/build_source.sh $TAG`, where `$TAG` is the the name of the signed git tag, e.g. `v2.1`.
-
-This process ends up with two final files in `dist`:
-
-```
-onionshare-$VERSION.tar.gz
-onionshare-$VERSION.tar.gz.asc
-```
-
-## Publishing the release
-
-To publish the release:
-
-- Create a new release on GitHub, put the changelog in the description of the release, and upload all six files (the macOS installer, the Windows installer, the source package, and their signatures)
-- Upload the six release files to https://onionshare.org/dist/$VERSION/
-- Copy the six release files into the OnionShare team Keybase filesystem
-- Update the [onionshare-website](https://github.com/micahflee/onionshare-website) repo:
- - Edit `latest-version.txt` to match the latest version
- - Update the version number and download links
- - Deploy to https://onionshare.org/
-- Email the [onionshare-dev](https://lists.riseup.net/www/subscribe/onionshare-dev) mailing list announcing the release
-- Make a PR to [homebrew-cask](https://github.com/homebrew/homebrew-cask) to update the macOS version
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 272f8efc..c64fee9e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,7 +7,7 @@
* New feature: All new design
* New feature: Ability to display QR codes of OnionShare addresses
* New feature: Web apps have responsive design and look better on mobile
-* New feature: Flatpak packaging for Linux
+* New feature: Flatpak and Snapcraft packaging for Linux
* Several bug fixes
## 2.2
diff --git a/MANIFEST.in b/MANIFEST.in
deleted file mode 100644
index 7dd8a881..00000000
--- a/MANIFEST.in
+++ /dev/null
@@ -1,13 +0,0 @@
-include LICENSE
-include README.md
-include BUILD.md
-include share/*
-include share/images/*
-include share/locale/*
-include share/templates/*
-include share/static/*
-include install/org.onionshare.OnionShare.desktop
-include install/org.onionshare.OnionShare.appdata.xml
-include install/org.onionshare.OnionShare.svg
-include install/scripts/onionshare-nautilus.py
-include tests/*.py
diff --git a/README.md b/README.md
index 57a835be..274d6d93 100644
--- a/README.md
+++ b/README.md
@@ -22,4 +22,4 @@ To learn how OnionShare works, what its security properties are, how to use it,
---
-Test status: [![CircleCI](https://circleci.com/gh/micahflee/onionshare.svg?style=svg)](https://circleci.com/gh/micahflee/onionshare)
+Test status: [![CircleCI](https://circleci.com/gh/micahflee/onionshare.svg?style=svg)](https://circleci.com/gh/micahflee/onionshare) \ No newline at end of file
diff --git a/RELEASE.md b/RELEASE.md
new file mode 100644
index 00000000..f3550bf2
--- /dev/null
+++ b/RELEASE.md
@@ -0,0 +1,234 @@
+# OnionShare Release Process
+
+Unless you're a core OnionShare developer making a release, you'll probably never need to follow it.
+
+## Changelog, version, docs, and signed git tag
+
+Before making a release, you must update the version in these places:
+
+- [ ] `cli/pyproject.toml`
+- [ ] `cli/setup.py`
+- [ ] `cli/onionshare_cli/resources/version.txt`
+- [ ] `desktop/pyproject.toml` (under `version` and **don't forget** the `./onionshare_cli-$VERSION-py3-none-any.whl` dependency)
+- [ ] `desktop/src/setup.py`
+- [ ] `docs/source/conf.py`
+- [ ] `snap/snapcraft.yaml`
+
+Update the documentation:
+
+- [ ] Update all of the documentation in `docs` to cover new features, including taking new screenshots if necessary
+
+You also must edit these files:
+
+- [ ] `desktop/src/org.onionshare.OnionShare.appdata.xml` should have the correct version, release date, and links to correct screenshots
+- [ ] `CHANGELOG.md` should be updated to include a list of all major changes since the last release
+
+Make sure snapcraft packaging works. In `snap/snapcraft.yaml`:
+
+- [ ] The `tor`, `libevent`, and `obfs4` parts should be updated if necessary
+- [ ] All python packages should be updated to match `cli/pyproject.toml` and `desktop/pyproject.toml`
+- [ ] Test the snap package, ensure it works
+
+Make sure Flatpak packaging works. In `flatpak/org.onionshare.OnionShare.yaml`:
+
+- [ ] Update `tor`, `libevent`, and `obfs4` dependencies, if necessary
+- [ ] Built the latest python dependencies using [this tool](https://github.com/flatpak/flatpak-builder-tools/blob/master/pip/flatpak-pip-generator) (see below)
+- [ ] Test the Flatpak package, ensure it works
+
+```
+# you may need to install toml
+pip3 install --user toml
+
+# clone flatpak-build-tools
+git clone https://github.com/flatpak/flatpak-builder-tools.git
+cd flatpak-builder-tools/pip
+
+# get onionshare-cli dependencies
+./flatpak-pip-generator $(python3 -c 'import toml; print("\n".join([x for x in toml.loads(open("../../onionshare/cli/pyproject.toml").read())["tool"]["poetry"]["dependencies"]]))' |grep -v "^python$" |tr "\n" " ")
+mv python3-modules.json onionshare-cli.json
+
+# get onionshare dependencies
+./flatpak-pip-generator $(python3 -c 'import toml; print("\n".join(toml.loads(open("../../onionshare/desktop/pyproject.toml").read())["tool"]["briefcase"]["app"]["onionshare"]["requires"]))' |grep -v "./onionshare_cli" |grep -v -i "pyside2" |tr "\n" " ")
+mv python3-modules.json onionshare.json
+
+# use something like https://www.json2yaml.com/ to convert to yaml and update the manifest
+# add all of the modules in both onionshare-cli and onionshare to the submodules of "onionshare"
+# - onionshare-cli.json
+# - onionshare.json
+```
+
+Finally:
+
+- [ ] There must be a PGP-signed git tag for the version, e.g. for OnionShare 2.1, the tag must be `v2.1`
+
+The first step for the Linux, macOS, and Windows releases is the same.
+
+Verify the release git tag:
+
+```sh
+git fetch
+git tag -v v$VERSION
+```
+
+If the tag verifies successfully, check it out:
+
+```sh
+git checkout v$VERSION
+```
+
+## Linux Flatpak release
+
+You must have `flatpak` and `flatpak-builder` installed, with flathub remote added (`flatpak remote-add --if-not-exists --user flathub https://flathub.org/repo/flathub.flatpakrepo`).
+
+Build and test the Flatpak package before publishing:
+
+```sh
+flatpak-builder build --force-clean --install-deps-from=flathub --install --user flatpak/org.onionshare.OnionShare.yaml
+flatpak run org.onionshare.OnionShare
+```
+
+Once you confirm it works, create a single-file bundle:
+
+```sh
+flatpak build-bundle ~/.local/share/flatpak/repo OnionShare.flatpak org.onionshare.OnionShare
+```
+
+This will create `OnionShare.flatpak`.
+
+## Linux Snapcraft release
+
+You must have `snap` and `snapcraft` (`snap install snapcraft --classic`) installed.
+
+Build and test the snap before publishing:
+
+```sh
+snapcraft
+snap install --devmode ./onionshare_$VERSION_amd64.snap
+```
+
+Run the OnionShare snap:
+
+```sh
+/snap/bin/onionshare # GUI version
+/snap/bin/onionshare.cli # CLI version
+```
+
+This will create `onionshare_$VERSION_amd64.snap`.
+
+## Linux AppImage release
+
+_Note: AppImage packages are currently broken due to [this briefcase bug](https://github.com/beeware/briefcase/issues/504). Until it's fixed, OnionShare for Linux will only be available in Flatpak and Snapcraft._
+
+Set up the development environment described in `README.md`.
+
+Make sure your virtual environment is active:
+
+```sh
+. venv/bin/activate
+```
+
+Run the AppImage build script:
+
+```sh
+./package/linux/build-appimage.py
+```
+
+### Windows
+
+Set up the development environment described in `README.md`. And install the [Windows 10 SDK](https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk) and add `C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x86` to your path.
+
+Make sure your virtual environment is active:
+
+```
+venv\Scripts\activate.bat
+```
+
+Run the Windows build script:
+
+```
+python package\windows\build.py
+```
+
+This will create `desktop/windows/OnionShare-$VERSION.msi`, signed.
+
+### macOS
+
+Set up the development environment described in `README.md`. And install `create-dmg`:
+
+```sh
+brew install create-dmg
+```
+
+Make sure your virtual environment is active:
+
+```sh
+. venv/bin/activate
+```
+
+Run the macOS build script:
+
+```sh
+./package/macos/build.py --with-codesign
+```
+
+Now, notarize the release. You must have an app-specific Apple ID password saved in the login keychain called `onionshare-notarize`.
+
+- Notarize it: `xcrun altool --notarize-app --primary-bundle-id "com.micahflee.onionshare" -u "micah@micahflee.com" -p "@keychain:onionshare-notarize" --file macOS/OnionShare.dmg`
+- Wait for it to get approved, check status with: `xcrun altool --notarization-history 0 -u "micah@micahflee.com" -p "@keychain:onionshare-notarize"`
+- After it's approved, staple the ticket: `xcrun stapler staple macOS/OnionShare.dmg`
+
+This will create `desktop/macOS/OnionShare.dmg`, signed and notarized.
+
+### Source package
+
+To make a source package, run `./build-source.sh $TAG`, where `$TAG` is the the name of the signed git tag, e.g. `v2.1`.
+
+This will create `dist/onionshare-$VERSION.tar.gz`.
+
+### Publishing the release
+
+After following all of the previous steps, gather these files:
+
+- `OnionShare.flatpak` (rename it to `OnionShare-$VERSION.flatpak`)
+- `onionshare_$VERSION_amd64.snap`
+- `OnionShare-$VERSION.msi`
+- `OnionShare.dmg` (rename it to `OnionShare-$VERSION.dmg`)
+- `onionshare-$VERSION.tar.gz`
+
+Create a PGP signature for each of these files, e.g:
+
+```sh
+gpg -a --detach-sign OnionShare-$VERSION.flatpak
+gpg -a --detach-sign [... and so on]
+```
+
+Create a release on GitHub:
+
+- Match it to the version tag, put the changelog in description of the release
+- Upload all 10 files (binary and source packages and their `.asc` signatures)
+
+Update onionshare.org:
+
+- Upload all 10 files to https://onionshare.org/dist/$VERSION/
+- Update the [onionshare-website](https://github.com/micahflee/onionshare-website) repo:
+ - Edit `latest-version.txt` to match the latest version
+ - Update the version number and download links
+ - Deploy to https://onionshare.org/
+
+Update Homebrew:
+
+- Make a PR to [homebrew-cask](https://github.com/homebrew/homebrew-cask) to update the macOS version
+
+Update onionshare-cli on PyPi:
+
+```sh
+cd cli
+poetry install
+poetry publish --build
+```
+
+Update the community:
+
+- Upload all 10 files to the OnionShare team Keybase filesystem
+- Email the [onionshare-dev](https://lists.riseup.net/www/subscribe/onionshare-dev) mailing list announcing the release
+- Tweet, toot, etc.
diff --git a/apparmor/abstractions/onionshare b/apparmor/abstractions/onionshare
deleted file mode 100644
index fa94e68d..00000000
--- a/apparmor/abstractions/onionshare
+++ /dev/null
@@ -1,29 +0,0 @@
-#include <abstractions/base>
-#include <abstractions/nameservice>
-#include <abstractions/private-files-strict>
-#include <abstractions/python>
-
-# Why are these not in abstractions/python?
-/usr/lib{,32,64}/python{2,3}.[0-9]/__pycache__/ rw,
-/usr/lib{,32,64}/python{2,3}.[0-9]/__pycache__/* rw,
-/usr/lib{,32,64}/python{2,3}.[0-9]/**/__pycache__/ rw,
-/usr/lib{,32,64}/python{2,3}.[0-9]/**/__pycache__/* rw,
-/usr/lib{,32,64}/python{2,3}/**/__pycache__/ rw,
-/usr/lib{,32,64}/python{2,3}/**/__pycache__/* rw,
-
-/bin/dash rix,
-/proc/*/mounts r,
-/proc/*/fd/ r,
-/sbin/ldconfig rix,
-/sbin/ldconfig.real rix,
-/bin/uname rix,
-/etc/mime.types r,
-/usr/share/onionshare/ r,
-/usr/share/onionshare/** r,
-/tmp/ rw,
-/tmp/** rw,
-
-# Allow read on almost anything in @{HOME}. Lenient, but
-# private-files-strict is in effect.
-owner @{HOME}/ r,
-owner @{HOME}/[^.]** r,
diff --git a/apparmor/local/usr.bin.onionshare b/apparmor/local/usr.bin.onionshare
deleted file mode 100644
index 6453771d..00000000
--- a/apparmor/local/usr.bin.onionshare
+++ /dev/null
@@ -1,2 +0,0 @@
-# Site-specific additions and overrides for usr.bin.onionshare.
-# For more details, please see /etc/apparmor.d/local/README.
diff --git a/apparmor/local/usr.bin.onionshare-gui b/apparmor/local/usr.bin.onionshare-gui
deleted file mode 100644
index fa5ba3f0..00000000
--- a/apparmor/local/usr.bin.onionshare-gui
+++ /dev/null
@@ -1,2 +0,0 @@
-# Site-specific additions and overrides for usr.bin.onionshare-gui.
-# For more details, please see /etc/apparmor.d/local/README.
diff --git a/apparmor/usr.bin.onionshare b/apparmor/usr.bin.onionshare
deleted file mode 100644
index 1c14ccc1..00000000
--- a/apparmor/usr.bin.onionshare
+++ /dev/null
@@ -1,10 +0,0 @@
-#include <tunables/global>
-
-/usr/bin/onionshare {
- #include <abstractions/onionshare>
-
- /usr/bin/ r,
- /usr/bin/onionshare r,
-
- #include <local/usr.bin.onionshare>
-}
diff --git a/apparmor/usr.bin.onionshare-gui b/apparmor/usr.bin.onionshare-gui
deleted file mode 100644
index 746dadc1..00000000
--- a/apparmor/usr.bin.onionshare-gui
+++ /dev/null
@@ -1,28 +0,0 @@
-#include <tunables/global>
-
-/usr/bin/onionshare-gui {
- #include <abstractions/gnome>
- #include <abstractions/ibus>
- #include <abstractions/onionshare>
-
- /usr/bin/ r,
- /usr/bin/onionshare-gui r,
- /proc/*/cmdline r,
-
- # The freedesktop.org abstraction doesn't allow `k`
- /usr/share/icons/*/index.theme k,
-
- # Why do these still emit audit journal entries?
- owner @{HOME}/.config/ibus/bus/ rw,
- owner @{HOME}/.config/ibus/bus/* rw,
- deny @{HOME}/.ICEauthority r,
-
- deny /etc/machine-id r,
- deny /var/lib/dbus/machine-id.* rw,
-
- # Accessibility support
- owner /{,var/}run/user/*/at-spi2-*/ rw,
- owner /{,var/}run/user/*/at-spi2-*/** rw,
-
- #include <local/usr.bin.onionshare-gui>
-}
diff --git a/install/build_source.sh b/build-source.sh
index d7f48722..b7bd700a 100755
--- a/install/build_source.sh
+++ b/build-source.sh
@@ -1,7 +1,6 @@
#!/bin/bash
# The script builds a source package
-# See https://github.com/micahflee/onionshare/blob/develop/BUILD.md#source-package
# Usage
display_usage() {
@@ -67,15 +66,13 @@ git checkout $TAG
cd ..
rm -rf onionshare/.git
tar -cf onionshare-$VERSION.tar.gz onionshare/
-gpg -a --detach-sign onionshare-$VERSION.tar.gz
# Move source package to dist
cd ../..
mv build/source/onionshare-$VERSION.tar.gz dist
-mv build/source/onionshare-$VERSION.tar.gz.asc dist
# Clean up
rm -rf build/source/onionshare
rm build/source/verify.txt
-echo "Source package complete, files are in dist"
+echo "Source package complete, file in dist"
diff --git a/cli/.circleci/config.yml b/cli/.circleci/config.yml
new file mode 100644
index 00000000..70d16fea
--- /dev/null
+++ b/cli/.circleci/config.yml
@@ -0,0 +1,38 @@
+version: 2
+workflows:
+ version: 2
+ test:
+ jobs:
+ - test-3.6
+ - test-3.7
+ - test-3.8
+
+jobs:
+ test-3.6: &test-template
+ docker:
+ - image: circleci/python:3.6-buster
+
+ working_directory: ~/repo
+
+ steps:
+ - checkout
+
+ - run:
+ name: Install dependencies
+ command: |
+ poetry install
+
+ - run:
+ name: Run unit tests
+ command: |
+ poetry run pytest -vvv ./tests
+
+ test-3.7:
+ <<: *test-template
+ docker:
+ - image: circleci/python:3.7-buster
+
+ test-3.8:
+ <<: *test-template
+ docker:
+ - image: circleci/python:3.8-buster
diff --git a/cli/README.md b/cli/README.md
new file mode 100644
index 00000000..06bb18cf
--- /dev/null
+++ b/cli/README.md
@@ -0,0 +1,68 @@
+```
+ @@@@@@@@@
+ @@@@@@@@@@@@@@@@@@@
+ @@@@@@@@@@@@@@@@@@@@@@@@@
+ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ___ _
+ @@@@@@ @@@@@@@@@@@@@ / _ \ (_)
+ @@@@ @ @@@@@@@@@@@ | | | |_ __ _ ___ _ __
+ @@@@@@@@ @@@@@@@@@@ | | | | '_ \| |/ _ \| '_ \
+ @@@@@@@@@@@@ @@@@@@@@@@ \ \_/ / | | | | (_) | | | |
+ @@@@@@@@@@@@@@@@ @@@@@@@@@ \___/|_| |_|_|\___/|_| |_|
+ @@@@@@@@@ @@@@@@@@@@@@@@@@ _____ _
+ @@@@@@@@@@ @@@@@@@@@@@@ / ___| |
+ @@@@@@@@@@ @@@@@@@@ \ `--.| |__ __ _ _ __ ___
+ @@@@@@@@@@@ @ @@@@ `--. \ '_ \ / _` | '__/ _ \
+ @@@@@@@@@@@@@ @@@@@@ /\__/ / | | | (_| | | | __/
+ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@ \____/|_| |_|\__,_|_| \___|
+ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ @@@@@@@@@@@@@@@@@@@@@@@@@
+ @@@@@@@@@@@@@@@@@@@
+ @@@@@@@@@
+```
+
+## Installing OnionShare CLI
+
+First, make sure you have `tor` installed. In Linux, install it through your package manager. In macOS, install it with [Homebrew](https://brew.sh): `brew install tor`.
+
+Then install OnionShare CLI:
+
+```sh
+pip install onionshare-cli
+```
+
+Then run it with:
+
+```sh
+onionshare-cli --help
+```
+
+## Developing OnionShare CLI
+
+You must have python3 and [poetry](https://python-poetry.org/) installed.
+
+Install dependencies with poetry:
+
+```sh
+poetry install
+```
+
+To run from the source tree:
+
+```sh
+poetry run onionshare-cli
+```
+
+To run tests:
+
+```sh
+poetry run pytest -v ./tests
+```
+
+## Build a wheel package
+
+```sh
+poetry build
+```
+
+This will create `dist/onionshare_cli-$VERSION-py3-none-any.whl`.
diff --git a/onionshare/__init__.py b/cli/onionshare_cli/__init__.py
index c1367b1e..7361ac9e 100644
--- a/onionshare/__init__.py
+++ b/cli/onionshare_cli/__init__.py
@@ -57,19 +57,19 @@ def main(cwd=None):
" @@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ___ _ "
)
print(
- " @@@@@@ @@@@@@@@@@@@@ / _ \ (_) "
+ " @@@@@@ @@@@@@@@@@@@@ / _ \\ (_) "
)
print(
" @@@@ @ @@@@@@@@@@@ | | | |_ __ _ ___ _ __ "
)
print(
- " @@@@@@@@ @@@@@@@@@@ | | | | '_ \| |/ _ \| '_ \ "
+ " @@@@@@@@ @@@@@@@@@@ | | | | '_ \\| |/ _ \\| '_ \\ "
)
print(
- " @@@@@@@@@@@@ @@@@@@@@@@ \ \_/ / | | | | (_) | | | | "
+ " @@@@@@@@@@@@ @@@@@@@@@@ \\ \\_/ / | | | | (_) | | | | "
)
print(
- " @@@@@@@@@@@@@@@@ @@@@@@@@@ \___/|_| |_|_|\___/|_| |_| "
+ " @@@@@@@@@@@@@@@@ @@@@@@@@@ \\___/|_| |_|_|\\___/|_| |_| "
)
print(
" @@@@@@@@@ @@@@@@@@@@@@@@@@ _____ _ "
@@ -78,16 +78,16 @@ def main(cwd=None):
" @@@@@@@@@@ @@@@@@@@@@@@ / ___| | "
)
print(
- " @@@@@@@@@@ @@@@@@@@ \ `--.| |__ __ _ _ __ ___ "
+ " @@@@@@@@@@ @@@@@@@@ \\ `--.| |__ __ _ _ __ ___ "
)
print(
- " @@@@@@@@@@@ @ @@@@ `--. \ '_ \ / _` | '__/ _ \\"
+ " @@@@@@@@@@@ @ @@@@ `--. \\ '_ \\ / _` | '__/ _ \\"
)
print(
- " @@@@@@@@@@@@@ @@@@@@ /\__/ / | | | (_| | | | __/"
+ " @@@@@@@@@@@@@ @@@@@@ /\\__/ / | | | (_| | | | __/"
)
print(
- " @@@@@@@@@@@@@@@@@@@@@@@@@@@@@ \____/|_| |_|\__,_|_| \___|"
+ " @@@@@@@@@@@@@@@@@@@@@@@@@@@@@ \\____/|_| |_|\\__,_|_| \\___|"
)
print(" @@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ")
print(" @@@@@@@@@@@@@@@@@@@@@@@@@ ")
diff --git a/onionshare/common.py b/cli/onionshare_cli/common.py
index 27104669..a1213387 100644
--- a/onionshare/common.py
+++ b/cli/onionshare_cli/common.py
@@ -29,6 +29,7 @@ import tempfile
import threading
import time
import shutil
+from pkg_resources import resource_filename
from .settings import Settings
@@ -71,49 +72,12 @@ class Common:
def get_resource_path(self, filename):
"""
- Returns the absolute path of a resource, regardless of whether OnionShare is installed
- systemwide, and whether regardless of platform
+ Returns the absolute path of a resource
"""
- # On Windows, and in Windows dev mode, switch slashes in incoming filename to backslackes
- if self.platform == "Windows":
- filename = filename.replace("/", "\\")
-
- if getattr(sys, "onionshare_dev_mode", False):
- # Look for resources directory relative to python file
- prefix = os.path.join(
- os.path.dirname(
- os.path.dirname(
- os.path.abspath(inspect.getfile(inspect.currentframe()))
- )
- ),
- "share",
- )
- if not os.path.exists(prefix):
- # While running tests during stdeb bdist_deb, look 3 directories up for the share folder
- prefix = os.path.join(
- os.path.dirname(
- os.path.dirname(os.path.dirname(os.path.dirname(prefix)))
- ),
- "share",
- )
-
- elif self.platform == "BSD" or self.platform == "Linux":
- # Look for resources relative to the binary, so if the binary is /usr/bin/onionshare-gui and
- # the resource dir is /usr/share/onionshare, then the resource dir relative to the binary dir
- # is ../share/onionshare
- prefix = os.path.join(
- os.path.dirname(os.path.dirname(sys.argv[0])), "share/onionshare"
- )
-
- elif getattr(sys, "frozen", False):
- # Check if app is "frozen"
- # https://pythonhosted.org/PyInstaller/#run-time-information
- if self.platform == "Darwin":
- prefix = os.path.join(sys._MEIPASS, "share")
- elif self.platform == "Windows":
- prefix = os.path.join(os.path.dirname(sys.executable), "share")
-
- return os.path.join(prefix, filename)
+ self.log("Common", "get_resource_path", f"filename={filename}")
+ path = resource_filename("onionshare_cli", os.path.join("resources", filename))
+ self.log("Common", "get_resource_path", f"filename={filename}, path={path}")
+ return path
def get_tor_paths(self):
if self.platform == "Linux":
@@ -123,31 +87,17 @@ class Common:
tor_geo_ip_file_path = os.path.join(prefix, "share/tor/geoip")
tor_geo_ipv6_file_path = os.path.join(prefix, "share/tor/geoip6")
elif self.platform == "Windows":
- base_path = os.path.join(
- os.path.dirname(os.path.dirname(self.get_resource_path(""))), "tor"
- )
- tor_path = os.path.join(os.path.join(base_path, "Tor"), "tor.exe")
- obfs4proxy_file_path = os.path.join(
- os.path.join(base_path, "Tor"), "obfs4proxy.exe"
- )
- tor_geo_ip_file_path = os.path.join(
- os.path.join(os.path.join(base_path, "Data"), "Tor"), "geoip"
- )
- tor_geo_ipv6_file_path = os.path.join(
- os.path.join(os.path.join(base_path, "Data"), "Tor"), "geoip6"
- )
+ base_path = self.get_resource_path("tor")
+ tor_path = os.path.join(base_path, "Tor", "tor.exe")
+ obfs4proxy_file_path = os.path.join(base_path, "Tor", "obfs4proxy.exe")
+ tor_geo_ip_file_path = os.path.join(base_path, "Data", "Tor", "geoip")
+ tor_geo_ipv6_file_path = os.path.join(base_path, "Data", "Tor", "geoip6")
elif self.platform == "Darwin":
- base_path = os.path.dirname(
- os.path.dirname(os.path.dirname(self.get_resource_path("")))
- )
- tor_path = os.path.join(base_path, "Resources", "Tor", "tor")
- tor_geo_ip_file_path = os.path.join(base_path, "Resources", "Tor", "geoip")
- tor_geo_ipv6_file_path = os.path.join(
- base_path, "Resources", "Tor", "geoip6"
- )
- obfs4proxy_file_path = os.path.join(
- base_path, "Resources", "Tor", "obfs4proxy"
- )
+ tor_path = shutil.which("tor")
+ obfs4proxy_file_path = shutil.which("obfs4proxy")
+ prefix = os.path.dirname(os.path.dirname(tor_path))
+ tor_geo_ip_file_path = os.path.join(prefix, "share/tor/geoip")
+ tor_geo_ipv6_file_path = os.path.join(prefix, "share/tor/geoip6")
elif self.platform == "BSD":
tor_path = "/usr/local/bin/tor"
tor_geo_ip_file_path = "/usr/local/share/tor/geoip"
diff --git a/onionshare/mode_settings.py b/cli/onionshare_cli/mode_settings.py
index b353fcde..4e3a27ab 100644
--- a/onionshare/mode_settings.py
+++ b/cli/onionshare_cli/mode_settings.py
@@ -102,7 +102,7 @@ class ModeSettings:
elif self.common.platform == "Windows":
# On Windows, os.path.expanduser() needs to use backslash, or else it
# retains the forward slash, which breaks opening the folder in explorer.
- return os.path.expanduser("~\OnionShare")
+ return os.path.expanduser("~\\OnionShare")
else:
# All other OSes
return os.path.expanduser("~/OnionShare")
diff --git a/onionshare/onion.py b/cli/onionshare_cli/onion.py
index c66c0df4..6a42638a 100644
--- a/onionshare/onion.py
+++ b/cli/onionshare_cli/onion.py
@@ -25,9 +25,11 @@ from Crypto.PublicKey import RSA
import base64, os, sys, tempfile, shutil, urllib, platform, subprocess, time, shlex
from distutils.version import LooseVersion as Version
-from . import common, strings
+from . import common
from .settings import Settings
+# TODO: Figure out how to localize this for the GUI
+
class TorErrorAutomatic(Exception):
"""
@@ -150,7 +152,7 @@ class Onion(object):
is necessary for status updates to reach the GUI.
"""
- def __init__(self, common, use_tmp_dir=False):
+ def __init__(self, common, use_tmp_dir=False, get_tor_paths=None):
self.common = common
self.common.log("Onion", "__init__")
@@ -165,12 +167,14 @@ class Onion(object):
self.bundle_tor_supported = True
# Set the path of the tor binary, for bundled tor
+ if not get_tor_paths:
+ get_tor_paths = self.common.get_tor_paths
(
self.tor_path,
self.tor_geo_ip_file_path,
self.tor_geo_ipv6_file_path,
self.obfs4proxy_file_path,
- ) = self.common.get_tor_paths()
+ ) = get_tor_paths()
# The tor process
self.tor_proc = None
@@ -210,15 +214,14 @@ class Onion(object):
self.common.load_settings()
self.settings = self.common.settings
- strings.load_strings(self.common)
-
# The Tor controller
self.c = None
if self.settings.get("connection_type") == "bundled":
if not self.bundle_tor_supported:
raise BundledTorNotSupported(
- strings._("settings_error_bundled_tor_not_supported")
+ # strings._("settings_error_bundled_tor_not_supported")
+ "Using the Tor version that comes with OnionShare does not work in developer mode on Windows or macOS."
)
# Create a torrc for this session
@@ -244,7 +247,7 @@ class Onion(object):
try:
self.tor_socks_port = self.common.get_available_port(1000, 65535)
except:
- raise OSError(strings._("no_available_port"))
+ raise OSError("OnionShare port not available")
self.tor_torrc = os.path.join(self.tor_data_directory_name, "torrc")
if self.common.platform == "Windows" or self.common.platform == "Darwin":
@@ -256,7 +259,7 @@ class Onion(object):
try:
self.tor_control_port = self.common.get_available_port(1000, 65535)
except:
- raise OSError(strings._("no_available_port"))
+ raise OSError("OnionShare port not available")
self.tor_control_socket = None
else:
# Linux and BSD can use unix sockets
@@ -325,6 +328,10 @@ class Onion(object):
f.write(self.settings.get("tor_bridges_use_custom_bridges"))
f.write("\nUseBridges 1")
+ # Make sure the tor path is accurate
+ if not os.path.exists(self.tor_path):
+ raise BundledTorNotSupported(f"Cannot find tor binary: {self.tor_path}")
+
# Execute a tor subprocess
start_ts = time.time()
if self.common.platform == "Windows":
@@ -360,7 +367,8 @@ class Onion(object):
self.c.authenticate()
except Exception as e:
raise BundledTorBroken(
- strings._("settings_error_bundled_tor_broken").format(e.args[0])
+ # strings._("settings_error_bundled_tor_broken").format(e.args[0])
+ "OnionShare could not connect to Tor:\n{}".format(e.args[0])
)
while True:
@@ -409,7 +417,8 @@ class Onion(object):
try:
self.tor_proc.terminate()
raise BundledTorTimeout(
- strings._("settings_error_bundled_tor_timeout")
+ # strings._("settings_error_bundled_tor_timeout")
+ "Taking too long to connect to Tor. Maybe you aren't connected to the Internet, or have an inaccurate system clock?"
)
except FileNotFoundError:
pass
@@ -467,18 +476,27 @@ class Onion(object):
)
elif self.common.platform == "Windows":
# Windows doesn't support unix sockets
- raise TorErrorAutomatic(strings._("settings_error_automatic"))
+ raise TorErrorAutomatic(
+ # strings._("settings_error_automatic")
+ "Could not connect to the Tor controller. Is Tor Browser (available from torproject.org) running in the background?"
+ )
self.c = Controller.from_socket_file(path=socket_file_path)
except:
- raise TorErrorAutomatic(strings._("settings_error_automatic"))
+ raise TorErrorAutomatic(
+ # strings._("settings_error_automatic")
+ "Could not connect to the Tor controller. Is Tor Browser (available from torproject.org) running in the background?"
+ )
# Try authenticating
try:
self.c.authenticate()
except:
- raise TorErrorAutomatic(strings._("settings_error_automatic"))
+ raise TorErrorAutomatic(
+ # strings._("settings_error_automatic")
+ "Could not connect to the Tor controller. Is Tor Browser (available from torproject.org) running in the background?"
+ )
else:
# Use specific settings to connect to tor
@@ -495,19 +513,24 @@ class Onion(object):
path=self.settings.get("socket_file_path")
)
else:
- raise TorErrorInvalidSetting(strings._("settings_error_unknown"))
+ raise TorErrorInvalidSetting(
+ # strings._("settings_error_unknown")
+ "Can't connect to Tor controller because your settings don't make sense."
+ )
except:
if self.settings.get("connection_type") == "control_port":
raise TorErrorSocketPort(
- strings._("settings_error_socket_port").format(
+ # strings._("settings_error_socket_port")
+ "Can't connect to the Tor controller at {}:{}.".format(
self.settings.get("control_port_address"),
self.settings.get("control_port_port"),
)
)
else:
raise TorErrorSocketFile(
- strings._("settings_error_socket_file").format(
+ # strings._("settings_error_socket_file")
+ "Can't connect to the Tor controller using socket file {}.".format(
self.settings.get("socket_file_path")
)
)
@@ -519,19 +542,25 @@ class Onion(object):
elif self.settings.get("auth_type") == "password":
self.c.authenticate(self.settings.get("auth_password"))
else:
- raise TorErrorInvalidSetting(strings._("settings_error_unknown"))
+ raise TorErrorInvalidSetting(
+ # strings._("settings_error_unknown")
+ "Can't connect to Tor controller because your settings don't make sense."
+ )
except MissingPassword:
raise TorErrorMissingPassword(
- strings._("settings_error_missing_password")
+ # strings._("settings_error_missing_password")
+ "Connected to Tor controller, but it requires a password to authenticate."
)
except UnreadableCookieFile:
raise TorErrorUnreadableCookieFile(
- strings._("settings_error_unreadable_cookie_file")
+ # strings._("settings_error_unreadable_cookie_file")
+ "Connected to the Tor controller, but password may be wrong, or your user is not permitted to read the cookie file."
)
except AuthenticationFailure:
raise TorErrorAuthError(
- strings._("settings_error_auth").format(
+ # strings._("settings_error_auth")
+ "Connected to {}:{}, but can't authenticate. Maybe this isn't a Tor controller?".format(
self.settings.get("control_port_address"),
self.settings.get("control_port_port"),
)
@@ -590,9 +619,15 @@ class Onion(object):
self.common.log("Onion", "start_onion_service", f"port={port}")
if not self.supports_ephemeral:
- raise TorTooOld(strings._("error_ephemeral_not_supported"))
+ raise TorTooOld(
+ # strings._("error_ephemeral_not_supported")
+ "Your version of Tor is too old, ephemeral onion services are not supported"
+ )
if mode_settings.get("general", "client_auth") and not self.supports_stealth:
- raise TorTooOld(strings._("error_stealth_not_supported"))
+ raise TorTooOld(
+ # strings._("error_stealth_not_supported")
+ "Your version of Tor is too old, stealth onion services are not supported"
+ )
auth_cookie = None
if mode_settings.get("general", "client_auth"):
@@ -650,7 +685,8 @@ class Onion(object):
except ProtocolError as e:
raise TorErrorProtocolError(
- strings._("error_tor_protocol_error").format(e.args[0])
+ # strings._("error_tor_protocol_error")
+ "Tor error: {}".format(e.args[0])
)
onion_host = res.service_id + ".onion"
diff --git a/onionshare/onionshare.py b/cli/onionshare_cli/onionshare.py
index 25c8ad90..f74672ce 100644
--- a/onionshare/onionshare.py
+++ b/cli/onionshare_cli/onionshare.py
@@ -20,7 +20,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import os, shutil
-from . import common, strings
+from . import common
from .onion import TorTooOld, TorErrorProtocolError
from .common import AutoStopTimer
@@ -61,7 +61,7 @@ class OnionShare(object):
try:
self.port = self.common.get_available_port(17600, 17650)
except:
- raise OSError(strings._("no_available_port"))
+ raise OSError("Cannot find an available OnionShare port")
def start_onion_service(self, mode_settings, await_publication=True):
"""
diff --git a/share/static/css/style.css b/cli/onionshare_cli/resources/static/css/style.css
index 88d9cb79..88d9cb79 100644
--- a/share/static/css/style.css
+++ b/cli/onionshare_cli/resources/static/css/style.css
diff --git a/share/static/img/ajax.gif b/cli/onionshare_cli/resources/static/img/ajax.gif
index 01d955aa..01d955aa 100644
--- a/share/static/img/ajax.gif
+++ b/cli/onionshare_cli/resources/static/img/ajax.gif
Binary files differ
diff --git a/share/static/img/favicon.ico b/cli/onionshare_cli/resources/static/img/favicon.ico
index 63e65d8b..63e65d8b 100644
--- a/share/static/img/favicon.ico
+++ b/cli/onionshare_cli/resources/static/img/favicon.ico
Binary files differ
diff --git a/share/images/logo.png b/cli/onionshare_cli/resources/static/img/logo.png
index 43884c1f..43884c1f 100644
--- a/share/images/logo.png
+++ b/cli/onionshare_cli/resources/static/img/logo.png
Binary files differ
diff --git a/share/static/img/logo_large.png b/cli/onionshare_cli/resources/static/img/logo_large.png
index ee8f26ac..ee8f26ac 100644
--- a/share/static/img/logo_large.png
+++ b/cli/onionshare_cli/resources/static/img/logo_large.png
Binary files differ
diff --git a/share/static/img/web_file.png b/cli/onionshare_cli/resources/static/img/web_file.png
index 1931aff0..1931aff0 100644
--- a/share/static/img/web_file.png
+++ b/cli/onionshare_cli/resources/static/img/web_file.png
Binary files differ
diff --git a/share/static/img/web_folder.png b/cli/onionshare_cli/resources/static/img/web_folder.png
index 3ca5df21..3ca5df21 100644
--- a/share/static/img/web_folder.png
+++ b/cli/onionshare_cli/resources/static/img/web_folder.png
Binary files differ
diff --git a/share/static/js/chat.js b/cli/onionshare_cli/resources/static/js/chat.js
index 39547725..39547725 100644
--- a/share/static/js/chat.js
+++ b/cli/onionshare_cli/resources/static/js/chat.js
diff --git a/share/static/js/jquery-3.5.1.min.js b/cli/onionshare_cli/resources/static/js/jquery-3.5.1.min.js
index b0614034..b0614034 100644
--- a/share/static/js/jquery-3.5.1.min.js
+++ b/cli/onionshare_cli/resources/static/js/jquery-3.5.1.min.js
diff --git a/share/static/js/receive.js b/cli/onionshare_cli/resources/static/js/receive.js
index eac67412..eac67412 100644
--- a/share/static/js/receive.js
+++ b/cli/onionshare_cli/resources/static/js/receive.js
diff --git a/share/static/js/send.js b/cli/onionshare_cli/resources/static/js/send.js
index 43e9892d..43e9892d 100644
--- a/share/static/js/send.js
+++ b/cli/onionshare_cli/resources/static/js/send.js
diff --git a/share/static/js/socket.io.min.js b/cli/onionshare_cli/resources/static/js/socket.io.min.js
index b622e1b9..b622e1b9 100644
--- a/share/static/js/socket.io.min.js
+++ b/cli/onionshare_cli/resources/static/js/socket.io.min.js
diff --git a/share/templates/401.html b/cli/onionshare_cli/resources/templates/401.html
index 5e43ca01..5e43ca01 100644
--- a/share/templates/401.html
+++ b/cli/onionshare_cli/resources/templates/401.html
diff --git a/share/templates/403.html b/cli/onionshare_cli/resources/templates/403.html
index c9d28eea..c9d28eea 100644
--- a/share/templates/403.html
+++ b/cli/onionshare_cli/resources/templates/403.html
diff --git a/share/templates/404.html b/cli/onionshare_cli/resources/templates/404.html
index e816f2c4..e816f2c4 100644
--- a/share/templates/404.html
+++ b/cli/onionshare_cli/resources/templates/404.html
diff --git a/share/templates/405.html b/cli/onionshare_cli/resources/templates/405.html
index 63888004..63888004 100644
--- a/share/templates/405.html
+++ b/cli/onionshare_cli/resources/templates/405.html
diff --git a/share/templates/chat.html b/cli/onionshare_cli/resources/templates/chat.html
index b4443c09..b4443c09 100644
--- a/share/templates/chat.html
+++ b/cli/onionshare_cli/resources/templates/chat.html
diff --git a/share/templates/denied.html b/cli/onionshare_cli/resources/templates/denied.html
index 49147ef2..49147ef2 100644
--- a/share/templates/denied.html
+++ b/cli/onionshare_cli/resources/templates/denied.html
diff --git a/share/templates/listing.html b/cli/onionshare_cli/resources/templates/listing.html
index ea050710..ea050710 100644
--- a/share/templates/listing.html
+++ b/cli/onionshare_cli/resources/templates/listing.html
diff --git a/share/templates/receive.html b/cli/onionshare_cli/resources/templates/receive.html
index 20f4bb7e..20f4bb7e 100644
--- a/share/templates/receive.html
+++ b/cli/onionshare_cli/resources/templates/receive.html
diff --git a/share/templates/send.html b/cli/onionshare_cli/resources/templates/send.html
index dd30bfdd..dd30bfdd 100644
--- a/share/templates/send.html
+++ b/cli/onionshare_cli/resources/templates/send.html
diff --git a/share/templates/thankyou.html b/cli/onionshare_cli/resources/templates/thankyou.html
index aa0bc553..aa0bc553 100644
--- a/share/templates/thankyou.html
+++ b/cli/onionshare_cli/resources/templates/thankyou.html
diff --git a/share/torrc_template b/cli/onionshare_cli/resources/torrc_template
index 8ac9e1ef..8ac9e1ef 100644
--- a/share/torrc_template
+++ b/cli/onionshare_cli/resources/torrc_template
diff --git a/share/torrc_template-meek_lite_amazon b/cli/onionshare_cli/resources/torrc_template-meek_lite_amazon
index 606ae889..606ae889 100644
--- a/share/torrc_template-meek_lite_amazon
+++ b/cli/onionshare_cli/resources/torrc_template-meek_lite_amazon
diff --git a/share/torrc_template-meek_lite_azure b/cli/onionshare_cli/resources/torrc_template-meek_lite_azure
index a9b374ba..a9b374ba 100644
--- a/share/torrc_template-meek_lite_azure
+++ b/cli/onionshare_cli/resources/torrc_template-meek_lite_azure
diff --git a/share/torrc_template-obfs4 b/cli/onionshare_cli/resources/torrc_template-obfs4
index 306c456c..306c456c 100644
--- a/share/torrc_template-obfs4
+++ b/cli/onionshare_cli/resources/torrc_template-obfs4
diff --git a/cli/onionshare_cli/resources/version.txt b/cli/onionshare_cli/resources/version.txt
new file mode 100644
index 00000000..355ca743
--- /dev/null
+++ b/cli/onionshare_cli/resources/version.txt
@@ -0,0 +1 @@
+2.3.dev2 \ No newline at end of file
diff --git a/share/wordlist.txt b/cli/onionshare_cli/resources/wordlist.txt
index caf71f52..caf71f52 100644
--- a/share/wordlist.txt
+++ b/cli/onionshare_cli/resources/wordlist.txt
diff --git a/onionshare/settings.py b/cli/onionshare_cli/settings.py
index 6b6ed6ab..82fcd6b9 100644
--- a/onionshare/settings.py
+++ b/cli/onionshare_cli/settings.py
@@ -29,8 +29,6 @@ try:
except:
pass
-from . import strings
-
class Settings(object):
"""
diff --git a/onionshare/web/__init__.py b/cli/onionshare_cli/web/__init__.py
index f036d011..f036d011 100644
--- a/onionshare/web/__init__.py
+++ b/cli/onionshare_cli/web/__init__.py
diff --git a/onionshare/web/chat_mode.py b/cli/onionshare_cli/web/chat_mode.py
index 15e236d3..15e236d3 100644
--- a/onionshare/web/chat_mode.py
+++ b/cli/onionshare_cli/web/chat_mode.py
diff --git a/onionshare/web/receive_mode.py b/cli/onionshare_cli/web/receive_mode.py
index a9876c40..a0da0d3c 100644
--- a/onionshare/web/receive_mode.py
+++ b/cli/onionshare_cli/web/receive_mode.py
@@ -25,8 +25,6 @@ from datetime import datetime
from flask import Request, request, render_template, make_response, flash, redirect
from werkzeug.utils import secure_filename
-from .. import strings
-
class ReceiveModeWeb:
"""
@@ -126,8 +124,6 @@ class ReceiveModeWeb:
flash(msg, "error")
return redirect("/")
- # Note that flash strings are in English, and not translated, on purpose,
- # to avoid leaking the locale of the OnionShare user
if ajax:
info_flashes = []
diff --git a/onionshare/web/send_base_mode.py b/cli/onionshare_cli/web/send_base_mode.py
index 9d5f876b..f9db28c6 100644
--- a/onionshare/web/send_base_mode.py
+++ b/cli/onionshare_cli/web/send_base_mode.py
@@ -25,8 +25,6 @@ import mimetypes
import gzip
from flask import Response, request, render_template, make_response
-from .. import strings
-
class SendBaseModeWeb:
"""
diff --git a/onionshare/web/share_mode.py b/cli/onionshare_cli/web/share_mode.py
index ccd29e1c..39c82d31 100644
--- a/onionshare/web/share_mode.py
+++ b/cli/onionshare_cli/web/share_mode.py
@@ -26,7 +26,6 @@ import mimetypes
from flask import Response, request, render_template, make_response
from .send_base_mode import SendBaseModeWeb
-from .. import strings
class ShareModeWeb(SendBaseModeWeb):
diff --git a/onionshare/web/web.py b/cli/onionshare_cli/web/web.py
index 117ea83a..14d780c3 100644
--- a/onionshare/web/web.py
+++ b/cli/onionshare_cli/web/web.py
@@ -42,8 +42,6 @@ from flask import (
from flask_httpauth import HTTPBasicAuth
from flask_socketio import SocketIO
-from .. import strings
-
from .share_mode import ShareModeWeb
from .receive_mode import ReceiveModeWeb, ReceiveModeWSGIMiddleware, ReceiveModeRequest
from .website_mode import WebsiteModeWeb
diff --git a/onionshare/web/website_mode.py b/cli/onionshare_cli/web/website_mode.py
index 2838fc05..ef37ab12 100644
--- a/onionshare/web/website_mode.py
+++ b/cli/onionshare_cli/web/website_mode.py
@@ -25,7 +25,6 @@ import mimetypes
from flask import Response, request, render_template, make_response
from .send_base_mode import SendBaseModeWeb
-from .. import strings
class WebsiteModeWeb(SendBaseModeWeb):
diff --git a/cli/poetry.lock b/cli/poetry.lock
new file mode 100644
index 00000000..00331cc4
--- /dev/null
+++ b/cli/poetry.lock
@@ -0,0 +1,603 @@
+[[package]]
+name = "atomicwrites"
+version = "1.4.0"
+description = "Atomic file writes."
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+
+[[package]]
+name = "attrs"
+version = "20.3.0"
+description = "Classes Without Boilerplate"
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+
+[package.extras]
+dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "furo", "sphinx", "pre-commit"]
+docs = ["furo", "sphinx", "zope.interface"]
+tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"]
+tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"]
+
+[[package]]
+name = "certifi"
+version = "2020.11.8"
+description = "Python package for providing Mozilla's CA Bundle."
+category = "main"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "chardet"
+version = "3.0.4"
+description = "Universal encoding detector for Python 2 and 3"
+category = "main"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "click"
+version = "7.1.2"
+description = "Composable command line interface toolkit"
+category = "main"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+
+[[package]]
+name = "colorama"
+version = "0.4.4"
+description = "Cross-platform colored terminal text."
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+
+[[package]]
+name = "dnspython"
+version = "1.16.0"
+description = "DNS toolkit"
+category = "main"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+
+[package.extras]
+DNSSEC = ["pycryptodome", "ecdsa (>=0.13)"]
+IDNA = ["idna (>=2.1)"]
+
+[[package]]
+name = "eventlet"
+version = "0.29.1"
+description = "Highly concurrent networking library"
+category = "main"
+optional = false
+python-versions = "*"
+
+[package.dependencies]
+dnspython = ">=1.15.0,<2.0.0"
+greenlet = ">=0.3"
+six = ">=1.10.0"
+
+[[package]]
+name = "flask"
+version = "1.1.2"
+description = "A simple framework for building complex web applications."
+category = "main"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+
+[package.dependencies]
+click = ">=5.1"
+itsdangerous = ">=0.24"
+Jinja2 = ">=2.10.1"
+Werkzeug = ">=0.15"
+
+[package.extras]
+dev = ["pytest", "coverage", "tox", "sphinx", "pallets-sphinx-themes", "sphinxcontrib-log-cabinet", "sphinx-issues"]
+docs = ["sphinx", "pallets-sphinx-themes", "sphinxcontrib-log-cabinet", "sphinx-issues"]
+dotenv = ["python-dotenv"]
+
+[[package]]
+name = "flask-httpauth"
+version = "4.1.0"
+description = "Basic and Digest HTTP authentication for Flask routes"
+category = "main"
+optional = false
+python-versions = "*"
+
+[package.dependencies]
+Flask = "*"
+
+[[package]]
+name = "flask-socketio"
+version = "4.3.1"
+description = "Socket.IO integration for Flask applications"
+category = "main"
+optional = false
+python-versions = "*"
+
+[package.dependencies]
+Flask = ">=0.9"
+python-socketio = ">=4.3.0"
+
+[[package]]
+name = "greenlet"
+version = "0.4.17"
+description = "Lightweight in-process concurrent programming"
+category = "main"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "idna"
+version = "2.10"
+description = "Internationalized Domain Names in Applications (IDNA)"
+category = "main"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+
+[[package]]
+name = "importlib-metadata"
+version = "2.0.0"
+description = "Read metadata from Python packages"
+category = "dev"
+optional = false
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
+
+[package.dependencies]
+zipp = ">=0.5"
+
+[package.extras]
+docs = ["sphinx", "rst.linker"]
+testing = ["packaging", "pep517", "importlib-resources (>=1.3)"]
+
+[[package]]
+name = "iniconfig"
+version = "1.1.1"
+description = "iniconfig: brain-dead simple config-ini parsing"
+category = "dev"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "itsdangerous"
+version = "1.1.0"
+description = "Various helpers to pass data to untrusted environments and back."
+category = "main"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+
+[[package]]
+name = "jinja2"
+version = "2.11.2"
+description = "A very fast and expressive template engine."
+category = "main"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+
+[package.dependencies]
+MarkupSafe = ">=0.23"
+
+[package.extras]
+i18n = ["Babel (>=0.8)"]
+
+[[package]]
+name = "markupsafe"
+version = "1.1.1"
+description = "Safely add untrusted strings to HTML/XML markup."
+category = "main"
+optional = false
+python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*"
+
+[[package]]
+name = "packaging"
+version = "20.4"
+description = "Core utilities for Python packages"
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+
+[package.dependencies]
+pyparsing = ">=2.0.2"
+six = "*"
+
+[[package]]
+name = "pluggy"
+version = "0.13.1"
+description = "plugin and hook calling mechanisms for python"
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+
+[package.dependencies]
+importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
+
+[package.extras]
+dev = ["pre-commit", "tox"]
+
+[[package]]
+name = "py"
+version = "1.9.0"
+description = "library with cross-python path, ini-parsing, io, code, log facilities"
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+
+[[package]]
+name = "pycryptodome"
+version = "3.9.9"
+description = "Cryptographic library for Python"
+category = "main"
+optional = false
+python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+
+[[package]]
+name = "pyparsing"
+version = "2.4.7"
+description = "Python parsing module"
+category = "dev"
+optional = false
+python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
+
+[[package]]
+name = "pysocks"
+version = "1.7.1"
+description = "A Python SOCKS client module. See https://github.com/Anorov/PySocks for more information."
+category = "main"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+
+[[package]]
+name = "pytest"
+version = "6.1.2"
+description = "pytest: simple powerful testing with Python"
+category = "dev"
+optional = false
+python-versions = ">=3.5"
+
+[package.dependencies]
+atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""}
+attrs = ">=17.4.0"
+colorama = {version = "*", markers = "sys_platform == \"win32\""}
+importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
+iniconfig = "*"
+packaging = "*"
+pluggy = ">=0.12,<1.0"
+py = ">=1.8.2"
+toml = "*"
+
+[package.extras]
+checkqa_mypy = ["mypy (==0.780)"]
+testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"]
+
+[[package]]
+name = "python-engineio"
+version = "3.13.2"
+description = "Engine.IO server"
+category = "main"
+optional = false
+python-versions = "*"
+
+[package.dependencies]
+six = ">=1.9.0"
+
+[package.extras]
+asyncio_client = ["aiohttp (>=3.4)"]
+client = ["requests (>=2.21.0)", "websocket-client (>=0.54.0)"]
+
+[[package]]
+name = "python-socketio"
+version = "4.6.0"
+description = "Socket.IO server"
+category = "main"
+optional = false
+python-versions = "*"
+
+[package.dependencies]
+python-engineio = ">=3.13.0"
+six = ">=1.9.0"
+
+[package.extras]
+asyncio_client = ["aiohttp (>=3.4)", "websockets (>=7.0)"]
+client = ["requests (>=2.21.0)", "websocket-client (>=0.54.0)"]
+
+[[package]]
+name = "requests"
+version = "2.24.0"
+description = "Python HTTP for Humans."
+category = "main"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+
+[package.dependencies]
+certifi = ">=2017.4.17"
+chardet = ">=3.0.2,<4"
+idna = ">=2.5,<3"
+urllib3 = ">=1.21.1,<1.25.0 || >1.25.0,<1.25.1 || >1.25.1,<1.26"
+
+[package.extras]
+security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"]
+socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"]
+
+[[package]]
+name = "six"
+version = "1.15.0"
+description = "Python 2 and 3 compatibility utilities"
+category = "main"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
+
+[[package]]
+name = "stem"
+version = "1.8.0"
+description = "Stem is a Python controller library that allows applications to interact with Tor (https://www.torproject.org/)."
+category = "main"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "toml"
+version = "0.10.2"
+description = "Python Library for Tom's Obvious, Minimal Language"
+category = "dev"
+optional = false
+python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
+
+[[package]]
+name = "urllib3"
+version = "1.25.11"
+description = "HTTP library with thread-safe connection pooling, file post, and more."
+category = "main"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
+
+[package.extras]
+brotli = ["brotlipy (>=0.6.0)"]
+secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"]
+socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
+
+[[package]]
+name = "werkzeug"
+version = "1.0.1"
+description = "The comprehensive WSGI web application library."
+category = "main"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+
+[package.extras]
+dev = ["pytest", "pytest-timeout", "coverage", "tox", "sphinx", "pallets-sphinx-themes", "sphinx-issues"]
+watchdog = ["watchdog"]
+
+[[package]]
+name = "zipp"
+version = "3.4.0"
+description = "Backport of pathlib-compatible object wrapper for zip files"
+category = "dev"
+optional = false
+python-versions = ">=3.6"
+
+[package.extras]
+docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"]
+testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "jaraco.test (>=3.2.0)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"]
+
+[metadata]
+lock-version = "1.1"
+python-versions = "^3.6"
+content-hash = "3947b230139f4b699f40c97e0b90d8c8ab6d3d7ef9093d16d2acb507131e14da"
+
+[metadata.files]
+atomicwrites = [
+ {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"},
+ {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"},
+]
+attrs = [
+ {file = "attrs-20.3.0-py2.py3-none-any.whl", hash = "sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6"},
+ {file = "attrs-20.3.0.tar.gz", hash = "sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700"},
+]
+certifi = [
+ {file = "certifi-2020.11.8-py2.py3-none-any.whl", hash = "sha256:1f422849db327d534e3d0c5f02a263458c3955ec0aae4ff09b95f195c59f4edd"},
+ {file = "certifi-2020.11.8.tar.gz", hash = "sha256:f05def092c44fbf25834a51509ef6e631dc19765ab8a57b4e7ab85531f0a9cf4"},
+]
+chardet = [
+ {file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"},
+ {file = "chardet-3.0.4.tar.gz", hash = "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"},
+]
+click = [
+ {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"},
+ {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"},
+]
+colorama = [
+ {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
+ {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"},
+]
+dnspython = [
+ {file = "dnspython-1.16.0-py2.py3-none-any.whl", hash = "sha256:f69c21288a962f4da86e56c4905b49d11aba7938d3d740e80d9e366ee4f1632d"},
+ {file = "dnspython-1.16.0.zip", hash = "sha256:36c5e8e38d4369a08b6780b7f27d790a292b2b08eea01607865bf0936c558e01"},
+]
+eventlet = [
+ {file = "eventlet-0.29.1-py2.py3-none-any.whl", hash = "sha256:a07b8c8e1f43bc4c44a255baeb066a4edce783dcfacae213bcabb95fdcd02d8c"},
+ {file = "eventlet-0.29.1.tar.gz", hash = "sha256:9faff63631b01277c463ae91cd4ab3f25a2f0f5abe3219d43a386ef1daa6159a"},
+]
+flask = [
+ {file = "Flask-1.1.2-py2.py3-none-any.whl", hash = "sha256:8a4fdd8936eba2512e9c85df320a37e694c93945b33ef33c89946a340a238557"},
+ {file = "Flask-1.1.2.tar.gz", hash = "sha256:4efa1ae2d7c9865af48986de8aeb8504bf32c7f3d6fdc9353d34b21f4b127060"},
+]
+flask-httpauth = [
+ {file = "Flask-HTTPAuth-4.1.0.tar.gz", hash = "sha256:9e028e4375039a49031eb9ecc40be4761f0540476040f6eff329a31dabd4d000"},
+ {file = "Flask_HTTPAuth-4.1.0-py2.py3-none-any.whl", hash = "sha256:29e0288869a213c7387f0323b6bf2c7191584fb1da8aa024d9af118e5cd70de7"},
+]
+flask-socketio = [
+ {file = "Flask-SocketIO-4.3.1.tar.gz", hash = "sha256:36c1d5765010d1f4e4f05b4cc9c20c289d9dc70698c88d1addd0afcfedc5b062"},
+ {file = "Flask_SocketIO-4.3.1-py2.py3-none-any.whl", hash = "sha256:3668675bf7763c5b5f56689d439f07356e89c0a52e0c9e9cd3cc08563c07b252"},
+]
+greenlet = [
+ {file = "greenlet-0.4.17-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:75e4c27188f28149b74e7685809f9227410fd15432a4438fc48627f518577fa5"},
+ {file = "greenlet-0.4.17-cp27-cp27m-win32.whl", hash = "sha256:3af587e9813f9bd8be9212722321a5e7be23b2bc37e6323a90e592ab0c2ef117"},
+ {file = "greenlet-0.4.17-cp27-cp27m-win_amd64.whl", hash = "sha256:ccd62f09f90b2730150d82f2f2ffc34d73c6ce7eac234aed04d15dc8a3023994"},
+ {file = "greenlet-0.4.17-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:13037e2d7ab2145300676852fa069235512fdeba4ed1e3bb4b0677a04223c525"},
+ {file = "greenlet-0.4.17-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:e495096e3e2e8f7192afb6aaeba19babc4fb2bdf543d7b7fed59e00c1df7f170"},
+ {file = "greenlet-0.4.17-cp35-cp35m-win32.whl", hash = "sha256:124a3ae41215f71dc91d1a3d45cbf2f84e46b543e5d60b99ecc20e24b4c8f272"},
+ {file = "greenlet-0.4.17-cp35-cp35m-win_amd64.whl", hash = "sha256:5494e3baeacc371d988345fbf8aa4bd15555b3077c40afcf1994776bb6d77eaf"},
+ {file = "greenlet-0.4.17-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:bee111161420f341a346731279dd976be161b465c1286f82cc0779baf7b729e8"},
+ {file = "greenlet-0.4.17-cp36-cp36m-win32.whl", hash = "sha256:ac85db59aa43d78547f95fc7b6fd2913e02b9e9b09e2490dfb7bbdf47b2a4914"},
+ {file = "greenlet-0.4.17-cp36-cp36m-win_amd64.whl", hash = "sha256:4481002118b2f1588fa3d821936ffdc03db80ef21186b62b90c18db4ba5e743b"},
+ {file = "greenlet-0.4.17-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:be7a79988b8fdc5bbbeaed69e79cfb373da9759242f1565668be4fb7f3f37552"},
+ {file = "greenlet-0.4.17-cp37-cp37m-win32.whl", hash = "sha256:97f2b01ab622a4aa4b3724a3e1fba66f47f054c434fbaa551833fa2b41e3db51"},
+ {file = "greenlet-0.4.17-cp37-cp37m-win_amd64.whl", hash = "sha256:d3436110ca66fe3981031cc6aff8cc7a40d8411d173dde73ddaa5b8445385e2d"},
+ {file = "greenlet-0.4.17-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:a34023b9eabb3525ee059f3bf33a417d2e437f7f17e341d334987d4091ae6072"},
+ {file = "greenlet-0.4.17-cp38-cp38-win32.whl", hash = "sha256:e66a824f44892bc4ec66c58601a413419cafa9cec895e63d8da889c8a1a4fa4a"},
+ {file = "greenlet-0.4.17-cp38-cp38-win_amd64.whl", hash = "sha256:47825c3a109f0331b1e54c1173d4e57fa000aa6c96756b62852bfa1af91cd652"},
+ {file = "greenlet-0.4.17-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:1023d7b43ca11264ab7052cb09f5635d4afdb43df55e0854498fc63070a0b206"},
+ {file = "greenlet-0.4.17.tar.gz", hash = "sha256:41d8835c69a78de718e466dd0e6bfd4b46125f21a67c3ff6d76d8d8059868d6b"},
+]
+idna = [
+ {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"},
+ {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"},
+]
+importlib-metadata = [
+ {file = "importlib_metadata-2.0.0-py2.py3-none-any.whl", hash = "sha256:cefa1a2f919b866c5beb7c9f7b0ebb4061f30a8a9bf16d609b000e2dfaceb9c3"},
+ {file = "importlib_metadata-2.0.0.tar.gz", hash = "sha256:77a540690e24b0305878c37ffd421785a6f7e53c8b5720d211b211de8d0e95da"},
+]
+iniconfig = [
+ {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"},
+ {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"},
+]
+itsdangerous = [
+ {file = "itsdangerous-1.1.0-py2.py3-none-any.whl", hash = "sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749"},
+ {file = "itsdangerous-1.1.0.tar.gz", hash = "sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19"},
+]
+jinja2 = [
+ {file = "Jinja2-2.11.2-py2.py3-none-any.whl", hash = "sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035"},
+ {file = "Jinja2-2.11.2.tar.gz", hash = "sha256:89aab215427ef59c34ad58735269eb58b1a5808103067f7bb9d5836c651b3bb0"},
+]
+markupsafe = [
+ {file = "MarkupSafe-1.1.1-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161"},
+ {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"},
+ {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183"},
+ {file = "MarkupSafe-1.1.1-cp27-cp27m-win32.whl", hash = "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b"},
+ {file = "MarkupSafe-1.1.1-cp27-cp27m-win_amd64.whl", hash = "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e"},
+ {file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f"},
+ {file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1"},
+ {file = "MarkupSafe-1.1.1-cp34-cp34m-macosx_10_6_intel.whl", hash = "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5"},
+ {file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1"},
+ {file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735"},
+ {file = "MarkupSafe-1.1.1-cp34-cp34m-win32.whl", hash = "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21"},
+ {file = "MarkupSafe-1.1.1-cp34-cp34m-win_amd64.whl", hash = "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235"},
+ {file = "MarkupSafe-1.1.1-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b"},
+ {file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f"},
+ {file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905"},
+ {file = "MarkupSafe-1.1.1-cp35-cp35m-win32.whl", hash = "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1"},
+ {file = "MarkupSafe-1.1.1-cp35-cp35m-win_amd64.whl", hash = "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d"},
+ {file = "MarkupSafe-1.1.1-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff"},
+ {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473"},
+ {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e"},
+ {file = "MarkupSafe-1.1.1-cp36-cp36m-win32.whl", hash = "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66"},
+ {file = "MarkupSafe-1.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5"},
+ {file = "MarkupSafe-1.1.1-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d"},
+ {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e"},
+ {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6"},
+ {file = "MarkupSafe-1.1.1-cp37-cp37m-win32.whl", hash = "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2"},
+ {file = "MarkupSafe-1.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c"},
+ {file = "MarkupSafe-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15"},
+ {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2"},
+ {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42"},
+ {file = "MarkupSafe-1.1.1-cp38-cp38-win32.whl", hash = "sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b"},
+ {file = "MarkupSafe-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be"},
+ {file = "MarkupSafe-1.1.1.tar.gz", hash = "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b"},
+]
+packaging = [
+ {file = "packaging-20.4-py2.py3-none-any.whl", hash = "sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181"},
+ {file = "packaging-20.4.tar.gz", hash = "sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8"},
+]
+pluggy = [
+ {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"},
+ {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"},
+]
+py = [
+ {file = "py-1.9.0-py2.py3-none-any.whl", hash = "sha256:366389d1db726cd2fcfc79732e75410e5fe4d31db13692115529d34069a043c2"},
+ {file = "py-1.9.0.tar.gz", hash = "sha256:9ca6883ce56b4e8da7e79ac18787889fa5206c79dcc67fb065376cd2fe03f342"},
+]
+pycryptodome = [
+ {file = "pycryptodome-3.9.9-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:5598dc6c9dbfe882904e54584322893eff185b98960bbe2cdaaa20e8a437b6e5"},
+ {file = "pycryptodome-3.9.9-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:1cfdb92dca388e27e732caa72a1cc624520fe93752a665c3b6cd8f1a91b34916"},
+ {file = "pycryptodome-3.9.9-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5f19e6ef750f677d924d9c7141f54bade3cd56695bbfd8a9ef15d0378557dfe4"},
+ {file = "pycryptodome-3.9.9-cp27-cp27m-win32.whl", hash = "sha256:a3d8a9efa213be8232c59cdc6b65600276508e375e0a119d710826248fd18d37"},
+ {file = "pycryptodome-3.9.9-cp27-cp27m-win_amd64.whl", hash = "sha256:50826b49fbca348a61529693b0031cdb782c39060fb9dca5ac5dff858159dc5a"},
+ {file = "pycryptodome-3.9.9-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:19cb674df6c74a14b8b408aa30ba8a89bd1c01e23505100fb45f930fbf0ed0d9"},
+ {file = "pycryptodome-3.9.9-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:28f75e58d02019a7edc7d4135203d2501dfc47256d175c72c9798f9a129a49a7"},
+ {file = "pycryptodome-3.9.9-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:6d3baaf82681cfb1a842f1c8f77beac791ceedd99af911e4f5fabec32bae2259"},
+ {file = "pycryptodome-3.9.9-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:946399d15eccebafc8ce0257fc4caffe383c75e6b0633509bd011e357368306c"},
+ {file = "pycryptodome-3.9.9-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:eb01f9997e4d6a8ec8a1ad1f676ba5a362781ff64e8189fe2985258ba9cb9706"},
+ {file = "pycryptodome-3.9.9-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:411745c6dce4eff918906eebcde78771d44795d747e194462abb120d2e537cd9"},
+ {file = "pycryptodome-3.9.9-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:8f9f84059039b672a5a705b3c5aa21747867bacc30a72e28bf0d147cc8ef85ed"},
+ {file = "pycryptodome-3.9.9-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:7798e73225a699651888489fbb1dbc565e03a509942a8ce6194bbe6fb582a41f"},
+ {file = "pycryptodome-3.9.9-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:46e96aeb8a9ca8b1edf9b1fd0af4bf6afcf3f1ca7fa35529f5d60b98f3e4e959"},
+ {file = "pycryptodome-3.9.9-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:843e5f10ecdf9d307032b8b91afe9da1d6ed5bb89d0bbec5c8dcb4ba44008e11"},
+ {file = "pycryptodome-3.9.9-cp36-cp36m-win32.whl", hash = "sha256:b68794fba45bdb367eeb71249c26d23e61167510a1d0c3d6cf0f2f14636e62ee"},
+ {file = "pycryptodome-3.9.9-cp36-cp36m-win_amd64.whl", hash = "sha256:60febcf5baf70c566d9d9351c47fbd8321da9a4edf2eff45c4c31c86164ca794"},
+ {file = "pycryptodome-3.9.9-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:4ed27951b0a17afd287299e2206a339b5b6d12de9321e1a1575261ef9c4a851b"},
+ {file = "pycryptodome-3.9.9-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:9000877383e2189dafd1b2fc68c6c726eca9a3cfb6d68148fbb72ccf651959b6"},
+ {file = "pycryptodome-3.9.9-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:faa682c404c218e8788c3126c9a4b8fbcc54dc245b5b6e8ea5b46f3b63bd0c84"},
+ {file = "pycryptodome-3.9.9-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:62c488a21c253dadc9f731a32f0ac61e4e436d81a1ea6f7d1d9146ed4d20d6bd"},
+ {file = "pycryptodome-3.9.9-cp37-cp37m-win32.whl", hash = "sha256:834b790bbb6bd18956f625af4004d9c15eed12d5186d8e57851454ae76d52215"},
+ {file = "pycryptodome-3.9.9-cp37-cp37m-win_amd64.whl", hash = "sha256:70d807d11d508433daf96244ec1c64e55039e8a35931fc5ea9eee94dbe3cb6b5"},
+ {file = "pycryptodome-3.9.9-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:27397aee992af69d07502126561d851ba3845aa808f0e55c71ad0efa264dd7d4"},
+ {file = "pycryptodome-3.9.9-cp38-cp38-manylinux1_i686.whl", hash = "sha256:d7ec2bd8f57c559dd24e71891c51c25266a8deb66fc5f02cc97c7fb593d1780a"},
+ {file = "pycryptodome-3.9.9-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:e15bde67ccb7d4417f627dd16ffe2f5a4c2941ce5278444e884cb26d73ecbc61"},
+ {file = "pycryptodome-3.9.9-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:5c3c4865730dfb0263f822b966d6d58429d8b1e560d1ddae37685fd9e7c63161"},
+ {file = "pycryptodome-3.9.9-cp38-cp38-win32.whl", hash = "sha256:76b1a34d74bb2c91bce460cdc74d1347592045627a955e9a252554481c17c52f"},
+ {file = "pycryptodome-3.9.9-cp38-cp38-win_amd64.whl", hash = "sha256:6e4227849e4231a3f5b35ea5bdedf9a82b3883500e5624f00a19156e9a9ef861"},
+ {file = "pycryptodome-3.9.9-cp39-cp39-manylinux1_i686.whl", hash = "sha256:2a68df525b387201a43b27b879ce8c08948a430e883a756d6c9e3acdaa7d7bd8"},
+ {file = "pycryptodome-3.9.9-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:a4599c0ca0fc027c780c1c45ed996d5bef03e571470b7b1c7171ec1e1a90914c"},
+ {file = "pycryptodome-3.9.9-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:b4e6b269a8ddaede774e5c3adbef6bf452ee144e6db8a716d23694953348cd86"},
+ {file = "pycryptodome-3.9.9-cp39-cp39-win32.whl", hash = "sha256:a199e9ca46fc6e999e5f47fce342af4b56c7de85fae893c69ab6aa17531fb1e1"},
+ {file = "pycryptodome-3.9.9-cp39-cp39-win_amd64.whl", hash = "sha256:6e89bb3826e6f84501e8e3b205c22595d0c5492c2f271cbb9ee1c48eb1866645"},
+ {file = "pycryptodome-3.9.9.tar.gz", hash = "sha256:910e202a557e1131b1c1b3f17a63914d57aac55cf9fb9b51644962841c3995c4"},
+]
+pyparsing = [
+ {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"},
+ {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"},
+]
+pysocks = [
+ {file = "PySocks-1.7.1-py27-none-any.whl", hash = "sha256:08e69f092cc6dbe92a0fdd16eeb9b9ffbc13cadfe5ca4c7bd92ffb078b293299"},
+ {file = "PySocks-1.7.1-py3-none-any.whl", hash = "sha256:2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5"},
+ {file = "PySocks-1.7.1.tar.gz", hash = "sha256:3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0"},
+]
+pytest = [
+ {file = "pytest-6.1.2-py3-none-any.whl", hash = "sha256:4288fed0d9153d9646bfcdf0c0428197dba1ecb27a33bb6e031d002fa88653fe"},
+ {file = "pytest-6.1.2.tar.gz", hash = "sha256:c0a7e94a8cdbc5422a51ccdad8e6f1024795939cc89159a0ae7f0b316ad3823e"},
+]
+python-engineio = [
+ {file = "python-engineio-3.13.2.tar.gz", hash = "sha256:36b33c6aa702d9b6a7f527eec6387a2da1a9a24484ec2f086d76576413cef04b"},
+ {file = "python_engineio-3.13.2-py2.py3-none-any.whl", hash = "sha256:cfded18156862f94544a9f8ef37f56727df731c8552d7023f5afee8369be2db6"},
+]
+python-socketio = [
+ {file = "python-socketio-4.6.0.tar.gz", hash = "sha256:358d8fbbc029c4538ea25bcaa283e47f375be0017fcba829de8a3a731c9df25a"},
+ {file = "python_socketio-4.6.0-py2.py3-none-any.whl", hash = "sha256:d437f797c44b6efba2f201867cf02b8c96b97dff26d4e4281ac08b45817cd522"},
+]
+requests = [
+ {file = "requests-2.24.0-py2.py3-none-any.whl", hash = "sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898"},
+ {file = "requests-2.24.0.tar.gz", hash = "sha256:b3559a131db72c33ee969480840fff4bb6dd111de7dd27c8ee1f820f4f00231b"},
+]
+six = [
+ {file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"},
+ {file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"},
+]
+stem = [
+ {file = "stem-1.8.0.tar.gz", hash = "sha256:a0b48ea6224e95f22aa34c0bc3415f0eb4667ddeae3dfb5e32a6920c185568c2"},
+]
+toml = [
+ {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
+ {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
+]
+urllib3 = [
+ {file = "urllib3-1.25.11-py2.py3-none-any.whl", hash = "sha256:f5321fbe4bf3fefa0efd0bfe7fb14e90909eb62a48ccda331726b4319897dd5e"},
+ {file = "urllib3-1.25.11.tar.gz", hash = "sha256:8d7eaa5a82a1cac232164990f04874c594c9453ec55eef02eab885aa02fc17a2"},
+]
+werkzeug = [
+ {file = "Werkzeug-1.0.1-py2.py3-none-any.whl", hash = "sha256:2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43"},
+ {file = "Werkzeug-1.0.1.tar.gz", hash = "sha256:6c80b1e5ad3665290ea39320b91e1be1e0d5f60652b964a3070216de83d2e47c"},
+]
+zipp = [
+ {file = "zipp-3.4.0-py3-none-any.whl", hash = "sha256:102c24ef8f171fd729d46599845e95c7ab894a4cf45f5de11a44cc7444fb1108"},
+ {file = "zipp-3.4.0.tar.gz", hash = "sha256:ed5eee1974372595f9e416cc7bbeeb12335201d8081ca8a0743c954d4446e5cb"},
+]
diff --git a/pyproject.toml b/cli/pyproject.toml
index dda3b665..08206844 100644
--- a/pyproject.toml
+++ b/cli/pyproject.toml
@@ -1,52 +1,40 @@
[tool.poetry]
-name = "onionshare"
-version = "2.3"
+name = "onionshare_cli"
+version = "2.3.dev2"
description = "OnionShare lets you securely and anonymously send and receive files. It works by starting a web server, making it accessible as a Tor onion service, and generating an unguessable web address so others can download files from you, or upload files to you. It does _not_ require setting up a separate server or using a third party file-sharing service."
authors = ["Micah Lee <micah@micahflee.com>"]
license = "GPLv3+"
+classifiers = [
+ "Programming Language :: Python :: 3",
+ "Framework :: Flask",
+ "Topic :: Communications :: File Sharing",
+ "Topic :: Security :: Cryptography",
+ "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
+ "Intended Audience :: End Users/Desktop",
+ "Operating System :: OS Independent",
+ "Environment :: Web Environment",
+]
[tool.poetry.dependencies]
-python = "^3.7"
-altgraph = "*"
-certifi = "*"
-chardet = "*"
-Click = "*"
-Flask = "*"
-Flask-HTTPAuth = "*"
-future = "*"
-idna = "*"
-itsdangerous = "*"
-Jinja2 = "*"
-macholib = "*"
-MarkupSafe = "*"
-pefile = "*"
+python = "^3.6"
+click = "*"
+flask = "*"
+flask-httpauth = "*"
+flask-socketio = "*"
pycryptodome = "*"
-PyQt5 = "5.14"
-PyQt5-sip = "*"
-PySocks = "*"
+pysocks = "*"
requests = "*"
stem = "*"
urllib3 = "*"
-Werkzeug = "*"
-flask-socketio = "^4.3.0"
-eventlet = "^0.25.2"
-qrcode = "^6.1"
-psutil = "^5.7.2"
+eventlet = "*"
+setuptools = "*"
[tool.poetry.dev-dependencies]
-atomicwrites = "*"
-attrs = "*"
-more-itertools = "*"
-pluggy = "*"
-py = "*"
pytest = "*"
-pytest-faulthandler = "*"
-pytest-qt = "*"
-six = "*"
-urllib3 = "*"
setuptools = "*"
-pyinstaller = {version = "*", platform = "darwin"}
-black = {version = "^19.10b0", allow-prereleases = true}
+
+[tool.poetry.scripts]
+onionshare-cli = 'onionshare_cli:main'
[build-system]
requires = ["poetry>=0.12"]
diff --git a/cli/setup.py b/cli/setup.py
new file mode 100644
index 00000000..1ebe028c
--- /dev/null
+++ b/cli/setup.py
@@ -0,0 +1,70 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+OnionShare | https://onionshare.org/
+
+Copyright (C) 2014-2020 Micah Lee, et al. <micah@micahflee.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+"""
+
+# snap and flatpak packaging uses setup.py
+# PyPi publishing, developing, and testing uses poetry
+
+import os
+import setuptools
+
+version = "2.3.dev2"
+
+setuptools.setup(
+ name="onionshare-cli",
+ version=version,
+ description="OnionShare lets you securely and anonymously send and receive files. It works by starting a web server, making it accessible as a Tor onion service, and generating an unguessable web address so others can download files from you, or upload files to you. It does _not_ require setting up a separate server or using a third party file-sharing service.",
+ author="Micah Lee",
+ author_email="micah@micahflee.com",
+ maintainer="Micah Lee",
+ maintainer_email="micah@micahflee.com",
+ url="https://onionshare.org",
+ license="GPLv3",
+ keywords="onion, share, onionshare, tor, anonymous, web server",
+ classifiers=[
+ "Programming Language :: Python :: 3",
+ "Framework :: Flask",
+ "Topic :: Communications :: File Sharing",
+ "Topic :: Security :: Cryptography",
+ "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
+ "Intended Audience :: End Users/Desktop",
+ "Operating System :: OS Independent",
+ "Environment :: Web Environment",
+ ],
+ packages=[
+ "onionshare_cli",
+ "onionshare_cli.web",
+ ],
+ package_data={
+ "onionshare_cli": [
+ "resources/*",
+ "resources/static/*",
+ "resources/static/css/*",
+ "resources/static/img/*",
+ "resources/static/js/*",
+ "resources/templates/*",
+ ]
+ },
+ entry_points={
+ "console_scripts": [
+ "onionshare-cli = onionshare_cli:main",
+ ],
+ },
+)
diff --git a/tests/__init__.py b/cli/tests/__init__.py
index e69de29b..e69de29b 100644
--- a/tests/__init__.py
+++ b/cli/tests/__init__.py
diff --git a/tests/conftest.py b/cli/tests/conftest.py
index ba0f1e72..04d4112a 100644
--- a/tests/conftest.py
+++ b/cli/tests/conftest.py
@@ -12,7 +12,7 @@ import tempfile
import pytest
-from onionshare import common, web, settings, strings
+from onionshare_cli import common, web
# The temporary directory for CLI tests
@@ -21,9 +21,6 @@ test_temp_dir = None
def pytest_addoption(parser):
parser.addoption(
- "--rungui", action="store_true", default=False, help="run GUI tests"
- )
- parser.addoption(
"--runtor", action="store_true", default=False, help="run tor tests"
)
@@ -36,13 +33,6 @@ def pytest_collection_modifyitems(config, items):
if "tor" in item.keywords:
item.add_marker(skip_tor)
- if not config.getoption("--rungui"):
- # --rungui given in cli: do not skip GUI tests
- skip_gui = pytest.mark.skip(reason="need --rungui option to run")
- for item in items:
- if "gui" in item.keywords:
- item.add_marker(skip_gui)
-
@pytest.fixture
def temp_dir():
@@ -205,5 +195,4 @@ def common_obj():
def settings_obj(sys_onionshare_dev_mode, platform_linux):
_common = common.Common()
_common.version = "DUMMY_VERSION_1.2.3"
- strings.load_strings(_common)
return settings.Settings(_common)
diff --git a/tests/pytest.ini b/cli/tests/pytest.ini
index 393e0dd8..393e0dd8 100644
--- a/tests/pytest.ini
+++ b/cli/tests/pytest.ini
diff --git a/tests/test_cli.py b/cli/tests/test_cli.py
index 7cc61853..99f26547 100644
--- a/tests/test_cli.py
+++ b/cli/tests/test_cli.py
@@ -2,9 +2,9 @@ import os
import pytest
-from onionshare import OnionShare
-from onionshare.common import Common
-from onionshare.mode_settings import ModeSettings
+from onionshare_cli import OnionShare
+from onionshare_cli.common import Common
+from onionshare_cli.mode_settings import ModeSettings
class MyOnion:
@@ -14,7 +14,9 @@ class MyOnion:
self.scheduled_key = None
@staticmethod
- def start_onion_service(self, mode_settings_obj, await_publication=True, save_scheduled_key=False):
+ def start_onion_service(
+ self, mode_settings_obj, await_publication=True, save_scheduled_key=False
+ ):
return "test_service_id.onion"
diff --git a/tests/test_cli_common.py b/cli/tests/test_cli_common.py
index b60d22d7..e95ba03e 100644
--- a/tests/test_cli_common.py
+++ b/cli/tests/test_cli_common.py
@@ -38,7 +38,7 @@ class TestBuildPassword:
),
)
def test_build_password_regex(self, test_input, expected):
- """ Test that `PASSWORD_REGEX` accounts for the following patterns
+ """Test that `PASSWORD_REGEX` accounts for the following patterns
There are a few hyphenated words in `wordlist.txt`:
* drop-down
@@ -61,7 +61,7 @@ class TestBuildPassword:
class TestDirSize:
def test_temp_dir_size(self, common_obj, temp_dir_1024_delete):
- """ dir_size() should return the total size (in bytes) of all files
+ """dir_size() should return the total size (in bytes) of all files
in a particular directory.
"""
@@ -152,34 +152,6 @@ class TestGetPlatform:
assert common_obj.platform == "Windows"
-# TODO: double-check these tests
-class TestGetResourcePath:
- def test_onionshare_dev_mode(self, common_obj, sys_onionshare_dev_mode):
- prefix = os.path.join(
- os.path.dirname(
- os.path.dirname(
- os.path.abspath(inspect.getfile(inspect.currentframe()))
- )
- ),
- "share",
- )
- assert common_obj.get_resource_path(
- os.path.join(prefix, "test_filename")
- ) == os.path.join(prefix, "test_filename")
-
- def test_linux(self, common_obj, platform_linux, sys_argv_sys_prefix):
- prefix = os.path.join(sys.prefix, "share", "onionshare")
- assert common_obj.get_resource_path(
- os.path.join(prefix, "test_filename")
- ) == os.path.join(prefix, "test_filename")
-
- def test_frozen_darwin(self, common_obj, platform_darwin, sys_frozen, sys_meipass):
- prefix = os.path.join(sys._MEIPASS, "share")
- assert common_obj.get_resource_path(
- os.path.join(prefix, "test_filename")
- ) == os.path.join(prefix, "test_filename")
-
-
class TestGetTorPaths:
@pytest.mark.skipif(sys.platform != "Darwin", reason="requires MacOS")
def test_get_tor_paths_darwin(
diff --git a/tests/test_cli_settings.py b/cli/tests/test_cli_settings.py
index 83b51e54..62f97267 100644
--- a/tests/test_cli_settings.py
+++ b/cli/tests/test_cli_settings.py
@@ -5,7 +5,7 @@ import sys
import pytest
-from onionshare import common, settings, strings
+from onionshare_cli import common, settings
@pytest.fixture
@@ -66,8 +66,6 @@ class TestSettings:
assert os.path.exists(tmp_file_path) is False
def test_save(self, monkeypatch, temp_dir, settings_obj):
- monkeypatch.setattr(strings, "_", lambda _: "")
-
settings_filename = "default_settings.json"
new_temp_dir = tempfile.mkdtemp(dir=temp_dir)
settings_path = os.path.join(new_temp_dir, settings_filename)
diff --git a/tests/test_cli_web.py b/cli/tests/test_cli_web.py
index d2802bf3..063bd43c 100644
--- a/tests/test_cli_web.py
+++ b/cli/tests/test_cli_web.py
@@ -13,11 +13,10 @@ import base64
import pytest
from werkzeug.datastructures import Headers
-from onionshare.common import Common
-from onionshare import strings
-from onionshare.web import Web
-from onionshare.settings import Settings
-from onionshare.mode_settings import ModeSettings
+from onionshare_cli.common import Common
+from onionshare_cli.web import Web
+from onionshare_cli.settings import Settings
+from onionshare_cli.mode_settings import ModeSettings
DEFAULT_ZW_FILENAME_REGEX = re.compile(r"^onionshare_[a-z2-7]{6}.zip$")
RANDOM_STR_REGEX = re.compile(r"^[a-z2-7]+$")
@@ -26,7 +25,6 @@ RANDOM_STR_REGEX = re.compile(r"^[a-z2-7]+$")
def web_obj(temp_dir, common_obj, mode, num_files=0):
""" Creates a Web object, in either share mode or receive mode, ready for testing """
common_obj.settings = Settings(common_obj)
- strings.load_strings(common_obj)
mode_settings = ModeSettings(common_obj)
web = Web(common_obj, False, mode_settings, mode)
web.generate_password()
diff --git a/desktop/README.md b/desktop/README.md
new file mode 100644
index 00000000..a1406b47
--- /dev/null
+++ b/desktop/README.md
@@ -0,0 +1,113 @@
+# OnionShare Desktop
+
+## Building OnionShare
+
+Start by getting the source code and changing to the `desktop` folder:
+
+```sh
+git clone https://github.com/micahflee/onionshare.git
+cd onionshare/desktop
+```
+
+### Install platform-specific dependencies
+
+#### Linux
+
+If you're using Linux, install `tor` and `obfs4proxy` from either the [official Debian repository](https://support.torproject.org/apt/tor-deb-repo/), or from your package manager.
+
+#### macOS
+
+Download and install Python 3.8.6 from https://www.python.org/downloads/release/python-386/. I downloaded `python-3.8.6-macosx10.9.pkg`. (You may need to also run `/Applications/Python\ 3.8/Install\ Certificates.command`.)
+
+Install python dependencies:
+
+```sh
+pip3 install --user poetry requests
+```
+
+Download Tor Browser and extract the binaries:
+
+```sh
+./scripts/get-tor-osx.py
+```
+
+#### Windows
+
+These instructions include adding folders to the path in Windows. To do this, go to Start and type "advanced system settings", and open "View advanced system settings" in the Control Panel. Click Environment Variables. Under "System variables" double-click on Path. From there you can add and remove folders that are available in the PATH.
+
+Download Python 3.8.6, 32-bit (x86) from https://www.python.org/downloads/release/python-386/. I downloaded `python-3.8.6.exe`. When installing it, make sure to check the "Add Python 3.8 to PATH" checkbox on the first page of the installer.
+
+Download and install 7-Zip from http://www.7-zip.org/download.html. I downloaded `7z1900.exe`. Add `C:\Program Files (x86)\7-Zip` to your path.
+
+Install python dependencies:
+
+```
+pip install poetry requests
+```
+
+Download Tor Browser and extract the binaries:
+
+```
+python scripts\get-tor-windows.py
+```
+
+### Prepare the code
+
+In order to work with the desktop app, you'll need to build a wheel of the CLI package first, and copy it into the `desktop` folder:
+
+```sh
+cd ../cli
+poetry install
+poetry build
+cp dist/onionshare_cli-*.whl ../desktop
+cd ../desktop
+```
+
+OnionShare uses [Briefcase](https://briefcase.readthedocs.io/en/latest/).
+
+Install Briefcase dependencies by following [these instructions](https://docs.beeware.org/en/latest/tutorial/tutorial-0.html#install-dependencies).
+
+Now create and/or activate a virtual environment.
+
+* Linux and macOS
+ ```
+ python3 -m venv venv
+ . venv/bin/activate
+ ```
+* Windows
+ ```
+ python -m venv venv
+ venv\Scripts\activate.bat
+ ```
+
+While your virtual environment is active, install briefcase from pip.
+
+```
+pip install briefcase
+```
+
+Run OnionShare from the source tree like this:
+
+```
+briefcase dev -d
+```
+
+## Running tests
+
+Install these packages inside your virtual environment:
+
+```sh
+pip install pytest pytest-briefcase pytest-faulthandler pytest-qt
+```
+
+Then run the tests:
+
+```sh
+./tests/run.sh
+```
+
+If you want to run tests while hiding the GUI, you must have the `xvfb` package installed, and then:
+
+```sh
+xvfb-run ./tests/run.sh
+```
diff --git a/install/check_lacked_trans.py b/desktop/check_lacked_trans.py
index 965b103b..965b103b 100755
--- a/install/check_lacked_trans.py
+++ b/desktop/check_lacked_trans.py
diff --git a/desktop/package/linux/build-appimage.py b/desktop/package/linux/build-appimage.py
new file mode 100755
index 00000000..73164b55
--- /dev/null
+++ b/desktop/package/linux/build-appimage.py
@@ -0,0 +1,47 @@
+#!/usr/bin/env python3
+import os
+import inspect
+import subprocess
+import argparse
+import shutil
+import glob
+
+root = os.path.dirname(
+ os.path.dirname(
+ os.path.dirname(
+ os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
+ )
+ )
+)
+
+
+def run(cmd, cwd=None):
+ subprocess.run(cmd, cwd=cwd, check=True)
+
+
+def main():
+ cli_dir = os.path.join(root, "cli")
+ desktop_dir = os.path.join(root, "desktop")
+
+ print("○ Clean up from last build")
+ if os.path.exists(os.path.join(cli_dir, "dist")):
+ shutil.rmtree(os.path.join(cli_dir, "dist"))
+ if os.path.exists(os.path.join(desktop_dir, "linux")):
+ shutil.rmtree(os.path.join(desktop_dir, "linux"))
+
+ print("○ Building onionshare-cli")
+ run(["poetry", "install"], cli_dir)
+ run(["poetry", "build"], cli_dir)
+ whl_filename = glob.glob(os.path.join(cli_dir, "dist", "*.whl"))[0]
+ whl_basename = os.path.basename(whl_filename)
+ shutil.copyfile(whl_filename, os.path.join(desktop_dir, whl_basename))
+
+ print("○ Create the binary")
+ run(["briefcase", "create"], desktop_dir)
+
+ print("○ Create the AppImage")
+ run(["briefcase", "build"], desktop_dir)
+
+
+if __name__ == "__main__":
+ main() \ No newline at end of file
diff --git a/install/org.onionshare.OnionShare.desktop b/desktop/package/linux/org.onionshare.OnionShare.desktop
index 190e2f26..190e2f26 100644
--- a/install/org.onionshare.OnionShare.desktop
+++ b/desktop/package/linux/org.onionshare.OnionShare.desktop
diff --git a/install/macos_sandbox/child.plist b/desktop/package/macos/ChildEntitlements.plist
index 06d88f66..06d88f66 100644
--- a/install/macos_sandbox/child.plist
+++ b/desktop/package/macos/ChildEntitlements.plist
diff --git a/install/macos_sandbox/parent.plist b/desktop/package/macos/Entitlements.plist
index 3929abe9..8b9ac949 100644
--- a/install/macos_sandbox/parent.plist
+++ b/desktop/package/macos/Entitlements.plist
@@ -6,6 +6,10 @@
<key>com.apple.security.app-sandbox</key>
<true/>
+ <!-- Required for running PyInstaller python code with hardened runtime -->
+ <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
+ <true/>
+
<!-- Both OnionShare and Tor need network server and client -->
<key>com.apple.security.network.server</key>
<true/>
diff --git a/desktop/package/macos/build.py b/desktop/package/macos/build.py
new file mode 100755
index 00000000..0ba23129
--- /dev/null
+++ b/desktop/package/macos/build.py
@@ -0,0 +1,131 @@
+#!/usr/bin/env python3
+import os
+import inspect
+import subprocess
+import argparse
+import shutil
+import glob
+
+root = os.path.dirname(
+ os.path.dirname(
+ os.path.dirname(
+ os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
+ )
+ )
+)
+
+
+def run(cmd, cwd=None):
+ subprocess.run(cmd, cwd=cwd, check=True)
+
+
+def main():
+ # Parse arguments
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ "--with-codesign",
+ action="store_true",
+ dest="with_codesign",
+ help="Codesign the app bundle",
+ )
+ args = parser.parse_args()
+
+ cli_dir = os.path.join(root, "cli")
+ desktop_dir = os.path.join(root, "desktop")
+
+ print("○ Clean up from last build")
+ if os.path.exists(os.path.join(cli_dir, "dist")):
+ shutil.rmtree(os.path.join(cli_dir, "dist"))
+ if os.path.exists(os.path.join(desktop_dir, "macOS")):
+ shutil.rmtree(os.path.join(desktop_dir, "macOS"))
+
+ print("○ Building onionshare-cli")
+ run(["poetry", "install"], cli_dir)
+ run(["poetry", "build"], cli_dir)
+ whl_filename = glob.glob(os.path.join(cli_dir, "dist", "*.whl"))[0]
+ whl_basename = os.path.basename(whl_filename)
+ shutil.copyfile(whl_filename, os.path.join(desktop_dir, whl_basename))
+
+ print("○ Create app bundle")
+ run(["briefcase", "create"], desktop_dir)
+ app_path = os.path.join(desktop_dir, "macOS", "OnionShare", "OnionShare.app")
+ print(f"○ Unsigned app bundle: {app_path}")
+
+ if args.with_codesign:
+ identity_name_application = "Developer ID Application: Micah Lee (N9B95FDWH4)"
+ entitlements_child_filename = os.path.join(
+ desktop_dir, "package", "macos", "ChildEntitlements.plist"
+ )
+ entitlements_filename = os.path.join(
+ desktop_dir, "package", "macos", "Entitlements.plist"
+ )
+
+ print("○ Code signing app bundle")
+ run(
+ [
+ "codesign",
+ "--deep",
+ "-s",
+ identity_name_application,
+ "--force",
+ "--entitlements",
+ entitlements_child_filename,
+ "--timestamp",
+ app_path,
+ ]
+ )
+ run(
+ [
+ "codesign",
+ "-s",
+ identity_name_application,
+ "--force",
+ "--entitlements",
+ entitlements_filename,
+ "--timestamp",
+ app_path,
+ ]
+ )
+ print(f"○ Signed app bundle: {app_path}")
+
+ if not os.path.exists("/usr/local/bin/create-dmg"):
+ print("○ Error: create-dmg is not installed")
+ return
+
+ print("○ Creating DMG")
+ dmg_path = os.path.join(desktop_dir, "macOS", "OnionShare.dmg")
+ run(
+ [
+ "create-dmg",
+ "--volname",
+ "OnionShare",
+ "--volicon",
+ os.path.join(
+ desktop_dir, "src", "onionshare", "resources", "onionshare.icns"
+ ),
+ "--window-size",
+ "400",
+ "200",
+ "--icon-size",
+ "100",
+ "--icon",
+ "OnionShare.app",
+ "100",
+ "70",
+ "--hide-extension",
+ "OnionShare.app",
+ "--app-drop-link",
+ "300",
+ "70",
+ dmg_path,
+ app_path,
+ "--identity",
+ identity_name_application,
+ ]
+ )
+
+ print(f"○ Finished building DMG: {dmg_path}")
+
+
+if __name__ == "__main__":
+ main() \ No newline at end of file
diff --git a/desktop/package/windows/build.py b/desktop/package/windows/build.py
new file mode 100644
index 00000000..de2f921c
--- /dev/null
+++ b/desktop/package/windows/build.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python3
+import os
+import inspect
+import subprocess
+import argparse
+import shutil
+import glob
+
+root = os.path.dirname(
+ os.path.dirname(
+ os.path.dirname(
+ os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
+ )
+ )
+)
+
+
+def run(cmd, cwd=None):
+ subprocess.run(cmd, cwd=cwd, check=True)
+
+
+def main():
+ cli_dir = os.path.join(root, "cli")
+ desktop_dir = os.path.join(root, "desktop")
+
+ print("○ Clean up from last build")
+ if os.path.exists(os.path.join(cli_dir, "dist")):
+ shutil.rmtree(os.path.join(cli_dir, "dist"))
+ if os.path.exists(os.path.join(desktop_dir, "windows")):
+ shutil.rmtree(os.path.join(desktop_dir, "windows"))
+
+ print("○ Building onionshare-cli")
+ run(["poetry", "install"], cli_dir)
+ run(["poetry", "build"], cli_dir)
+ whl_filename = glob.glob(os.path.join(cli_dir, "dist", "*.whl"))[0]
+ whl_basename = os.path.basename(whl_filename)
+ shutil.copyfile(whl_filename, os.path.join(desktop_dir, whl_basename))
+
+ print("○ Create the binary")
+ run(["briefcase", "create"], desktop_dir)
+ run(["briefcase", "package"], desktop_dir)
+ msi_filename = glob.glob(os.path.join(desktop_dir, "windows", "OnionShare-*.msi"))[
+ 0
+ ]
+ print(f"○ Created unsigned installer: {msi_filename}")
+
+ print(f"○ Signing installer")
+ run(
+ [
+ "signtool.exe",
+ "sign",
+ "/v",
+ "/d",
+ "OnionShare",
+ "/a",
+ "/tr",
+ "http://time.certum.pl/",
+ msi_filename,
+ ],
+ desktop_dir,
+ )
+ print(f"○ Signed installer: {msi_filename}")
+
+
+if __name__ == "__main__":
+ main() \ No newline at end of file
diff --git a/desktop/pyproject.toml b/desktop/pyproject.toml
new file mode 100644
index 00000000..d1be9c45
--- /dev/null
+++ b/desktop/pyproject.toml
@@ -0,0 +1,42 @@
+[tool.briefcase]
+project_name = "OnionShare"
+bundle = "org.onionshare"
+version = "2.3.dev2"
+url = "https://onionshare.org"
+license = "GPLv3"
+author = 'Micah Lee'
+author_email = "micah@micahflee.com"
+
+[tool.briefcase.app.onionshare]
+formal_name = "OnionShare"
+description = "Securely and anonymously share files, host websites, and chat with friends using the Tor network"
+icon = "src/onionshare/resources/onionshare"
+sources = ['src/onionshare']
+requires = [
+ "./onionshare_cli-2.3.dev2-py3-none-any.whl",
+ "psutil",
+ "pyside2==5.15.1",
+ "qrcode"
+]
+
+[tool.briefcase.app.onionshare.macOS]
+requires = []
+
+[tool.briefcase.app.onionshare.linux]
+requires = []
+system_requires = [
+ "tor",
+ "obfs4proxy",
+ "gcc",
+ "python3-dev",
+]
+
+[tool.briefcase.app.onionshare.windows]
+requires = ["pywin32"]
+
+# Mobile deployments
+[tool.briefcase.app.onionshare.iOS]
+requires = []
+
+[tool.briefcase.app.onionshare.android]
+requires = []
diff --git a/screenshots/appdata-onionshare-receive-client.png b/desktop/screenshots/appdata-onionshare-receive-client.png
index 8edcc326..8edcc326 100644
--- a/screenshots/appdata-onionshare-receive-client.png
+++ b/desktop/screenshots/appdata-onionshare-receive-client.png
Binary files differ
diff --git a/screenshots/appdata-onionshare-receive-server.png b/desktop/screenshots/appdata-onionshare-receive-server.png
index 121eab48..121eab48 100644
--- a/screenshots/appdata-onionshare-receive-server.png
+++ b/desktop/screenshots/appdata-onionshare-receive-server.png
Binary files differ
diff --git a/screenshots/appdata-onionshare-share-client.png b/desktop/screenshots/appdata-onionshare-share-client.png
index c57fb2a8..c57fb2a8 100644
--- a/screenshots/appdata-onionshare-share-client.png
+++ b/desktop/screenshots/appdata-onionshare-share-client.png
Binary files differ
diff --git a/screenshots/appdata-onionshare-share-server.png b/desktop/screenshots/appdata-onionshare-share-server.png
index d85e45ce..d85e45ce 100644
--- a/screenshots/appdata-onionshare-share-server.png
+++ b/desktop/screenshots/appdata-onionshare-share-server.png
Binary files differ
diff --git a/screenshots/onionshare-receive-client.png b/desktop/screenshots/onionshare-receive-client.png
index 648d67ae..648d67ae 100644
--- a/screenshots/onionshare-receive-client.png
+++ b/desktop/screenshots/onionshare-receive-client.png
Binary files differ
diff --git a/screenshots/onionshare-receive-server.png b/desktop/screenshots/onionshare-receive-server.png
index 0e801d3d..0e801d3d 100644
--- a/screenshots/onionshare-receive-server.png
+++ b/desktop/screenshots/onionshare-receive-server.png
Binary files differ
diff --git a/screenshots/onionshare-share-client.png b/desktop/screenshots/onionshare-share-client.png
index 58f102d4..58f102d4 100644
--- a/screenshots/onionshare-share-client.png
+++ b/desktop/screenshots/onionshare-share-client.png
Binary files differ
diff --git a/screenshots/onionshare-share-server.png b/desktop/screenshots/onionshare-share-server.png
index 329fc8af..329fc8af 100644
--- a/screenshots/onionshare-share-server.png
+++ b/desktop/screenshots/onionshare-share-server.png
Binary files differ
diff --git a/screenshots/onionshare-website-server.png b/desktop/screenshots/onionshare-website-server.png
index 55e4fa27..55e4fa27 100644
--- a/screenshots/onionshare-website-server.png
+++ b/desktop/screenshots/onionshare-website-server.png
Binary files differ
diff --git a/install/get-tor-osx.py b/desktop/scripts/get-tor-osx.py
index 073384d7..67aac51a 100644..100755
--- a/install/get-tor-osx.py
+++ b/desktop/scripts/get-tor-osx.py
@@ -1,3 +1,4 @@
+#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
OnionShare | https://onionshare.org/
@@ -36,10 +37,10 @@ import requests
def main():
- dmg_url = "https://archive.torproject.org/tor-package-archive/torbrowser/8.5.5/TorBrowser-8.5.5-osx64_en-US.dmg"
- dmg_filename = "TorBrowser-8.5.5-osx64_en-US.dmg"
+ dmg_url = "https://archive.torproject.org/tor-package-archive/torbrowser/10.0.2/TorBrowser-10.0.2-osx64_en-US.dmg"
+ dmg_filename = "TorBrowser-10.0.2-osx64_en-US.dmg"
expected_dmg_sha256 = (
- "9c1b7840bd251a4c52f0c919991e57cafb9178c55e11fa49f83ffacce3c20511"
+ "ac8d28f6f8d92e220f72ef7b0cb2bba45d5e0d4b243dc50806e33e08278e7730"
)
# Build paths
@@ -51,7 +52,9 @@ def main():
"/Volumes", "Tor Browser", "Tor Browser.app", "Contents"
)
dmg_path = os.path.join(working_path, dmg_filename)
- dist_path = os.path.join(root_path, "dist", "OnionShare.app", "Contents")
+ dist_path = os.path.join(root_path, "src", "onionshare", "resources", "tor")
+ if not os.path.exists(dist_path):
+ os.makedirs(dist_path, exist_ok=True)
# Make sure the working folder exists
if not os.path.exists(working_path):
@@ -77,46 +80,30 @@ def main():
# Mount the dmg, copy data to the working path
subprocess.call(["hdiutil", "attach", dmg_path])
- # Make sure Resources/tor exists before copying files
- if os.path.exists(os.path.join(dist_path, "Resources", "Tor")):
- shutil.rmtree(os.path.join(dist_path, "Resources", "Tor"))
- os.makedirs(os.path.join(dist_path, "Resources", "Tor"))
- if os.path.exists(os.path.join(dist_path, "MacOS", "Tor")):
- shutil.rmtree(os.path.join(dist_path, "MacOS", "Tor"))
- os.makedirs(os.path.join(dist_path, "MacOS", "Tor"))
-
- # Modify the tor script to adjust the path
- tor_script = open(
- os.path.join(dmg_tor_path, "Resources", "TorBrowser", "Tor", "tor"), "r"
- ).read()
- tor_script = tor_script.replace("../../../MacOS/Tor", "../../MacOS/Tor")
- open(os.path.join(dist_path, "Resources", "Tor", "tor"), "w").write(tor_script)
-
# Copy into dist
shutil.copyfile(
os.path.join(dmg_tor_path, "Resources", "TorBrowser", "Tor", "geoip"),
- os.path.join(dist_path, "Resources", "Tor", "geoip"),
+ os.path.join(dist_path, "geoip"),
)
shutil.copyfile(
os.path.join(dmg_tor_path, "Resources", "TorBrowser", "Tor", "geoip6"),
- os.path.join(dist_path, "Resources", "Tor", "geoip6"),
+ os.path.join(dist_path, "geoip6"),
)
- os.chmod(os.path.join(dist_path, "Resources", "Tor", "tor"), 0o755)
shutil.copyfile(
os.path.join(dmg_tor_path, "MacOS", "Tor", "tor.real"),
- os.path.join(dist_path, "MacOS", "Tor", "tor.real"),
+ os.path.join(dist_path, "tor"),
)
+ os.chmod(os.path.join(dist_path, "tor"), 0o755)
shutil.copyfile(
- os.path.join(dmg_tor_path, "MacOS", "Tor", "libevent-2.1.6.dylib"),
- os.path.join(dist_path, "MacOS", "Tor", "libevent-2.1.6.dylib"),
+ os.path.join(dmg_tor_path, "MacOS", "Tor", "libevent-2.1.7.dylib"),
+ os.path.join(dist_path, "libevent-2.1.7.dylib"),
)
- os.chmod(os.path.join(dist_path, "MacOS", "Tor", "tor.real"), 0o755)
# obfs4proxy binary
shutil.copyfile(
os.path.join(dmg_tor_path, "MacOS", "Tor", "PluggableTransports", "obfs4proxy"),
- os.path.join(dist_path, "Resources", "Tor", "obfs4proxy"),
+ os.path.join(dist_path, "obfs4proxy"),
)
- os.chmod(os.path.join(dist_path, "Resources", "Tor", "obfs4proxy"), 0o755)
+ os.chmod(os.path.join(dist_path, "obfs4proxy"), 0o755)
# Eject dmg
subprocess.call(["diskutil", "eject", "/Volumes/Tor Browser"])
diff --git a/install/get-tor-windows.py b/desktop/scripts/get-tor-windows.py
index 07811880..16841c60 100644
--- a/install/get-tor-windows.py
+++ b/desktop/scripts/get-tor-windows.py
@@ -34,26 +34,24 @@ import requests
def main():
- exe_url = "https://archive.torproject.org/tor-package-archive/torbrowser/8.5.5/torbrowser-install-8.5.5_en-US.exe"
- exe_filename = "torbrowser-install-8.5.5_en-US.exe"
+ exe_url = "https://archive.torproject.org/tor-package-archive/torbrowser/10.0.2/torbrowser-install-10.0.2_en-US.exe"
+ exe_filename = "torbrowser-install-10.0.2_en-US.exe"
expected_exe_sha256 = (
- "a3aa7e626d1d2365dcecc6f17055f467f31c4ff9558a769e51d4b90640e48bb0"
+ "c685c550fc420c39cbe40e453f2201789af5f64e7b024c9339c2a3bd01e61c2d"
)
# Build paths
root_path = os.path.dirname(
os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
)
- working_path = os.path.join(os.path.join(root_path, "build"), "tor")
+ working_path = os.path.join(root_path, "build", "tor")
exe_path = os.path.join(working_path, exe_filename)
- dist_path = os.path.join(
- os.path.join(os.path.join(root_path, "dist"), "onionshare"), "tor"
- )
+ dist_path = os.path.join(root_path, "src", "onionshare", "resources", "tor")
# Make sure the working folder exists
if not os.path.exists(working_path):
os.makedirs(working_path)
- # Make sure the zip is downloaded
+ # Make sure Tor Browser is downloaded
if not os.path.exists(exe_path):
print("Downloading {}".format(exe_url))
r = requests.get(exe_url)
@@ -71,26 +69,28 @@ def main():
sys.exit(-1)
# Extract the bits we need from the exe
- cmd = [
- "7z",
- "e",
- "-y",
- exe_path,
- "Browser\TorBrowser\Tor",
- "-o%s" % os.path.join(working_path, "Tor"),
- ]
- cmd2 = [
- "7z",
- "e",
- "-y",
- exe_path,
- "Browser\TorBrowser\Data\Tor\geoip*",
- "-o%s" % os.path.join(working_path, "Data"),
- ]
- subprocess.Popen(cmd).wait()
- subprocess.Popen(cmd2).wait()
+ subprocess.Popen(
+ [
+ "7z",
+ "e",
+ "-y",
+ exe_path,
+ "Browser\TorBrowser\Tor",
+ "-o%s" % os.path.join(working_path, "Tor"),
+ ]
+ ).wait()
+ subprocess.Popen(
+ [
+ "7z",
+ "e",
+ "-y",
+ exe_path,
+ "Browser\TorBrowser\Data\Tor\geoip*",
+ "-o%s" % os.path.join(working_path, "Data"),
+ ]
+ ).wait()
- # Copy into dist
+ # Copy into the onionshare resources
if os.path.exists(dist_path):
shutil.rmtree(dist_path)
os.makedirs(dist_path)
diff --git a/onionshare_gui/__init__.py b/desktop/src/onionshare/__init__.py
index 070d03a4..287d882c 100644
--- a/onionshare_gui/__init__.py
+++ b/desktop/src/onionshare/__init__.py
@@ -27,9 +27,9 @@ import signal
import json
import psutil
import getpass
-from PyQt5 import QtCore, QtWidgets
+from PySide2 import QtCore, QtWidgets
-from onionshare.common import Common
+from onionshare_cli.common import Common
from .gui_common import GuiCommon
from .widgets import Alert
@@ -186,7 +186,3 @@ def main():
# All done
sys.exit(qtapp.exec_())
-
-
-if __name__ == "__main__":
- main()
diff --git a/install/scripts/onionshare b/desktop/src/onionshare/__main__.py
index 67298b6f..7b087670 100755..100644
--- a/install/scripts/onionshare
+++ b/desktop/src/onionshare/__main__.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
OnionShare | https://onionshare.org/
@@ -18,6 +17,8 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
-import onionshare
-onionshare.main()
+from . import main
+
+if __name__ == "__main__":
+ main()
diff --git a/onionshare_gui/gui_common.py b/desktop/src/onionshare/gui_common.py
index 2e350cca..7a32f8ec 100644
--- a/onionshare_gui/gui_common.py
+++ b/desktop/src/onionshare/gui_common.py
@@ -19,9 +19,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
import os
+import inspect
+import shutil
+from pkg_resources import resource_filename
-from onionshare import strings
-from onionshare.onion import Onion
+from . import strings
+from onionshare_cli.onion import Onion
class GuiCommon:
@@ -46,10 +49,10 @@ class GuiCommon:
self.common.load_settings()
# Load strings
- strings.load_strings(self.common)
+ strings.load_strings(self.common, self.get_resource_path("locale"))
# Start the Onion
- self.onion = Onion(common)
+ self.onion = Onion(common, get_tor_paths=self.get_tor_paths)
# Lock filename
self.lock_filename = os.path.join(self.common.build_data_dir(), "lock")
@@ -327,3 +330,42 @@ class GuiCommon:
font-style: italic;
}""",
}
+
+ def get_tor_paths(self):
+ if self.common.platform == "Linux":
+ tor_path = shutil.which("tor")
+ obfs4proxy_file_path = shutil.which("obfs4proxy")
+ prefix = os.path.dirname(os.path.dirname(tor_path))
+ tor_geo_ip_file_path = os.path.join(prefix, "share/tor/geoip")
+ tor_geo_ipv6_file_path = os.path.join(prefix, "share/tor/geoip6")
+ elif self.common.platform == "Windows":
+ base_path = self.get_resource_path("tor")
+ tor_path = os.path.join(base_path, "Tor", "tor.exe")
+ obfs4proxy_file_path = os.path.join(base_path, "Tor", "obfs4proxy.exe")
+ tor_geo_ip_file_path = os.path.join(base_path, "Data", "Tor", "geoip")
+ tor_geo_ipv6_file_path = os.path.join(base_path, "Data", "Tor", "geoip6")
+ elif self.common.platform == "Darwin":
+ base_path = self.get_resource_path("tor")
+ tor_path = os.path.join(base_path, "tor")
+ obfs4proxy_file_path = os.path.join(base_path, "obfs4proxy.exe")
+ tor_geo_ip_file_path = os.path.join(base_path, "geoip")
+ tor_geo_ipv6_file_path = os.path.join(base_path, "geoip6")
+ elif self.common.platform == "BSD":
+ tor_path = "/usr/local/bin/tor"
+ tor_geo_ip_file_path = "/usr/local/share/tor/geoip"
+ tor_geo_ipv6_file_path = "/usr/local/share/tor/geoip6"
+ obfs4proxy_file_path = "/usr/local/bin/obfs4proxy"
+
+ return (
+ tor_path,
+ tor_geo_ip_file_path,
+ tor_geo_ipv6_file_path,
+ obfs4proxy_file_path,
+ )
+
+ @staticmethod
+ def get_resource_path(filename):
+ """
+ Returns the absolute path of a resource
+ """
+ return resource_filename("onionshare", os.path.join("resources", filename))
diff --git a/onionshare_gui/main_window.py b/desktop/src/onionshare/main_window.py
index 6bd84b8a..c1e0cd1a 100644
--- a/onionshare_gui/main_window.py
+++ b/desktop/src/onionshare/main_window.py
@@ -18,16 +18,18 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
-from PyQt5 import QtCore, QtWidgets, QtGui
+import time
+from PySide2 import QtCore, QtWidgets, QtGui
-from onionshare import strings
-from onionshare.web import Web
+from onionshare_cli.web import Web
+from . import strings
from .tor_connection_dialog import TorConnectionDialog
from .settings_dialog import SettingsDialog
from .widgets import Alert
from .update_checker import UpdateThread
from .tab_widget import TabWidget
+from .gui_common import GuiCommon
class MainWindow(QtWidgets.QMainWindow):
@@ -45,9 +47,7 @@ class MainWindow(QtWidgets.QMainWindow):
self.setMinimumWidth(1040)
self.setMinimumHeight(700)
self.setWindowTitle("OnionShare")
- self.setWindowIcon(
- QtGui.QIcon(self.common.get_resource_path("images/logo.png"))
- )
+ self.setWindowIcon(QtGui.QIcon(GuiCommon.get_resource_path("images/logo.png")))
# System tray
menu = QtWidgets.QMenu()
@@ -63,11 +63,11 @@ class MainWindow(QtWidgets.QMainWindow):
# The convention is Mac systray icons are always grayscale
if self.common.platform == "Darwin":
self.system_tray.setIcon(
- QtGui.QIcon(self.common.get_resource_path("images/logo_grayscale.png"))
+ QtGui.QIcon(GuiCommon.get_resource_path("images/logo_grayscale.png"))
)
else:
self.system_tray.setIcon(
- QtGui.QIcon(self.common.get_resource_path("images/logo.png"))
+ QtGui.QIcon(GuiCommon.get_resource_path("images/logo.png"))
)
self.system_tray.setContextMenu(menu)
self.system_tray.show()
@@ -80,13 +80,13 @@ class MainWindow(QtWidgets.QMainWindow):
# Server status indicator icons
self.status_bar.server_status_image_stopped = QtGui.QImage(
- self.common.get_resource_path("images/server_stopped.png")
+ GuiCommon.get_resource_path("images/server_stopped.png")
)
self.status_bar.server_status_image_working = QtGui.QImage(
- self.common.get_resource_path("images/server_working.png")
+ GuiCommon.get_resource_path("images/server_working.png")
)
self.status_bar.server_status_image_started = QtGui.QImage(
- self.common.get_resource_path("images/server_started.png")
+ GuiCommon.get_resource_path("images/server_started.png")
)
# Server status indicator on the status bar
@@ -112,7 +112,7 @@ class MainWindow(QtWidgets.QMainWindow):
self.settings_button.setDefault(False)
self.settings_button.setFixedSize(40, 50)
self.settings_button.setIcon(
- QtGui.QIcon(self.common.get_resource_path("images/settings.png"))
+ QtGui.QIcon(GuiCommon.get_resource_path("images/settings.png"))
)
self.settings_button.clicked.connect(self.open_settings)
self.settings_button.setStyleSheet(self.common.gui.css["settings_button"])
@@ -287,3 +287,6 @@ class MainWindow(QtWidgets.QMainWindow):
def cleanup(self):
self.tabs.cleanup()
self.common.gui.onion.cleanup()
+
+ # Wait 1 second for threads to close gracefully, so tests finally pass
+ time.sleep(1)
diff --git a/desktop/src/onionshare/resources/__init__.py b/desktop/src/onionshare/resources/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/desktop/src/onionshare/resources/__init__.py
diff --git a/share/images/close_tab.png b/desktop/src/onionshare/resources/images/close_tab.png
index a7984a6d..a7984a6d 100644
--- a/share/images/close_tab.png
+++ b/desktop/src/onionshare/resources/images/close_tab.png
Binary files differ
diff --git a/share/images/file_delete.png b/desktop/src/onionshare/resources/images/file_delete.png
index b9057df5..b9057df5 100644
--- a/share/images/file_delete.png
+++ b/desktop/src/onionshare/resources/images/file_delete.png
Binary files differ
diff --git a/share/images/history_completed.png b/desktop/src/onionshare/resources/images/history_completed.png
index e68fe5a2..e68fe5a2 100644
--- a/share/images/history_completed.png
+++ b/desktop/src/onionshare/resources/images/history_completed.png
Binary files differ
diff --git a/share/images/history_completed_none.png b/desktop/src/onionshare/resources/images/history_completed_none.png
index 8dbd6939..8dbd6939 100644
--- a/share/images/history_completed_none.png
+++ b/desktop/src/onionshare/resources/images/history_completed_none.png
Binary files differ
diff --git a/share/images/history_in_progress.png b/desktop/src/onionshare/resources/images/history_in_progress.png
index 19694659..19694659 100644
--- a/share/images/history_in_progress.png
+++ b/desktop/src/onionshare/resources/images/history_in_progress.png
Binary files differ
diff --git a/share/images/history_in_progress_none.png b/desktop/src/onionshare/resources/images/history_in_progress_none.png
index 2d61dba4..2d61dba4 100644
--- a/share/images/history_in_progress_none.png
+++ b/desktop/src/onionshare/resources/images/history_in_progress_none.png
Binary files differ
diff --git a/share/images/history_requests.png b/desktop/src/onionshare/resources/images/history_requests.png
index 4965744d..4965744d 100644
--- a/share/images/history_requests.png
+++ b/desktop/src/onionshare/resources/images/history_requests.png
Binary files differ
diff --git a/share/images/history_requests_none.png b/desktop/src/onionshare/resources/images/history_requests_none.png
index 93a71ef3..93a71ef3 100644
--- a/share/images/history_requests_none.png
+++ b/desktop/src/onionshare/resources/images/history_requests_none.png
Binary files differ
diff --git a/share/images/info.png b/desktop/src/onionshare/resources/images/info.png
index 4be4e65e..4be4e65e 100644
--- a/share/images/info.png
+++ b/desktop/src/onionshare/resources/images/info.png
Binary files differ
diff --git a/share/static/img/logo.png b/desktop/src/onionshare/resources/images/logo.png
index 43884c1f..43884c1f 100644
--- a/share/static/img/logo.png
+++ b/desktop/src/onionshare/resources/images/logo.png
Binary files differ
diff --git a/share/images/logo_grayscale.png b/desktop/src/onionshare/resources/images/logo_grayscale.png
index 950d9ff6..950d9ff6 100644
--- a/share/images/logo_grayscale.png
+++ b/desktop/src/onionshare/resources/images/logo_grayscale.png
Binary files differ
diff --git a/share/images/logo_text.png b/desktop/src/onionshare/resources/images/logo_text.png
index 3b584acd..3b584acd 100644
--- a/share/images/logo_text.png
+++ b/desktop/src/onionshare/resources/images/logo_text.png
Binary files differ
diff --git a/share/images/logo_transparent.png b/desktop/src/onionshare/resources/images/logo_transparent.png
index 1e8ed196..1e8ed196 100644
--- a/share/images/logo_transparent.png
+++ b/desktop/src/onionshare/resources/images/logo_transparent.png
Binary files differ
diff --git a/share/images/mode_chat.png b/desktop/src/onionshare/resources/images/mode_chat.png
index 33114364..33114364 100644
--- a/share/images/mode_chat.png
+++ b/desktop/src/onionshare/resources/images/mode_chat.png
Binary files differ
diff --git a/share/images/mode_chat.svg b/desktop/src/onionshare/resources/images/mode_chat.svg
index 335e9cf4..335e9cf4 100644
--- a/share/images/mode_chat.svg
+++ b/desktop/src/onionshare/resources/images/mode_chat.svg
diff --git a/share/images/mode_new_tab_chat.png b/desktop/src/onionshare/resources/images/mode_new_tab_chat.png
index 50759d64..50759d64 100644
--- a/share/images/mode_new_tab_chat.png
+++ b/desktop/src/onionshare/resources/images/mode_new_tab_chat.png
Binary files differ
diff --git a/share/images/mode_new_tab_receive.png b/desktop/src/onionshare/resources/images/mode_new_tab_receive.png
index 9db809be..9db809be 100644
--- a/share/images/mode_new_tab_receive.png
+++ b/desktop/src/onionshare/resources/images/mode_new_tab_receive.png
Binary files differ
diff --git a/share/images/mode_new_tab_share.png b/desktop/src/onionshare/resources/images/mode_new_tab_share.png
index 92973175..92973175 100644
--- a/share/images/mode_new_tab_share.png
+++ b/desktop/src/onionshare/resources/images/mode_new_tab_share.png
Binary files differ
diff --git a/share/images/mode_new_tab_website.png b/desktop/src/onionshare/resources/images/mode_new_tab_website.png
index 86b45f66..86b45f66 100644
--- a/share/images/mode_new_tab_website.png
+++ b/desktop/src/onionshare/resources/images/mode_new_tab_website.png
Binary files differ
diff --git a/share/images/mode_receive.png b/desktop/src/onionshare/resources/images/mode_receive.png
index d57aa409..d57aa409 100644
--- a/share/images/mode_receive.png
+++ b/desktop/src/onionshare/resources/images/mode_receive.png
Binary files differ
diff --git a/share/images/mode_receive.svg b/desktop/src/onionshare/resources/images/mode_receive.svg
index 5a0a29fd..5a0a29fd 100644
--- a/share/images/mode_receive.svg
+++ b/desktop/src/onionshare/resources/images/mode_receive.svg
diff --git a/share/images/mode_share.png b/desktop/src/onionshare/resources/images/mode_share.png
index ec287db4..ec287db4 100644
--- a/share/images/mode_share.png
+++ b/desktop/src/onionshare/resources/images/mode_share.png
Binary files differ
diff --git a/share/images/mode_share.svg b/desktop/src/onionshare/resources/images/mode_share.svg
index 9fb97c65..9fb97c65 100644
--- a/share/images/mode_share.svg
+++ b/desktop/src/onionshare/resources/images/mode_share.svg
diff --git a/share/images/mode_website.png b/desktop/src/onionshare/resources/images/mode_website.png
index 37a556d9..37a556d9 100644
--- a/share/images/mode_website.png
+++ b/desktop/src/onionshare/resources/images/mode_website.png
Binary files differ
diff --git a/share/images/mode_website.svg b/desktop/src/onionshare/resources/images/mode_website.svg
index 1a80846f..1a80846f 100644
--- a/share/images/mode_website.svg
+++ b/desktop/src/onionshare/resources/images/mode_website.svg
diff --git a/share/images/open_folder.png b/desktop/src/onionshare/resources/images/open_folder.png
index 0a734c41..0a734c41 100644
--- a/share/images/open_folder.png
+++ b/desktop/src/onionshare/resources/images/open_folder.png
Binary files differ
diff --git a/share/images/persistent_enabled.png b/desktop/src/onionshare/resources/images/persistent_enabled.png
index 6c295db5..6c295db5 100644
--- a/share/images/persistent_enabled.png
+++ b/desktop/src/onionshare/resources/images/persistent_enabled.png
Binary files differ
diff --git a/share/images/receive_icon_toggle.png b/desktop/src/onionshare/resources/images/receive_icon_toggle.png
index 846ececb..846ececb 100644
--- a/share/images/receive_icon_toggle.png
+++ b/desktop/src/onionshare/resources/images/receive_icon_toggle.png
Binary files differ
diff --git a/share/images/receive_icon_toggle_selected.png b/desktop/src/onionshare/resources/images/receive_icon_toggle_selected.png
index 127ce208..127ce208 100644
--- a/share/images/receive_icon_toggle_selected.png
+++ b/desktop/src/onionshare/resources/images/receive_icon_toggle_selected.png
Binary files differ
diff --git a/share/images/receive_icon_transparent.png b/desktop/src/onionshare/resources/images/receive_icon_transparent.png
index 99207097..99207097 100644
--- a/share/images/receive_icon_transparent.png
+++ b/desktop/src/onionshare/resources/images/receive_icon_transparent.png
Binary files differ
diff --git a/share/images/server_started.png b/desktop/src/onionshare/resources/images/server_started.png
index 9c0c3176..9c0c3176 100644
--- a/share/images/server_started.png
+++ b/desktop/src/onionshare/resources/images/server_started.png
Binary files differ
diff --git a/share/images/server_stopped.png b/desktop/src/onionshare/resources/images/server_stopped.png
index 5c5b2ec0..5c5b2ec0 100644
--- a/share/images/server_stopped.png
+++ b/desktop/src/onionshare/resources/images/server_stopped.png
Binary files differ
diff --git a/share/images/server_working.png b/desktop/src/onionshare/resources/images/server_working.png
index e5c8b318..e5c8b318 100644
--- a/share/images/server_working.png
+++ b/desktop/src/onionshare/resources/images/server_working.png
Binary files differ
diff --git a/share/images/settings.png b/desktop/src/onionshare/resources/images/settings.png
index b6f8fa55..b6f8fa55 100644
--- a/share/images/settings.png
+++ b/desktop/src/onionshare/resources/images/settings.png
Binary files differ
diff --git a/share/images/share_icon_toggle.png b/desktop/src/onionshare/resources/images/share_icon_toggle.png
index 87303c9f..87303c9f 100644
--- a/share/images/share_icon_toggle.png
+++ b/desktop/src/onionshare/resources/images/share_icon_toggle.png
Binary files differ
diff --git a/share/images/share_icon_toggle_selected.png b/desktop/src/onionshare/resources/images/share_icon_toggle_selected.png
index 0ba52cff..0ba52cff 100644
--- a/share/images/share_icon_toggle_selected.png
+++ b/desktop/src/onionshare/resources/images/share_icon_toggle_selected.png
Binary files differ
diff --git a/share/images/share_icon_transparent.png b/desktop/src/onionshare/resources/images/share_icon_transparent.png
index 3648c3fb..3648c3fb 100644
--- a/share/images/share_icon_transparent.png
+++ b/desktop/src/onionshare/resources/images/share_icon_transparent.png
Binary files differ
diff --git a/share/locale/af.json b/desktop/src/onionshare/resources/locale/af.json
index c9e641f5..c9e641f5 100644
--- a/share/locale/af.json
+++ b/desktop/src/onionshare/resources/locale/af.json
diff --git a/share/locale/am.json b/desktop/src/onionshare/resources/locale/am.json
index b787a617..b787a617 100644
--- a/share/locale/am.json
+++ b/desktop/src/onionshare/resources/locale/am.json
diff --git a/share/locale/ar.json b/desktop/src/onionshare/resources/locale/ar.json
index f1451cc7..f1451cc7 100644
--- a/share/locale/ar.json
+++ b/desktop/src/onionshare/resources/locale/ar.json
diff --git a/share/locale/bg.json b/desktop/src/onionshare/resources/locale/bg.json
index 9abe5623..9abe5623 100644
--- a/share/locale/bg.json
+++ b/desktop/src/onionshare/resources/locale/bg.json
diff --git a/share/locale/bn.json b/desktop/src/onionshare/resources/locale/bn.json
index 7d43b3bb..7d43b3bb 100644
--- a/share/locale/bn.json
+++ b/desktop/src/onionshare/resources/locale/bn.json
diff --git a/share/locale/ca.json b/desktop/src/onionshare/resources/locale/ca.json
index 5f9c3ebf..5f9c3ebf 100644
--- a/share/locale/ca.json
+++ b/desktop/src/onionshare/resources/locale/ca.json
diff --git a/share/locale/cs.json b/desktop/src/onionshare/resources/locale/cs.json
index d5c7511a..d5c7511a 100644
--- a/share/locale/cs.json
+++ b/desktop/src/onionshare/resources/locale/cs.json
diff --git a/share/locale/da.json b/desktop/src/onionshare/resources/locale/da.json
index 8eea6c7f..8eea6c7f 100644
--- a/share/locale/da.json
+++ b/desktop/src/onionshare/resources/locale/da.json
diff --git a/share/locale/de.json b/desktop/src/onionshare/resources/locale/de.json
index 2b5b249c..2b5b249c 100644
--- a/share/locale/de.json
+++ b/desktop/src/onionshare/resources/locale/de.json
diff --git a/share/locale/el.json b/desktop/src/onionshare/resources/locale/el.json
index b4645890..b4645890 100644
--- a/share/locale/el.json
+++ b/desktop/src/onionshare/resources/locale/el.json
diff --git a/share/locale/en.json b/desktop/src/onionshare/resources/locale/en.json
index fe880b61..b56c52d8 100644
--- a/share/locale/en.json
+++ b/desktop/src/onionshare/resources/locale/en.json
@@ -177,5 +177,15 @@
"gui_all_modes_transfer_finished_range": "Transferred {} - {}",
"gui_all_modes_transfer_finished": "Transferred {}",
"gui_all_modes_transfer_canceled_range": "Canceled {} - {}",
- "gui_all_modes_transfer_canceled": "Canceled {}"
+ "gui_all_modes_transfer_canceled": "Canceled {}",
+ "settings_error_unknown": "Can't connect to Tor controller because your settings don't make sense.",
+ "settings_error_automatic": "Could not connect to the Tor controller. Is Tor Browser (available from torproject.org) running in the background?",
+ "settings_error_socket_port": "Can't connect to the Tor controller at {}:{}.",
+ "settings_error_socket_file": "Can't connect to the Tor controller using socket file {}.",
+ "settings_error_auth": "Connected to {}:{}, but can't authenticate. Maybe this isn't a Tor controller?",
+ "settings_error_missing_password": "Connected to Tor controller, but it requires a password to authenticate.",
+ "settings_error_unreadable_cookie_file": "Connected to the Tor controller, but password may be wrong, or your user is not permitted to read the cookie file.",
+ "settings_error_bundled_tor_not_supported": "Using the Tor version that comes with OnionShare does not work in developer mode on Windows or macOS.",
+ "settings_error_bundled_tor_timeout": "Taking too long to connect to Tor. Maybe you aren't connected to the Internet, or have an inaccurate system clock?",
+ "settings_error_bundled_tor_broken": "OnionShare could not connect to Tor:\n{}"
} \ No newline at end of file
diff --git a/share/locale/eo.json b/desktop/src/onionshare/resources/locale/eo.json
index ea3cef9c..ea3cef9c 100644
--- a/share/locale/eo.json
+++ b/desktop/src/onionshare/resources/locale/eo.json
diff --git a/share/locale/es.json b/desktop/src/onionshare/resources/locale/es.json
index e101ae5b..e101ae5b 100644
--- a/share/locale/es.json
+++ b/desktop/src/onionshare/resources/locale/es.json
diff --git a/share/locale/fa.json b/desktop/src/onionshare/resources/locale/fa.json
index 5fe578e0..5fe578e0 100644
--- a/share/locale/fa.json
+++ b/desktop/src/onionshare/resources/locale/fa.json
diff --git a/share/locale/fi.json b/desktop/src/onionshare/resources/locale/fi.json
index c0a6f098..c0a6f098 100644
--- a/share/locale/fi.json
+++ b/desktop/src/onionshare/resources/locale/fi.json
diff --git a/share/locale/fr.json b/desktop/src/onionshare/resources/locale/fr.json
index e3ed5ef8..e3ed5ef8 100644
--- a/share/locale/fr.json
+++ b/desktop/src/onionshare/resources/locale/fr.json
diff --git a/share/locale/ga.json b/desktop/src/onionshare/resources/locale/ga.json
index 76e9d64a..76e9d64a 100644
--- a/share/locale/ga.json
+++ b/desktop/src/onionshare/resources/locale/ga.json
diff --git a/share/locale/gu.json b/desktop/src/onionshare/resources/locale/gu.json
index 15c7790d..15c7790d 100644
--- a/share/locale/gu.json
+++ b/desktop/src/onionshare/resources/locale/gu.json
diff --git a/share/locale/he.json b/desktop/src/onionshare/resources/locale/he.json
index c0965d19..c0965d19 100644
--- a/share/locale/he.json
+++ b/desktop/src/onionshare/resources/locale/he.json
diff --git a/share/locale/hi.json b/desktop/src/onionshare/resources/locale/hi.json
index 9cfc310d..9cfc310d 100644
--- a/share/locale/hi.json
+++ b/desktop/src/onionshare/resources/locale/hi.json
diff --git a/share/locale/hr.json b/desktop/src/onionshare/resources/locale/hr.json
index a5f56283..a5f56283 100644
--- a/share/locale/hr.json
+++ b/desktop/src/onionshare/resources/locale/hr.json
diff --git a/share/locale/hu.json b/desktop/src/onionshare/resources/locale/hu.json
index 7d0f6766..7d0f6766 100644
--- a/share/locale/hu.json
+++ b/desktop/src/onionshare/resources/locale/hu.json
diff --git a/share/locale/id.json b/desktop/src/onionshare/resources/locale/id.json
index 44adac8b..44adac8b 100644
--- a/share/locale/id.json
+++ b/desktop/src/onionshare/resources/locale/id.json
diff --git a/share/locale/is.json b/desktop/src/onionshare/resources/locale/is.json
index 5a04b251..5a04b251 100644
--- a/share/locale/is.json
+++ b/desktop/src/onionshare/resources/locale/is.json
diff --git a/share/locale/it.json b/desktop/src/onionshare/resources/locale/it.json
index f6e25927..f6e25927 100644
--- a/share/locale/it.json
+++ b/desktop/src/onionshare/resources/locale/it.json
diff --git a/share/locale/ja.json b/desktop/src/onionshare/resources/locale/ja.json
index 95ee43b7..95ee43b7 100644
--- a/share/locale/ja.json
+++ b/desktop/src/onionshare/resources/locale/ja.json
diff --git a/share/locale/ka.json b/desktop/src/onionshare/resources/locale/ka.json
index 9c41ed9f..9c41ed9f 100644
--- a/share/locale/ka.json
+++ b/desktop/src/onionshare/resources/locale/ka.json
diff --git a/share/locale/km.json b/desktop/src/onionshare/resources/locale/km.json
index 44dfde5a..44dfde5a 100644
--- a/share/locale/km.json
+++ b/desktop/src/onionshare/resources/locale/km.json
diff --git a/share/locale/ko.json b/desktop/src/onionshare/resources/locale/ko.json
index adda3a69..adda3a69 100644
--- a/share/locale/ko.json
+++ b/desktop/src/onionshare/resources/locale/ko.json
diff --git a/share/locale/lg.json b/desktop/src/onionshare/resources/locale/lg.json
index 96b5a0d1..96b5a0d1 100644
--- a/share/locale/lg.json
+++ b/desktop/src/onionshare/resources/locale/lg.json
diff --git a/share/locale/lt.json b/desktop/src/onionshare/resources/locale/lt.json
index 878e6ac0..878e6ac0 100644
--- a/share/locale/lt.json
+++ b/desktop/src/onionshare/resources/locale/lt.json
diff --git a/share/locale/mk.json b/desktop/src/onionshare/resources/locale/mk.json
index b389c2a0..b389c2a0 100644
--- a/share/locale/mk.json
+++ b/desktop/src/onionshare/resources/locale/mk.json
diff --git a/share/locale/ms.json b/desktop/src/onionshare/resources/locale/ms.json
index 8fda843a..8fda843a 100644
--- a/share/locale/ms.json
+++ b/desktop/src/onionshare/resources/locale/ms.json
diff --git a/share/locale/nb_NO.json b/desktop/src/onionshare/resources/locale/nb_NO.json
index 51a2ee76..51a2ee76 100644
--- a/share/locale/nb_NO.json
+++ b/desktop/src/onionshare/resources/locale/nb_NO.json
diff --git a/share/locale/nl.json b/desktop/src/onionshare/resources/locale/nl.json
index 1cea7d1c..1cea7d1c 100644
--- a/share/locale/nl.json
+++ b/desktop/src/onionshare/resources/locale/nl.json
diff --git a/share/locale/pa.json b/desktop/src/onionshare/resources/locale/pa.json
index 165e297b..165e297b 100644
--- a/share/locale/pa.json
+++ b/desktop/src/onionshare/resources/locale/pa.json
diff --git a/share/locale/pl.json b/desktop/src/onionshare/resources/locale/pl.json
index c62c335b..c62c335b 100644
--- a/share/locale/pl.json
+++ b/desktop/src/onionshare/resources/locale/pl.json
diff --git a/share/locale/pt_BR.json b/desktop/src/onionshare/resources/locale/pt_BR.json
index efcf51bf..efcf51bf 100644
--- a/share/locale/pt_BR.json
+++ b/desktop/src/onionshare/resources/locale/pt_BR.json
diff --git a/share/locale/pt_PT.json b/desktop/src/onionshare/resources/locale/pt_PT.json
index 2bf59741..2bf59741 100644
--- a/share/locale/pt_PT.json
+++ b/desktop/src/onionshare/resources/locale/pt_PT.json
diff --git a/share/locale/ro.json b/desktop/src/onionshare/resources/locale/ro.json
index d4e43f04..d4e43f04 100644
--- a/share/locale/ro.json
+++ b/desktop/src/onionshare/resources/locale/ro.json
diff --git a/share/locale/ru.json b/desktop/src/onionshare/resources/locale/ru.json
index 006c0dd2..006c0dd2 100644
--- a/share/locale/ru.json
+++ b/desktop/src/onionshare/resources/locale/ru.json
diff --git a/share/locale/sk.json b/desktop/src/onionshare/resources/locale/sk.json
index 89b6a5ee..89b6a5ee 100644
--- a/share/locale/sk.json
+++ b/desktop/src/onionshare/resources/locale/sk.json
diff --git a/share/locale/sl.json b/desktop/src/onionshare/resources/locale/sl.json
index 70e04baa..70e04baa 100644
--- a/share/locale/sl.json
+++ b/desktop/src/onionshare/resources/locale/sl.json
diff --git a/share/locale/sn.json b/desktop/src/onionshare/resources/locale/sn.json
index 4ee1a03b..4ee1a03b 100644
--- a/share/locale/sn.json
+++ b/desktop/src/onionshare/resources/locale/sn.json
diff --git a/share/locale/sr_Latn.json b/desktop/src/onionshare/resources/locale/sr_Latn.json
index 18dfad44..18dfad44 100644
--- a/share/locale/sr_Latn.json
+++ b/desktop/src/onionshare/resources/locale/sr_Latn.json
diff --git a/share/locale/sv.json b/desktop/src/onionshare/resources/locale/sv.json
index 26c095f0..26c095f0 100644
--- a/share/locale/sv.json
+++ b/desktop/src/onionshare/resources/locale/sv.json
diff --git a/share/locale/sw.json b/desktop/src/onionshare/resources/locale/sw.json
index 74707f3c..74707f3c 100644
--- a/share/locale/sw.json
+++ b/desktop/src/onionshare/resources/locale/sw.json
diff --git a/share/locale/te.json b/desktop/src/onionshare/resources/locale/te.json
index 541625f8..541625f8 100644
--- a/share/locale/te.json
+++ b/desktop/src/onionshare/resources/locale/te.json
diff --git a/share/locale/tr.json b/desktop/src/onionshare/resources/locale/tr.json
index c8261e83..c8261e83 100644
--- a/share/locale/tr.json
+++ b/desktop/src/onionshare/resources/locale/tr.json
diff --git a/share/locale/uk.json b/desktop/src/onionshare/resources/locale/uk.json
index 418b3f47..418b3f47 100644
--- a/share/locale/uk.json
+++ b/desktop/src/onionshare/resources/locale/uk.json
diff --git a/share/locale/wo.json b/desktop/src/onionshare/resources/locale/wo.json
index 89d732b3..89d732b3 100644
--- a/share/locale/wo.json
+++ b/desktop/src/onionshare/resources/locale/wo.json
diff --git a/share/locale/yo.json b/desktop/src/onionshare/resources/locale/yo.json
index 96b5a0d1..96b5a0d1 100644
--- a/share/locale/yo.json
+++ b/desktop/src/onionshare/resources/locale/yo.json
diff --git a/share/locale/zh_Hans.json b/desktop/src/onionshare/resources/locale/zh_Hans.json
index 497e42df..497e42df 100644
--- a/share/locale/zh_Hans.json
+++ b/desktop/src/onionshare/resources/locale/zh_Hans.json
diff --git a/share/locale/zh_Hant.json b/desktop/src/onionshare/resources/locale/zh_Hant.json
index 5bdd093d..5bdd093d 100644
--- a/share/locale/zh_Hant.json
+++ b/desktop/src/onionshare/resources/locale/zh_Hant.json
diff --git a/desktop/src/onionshare/resources/onionshare-128.png b/desktop/src/onionshare/resources/onionshare-128.png
new file mode 100644
index 00000000..856ab4e7
--- /dev/null
+++ b/desktop/src/onionshare/resources/onionshare-128.png
Binary files differ
diff --git a/desktop/src/onionshare/resources/onionshare-16.png b/desktop/src/onionshare/resources/onionshare-16.png
new file mode 100644
index 00000000..dea20940
--- /dev/null
+++ b/desktop/src/onionshare/resources/onionshare-16.png
Binary files differ
diff --git a/desktop/src/onionshare/resources/onionshare-256.png b/desktop/src/onionshare/resources/onionshare-256.png
new file mode 100644
index 00000000..b47cd94a
--- /dev/null
+++ b/desktop/src/onionshare/resources/onionshare-256.png
Binary files differ
diff --git a/desktop/src/onionshare/resources/onionshare-32.png b/desktop/src/onionshare/resources/onionshare-32.png
new file mode 100644
index 00000000..14c849c9
--- /dev/null
+++ b/desktop/src/onionshare/resources/onionshare-32.png
Binary files differ
diff --git a/install/org.onionshare.OnionShare.png b/desktop/src/onionshare/resources/onionshare-512.png
index a4810d04..a4810d04 100644
--- a/install/org.onionshare.OnionShare.png
+++ b/desktop/src/onionshare/resources/onionshare-512.png
Binary files differ
diff --git a/desktop/src/onionshare/resources/onionshare-64.png b/desktop/src/onionshare/resources/onionshare-64.png
new file mode 100644
index 00000000..8468dc52
--- /dev/null
+++ b/desktop/src/onionshare/resources/onionshare-64.png
Binary files differ
diff --git a/install/onionshare.icns b/desktop/src/onionshare/resources/onionshare.icns
index f65ad12d..f65ad12d 100644
--- a/install/onionshare.icns
+++ b/desktop/src/onionshare/resources/onionshare.icns
Binary files differ
diff --git a/install/onionshare.ico b/desktop/src/onionshare/resources/onionshare.ico
index dcde4f1f..dcde4f1f 100644
--- a/install/onionshare.ico
+++ b/desktop/src/onionshare/resources/onionshare.ico
Binary files differ
diff --git a/desktop/src/onionshare/resources/onionshare.png b/desktop/src/onionshare/resources/onionshare.png
new file mode 100644
index 00000000..a4810d04
--- /dev/null
+++ b/desktop/src/onionshare/resources/onionshare.png
Binary files differ
diff --git a/onionshare_gui/settings_dialog.py b/desktop/src/onionshare/settings_dialog.py
index dd711e59..5f37bda1 100644
--- a/onionshare_gui/settings_dialog.py
+++ b/desktop/src/onionshare/settings_dialog.py
@@ -18,20 +18,22 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
-from PyQt5 import QtCore, QtWidgets, QtGui
+from PySide2 import QtCore, QtWidgets, QtGui
import sys
import platform
import datetime
import re
import os
-from onionshare import strings, common
-from onionshare.settings import Settings
-from onionshare.onion import *
+from onionshare_cli import common
+from onionshare_cli.settings import Settings
+from onionshare_cli.onion import *
+from . import strings
from .widgets import Alert
from .update_checker import *
from .tor_connection_dialog import TorConnectionDialog
+from .gui_common import GuiCommon
class SettingsDialog(QtWidgets.QDialog):
@@ -39,7 +41,7 @@ class SettingsDialog(QtWidgets.QDialog):
Settings dialog.
"""
- settings_saved = QtCore.pyqtSignal()
+ settings_saved = QtCore.Signal()
def __init__(self, common):
super(SettingsDialog, self).__init__()
@@ -50,9 +52,7 @@ class SettingsDialog(QtWidgets.QDialog):
self.setModal(True)
self.setWindowTitle(strings._("gui_settings_window_title"))
- self.setWindowIcon(
- QtGui.QIcon(self.common.get_resource_path("images/logo.png"))
- )
+ self.setWindowIcon(QtGui.QIcon(GuiCommon.get_resource_path("images/logo.png")))
self.system = platform.system()
@@ -103,7 +103,7 @@ class SettingsDialog(QtWidgets.QDialog):
language_names.sort()
for language_name in language_names:
locale = language_names_to_locales[language_name]
- self.language_combobox.addItem(language_name, QtCore.QVariant(locale))
+ self.language_combobox.addItem(language_name, locale)
language_layout = QtWidgets.QHBoxLayout()
language_layout.addWidget(language_label)
language_layout.addWidget(self.language_combobox)
@@ -460,7 +460,7 @@ class SettingsDialog(QtWidgets.QDialog):
self._update_autoupdate_timestamp(autoupdate_timestamp)
locale = self.old_settings.get("locale")
- locale_index = self.language_combobox.findData(QtCore.QVariant(locale))
+ locale_index = self.language_combobox.findData(locale)
self.language_combobox.setCurrentIndex(locale_index)
connection_type = self.old_settings.get("connection_type")
@@ -665,9 +665,14 @@ class SettingsDialog(QtWidgets.QDialog):
else:
tor_status_update_func = None
- onion = Onion(self.common, use_tmp_dir=True)
+ onion = Onion(
+ self.common,
+ use_tmp_dir=True,
+ get_tor_paths=self.common.gui.get_tor_paths,
+ )
onion.connect(
- custom_settings=settings, tor_status_update_func=tor_status_update_func,
+ custom_settings=settings,
+ tor_status_update_func=tor_status_update_func,
)
# If an exception hasn't been raised yet, the Tor settings work
diff --git a/onionshare/strings.py b/desktop/src/onionshare/strings.py
index 7e1756e3..ce9207da 100644
--- a/onionshare/strings.py
+++ b/desktop/src/onionshare/strings.py
@@ -25,7 +25,7 @@ strings = {}
translations = {}
-def load_strings(common):
+def load_strings(common, locale_dir):
"""
Loads translated strings and fallback to English
if the translation does not exist.
@@ -35,7 +35,6 @@ def load_strings(common):
# Load all translations
translations = {}
for locale in common.settings.available_locales:
- locale_dir = common.get_resource_path("locale")
filename = os.path.join(locale_dir, f"{locale}.json")
with open(filename, encoding="utf-8") as f:
translations[locale] = json.load(f)
diff --git a/onionshare_gui/tab/__init__.py b/desktop/src/onionshare/tab/__init__.py
index 162d13aa..162d13aa 100644
--- a/onionshare_gui/tab/__init__.py
+++ b/desktop/src/onionshare/tab/__init__.py
diff --git a/onionshare_gui/tab/mode/__init__.py b/desktop/src/onionshare/tab/mode/__init__.py
index 65e46444..f92632f0 100644
--- a/onionshare_gui/tab/mode/__init__.py
+++ b/desktop/src/onionshare/tab/mode/__init__.py
@@ -18,15 +18,15 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
-from PyQt5 import QtCore, QtWidgets, QtGui
+from PySide2 import QtCore, QtWidgets, QtGui
-from onionshare import strings
-from onionshare.common import AutoStopTimer
+from onionshare_cli.common import AutoStopTimer
from .history import IndividualFileHistoryItem
from .mode_settings_widget import ModeSettingsWidget
from ..server_status import ServerStatus
+from ... import strings
from ...threads import OnionThread, AutoStartTimer
from ...widgets import Alert
@@ -36,14 +36,14 @@ class Mode(QtWidgets.QWidget):
The class that all modes inherit from
"""
- start_server_finished = QtCore.pyqtSignal()
- stop_server_finished = QtCore.pyqtSignal()
- starting_server_step2 = QtCore.pyqtSignal()
- starting_server_step3 = QtCore.pyqtSignal()
- starting_server_error = QtCore.pyqtSignal(str)
- starting_server_early = QtCore.pyqtSignal()
- set_server_active = QtCore.pyqtSignal(bool)
- change_persistent = QtCore.pyqtSignal(int, bool)
+ start_server_finished = QtCore.Signal()
+ stop_server_finished = QtCore.Signal()
+ starting_server_step2 = QtCore.Signal()
+ starting_server_step3 = QtCore.Signal()
+ starting_server_error = QtCore.Signal(str)
+ starting_server_early = QtCore.Signal()
+ set_server_active = QtCore.Signal(bool)
+ change_persistent = QtCore.Signal(int, bool)
def __init__(self, tab):
super(Mode, self).__init__()
diff --git a/onionshare_gui/tab/mode/chat_mode/__init__.py b/desktop/src/onionshare/tab/mode/chat_mode/__init__.py
index 4de9f387..25a02969 100644
--- a/onionshare_gui/tab/mode/chat_mode/__init__.py
+++ b/desktop/src/onionshare/tab/mode/chat_mode/__init__.py
@@ -22,15 +22,16 @@ import os
import random
import string
-from PyQt5 import QtCore, QtWidgets, QtGui
+from PySide2 import QtCore, QtWidgets, QtGui
-from onionshare import strings
-from onionshare.onion import *
-from onionshare.common import Common
-from onionshare.web import Web
+from onionshare_cli.onion import *
+from onionshare_cli.common import Common
+from onionshare_cli.web import Web
from .. import Mode
+from .... import strings
from ....widgets import MinimumWidthWidget
+from ....gui_common import GuiCommon
class ChatMode(Mode):
@@ -38,8 +39,8 @@ class ChatMode(Mode):
Parts of the main window UI for sharing files.
"""
- success = QtCore.pyqtSignal()
- error = QtCore.pyqtSignal(str)
+ success = QtCore.Signal()
+ error = QtCore.Signal(str)
def init(self):
"""
@@ -52,7 +53,7 @@ class ChatMode(Mode):
self.image_label = QtWidgets.QLabel()
self.image_label.setPixmap(
QtGui.QPixmap.fromImage(
- QtGui.QImage(self.common.get_resource_path("images/mode_chat.png"))
+ QtGui.QImage(GuiCommon.get_resource_path("images/mode_chat.png"))
)
)
self.image_label.setFixedSize(300, 300)
diff --git a/onionshare_gui/tab/mode/file_selection.py b/desktop/src/onionshare/tab/mode/file_selection.py
index a3212c96..54d9ea83 100644
--- a/onionshare_gui/tab/mode/file_selection.py
+++ b/desktop/src/onionshare/tab/mode/file_selection.py
@@ -19,11 +19,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
import os
-from PyQt5 import QtCore, QtWidgets, QtGui
-
-from onionshare import strings
+from PySide2 import QtCore, QtWidgets, QtGui
+from ... import strings
from ...widgets import Alert, AddFileDialog
+from ...gui_common import GuiCommon
class DropHereWidget(QtWidgets.QWidget):
@@ -40,7 +40,7 @@ class DropHereWidget(QtWidgets.QWidget):
self.image_label = QtWidgets.QLabel(parent=self)
self.image_label.setPixmap(
QtGui.QPixmap.fromImage(
- QtGui.QImage(self.common.get_resource_path(image_filename))
+ QtGui.QImage(GuiCommon.get_resource_path(image_filename))
)
)
self.image_label.setAlignment(QtCore.Qt.AlignCenter)
@@ -104,8 +104,8 @@ class FileList(QtWidgets.QListWidget):
The list of files and folders in the GUI.
"""
- files_dropped = QtCore.pyqtSignal()
- files_updated = QtCore.pyqtSignal()
+ files_dropped = QtCore.Signal()
+ files_updated = QtCore.Signal()
def __init__(self, common, background_image_filename, header_text, parent=None):
super(FileList, self).__init__(parent)
@@ -291,7 +291,7 @@ class FileList(QtWidgets.QListWidget):
item.item_button.setDefault(False)
item.item_button.setFlat(True)
item.item_button.setIcon(
- QtGui.QIcon(self.common.get_resource_path("images/file_delete.png"))
+ QtGui.QIcon(GuiCommon.get_resource_path("images/file_delete.png"))
)
item.item_button.clicked.connect(delete_item)
item.item_button.setSizePolicy(
diff --git a/onionshare_gui/tab/mode/history.py b/desktop/src/onionshare/tab/mode/history.py
index feb671ef..3e9c0571 100644
--- a/onionshare_gui/tab/mode/history.py
+++ b/desktop/src/onionshare/tab/mode/history.py
@@ -22,10 +22,11 @@ import time
import subprocess
import os
from datetime import datetime
-from PyQt5 import QtCore, QtWidgets, QtGui
+from PySide2 import QtCore, QtWidgets, QtGui
-from onionshare import strings
+from ... import strings
from ...widgets import Alert
+from ...gui_common import GuiCommon
class HistoryItem(QtWidgets.QWidget):
@@ -199,7 +200,7 @@ class ReceiveHistoryItemFile(QtWidgets.QWidget):
# Folder button
folder_pixmap = QtGui.QPixmap.fromImage(
- QtGui.QImage(self.common.get_resource_path("images/open_folder.png"))
+ QtGui.QImage(GuiCommon.get_resource_path("images/open_folder.png"))
)
folder_icon = QtGui.QIcon(folder_pixmap)
self.folder_button = QtWidgets.QPushButton()
@@ -699,9 +700,9 @@ class History(QtWidgets.QWidget):
Update the 'completed' widget.
"""
if self.completed_count == 0:
- image = self.common.get_resource_path("images/history_completed_none.png")
+ image = GuiCommon.get_resource_path("images/history_completed_none.png")
else:
- image = self.common.get_resource_path("images/history_completed.png")
+ image = GuiCommon.get_resource_path("images/history_completed.png")
self.completed_label.setText(f'<img src="{image}" /> {self.completed_count}')
self.completed_label.setToolTip(
strings._("history_completed_tooltip").format(self.completed_count)
@@ -712,9 +713,9 @@ class History(QtWidgets.QWidget):
Update the 'in progress' widget.
"""
if self.in_progress_count == 0:
- image = self.common.get_resource_path("images/history_in_progress_none.png")
+ image = GuiCommon.get_resource_path("images/history_in_progress_none.png")
else:
- image = self.common.get_resource_path("images/history_in_progress.png")
+ image = GuiCommon.get_resource_path("images/history_in_progress.png")
self.in_progress_label.setText(
f'<img src="{image}" /> {self.in_progress_count}'
@@ -728,9 +729,9 @@ class History(QtWidgets.QWidget):
Update the 'web requests' widget.
"""
if self.requests_count == 0:
- image = self.common.get_resource_path("images/history_requests_none.png")
+ image = GuiCommon.get_resource_path("images/history_requests_none.png")
else:
- image = self.common.get_resource_path("images/history_requests.png")
+ image = GuiCommon.get_resource_path("images/history_requests.png")
self.requests_label.setText(f'<img src="{image}" /> {self.requests_count}')
self.requests_label.setToolTip(
diff --git a/onionshare_gui/tab/mode/mode_settings_widget.py b/desktop/src/onionshare/tab/mode/mode_settings_widget.py
index 7c3b4667..39226540 100644
--- a/onionshare_gui/tab/mode/mode_settings_widget.py
+++ b/desktop/src/onionshare/tab/mode/mode_settings_widget.py
@@ -18,9 +18,9 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
-from PyQt5 import QtCore, QtWidgets
+from PySide2 import QtCore, QtWidgets
-from onionshare import strings
+from ... import strings
class ModeSettingsWidget(QtWidgets.QWidget):
@@ -28,7 +28,7 @@ class ModeSettingsWidget(QtWidgets.QWidget):
All of the common settings for each mode are in this widget
"""
- change_persistent = QtCore.pyqtSignal(int, bool)
+ change_persistent = QtCore.Signal(int, bool)
def __init__(self, common, tab, mode_settings):
super(ModeSettingsWidget, self).__init__()
diff --git a/onionshare_gui/tab/mode/receive_mode/__init__.py b/desktop/src/onionshare/tab/mode/receive_mode/__init__.py
index e6ca6f70..95d1ecbe 100644
--- a/onionshare_gui/tab/mode/receive_mode/__init__.py
+++ b/desktop/src/onionshare/tab/mode/receive_mode/__init__.py
@@ -19,14 +19,15 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
import os
-from PyQt5 import QtCore, QtWidgets, QtGui
+from PySide2 import QtCore, QtWidgets, QtGui
-from onionshare import strings
-from onionshare.web import Web
+from onionshare_cli.web import Web
from ..history import History, ToggleHistory, ReceiveHistoryItem
from .. import Mode
+from .... import strings
from ....widgets import MinimumWidthWidget, Alert
+from ....gui_common import GuiCommon
class ReceiveMode(Mode):
@@ -45,7 +46,7 @@ class ReceiveMode(Mode):
self.image_label = QtWidgets.QLabel()
self.image_label.setPixmap(
QtGui.QPixmap.fromImage(
- QtGui.QImage(self.common.get_resource_path("images/mode_receive.png"))
+ QtGui.QImage(GuiCommon.get_resource_path("images/mode_receive.png"))
)
)
self.image_label.setFixedSize(250, 250)
@@ -87,7 +88,7 @@ class ReceiveMode(Mode):
self.common,
QtGui.QPixmap.fromImage(
QtGui.QImage(
- self.common.get_resource_path("images/receive_icon_transparent.png")
+ GuiCommon.get_resource_path("images/receive_icon_transparent.png")
)
),
strings._("gui_receive_mode_no_files"),
@@ -100,11 +101,9 @@ class ReceiveMode(Mode):
self.common,
self,
self.history,
+ QtGui.QIcon(GuiCommon.get_resource_path("images/receive_icon_toggle.png")),
QtGui.QIcon(
- self.common.get_resource_path("images/receive_icon_toggle.png")
- ),
- QtGui.QIcon(
- self.common.get_resource_path("images/receive_icon_toggle_selected.png")
+ GuiCommon.get_resource_path("images/receive_icon_toggle_selected.png")
),
)
@@ -140,7 +139,6 @@ class ReceiveMode(Mode):
row_layout.addWidget(self.server_status)
row_layout.addStretch()
-
# Column layout
self.column_layout = QtWidgets.QHBoxLayout()
self.column_layout.addLayout(row_layout)
diff --git a/onionshare_gui/tab/mode/share_mode/__init__.py b/desktop/src/onionshare/tab/mode/share_mode/__init__.py
index ab4e320c..ccf85dbd 100644
--- a/onionshare_gui/tab/mode/share_mode/__init__.py
+++ b/desktop/src/onionshare/tab/mode/share_mode/__init__.py
@@ -19,18 +19,19 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
import os
-from PyQt5 import QtCore, QtWidgets, QtGui
+from PySide2 import QtCore, QtWidgets, QtGui
-from onionshare import strings
-from onionshare.onion import *
-from onionshare.common import Common
-from onionshare.web import Web
+from onionshare_cli.onion import *
+from onionshare_cli.common import Common
+from onionshare_cli.web import Web
-from ..file_selection import FileSelection
from .threads import CompressThread
from .. import Mode
+from ..file_selection import FileSelection
from ..history import History, ToggleHistory, ShareHistoryItem
+from .... import strings
from ....widgets import Alert, MinimumWidthWidget
+from ....gui_common import GuiCommon
class ShareMode(Mode):
@@ -102,7 +103,7 @@ class ShareMode(Mode):
self.common,
QtGui.QPixmap.fromImage(
QtGui.QImage(
- self.common.get_resource_path("images/share_icon_transparent.png")
+ GuiCommon.get_resource_path("images/share_icon_transparent.png")
)
),
strings._("gui_share_mode_no_files"),
@@ -130,9 +131,9 @@ class ShareMode(Mode):
self.common,
self,
self.history,
- QtGui.QIcon(self.common.get_resource_path("images/share_icon_toggle.png")),
+ QtGui.QIcon(GuiCommon.get_resource_path("images/share_icon_toggle.png")),
QtGui.QIcon(
- self.common.get_resource_path("images/share_icon_toggle_selected.png")
+ GuiCommon.get_resource_path("images/share_icon_toggle_selected.png")
),
)
@@ -426,7 +427,7 @@ class ShareMode(Mode):
class ZipProgressBar(QtWidgets.QProgressBar):
- update_processed_size_signal = QtCore.pyqtSignal(int)
+ update_processed_size_signal = QtCore.Signal(int)
def __init__(self, common, total_files_size):
super(ZipProgressBar, self).__init__()
diff --git a/onionshare_gui/tab/mode/share_mode/threads.py b/desktop/src/onionshare/tab/mode/share_mode/threads.py
index 500b6525..860c2d26 100644
--- a/onionshare_gui/tab/mode/share_mode/threads.py
+++ b/desktop/src/onionshare/tab/mode/share_mode/threads.py
@@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
-from PyQt5 import QtCore
+from PySide2 import QtCore
class CompressThread(QtCore.QThread):
@@ -26,8 +26,8 @@ class CompressThread(QtCore.QThread):
Compresses files to be shared
"""
- success = QtCore.pyqtSignal()
- error = QtCore.pyqtSignal(str)
+ success = QtCore.Signal()
+ error = QtCore.Signal(str)
def __init__(self, mode):
super(CompressThread, self).__init__()
diff --git a/onionshare_gui/tab/mode/website_mode/__init__.py b/desktop/src/onionshare/tab/mode/website_mode/__init__.py
index 96fcdea3..325b22f1 100644
--- a/onionshare_gui/tab/mode/website_mode/__init__.py
+++ b/desktop/src/onionshare/tab/mode/website_mode/__init__.py
@@ -22,17 +22,18 @@ import os
import random
import string
-from PyQt5 import QtCore, QtWidgets, QtGui
+from PySide2 import QtCore, QtWidgets, QtGui
-from onionshare import strings
-from onionshare.onion import *
-from onionshare.common import Common
-from onionshare.web import Web
+from onionshare_cli.onion import *
+from onionshare_cli.common import Common
+from onionshare_cli.web import Web
-from ..file_selection import FileSelection
from .. import Mode
+from ..file_selection import FileSelection
from ..history import History, ToggleHistory
+from .... import strings
from ....widgets import Alert, MinimumWidthWidget
+from ....gui_common import GuiCommon
class WebsiteMode(Mode):
@@ -40,8 +41,8 @@ class WebsiteMode(Mode):
Parts of the main window UI for sharing files.
"""
- success = QtCore.pyqtSignal()
- error = QtCore.pyqtSignal(str)
+ success = QtCore.Signal()
+ error = QtCore.Signal(str)
def init(self):
"""
@@ -102,7 +103,7 @@ class WebsiteMode(Mode):
self.common,
QtGui.QPixmap.fromImage(
QtGui.QImage(
- self.common.get_resource_path("images/share_icon_transparent.png")
+ GuiCommon.get_resource_path("images/share_icon_transparent.png")
)
),
strings._("gui_website_mode_no_files"),
@@ -133,9 +134,9 @@ class WebsiteMode(Mode):
self.common,
self,
self.history,
- QtGui.QIcon(self.common.get_resource_path("images/share_icon_toggle.png")),
+ QtGui.QIcon(GuiCommon.get_resource_path("images/share_icon_toggle.png")),
QtGui.QIcon(
- self.common.get_resource_path("images/share_icon_toggle_selected.png")
+ GuiCommon.get_resource_path("images/share_icon_toggle_selected.png")
),
)
diff --git a/onionshare_gui/tab/server_status.py b/desktop/src/onionshare/tab/server_status.py
index efa50669..29c72300 100644
--- a/onionshare_gui/tab/server_status.py
+++ b/desktop/src/onionshare/tab/server_status.py
@@ -20,13 +20,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import platform
import textwrap
-from PyQt5 import QtCore, QtWidgets, QtGui
-from PyQt5.QtCore import Qt
-
-from onionshare import strings
+from PySide2 import QtCore, QtWidgets, QtGui
+from PySide2.QtCore import Qt
+from .. import strings
from ..widgets import Alert
from ..widgets import QRCodeDialog
+from ..gui_common import GuiCommon
class ServerStatus(QtWidgets.QWidget):
@@ -34,13 +34,13 @@ class ServerStatus(QtWidgets.QWidget):
The server status chunk of the GUI.
"""
- server_started = QtCore.pyqtSignal()
- server_started_finished = QtCore.pyqtSignal()
- server_stopped = QtCore.pyqtSignal()
- server_canceled = QtCore.pyqtSignal()
- button_clicked = QtCore.pyqtSignal()
- url_copied = QtCore.pyqtSignal()
- hidservauth_copied = QtCore.pyqtSignal()
+ server_started = QtCore.Signal()
+ server_started_finished = QtCore.Signal()
+ server_stopped = QtCore.Signal()
+ server_canceled = QtCore.Signal()
+ button_clicked = QtCore.Signal()
+ url_copied = QtCore.Signal()
+ hidservauth_copied = QtCore.Signal()
STATUS_STOPPED = 0
STATUS_WORKING = 1
@@ -175,7 +175,7 @@ class ServerStatus(QtWidgets.QWidget):
"""
self.url_description.show()
- info_image = self.common.get_resource_path("images/info.png")
+ info_image = GuiCommon.get_resource_path("images/info.png")
if self.mode == self.common.gui.MODE_SHARE:
self.url_description.setText(
@@ -324,17 +324,17 @@ class ServerStatus(QtWidgets.QWidget):
if self.settings.get("general", "autostart_timer"):
if self.local_only:
self.autostart_timer_datetime = (
- self.mode_settings_widget.autostart_timer_widget.dateTime().toPyDateTime()
+ self.mode_settings_widget.autostart_timer_widget.dateTime().toPython()
)
else:
self.autostart_timer_datetime = (
self.mode_settings_widget.autostart_timer_widget.dateTime()
- .toPyDateTime()
+ .toPython()
.replace(second=0, microsecond=0)
)
# If the timer has actually passed already before the user hit Start, refuse to start the server.
if (
- QtCore.QDateTime.currentDateTime().toPyDateTime()
+ QtCore.QDateTime.currentDateTime().toPython()
> self.autostart_timer_datetime
):
can_start = False
@@ -346,18 +346,18 @@ class ServerStatus(QtWidgets.QWidget):
if self.settings.get("general", "autostop_timer"):
if self.local_only:
self.autostop_timer_datetime = (
- self.mode_settings_widget.autostop_timer_widget.dateTime().toPyDateTime()
+ self.mode_settings_widget.autostop_timer_widget.dateTime().toPython()
)
else:
# Get the timer chosen, stripped of its seconds. This prevents confusion if the share stops at (say) 37 seconds past the minute chosen
self.autostop_timer_datetime = (
self.mode_settings_widget.autostop_timer_widget.dateTime()
- .toPyDateTime()
+ .toPython()
.replace(second=0, microsecond=0)
)
# If the timer has actually passed already before the user hit Start, refuse to start the server.
if (
- QtCore.QDateTime.currentDateTime().toPyDateTime()
+ QtCore.QDateTime.currentDateTime().toPython()
> self.autostop_timer_datetime
):
can_start = False
diff --git a/onionshare_gui/tab/tab.py b/desktop/src/onionshare/tab/tab.py
index ae987729..5e819405 100644
--- a/onionshare_gui/tab/tab.py
+++ b/desktop/src/onionshare/tab/tab.py
@@ -19,12 +19,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
import queue
-from PyQt5 import QtCore, QtWidgets, QtGui
+from PySide2 import QtCore, QtWidgets, QtGui
-from onionshare import strings
-from onionshare.onionshare import OnionShare
-from onionshare.web import Web
-from onionshare.mode_settings import ModeSettings
+from onionshare_cli.onionshare import OnionShare
+from onionshare_cli.web import Web
+from onionshare_cli.mode_settings import ModeSettings
from .mode.share_mode import ShareMode
from .mode.receive_mode import ReceiveMode
@@ -33,6 +32,8 @@ from .mode.chat_mode import ChatMode
from .server_status import ServerStatus
+from .. import strings
+from ..gui_common import GuiCommon
from ..widgets import Alert
@@ -47,7 +48,7 @@ class NewTabButton(QtWidgets.QPushButton):
self.image_label = QtWidgets.QLabel(parent=self)
self.image_label.setPixmap(
QtGui.QPixmap.fromImage(
- QtGui.QImage(self.common.get_resource_path(image_filename))
+ QtGui.QImage(GuiCommon.get_resource_path(image_filename))
)
)
self.image_label.setAlignment(QtCore.Qt.AlignCenter)
@@ -79,9 +80,9 @@ class Tab(QtWidgets.QWidget):
A GUI tab, you know, sort of like in a web browser
"""
- change_title = QtCore.pyqtSignal(int, str)
- change_icon = QtCore.pyqtSignal(int, str)
- change_persistent = QtCore.pyqtSignal(int, bool)
+ change_title = QtCore.Signal(int, str)
+ change_icon = QtCore.Signal(int, str)
+ change_persistent = QtCore.Signal(int, bool)
def __init__(
self,
@@ -106,11 +107,15 @@ class Tab(QtWidgets.QWidget):
# Start the OnionShare app
self.app = OnionShare(common, self.common.gui.onion, self.common.gui.local_only)
+ # An invisible widget, used for hiding the persistent tab icon
+ self.invisible_widget = QtWidgets.QWidget()
+ self.invisible_widget.setFixedSize(0, 0)
+
# Onionshare logo
self.image_label = QtWidgets.QLabel()
self.image_label.setPixmap(
QtGui.QPixmap.fromImage(
- QtGui.QImage(self.common.get_resource_path("images/logo_text.png"))
+ QtGui.QImage(GuiCommon.get_resource_path("images/logo_text.png"))
)
)
self.image_label.setFixedSize(160, 40)
@@ -196,7 +201,7 @@ class Tab(QtWidgets.QWidget):
self.persistent_image_label.setPixmap(
QtGui.QPixmap.fromImage(
QtGui.QImage(
- self.common.get_resource_path("images/persistent_enabled.png")
+ GuiCommon.get_resource_path("images/persistent_enabled.png")
)
)
)
@@ -658,4 +663,7 @@ class Tab(QtWidgets.QWidget):
return False
def cleanup(self):
+ if self.get_mode() and self.get_mode().web_thread:
+ self.get_mode().web_thread.quit()
+ self.get_mode().web_thread.wait()
self.app.cleanup()
diff --git a/onionshare_gui/tab_widget.py b/desktop/src/onionshare/tab_widget.py
index fe80b95d..84d16e83 100644
--- a/onionshare_gui/tab_widget.py
+++ b/desktop/src/onionshare/tab_widget.py
@@ -18,13 +18,14 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
-from PyQt5 import QtCore, QtWidgets, QtGui
+from PySide2 import QtCore, QtWidgets, QtGui
-from onionshare import strings
-from onionshare.mode_settings import ModeSettings
+from onionshare_cli.mode_settings import ModeSettings
+from . import strings
from .tab import Tab
from .threads import EventHandlerThread
+from .gui_common import GuiCommon
class TabWidget(QtWidgets.QTabWidget):
@@ -32,7 +33,7 @@ class TabWidget(QtWidgets.QTabWidget):
A custom tab widget, that has a "+" button for adding new tabs
"""
- bring_to_front = QtCore.pyqtSignal()
+ bring_to_front = QtCore.Signal()
def __init__(self, common, system_tray, status_bar):
super(TabWidget, self).__init__()
@@ -143,6 +144,7 @@ class TabWidget(QtWidgets.QTabWidget):
self.add_tab(mode_settings)
def add_tab(self, mode_settings=None):
+ self.common.log("TabWidget", "add_tab", f"mode_settings: {mode_settings}")
tab = Tab(self.common, self.current_tab_id, self.system_tray, self.status_bar)
tab.change_title.connect(self.change_title)
tab.change_icon.connect(self.change_icon)
@@ -154,18 +156,22 @@ class TabWidget(QtWidgets.QTabWidget):
index = self.addTab(tab, strings._("gui_new_tab"))
self.setCurrentIndex(index)
- # Create a close button
- def close_tab():
- self.tabBar().tabCloseRequested.emit(self.indexOf(tab))
+ # In macOS, manually create a close button because tabs don't seem to have them otherwise
+ if self.common.platform == "Darwin":
- close_button = QtWidgets.QPushButton()
- close_button.setFlat(True)
- close_button.setFixedWidth(40)
- close_button.setIcon(
- QtGui.QIcon(self.common.get_resource_path("images/close_tab.png"))
- )
- close_button.clicked.connect(close_tab)
- self.tabBar().setTabButton(index, QtWidgets.QTabBar.RightSide, close_button)
+ def close_tab():
+ self.tabBar().tabCloseRequested.emit(self.indexOf(tab))
+
+ tab.close_button = QtWidgets.QPushButton()
+ tab.close_button.setFlat(True)
+ tab.close_button.setFixedWidth(40)
+ tab.close_button.setIcon(
+ QtGui.QIcon(GuiCommon.get_resource_path("images/close_tab.png"))
+ )
+ tab.close_button.clicked.connect(close_tab)
+ self.tabBar().setTabButton(
+ index, QtWidgets.QTabBar.RightSide, tab.close_button
+ )
tab.init(mode_settings)
# If it's persistent, set the persistent image in the tab
@@ -180,9 +186,14 @@ class TabWidget(QtWidgets.QTabWidget):
def change_icon(self, tab_id, icon_path):
index = self.indexOf(self.tabs[tab_id])
- self.setTabIcon(index, QtGui.QIcon(self.common.get_resource_path(icon_path)))
+ self.setTabIcon(index, QtGui.QIcon(GuiCommon.get_resource_path(icon_path)))
def change_persistent(self, tab_id, is_persistent):
+ self.common.log(
+ "TabWidget",
+ "change_persistent",
+ f"tab_id: {tab_id}, is_persistent: {is_persistent}",
+ )
index = self.indexOf(self.tabs[tab_id])
if is_persistent:
self.tabBar().setTabButton(
@@ -191,10 +202,8 @@ class TabWidget(QtWidgets.QTabWidget):
self.tabs[tab_id].persistent_image_label,
)
else:
- invisible_widget = QtWidgets.QWidget()
- invisible_widget.setFixedSize(0, 0)
self.tabBar().setTabButton(
- index, QtWidgets.QTabBar.LeftSide, invisible_widget
+ index, QtWidgets.QTabBar.LeftSide, self.tabs[tab_id].invisible_widget
)
self.save_persistent_tabs()
@@ -258,7 +267,7 @@ class TabBar(QtWidgets.QTabBar):
A custom tab bar
"""
- move_new_tab_button = QtCore.pyqtSignal()
+ move_new_tab_button = QtCore.Signal()
def __init__(self):
super(TabBar, self).__init__()
diff --git a/onionshare_gui/threads.py b/desktop/src/onionshare/threads.py
index d1e6ea3c..338bbf27 100644
--- a/onionshare_gui/threads.py
+++ b/desktop/src/onionshare/threads.py
@@ -21,10 +21,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import time
import json
import os
-from PyQt5 import QtCore
+from PySide2 import QtCore
-from onionshare import strings
-from onionshare.onion import (
+from onionshare_cli.onion import (
TorTooOld,
TorErrorInvalidSetting,
TorErrorAutomatic,
@@ -37,15 +36,17 @@ from onionshare.onion import (
BundledTorTimeout,
)
+from . import strings
+
class OnionThread(QtCore.QThread):
"""
Starts the onion service, and waits for it to finish
"""
- success = QtCore.pyqtSignal()
- success_early = QtCore.pyqtSignal()
- error = QtCore.pyqtSignal(str)
+ success = QtCore.Signal()
+ success_early = QtCore.Signal()
+ error = QtCore.Signal(str)
def __init__(self, mode):
super(OnionThread, self).__init__()
@@ -113,8 +114,8 @@ class WebThread(QtCore.QThread):
Starts the web service
"""
- success = QtCore.pyqtSignal()
- error = QtCore.pyqtSignal(str)
+ success = QtCore.Signal()
+ error = QtCore.Signal(str)
def __init__(self, mode):
super(WebThread, self).__init__()
@@ -132,8 +133,8 @@ class AutoStartTimer(QtCore.QThread):
Waits for a prescribed time before allowing a share to start
"""
- success = QtCore.pyqtSignal()
- error = QtCore.pyqtSignal(str)
+ success = QtCore.Signal()
+ error = QtCore.Signal(str)
def __init__(self, mode, canceled=False):
super(AutoStartTimer, self).__init__()
@@ -179,8 +180,8 @@ class EventHandlerThread(QtCore.QThread):
{"type": "new_share_tab", "filenames": ["file1", "file2"]}
"""
- new_tab = QtCore.pyqtSignal()
- new_share_tab = QtCore.pyqtSignal(list)
+ new_tab = QtCore.Signal()
+ new_share_tab = QtCore.Signal(list)
def __init__(self, common):
super(EventHandlerThread, self).__init__()
diff --git a/onionshare_gui/tor_connection_dialog.py b/desktop/src/onionshare/tor_connection_dialog.py
index 02868625..d5fa72a0 100644
--- a/onionshare_gui/tor_connection_dialog.py
+++ b/desktop/src/onionshare/tor_connection_dialog.py
@@ -18,11 +18,12 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
-from PyQt5 import QtCore, QtWidgets, QtGui
+from PySide2 import QtCore, QtWidgets, QtGui
-from onionshare import strings
-from onionshare.onion import *
+from onionshare_cli.onion import *
+from . import strings
+from .gui_common import GuiCommon
from .widgets import Alert
@@ -31,7 +32,7 @@ class TorConnectionDialog(QtWidgets.QProgressDialog):
Connecting to Tor dialog.
"""
- open_settings = QtCore.pyqtSignal()
+ open_settings = QtCore.Signal()
def __init__(self, common, custom_settings=False):
super(TorConnectionDialog, self).__init__(None)
@@ -46,9 +47,7 @@ class TorConnectionDialog(QtWidgets.QProgressDialog):
self.common.log("TorConnectionDialog", "__init__")
self.setWindowTitle("OnionShare")
- self.setWindowIcon(
- QtGui.QIcon(self.common.get_resource_path("images/logo.png"))
- )
+ self.setWindowIcon(QtGui.QIcon(GuiCommon.get_resource_path("images/logo.png")))
self.setModal(True)
self.setFixedSize(400, 150)
@@ -124,10 +123,10 @@ class TorConnectionDialog(QtWidgets.QProgressDialog):
class TorConnectionThread(QtCore.QThread):
- tor_status_update = QtCore.pyqtSignal(str, str)
- connected_to_tor = QtCore.pyqtSignal()
- canceled_connecting_to_tor = QtCore.pyqtSignal()
- error_connecting_to_tor = QtCore.pyqtSignal(str)
+ tor_status_update = QtCore.Signal(str, str)
+ connected_to_tor = QtCore.Signal()
+ canceled_connecting_to_tor = QtCore.Signal()
+ error_connecting_to_tor = QtCore.Signal(str)
def __init__(self, common, settings, dialog):
super(TorConnectionThread, self).__init__()
diff --git a/onionshare_gui/update_checker.py b/desktop/src/onionshare/update_checker.py
index 699ad952..be7a5e01 100644
--- a/onionshare_gui/update_checker.py
+++ b/desktop/src/onionshare/update_checker.py
@@ -18,15 +18,15 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
-from PyQt5 import QtCore
+from PySide2 import QtCore
import datetime, time, socket, re, platform
import socks
from distutils.version import LooseVersion as Version
-from onionshare.settings import Settings
-from onionshare.onion import Onion
+from onionshare_cli.settings import Settings
+from onionshare_cli.onion import Onion
-from onionshare import strings
+from . import strings
class UpdateCheckerCheckError(Exception):
@@ -57,10 +57,10 @@ class UpdateChecker(QtCore.QObject):
Only check at most once per day, unless force is True.
"""
- update_available = QtCore.pyqtSignal(str, str, str)
- update_not_available = QtCore.pyqtSignal()
- update_error = QtCore.pyqtSignal()
- update_invalid_version = QtCore.pyqtSignal(str)
+ update_available = QtCore.Signal(str, str, str)
+ update_not_available = QtCore.Signal()
+ update_error = QtCore.Signal()
+ update_invalid_version = QtCore.Signal(str)
def __init__(self, common, onion):
super(UpdateChecker, self).__init__()
@@ -183,10 +183,10 @@ class UpdateChecker(QtCore.QObject):
class UpdateThread(QtCore.QThread):
- update_available = QtCore.pyqtSignal(str, str, str)
- update_not_available = QtCore.pyqtSignal()
- update_error = QtCore.pyqtSignal()
- update_invalid_version = QtCore.pyqtSignal(str)
+ update_available = QtCore.Signal(str, str, str)
+ update_not_available = QtCore.Signal()
+ update_error = QtCore.Signal()
+ update_invalid_version = QtCore.Signal(str)
def __init__(self, common, onion, force=False):
super(UpdateThread, self).__init__()
diff --git a/onionshare_gui/widgets.py b/desktop/src/onionshare/widgets.py
index 846ff4e7..6fffd77f 100644
--- a/onionshare_gui/widgets.py
+++ b/desktop/src/onionshare/widgets.py
@@ -18,10 +18,12 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
-from PyQt5 import QtCore, QtWidgets, QtGui
-from onionshare import strings
+from PySide2 import QtCore, QtWidgets, QtGui
import qrcode
+from . import strings
+from .gui_common import GuiCommon
+
class Alert(QtWidgets.QMessageBox):
"""
@@ -43,9 +45,7 @@ class Alert(QtWidgets.QMessageBox):
self.common.log("Alert", "__init__")
self.setWindowTitle("OnionShare")
- self.setWindowIcon(
- QtGui.QIcon(self.common.get_resource_path("images/logo.png"))
- )
+ self.setWindowIcon(QtGui.QIcon(GuiCommon.get_resource_path("images/logo.png")))
self.setText(message)
self.setIcon(icon)
self.setStandardButtons(buttons)
@@ -145,9 +145,7 @@ class QRCodeDialog(QtWidgets.QDialog):
self.qr_label_description.setWordWrap(True)
self.setWindowTitle(strings._("gui_qr_code_dialog_title"))
- self.setWindowIcon(
- QtGui.QIcon(self.common.get_resource_path("images/logo.png"))
- )
+ self.setWindowIcon(QtGui.QIcon(GuiCommon.get_resource_path("images/logo.png")))
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(self.qr_label)
layout.addWidget(self.qr_label_description)
diff --git a/install/org.onionshare.OnionShare.appdata.xml b/desktop/src/org.onionshare.OnionShare.appdata.xml
index 3630b89c..835b4877 100644
--- a/install/org.onionshare.OnionShare.appdata.xml
+++ b/desktop/src/org.onionshare.OnionShare.appdata.xml
@@ -24,6 +24,6 @@
<update_contact>micah@micahflee.com</update_contact>
<content_rating type="oars-1.1" />
<releases>
- <release type="development" date="2020-09-20" version="2.3.dev1" />
+ <release type="development" date="2020-11-08" version="2.3.dev2" />
</releases>
</component>
diff --git a/desktop/src/setup.py b/desktop/src/setup.py
new file mode 100644
index 00000000..eb09c101
--- /dev/null
+++ b/desktop/src/setup.py
@@ -0,0 +1,72 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+OnionShare | https://onionshare.org/
+
+Copyright (C) 2014-2020 Micah Lee, et al. <micah@micahflee.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+"""
+
+# This setup.py file is used for flatpak packaging. For other packaging,
+# OnionShare uses briefcase.
+
+import os
+import setuptools
+
+version = "2.3.dev2"
+
+setuptools.setup(
+ name="onionshare",
+ version=version,
+ description="OnionShare lets you securely and anonymously send and receive files. It works by starting a web server, making it accessible as a Tor onion service, and generating an unguessable web address so others can download files from you, or upload files to you. It does _not_ require setting up a separate server or using a third party file-sharing service.",
+ author="Micah Lee",
+ author_email="micah@micahflee.com",
+ maintainer="Micah Lee",
+ maintainer_email="micah@micahflee.com",
+ url="https://onionshare.org",
+ license="GPLv3",
+ keywords="onion, share, onionshare, tor, anonymous, web server",
+ classifiers=[
+ "Programming Language :: Python :: 3",
+ "Framework :: Flask",
+ "Topic :: Communications :: File Sharing",
+ "Topic :: Security :: Cryptography",
+ "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
+ "Intended Audience :: End Users/Desktop",
+ "Operating System :: OS Independent",
+ "Environment :: Web Environment",
+ ],
+ packages=[
+ "onionshare",
+ "onionshare.tab",
+ "onionshare.tab.mode",
+ "onionshare.tab.mode.share_mode",
+ "onionshare.tab.mode.receive_mode",
+ "onionshare.tab.mode.website_mode",
+ "onionshare.tab.mode.chat_mode",
+ ],
+ package_data={
+ "onionshare": [
+ "resources/*",
+ "resources/images/*",
+ "resources/locale/*",
+ ]
+ },
+ entry_points={
+ "console_scripts": [
+ "onionshare = onionshare:main",
+ ],
+ },
+)
diff --git a/desktop/tests/__init__.py b/desktop/tests/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/desktop/tests/__init__.py
diff --git a/desktop/tests/conftest.py b/desktop/tests/conftest.py
new file mode 100644
index 00000000..65d13fa6
--- /dev/null
+++ b/desktop/tests/conftest.py
@@ -0,0 +1,222 @@
+import sys
+
+# Force tests to look for resources in the source code tree
+sys.onionshare_dev_mode = True
+
+# Let OnionShare know the tests are running, to avoid colliding with settings files
+sys.onionshare_test_mode = True
+
+import os
+import shutil
+import tempfile
+from datetime import datetime, timedelta
+
+import pytest
+
+from PySide2 import QtTest, QtGui
+
+
+@staticmethod
+def qWait(t, qtapp):
+ end = datetime.now() + timedelta(milliseconds=t)
+ while datetime.now() < end:
+ qtapp.processEvents()
+
+
+# Monkeypatch qWait, because PySide2 doesn't have it
+# https://stackoverflow.com/questions/17960159/qwait-analogue-in-pyside
+QtTest.QTest.qWait = qWait
+
+# Allow importing onionshare_cli from the source tree
+sys.path.insert(
+ 0,
+ os.path.join(
+ os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))),
+ "cli",
+ ),
+)
+
+from onionshare_cli import common, web, settings
+
+
+# The temporary directory for CLI tests
+test_temp_dir = None
+
+
+def pytest_addoption(parser):
+ parser.addoption(
+ "--runtor", action="store_true", default=False, help="run tor tests"
+ )
+
+
+def pytest_collection_modifyitems(config, items):
+ if not config.getoption("--runtor"):
+ # --runtor given in cli: do not skip tor tests
+ skip_tor = pytest.mark.skip(reason="need --runtor option to run")
+ for item in items:
+ if "tor" in item.keywords:
+ item.add_marker(skip_tor)
+
+
+@pytest.fixture
+def temp_dir():
+ """Creates a persistent temporary directory for the CLI tests to use"""
+ global test_temp_dir
+ if not test_temp_dir:
+ test_temp_dir = tempfile.mkdtemp()
+ return test_temp_dir
+
+
+@pytest.fixture
+def temp_dir_1024(temp_dir):
+ """ Create a temporary directory that has a single file of a
+ particular size (1024 bytes).
+ """
+
+ new_temp_dir = tempfile.mkdtemp(dir=temp_dir)
+ tmp_file, tmp_file_path = tempfile.mkstemp(dir=new_temp_dir)
+ with open(tmp_file, "wb") as f:
+ f.write(b"*" * 1024)
+ return new_temp_dir
+
+
+# pytest > 2.9 only needs @pytest.fixture
+@pytest.yield_fixture
+def temp_dir_1024_delete(temp_dir):
+ """ Create a temporary directory that has a single file of a
+ particular size (1024 bytes). The temporary directory (including
+ the file inside) will be deleted after fixture usage.
+ """
+
+ with tempfile.TemporaryDirectory(dir=temp_dir) as new_temp_dir:
+ tmp_file, tmp_file_path = tempfile.mkstemp(dir=new_temp_dir)
+ with open(tmp_file, "wb") as f:
+ f.write(b"*" * 1024)
+ yield new_temp_dir
+
+
+@pytest.fixture
+def temp_file_1024(temp_dir):
+ """ Create a temporary file of a particular size (1024 bytes). """
+
+ with tempfile.NamedTemporaryFile(delete=False, dir=temp_dir) as tmp_file:
+ tmp_file.write(b"*" * 1024)
+ return tmp_file.name
+
+
+# pytest > 2.9 only needs @pytest.fixture
+@pytest.yield_fixture
+def temp_file_1024_delete(temp_dir):
+ """
+ Create a temporary file of a particular size (1024 bytes).
+ The temporary file will be deleted after fixture usage.
+ """
+
+ with tempfile.NamedTemporaryFile(dir=temp_dir, delete=False) as tmp_file:
+ tmp_file.write(b"*" * 1024)
+ tmp_file.flush()
+ tmp_file.close()
+ yield tmp_file.name
+
+
+# pytest > 2.9 only needs @pytest.fixture
+@pytest.yield_fixture(scope="session")
+def custom_zw():
+ zw = web.share_mode.ZipWriter(
+ common.Common(),
+ zip_filename=common.Common.random_string(4, 6),
+ processed_size_callback=lambda _: "custom_callback",
+ )
+ yield zw
+ zw.close()
+ os.remove(zw.zip_filename)
+
+
+# pytest > 2.9 only needs @pytest.fixture
+@pytest.yield_fixture(scope="session")
+def default_zw():
+ zw = web.share_mode.ZipWriter(common.Common())
+ yield zw
+ zw.close()
+ tmp_dir = os.path.dirname(zw.zip_filename)
+ try:
+ shutil.rmtree(tmp_dir, ignore_errors=True)
+ except:
+ pass
+
+
+@pytest.fixture
+def locale_en(monkeypatch):
+ monkeypatch.setattr("locale.getdefaultlocale", lambda: ("en_US", "UTF-8"))
+
+
+@pytest.fixture
+def locale_fr(monkeypatch):
+ monkeypatch.setattr("locale.getdefaultlocale", lambda: ("fr_FR", "UTF-8"))
+
+
+@pytest.fixture
+def locale_invalid(monkeypatch):
+ monkeypatch.setattr("locale.getdefaultlocale", lambda: ("xx_XX", "UTF-8"))
+
+
+@pytest.fixture
+def locale_ru(monkeypatch):
+ monkeypatch.setattr("locale.getdefaultlocale", lambda: ("ru_RU", "UTF-8"))
+
+
+@pytest.fixture
+def platform_darwin(monkeypatch):
+ monkeypatch.setattr("platform.system", lambda: "Darwin")
+
+
+@pytest.fixture # (scope="session")
+def platform_linux(monkeypatch):
+ monkeypatch.setattr("platform.system", lambda: "Linux")
+
+
+@pytest.fixture
+def platform_windows(monkeypatch):
+ monkeypatch.setattr("platform.system", lambda: "Windows")
+
+
+@pytest.fixture
+def sys_argv_sys_prefix(monkeypatch):
+ monkeypatch.setattr("sys.argv", [sys.prefix])
+
+
+@pytest.fixture
+def sys_frozen(monkeypatch):
+ monkeypatch.setattr("sys.frozen", True, raising=False)
+
+
+@pytest.fixture
+def sys_meipass(monkeypatch):
+ monkeypatch.setattr("sys._MEIPASS", os.path.expanduser("~"), raising=False)
+
+
+@pytest.fixture # (scope="session")
+def sys_onionshare_dev_mode(monkeypatch):
+ monkeypatch.setattr("sys.onionshare_dev_mode", True, raising=False)
+
+
+@pytest.fixture
+def time_time_100(monkeypatch):
+ monkeypatch.setattr("time.time", lambda: 100)
+
+
+@pytest.fixture
+def time_strftime(monkeypatch):
+ monkeypatch.setattr("time.strftime", lambda _: "Jun 06 2013 11:05:00")
+
+
+@pytest.fixture
+def common_obj():
+ return common.Common()
+
+
+@pytest.fixture
+def settings_obj(sys_onionshare_dev_mode, platform_linux):
+ _common = common.Common()
+ _common.version = "DUMMY_VERSION_1.2.3"
+ return settings.Settings(_common)
diff --git a/tests/gui_base_test.py b/desktop/tests/gui_base_test.py
index 2b9bcd99..214da945 100644
--- a/tests/gui_base_test.py
+++ b/desktop/tests/gui_base_test.py
@@ -10,18 +10,18 @@ import tempfile
import secrets
import platform
-from PyQt5 import QtCore, QtTest, QtWidgets
+from PySide2 import QtCore, QtTest, QtWidgets
-from onionshare import strings
-from onionshare.common import Common
-from onionshare.settings import Settings
-from onionshare.onion import Onion
-from onionshare.web import Web
+from onionshare_cli.common import Common
+from onionshare_cli.settings import Settings
+from onionshare_cli.onion import Onion
+from onionshare_cli.web import Web
-from onionshare_gui import Application, MainWindow, GuiCommon
-from onionshare_gui.tab.mode.share_mode import ShareMode
-from onionshare_gui.tab.mode.receive_mode import ReceiveMode
-from onionshare_gui.tab.mode.website_mode import WebsiteMode
+from onionshare import Application, MainWindow, GuiCommon
+from onionshare.tab.mode.share_mode import ShareMode
+from onionshare.tab.mode.receive_mode import ReceiveMode
+from onionshare.tab.mode.website_mode import WebsiteMode
+from onionshare import strings
class GuiBaseTest(unittest.TestCase):
@@ -82,7 +82,7 @@ class GuiBaseTest(unittest.TestCase):
def verify_new_tab(self, tab):
# Make sure the new tab widget is showing, and no mode has been started
- QtTest.QTest.qWait(1000)
+ QtTest.QTest.qWait(1000, self.gui.qtapp)
self.assertTrue(tab.new_tab.isVisible())
self.assertFalse(hasattr(tab, "share_mode"))
self.assertFalse(hasattr(tab, "receive_mode"))
@@ -196,7 +196,7 @@ class GuiBaseTest(unittest.TestCase):
"onionshare", tab.get_mode().web.password
),
)
- QtTest.QTest.qWait(2000)
+ QtTest.QTest.qWait(2000, self.gui.qtapp)
if type(tab.get_mode()) == ShareMode:
# Download files
@@ -210,7 +210,7 @@ class GuiBaseTest(unittest.TestCase):
"onionshare", tab.get_mode().web.password
),
)
- QtTest.QTest.qWait(2000)
+ QtTest.QTest.qWait(2000, self.gui.qtapp)
# Indicator should be visible, have a value of "1"
self.assertTrue(tab.get_mode().toggle_history.indicator_label.isVisible())
@@ -256,7 +256,7 @@ class GuiBaseTest(unittest.TestCase):
def server_is_started(self, tab, startup_time=2000):
"""Test that the server has started"""
- QtTest.QTest.qWait(startup_time)
+ QtTest.QTest.qWait(startup_time, self.gui.qtapp)
# Should now be in SERVER_STARTED state
self.assertEqual(tab.get_mode().server_status.status, 2)
@@ -383,7 +383,7 @@ class GuiBaseTest(unittest.TestCase):
def web_server_is_stopped(self, tab):
"""Test that the web server also stopped"""
- QtTest.QTest.qWait(800)
+ QtTest.QTest.qWait(800, self.gui.qtapp)
try:
requests.get(f"http://127.0.0.1:{tab.app.port}/")
@@ -455,7 +455,7 @@ class GuiBaseTest(unittest.TestCase):
def server_timed_out(self, tab, wait):
"""Test that the server has timed out after the timer ran out"""
- QtTest.QTest.qWait(wait)
+ QtTest.QTest.qWait(wait, self.gui.qtapp)
# We should have timed out now
self.assertEqual(tab.get_mode().server_status.status, 0)
diff --git a/desktop/tests/run.bat b/desktop/tests/run.bat
new file mode 100644
index 00000000..20dfe160
--- /dev/null
+++ b/desktop/tests/run.bat
@@ -0,0 +1,4 @@
+pytest -v tests\test_gui_tabs.py
+pytest -v tests\test_gui_share.py
+pytest -v tests\test_gui_receive.py
+pytest -v tests\test_gui_website.py
diff --git a/desktop/tests/run.sh b/desktop/tests/run.sh
new file mode 100755
index 00000000..833c1516
--- /dev/null
+++ b/desktop/tests/run.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+pytest -v tests/test_gui_tabs.py && \
+pytest -v tests/test_gui_share.py && \
+pytest -v tests/test_gui_receive.py && \
+pytest -v tests/test_gui_website.py
diff --git a/tests/test_gui_receive.py b/desktop/tests/test_gui_receive.py
index d9501460..848b2f11 100644
--- a/tests/test_gui_receive.py
+++ b/desktop/tests/test_gui_receive.py
@@ -5,7 +5,7 @@ import shutil
import sys
from datetime import datetime, timedelta
-from PyQt5 import QtCore, QtTest
+from PySide2 import QtCore, QtTest
from .gui_base_test import GuiBaseTest
@@ -19,7 +19,7 @@ class TestReceive(GuiBaseTest):
"""Test that we can upload the file"""
# Wait 2 seconds to make sure the filename, based on timestamp, isn't accidentally reused
- QtTest.QTest.qWait(2000)
+ QtTest.QTest.qWait(2000, self.gui.qtapp)
files = {"file[]": open(file_to_upload, "rb")}
url = f"http://127.0.0.1:{tab.app.port}/upload"
@@ -46,7 +46,7 @@ class TestReceive(GuiBaseTest):
),
)
- QtTest.QTest.qWait(1000)
+ QtTest.QTest.qWait(1000, self.gui.qtapp)
# Make sure the file is within the last 10 seconds worth of fileames
exists = False
@@ -70,7 +70,7 @@ class TestReceive(GuiBaseTest):
def upload_file_should_fail(self, tab):
"""Test that we can't upload the file when permissions are wrong, and expected content is shown"""
- QtTest.QTest.qWait(1000)
+ QtTest.QTest.qWait(1000, self.gui.qtapp)
files = {"file[]": open(self.tmpfile_test, "rb")}
url = f"http://127.0.0.1:{tab.app.port}/upload"
@@ -171,7 +171,6 @@ class TestReceive(GuiBaseTest):
# Tests
- @pytest.mark.gui
def test_clear_all_button(self):
"""
Clear all history items should work
@@ -183,7 +182,6 @@ class TestReceive(GuiBaseTest):
self.close_all_tabs()
- @pytest.mark.gui
def test_autostop_timer(self):
"""
Test autostop timer
@@ -201,7 +199,6 @@ class TestReceive(GuiBaseTest):
self.close_all_tabs()
- @pytest.mark.gui
def test_upload(self):
"""
Test uploading files
@@ -213,7 +210,6 @@ class TestReceive(GuiBaseTest):
self.close_all_tabs()
- @pytest.mark.gui
@pytest.mark.skipif(sys.platform == "win32", reason="Windows doesn't have chmod")
def test_upload_non_writable_dir(self):
"""
@@ -225,7 +221,6 @@ class TestReceive(GuiBaseTest):
self.close_all_tabs()
- @pytest.mark.gui
def test_public_upload(self):
"""
Test uploading files in public mode
@@ -238,7 +233,6 @@ class TestReceive(GuiBaseTest):
self.close_all_tabs()
- @pytest.mark.gui
@pytest.mark.skipif(sys.platform == "win32", reason="Windows doesn't have chmod")
def test_public_upload_non_writable_dir(self):
"""
diff --git a/tests/test_gui_share.py b/desktop/tests/test_gui_share.py
index 441fc03a..0e521d52 100644
--- a/tests/test_gui_share.py
+++ b/desktop/tests/test_gui_share.py
@@ -4,7 +4,7 @@ import requests
import tempfile
import zipfile
-from PyQt5 import QtCore, QtTest
+from PySide2 import QtCore, QtTest
from .gui_base_test import GuiBaseTest
@@ -88,10 +88,10 @@ class TestShare(GuiBaseTest):
tmp_file.close()
z = zipfile.ZipFile(tmp_file.name)
- QtTest.QTest.qWait(50)
+ QtTest.QTest.qWait(5, self.gui.qtapp)
self.assertEqual("onionshare", z.read("test.txt").decode("utf-8"))
- QtTest.QTest.qWait(500)
+ QtTest.QTest.qWait(500, self.gui.qtapp)
def individual_file_is_viewable_or_not(self, tab):
"""
@@ -143,7 +143,7 @@ class TestShare(GuiBaseTest):
self.assertEqual("onionshare", f.read())
os.remove(tmp_file.name)
- QtTest.QTest.qWait(500)
+ QtTest.QTest.qWait(500, self.gui.qtapp)
def hit_401(self, tab):
"""Test that the server stops after too many 401s, or doesn't when in public mode"""
@@ -190,7 +190,7 @@ class TestShare(GuiBaseTest):
def scheduled_service_started(self, tab, wait):
"""Test that the server has timed out after the timer ran out"""
- QtTest.QTest.qWait(wait)
+ QtTest.QTest.qWait(wait, self.gui.qtapp)
# We should have started now
self.assertEqual(tab.get_mode().server_status.status, 2)
@@ -201,15 +201,15 @@ class TestShare(GuiBaseTest):
self.add_remove_buttons_hidden(tab)
self.mode_settings_widget_is_hidden(tab)
self.set_autostart_timer(tab, 10)
- QtTest.QTest.qWait(500)
+ QtTest.QTest.qWait(500, self.gui.qtapp)
QtTest.QTest.mousePress(
tab.get_mode().server_status.server_button, QtCore.Qt.LeftButton
)
- QtTest.QTest.qWait(100)
+ QtTest.QTest.qWait(100, self.gui.qtapp)
QtTest.QTest.mouseRelease(
tab.get_mode().server_status.server_button, QtCore.Qt.LeftButton
)
- QtTest.QTest.qWait(500)
+ QtTest.QTest.qWait(500, self.gui.qtapp)
self.assertEqual(
tab.get_mode().server_status.status,
tab.get_mode().server_status.STATUS_STOPPED,
@@ -307,7 +307,6 @@ class TestShare(GuiBaseTest):
# Tests
- @pytest.mark.gui
def test_autostart_and_autostop_timer_mismatch(self):
"""
If autostart timer is after autostop timer, a warning should be thrown
@@ -332,7 +331,6 @@ class TestShare(GuiBaseTest):
self.close_all_tabs()
- @pytest.mark.gui
def test_autostart_timer(self):
"""
Autostart timer should automatically start
@@ -354,7 +352,6 @@ class TestShare(GuiBaseTest):
self.close_all_tabs()
- @pytest.mark.gui
def test_autostart_timer_too_short(self):
"""
Autostart timer should throw a warning if the scheduled time is too soon
@@ -372,14 +369,13 @@ class TestShare(GuiBaseTest):
self.run_all_share_mode_setup_tests(tab)
# Set a low timeout
self.set_autostart_timer(tab, 2)
- QtTest.QTest.qWait(2200)
+ QtTest.QTest.qWait(2200, self.gui.qtapp)
QtCore.QTimer.singleShot(200, accept_dialog)
tab.get_mode().server_status.server_button.click()
self.assertEqual(tab.get_mode().server_status.status, 0)
self.close_all_tabs()
- @pytest.mark.gui
def test_autostart_timer_cancel(self):
"""
Test canceling a scheduled share
@@ -394,7 +390,6 @@ class TestShare(GuiBaseTest):
self.close_all_tabs()
- @pytest.mark.gui
def test_clear_all_history_button(self):
"""
Test clearing all history items
@@ -407,7 +402,6 @@ class TestShare(GuiBaseTest):
self.close_all_tabs()
- @pytest.mark.gui
def test_remove_all_file_selection_button(self):
"""
Test remove all file items at once
@@ -419,7 +413,6 @@ class TestShare(GuiBaseTest):
self.close_all_tabs()
- @pytest.mark.gui
def test_public_mode(self):
"""
Public mode shouldn't have a password
@@ -432,7 +425,6 @@ class TestShare(GuiBaseTest):
self.close_all_tabs()
- @pytest.mark.gui
def test_without_autostop_sharing(self):
"""
Disable autostop sharing after first download
@@ -445,7 +437,6 @@ class TestShare(GuiBaseTest):
self.close_all_tabs()
- @pytest.mark.gui
def test_download(self):
"""
Test downloading in share mode
@@ -457,7 +448,6 @@ class TestShare(GuiBaseTest):
self.close_all_tabs()
- @pytest.mark.gui
def test_individual_files_without_autostop_sharing(self):
"""
Test downloading individual files with autostop sharing disabled
@@ -470,7 +460,6 @@ class TestShare(GuiBaseTest):
self.close_all_tabs()
- @pytest.mark.gui
def test_individual_files(self):
"""
Test downloading individual files
@@ -482,7 +471,6 @@ class TestShare(GuiBaseTest):
self.close_all_tabs()
- @pytest.mark.gui
def test_large_download(self):
"""
Test a large download
@@ -503,7 +491,6 @@ class TestShare(GuiBaseTest):
self.close_all_tabs()
- @pytest.mark.gui
def test_persistent_password(self):
"""
Test a large download
@@ -522,7 +509,6 @@ class TestShare(GuiBaseTest):
self.close_all_tabs()
- @pytest.mark.gui
def test_autostop_timer(self):
"""
Test the autostop timer
@@ -541,7 +527,6 @@ class TestShare(GuiBaseTest):
self.close_all_tabs()
- @pytest.mark.gui
def test_autostop_timer_too_short(self):
"""
Test the autostop timer when the timeout is too short
@@ -559,14 +544,13 @@ class TestShare(GuiBaseTest):
self.run_all_share_mode_setup_tests(tab)
# Set a low timeout
self.set_timeout(tab, 2)
- QtTest.QTest.qWait(2100)
+ QtTest.QTest.qWait(2100, self.gui.qtapp)
QtCore.QTimer.singleShot(2200, accept_dialog)
tab.get_mode().server_status.server_button.click()
self.assertEqual(tab.get_mode().server_status.status, 0)
self.close_all_tabs()
- @pytest.mark.gui
def test_unreadable_file(self):
"""
Sharing an unreadable file should throw a warning
@@ -587,7 +571,6 @@ class TestShare(GuiBaseTest):
self.close_all_tabs()
- @pytest.mark.gui
def test_401_triggers_ratelimit(self):
"""
Rate limit should be triggered
@@ -607,7 +590,6 @@ class TestShare(GuiBaseTest):
self.close_all_tabs()
- @pytest.mark.gui
def test_401_public_skips_ratelimit(self):
"""
Public mode should skip the rate limit
diff --git a/tests/test_gui_tabs.py b/desktop/tests/test_gui_tabs.py
index a2473441..4ebbdffb 100644
--- a/tests/test_gui_tabs.py
+++ b/desktop/tests/test_gui_tabs.py
@@ -1,7 +1,7 @@
import pytest
import os
-from PyQt5 import QtCore, QtTest, QtWidgets
+from PySide2 import QtCore, QtTest, QtWidgets
from .gui_base_test import GuiBaseTest
@@ -20,7 +20,7 @@ class TestTabs(GuiBaseTest):
tab.get_mode().server_status.status,
tab.get_mode().server_status.STATUS_WORKING,
)
- QtTest.QTest.qWait(1000)
+ QtTest.QTest.qWait(1000, self.gui.qtapp)
self.assertEqual(
tab.get_mode().server_status.status,
tab.get_mode().server_status.STATUS_STARTED,
@@ -51,7 +51,7 @@ class TestTabs(GuiBaseTest):
# Click the persistent checkbox
tab.get_mode().server_status.mode_settings_widget.persistent_checkbox.click()
- QtTest.QTest.qWait(100)
+ QtTest.QTest.qWait(100, self.gui.qtapp)
# There should be a persistent settings file now
self.assertTrue(os.path.exists(tab.settings.filename))
@@ -83,18 +83,15 @@ class TestTabs(GuiBaseTest):
# Tests
- @pytest.mark.gui
def test_01_common_tests(self):
"""Run all common tests"""
self.run_all_common_setup_tests()
- @pytest.mark.gui
def test_02_starts_with_one_new_tab(self):
"""There should be one "New Tab" tab open"""
self.assertEqual(self.gui.tabs.count(), 1)
self.assertTrue(self.gui.tabs.widget(0).new_tab.isVisible())
- @pytest.mark.gui
def test_03_new_tab_button_opens_new_tabs(self):
"""Clicking the "+" button should open new tabs"""
self.assertEqual(self.gui.tabs.count(), 1)
@@ -103,7 +100,6 @@ class TestTabs(GuiBaseTest):
self.gui.tabs.new_tab_button.click()
self.assertEqual(self.gui.tabs.count(), 4)
- @pytest.mark.gui
def test_04_close_tab_button_closes_tabs(self):
"""Clicking the "x" button should close tabs"""
self.assertEqual(self.gui.tabs.count(), 4)
@@ -112,7 +108,6 @@ class TestTabs(GuiBaseTest):
self.gui.tabs.tabBar().tabButton(0, QtWidgets.QTabBar.RightSide).click()
self.assertEqual(self.gui.tabs.count(), 1)
- @pytest.mark.gui
def test_05_closing_last_tab_opens_new_one(self):
"""Closing the last tab should open a new tab"""
self.assertEqual(self.gui.tabs.count(), 1)
@@ -129,7 +124,6 @@ class TestTabs(GuiBaseTest):
self.assertEqual(self.gui.tabs.count(), 1)
self.assertTrue(self.gui.tabs.widget(0).new_tab.isVisible())
- @pytest.mark.gui
def test_06_new_tab_mode_buttons_show_correct_modes(self):
"""Clicking the mode buttons in a new tab should change the mode of the tab"""
@@ -166,43 +160,36 @@ class TestTabs(GuiBaseTest):
self.gui.tabs.tabBar().tabButton(0, QtWidgets.QTabBar.RightSide).click()
self.gui.tabs.tabBar().tabButton(0, QtWidgets.QTabBar.RightSide).click()
- @pytest.mark.gui
def test_07_close_share_tab_while_server_started_should_warn(self):
"""Closing a share mode tab when the server is running should throw a warning"""
tab = self.new_share_tab_with_files()
self.close_tab_with_active_server(tab)
- @pytest.mark.gui
def test_08_close_receive_tab_while_server_started_should_warn(self):
"""Closing a recieve mode tab when the server is running should throw a warning"""
tab = self.new_receive_tab()
self.close_tab_with_active_server(tab)
- @pytest.mark.gui
def test_09_close_website_tab_while_server_started_should_warn(self):
"""Closing a website mode tab when the server is running should throw a warning"""
tab = self.new_website_tab_with_files()
self.close_tab_with_active_server(tab)
- @pytest.mark.gui
def test_10_close_persistent_share_tab_shows_warning(self):
"""Closing a share mode tab that's persistent should show a warning"""
tab = self.new_share_tab_with_files()
self.close_persistent_tab(tab)
- @pytest.mark.gui
def test_11_close_persistent_receive_tab_shows_warning(self):
"""Closing a receive mode tab that's persistent should show a warning"""
tab = self.new_receive_tab()
self.close_persistent_tab(tab)
- @pytest.mark.gui
def test_12_close_persistent_website_tab_shows_warning(self):
"""Closing a website mode tab that's persistent should show a warning"""
tab = self.new_website_tab_with_files()
self.close_persistent_tab(tab)
- @pytest.mark.gui
def test_13_quit_with_server_started_should_warn(self):
"""Quitting OnionShare with any active servers should show a warning"""
tab = self.new_share_tab()
@@ -217,7 +204,7 @@ class TestTabs(GuiBaseTest):
tab.get_mode().server_status.status,
tab.get_mode().server_status.STATUS_WORKING,
)
- QtTest.QTest.qWait(500)
+ QtTest.QTest.qWait(500, self.gui.qtapp)
self.assertEqual(
tab.get_mode().server_status.status,
tab.get_mode().server_status.STATUS_STARTED,
diff --git a/tests/test_gui_website.py b/desktop/tests/test_gui_website.py
index 80c74dea..164aa07d 100644
--- a/tests/test_gui_website.py
+++ b/desktop/tests/test_gui_website.py
@@ -4,7 +4,7 @@ import requests
import shutil
from datetime import datetime, timedelta
-from PyQt5 import QtCore, QtTest
+from PySide2 import QtCore, QtTest
from .gui_base_test import GuiBaseTest
@@ -25,7 +25,7 @@ class TestWebsite(GuiBaseTest):
),
)
- QtTest.QTest.qWait(500)
+ QtTest.QTest.qWait(500, self.gui.qtapp)
self.assertTrue("This is a test website hosted by OnionShare" in r.text)
def check_csp_header(self, tab):
@@ -41,7 +41,7 @@ class TestWebsite(GuiBaseTest):
),
)
- QtTest.QTest.qWait(500)
+ QtTest.QTest.qWait(500, self.gui.qtapp)
if tab.settings.get("website", "disable_csp"):
self.assertFalse("Content-Security-Policy" in r.headers)
else:
@@ -87,7 +87,6 @@ class TestWebsite(GuiBaseTest):
# Tests
- @pytest.mark.gui
def test_website(self):
"""
Test website mode
@@ -96,7 +95,6 @@ class TestWebsite(GuiBaseTest):
self.run_all_website_mode_download_tests(tab)
self.close_all_tabs()
- @pytest.mark.gui
def test_csp_enabled(self):
"""
Test disabling CSP
diff --git a/dev_scripts/onionshare b/dev_scripts/onionshare
deleted file mode 100755
index 33e59203..00000000
--- a/dev_scripts/onionshare
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-"""
-OnionShare | https://onionshare.org/
-
-Copyright (C) 2014-2020 Micah Lee, et al. <micah@micahflee.com>
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see <http://www.gnu.org/licenses/>.
-"""
-
-# Load onionshare module and resources from the source code tree
-import os, sys
-
-sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-sys.onionshare_dev_mode = True
-
-import onionshare
-
-onionshare.main()
diff --git a/dev_scripts/onionshare-gui b/dev_scripts/onionshare-gui
deleted file mode 100755
index 6585be02..00000000
--- a/dev_scripts/onionshare-gui
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-"""
-OnionShare | https://onionshare.org/
-
-Copyright (C) 2014-2020 Micah Lee, et al. <micah@micahflee.com>
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see <http://www.gnu.org/licenses/>.
-"""
-
-# Load onionshare module and resources from the source code tree
-import os, sys
-
-sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-sys.onionshare_dev_mode = True
-
-import onionshare_gui
-
-onionshare_gui.main()
diff --git a/docs/pyproject.toml b/docs/pyproject.toml
index 9cc7bcc2..1b1cb289 100644
--- a/docs/pyproject.toml
+++ b/docs/pyproject.toml
@@ -5,7 +5,7 @@ description = ""
authors = ["Micah Lee <micah@micahflee.com>"]
[tool.poetry.dependencies]
-python = "~3.6"
+python = "^3.6"
sphinx = "^3.2.1"
sphinx-rtd-theme = "^0.5.0"
sphinx-intl = "^2.0.1"
diff --git a/docs/source/conf.py b/docs/source/conf.py
index a8d0393e..ac8bd793 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -16,7 +16,7 @@ languages = [
("Українська", "uk"),
]
-versions = ["2.3"]
+versions = ["2.3.dev2"]
html_theme = "sphinx_rtd_theme"
html_logo = "_static/logo.png"
diff --git a/docs/source/install.rst b/docs/source/install.rst
index a8383e35..51e000de 100644
--- a/docs/source/install.rst
+++ b/docs/source/install.rst
@@ -6,30 +6,32 @@ Install on Windows or macOS
You can download OnionShare for Windows and macOS from the `OnionShare website <https://onionshare.org/>`_.
-For added security, see :ref:`verifying_sigs`.
-
.. _linux:
-Install in Linux with Flatpak
------------------------------
+Install in Linux
+----------------
+
+There are various ways to install OnionShare for Linux, but the recommended way is to use either the `Flatpak <https://flatpak.org/>`_ or the `Snapcraft <https://snapcraft.io/>`_ package. Flatpak and Snapcraft ensure that you'll always use the most latest dependencies and run OnionShare inside of a sandbox.
+
+Snapcraft is built-in to Ubuntu and Flatpak is built-in to Fedora, but which you use is up to you. Both work in all Linux distributions.
-There are various ways to install OnionShare for Linux, but the recommended way is to use the Flatpak package. Flatpak ensures that you'll always use the most latest dependencies and run OnionShare inside of a sandbox.
+**Install OnionShare using Flatpak**: https://flathub.org/apps/details/org.onionshare.OnionShare
-Make sure you have ``flatpak`` installed and the Flathub repository added by following `these instructions <https://flatpak.org/setup/>`_ for your Linux distribution.
+**Install OnionShare using Snapcraft**: https://snapcraft.io/onionshare
-Then install OnionShare from Flathub by following `the instructions here <https://flathub.org/apps/details/org.onionshare.OnionShare>`_.
+You can also download and install a PGP-signed ``.flatpak`` or ``.snap`` packages from https://onionshare.org/dist/ if you prefer.
.. _verifying_sigs:
Verifying PGP signatures
------------------------
-You can verify that the Windows, macOS, or source package you download is legitimate and hasn't been tampered with by verifying its PGP signature. For Windows and macOS, this step is optional and provides defense in depth: the installers also include their operating system-specific signatures, and you can just rely on those alone if you'd like.
+You can verify that the Windows, macOS, Flatpak, Snapcraft, or source package you download is legitimate and hasn't been tampered with by verifying its PGP signature. For Windows and macOS, this step is optional and provides defense in depth: the installers also include their operating system-specific signatures, and you can just rely on those alone if you'd like.
Signing key
^^^^^^^^^^^
-Windows, macOS, and source packaged are signed by Micah Lee, the core developer, using his PGP public key with fingerprint ``927F419D7EC82C2F149C1BD1403C2657CD994F73``. You can download Micah's key `from the keys.openpgp.org keyserver <https://keys.openpgp.org/vks/v1/by-fingerprint/927F419D7EC82C2F149C1BD1403C2657CD994F73>`_.
+Packages are signed by Micah Lee, the core developer, using his PGP public key with fingerprint ``927F419D7EC82C2F149C1BD1403C2657CD994F73``. You can download Micah's key `from the keys.openpgp.org keyserver <https://keys.openpgp.org/vks/v1/by-fingerprint/927F419D7EC82C2F149C1BD1403C2657CD994F73>`_.
In order to verify signatures, you must have GnuPG installed. For macOS you probably want `GPGTools <https://gpgtools.org/>`_, and for Windows you probably want `Gpg4win <https://www.gpg4win.org/>`_.
diff --git a/flatpak/org.onionshare.OnionShare.yaml b/flatpak/org.onionshare.OnionShare.yaml
new file mode 100644
index 00000000..4553a61b
--- /dev/null
+++ b/flatpak/org.onionshare.OnionShare.yaml
@@ -0,0 +1,321 @@
+---
+app-id: org.onionshare.OnionShare
+command: onionshare
+runtime: org.kde.Platform
+runtime-version: "5.15"
+sdk: org.kde.Sdk
+sdk-extensions:
+ - org.freedesktop.Sdk.Extension.golang
+separate-locales: false
+finish-args:
+ - "--device=dri"
+ - "--share=ipc"
+ - "--share=network"
+ - "--socket=wayland"
+ - "--socket=x11"
+ - "--talk-name=org.freedesktop.Flatpak"
+ - "--talk-name=org.freedesktop.Notifications"
+ - "--talk-name=org.freedesktop.secrets"
+ - "--filesystem=home:ro"
+ - "--filesystem=~/OnionShare:create"
+ - "--filesystem=xdg-config/onionshare:create"
+cleanup:
+ - "/go"
+ - "/bin/scripts"
+modules:
+ # thanks https://github.com/flathub/org.freecadweb.FreeCAD/blob/master/org.freecadweb.FreeCAD.yaml
+ - name: pyside2
+ buildsystem: cmake-ninja
+ builddir: true
+ config-opts:
+ - -DCMAKE_BUILD_TYPE=Release
+ - -DBUILD_TESTS=OFF
+ cleanup:
+ - /bin
+ sources:
+ - type: archive
+ sha256: f175c1d8813257904cf0efeb58e44f68d53b9916f73adaf9ce19514c0271c3fa
+ url: https://download.qt.io/official_releases/QtForPython/pyside2/PySide2-5.15.1-src/pyside-setup-opensource-src-5.15.1.tar.xz
+ - type: shell
+ commands:
+ - mkdir -p /app/include/qt5tmp && cp -R /usr/include/Qt* /app/include/qt5tmp # https://bugreports.qt.io/browse/PYSIDE-787
+ - sed -i 's|\(--include-paths=\)|\1/app/include/qt5tmp:|' sources/pyside2/cmake/Macros/PySideModules.cmake
+ - name: tor
+ buildsystem: simple
+ build-commands:
+ - "./configure --prefix=${FLATPAK_DEST}"
+ - make
+ - make install
+ sources:
+ - type: archive
+ sha256: a45ca00afe765e3baa839767c9dd6ac9a46dd01720a3a8ff4d86558c12359926
+ url: https://dist.torproject.org/tor-0.4.4.5.tar.gz
+ modules:
+ - name: libevent
+ buildsystem: simple
+ build-commands:
+ - "./configure --prefix=${FLATPAK_DEST}"
+ - make
+ - make install
+ sources:
+ - type: archive
+ url: https://github.com/libevent/libevent/releases/download/release-2.1.12-stable/libevent-2.1.12-stable.tar.gz
+ sha256: 92e6de1be9ec176428fd2367677e61ceffc2ee1cb119035037a27d346b0403bb
+ - name: obfs4proxy
+ buildsystem: simple
+ build-options:
+ env:
+ GOBIN: "/app/bin/"
+ build-commands:
+ - ". /usr/lib/sdk/golang/enable.sh; GOPATH=$PWD go install gitlab.com/yawning/obfs4.git/obfs4proxy"
+ sources:
+ - type: git
+ url: https://git.torproject.org/pluggable-transports/goptlib
+ commit: 781a46c66d2ddbc3509354ae7f1fccab74cb9927
+ dest: src/git.torproject.org/pluggable-transports/goptlib.git
+ - type: git
+ url: https://gitlab.com/yawning/obfs4
+ commit: 2d8f3c8bbfd7a7ca931738a64c2f6e97b7332d9e
+ dest: src/gitlab.com/yawning/obfs4.git
+ - type: git
+ url: https://gitlab.com/yawning/bsaes
+ commit: 0a714cd429ec754482b4001e918db30cd2094405
+ dest: src/gitlab.com/yawning/bsaes.git
+ - type: git
+ url: https://gitlab.com/yawning/utls
+ commit: 2dd4f38ff9e07464eb2748cc017eac1355e42251
+ dest: src/gitlab.com/yawning/utls.git
+ - type: git
+ url: https://go.googlesource.com/sys
+ commit: ddb9806d33aed8dbaac1cd6f1cba58952e87f933
+ dest: src/golang.org/x/sys
+ - type: git
+ url: https://go.googlesource.com/text
+ commit: 23ae387dee1f90d29a23c0e87ee0b46038fbed0e
+ dest: src/golang.org/x/text
+ - type: git
+ url: https://go.googlesource.com/net
+ commit: 4c5254603344ea4a8ae4bed7e296a9588303e14f
+ dest: src/golang.org/x/net
+ - type: git
+ url: https://go.googlesource.com/crypto
+ commit: 75b288015ac94e66e3d6715fb68a9b41bf046ec2
+ dest: src/golang.org/x/crypto
+ - type: git
+ url: https://github.com/dsnet/compress
+ commit: da652975a8eea9fa0735aba8056747a751db0bd3
+ dest: src/github.com/dsnet/compress
+ - type: git
+ url: https://github.com/dchest/siphash
+ commit: 34f201214d993633bb24f418ba11736ab8b55aa7
+ dest: src/github.com/dchest/siphash
+ - name: onionshare
+ buildsystem: simple
+ ensure-writable:
+ - easy-install.pth
+ build-commands:
+ - python3 setup.py install --prefix=${FLATPAK_DEST}
+ - install -D -m0644 org.onionshare.OnionShare.appdata.xml ${FLATPAK_DEST}/share/metainfo/${FLATPAK_ID}.appdata.xml
+ sources:
+ - type: dir
+ path: ../desktop/src
+ modules:
+ - name: onionshare-cli
+ buildsystem: simple
+ build-commands:
+ - python3 setup.py install --prefix=${FLATPAK_DEST}
+ sources:
+ - type: dir
+ path: ../cli
+ - name: python3-click
+ buildsystem: simple
+ build-commands:
+ - pip3 install --exists-action=i --no-index --find-links="file://${PWD}" --prefix=${FLATPAK_DEST}
+ "click"
+ sources:
+ - type: file
+ url: https://files.pythonhosted.org/packages/d2/3d/fa76db83bf75c4f8d338c2fd15c8d33fdd7ad23a9b5e57eb6c5de26b430e/click-7.1.2-py2.py3-none-any.whl
+ sha256: dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc
+ - name: python3-flask
+ buildsystem: simple
+ build-commands:
+ - pip3 install --exists-action=i --no-index --find-links="file://${PWD}" --prefix=${FLATPAK_DEST}
+ "flask"
+ sources:
+ - type: file
+ url: https://files.pythonhosted.org/packages/b9/2e/64db92e53b86efccfaea71321f597fa2e1b2bd3853d8ce658568f7a13094/MarkupSafe-1.1.1.tar.gz
+ sha256: 29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b
+ - type: file
+ url: https://files.pythonhosted.org/packages/d2/3d/fa76db83bf75c4f8d338c2fd15c8d33fdd7ad23a9b5e57eb6c5de26b430e/click-7.1.2-py2.py3-none-any.whl
+ sha256: dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc
+ - type: file
+ url: https://files.pythonhosted.org/packages/30/9e/f663a2aa66a09d838042ae1a2c5659828bb9b41ea3a6efa20a20fd92b121/Jinja2-2.11.2-py2.py3-none-any.whl
+ sha256: f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035
+ - type: file
+ url: https://files.pythonhosted.org/packages/76/ae/44b03b253d6fade317f32c24d100b3b35c2239807046a4c953c7b89fa49e/itsdangerous-1.1.0-py2.py3-none-any.whl
+ sha256: b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749
+ - type: file
+ url: https://files.pythonhosted.org/packages/f2/28/2a03252dfb9ebf377f40fba6a7841b47083260bf8bd8e737b0c6952df83f/Flask-1.1.2-py2.py3-none-any.whl
+ sha256: 8a4fdd8936eba2512e9c85df320a37e694c93945b33ef33c89946a340a238557
+ - type: file
+ url: https://files.pythonhosted.org/packages/cc/94/5f7079a0e00bd6863ef8f1da638721e9da21e5bacee597595b318f71d62e/Werkzeug-1.0.1-py2.py3-none-any.whl
+ sha256: 2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43
+ - name: python3-flask-httpauth
+ buildsystem: simple
+ build-commands:
+ - pip3 install --exists-action=i --no-index --find-links="file://${PWD}" --prefix=${FLATPAK_DEST}
+ "flask-httpauth"
+ sources:
+ - type: file
+ url: https://files.pythonhosted.org/packages/b9/2e/64db92e53b86efccfaea71321f597fa2e1b2bd3853d8ce658568f7a13094/MarkupSafe-1.1.1.tar.gz
+ sha256: 29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b
+ - type: file
+ url: https://files.pythonhosted.org/packages/d2/3d/fa76db83bf75c4f8d338c2fd15c8d33fdd7ad23a9b5e57eb6c5de26b430e/click-7.1.2-py2.py3-none-any.whl
+ sha256: dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc
+ - type: file
+ url: https://files.pythonhosted.org/packages/e1/a8/c1cda654d5da7ba45bc0bd567cd7e2d2508997decfae5191813f31c93b9e/Flask_HTTPAuth-4.1.0-py2.py3-none-any.whl
+ sha256: 29e0288869a213c7387f0323b6bf2c7191584fb1da8aa024d9af118e5cd70de7
+ - type: file
+ url: https://files.pythonhosted.org/packages/30/9e/f663a2aa66a09d838042ae1a2c5659828bb9b41ea3a6efa20a20fd92b121/Jinja2-2.11.2-py2.py3-none-any.whl
+ sha256: f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035
+ - type: file
+ url: https://files.pythonhosted.org/packages/76/ae/44b03b253d6fade317f32c24d100b3b35c2239807046a4c953c7b89fa49e/itsdangerous-1.1.0-py2.py3-none-any.whl
+ sha256: b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749
+ - type: file
+ url: https://files.pythonhosted.org/packages/f2/28/2a03252dfb9ebf377f40fba6a7841b47083260bf8bd8e737b0c6952df83f/Flask-1.1.2-py2.py3-none-any.whl
+ sha256: 8a4fdd8936eba2512e9c85df320a37e694c93945b33ef33c89946a340a238557
+ - type: file
+ url: https://files.pythonhosted.org/packages/cc/94/5f7079a0e00bd6863ef8f1da638721e9da21e5bacee597595b318f71d62e/Werkzeug-1.0.1-py2.py3-none-any.whl
+ sha256: 2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43
+ - name: python3-flask-socketio
+ buildsystem: simple
+ build-commands:
+ - pip3 install --exists-action=i --no-index --find-links="file://${PWD}" --prefix=${FLATPAK_DEST}
+ "flask-socketio"
+ sources:
+ - type: file
+ url: https://files.pythonhosted.org/packages/b9/2e/64db92e53b86efccfaea71321f597fa2e1b2bd3853d8ce658568f7a13094/MarkupSafe-1.1.1.tar.gz
+ sha256: 29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b
+ - type: file
+ url: https://files.pythonhosted.org/packages/d2/3d/fa76db83bf75c4f8d338c2fd15c8d33fdd7ad23a9b5e57eb6c5de26b430e/click-7.1.2-py2.py3-none-any.whl
+ sha256: dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc
+ - type: file
+ url: https://files.pythonhosted.org/packages/8a/fa/ea1df958bd76a4a55b20dd87593839adf893e1fae0095b449fecdf325f21/Flask_SocketIO-4.3.1-py2.py3-none-any.whl
+ sha256: 3668675bf7763c5b5f56689d439f07356e89c0a52e0c9e9cd3cc08563c07b252
+ - type: file
+ url: https://files.pythonhosted.org/packages/4a/b0/602e549c6d735eb487f186b35e0b82e61c89459f57d1c24d5c7be6f56d05/python_engineio-3.13.2-py2.py3-none-any.whl
+ sha256: cfded18156862f94544a9f8ef37f56727df731c8552d7023f5afee8369be2db6
+ - type: file
+ url: https://files.pythonhosted.org/packages/30/9e/f663a2aa66a09d838042ae1a2c5659828bb9b41ea3a6efa20a20fd92b121/Jinja2-2.11.2-py2.py3-none-any.whl
+ sha256: f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035
+ - type: file
+ url: https://files.pythonhosted.org/packages/76/ae/44b03b253d6fade317f32c24d100b3b35c2239807046a4c953c7b89fa49e/itsdangerous-1.1.0-py2.py3-none-any.whl
+ sha256: b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749
+ - type: file
+ url: https://files.pythonhosted.org/packages/3d/97/00741edd49788510b834b60a1a4d0afb2c4942770c11b8e0f6e914371718/python_socketio-4.6.0-py2.py3-none-any.whl
+ sha256: d437f797c44b6efba2f201867cf02b8c96b97dff26d4e4281ac08b45817cd522
+ - type: file
+ url: https://files.pythonhosted.org/packages/f2/28/2a03252dfb9ebf377f40fba6a7841b47083260bf8bd8e737b0c6952df83f/Flask-1.1.2-py2.py3-none-any.whl
+ sha256: 8a4fdd8936eba2512e9c85df320a37e694c93945b33ef33c89946a340a238557
+ - type: file
+ url: https://files.pythonhosted.org/packages/cc/94/5f7079a0e00bd6863ef8f1da638721e9da21e5bacee597595b318f71d62e/Werkzeug-1.0.1-py2.py3-none-any.whl
+ sha256: 2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43
+ - type: file
+ url: https://files.pythonhosted.org/packages/ee/ff/48bde5c0f013094d729fe4b0316ba2a24774b3ff1c52d924a8a4cb04078a/six-1.15.0-py2.py3-none-any.whl
+ sha256: 8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced
+ - name: python3-pycryptodome
+ buildsystem: simple
+ build-commands:
+ - pip3 install --exists-action=i --no-index --find-links="file://${PWD}" --prefix=${FLATPAK_DEST}
+ "pycryptodome"
+ sources:
+ - type: file
+ url: https://files.pythonhosted.org/packages/c4/3a/5bca2cb1648b171afd6b7d29a11c6bca8b305bb75b7e2d78a0f5c61ff95e/pycryptodome-3.9.9.tar.gz
+ sha256: 910e202a557e1131b1c1b3f17a63914d57aac55cf9fb9b51644962841c3995c4
+ - name: python3-pysocks
+ buildsystem: simple
+ build-commands:
+ - pip3 install --exists-action=i --no-index --find-links="file://${PWD}" --prefix=${FLATPAK_DEST}
+ "pysocks"
+ sources:
+ - type: file
+ url: https://files.pythonhosted.org/packages/8d/59/b4572118e098ac8e46e399a1dd0f2d85403ce8bbaad9ec79373ed6badaf9/PySocks-1.7.1-py3-none-any.whl
+ sha256: 2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5
+ - name: python3-requests
+ buildsystem: simple
+ build-commands:
+ - pip3 install --exists-action=i --no-index --find-links="file://${PWD}" --prefix=${FLATPAK_DEST}
+ "requests"
+ sources:
+ - type: file
+ url: https://files.pythonhosted.org/packages/56/aa/4ef5aa67a9a62505db124a5cb5262332d1d4153462eb8fd89c9fa41e5d92/urllib3-1.25.11-py2.py3-none-any.whl
+ sha256: f5321fbe4bf3fefa0efd0bfe7fb14e90909eb62a48ccda331726b4319897dd5e
+ - type: file
+ url: https://files.pythonhosted.org/packages/bc/a9/01ffebfb562e4274b6487b4bb1ddec7ca55ec7510b22e4c51f14098443b8/chardet-3.0.4-py2.py3-none-any.whl
+ sha256: fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691
+ - type: file
+ url: https://files.pythonhosted.org/packages/5e/c4/6c4fe722df5343c33226f0b4e0bb042e4dc13483228b4718baf286f86d87/certifi-2020.6.20-py2.py3-none-any.whl
+ sha256: 8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41
+ - type: file
+ url: https://files.pythonhosted.org/packages/45/1e/0c169c6a5381e241ba7404532c16a21d86ab872c9bed8bdcd4c423954103/requests-2.24.0-py2.py3-none-any.whl
+ sha256: fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898
+ - type: file
+ url: https://files.pythonhosted.org/packages/a2/38/928ddce2273eaa564f6f50de919327bf3a00f091b5baba8dfa9460f3a8a8/idna-2.10-py2.py3-none-any.whl
+ sha256: b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0
+ - name: python3-stem
+ buildsystem: simple
+ build-commands:
+ - pip3 install --exists-action=i --no-index --find-links="file://${PWD}" --prefix=${FLATPAK_DEST}
+ "stem"
+ sources:
+ - type: file
+ url: https://files.pythonhosted.org/packages/71/bd/ab05ffcbfe74dca704e860312e00c53ef690b1ddcb23be7a4d9ea4f40260/stem-1.8.0.tar.gz
+ sha256: a0b48ea6224e95f22aa34c0bc3415f0eb4667ddeae3dfb5e32a6920c185568c2
+ - name: python3-urllib3
+ buildsystem: simple
+ build-commands:
+ - pip3 install --exists-action=i --no-index --find-links="file://${PWD}" --prefix=${FLATPAK_DEST}
+ "urllib3"
+ sources:
+ - type: file
+ url: https://files.pythonhosted.org/packages/56/aa/4ef5aa67a9a62505db124a5cb5262332d1d4153462eb8fd89c9fa41e5d92/urllib3-1.25.11-py2.py3-none-any.whl
+ sha256: f5321fbe4bf3fefa0efd0bfe7fb14e90909eb62a48ccda331726b4319897dd5e
+ - name: python3-eventlet
+ buildsystem: simple
+ build-commands:
+ - pip3 install --exists-action=i --no-index --find-links="file://${PWD}" --prefix=${FLATPAK_DEST}
+ "eventlet"
+ sources:
+ - type: file
+ url: https://files.pythonhosted.org/packages/72/0c/fd07c7674ad6eded937194b84d8453425c36c6ef118536907b0185624d82/greenlet-0.4.17.tar.gz
+ sha256: 41d8835c69a78de718e466dd0e6bfd4b46125f21a67c3ff6d76d8d8059868d6b
+ - type: file
+ url: https://files.pythonhosted.org/packages/e3/85/2ae0512c942664570227a2f9c88b24dd3c0846c5c60cb05b6a2a26979d66/eventlet-0.29.1-py2.py3-none-any.whl
+ sha256: a07b8c8e1f43bc4c44a255baeb066a4edce783dcfacae213bcabb95fdcd02d8c
+ - type: file
+ url: https://files.pythonhosted.org/packages/ec/d3/3aa0e7213ef72b8585747aa0e271a9523e713813b9a20177ebe1e939deb0/dnspython-1.16.0-py2.py3-none-any.whl
+ sha256: f69c21288a962f4da86e56c4905b49d11aba7938d3d740e80d9e366ee4f1632d
+ - type: file
+ url: https://files.pythonhosted.org/packages/ee/ff/48bde5c0f013094d729fe4b0316ba2a24774b3ff1c52d924a8a4cb04078a/six-1.15.0-py2.py3-none-any.whl
+ sha256: 8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced
+ - name: python3-psutil
+ buildsystem: simple
+ build-commands:
+ - pip3 install --exists-action=i --no-index --find-links="file://${PWD}" --prefix=${FLATPAK_DEST}
+ "psutil"
+ sources:
+ - type: file
+ url: https://files.pythonhosted.org/packages/33/e0/82d459af36bda999f82c7ea86c67610591cf5556168f48fd6509e5fa154d/psutil-5.7.3.tar.gz
+ sha256: af73f7bcebdc538eda9cc81d19db1db7bf26f103f91081d780bbacfcb620dee2
+ - name: python3-qrcode
+ buildsystem: simple
+ build-commands:
+ - pip3 install --exists-action=i --no-index --find-links="file://${PWD}" --prefix=${FLATPAK_DEST}
+ "qrcode"
+ sources:
+ - type: file
+ url: https://files.pythonhosted.org/packages/42/87/4a3a77e59ab7493d64da1f69bf1c2e899a4cf81e51b2baa855e8cc8115be/qrcode-6.1-py2.py3-none-any.whl
+ sha256: 3996ee560fc39532910603704c82980ff6d4d5d629f9c3f25f34174ce8606cf5
+ - type: file
+ url: https://files.pythonhosted.org/packages/ee/ff/48bde5c0f013094d729fe4b0316ba2a24774b3ff1c52d924a8a4cb04078a/six-1.15.0-py2.py3-none-any.whl
+ sha256: 8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced
diff --git a/git-hooks/README.md b/git-hooks/README.md
deleted file mode 100644
index 0d8f80c9..00000000
--- a/git-hooks/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-To use these hooks, cp any of them to onionshare's `.git/hooks`.
-
-* `pre-push` runs the test suite, and will push if the tests pass.
diff --git a/git-hooks/pre-push b/git-hooks/pre-push
deleted file mode 100755
index 1d8e57f8..00000000
--- a/git-hooks/pre-push
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/bash
-
-# Pre-push hook. If you want to test with a different version of firefox, put
-# the path in the CFX_FIREFOX environment variable.
diff --git a/install/build_deb.sh b/install/build_deb.sh
deleted file mode 100755
index aec026a4..00000000
--- a/install/build_deb.sh
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/bin/bash
-
-DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )"
-cd $DIR
-
-VERSION=`cat share/version.txt`
-
-# clean up from last build
-rm -r deb_dist >/dev/null 2>&1
-
-# build binary package
-python3 setup.py --command-packages=stdeb.command bdist_deb
-
-# return install instructions if onionshare builds properly
-if [[ $? -eq 0 ]]; then
- # The build process in stdeb's util.py renames .dev to ~dev
- # Adjust it here for the purposes of displaying the right filename
- VERSION="${VERSION/.dev/~dev}"
- echo ""
- echo "To install, run:"
- echo "sudo dpkg -i deb_dist/onionshare_$VERSION-1_all.deb"
-else
- echo "OnionShare failed to build!"
- exit 1
-fi
diff --git a/install/build_exe.bat b/install/build_exe.bat
deleted file mode 100644
index ba626fa2..00000000
--- a/install/build_exe.bat
+++ /dev/null
@@ -1,17 +0,0 @@
-REM delete old dist files
-rmdir /s /q dist
-
-REM build onionshare-gui.exe
-pyinstaller install\pyinstaller.spec -y
-
-REM download tor
-python install\get-tor-windows.py
-
-REM sign onionshare-gui.exe
-signtool.exe sign /v /d "OnionShare" /a /tr http://time.certum.pl/ dist\onionshare\onionshare-gui.exe
-
-REM build an installer, dist\onionshare-setup.exe
-makensis.exe install\onionshare.nsi
-
-REM sign onionshare-setup.exe
-signtool.exe sign /v /d "OnionShare" /a /tr http://time.certum.pl/ dist\onionshare-setup.exe
diff --git a/install/build_osx.sh b/install/build_osx.sh
deleted file mode 100755
index 40e1fe90..00000000
--- a/install/build_osx.sh
+++ /dev/null
@@ -1,55 +0,0 @@
-#!/bin/bash
-
-ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )"
-cd $ROOT
-
-# deleting dist
-echo Deleting dist folder
-rm -rf $ROOT/dist &>/dev/null 2>&1
-
-# build the .app
-echo Building OnionShare.app
-pyinstaller $ROOT/install/pyinstaller.spec
-python3 $ROOT/install/get-tor-osx.py
-
-# create a symlink of onionshare-gui called onionshare, for the CLI version
-cd $ROOT/dist/OnionShare.app/Contents/MacOS
-ln -s onionshare-gui onionshare
-cd $ROOT
-
-if [ "$1" = "--release" ]; then
- mkdir -p dist
- APP_PATH="$ROOT/dist/OnionShare.app"
- PKG_PATH="$ROOT/dist/OnionShare.pkg"
- IDENTITY_NAME_APPLICATION="Developer ID Application: Micah Lee"
- IDENTITY_NAME_INSTALLER="Developer ID Installer: Micah Lee"
- ENTITLEMENTS_CHILD_PATH="$ROOT/install/macos_sandbox/child.plist"
- ENTITLEMENTS_PARENT_PATH="$ROOT/install/macos_sandbox/parent.plist"
-
- echo "Codesigning the app bundle"
- codesign \
- --deep \
- -s "$IDENTITY_NAME_APPLICATION" \
- --force \
- --entitlements "$ENTITLEMENTS_CHILD_PATH" \
- --timestamp \
- "$APP_PATH"
- codesign \
- -s "$IDENTITY_NAME_APPLICATION" \
- --force \
- --entitlements "$ENTITLEMENTS_PARENT_PATH" \
- --timestamp \
- "$APP_PATH"
-
- echo "Creating an installer"
- productbuild \
- --sign "$IDENTITY_NAME_INSTALLER" \
- --component "$APP_PATH" /Applications \
- --timestamp \
- "$PKG_PATH"
-
- echo "Cleaning up"
- rm -rf "$APP_PATH"
-
- echo "All done, your installer is in: $PKG_PATH"
-fi
diff --git a/install/build_rpm.sh b/install/build_rpm.sh
deleted file mode 100755
index 145f0a3c..00000000
--- a/install/build_rpm.sh
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-
-DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )"
-cd $DIR
-
-VERSION=`cat share/version.txt`
-
-# clean up from last build
-rm -r build dist >/dev/null 2>&1
-
-# build binary package
-python3 setup.py bdist_rpm --requires="python3-flask, python3-flask-httpauth, python3-stem, python3-qt5, python3-crypto, python3-pysocks, nautilus-python, tor, obfs4, python3-psutil, python3-socketio, python3-flask-socketio, python3-qrcode"
-
-# install it
-echo ""
-echo "To install, run:"
-echo "sudo dnf install dist/onionshare-$VERSION-1.noarch.rpm"
diff --git a/install/onionshare.nsi b/install/onionshare.nsi
deleted file mode 100644
index 21ac0baa..00000000
--- a/install/onionshare.nsi
+++ /dev/null
@@ -1,111 +0,0 @@
-!define APPNAME "OnionShare"
-!define BINPATH "..\dist\onionshare"
-!define ABOUTURL "https:\\onionshare.org\"
-
-# change these with each release
-!define INSTALLSIZE 132423
-!define VERSIONMAJOR 2
-!define VERSIONMINOR 3
-!define VERSIONSTRING "2.3.dev1"
-
-RequestExecutionLevel admin
-
-Name "OnionShare"
-InstallDir "$PROGRAMFILES\${APPNAME}"
-Icon "onionshare.ico"
-
-!include LogicLib.nsh
-
-Page directory
-Page instfiles
-
-!macro VerifyUserIsAdmin
-UserInfo::GetAccountType
-pop $0
-${If} $0 != "admin" ;Require admin rights on NT4+
- messageBox mb_iconstop "Administrator rights required!"
- setErrorLevel 740 ;ERROR_ELEVATION_REQUIRED
- quit
-${EndIf}
-!macroend
-
-# in order to code sign uninstall.exe, we need to do some hacky stuff outlined
-# here: http:\\nsis.sourceforge.net\Signing_an_Uninstaller
-!ifdef INNER
- !echo "Creating uninstall.exe"
- OutFile "$%TEMP%\tempinstaller.exe"
- SetCompress off
-!else
- !echo "Creating normal installer"
- !system "makensis.exe /DINNER onionshare.nsi" = 0
- !system "$%TEMP%\tempinstaller.exe" = 2
- !system "signtool.exe sign /v /d $\"Uninstall OnionShare$\" /a /tr http://time.certum.pl/ $%TEMP%\uninstall.exe" = 0
-
- # all done, now we can build the real installer
- OutFile "..\dist\onionshare-setup.exe"
- SetCompressor /FINAL /SOLID lzma
-!endif
-
-Function .onInit
- !ifdef INNER
- WriteUninstaller "$%TEMP%\uninstall.exe"
- Quit # bail out early
- !endif
-
- setShellVarContext all
- !insertmacro VerifyUserIsAdmin
-FunctionEnd
-
-Section "install"
- SetOutPath "$INSTDIR"
- File "onionshare.ico"
- File /a /r "${BINPATH}\"
-
- # uninstaller
- !ifndef INNER
- SetOutPath $INSTDIR
- File $%TEMP%\uninstall.exe
- !endif
-
- # start menu
- CreateShortCut "$SMPROGRAMS\${APPNAME}.lnk" "$INSTDIR\onionshare-gui.exe" "" "$INSTDIR\onionshare.ico"
-
- # registry information for add\remove programs
- WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "DisplayName" "${APPNAME}"
- WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\""
- WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" \S"
- WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "InstallLocation" "$\"$INSTDIR$\""
- WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "DisplayIcon" "$\"$INSTDIR\onionshare.ico$\""
- WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "URLInfoAbout" "$\"${ABOUTURL}$\""
- WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "DisplayVersion" ${VERSIONSTRING}
- WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "VersionMajor" ${VERSIONMAJOR}
- WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "VersionMinor" ${VERSIONMINOR}
- # there is no option for modifying or repairing the install
- WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "NoModify" 1
- WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "NoRepair" 1
- # set the INSTALLSIZE constant (!defined at the top of this script) so Add\Remove Programs can accurately report the size
- WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "EstimatedSize" ${INSTALLSIZE}
-SectionEnd
-
-# uninstaller
-Function un.onInit
- SetShellVarContext all
-
- #Verify the uninstaller - last chance to back out
- MessageBox MB_OKCANCEL "Uninstall ${APPNAME}?" IDOK next
- Abort
- next:
- !insertmacro VerifyUserIsAdmin
-FunctionEnd
-
-!ifdef INNER
- Section "uninstall"
- Delete "$SMPROGRAMS\${APPNAME}.lnk"
-
- # remove files
- RMDir /r $INSTDIR
-
- # remove uninstaller information from the registry
- DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}"
- SectionEnd
-!endif
diff --git a/install/onionshare80.xpm b/install/onionshare80.xpm
deleted file mode 100644
index a3d0f6dc..00000000
--- a/install/onionshare80.xpm
+++ /dev/null
@@ -1,257 +0,0 @@
-/* XPM */
-static char * icon_xpm[] = {
-"80 80 174 2",
-" c None",
-". c #4E0D4E",
-"+ c #531453",
-"@ c #581B58",
-"# c #673067",
-"$ c #906890",
-"% c #B397B3",
-"& c #CFBECF",
-"* c #E0D5E0",
-"= c #F0EBF0",
-"- c #FCFCFC",
-"; c #4F0E4F",
-"> c #6E396E",
-", c #8F668F",
-"' c #C1AAC1",
-") c #EFE9EF",
-"! c #FFFFFF",
-"~ c #865986",
-"{ c #C5B0C5",
-"] c #EAE2EA",
-"^ c #764476",
-"/ c #DFD4DF",
-"( c #FAF9FA",
-"_ c #5E235E",
-": c #BDA5BD",
-"< c #885C88",
-"[ c #E8DFE8",
-"} c #521352",
-"| c #B89EB8",
-"1 c #FCFBFC",
-"2 c #5B1F5B",
-"3 c #4D0C4D",
-"4 c #571A57",
-"5 c #5D225D",
-"6 c #D8C9D8",
-"7 c #612761",
-"8 c #D4C4D4",
-"9 c #D4C5D4",
-"0 c #4E0C4E",
-"a c #632A63",
-"b c #DDD1DD",
-"c c #693269",
-"d c #DED3DE",
-"e c #FDFCFD",
-"f c #F6F3F6",
-"g c #D7C9D7",
-"h c #A482A4",
-"i c #7E4E7E",
-"j c #652D65",
-"k c #521252",
-"l c #490649",
-"m c #4B094B",
-"n c #662E66",
-"o c #D9CCD9",
-"p c #DCD0DC",
-"q c #A584A5",
-"r c #622862",
-"s c #440044",
-"t c #470447",
-"u c #4A084A",
-"v c #4C0A4C",
-"w c #825482",
-"x c #6F3A6F",
-"y c #4D0B4D",
-"z c #642B64",
-"A c #DBCFDB",
-"B c #F7F3F7",
-"C c #9B779B",
-"D c #835683",
-"E c #E5DBE5",
-"F c #E4DAE4",
-"G c #E8E0E8",
-"H c #713C71",
-"I c #4C0B4C",
-"J c #8C628C",
-"K c #E2D9E2",
-"L c #672F67",
-"M c #6D386D",
-"N c #E7DFE7",
-"O c #622962",
-"P c #926A92",
-"Q c #FAF8FA",
-"R c #E2D7E2",
-"S c #6C376C",
-"T c #4A074A",
-"U c #6B346B",
-"V c #CCBACC",
-"W c #875C87",
-"X c #F9F7F9",
-"Y c #7B4C7B",
-"Z c #DED4DE",
-"` c #5B1E5B",
-" . c #855885",
-".. c #DDD2DD",
-"+. c #895E89",
-"@. c #DBCEDB",
-"#. c #4B084B",
-"$. c #7F507F",
-"%. c #F7F4F7",
-"&. c #5F245F",
-"*. c #764576",
-"=. c #551755",
-"-. c #FEFEFE",
-";. c #D7CAD7",
-">. c #5C205C",
-",. c #815381",
-"'. c #F3EEF3",
-"). c #774577",
-"!. c #F4F0F4",
-"~. c #D3C3D3",
-"{. c #591C59",
-"]. c #703C70",
-"^. c #FEFDFE",
-"/. c #D3C4D3",
-"(. c #511051",
-"_. c #501150",
-":. c #B093B0",
-"<. c #B59AB5",
-"[. c #FDFDFD",
-"}. c #B79CB7",
-"|. c #B599B5",
-"1. c #895F89",
-"2. c #734073",
-"3. c #987298",
-"4. c #9A759A",
-"5. c #8A608A",
-"6. c #511251",
-"7. c #602660",
-"8. c #CEBCCE",
-"9. c #F1ECF1",
-"0. c #855985",
-"a. c #5E225E",
-"b. c #784778",
-"c. c #DED1DE",
-"d. c #F3EFF3",
-"e. c #7F517F",
-"f. c #F5F1F5",
-"g. c #470347",
-"h. c #5D215D",
-"i. c #F3F0F3",
-"j. c #865B86",
-"k. c #450145",
-"l. c #D6C7D6",
-"m. c #F4F1F4",
-"n. c #805280",
-"o. c #E6DCE6",
-"p. c #885D88",
-"q. c #5C215C",
-"r. c #E6DDE6",
-"s. c #F8F6F8",
-"t. c #936C93",
-"u. c #460246",
-"v. c #DACDDA",
-"w. c #F6F4F6",
-"x. c #8E658E",
-"y. c #450045",
-"z. c #5E245E",
-"A. c #642C64",
-"B. c #DED2DE",
-"C. c #F7F5F7",
-"D. c #EEE7EE",
-"E. c #EDE6ED",
-"F. c #916991",
-"G. c #ECE5EC",
-"H. c #FBF9FB",
-"I. c #6A336A",
-"J. c #662F66",
-"K. c #FBFAFB",
-"L. c #956F95",
-"M. c #E9E1E9",
-"N. c #DACCDA",
-"O. c #541654",
-"P. c #BAA1BA",
-"Q. c #4E0E4E",
-" . . . . . . . . . . . . ",
-" . . . . . . . . . . . . . . . . . . . . ",
-" . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
-" . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
-" . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
-" . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
-" . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
-" . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
-" . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
-" . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
-" . . . . . . . . . . . . . . . . . . + @ # $ % & * = - - = * & % $ # @ + . . . . . . . . . . . . . . . . . . ",
-" . . . . . . . . . . . . . . . . ; > , ' ) ! ! ! ! ! ! ! ! ! ! ! ! ! ! ) ' , > ; . . . . . . . . . . . . . . . . ",
-" . . . . . . . . . . . . . . . . ~ { ] ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ] { ~ . . . . . . . . . . . . . . . . ",
-" . . . . . . . . . . . . . . . ^ / ( ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ( / ^ . . . . . . . . . . . . . . . ",
-" . . . . . . . . . . . . . . _ : ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! : _ . . . . . . . . . . . . . . ",
-" . . . . . . . . . . . . . . < [ ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! [ < . . . . . . . . . . . . . . ",
-" . . . . . . . . . . . . } | 1 ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! 1 | } . . . . . . . . . . . . ",
-" . . . . . . . . . . . . 2 & ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! & 2 . . . . . . . . . . . . ",
-" . . . . . . . . . . . . 2 & ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! & 2 . . . . . . . . . . . . ",
-" . . . . . . . . . 3 3 4 & ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! & 2 . . . . . . . . . . . ",
-" . . . . . . . . . . . . 5 6 ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! & } . . . . . . . . . . . ",
-" . . . . . . . . . . . . . 7 8 ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! | . . . . . . . . . . . ",
-" . . . . . . . . . . . . . . . _ 9 ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! 1 < . . . . . . . . . . . ",
-" . . . . . . . 3 0 . . . . . . . a b ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! [ _ . . . . . . . . . . ",
-" . . . . . . . . 0 . . . . . . . . . c d ! ! ! ! ! ! ! ! ! ! e f g h i j k k j i h g f e ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! : . . . . . . . . . . . ",
-" . . . . . . . . . . . . . l m . . . . n o ! ! ! ! ! ! ! ! p q r s t u v . . v u t s r q p ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ^ . . . . . . . . . . ",
-" . . . . . . . . . . . . . 3 w x y . . . . z A ! ! ! ! ! B C 7 t v . . . . . . . . . . v t 7 C B ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! / . . . . . . . . . . . ",
-" . . . . . 3 0 . . . . . y D ! E 7 3 . . . . c F ! ! ! G H ; 3 . . . . . . . . . . . . . . 3 ; H G ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ( ~ . . . . . . . . . . ",
-" . . . . . 0 . . . . 3 I J ! ! ! K L l . . . . M E ! N O u . . . . . . . . . . . . . . . . . . u O N ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! { ; . . . . . . . . . ",
-" . . . . . . . . . . I P Q ! ! ! ! R S T . . . . U V O l . . . . . . . . . . . . . . . . . . . . l O G ! ! ! ! ! ! ! ! ! ! ! ! ! ! ] > . . . . . . . . . ",
-" . . . . 0 . . . . . v W X ! ! ! ! ! ! / j 3 . . . . + u . . . . . . . . . . . . . . . . . . . . . . u H B ! ! ! ! ! ! ! ! ! ! ! ! ! ! , . . . . . . . . . . ",
-" . . . 0 . . . . . v Y ! ! ! ! ! ! ! ! ! Z ` 0 . . . . . 3 . . . . . . . . . . . . . . . . . . . . . . ; C ! ! ! ! ! ! ! ! ! ! ! ! ! ! ' + . . . . . . . . . ",
-" . . 0 . . . . 0 I .! ! ! ! ! ! ! ! ! ! ! ..7 u . . . . . 3 . . . . . . . . . . . . . . . . . . . . . 3 7 p ! ! ! ! ! ! ! ! ! ! ! ! ! ) @ . . . . . . . . . ",
-" . . . . . . . v +.B ! ! ! ! ! ! ! ! ! ! ! ! @.L #.. . . . . 3 . . . . . . . . . . . . . . . . . . . . . t q e ! ! ! ! ! ! ! ! ! ! ! ! ! # . . . . . . . . . ",
-". 0 . . . . . m $.%.! ! ! ! ! ! ! ! ! ! ! ! ! ! o &.. . . . . . 3 . . . . . . . . . . . . . . . . . . . . v r f ! ! ! ! ! ! ! ! ! ! ! ! ! $ . . . . . . . . . . ",
-"3 . . . . . m *.! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! o =.. . . . . . 3 . . . . . . . . . . . . . . . . . . . . s g ! ! ! ! ! ! ! ! ! ! ! ! ! % . . . . . . . . . . ",
-". . . . . v i -.! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ;.>.m . . . . 3 3 . . . . . . . . . . . . . . . . . . . t h ! ! ! ! ! ! ! ! ! ! ! ! ! & . . . . . . . . . . ",
-". . . . v ,.'.! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! 9 r v . . . . . 3 . . . . . . . . . . . . . . . . . . u i ! ! ! ! ! ! ! ! ! ! ! ! ! * . . . . . . . . . . ",
-". . . u ).!.! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ~.{.. . . . . . 3 . . . . . . . . . . . . . . . . . v j ! ! ! ! ! ! ! ! ! ! ! ! ! = . . . . . . . . . . ",
-". . m ].^.! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! /.(.. . . . . . 3 . . . . . . . . . . . . . . . . . k ! ! ! ! ! ! ! ! ! ! ! ! ! - . . . . . . . . . . ",
-". y _.:.<.<.<.<.<.<.[.! ! ! ! ! ! ! ! ! ! ! ! ! }.<.<.<.|.<.1.l . . . . . 3 . . . . 3 . . . . . m 2.3.3.3.3.3.4.! ! ! ! ! ! ! ! ! ! ! ! ! [.3.3.3.3.3.3.5.6.3 . ",
-". . . . . . . . . . = ! ! ! ! ! ! ! ! ! ! ! ! ! j v . . . . . . . . . . . . . . . . 3 . . . . . y 7.8.! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! 9.0.#.. . ",
-". . . . . . . . . . * ! ! ! ! ! ! ! ! ! ! ! ! ! i u . . . . . . . . . . . . . . . . . 3 . . . . . 3 a.8.! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! 9.b.m . . . ",
-". . . . . . . . . . & ! ! ! ! ! ! ! ! ! ! ! ! ! h t . . . . . . . . . . . . . . . . . . 3 . . . . . 3 2 c.! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! d.e.3 . . . . ",
-". . . . . . . . . . % ! ! ! ! ! ! ! ! ! ! ! ! ! g s . . . . . . . . . . . . . . . . . . . 3 . . . . . m {./ ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! f.5.g.. . . . . ",
-". . . . . . . . . . $ ! ! ! ! ! ! ! ! ! ! ! ! ! f r v . . . . . . . . . . . . . . . . . . . 3 . . . . . m h.8 ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! i.j.k.. . . . . 0 ",
-" . . . . . . . . . # ! ! ! ! ! ! ! ! ! ! ! ! ! e q t . . . . . . . . . . . . . . . . . . . . 3 . . . . . y r l.! ! ! ! ! ! ! ! ! ! ! ! ! ! m.n.m . . . . . 3 ",
-" . . . . . . . . . @ ) ! ! ! ! ! ! ! ! ! ! ! ! ! p 7 3 . . . . . . . . . . . . . . . . . . . . 3 . . . . . y &.o.! ! ! ! ! ! ! ! ! ! ! ! %.p.y . . . . . 3 . ",
-" . . . . . . . . . + ' ! ! ! ! ! ! ! ! ! ! ! ! ! ! C ; . . . . . . . . . . . . . . . . . . . . . 3 . . . . . #.q.r.! ! ! ! ! ! ! ! ! ! s.t.u.. . . . . 3 . . ",
-" . . . . . . . . . . , ! ! ! ! ! ! ! ! ! ! ! ! ! ! B H u . . . . . . . . . . . . . . . . . . . . . 3 3 . . . . #.7 v.! ! ! ! ! ! ! ! w.x.y.. . . . . 3 . . . ",
-" . . . . . . . . . > ] ! ! ! ! ! ! ! ! ! ! ! ! ! ! G O l . . . . . . . . . . . . . . . . . . . . l z.A.. . . . y L B.! ! ! ! ! ! C.+.v . . . . . 3 . . . ",
-" . . . . . . . . . ; { ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! N O u . . . . . . . . . . . . . . . . . . u O N D.h.. . . . y O E.! ! ! ! ( F.y . . . . . 3 . . . . ",
-" . . . . . . . . . . ~ ( ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! G H ; 3 . . . . . . . . . . . . . . 3 ; H G ! ! D.a . . . . u 7.G.! ! H.C k.. . . . . 3 . . . . . ",
-" . . . . . . . . . . . / ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! B C 7 t v . . . . . . . . . . v t 7 C B ! ! ! ! R I.. . . . #.J.R K.L.y.. . . . . 3 . . . . . . ",
-" . . . . . . . . . . ^ ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! p q r s t u v . . v u t s r q p ! ! ! ! ! ! ! * 7 . . . . y x n.y . . . . . 3 . . . . . . ",
-" . . . . . . . . . . . : ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! e f g h i j k k j i h g f e ! ! ! ! ! ! ! ! ! M.@ . . . . . . . . . . . 3 . . . . . . . ",
-" . . . . . . . . . . _ [ ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! G _ . . . . . . . . . 3 . . . . . . . ",
-" . . . . . . . . . . . < 1 ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! @.A.. . . . . . . 3 . . . . . . . . ",
-" . . . . . . . . . . . | ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! N.2 . . . . . 3 3 . . . . . . . ",
-" . . . . . . . . . . . } & ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! F O.. . . 3 . . . . . . . . . ",
-" . . . . . . . . . . . 2 & ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! P.Q.. 3 . . . . . . . . . ",
-" . . . . . . . . . . . . 2 & ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! & 2 0 3 . . . . . . . . . . ",
-" . . . . . . . . . . . . 2 & ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! & 2 . . . . . . . . . . . . ",
-" . . . . . . . . . . . . } | 1 ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! 1 | } . . . . . . . . . . . . ",
-" . . . . . . . . . . . . . . < [ ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! [ < . . . . . . . . . . . . . . ",
-" . . . . . . . . . . . . . . _ : ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! : _ . . . . . . . . . . . . . . ",
-" . . . . . . . . . . . . . . . ^ / ( ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ( / ^ . . . . . . . . . . . . . . . ",
-" . . . . . . . . . . . . . . . . ~ { ] ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ] { ~ . . . . . . . . . . . . . . . . ",
-" . . . . . . . . . . . . . . . . ; > , ' ) ! ! ! ! ! ! ! ! ! ! ! ! ! ! ) ' , > ; . . . . . . . . . . . . . . . . ",
-" . . . . . . . . . . . . . . . . . . + @ # $ % & * = - - = * & % $ # @ + . . . . . . . . . . . . . . . . . . ",
-" . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
-" . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
-" . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
-" . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
-" . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
-" . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
-" . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
-" . . . . . . . . . . . . . . . . . . . . . . . . . . . . ",
-" . . . . . . . . . . . . . . . . . . . . ",
-" . . . . . . . . . . . . "};
diff --git a/install/org.onionshare.OnionShare.svg b/install/org.onionshare.OnionShare.svg
deleted file mode 100644
index 502da0d8..00000000
--- a/install/org.onionshare.OnionShare.svg
+++ /dev/null
@@ -1,2154 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Generator: Adobe Illustrator 23.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
- <!ENTITY ns_extend "http://ns.adobe.com/Extensibility/1.0/">
- <!ENTITY ns_ai "http://ns.adobe.com/AdobeIllustrator/10.0/">
- <!ENTITY ns_graphs "http://ns.adobe.com/Graphs/1.0/">
- <!ENTITY ns_vars "http://ns.adobe.com/Variables/1.0/">
- <!ENTITY ns_imrep "http://ns.adobe.com/ImageReplacement/1.0/">
- <!ENTITY ns_sfw "http://ns.adobe.com/SaveForWeb/1.0/">
- <!ENTITY ns_custom "http://ns.adobe.com/GenericCustomNamespace/1.0/">
- <!ENTITY ns_adobe_xpath "http://ns.adobe.com/XPath/1.0/">
-]>
-<svg version="1.1" id="OnionShare" xmlns:x="&ns_extend;" xmlns:i="&ns_ai;" xmlns:graph="&ns_graphs;"
- xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1024 1024"
- style="enable-background:new 0 0 1024 1024;" xml:space="preserve">
-<style type="text/css">
- .st0{fill:#FFFFFF;}
- .st1{fill:#4E0D4E;}
-</style>
-<switch>
- <foreignObject requiredExtensions="&ns_ai;" x="0" y="0" width="1" height="1">
- <i:pgfRef xlink:href="#adobe_illustrator_pgf">
- </i:pgfRef>
- </foreignObject>
- <g i:extraneous="self">
- <g>
- <path class="st0" d="M896,512c0-212.08-171.92-384-384-384c-112.14,0-213.06,48.08-283.26,124.74l130.35,130.35
- C395.77,339.61,450.66,312,512,312c110.46,0,200,89.54,200,200h-88l176,176l176-176H896z"/>
- <circle class="st1" cx="512" cy="512" r="512"/>
- <path class="st0" d="M896,512c0-212.08-171.92-384-384-384c-112.14,0-213.06,48.08-283.26,124.74l130.35,130.35
- C395.77,339.61,450.66,312,512,312c110.46,0,200,89.54,200,200h-88l176,176l176-176H896z"/>
- <path class="st0" d="M128,512c0,212.08,171.92,384,384,384c112.14,0,213.06-48.08,283.26-124.74L664.91,640.91
- C628.23,684.39,573.34,712,512,712c-110.46,0-200-89.54-200-200h88L224,336L48,512H128z"/>
- </g>
- </g>
-</switch>
-<i:pgf id="adobe_illustrator_pgf">
- <![CDATA[
- eJzsvfuSHEd25vkE8Q65f8ise226FOGX8IjesTWrq7bX1FJbtzQj2dgYDSKhFkYkQAPB1vQ+/X6/
-73hkRlZlAaDIJns0qCBAVIZnXNyPn+t3zvmL/+M3v/vF9Rdv/unlL/LVeBj+4i9u37588e7N218e
-/OnhV19++e03797y0c9++/PD1K5GDbr+1fJZH/hfXr795tWb1788JF3gatLJB779s7sXr1//8XD3
-7ddfvvyfPz/87Oc68Xev3n35Uqe+fPP7N1ff/OH3P99up+/fvXinU+kv619O62H9ZZ0Pv/k1p1+8
-/sOLb7559f/p5DTnJeuzmzffvv7i1evf37z5n788/GJKtR1SG9vhFymnQ245acz/8+q3L795MnC+
-WnLNKbV5rtVfuirLlKa2lnVOvsBuRFm42rQfoivfvfn8269evn73m7dvPn/5zTe3b7588/abXx5u
-//ji9eHXL36vMy8O//jyyy/f/Nvh5ssXn//roMmqnz28+vKl5uWrF+8OU2YKr381pc9uvn315Rd/
-8+1X//RSM1aLP86f+ZJ//42upcvybz5un/3qK33yu5fv3umNdEOW4bd/dbN/DH3o42f/7bcvf//K
-q6aZ/e8/75d9++brr168/ddvfrC54Kp/9/Krr7/U2nmOUx2vqr7q/+1/6WM1CX0tppTO77+eX/zw
-i7ws+/uvh1zPHzGueVqOl3949fLffnn4mzevX8acX79997sgnFLGMf6OM7/99suXb//+9at3mouZ
-j9aY9F+/+eLllxp//P7Dly881z6m098x4O9evP39y3citDdffvvOe2DZ7qBF/esXf3wJZUxxg7/9
-+uXrv3vzX/yMv0hzmq7mluuyLlNu66GUMl3lrF+WlEtdDuOVJq6uVTS/lDavIpt1PkzjNB2mxQ+h
-QVMaj882Hf/uj8ANud32HE0E8xuR0N++ffX7V69/OXmSawni+qu3r7440daUdO15+5/vcFWnlZ9l
-XNNcp/KRn7TqT9axzJmN+hGfxHRp5t+9e/m6T5/2yu2vd7Q/Xv36d3qd+9df3L75iuX/Br4gon+t
-/SD2EueO//YZff3br2Nq/PtnopTfvH31mmsOf+Mzy2e/+fJbnfqrt2++/fpXr//5zfCz4IL/5eXn
-YnUipi8Of/tP/0O/iKN5Px7+7u2Lz3UB/X4cc/Xi1dc/f+/l9HJvXx7ipL7pX7f/f/jbdy//WZzk
-9PX49P71H15++ebr3WVj3Iev95svX7x+8fbgz4+X++tXf9CZF5qe0wUZ+PLdP3zEFUVwX2s6fA0P
-eXT19wzYnfrwjf761esnF/BnL96++7c3b//1eMOdGLt68fUHrvq7f3357vN/eXzd/un3u/Ifv/qn
-N1+++uar49f3n/xG1371+Zcvf/fHb969/IiF+93n7JG3h5u3337zL4e/e/Pmy9Nlz04dV7B/7E8Z
-/+dxj9/4C6//9rX+8S+X7tQHPL6TGHR858/0XsfvXLqPTv6vco/bF19++er3b198/S+vPr90mwvn
-j/fbn/tuy6Q3+vLl6y++Od4mfj1dGhYVn330sh/uv3iljfoMU3rvmN/92wtt/79+9U/vvRvP/c+v
-Xn+hbfG7b1+9e3maozdffY06evjdv7z4+qU3+zbyd8cL1s8ktfZy6Re/eI/AkoC9eb07/1dvX3zx
-SrJQGvbDiy8kmt4cbvXrS1j7y5evfz5c/ljSPR9uvhj+2yABnpYV/WNax7EsSZ9M89ratMx1nEZp
-LcOkz6SELBPnS1slsvlePvvRJ3NdpMnUtJZpanPlW3WUZpDXNNV5mfNQDn/x2c3bn+amF9718OS2
-KFOPb3t4ctvDk9sentz2wLXmQ5WGJkVUTyDl5bOf8AluvvnR33+Mu9ef7PVPD/ATvH2f+5967f3u
-N3dHVrNxjMtM5DffvpXx/p8Of/v2xevfvxT7ePTBnnGMY05rXcvS9F7Tqk9ynaepjiXLbGdvrqtM
-ubK2pZR5nbWj+WzR6dySzLtxWmd28O5VSvO+96mxxdDjDv7Pw/V8XXWU63ydricd43qv4269Wa/D
-DFlnHmnVROiRNNHL/XK33MjkWpe2zIumdZnaQ7vVoeca2txKy22aH3Tc6bjRg66aQX7qLOtk1rrM
-0zzOY33QcV/vdNzWGx26U11q01Fr0ZFqGmQCPei4L7c69KBlLbpDmTlfso5UxjLmh3yv4y7f6tDL
-5DUvOlrW/RikVU76M+VxyGN68HGv4y7d6rjRcZ30hmlJTQePWJOuLPudH5nLaeSYHqZ7HXc6bjRb
-N5qRZRB1NR3zVHWUSTdh/DSNDzruxzsdt/pzM17rWH0sOmYfWtx+5LjD8H9rWfRQ0/FIu//7cc9+
-30aN23HzwJ9+3PvPvehV/7vV37c6rm9u9Of6Zr3RQt40HfVmZv5vsg5mg4d90HGv41YHw0UQ14vo
-BYopA3MskjHRrA867kQ2tzoYB3WIGkw4kE4QD+/9oONOJHSr48ZkdL3w0wZT07xUlk00JaqCrpZR
-tHXf7vTnVn/f6O9rHav+LPq76e8GvUASIrvEQrSxjfPDIPq71xE0eKs/Nzz7kRq1y/V3MUVuNAlV
-Tp0qHzpd8kfU6WUZf+Cf919QPEsEsmot7qdRRDWL2m6me1GJLHzR6k26z6OIumrGbvOdaCgNRYxB
-c35T7utYs7bIoi11V+/1alkv3DQBt/OD5ihroy6axTuR4qRdPGsRrrU0D1qorIVr4gB368OgFc5a
-8EUEcHt9d/0g0kgilCbiuRYp3YviJu25oklqWtT19vb2ThQ/3WVN33yn6/vPcnd9d3N3d/cwaP/k
-++pjvm9iNtf3t/d3OuLnQZsmacOzCuYhopj14WZ33D3cH487LcuohYFQ/CIQDgRUREhVL6V3NH1B
-Z9eiN+juzhTIdUezNDZ+NqVWiAPKHUTA/FxrFm5M1nfmiw9sYfPJ5A1QzD2hq8b1Rfv83PTJutPu
-efCUjcPN5I2Vb7Q23mqzN97C9b0Zb7w12ab37GDPK/s799mtt1o5zzGzfD1oW/INTbeO+9uH2wcY
-jSZePE2TX3TUvgQsgF6AB9Ii8IU7JvyOqRzhZ+KEedCyiMt6WVgYTRFvrOXhkU5LxAKND5NZqLju
-cam0Tx88qQ9+Z+8XbUqtBDNrzs27w8V5OO7Fd8UAYZuwetErFMuPSNViYDH9rkwyczZ4L/Je996h
-D+ahk3cvu5jdXL2v2d8NfuL9zgrdmAvcmh/cQ1ewicH8Ap4vUWEewm35bjNvgces5jg3lnB35kT3
-ftcguD3JiegGU918pLqN7vaUt9Henvqyqe9If+agJsDhjAY7FR7pMB3pcE+JGy3uqbHTo5dFy38r
-QrjW9didsya0iGSSiGcUId2LQm5FWte656K3njXpRVSIrBktTxAjN12AtJt50NIUS47JcuNed0Jm
-XFtitJAYXcMY9fToF7ddw0BQ7DUMRMT9oHlCPlxrGhYLhqrJzRYKm0C41ZIgCBAAswVAsP/RfP/O
-HP/avL7N83BUPSarHfdd5bjuCsdshUNKU0XbQtu4E53eWNtYurZRrGtMoWsMVjVuuqKBmlG7kjFZ
-vwjNIrSKxRpF7drE1LWIO21vdIgVOadl2RlVj/TAwyM98PBED7Rv+ZEeeHiiBx6e6IHPmFQ/0f1t
-UvwE966TRtfyk77/9gyeA0nwxXxACusazv2FnSIrR2bKuvZgQtnZJ6lhs6S2ewYMnVC7t5920Yj6
-Ue72XUymv3/9+sVXL784/L5/BHHIcLr4MSGcMJ+6dpakNFVx9lUM8lZyapLiVMTkUZ1uJbVQnoq2
-46qteXdUoAiK3mhD30uJmrTTq/b89SAGcGdFKlksIYxuJFFD4hTLmNUKlSWK5AmipFiANIuNG4uM
-+00zGY6KSaglm0qyV0c2ZaR2cbCJArNzy4G7oxy4H7oomLpKEsIgxEEIhBAJIRTaUTSchMP2cxPH
-0GXFJi9Ox30/HrYDrWZ3TJePwVrP+ZEvHuWZo54fw+MPdsf87NGeP4ZnTy3/vmP4DoPXjzmGjxv2
-8cenC14YcLTvJvGQbNNr4yL34iOjLPosRTU4yY3EN7wk2RRr5ia3EvoP4odZisBsjnI9iLDvOlPJ
-Ns2a1WArv13hRdldrOLeWLe9N38JDlPNYxZzGWuvw1F5nayzbszmpKneHLXU0FFDQz3qpzvl1EbR
-0CkxdNPOiLp2uumnueunJ6a011K3Yz3pq9ddZ+W4PR53e8616bFxWJsdj7bVtGNoaYj/9SO/5yiP
-jvrkMC8cOku8dLSPPpbTMex/+ahjff8xfGjAdz0+9oIf/TN8/ND/bS74Xg6y4x+LSBvbHkfOtNNG
-bsw/pHqKf1Qph4t23c2AUiIje5LpUa2WLNZKMJ0nm8vFpvKOf8gqnro9vFnCz3KQjYfsuci1pd9t
-t3TvH3GRfOQi4Vxpw9G/suck95ude+QlwU1CwTl5XE5c5Wj9DmYtbcdU1h2NXuYpjznLGYcZnjCZ
-czbziOFcOB5xmuE7MKHnjx1jGi7wqvcfz7OwD/K4f9fx6YI/wgV/dB/z1I8IbmQfxQbUbOYV7Ota
-+j0BjAcPngZzstJ52eowyK30oeBnMoutES3maLdHrSh1O2sOvoZatClGgznbLM7Gvrjdcbds7oZ+
-BNGH5+/B2lHu7uxmZQQdH7/eg915eRBXg6c1m2GrPXfmZfbZwcM2G6xZd7FP1f7OYFSh8ARLauEO
-jp9gOuEWDT6ycYhtU29rufGrblftDCkbT4MtqJOdtDeE9hbNuUHyWGnd/Qz+++7CcX/5OMWLLh5p
-6KGmjznKxxzDxw2zl/ujjuHjh/5vc0FzkIeHh7uHG0m89lAf8sN0/3B/pxVftQGqNt1093B3J8rA
-+Tvflbtkp+/d7Y3dvbNdvZPdvDh5Vyzk2e5dnLu4dnHs4tYNp264dO8c+Qt3bjhzuyv3zI/bvbjD
-0Y37MU7cnRvXXty9H7d7cgfvlnDmbu7ccOiGSzecuuHWDcfuTQ8lL3bv4uCNgHKJkPJgT+/UI8tb
-bPmux5dv7Pi9DjbR48ytx5p9T0ecS0cXJI4hOy4cLHYXf8ZPHMe2mzY3ycZaNoVpOR7W24ZjoHru
-4erTUXZHPjse/0ynYzhFuc+P6eGZ4/69x93gMPnHHbcfcwwfN+wZT9SFY/j4of+bXPDh4RMH+cRB
-PnGQP9f9+ed/wU8c5BMH+cRB/nz355//Bc1BNlx7PyYf3/lDwBRNm28pa2uj9laE5eda8jiDEZ6n
-Voz+BTesv0qZciG23bSB2SoL8ZmRkP80nkGEP+qTQCRfQFj8OT3UzTdDJGXOhykDRBjFQbdHvXBm
-G68H1Il5upr0c8jlap5OIIr3jDj/ftNVa9JTjVc5re3C9x+POH6/tUdYhscff0/QwXQZdDDtMNv/
-ebg5ungs946/BQDuFDAKWG8Aq3T4VwmF2dDh9sFfj4Dtszsd7xFXv7m9i2+2qV78xw==
- ]]>
- <![CDATA[
- 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
- ]]>
- <![CDATA[
- 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
- ]]>
- <![CDATA[
- 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
- ]]>
- <![CDATA[
- NE8wcY3Ar4pfphA7C7BFActVV1uSMTMpPNgzGrZd8XMUuaCjqmTgoQKER/HCMh2N2Zg6os4gFnEH
-exFpUEcTN1B5pYXCIytBpl2/ER72Cc4mGxB8DJBAhIJenr7yet4Zo45kDMRlMozSZuQsrVmzoxEg
-R2WFz/jDWngewdPjGpO4DzuwonuDKiO1YDYqPIeKPZNEQkhsNYtvoMY0MGACNp2RW/h14UTg7KFI
-WBwUmaceVOak+eUCBm4JmtOqg5TRHGFpzg3ANthHB51bipicnaKrBZP2vC5A4lKAgALjMuPY6Pxo
-TIZC4Pgg9OSXLZ53+razx8YSEbkmKZDncMgXEKoggcVpgzGNS+RiNDBcvKwoJ5zYYn/ogh5h7Qyl
-F+In1LdU40V1mXbhTgQVsyF9kto9sldtYfDE2oDZ4EFjFzXxSIWKtoUpKVZi7CBL4xG5j7A+JvUR
-Rx86/gLf8J3WfqeuxIAFSAZbElJyXop1mATkF7ANSMdmCFbEnlpzT+6QH5OR8cS7s9R1h8hSxPW1
-fbiOuFudCK6BcnQcDL2hEgdLmnrr75D7Qg1qh6lAgxnrpZ0HyuG2K70A7IAMjtMa2QBNzMqYce0i
-67Z4gmDNhMIM9Gd/APTHudKVZ9zrM1q5BBfgXCL7xvdJt8goXboOcQOzeBwb0t3Y9NbOkwPQhJ1F
-MihjmxcDXbk6CQRY4gxguhLCKNJt8VfA1kZkN3oVunkBqiqa0Akp0zK2iNOu43Y5ZDWaNJh47V5x
-sAlkv4kdcsA8Bik+96vNtceDiE2MgdRPQEXEfnTbbuBpZoE8atRcF3jLCMyDm4iQtGFsKpnN4U8x
-bh8VNCAepABEtJjIpaPBKE0y3O23DrYrG5hO7NjEKMrYxC0iNRk/vBE9ILIjGQcygQM7R2E2lz4G
-1pCYNuvs1dQqWcloVuScy2SDHG1mhWxHsrqwdgmxL6k7W4oBgpHxJD5PZHBh60xAO8Ex4RqcC1Wr
-xMU1jxO+MHBgkoVeLnH5ukVaJ1pkVqMm8WqxZOJJEkMkniRsCZuZmRPJkdcxG8WFBoI1AslMm4PG
-G3y2pZ+JbpJWtS74zcioydE+DX1wRfcBrw0lVqNJxmx/v2ZlAovTtObjKfopsUT0U1shRzZLaj2k
-WfByEDlBQRihUVDjGTd18o2hFm6cDVwf/fbVGTdps+uxbVfieIvR8wfJoatiRz3CxE5fCc+C/Ad5
-Bi4TAdClfl6MIXKuF5kSjsg7IAr8tjGxmFjwiTWQxbUZAursJ/sTsJcdHZS+YASKbnzyFWEhOeUJ
-j36zOBhH4OKSnsVOowZFg3XQI4MBb9Ez1a4wsUPnUxFtWryeJeCddkhU6ecgz247ca1rQiedQKVH
-PHOZHY6T0d1wMs8rgU5JkggMgloEAW37NtJVHGUSM0hbEEM2tJYL3ysBh2wJY3lIgKKQt0B6l5HR
-hggioFYUhQ+Gut4bBUxkOcgc+k6RX/yvRB5EqCQvRPwnhISYBdrKV92BpddLhhm0FmjeZTIKZMYr
-KLZDAkO2VTQayftkhARNxkmLi3lG8D6+UzC42bBb4I6LAWTWGFlbzKepHmJE9QjSo2wVyHqbsQrg
-3v1Oa9ypIsDtr4BcgOAe0R2zUyPiiYHLa/s6B6PQpgFfBW+9jP2t2U1PRzB7U589IBEX7wQ1FoTB
-im9iufDEHlFjxJryhbf+4Dr9kLTxfIT4OxPZ0wgxYS7AvmNy1MrpvYb+ARiTCpodIcb5gnsMhcDZ
-uldzb/kbvZ3zhbYXo83FfZE4R5Ar6M8J17rxZ6RJiqNH4BjTraToedmAMxENnjDp0HEWJ4kWkbO2
-YThgpLsseK5lrJaezcc53FILuRYrsn6UjLBRMtvZOtndT6o1qVjSH5PWX5xIohXUSTb2Y4VNy/gE
-Xxkab5oBWcvSaCRjzh6FXMMDRT6GrlOwdA2RtRgjD8MwydkDFjtTpOJP9gGT9MoIB1Sd1TKFeVWz
-awKAniJ8E8IaM8IqVcWuNJwfY6Q6DdPSWsRMTT9JvhLSmlGrpd0ISJlfS2Je5pHkImRnBlNaHTRo
-FAqU7JNuQcRsy7iVDiYzB32p4e9nFgAWLhhqgIxw2Y2SzH55iUe//Cj1cc2nnDve22ElwMf61Oly
-pYVnRvsHS0iCIfQyqj7YHxWW86KNp5naa3NVCzjiJQeHJongbDrMeHw4Tgqf8QiHtgEEwSdIxtEJ
-KfzZOXVGocTlgLGwsuQf4KvDnV0QwMQmVn978QRJVJINZN9YyF++HL4lmn3zZYBIqw0Y0odlF041
-QJwk2q5jkIVYIWSBRSqyMLp5Bis7GbfPCMyqlX5r0PtmdYe7G8V3Cn0jkkdlm+ATwjyZwzzJVi/Q
-2Ls6Cvl0jV1MMZzKeD7ZDyOxWJJZAcDi6QJCg9mNCbMSowbOC/4fgGz4vdfIF2+UJwOXPDo7khgW
-3LubQtraBrpZeM9ByICzGUWpAF1njpVsLZE2EXeaiYWReQigAoz0Cvdp1fnhTiYGi6mntT8w7kSk
-rYBldbK5RznuhTJMbh4jcK1So2CcMXtR46zggmzPcSeSUFzFYOx3ysCrUeZrzwLEmlnQ+kTOzW5A
-a32kZuPvHrvdxKzI3qF6gPU5O32agRAHAgMySHhYcOqLExJH2qNKTSGH8/RKlH5sfBOVfeL5ZhvE
-gCeAYDr6MkXWCxMmzW4OQ5JRI4ZNm6zOWGmCn4CHc0ZdJemEZHYxDk19tkdDY1GfkowC7WkIjO1E
-6Hd06qgYEXoboTz4TsR5WJDZIWPoX5tFynYlxlENvAWWKX1pifKV5E22iBaRMQt7DWjq6lxEXEaT
-E+EmoN7Qysjkd/lvZzpFJ8bV19nKEAD55c7kb61G9e5icHYX6swM4h3uj88Wdrq0Hssb7e/Qgo3O
-ThyvXDdittFSXJJAl81G3ZILS2InyfncBi2h30mr2ODb2qREXUjunBo+F30U0b6Mx9gjpKEuTuw0
-JoAMcdxtJao2VBtpeFHITiwd/uRXkV2yeD+xLROMa6YixWxXFjNBBA4zB5eUK15EFiWYusVzWEfz
-VU3BGCOsQc160LTRuPPympECaM72YZBRR+64JKXEAK4AVDXp854iMHTkyjlzdOrOcEbZkwTcrJAN
-VSRDI/IG5Cb7OsFHqPCzRn0MQvPQc1niRlYWNEBkMNl7l6lYNxPCmToJLthDIo020ynSsFG75vEv
-a7Gkg+YIvGvTMtXeMwXcsvYMOdJ2z1g0SwKOW+57BgNAhrxYSddSwd/bPSNrDY6WV+e9oL5SeU9z
-IvM8RZb17DxO3Ad1dUzTSP2F7bdESm5kelL8qHRGplEzRQbIAlzsRCTIibXidAXCs3hGwF8UsdYx
-IHSNNH/bQti7JOd4RCZgaxTmmGxlA4baQljwHAKjlByxhzZFJF+jcM4fmFQi3mwcuyHBF6P1zfhy
-UvLaJLuBtYkbKLYqxWXZHIQ1lCpOdswwaZiY+oSP4tsoepYQJUCWyYDdqcGFY+2B3rL2Sw3frmxD
-P4FGdtdGa5Hc4PBxDbPRsWL8IhVUIMl/5DlSg3B0wieeN+Ma8St3sdgiRspJV4jQSbw6+noGvlIx
-+drqV2mBWgfUneEgDUcvFo44nvlkXcyqP+9ueWcUSC6B+TYIV2+Fo9vRA7vlIbApSNAZIM6q9Vdx
-jeirsiqSXX3UAMHVNwOa2XxbBY8YGKfUwmXoXFRQ9esYzzdTlVGMabQGgo+YyjGaFcpQ8O6TOQtZ
-k1N3ItgZL81h7AU5mEcxBHvYCtOPw2AOD+aEr5KlIN2IpZBECI9Ctzon8lwOuPWoMIHLb3VuW1fF
-q9nPFji33soz4HHgGVb2LOJoJjemJaC7muXa1XRAcnWTew19lTUawSEC/cNrw+eO3lHorGLtV6xH
-iAl0tMgEiWku33Bu4uipW3aE3ncumxtZQmYmkj0Be1ucAppIx0ZKk+lByDZi6iTtEkLGqHG0Zg2y
-ZQQxVk7M+LrxW5bcHbNG1ADWXdYIj62YAwRXJmNyPc2ukNNCCGPlSq5nrFwy5jo5gxnCsY6RQ/7S
-ai+Hw8sYNvakWu7hBJwjpm4TtrgGVfNiBVclvb/jbSJNdZ2OipexABiHmg7CzyPJ1MTHQF8BGEOP
-8e4TF9SO9AjH0QoGF049YL32u9udEWiPQOhRJCmdlMmJOGkj361FEppfhkB9qHgtjELgFDPoJepj
-BPIEOEP1iAZKDAFKxRBGZGPsyEFNm+Ylno6DECxYDhgBpV+AEaBQSV9PsAhNDBoObl8SJtGPnUvZ
-NstAekVhIUfSkUskcpLMSxyHUviOystMtZIz2dmf2aiGK9uHi3URUScpHoR+7PZtRKRt+gaYs1rB
-JO1h2gA3Tnopq0teHzg/YWXJdrfoYQnI0l4du9TU/aFDDQhMp7GG6gygbsQ+BFVtDis2FOsDgxED
-LCjltrumUN7IQNRe0YgFfzAjxGXaFmFPgaKB/JEAmqAU6ZU9+RPdpXla7OKHTqee32wzBrV7A4sw
-NSDbmZqUcuSEacMfsA4pTIZKCnVE/inMrKDKT5ONyxk0yoyzCcwgsQ/yrcQpRcsb8GC6Am/MbieC
-6pQyOOIKikoLYfzCjGKDOkaEhImZSE4pzQBFBtiPDbkl02yJWI1sAKms7Wgdo2FgHQMhc84ZOSg8
-pyUPCgD4QQcPKKRE8ICEh3/sz5mK35eSSj0HsRHwIxmTeDpvYscEVSKW0qkoVVNR6i+CATpbtER0
-IUDai4OXRw+ITSgqrDkzbcnBQqnAhk1VDVvO6NlAUCYnSFsRK5UE18UjIjAMqBaEG2q+YcWkbMzd
-Is89akJ1AbYOmI+e9I3JEgFmQiNYCwmbHOCxtQfxKwJqB0K6yZFhEYMzC5mnDtMmbBxQ2CiM7Bsk
-HCiFck3Y5GQsjPEGxpRRrgfPSqVGyuJ48gTHd04jMTFgquybfoMaiCvRvCsklNkuFkeJK2CeGdZh
-ZPeEdxvfopSpMRktMzlzouVUW+gFUUpByhoBz6M7SheyO4pwHaN6ire43TzbrSXjFLfOUqYWGaYE
-DuFS0J9HrFFDgnTMyOuxa596NT1Q6NA4YUCH/mBj5DazvlKy0KgOROmpf0iEHb+7IR8GH7NNRGDB
-XjQjJHRrFOC1xcgYo08rUKvElK8RXaUOhx0TaKBmdsl+sGpLEn5JFiheV9wHi30U1Kfv+5akEAKt
-VG3IaCHgS2AfemCiaQZuNAKPJNm5HAQ4QYOzChUzkoEbgUySJuA0FGcvMbsoTNsikxbktcSKNtAE
-XBhrSWDD5E7tthFCXoAAuqIEaa0VbjN2QZEnV1ai4EUiAu98QJuoI9lzQTOeOupwp1Bx+2aa0Oxn
-J0kv1ojyGCV0ZhAHXkBinzBKJ2BMAWQJfYQItRhyJX2EjY2Pm4IvvEcKPaK6RhCoH02NISN4bPAD
-VTYEX9YyzijoYej6y8SXKuUORtwvWKApclC0vsBaqAzXkRcLwaIsTZV0JJxrzmUBPw==
- ]]>
- <![CDATA[
- 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
- ]]>
- <![CDATA[
- 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
- ]]>
- <![CDATA[
- CMJioL2jDAOIDcpoodrBhOuK7lhrxMZS2Qo7WC0/Zd8fC7IX/QPdiSeAy8v18EE82yMNu5roe6KD
-j77nwpQTGBChqWXipiAkCi1ghAtA3oRyb8pEQPUQVp0rigyDKLit4Di1WsWwrUSQ8dEsDwIybY/1
-xtazqsMXaR0tUcEfUEj72+0G2oMDJKhV0FB4HLotUIJlVxGGKiQCSgBRb+SUotV1eegScEGLq+mo
-gOPtwpyDA6Myu5dQE0hH3ijpsLSrF9okjkTmeOwSmYOGVKcTGNp4aYN8kfFUjg0sqPVXvaugoZ+J
-OYn0IVmjqEv2oAkfQo5DK2i2nxoatsuiQ0+meEjPzJbGqyDNvdKIDcYZNdOE8TRQUAO6VSj7mvQC
-dHrqPUTaPUSe3BJvnl87NIVC+wSSH2p89eu1tSsVjtlwueYweGWDx8Z63YdnGR9aQ1UWibKkSoNV
-tbdz1UswY/U6Y0b64QPk5z2JJSmbfoluHo5CAwFket8350OJ6tWBK3Yh2voO8fN3cm6WCufeNHPR
-chIWH+43phVfNsyeq0CXrRNGIJqeyyTnfBW2c4Tw8PPxAKj37YZVRHKlI5FRkneH0dS0e6somiII
-NX5YuW3MFPcUGjon+8OUJpQRHDyDGXxd3uplP0OHBszgKL6VUVW8MbRSEVhnougCpNCVv7jXIUd8
-aHGjemaEriyaI1SNoOD3Cob4bTXLkK4bo/Z+8+alGubqj3ZFyLGCVwjoJDeLVtWrCB576QIpVHW+
-gHV0t7pHLiQNc5AQjlqKw3eQ6NuzRBofnC1Vt5UNYwsChPvmBZ7QjEcPTaHGof7ZGt+IXfzbnQdr
-xP1tPzXaZUpCoKE4zAwo3k49UxcAE0Y4vaAa49XLCBCcjJiPnnbXR5pab7/iWGzyCUN6iIG0ka6T
-PZCE4ENVnsbEWinqrbgb7nkE4qm50T7fmgaSaXQHKfY/AJJGFKFJfCVwX9fkMPp/58nze2nAP1cQ
-BL8s2mEEyEgpsDjvO6B/zJsaBTFWumqZc7ReWNCAv5j/Z0Ak8fcnHtwgv0jwPq+HNj7+HnGkpMmM
-RnS9NXR1IDgMqeOr1AQ0gWhm0K96Yi4cs8Yd805M1um7CbRtMcBEaXvgc/qBGSBvv550J4mgjbNf
-gVsebvjCc8rDZeGDmh9V6HuILQAlQqRwVuS4OAi0KqHu9e8CWC9vwQUjtjT7RktnT2wzh2R4a1TC
-WyT+zi3dKOxJh/dskXyNM9yjxKrMijM2rCiIs3GQ3HclnrcmyJf3utN6FbFEA2Necr8k2XiHn7nA
-Sb/emxzgYBWmbNgugPtXXC6jhozc3AzmoCh0jy5rm1fEkAPmXL60u4AE7hdgo89SgPREk3qTYtbL
-hURhMKvZnIYKpYUlCn8OhEyCviv5gvNZb1fnVCXU9JerzBNAI3CUKeeiqDoTFZ7jOkx01TwQYyXo
-d6tuN+ifKz1QqrhdTViCMizSp74apvL0xBB5lbVGzjWF+D43LCzqqnoBMSIdE8Wv6rZunwhnu0dD
-6R3p/I7gQMpUJ/a1fjWlGz1356E+3lZG9GCJUQ4ajhjffEY/aEuWh7Bd1IqNDPJKS1FqMmIeFVlJ
-Alx2D5vcoGiuFKRO7+/W8/KcUc1RarCe3aGSaphFPZw0C7Pn1xEwDYlQtdWTKBXOGfzb7FMyaAcF
-vvGBGuZvXXMwfmDEbSMabOPW6wwCcoCbFLy4XUrePBAId5kYO9oijHoQ9eTpi8Dq6wHIGlLZUCGs
-45LnG4QGwBtsYsq2PrvkhZWIxZePqgSGY31foAF3lUrxmaWyGEr9rdmdnVRTiomslVqw3YZGSBoA
-1+8TmeDk6qJha+TPAOK09yt4u8mSx6P3NDKqoKRjl6kIQim4SCEGqxdzuYr5iIOj1F3tmT4iUQbg
-Qe4kAR5owttGoVSGtckZRSQyrnDxsgUS1AZOtjtTObcYtJFVNkEE6j5yR8++srUUymb7uYCmbxXv
-dM4c0CiswLPi9dE1558s3iknJIcQ6QFpznuFhS1t4G9dNQa6o0C8MBnFxfFAn1cu3fni6YiuVSmQ
-TtYZ5YvFRodliDgT6xl6+qIffasgdIGqzZ+msCuYHlrfA42eWu1BnldWVGV8KJzTkOGY7+zTIzzk
-FHgaWrvTESrgn6ys/wA+QBA2G3MIC1ddnldBQWpwlC8rUhBAXoXvyPYLZL9HDfphN/rRJ44j+enO
-vH/8jrR4sGRiAZWTckCrQ8vDHeUcQVUOaSEyZkQk6sBva0nTTenfX/mO536H25/w1J8LMA+t1Y0n
-62ZCjWDdwP6y8/MQPfWTg7ATvJCqKPPo5dOseYE2Z7bAKkzUg+sZ1aHPPbK+X6d/QBJ7HVXJCwZg
-NuUAPDUq5V+ZaBxGKAVyGAGCccQELFGBCV9IUkSCz7lYvm7yM26vqmrrhbT9K1k7DoK8FKjexZUG
-yohpdyXveS+paJ/HRGiio/okhHuQjgz7F2YmHySEp6R2ngPNOlNHDMRhiXKB7LvFrO4+8Z78HNUh
-eJo8z92D/0AoS1jVa+cdDPEKxDIxOIrvJ+riStFaKhYt4qItcrJ6HP3eH7TMjlm4USJoGTyyqzjz
-quUV+Q/nWY3HNfJFWtawFLOC6STT6uyRXIaviA6nBFi/hqQ/yHq59CMlr6oVq3+4m4LgJBqeIVhP
-vBeuVoFA2MwFMzVjXV6UhiYxPu9NHRPwVSs+poxQj8Ni261egiFADgS5ja2n0o75PNAqGGR0mN+i
-KXmPI686s/RLFYBT38N+flGg4yFWhpR/u63okYogFXU9jKhlziKSJVkbXdMW7C6mUuyDGCH4wctz
-pm+h0RX7V45bxP4uCg4RODqRvGrN06mM5HuWFvT+ThAsBUC0GS3keoKgYbVHmNqawsgqzhWOSMmA
-4+DiNpuy39CG8XEceXPJtHUI981tjRrrb2+ySwiut+YDAuy5UE5ZEMAg+v0rpn5FoHUlhY2jwdn5
-2r4TRZ0WEtI4hFhRGPi9Xee6pvS+DBBwZTVK1sNexTkvTpghGpAFjBwDtgbUcsr45oF+DRVQmXIb
-lngw/aTE0wRcPKriMaLCjlcJe2TEQgK7Ib8rc55W4EqZqKCUEjDXfWH1ZNYwA86e1yZYaSTBuTQG
-KdBEGTGRljtT7tWdBa4VgfEJCoSOcyWRvCgCeo8lkykXIIBlKwAD5Z9D6ELTm3hzTW/FpiRgC0iA
-lAOV+KH88qpCsNUyxBqBtpgj6FNmh6DALw5frWhFoTmiENPHx/kX0EwcsYFmou6SP+cdlJEyADJ9
-ViL6e2/+nFFoY3ybHeDtF/xyf9MwwfiUO6AVmnhlUAYfnAIpCElbGDCg1gfe6IiwcXicpzFSWCrN
-0tPJYTyE+m/iEqg41XQmc+pRtxcqeZMYxNnf/XuUw5n8yt3V+BZ7LCb1JqnMoUTASzgm64ARKg2e
-EQsEgNDhQpbFeT6jBc4j+mA6OGqfKZ/P0Fhh8zsT4BH4VWoQgmBxCQxQy36F48EKFENbAy+FYjHl
-bYjMAkOI3cn3KpFmEWlLRWnqcK7PChKz1O3F81L0wWNV7CWoVECoZ60C1/711/24fz2vk+Ah4e5U
-09w682sCiPblm740/tyTfOWcXJ9p0MX7gE/n3+uIS73+UGM+mrjzbrqx5Yhj9UIIinrkaGRHP+Dy
-vCMl8EuSYKtIHfH8kmaLkJQVPxpGvADerGFDbDtHxuAI4fchIctR2sbXxNHLmDJVQVs+xSNcsCge
-Pbaj7rKobBMeldQHwWzTKttRc3j1jjs5newAqHRdo+X5e1+KaJXgfynr7VQ0jcAcK2iwJ3VpgPTj
-joCJzIhtbv1XL+T/cDr/l+B0gmEmYP+DoXSI0L+l24IBiWbW2GVIEqeZVzxvYvcIzQWtewpNNbLe
-b/vMayi7DM81Se3nXANntmi3XwKF3465jP02QNsEmhZYVwqs9PXYCgF9AIY32MCvkFiDMwtvWR0/
-Fl17fs9AQaphvBohcd2sgMYAcrpfRxS+2Q21esAJcEr6+YVe8i7tjx8QHaDohST/Hz7UE2emGC78
-GufWSUMUWIiV9isEOahZ+XzOu5kxLuSX48A7bpn0SS0ulV97wvwTXAP9cOJWeL8j+DsJDQOR87gd
-8+LnNEjS3pRvOoeJNGwSagIbiSfU6oClXv2Y7zb2m6YfBATE8rlxu8xsAGMZRWw8SCCdPM++H+z7
-wbW44SHbJvfDLjmLBhyvBlWp0NBk0p/Dg9Sc0/qlVr6SlWA9TwbZpXW8iX7MviXSue0hHEN5rJkL
-Dfr0zABkGnjTVGFVjilsuqDNOqLW5RdtLLsr+Bto/9PBtL950zKPptoEZH/DXLIq3f1SXej4yvyy
-viyJE/2jKYnz+cDfEOFZABAjFfOB38PPUnlCiF0Jw6tj93aSOUQkQMUDm4v72JkO/Ro42Hym2Qym
-jn4ImDrUY1WtUEW4RXr3fFCBqCt5QfkA+OtSAD8UVr/Oxl+zeyeHgr7cFMAK9sF/97DDTRcLEu0s
-ul9GFZwve96rHYdZy77C3GbU0Teskh0hur4gbjB2Lkjc2E6EDtmi/lKo/KEOuNjPWOWsat5kpxDA
-kUnBowyby9ta//tGtA3XGGDaWNyK90eRl6wIY7WBEo1SBFczCuOgJUWtpKLC9kjyygHpUfx1Zmw7
-l8wG6tyWN4SCC02Es1f9q9XDVNM0FNVgyhybzuUITINKY8UFJO8RAiGYg6g8WoCnudQwcTDRrToJ
-VwUi9dySHNADO7FwXSn93Foe9S9rTZzeQyLZlrhMrdB6O3CO824w38t1ry/xuW5pF1/+Wnot/igd
-kWxcnIn8os+uamW54oRIxS63XeVv3F3l6EEqyC3ybnqJMJvd+Yb+LJEXmmVOh0InJn5+6D07C064
-T1f0fPgsC2PP1TUmaaKYUkZ4AziNqd7MANXZd/Tucey1aLHQ8XodAHeGAbSqsveDtgZLT22soTKH
-RAk9ewiUes4wlwhlly6IxU4W9g90sgiQ/2wElR+FWc6+eEt9GVXvqJ7Okc7rTWxuywOBlLkswK3o
-HpENlh3kbAy5988Hfi+7UiV15WXM3/9Ia3Tyt31L314PzSao0OQffxjh70Y7D0u5G3JmVM0ode+8
-f3pV3L8GxTVl4ClexkcYkXqSD04KjOMe/YlTbONVaLncsdgraQEwCkFSavp2zJkOsUt8hls6uTTs
-k2gaZU4oLwq9w5QNI2SdKmVjZUppvoo3Jvq/Xgis0NQ2mnN12rTRVO2snepZpIXzXLEP3tH/LUtl
-Le2Co/HQx33yYJOVUaVnTL/2gadbEzQ1/HsoeqgFhqgl7/yhy1njHwwHDZddti5GUGvy0ZMI+2oo
-qstT36nBYFYNMYcYS7Y3HmURSdzkMfafqdtYb1B3HpdOdDoJ38YlVwMlgT0J4GSB5mORYkOGxuLQ
-NBrpoiaUhKM+vw/ZcO6AJoIjqIYp7D1aFJVFsPGsypWeKLFaFDdB466MlAln/FfQAQ==
- ]]>
- <![CDATA[
- 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
- ]]>
- <![CDATA[
- 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
- ]]>
- <![CDATA[
- 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
- ]]>
- <![CDATA[
- 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
- ]]>
- <![CDATA[
- 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
- ]]>
- <![CDATA[
- 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
- ]]>
- <![CDATA[
- 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
- ]]>
- <![CDATA[
- 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
- ]]>
- <![CDATA[
- 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
- ]]>
- <![CDATA[
- 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
-OHhWgu0m4WXzxsIxgspBsTiymKSzEnMKXiEu/LVgGwWp888aofCEHYg7u5r4EyXqXMUEiKDzOnjt
-INjVcWcpAiJXo8n0gs3bwoVI1k/XUTFfQxQEOMilsXGLNewrqACvemsV6hBEaCbnAQOIrom2As9n
-cXbNCKpTJrBKTwA1l+sDOdCPB1nvqqidda0gXFsn3LIvOnmPuW/BT4rRnzznAPoCEewovIFrSbtR
-riwPSYj9HRDMUVuFnrHuyCTGK6IQSThsQjjSBCLywHdFw4vy/gsmLoqQ67bY3HujmR+EEC1qcQUv
-AtziNUzu4oFYniNEi7bbBxgAkl6uOSgXhRbZVRb4Ii3RloPqv3UgOKO4Nox8LqLLIaM0LPVuUmbR
-UYMqi0F1hnImAHalNN7RrwgDLL4beDndABfptCyVrFR2u0XjqYRChgwCI66rrLR1DRFR7b2+XkR4
-pBMCooAdH3vCfYROmhFg1AE6O3qEsSMZqcK7xl3nSvsInQub0VRpwE3KNelCCPmCkw3yahIzq3p5
-UxPK4BNg28EEB8PunXNyn+vg3oCh761m9uZffHX05ujg4ujlN/aIW2prb3mDtPjtn04v1m/HA8/O
-dcuLY5p+87ef3xz5XW9tzT8H354c+Wu/ODv85n8f/ey/yc3it18dHZzc8KvfHb/+5suj88Oj04u1
-9rc948vzox+Pj36yR5y8ndj0q7Of3t46bmsvYW99fPR29Q6kOEOaBukssd9be/C3Y+vzfx6/vPi+
-PoakKtX7BIzE8v4f/s+j4+++v7jrBV8cvbr4xlbEH87PTu9s/LezN1faXlkJv3/2q8//1H7z+9OX
-9Zd8znz+5i9np1/aUr6w1by355efH31nd1v74tlf3vBN7988P3/39vvxPr/+y9FPi/phMTS/edYs
-Prf//8dPz5TT8e5ZWHz+5pkKsvW///jZPvwv++P/2aWfFmnx58X/+b/N4iW/+erZHkHUhf7zevkB
-TlFg315whQ9U9dx62X7yYv0+L56d8iq8w1fPAIyE5ybZQU38j2JhcuNJMU7CEiJfhOATuXMgEqlw
-fF+kVLFLKo3LtGnXUdjNWFUy4HriyaLZr5XnNfmkXfzj85t74F1VGXu+1LGvr7QfPIHuavt6ubZf
-fRG7fRksry/fZrx87f5QoZLAeOX+4+Vr9xcVeLx2//Ey7f/u68YW2qVVM2kxhSmLKbx3MVGhTIKv
-3hqU5uW71suEIAlXv6g9y7dcG3/+4ua7bt8iS/vYlGu9UcejaLKHq51sVXqd1i57z+GL9AVQTK1Z
-rIajVdotJvWlIcprawrORm4oc7+/9vh6WY9Hh8R0W13mnVilmXeK2bNQL10ETjwJDO3S5dWEXHkP
-yrMp3r3yHuNlfw98nsN6a+5NWcdAVi96C7Rgly5efo/l5dvfA+V+3DNr71Ev+3tk9P31yz5I2uX6
-C6qdyxcvvcfq8pX3iCsxub4fVpfH27y4chmGyKBlEWXjp/oeQWO01g+/9sWVTvvVDxAIfz89PXh9
-9HKhq4iGRXtdKtx6uoTm/ccLZmJRxSm7ae3wuPbFeAEkiH7tgLnt+urg8Re0f/5rO4SDCUkt1Z4s
-c4AYMinYywuZIGpX9wll430IHTytpbveqK6q6/fKAiZzWNR0270uNxp3ytVm7DpKMZ1+8vWNz7vc
-5ta38sLpDpLe2N32Vpcb3fpWUEoVnghq0G2vdbkR92JFvm+BkaVUzF5/fXWFjV+c3Lxum0vzcnOj
-a3f6/tl/2hr9/56NWuIWLlMBF1AjAstF/55leqlRnS6KvUlmGCdR9QfFmhEmvu1eVw==
- ]]>
- <![CDATA[
- G918LzG+d6p794PnSrPXNza6efsgPZXViIkfbnmva41uea9euFZMCA6mW97raqMb3mtcqHVlrRb1
-UjW/+sVlUbi+BLvgqa/68cltd72+Hv++9tdtp8bGRkxo/Kuv/+OPfzg+sds8++3yTzOOf/uPP7/4
-y9nLI/68ZDXf+sVni1//6/XJqX21Z691fvztu4sj2Z9meJ8fXGlx+P3xycvzI/kJYjVkx+/4z0W1
-un9t++dXv1n89u+nx4d2efQ2rDf98eDknbf9yU3R9zXmFKWtvcpPo+G6xT36vtrIE7v0/dKkfuA+
-Te/Rz5M78/NW9+Nfk/vxr0fox9m3/+/o8OL52bvTl/Zqz8/ueNtVt15p/1vTi7eTO3jpNw/e1c//
-9M3nJ2++P/gmTO3j8cs1v+UtfaLN/5jwxtsiJi/enX/77uTo9PBo6ij4TydO8ficB+7V6dnXF8cX
-h3fI9FWf3qo13sXpq/fSbx5e4Ow3eWrvvj14e/SH86P/emfTPF2MXvnVg/cwTu3e6bvXfz28OPhx
-g7lb/8mDd4wtN7Vv50dv351MP8fH5lMk0C2vHt7z6jdLv7VD4OhvE8XJ6p3fM/wPPC9fn707Pzz6
-4/nBm++PDyefCaeTJ+f4dMsX2/HpHXvuUmfiI/TmrtFe9eXszdH5wcXZ+eQOrX7waJvni7PXb87e
-Hl9ssHc+xntIK5v6Cr/93dGrxWezCbh9PZpNwG3tx2wCbpsJmD5lE/DV+YHpwid/OTt+OxuBO2YE
-TvZd7KYNOHlfzjbgbAPONuBsA57NNuBsA66vlpCenA24QY92xQbci0/FCtykJ9ttB5px9Pzox6OT
-r78/eHn206cdJXO1QLbiU1EKvj15d4eAvwcNdFvNhbcXL3939ONxrTiZbOut/+jRNIQ/Hrx7+/b4
-4PT5nRO4jQr25Cl6OV3Ov9xq0/TldDH/8jHk/CaCYNuF2tmrV2+PLu7eGbtrXP9VPdy9fX+CZkl2
-4eHZydn5v//0/Z0mzrq0/vlkurextp730S/oy+TUkrfvzl8dHB59fXiwyQxd+tGDd+7tm6PDv767
-Yw/tnvIzWUGn/+9ODs6/ODt9e3FwOr1r13/4CAHQTXv5+3+9OTs9+oBern64S5bKXgDk+4nY0nmD
-rmy3Mb0XN5mW/57cl/9+RFXky7Pj04sXmziYPo6v8ujrumNfVB1j97SjDY+kbVcfPshdMscdzp+w
-MrQ74ZRtkQmT9bkf2snzQdPtVUx/mC4CfngMCTD5/P7hDufQekfSo8nnJxbl3vgM3fYD5+D8+OL7
-10cX06dolw6ek+OLLw+O77LLds8Mny4k7pCL60IiPJEjdHfs6M09yRvLx0eazz8fnX93xEjunkq0
-qcx4wlPy8d5jTjy6H603zIlHO5B4tEGftt1ZOrkj2+0q/bTqT744Ozt5fn509N+To6FPMb8q7E+u
-9j4/eHn8bvoEj813wwe63Rb29I68nN6Rl4/QkZfHJwfT0w92yaqePEW75sj989n5m+/PTs6+m3wK
-b4/Z8gSl25ORadMLY2aZ9kgy7ckWyu2yTNt7Mom8G5TGbbko26xEY4tl2fSe7NqW39X03RkjoAYZ
-dxAjYLLyuZsYAZNzlXcNI2ADeb7tJ9PkJbj1J9N0S27HTqZdRm24IwFqTXxvVqfwSAUKn+TG3/p0
-nG8nr7KtF2KTe7IrSTdfTQ59ffH9wenp0cnXRydHh5v4P67/8OGjRZMDlR/ayes/fLTj6HfHb9+c
-HBwevT46vfjzwZvdO5NeH9itJscud8FW2kAAbvmx1CzG/11c+zNc+nNqj/XXdLtibP7wc7gZ0uE2
-H2KTe7JrmvgXVEj/eYL42Eaxt8EC23Ih8e1kx8LWb5XJPdkVfW96rfPDAL1sy+57tVEm0avjk5NN
-MqVOHmGmT45Pjw4m52CbwX7457PpebRrP9hev+XF2XTN8GybN+Or87PX09ebGj9CQOB08v45gLj8
-3d1h97Verf/k4dXeOxTUtUgABG/TIwDe+sH7c34kE3HydL18eXxx/OMGk7X8wcMLh8lT9XI6Cpi3
-ffjCvMln8NpcjY//i95+6oRd/tXDZ0Wd/HTw8+SZM+3p4uB8I23L2z+SZXJwevx6A1n3kWpUdhv+
-bq+f02a2zM47fDJpM9N7smsukTlt5jaFf06b+VhpM0+dX3E6lNquJc5sING3/Wx6Mokz03uya2fT
-LifOTNZGdyNx5pPc+FufOHP4ZBJnpvdkVwIpc+LMnDizZWfS00uc2UAAbvmxdEe2zBNOnDl8Mokz
-03uya5r4TifObLDAtlxIHD6ZxJnpPdkVfW/bEmd2IUS0O+k/G+y8TWXII03lDoMVbpA/OE/G7uKV
-7M5cfLz3eNx3eDKQkZ//6ZvfCcXlm808ZpNUp905xaY72XYELOlJwq0/IN7QY4nYD4DnmeXbJPnW
-fcrybXLnZ/k2y7dZvu2UfPv9uV2Y1bdZvG27eDtioc7SbZZum0u3WXmbpdss3Wbp9tSk23rY6JvN
-wv1PTMhN7vynFyWcN9EGm6h8yptocufnTTRvorV18wnxH+VmkSdnCvqrfrVBsuDaLx4+5/hP33x5
-/K+jky9PDn7+ZrMK0ycmB8+PXp/dBbqwW5g0b9+ASjO1R7uESXN8+vLo1fHpnWSv64lvb44OLn63
-AQjF2i8eoW51RneZ0V0Wj43uEqbP1fbDu0w8l2dslzsSgkdsl4dei4vwWWwWIdt/m4X9/2f2t/37
-mX2x+OhVHI9itmwMZLMtqtQT5JT8dhOG9S0vF9ikL7tSMDB7MbZeKmy0hbZcHHxgNGrbS+DvGvZ7
-CkY9dLnJ2es3Z2/NWPzruzsk2S7XFNY+7p5cmOx1+uGOlJ21+aDp9hat/TBdDvzwGGJgsq/zhzsi
-cOsdSTuy83fj6NlQud72g+fg/Pji+9dHF9MP0109gD4+9uHWCos7ur4uLMITOUp3J/zxQWt0rkL8
-gPeY489z/Hmzrn4q8efNUCTn+POWx5+fLifKHH+e489XOzXHn+/foTLHn+f485bEn6WDEYGOzWcb
-6WNzzHl73WLb7embY87b7fmaY85bLxU29LZ+vRF8/KXfbPWO2nZJNxmC7u2781em7G42T5d/9OCd
-+/no5OTsp6k9PDn+7vsL+37vEJTYyX28+rPtDX6+PH716t3boy/OTk2VO50u5q/97sG7WN/gqRzJ
-G3bnI2ZEbMtpMbvgZhfc7IKbXXCzC251rD8lht9NdKvZD7edfjjXpj/77vzo6PQzs4GOPrOT4Pi7
-s89+PD47Obr47Pzo5Wdn5wend8XZZwfdQyMSTfaYHp3Yh418JWu/eHgJ2U/u2MF/H79+d3EHG+m6
-DBnbP5r353fHMrZeIDgfOXfmd26uvKgyfPc2wFNy2IQn7bGxM+Spu2vevjk6NPX//CFKIh48ajx5
-bdZB2NgXdf2H27wD68v+/l9vzKb8gF6ufjg7c2ZnzuzMmZ05Z7MzZ3bmzM6c2Znzy+U+rht35lTP
-jnw6szNnu23Z2ZnzS5w5jyEpP1rUevZMfV3tpN11TX2AN2DbPVRPskz6aeJzPKQv6pGk1Q7Dc0yv
-795yeI7pHZnhObYaRWm7D55NswS3/tB52tgcJ8cXXx4c3+UV38EoyGQh8QnCcmztXGz5ETojXG3b
-Ebqp+Nr20/ODLNH5BN2GE3RGtvqUjtDdSQTYeH3OqFYf8B6P+w4zqtXuoVp9/qdvvv7+4OXZT582
-79AnDlywK8rAZGyyudj/sXbSZDrQl5PZaNX0wdfa9I7ccTysd+RfWy4Itl2onb169fbogp1xfvRy
-I3G9a8Gqv6qnn5SN8OGT+4SNhW2ZnIcJE+3OvMxG3JYbcSE1v5q6Tn86frlBEllt/fCO/3Z6j74/
-2iQna9n8wfu0F/LkPk1XGB9DX9ykJ9M1xsdQGD9J98cnDXs9uz92wv3Rze6PbVeT+6fi/pjekdn9
-sQMW8uz+2PpDeHZ/bLFcn90fs/tjp9wfn5gRd3GwQWLXUzThXp0fHF4cnPzl7Hh62rv/eOIcj096
-cNSGry+OLw7v8M6tmz60/tvxyQYFyJd+8/AZbvuTUWS+PXh79Ifzo/96d3R6ON1+uPKrh/dbTs7h
-O333+q+2in/cYO7Wf/LgPTv8eOlsD92TzfxfE3vyGIja03syg2lfP/pn/KUZf+mjnXOTuVouzqar
-JWfbfWS/Oj97PX1PqfEj6FhPFxnrCSNJPSUgqQ002xlH6g4tZcSRehRv0sZoSh/Fk/S3d+ffvjux
-tbSDrsYNVPEtNypm+JcPrx98JFfwB1SnzW7Y9/o+nlwW2gY92pUstOk92u4ctOn9mDPQtid4sVJW
-vrkDeuJphzAuJiptcwBj2wIYzROPYExOhtq1AAZbbgvc5bMN+AvmZbYCZyvwnrfObAXOVuBsBc5W
-4GwFPooVOFmbfopW4JzItrt24GTMjN00Ayd3bzYDZzNwNgNnM3A2A2czcN1oyk/ODNygR7tiBu6F
-p2IIbtKT2RTcHlPwP8/OXn53fjD9cHmKduCT5CXZqBh9ywstniLCxmQLb0bYmAFGH6wjM8LGA4Mw
-PBURPeOFbLs0e3Viup6zZ//7tycHhz98tvBLZ28ODo8vfv73DZyqby9+PpnuBq+tH74+cxOm8G3f
-YBt1Ztf21B9YiLu3pTZbYDtxHn0YKNC2O0/fCnnxi6ckD54mN/Cno0Z8CvyGPshfHx5soCxc+s1s
-YPySot3J2ty781cHh0ebzdPlHz145376fgP0ghP8+/b93oQDe62LV3/28DGPyXa7kxB/cXb69uLg
-LnbIdSP+6u8evIub0idv+am8YXc+AVyYbjIk09GJfdjIy7n2i4ffm+1k+Xrw38ev320QYl22f/BO
-SeJ9PHymR1K1fncs6fZik6DwR0IL+J3Lhxf1ZNk93W9WkGYFaXsUpA+gj96V+OBk3W8cg42Vv+s/
-fITajk17+ft/vTk7PfqAXq5+OGtPs/b08bSnWXn6aMrT13Ur76729AHn1bYrUXOy9c441x9SW5q9
-6pvOzuST/oc7oFvW5oOmD1+cNbkj08XAD48hBaZ35I7EifWOpEeT0U8swXVTz/HWHzoH58cX378+
-2oBdYpcOn5Pjiy8Pju8y3J6wnf7DHS3XhUSYj9CPOxdbfoRO78h8hG6n+Nr20/ODLNH5BJ1P0MeU
-EZ/gCbo7ruqZVHKLNaOPfnztzpR8vPfYvWUxIyBVbWjnEJCePBDu06Xy+6CIyXZbE1ORj3Y3sLDL
-2E6vD+xWk3EsdkG+b77etn0HhUVT//emv5ZXpnZXf02Xh2PzB+/2H+2nb+9Oq9tduaGasz9P2IDb
-KDie4En1oKVl2wrzMEOKPNaO2pustW87psjekwEVeRCX1QP36a+fTB3trsJxbKz5PN0lt/2BpaeZ
-D0icgvn62xPGZN7hbIYPmZ5tFxLrfZpcZ7gr+neYztU+a+DzuXuPW+ofr47O/3B8vg==
- ]]>
- <![CDATA[
- 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
- ]]>
- <![CDATA[
- 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
- ]]>
- <![CDATA[
- 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
- ]]>
- <![CDATA[
- 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
- ]]>
- <![CDATA[
- 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
- ]]>
- <![CDATA[
- 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
- ]]>
- <![CDATA[
- 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
- ]]>
- <![CDATA[
- 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
- ]]>
- <![CDATA[
- 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
- ]]>
- <![CDATA[
- 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
- ]]>
-</i:pgf>
-</svg>
diff --git a/install/ppa_release.sh b/install/ppa_release.sh
deleted file mode 100755
index cb1a4cdb..00000000
--- a/install/ppa_release.sh
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/bash
-
-# This script pushes updates to my Ubuntu PPA: https://launchpad.net/~micahflee/+archive/ppa
-# If you want to use it, you'll need your own ~/.dput.cf and ssh key.
-# More info: https://help.launchpad.net/Packaging/PPA/Uploading
-
-DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )"
-cd $DIR
-
-VERSION=`cat share/version.txt`
-
-rm -rf deb_dist >/dev/null 2>&1
-python3 setup.py --command-packages=stdeb.command sdist_dsc
-cd deb_dist/onionshare-$VERSION
-dpkg-buildpackage -S
-cd ..
-dput ppa:micahflee/ppa onionshare_$VERSION-1_source.changes
-cd ..
diff --git a/install/pyinstaller.spec b/install/pyinstaller.spec
deleted file mode 100644
index 7eeb5153..00000000
--- a/install/pyinstaller.spec
+++ /dev/null
@@ -1,67 +0,0 @@
-# -*- mode: python -*-
-
-import platform
-p = platform.system()
-
-version = open('share/version.txt').read().strip()
-
-a = Analysis(
- ['scripts/onionshare-pyinstaller'],
- pathex=['.'],
- binaries=None,
- datas=[
- ('../share/version.txt', 'share'),
- ('../share/wordlist.txt', 'share'),
- ('../share/torrc_template', 'share'),
- ('../share/torrc_template-obfs4', 'share'),
- ('../share/torrc_template-meek_lite_azure', 'share'),
- ('../share/images/*', 'share/images'),
- ('../share/locale/*', 'share/locale'),
- ('../share/static/*', 'share/static'),
- ('../share/templates/*', 'share/templates'),
- ('../share/static/css/*', 'share/static/css'),
- ('../share/static/img/*', 'share/static/img'),
- ('../share/static/js/*', 'share/static/js'),
- ('../install/licenses/*', 'licenses')
- ],
- hiddenimports=[],
- hookspath=[],
- runtime_hooks=[],
- win_no_prefer_redirects=False,
- win_private_assemblies=False,
- cipher=None)
-
-pyz = PYZ(
- a.pure, a.zipped_data,
- cipher=None)
-
-exe = EXE(
- pyz,
- a.scripts,
- exclude_binaries=True,
- name='onionshare-gui',
- debug=False,
- strip=False,
- upx=True,
- console=False)
-
-coll = COLLECT(
- exe,
- a.binaries,
- a.zipfiles,
- a.datas,
- strip=False,
- upx=True,
- name='onionshare')
-
-if p == 'Darwin':
- app = BUNDLE(
- coll,
- name='OnionShare.app',
- icon='onionshare.icns',
- bundle_identifier='com.micahflee.onionshare',
- info_plist={
- 'CFBundleShortVersionString': version,
- 'NSHighResolutionCapable': 'True'
- }
- )
diff --git a/install/scripts/onionshare-gui b/install/scripts/onionshare-gui
deleted file mode 100755
index f1d36a86..00000000
--- a/install/scripts/onionshare-gui
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-"""
-OnionShare | https://onionshare.org/
-
-Copyright (C) 2014-2020 Micah Lee, et al. <micah@micahflee.com>
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see <http://www.gnu.org/licenses/>.
-"""
-import onionshare_gui
-
-onionshare_gui.main()
diff --git a/install/scripts/onionshare-nautilus.py b/install/scripts/onionshare-nautilus.py
deleted file mode 100644
index 776ca5de..00000000
--- a/install/scripts/onionshare-nautilus.py
+++ /dev/null
@@ -1,105 +0,0 @@
-import os
-import sys
-import json
-import locale
-import subprocess
-try:
- import urllib.request
-except:
- import urllib
-import gi
-
-gi.require_version("Nautilus", "3.0")
-
-from gi.repository import Nautilus
-from gi.repository import GObject
-
-# Put me in /usr/share/nautilus-python/extensions/
-class OnionShareExtension(GObject.GObject, Nautilus.MenuProvider):
- def __init__(self):
- # Get the localized string for "Share via OnionShare" label
- self.label = None
- default_label = "Share via OnionShare"
-
- try:
- # Re-implement localization in python2
- default_locale = "en"
- locale_dir = os.path.join(sys.prefix, "share/onionshare/locale")
- if os.path.exists(locale_dir):
- # Load all translations
- strings = {}
- translations = {}
- for filename in os.listdir(locale_dir):
- abs_filename = os.path.join(locale_dir, filename)
- lang, ext = os.path.splitext(filename)
- if ext == ".json":
- with open(abs_filename) as f:
- translations[lang] = json.load(f)
-
- strings = translations[default_locale]
- lc, enc = locale.getdefaultlocale()
- if lc:
- lang = lc[:2]
- if lang in translations:
- # if a string doesn't exist, fallback to English
- for key in translations[default_locale]:
- if key in translations[lang]:
- strings[key] = translations[lang][key]
-
- self.label = strings["share_via_onionshare"]
-
- except:
- self.label = default_label
-
- if not self.label:
- self.label = default_label
-
- """
- # This more elegant solution will only work if nautilus is using python3, and onionshare is installed system-wide.
- # But nautilus is using python2, so this is commented out.
- try:
- import onionshare
- onionshare.strings.load_strings(onionshare.common)
- self.label = onionshare.strings._('share_via_onionshare')
- except:
- import sys
- print('python version: {}').format(sys.version)
- self.label = 'Share via OnionShare'
- """
-
- def url2path(self, url):
- file_uri = url.get_activation_uri()
- arg_uri = file_uri[7:]
- try:
- path = urllib.request.url2pathname(arg_uri)
- except:
- path = urllib.url2pathname(arg_uri)
- return path
-
- def exec_onionshare(self, filenames):
- # Would prefer this method but there is a conflict between GTK 2.0 vs GTK 3.0 components being loaded at once
- # (nautilus:3090): Gtk-ERROR **: GTK+ 2.x symbols detected. Using GTK+ 2.x and GTK+ 3 in the same process is not supported
- # sys.argv = ["", "--filenames"] + filenames
- # sys.exit(onionshare_gui.main())
- path = os.path.join(os.sep, "usr", "bin", "onionshare-gui")
- cmd = [path, "--filenames"] + filenames
- subprocess.Popen(cmd)
-
- def get_file_items(self, window, files):
- menuitem = Nautilus.MenuItem(
- name="OnionShare::Nautilus", label=self.label, tip="", icon=""
- )
- menu = Nautilus.Menu()
- menu.append_item(menuitem)
- menuitem.connect("activate", self.menu_activate_cb, files)
- return (menuitem,)
-
- def menu_activate_cb(self, menu, files):
- file_list = []
- for file in files:
- file_list.append(self.url2path(file))
- self.exec_onionshare(file_list)
-
- # Workaround https://bugzilla.gnome.org/show_bug.cgi?id=784278
- def get_background_items(self, window, file):
- return None
diff --git a/install/scripts/onionshare-pyinstaller b/install/scripts/onionshare-pyinstaller
deleted file mode 100644
index 8ca791aa..00000000
--- a/install/scripts/onionshare-pyinstaller
+++ /dev/null
@@ -1,47 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-"""
-OnionShare | https://onionshare.org/
-
-Copyright (C) 2014-2020 Micah Lee, et al. <micah@micahflee.com>
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see <http://www.gnu.org/licenses/>.
-"""
-import sys, os, platform
-
-# In macOS, allow both CLI and GUI depending on the filename of the binary
-# being executed
-if platform.system() == "Darwin":
- # If the binary being executed is called 'onionshare', use CLI
- basename = os.path.basename(sys.argv[0])
- if basename == "onionshare":
- import onionshare
-
- onionshare.main()
-
- # Otherwise, use GUI
- else:
- import onionshare_gui
-
- onionshare_gui.main()
-
-# Unfortunately this trick won't work in Windows because I want to set
-# console=False in the PyInstaller spec file, so there isn't a command prompt
-# open in the background every you run the GUI. Hopefully Windows can get
-# a built-in CLI when PyInstaller 3.3 comes out:
-# https://pyinstaller.readthedocs.io/en/stable/spec-files.html#multipackage-bundles
-else:
- import onionshare_gui
-
- onionshare_gui.main()
diff --git a/install/licenses/license-jquery.txt b/licenses/license-jquery.txt
index e3dbacb9..e3dbacb9 100644
--- a/install/licenses/license-jquery.txt
+++ b/licenses/license-jquery.txt
diff --git a/install/licenses/license-obfs4.txt b/licenses/license-obfs4.txt
index 6b89f8ca..6b89f8ca 100644
--- a/install/licenses/license-obfs4.txt
+++ b/licenses/license-obfs4.txt
diff --git a/install/licenses/license-onionshare.txt b/licenses/license-onionshare.txt
index 77d05583..77d05583 100644
--- a/install/licenses/license-onionshare.txt
+++ b/licenses/license-onionshare.txt
diff --git a/install/licenses/license-tor.txt b/licenses/license-tor.txt
index 3d0f8c12..3d0f8c12 100644
--- a/install/licenses/license-tor.txt
+++ b/licenses/license-tor.txt
diff --git a/install/licenses/readme.txt b/licenses/readme.txt
index 3dd5d2fe..3dd5d2fe 100644
--- a/install/licenses/readme.txt
+++ b/licenses/readme.txt
diff --git a/poetry.lock b/poetry.lock
deleted file mode 100644
index a9780ff4..00000000
--- a/poetry.lock
+++ /dev/null
@@ -1,956 +0,0 @@
-[[package]]
-category = "main"
-description = "Python graph (network) package"
-name = "altgraph"
-optional = false
-python-versions = "*"
-version = "0.17"
-
-[[package]]
-category = "dev"
-description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
-name = "appdirs"
-optional = false
-python-versions = "*"
-version = "1.4.4"
-
-[[package]]
-category = "dev"
-description = "Atomic file writes."
-name = "atomicwrites"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-version = "1.4.0"
-
-[[package]]
-category = "dev"
-description = "Classes Without Boilerplate"
-name = "attrs"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-version = "19.3.0"
-
-[package.extras]
-azure-pipelines = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "pytest-azurepipelines"]
-dev = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "sphinx", "pre-commit"]
-docs = ["sphinx", "zope.interface"]
-tests = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"]
-
-[[package]]
-category = "dev"
-description = "The uncompromising code formatter."
-name = "black"
-optional = false
-python-versions = ">=3.6"
-version = "19.10b0"
-
-[package.dependencies]
-appdirs = "*"
-attrs = ">=18.1.0"
-click = ">=6.5"
-pathspec = ">=0.6,<1"
-regex = "*"
-toml = ">=0.9.4"
-typed-ast = ">=1.4.0"
-
-[package.extras]
-d = ["aiohttp (>=3.3.2)", "aiohttp-cors"]
-
-[[package]]
-category = "main"
-description = "Python package for providing Mozilla's CA Bundle."
-name = "certifi"
-optional = false
-python-versions = "*"
-version = "2020.6.20"
-
-[[package]]
-category = "main"
-description = "Universal encoding detector for Python 2 and 3"
-name = "chardet"
-optional = false
-python-versions = "*"
-version = "3.0.4"
-
-[[package]]
-category = "main"
-description = "Composable command line interface toolkit"
-name = "click"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
-version = "7.1.2"
-
-[[package]]
-category = "main"
-description = "Cross-platform colored terminal text."
-marker = "platform_system == \"Windows\" or sys_platform == \"win32\""
-name = "colorama"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
-version = "0.4.3"
-
-[[package]]
-category = "main"
-description = "DNS toolkit"
-name = "dnspython"
-optional = false
-python-versions = ">=3.6"
-version = "2.0.0"
-
-[package.extras]
-curio = ["curio (>=1.2)", "sniffio (>=1.1)"]
-dnssec = ["cryptography (>=2.6)"]
-doh = ["requests", "requests-toolbelt"]
-idna = ["idna (>=2.1)"]
-trio = ["trio (>=0.14.0)", "sniffio (>=1.1)"]
-
-[[package]]
-category = "main"
-description = "Highly concurrent networking library"
-name = "eventlet"
-optional = false
-python-versions = "*"
-version = "0.25.2"
-
-[package.dependencies]
-dnspython = ">=1.15.0"
-greenlet = ">=0.3"
-monotonic = ">=1.4"
-six = ">=1.10.0"
-
-[[package]]
-category = "main"
-description = "A simple framework for building complex web applications."
-name = "flask"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
-version = "1.1.2"
-
-[package.dependencies]
-Jinja2 = ">=2.10.1"
-Werkzeug = ">=0.15"
-click = ">=5.1"
-itsdangerous = ">=0.24"
-
-[package.extras]
-dev = ["pytest", "coverage", "tox", "sphinx", "pallets-sphinx-themes", "sphinxcontrib-log-cabinet", "sphinx-issues"]
-docs = ["sphinx", "pallets-sphinx-themes", "sphinxcontrib-log-cabinet", "sphinx-issues"]
-dotenv = ["python-dotenv"]
-
-[[package]]
-category = "main"
-description = "Basic and Digest HTTP authentication for Flask routes"
-name = "flask-httpauth"
-optional = false
-python-versions = "*"
-version = "4.1.0"
-
-[package.dependencies]
-Flask = "*"
-
-[[package]]
-category = "main"
-description = "Socket.IO integration for Flask applications"
-name = "flask-socketio"
-optional = false
-python-versions = "*"
-version = "4.3.1"
-
-[package.dependencies]
-Flask = ">=0.9"
-python-socketio = ">=4.3.0"
-
-[[package]]
-category = "main"
-description = "Clean single-source support for Python 3 and 2"
-name = "future"
-optional = false
-python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
-version = "0.18.2"
-
-[[package]]
-category = "main"
-description = "Lightweight in-process concurrent programming"
-name = "greenlet"
-optional = false
-python-versions = "*"
-version = "0.4.16"
-
-[[package]]
-category = "main"
-description = "Internationalized Domain Names in Applications (IDNA)"
-name = "idna"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-version = "2.10"
-
-[[package]]
-category = "dev"
-description = "Read metadata from Python packages"
-marker = "python_version < \"3.8\""
-name = "importlib-metadata"
-optional = false
-python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
-version = "1.7.0"
-
-[package.dependencies]
-zipp = ">=0.5"
-
-[package.extras]
-docs = ["sphinx", "rst.linker"]
-testing = ["packaging", "pep517", "importlib-resources (>=1.3)"]
-
-[[package]]
-category = "dev"
-description = "iniconfig: brain-dead simple config-ini parsing"
-name = "iniconfig"
-optional = false
-python-versions = "*"
-version = "1.0.1"
-
-[[package]]
-category = "main"
-description = "Various helpers to pass data to untrusted environments and back."
-name = "itsdangerous"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-version = "1.1.0"
-
-[[package]]
-category = "main"
-description = "A very fast and expressive template engine."
-name = "jinja2"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
-version = "2.11.2"
-
-[package.dependencies]
-MarkupSafe = ">=0.23"
-
-[package.extras]
-i18n = ["Babel (>=0.8)"]
-
-[[package]]
-category = "main"
-description = "Mach-O header analysis and editing"
-name = "macholib"
-optional = false
-python-versions = "*"
-version = "1.14"
-
-[package.dependencies]
-altgraph = ">=0.15"
-
-[[package]]
-category = "main"
-description = "Safely add untrusted strings to HTML/XML markup."
-name = "markupsafe"
-optional = false
-python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*"
-version = "1.1.1"
-
-[[package]]
-category = "main"
-description = "An implementation of time.monotonic() for Python 2 & < 3.3"
-name = "monotonic"
-optional = false
-python-versions = "*"
-version = "1.5"
-
-[[package]]
-category = "dev"
-description = "More routines for operating on iterables, beyond itertools"
-name = "more-itertools"
-optional = false
-python-versions = ">=3.5"
-version = "8.4.0"
-
-[[package]]
-category = "dev"
-description = "Core utilities for Python packages"
-name = "packaging"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-version = "20.4"
-
-[package.dependencies]
-pyparsing = ">=2.0.2"
-six = "*"
-
-[[package]]
-category = "dev"
-description = "Utility library for gitignore style pattern matching of file paths."
-name = "pathspec"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
-version = "0.8.0"
-
-[[package]]
-category = "main"
-description = "Python PE parsing module"
-name = "pefile"
-optional = false
-python-versions = "*"
-version = "2019.4.18"
-
-[package.dependencies]
-future = "*"
-
-[[package]]
-category = "dev"
-description = "plugin and hook calling mechanisms for python"
-name = "pluggy"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-version = "0.13.1"
-
-[package.dependencies]
-[package.dependencies.importlib-metadata]
-python = "<3.8"
-version = ">=0.12"
-
-[package.extras]
-dev = ["pre-commit", "tox"]
-
-[[package]]
-category = "main"
-description = "Cross-platform lib for process and system monitoring in Python."
-name = "psutil"
-optional = false
-python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-version = "5.7.2"
-
-[package.extras]
-test = ["ipaddress", "mock", "unittest2", "enum34", "pywin32", "wmi"]
-
-[[package]]
-category = "dev"
-description = "library with cross-python path, ini-parsing, io, code, log facilities"
-name = "py"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-version = "1.9.0"
-
-[[package]]
-category = "main"
-description = "Cryptographic library for Python"
-name = "pycryptodome"
-optional = false
-python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-version = "3.9.8"
-
-[[package]]
-category = "dev"
-description = "PyInstaller bundles a Python application and all its dependencies into a single package."
-marker = "sys_platform == \"darwin\""
-name = "pyinstaller"
-optional = false
-python-versions = "*"
-version = "4.0"
-
-[package.dependencies]
-altgraph = "*"
-macholib = ">=1.8"
-pyinstaller-hooks-contrib = ">=2020.6"
-setuptools = "*"
-
-[package.extras]
-encryption = ["tinyaes (>=1.0.0)"]
-hook_testing = ["pytest (>=2.7.3)", "execnet (>=1.5.0)", "psutil"]
-
-[[package]]
-category = "dev"
-description = "Community maintained hooks for PyInstaller"
-marker = "sys_platform == \"darwin\""
-name = "pyinstaller-hooks-contrib"
-optional = false
-python-versions = "*"
-version = "2020.7"
-
-[[package]]
-category = "dev"
-description = "Python parsing module"
-name = "pyparsing"
-optional = false
-python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
-version = "2.4.7"
-
-[[package]]
-category = "main"
-description = "Python bindings for the Qt cross platform application toolkit"
-name = "pyqt5"
-optional = false
-python-versions = ">=3.5"
-version = "5.14.0"
-
-[package.dependencies]
-PyQt5-sip = ">=12.7,<13"
-
-[[package]]
-category = "main"
-description = "The sip module support for PyQt5"
-name = "pyqt5-sip"
-optional = false
-python-versions = ">=3.5"
-version = "12.8.0"
-
-[[package]]
-category = "main"
-description = "A Python SOCKS client module. See https://github.com/Anorov/PySocks for more information."
-name = "pysocks"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-version = "1.7.1"
-
-[[package]]
-category = "dev"
-description = "pytest: simple powerful testing with Python"
-name = "pytest"
-optional = false
-python-versions = ">=3.5"
-version = "6.0.1"
-
-[package.dependencies]
-atomicwrites = ">=1.0"
-attrs = ">=17.4.0"
-colorama = "*"
-iniconfig = "*"
-more-itertools = ">=4.0.0"
-packaging = "*"
-pluggy = ">=0.12,<1.0"
-py = ">=1.8.2"
-toml = "*"
-
-[package.dependencies.importlib-metadata]
-python = "<3.8"
-version = ">=0.12"
-
-[package.extras]
-checkqa_mypy = ["mypy (0.780)"]
-testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"]
-
-[[package]]
-category = "dev"
-description = "py.test plugin that activates the fault handler module for tests (dummy package)"
-name = "pytest-faulthandler"
-optional = false
-python-versions = "*"
-version = "2.0.1"
-
-[package.dependencies]
-pytest = ">=5.0"
-
-[[package]]
-category = "dev"
-description = "pytest support for PyQt and PySide applications"
-name = "pytest-qt"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-version = "3.3.0"
-
-[package.dependencies]
-pytest = ">=3.0.0"
-
-[package.extras]
-dev = ["pre-commit", "tox"]
-doc = ["sphinx", "sphinx-rtd-theme"]
-
-[[package]]
-category = "main"
-description = "Engine.IO server"
-name = "python-engineio"
-optional = false
-python-versions = "*"
-version = "3.13.2"
-
-[package.dependencies]
-six = ">=1.9.0"
-
-[package.extras]
-asyncio_client = ["aiohttp (>=3.4)"]
-client = ["requests (>=2.21.0)", "websocket-client (>=0.54.0)"]
-
-[[package]]
-category = "main"
-description = "Socket.IO server"
-name = "python-socketio"
-optional = false
-python-versions = "*"
-version = "4.6.0"
-
-[package.dependencies]
-python-engineio = ">=3.13.0"
-six = ">=1.9.0"
-
-[package.extras]
-asyncio_client = ["aiohttp (>=3.4)", "websockets (>=7.0)"]
-client = ["requests (>=2.21.0)", "websocket-client (>=0.54.0)"]
-
-[[package]]
-category = "main"
-description = "QR Code image generator"
-name = "qrcode"
-optional = false
-python-versions = "*"
-version = "6.1"
-
-[package.dependencies]
-colorama = "*"
-six = "*"
-
-[package.extras]
-dev = ["tox", "pytest", "mock"]
-maintainer = ["zest.releaser"]
-pil = ["pillow"]
-test = ["pytest", "pytest-cov", "mock"]
-
-[[package]]
-category = "dev"
-description = "Alternative regular expression module, to replace re."
-name = "regex"
-optional = false
-python-versions = "*"
-version = "2020.7.14"
-
-[[package]]
-category = "main"
-description = "Python HTTP for Humans."
-name = "requests"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
-version = "2.24.0"
-
-[package.dependencies]
-certifi = ">=2017.4.17"
-chardet = ">=3.0.2,<4"
-idna = ">=2.5,<3"
-urllib3 = ">=1.21.1,<1.25.0 || >1.25.0,<1.25.1 || >1.25.1,<1.26"
-
-[package.extras]
-security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"]
-socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7)", "win-inet-pton"]
-
-[[package]]
-category = "main"
-description = "Python 2 and 3 compatibility utilities"
-name = "six"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
-version = "1.15.0"
-
-[[package]]
-category = "main"
-description = "Stem is a Python controller library that allows applications to interact with Tor (https://www.torproject.org/)."
-name = "stem"
-optional = false
-python-versions = "*"
-version = "1.8.0"
-
-[[package]]
-category = "dev"
-description = "Python Library for Tom's Obvious, Minimal Language"
-name = "toml"
-optional = false
-python-versions = "*"
-version = "0.10.1"
-
-[[package]]
-category = "dev"
-description = "a fork of Python 2 and 3 ast modules with type comment support"
-name = "typed-ast"
-optional = false
-python-versions = "*"
-version = "1.4.1"
-
-[[package]]
-category = "main"
-description = "HTTP library with thread-safe connection pooling, file post, and more."
-name = "urllib3"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
-version = "1.25.10"
-
-[package.extras]
-brotli = ["brotlipy (>=0.6.0)"]
-secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "pyOpenSSL (>=0.14)", "ipaddress"]
-socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"]
-
-[[package]]
-category = "main"
-description = "The comprehensive WSGI web application library."
-name = "werkzeug"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
-version = "1.0.1"
-
-[package.extras]
-dev = ["pytest", "pytest-timeout", "coverage", "tox", "sphinx", "pallets-sphinx-themes", "sphinx-issues"]
-watchdog = ["watchdog"]
-
-[[package]]
-category = "dev"
-description = "Backport of pathlib-compatible object wrapper for zip files"
-marker = "python_version < \"3.8\""
-name = "zipp"
-optional = false
-python-versions = ">=3.6"
-version = "3.1.0"
-
-[package.extras]
-docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"]
-testing = ["jaraco.itertools", "func-timeout"]
-
-[metadata]
-content-hash = "b5a36d265c4247b98b493fac989ecdd3c11920bd4c81d47f2af9e64edb5fd5bb"
-lock-version = "1.0"
-python-versions = "^3.7"
-
-[metadata.files]
-altgraph = [
- {file = "altgraph-0.17-py2.py3-none-any.whl", hash = "sha256:c623e5f3408ca61d4016f23a681b9adb100802ca3e3da5e718915a9e4052cebe"},
- {file = "altgraph-0.17.tar.gz", hash = "sha256:1f05a47122542f97028caf78775a095fbe6a2699b5089de8477eb583167d69aa"},
-]
-appdirs = [
- {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"},
- {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"},
-]
-atomicwrites = [
- {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"},
- {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"},
-]
-attrs = [
- {file = "attrs-19.3.0-py2.py3-none-any.whl", hash = "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c"},
- {file = "attrs-19.3.0.tar.gz", hash = "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"},
-]
-black = [
- {file = "black-19.10b0-py36-none-any.whl", hash = "sha256:1b30e59be925fafc1ee4565e5e08abef6b03fe455102883820fe5ee2e4734e0b"},
- {file = "black-19.10b0.tar.gz", hash = "sha256:c2edb73a08e9e0e6f65a0e6af18b059b8b1cdd5bef997d7a0b181df93dc81539"},
-]
-certifi = [
- {file = "certifi-2020.6.20-py2.py3-none-any.whl", hash = "sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41"},
- {file = "certifi-2020.6.20.tar.gz", hash = "sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3"},
-]
-chardet = [
- {file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"},
- {file = "chardet-3.0.4.tar.gz", hash = "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"},
-]
-click = [
- {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"},
- {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"},
-]
-colorama = [
- {file = "colorama-0.4.3-py2.py3-none-any.whl", hash = "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff"},
- {file = "colorama-0.4.3.tar.gz", hash = "sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"},
-]
-dnspython = [
- {file = "dnspython-2.0.0-py3-none-any.whl", hash = "sha256:40bb3c24b9d4ec12500f0124288a65df232a3aa749bb0c39734b782873a2544d"},
- {file = "dnspython-2.0.0.zip", hash = "sha256:044af09374469c3a39eeea1a146e8cac27daec951f1f1f157b1962fc7cb9d1b7"},
-]
-eventlet = [
- {file = "eventlet-0.25.2-py2.py3-none-any.whl", hash = "sha256:955f2cf538829bfcb7b3aa885ace40e8ae5965dcd5b876c384d0c5869702db1d"},
- {file = "eventlet-0.25.2.tar.gz", hash = "sha256:4c8ab42c51bff55204fef43cff32616558bedbc7538d876bb6a96ce820c7f9ed"},
-]
-flask = [
- {file = "Flask-1.1.2-py2.py3-none-any.whl", hash = "sha256:8a4fdd8936eba2512e9c85df320a37e694c93945b33ef33c89946a340a238557"},
- {file = "Flask-1.1.2.tar.gz", hash = "sha256:4efa1ae2d7c9865af48986de8aeb8504bf32c7f3d6fdc9353d34b21f4b127060"},
-]
-flask-httpauth = [
- {file = "Flask-HTTPAuth-4.1.0.tar.gz", hash = "sha256:9e028e4375039a49031eb9ecc40be4761f0540476040f6eff329a31dabd4d000"},
- {file = "Flask_HTTPAuth-4.1.0-py2.py3-none-any.whl", hash = "sha256:29e0288869a213c7387f0323b6bf2c7191584fb1da8aa024d9af118e5cd70de7"},
-]
-flask-socketio = [
- {file = "Flask-SocketIO-4.3.1.tar.gz", hash = "sha256:36c1d5765010d1f4e4f05b4cc9c20c289d9dc70698c88d1addd0afcfedc5b062"},
- {file = "Flask_SocketIO-4.3.1-py2.py3-none-any.whl", hash = "sha256:3668675bf7763c5b5f56689d439f07356e89c0a52e0c9e9cd3cc08563c07b252"},
-]
-future = [
- {file = "future-0.18.2.tar.gz", hash = "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"},
-]
-greenlet = [
- {file = "greenlet-0.4.16-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:80cb0380838bf4e48da6adedb0c7cd060c187bb4a75f67a5aa9ec33689b84872"},
- {file = "greenlet-0.4.16-cp27-cp27m-win32.whl", hash = "sha256:df7de669cbf21de4b04a3ffc9920bc8426cab4c61365fa84d79bf97401a8bef7"},
- {file = "greenlet-0.4.16-cp27-cp27m-win_amd64.whl", hash = "sha256:1429dc183b36ec972055e13250d96e174491559433eb3061691b446899b87384"},
- {file = "greenlet-0.4.16-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:5ea034d040e6ab1d2ae04ab05a3f37dbd719c4dee3804b13903d4cc794b1336e"},
- {file = "greenlet-0.4.16-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c196a5394c56352e21cb7224739c6dd0075b69dd56f758505951d1d8d68cf8a9"},
- {file = "greenlet-0.4.16-cp35-cp35m-win32.whl", hash = "sha256:1000038ba0ea9032948e2156a9c15f5686f36945e8f9906e6b8db49f358e7b52"},
- {file = "greenlet-0.4.16-cp35-cp35m-win_amd64.whl", hash = "sha256:1b805231bfb7b2900a16638c3c8b45c694334c811f84463e52451e00c9412691"},
- {file = "greenlet-0.4.16-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:e5db19d4a7d41bbeb3dd89b49fc1bc7e6e515b51bbf32589c618655a0ebe0bf0"},
- {file = "greenlet-0.4.16-cp36-cp36m-win32.whl", hash = "sha256:eac2a3f659d5f41d6bbfb6a97733bc7800ea5e906dc873732e00cebb98cec9e4"},
- {file = "greenlet-0.4.16-cp36-cp36m-win_amd64.whl", hash = "sha256:7eed31f4efc8356e200568ba05ad645525f1fbd8674f1e5be61a493e715e3873"},
- {file = "greenlet-0.4.16-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:682328aa576ec393c1872615bcb877cf32d800d4a2f150e1a5dc7e56644010b1"},
- {file = "greenlet-0.4.16-cp37-cp37m-win32.whl", hash = "sha256:3a35e33902b2e6079949feed7a2dafa5ac6f019da97bd255842bb22de3c11bf5"},
- {file = "greenlet-0.4.16-cp37-cp37m-win_amd64.whl", hash = "sha256:b0b2a984bbfc543d144d88caad6cc7ff4a71be77102014bd617bd88cfb038727"},
- {file = "greenlet-0.4.16-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:d83c1d38658b0f81c282b41238092ed89d8f93c6e342224ab73fb39e16848721"},
- {file = "greenlet-0.4.16-cp38-cp38-win32.whl", hash = "sha256:e695ac8c3efe124d998230b219eb51afb6ef10524a50b3c45109c4b77a8a3a92"},
- {file = "greenlet-0.4.16-cp38-cp38-win_amd64.whl", hash = "sha256:133ba06bad4e5f2f8bf6a0ac434e0fd686df749a86b3478903b92ec3a9c0c90b"},
- {file = "greenlet-0.4.16.tar.gz", hash = "sha256:6e06eac722676797e8fce4adb8ad3dc57a1bb3adfb0dd3fdf8306c055a38456c"},
-]
-idna = [
- {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"},
- {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"},
-]
-importlib-metadata = [
- {file = "importlib_metadata-1.7.0-py2.py3-none-any.whl", hash = "sha256:dc15b2969b4ce36305c51eebe62d418ac7791e9a157911d58bfb1f9ccd8e2070"},
- {file = "importlib_metadata-1.7.0.tar.gz", hash = "sha256:90bb658cdbbf6d1735b6341ce708fc7024a3e14e99ffdc5783edea9f9b077f83"},
-]
-iniconfig = [
- {file = "iniconfig-1.0.1-py3-none-any.whl", hash = "sha256:80cf40c597eb564e86346103f609d74efce0f6b4d4f30ec8ce9e2c26411ba437"},
- {file = "iniconfig-1.0.1.tar.gz", hash = "sha256:e5f92f89355a67de0595932a6c6c02ab4afddc6fcdc0bfc5becd0d60884d3f69"},
-]
-itsdangerous = [
- {file = "itsdangerous-1.1.0-py2.py3-none-any.whl", hash = "sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749"},
- {file = "itsdangerous-1.1.0.tar.gz", hash = "sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19"},
-]
-jinja2 = [
- {file = "Jinja2-2.11.2-py2.py3-none-any.whl", hash = "sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035"},
- {file = "Jinja2-2.11.2.tar.gz", hash = "sha256:89aab215427ef59c34ad58735269eb58b1a5808103067f7bb9d5836c651b3bb0"},
-]
-macholib = [
- {file = "macholib-1.14-py2.py3-none-any.whl", hash = "sha256:c500f02867515e6c60a27875b408920d18332ddf96b4035ef03beddd782d4281"},
- {file = "macholib-1.14.tar.gz", hash = "sha256:0c436bc847e7b1d9bda0560351bf76d7caf930fb585a828d13608839ef42c432"},
-]
-markupsafe = [
- {file = "MarkupSafe-1.1.1-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161"},
- {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"},
- {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183"},
- {file = "MarkupSafe-1.1.1-cp27-cp27m-win32.whl", hash = "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b"},
- {file = "MarkupSafe-1.1.1-cp27-cp27m-win_amd64.whl", hash = "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e"},
- {file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f"},
- {file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1"},
- {file = "MarkupSafe-1.1.1-cp34-cp34m-macosx_10_6_intel.whl", hash = "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5"},
- {file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1"},
- {file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735"},
- {file = "MarkupSafe-1.1.1-cp34-cp34m-win32.whl", hash = "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21"},
- {file = "MarkupSafe-1.1.1-cp34-cp34m-win_amd64.whl", hash = "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235"},
- {file = "MarkupSafe-1.1.1-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b"},
- {file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f"},
- {file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905"},
- {file = "MarkupSafe-1.1.1-cp35-cp35m-win32.whl", hash = "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1"},
- {file = "MarkupSafe-1.1.1-cp35-cp35m-win_amd64.whl", hash = "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d"},
- {file = "MarkupSafe-1.1.1-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff"},
- {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473"},
- {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e"},
- {file = "MarkupSafe-1.1.1-cp36-cp36m-win32.whl", hash = "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66"},
- {file = "MarkupSafe-1.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5"},
- {file = "MarkupSafe-1.1.1-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d"},
- {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e"},
- {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6"},
- {file = "MarkupSafe-1.1.1-cp37-cp37m-win32.whl", hash = "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2"},
- {file = "MarkupSafe-1.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c"},
- {file = "MarkupSafe-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15"},
- {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2"},
- {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42"},
- {file = "MarkupSafe-1.1.1-cp38-cp38-win32.whl", hash = "sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b"},
- {file = "MarkupSafe-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be"},
- {file = "MarkupSafe-1.1.1.tar.gz", hash = "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b"},
-]
-monotonic = [
- {file = "monotonic-1.5-py2.py3-none-any.whl", hash = "sha256:552a91f381532e33cbd07c6a2655a21908088962bb8fa7239ecbcc6ad1140cc7"},
- {file = "monotonic-1.5.tar.gz", hash = "sha256:23953d55076df038541e648a53676fb24980f7a1be290cdda21300b3bc21dfb0"},
-]
-more-itertools = [
- {file = "more-itertools-8.4.0.tar.gz", hash = "sha256:68c70cc7167bdf5c7c9d8f6954a7837089c6a36bf565383919bb595efb8a17e5"},
- {file = "more_itertools-8.4.0-py3-none-any.whl", hash = "sha256:b78134b2063dd214000685165d81c154522c3ee0a1c0d4d113c80361c234c5a2"},
-]
-packaging = [
- {file = "packaging-20.4-py2.py3-none-any.whl", hash = "sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181"},
- {file = "packaging-20.4.tar.gz", hash = "sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8"},
-]
-pathspec = [
- {file = "pathspec-0.8.0-py2.py3-none-any.whl", hash = "sha256:7d91249d21749788d07a2d0f94147accd8f845507400749ea19c1ec9054a12b0"},
- {file = "pathspec-0.8.0.tar.gz", hash = "sha256:da45173eb3a6f2a5a487efba21f050af2b41948be6ab52b6a1e3ff22bb8b7061"},
-]
-pefile = [
- {file = "pefile-2019.4.18.tar.gz", hash = "sha256:a5d6e8305c6b210849b47a6174ddf9c452b2888340b8177874b862ba6c207645"},
-]
-pluggy = [
- {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"},
- {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"},
-]
-psutil = [
- {file = "psutil-5.7.2-cp27-none-win32.whl", hash = "sha256:f2018461733b23f308c298653c8903d32aaad7873d25e1d228765e91ae42c3f2"},
- {file = "psutil-5.7.2-cp27-none-win_amd64.whl", hash = "sha256:66c18ca7680a31bf16ee22b1d21b6397869dda8059dbdb57d9f27efa6615f195"},
- {file = "psutil-5.7.2-cp35-cp35m-win32.whl", hash = "sha256:5e9d0f26d4194479a13d5f4b3798260c20cecf9ac9a461e718eb59ea520a360c"},
- {file = "psutil-5.7.2-cp35-cp35m-win_amd64.whl", hash = "sha256:4080869ed93cce662905b029a1770fe89c98787e543fa7347f075ade761b19d6"},
- {file = "psutil-5.7.2-cp36-cp36m-win32.whl", hash = "sha256:d8a82162f23c53b8525cf5f14a355f5d1eea86fa8edde27287dd3a98399e4fdf"},
- {file = "psutil-5.7.2-cp36-cp36m-win_amd64.whl", hash = "sha256:0ee3c36428f160d2d8fce3c583a0353e848abb7de9732c50cf3356dd49ad63f8"},
- {file = "psutil-5.7.2-cp37-cp37m-win32.whl", hash = "sha256:ff1977ba1a5f71f89166d5145c3da1cea89a0fdb044075a12c720ee9123ec818"},
- {file = "psutil-5.7.2-cp37-cp37m-win_amd64.whl", hash = "sha256:a5b120bb3c0c71dfe27551f9da2f3209a8257a178ed6c628a819037a8df487f1"},
- {file = "psutil-5.7.2-cp38-cp38-win32.whl", hash = "sha256:10512b46c95b02842c225f58fa00385c08fa00c68bac7da2d9a58ebe2c517498"},
- {file = "psutil-5.7.2-cp38-cp38-win_amd64.whl", hash = "sha256:68d36986ded5dac7c2dcd42f2682af1db80d4bce3faa126a6145c1637e1b559f"},
- {file = "psutil-5.7.2.tar.gz", hash = "sha256:90990af1c3c67195c44c9a889184f84f5b2320dce3ee3acbd054e3ba0b4a7beb"},
-]
-py = [
- {file = "py-1.9.0-py2.py3-none-any.whl", hash = "sha256:366389d1db726cd2fcfc79732e75410e5fe4d31db13692115529d34069a043c2"},
- {file = "py-1.9.0.tar.gz", hash = "sha256:9ca6883ce56b4e8da7e79ac18787889fa5206c79dcc67fb065376cd2fe03f342"},
-]
-pycryptodome = [
- {file = "pycryptodome-3.9.8-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:50348edd283afdccddc0938cdc674484533912ba8a99a27c7bfebb75030aa856"},
- {file = "pycryptodome-3.9.8-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:80d57177a0b7c14d4594c62bbb47fe2f6309ad3b0a34348a291d570925c97a82"},
- {file = "pycryptodome-3.9.8-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:fbe65d5cfe04ff2f7684160d50f5118bdefb01e3af4718eeb618bfed40f19d94"},
- {file = "pycryptodome-3.9.8-cp27-cp27m-win32.whl", hash = "sha256:bcd5b8416e73e4b0d48afba3704d8c826414764dafaed7a1a93c442188d90ccc"},
- {file = "pycryptodome-3.9.8-cp27-cp27m-win_amd64.whl", hash = "sha256:360955eece2cd0fa694a708d10303c6abd7b39614fa2547b6bd245da76198beb"},
- {file = "pycryptodome-3.9.8-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:1e655746f539421d923fd48df8f6f40b3443d80b75532501c0085b64afed9df5"},
- {file = "pycryptodome-3.9.8-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:709b9f144d23e290b9863121d1ace14a72e01f66ea9c903fbdc690520dfdfcf0"},
- {file = "pycryptodome-3.9.8-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:6276478ada411aca97c0d5104916354b3d740d368407912722bd4d11aa9ee4c2"},
- {file = "pycryptodome-3.9.8-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:54bdedd28476dea8a3cd86cb67c0df1f0e3d71cae8022354b0f879c41a3d27b2"},
- {file = "pycryptodome-3.9.8-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:f521178e5a991ffd04182ed08f552daca1affcb826aeda0e1945cd989a9d4345"},
- {file = "pycryptodome-3.9.8-cp35-cp35m-win32.whl", hash = "sha256:a207231a52426de3ff20f5608f0687261a3329d97a036c51f7d4c606a6f30c23"},
- {file = "pycryptodome-3.9.8-cp35-cp35m-win_amd64.whl", hash = "sha256:2b998dc45ef5f4e5cf5248a6edfcd8d8e9fb5e35df8e4259b13a1b10eda7b16b"},
- {file = "pycryptodome-3.9.8-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:03d5cca8618620f45fd40f827423f82b86b3a202c8d44108601b0f5f56b04299"},
- {file = "pycryptodome-3.9.8-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:f78a68c2c820e4731e510a2df3eef0322f24fde1781ced970bf497b6c7d92982"},
- {file = "pycryptodome-3.9.8-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:132a56abba24e2e06a479d8e5db7a48271a73a215f605017bbd476d31f8e71c1"},
- {file = "pycryptodome-3.9.8-cp36-cp36m-win32.whl", hash = "sha256:67dcad1b8b201308586a8ca2ffe89df1e4f731d5a4cdd0610cc4ea790351c739"},
- {file = "pycryptodome-3.9.8-cp36-cp36m-win_amd64.whl", hash = "sha256:b56638d58a3a4be13229c6a815cd448f9e3ce40c00880a5398471b42ee86f50e"},
- {file = "pycryptodome-3.9.8-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:bec2bcdf7c9ce7f04d718e51887f3b05dc5c1cfaf5d2c2e9065ecddd1b2f6c9a"},
- {file = "pycryptodome-3.9.8-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:abc2e126c9490e58a36a0f83516479e781d83adfb134576a5cbe5c6af2a3e93c"},
- {file = "pycryptodome-3.9.8-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ef39c98d9b8c0736d91937d193653e47c3b19ddf4fc3bccdc5e09aaa4b0c5d21"},
- {file = "pycryptodome-3.9.8-cp37-cp37m-win32.whl", hash = "sha256:4350a42028240c344ee855f032c7d4ad6ff4f813bfbe7121547b7dc579ecc876"},
- {file = "pycryptodome-3.9.8-cp37-cp37m-win_amd64.whl", hash = "sha256:c8bf40cf6e281a4378e25846924327e728a887e8bf0ee83b2604a0f4b61692e8"},
- {file = "pycryptodome-3.9.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d8074c8448cfd0705dfa71ca333277fce9786d0b9cac75d120545de6253f996a"},
- {file = "pycryptodome-3.9.8-cp38-cp38-manylinux1_i686.whl", hash = "sha256:8063a712fba642f78d3c506b0896846601b6de7f5c3d534e388ad0cc07f5a149"},
- {file = "pycryptodome-3.9.8-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:dd302b6ae3965afeb5ef1b0d92486f986c0e65183cd7835973f0b593800590e6"},
- {file = "pycryptodome-3.9.8-cp38-cp38-win32.whl", hash = "sha256:02e51e1d5828d58f154896ddfd003e2e7584869c275e5acbe290443575370fba"},
- {file = "pycryptodome-3.9.8-cp38-cp38-win_amd64.whl", hash = "sha256:55eb61aca2c883db770999f50d091ff7c14016f2769ad7bca3d9b75d1d7c1b68"},
- {file = "pycryptodome-3.9.8-cp39-cp39-manylinux1_i686.whl", hash = "sha256:39ef9fb52d6ec7728fce1f1693cb99d60ce302aeebd59bcedea70ca3203fda60"},
- {file = "pycryptodome-3.9.8-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:de6e1cd75677423ff64712c337521e62e3a7a4fc84caabbd93207752e831a85a"},
- {file = "pycryptodome-3.9.8.tar.gz", hash = "sha256:0e24171cf01021bc5dc17d6a9d4f33a048f09d62cc3f62541e95ef104588bda4"},
-]
-pyinstaller = [
- {file = "pyinstaller-4.0.tar.gz", hash = "sha256:970beb07115761d5e4ec317c1351b712fd90ae7f23994db914c633281f99bab0"},
-]
-pyinstaller-hooks-contrib = [
- {file = "pyinstaller-hooks-contrib-2020.7.tar.gz", hash = "sha256:74936d044f319cd7a9dca322b46a818fcb6e2af1c67af62e8a6a3121eb2863d2"},
- {file = "pyinstaller_hooks_contrib-2020.7-py2.py3-none-any.whl", hash = "sha256:5b6e06ba6072499189f5b8e1623d5f0414962941aac370ee4f842de25455be5b"},
-]
-pyparsing = [
- {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"},
- {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"},
-]
-pyqt5 = [
- {file = "PyQt5-5.14.0-5.14.0-cp35.cp36.cp37.cp38-abi3-macosx_10_6_intel.whl", hash = "sha256:895d4101f7f8c82bc728d7eb9da1c756955ce27a0c945eafe7f234dd03402853"},
- {file = "PyQt5-5.14.0-5.14.0-cp35.cp36.cp37.cp38-abi3-manylinux1_x86_64.whl", hash = "sha256:a757ba71c51f428b52ba404e781e2f19b4436b2c31298b8313339d5817781b65"},
- {file = "PyQt5-5.14.0-5.14.0-cp35.cp36.cp37.cp38-none-win32.whl", hash = "sha256:cc3529c0f7cbbe7491073458d5d15e7518ce544ad8c627f485e5db8a27fcaf61"},
- {file = "PyQt5-5.14.0-5.14.0-cp35.cp36.cp37.cp38-none-win_amd64.whl", hash = "sha256:0dcc128b72f83cce0fc7926c83f05a9b74b652b5eb31a4ab71693ac8829e73c8"},
- {file = "PyQt5-5.14.0.tar.gz", hash = "sha256:0145a6b7de15756366decb736c349a0cb510d706c83fda5b8cd9e0557bc1da72"},
-]
-pyqt5-sip = [
- {file = "PyQt5_sip-12.8.0-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:9ef12754021bcc1246f97e00ea62b5594dd5c61192830639ab4a1640bd4b7940"},
- {file = "PyQt5_sip-12.8.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:fa3d70f370604efc67085849d3d1d3d2109faa716c520faf601d15845df64de6"},
- {file = "PyQt5_sip-12.8.0-cp35-cp35m-win32.whl", hash = "sha256:61aa60fb848d740581646603a12c2dcb8d7c4cbd2a9c476a1c891ec360ff0b87"},
- {file = "PyQt5_sip-12.8.0-cp35-cp35m-win_amd64.whl", hash = "sha256:8d9f4dc7dbae9783c5dafd66801875a2ebf9302c3addd5739f772285c1c1e91c"},
- {file = "PyQt5_sip-12.8.0-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:9b69db29571dde679908fb237784a8e7af4a2cbf1b7bb25bdb86e487210e04d2"},
- {file = "PyQt5_sip-12.8.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:58eae636e0b1926cddec98a703319a47f671cef07d73aaa525ba421cd4adfeb5"},
- {file = "PyQt5_sip-12.8.0-cp36-cp36m-win32.whl", hash = "sha256:e6254647fa35e1260282aeb9c32a3dd363287b9a1ffcc4f22bd27e54178e92e4"},
- {file = "PyQt5_sip-12.8.0-cp36-cp36m-win_amd64.whl", hash = "sha256:f4c294bfaf2be8004583266d4621bfd3a387e12946f548f966a7fbec91845f1b"},
- {file = "PyQt5_sip-12.8.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:224e2fbb7088595940c348d168a317caa2110cbb7a5b957a8c3fc0d9296ee069"},
- {file = "PyQt5_sip-12.8.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5c19c4ad67af087e8f4411da7422391b236b941f5f0697f615c5816455d1355d"},
- {file = "PyQt5_sip-12.8.0-cp37-cp37m-win32.whl", hash = "sha256:2a1153cda63f2632d3d5698f0cf29f6b1f1d5162305dc6f5b23336ad8f1039ed"},
- {file = "PyQt5_sip-12.8.0-cp37-cp37m-win_amd64.whl", hash = "sha256:94c80677b1e8c92fa080e24045d54ace5e4343c4ee6d0216675cd91d6f8e122a"},
- {file = "PyQt5_sip-12.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2a2239d16a49ce6eaf10166a84424543111f8ebe49d3c124d02af91b01a58425"},
- {file = "PyQt5_sip-12.8.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:b1bbe763d431d26f9565cba3e99866768761366ab6d609d2506d194882156fa7"},
- {file = "PyQt5_sip-12.8.0-cp38-cp38-win32.whl", hash = "sha256:d7b8a8f89385ad9e3da38e0123c22c0efc18005e0e2731b6b95e4c21db2049d2"},
- {file = "PyQt5_sip-12.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:1d65ce08a56282fb0273dd06585b8927b88d4fba71c01a54f8e2ac87ac1ed387"},
- {file = "PyQt5_sip-12.8.0.tar.gz", hash = "sha256:0a34b6596bdd28d52da3a51fa8d9bb0b287bcb605c2512aa3251b9028cc71f4d"},
-]
-pysocks = [
- {file = "PySocks-1.7.1-py27-none-any.whl", hash = "sha256:08e69f092cc6dbe92a0fdd16eeb9b9ffbc13cadfe5ca4c7bd92ffb078b293299"},
- {file = "PySocks-1.7.1-py3-none-any.whl", hash = "sha256:2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5"},
- {file = "PySocks-1.7.1.tar.gz", hash = "sha256:3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0"},
-]
-pytest = [
- {file = "pytest-6.0.1-py3-none-any.whl", hash = "sha256:8b6007800c53fdacd5a5c192203f4e531eb2a1540ad9c752e052ec0f7143dbad"},
- {file = "pytest-6.0.1.tar.gz", hash = "sha256:85228d75db9f45e06e57ef9bf4429267f81ac7c0d742cc9ed63d09886a9fe6f4"},
-]
-pytest-faulthandler = [
- {file = "pytest-faulthandler-2.0.1.tar.gz", hash = "sha256:ed72bbce87ac344da81eb7d882196a457d4a1026a3da4a57154dacd85cd71ae5"},
- {file = "pytest_faulthandler-2.0.1-py2.py3-none-any.whl", hash = "sha256:236430ba962fd1c910d670922be55fe5b25ea9bc3fc6561a0cafbb8759e7504d"},
-]
-pytest-qt = [
- {file = "pytest-qt-3.3.0.tar.gz", hash = "sha256:714b0bf86c5313413f2d300ac613515db3a1aef595051ab8ba2ffe619dbe8925"},
- {file = "pytest_qt-3.3.0-py2.py3-none-any.whl", hash = "sha256:5f8928288f50489d83f5d38caf2d7d9fcd6e7cf769947902caa4661dc7c851e3"},
-]
-python-engineio = [
- {file = "python-engineio-3.13.2.tar.gz", hash = "sha256:36b33c6aa702d9b6a7f527eec6387a2da1a9a24484ec2f086d76576413cef04b"},
- {file = "python_engineio-3.13.2-py2.py3-none-any.whl", hash = "sha256:cfded18156862f94544a9f8ef37f56727df731c8552d7023f5afee8369be2db6"},
-]
-python-socketio = [
- {file = "python-socketio-4.6.0.tar.gz", hash = "sha256:358d8fbbc029c4538ea25bcaa283e47f375be0017fcba829de8a3a731c9df25a"},
- {file = "python_socketio-4.6.0-py2.py3-none-any.whl", hash = "sha256:d437f797c44b6efba2f201867cf02b8c96b97dff26d4e4281ac08b45817cd522"},
-]
-qrcode = [
- {file = "qrcode-6.1-py2.py3-none-any.whl", hash = "sha256:3996ee560fc39532910603704c82980ff6d4d5d629f9c3f25f34174ce8606cf5"},
- {file = "qrcode-6.1.tar.gz", hash = "sha256:505253854f607f2abf4d16092c61d4e9d511a3b4392e60bff957a68592b04369"},
-]
-regex = [
- {file = "regex-2020.7.14-cp27-cp27m-win32.whl", hash = "sha256:e46d13f38cfcbb79bfdb2964b0fe12561fe633caf964a77a5f8d4e45fe5d2ef7"},
- {file = "regex-2020.7.14-cp27-cp27m-win_amd64.whl", hash = "sha256:6961548bba529cac7c07af2fd4d527c5b91bb8fe18995fed6044ac22b3d14644"},
- {file = "regex-2020.7.14-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:c50a724d136ec10d920661f1442e4a8b010a4fe5aebd65e0c2241ea41dbe93dc"},
- {file = "regex-2020.7.14-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:8a51f2c6d1f884e98846a0a9021ff6861bdb98457879f412fdc2b42d14494067"},
- {file = "regex-2020.7.14-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:9c568495e35599625f7b999774e29e8d6b01a6fb684d77dee1f56d41b11b40cd"},
- {file = "regex-2020.7.14-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:51178c738d559a2d1071ce0b0f56e57eb315bcf8f7d4cf127674b533e3101f88"},
- {file = "regex-2020.7.14-cp36-cp36m-win32.whl", hash = "sha256:9eddaafb3c48e0900690c1727fba226c4804b8e6127ea409689c3bb492d06de4"},
- {file = "regex-2020.7.14-cp36-cp36m-win_amd64.whl", hash = "sha256:14a53646369157baa0499513f96091eb70382eb50b2c82393d17d7ec81b7b85f"},
- {file = "regex-2020.7.14-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:1269fef3167bb52631ad4fa7dd27bf635d5a0790b8e6222065d42e91bede4162"},
- {file = "regex-2020.7.14-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d0a5095d52b90ff38592bbdc2644f17c6d495762edf47d876049cfd2968fbccf"},
- {file = "regex-2020.7.14-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:4c037fd14c5f4e308b8370b447b469ca10e69427966527edcab07f52d88388f7"},
- {file = "regex-2020.7.14-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:bc3d98f621898b4a9bc7fecc00513eec8f40b5b83913d74ccb445f037d58cd89"},
- {file = "regex-2020.7.14-cp37-cp37m-win32.whl", hash = "sha256:46bac5ca10fb748d6c55843a931855e2727a7a22584f302dd9bb1506e69f83f6"},
- {file = "regex-2020.7.14-cp37-cp37m-win_amd64.whl", hash = "sha256:0dc64ee3f33cd7899f79a8d788abfbec168410be356ed9bd30bbd3f0a23a7204"},
- {file = "regex-2020.7.14-cp38-cp38-manylinux1_i686.whl", hash = "sha256:5ea81ea3dbd6767873c611687141ec7b06ed8bab43f68fad5b7be184a920dc99"},
- {file = "regex-2020.7.14-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:bbb332d45b32df41200380fff14712cb6093b61bd142272a10b16778c418e98e"},
- {file = "regex-2020.7.14-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:c11d6033115dc4887c456565303f540c44197f4fc1a2bfb192224a301534888e"},
- {file = "regex-2020.7.14-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:75aaa27aa521a182824d89e5ab0a1d16ca207318a6b65042b046053cfc8ed07a"},
- {file = "regex-2020.7.14-cp38-cp38-win32.whl", hash = "sha256:d6cff2276e502b86a25fd10c2a96973fdb45c7a977dca2138d661417f3728341"},
- {file = "regex-2020.7.14-cp38-cp38-win_amd64.whl", hash = "sha256:7a2dd66d2d4df34fa82c9dc85657c5e019b87932019947faece7983f2089a840"},
- {file = "regex-2020.7.14.tar.gz", hash = "sha256:3a3af27a8d23143c49a3420efe5b3f8cf1a48c6fc8bc6856b03f638abc1833bb"},
-]
-requests = [
- {file = "requests-2.24.0-py2.py3-none-any.whl", hash = "sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898"},
- {file = "requests-2.24.0.tar.gz", hash = "sha256:b3559a131db72c33ee969480840fff4bb6dd111de7dd27c8ee1f820f4f00231b"},
-]
-six = [
- {file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"},
- {file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"},
-]
-stem = [
- {file = "stem-1.8.0.tar.gz", hash = "sha256:a0b48ea6224e95f22aa34c0bc3415f0eb4667ddeae3dfb5e32a6920c185568c2"},
-]
-toml = [
- {file = "toml-0.10.1-py2.py3-none-any.whl", hash = "sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88"},
- {file = "toml-0.10.1.tar.gz", hash = "sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f"},
-]
-typed-ast = [
- {file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3"},
- {file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:aaee9905aee35ba5905cfb3c62f3e83b3bec7b39413f0a7f19be4e547ea01ebb"},
- {file = "typed_ast-1.4.1-cp35-cp35m-win32.whl", hash = "sha256:0c2c07682d61a629b68433afb159376e24e5b2fd4641d35424e462169c0a7919"},
- {file = "typed_ast-1.4.1-cp35-cp35m-win_amd64.whl", hash = "sha256:4083861b0aa07990b619bd7ddc365eb7fa4b817e99cf5f8d9cf21a42780f6e01"},
- {file = "typed_ast-1.4.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:269151951236b0f9a6f04015a9004084a5ab0d5f19b57de779f908621e7d8b75"},
- {file = "typed_ast-1.4.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:24995c843eb0ad11a4527b026b4dde3da70e1f2d8806c99b7b4a7cf491612652"},
- {file = "typed_ast-1.4.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:fe460b922ec15dd205595c9b5b99e2f056fd98ae8f9f56b888e7a17dc2b757e7"},
- {file = "typed_ast-1.4.1-cp36-cp36m-win32.whl", hash = "sha256:4e3e5da80ccbebfff202a67bf900d081906c358ccc3d5e3c8aea42fdfdfd51c1"},
- {file = "typed_ast-1.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:249862707802d40f7f29f6e1aad8d84b5aa9e44552d2cc17384b209f091276aa"},
- {file = "typed_ast-1.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8ce678dbaf790dbdb3eba24056d5364fb45944f33553dd5869b7580cdbb83614"},
- {file = "typed_ast-1.4.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:c9e348e02e4d2b4a8b2eedb48210430658df6951fa484e59de33ff773fbd4b41"},
- {file = "typed_ast-1.4.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:bcd3b13b56ea479b3650b82cabd6b5343a625b0ced5429e4ccad28a8973f301b"},
- {file = "typed_ast-1.4.1-cp37-cp37m-win32.whl", hash = "sha256:d5d33e9e7af3b34a40dc05f498939f0ebf187f07c385fd58d591c533ad8562fe"},
- {file = "typed_ast-1.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:0666aa36131496aed8f7be0410ff974562ab7eeac11ef351def9ea6fa28f6355"},
- {file = "typed_ast-1.4.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:d205b1b46085271b4e15f670058ce182bd1199e56b317bf2ec004b6a44f911f6"},
- {file = "typed_ast-1.4.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:6daac9731f172c2a22ade6ed0c00197ee7cc1221aa84cfdf9c31defeb059a907"},
- {file = "typed_ast-1.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:498b0f36cc7054c1fead3d7fc59d2150f4d5c6c56ba7fb150c013fbc683a8d2d"},
- {file = "typed_ast-1.4.1-cp38-cp38-win32.whl", hash = "sha256:715ff2f2df46121071622063fc7543d9b1fd19ebfc4f5c8895af64a77a8c852c"},
- {file = "typed_ast-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:fc0fea399acb12edbf8a628ba8d2312f583bdbdb3335635db062fa98cf71fca4"},
- {file = "typed_ast-1.4.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34"},
- {file = "typed_ast-1.4.1.tar.gz", hash = "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b"},
-]
-urllib3 = [
- {file = "urllib3-1.25.10-py2.py3-none-any.whl", hash = "sha256:e7983572181f5e1522d9c98453462384ee92a0be7fac5f1413a1e35c56cc0461"},
- {file = "urllib3-1.25.10.tar.gz", hash = "sha256:91056c15fa70756691db97756772bb1eb9678fa585d9184f24534b100dc60f4a"},
-]
-werkzeug = [
- {file = "Werkzeug-1.0.1-py2.py3-none-any.whl", hash = "sha256:2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43"},
- {file = "Werkzeug-1.0.1.tar.gz", hash = "sha256:6c80b1e5ad3665290ea39320b91e1be1e0d5f60652b964a3070216de83d2e47c"},
-]
-zipp = [
- {file = "zipp-3.1.0-py3-none-any.whl", hash = "sha256:aa36550ff0c0b7ef7fa639055d797116ee891440eac1a56f378e2d3179e0320b"},
- {file = "zipp-3.1.0.tar.gz", hash = "sha256:c599e4d75c98f6798c509911d08a22e6c021d074469042177c8c86fb92eefd96"},
-]
diff --git a/setup.cfg b/setup.cfg
deleted file mode 100644
index 0a8df87a..00000000
--- a/setup.cfg
+++ /dev/null
@@ -1,2 +0,0 @@
-[wheel]
-universal = 1 \ No newline at end of file
diff --git a/setup.py b/setup.py
deleted file mode 100644
index ebecd40b..00000000
--- a/setup.py
+++ /dev/null
@@ -1,98 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-"""
-OnionShare | https://onionshare.org/
-
-Copyright (C) 2014-2020 Micah Lee, et al. <micah@micahflee.com>
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see <http://www.gnu.org/licenses/>.
-"""
-
-import os, sys, platform, tempfile
-from distutils.core import setup
-
-
-def file_list(path):
- files = []
- for filename in os.listdir(path):
- if os.path.isfile(os.path.join(path, filename)):
- files.append(os.path.join(path, filename))
- return files
-
-
-version = open("share/version.txt").read().strip()
-description = "OnionShare is an open source tool that lets you securely and anonymously share files, host websites, and chat with friends using the Tor network."
-
-author = "Micah Lee"
-author_email = "micah@micahflee.com"
-url = "https://onionshare.org"
-license = "GPL v3"
-keywords = "onion, share, onionshare, tor, anonymous, web server"
-classifiers = [
- "Programming Language :: Python :: 3",
- "Framework :: Flask",
- "Topic :: Communications :: File Sharing",
- "Topic :: Security :: Cryptography",
- "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
- "Intended Audience :: End Users/Desktop",
- "Operating System :: OS Independent",
- "Environment :: Web Environment",
-]
-data_files = [
- ("share/applications", ["install/org.onionshare.OnionShare.desktop"],),
- ("share/icons/hicolor/512x512/apps", ["install/org.onionshare.OnionShare.png"],),
- ("share/metainfo", ["install/org.onionshare.OnionShare.appdata.xml"],),
- ("share/onionshare", file_list("share")),
- ("share/onionshare/images", file_list("share/images")),
- ("share/onionshare/locale", file_list("share/locale")),
- ("share/onionshare/templates", file_list("share/templates"),),
- ("share/onionshare/static/css", file_list("share/static/css"),),
- ("share/onionshare/static/img", file_list("share/static/img"),),
- ("share/onionshare/static/js", file_list("share/static/js"),),
-]
-if not platform.system().endswith("BSD") and platform.system() != "DragonFly":
- data_files.append(
- (
- "share/nautilus-python/extensions/",
- ["install/scripts/onionshare-nautilus.py"],
- )
- )
-
-setup(
- name="onionshare",
- version=version,
- description=description,
- author=author,
- author_email=author_email,
- maintainer=author,
- maintainer_email=author_email,
- url=url,
- license=license,
- keywords=keywords,
- classifiers=classifiers,
- packages=[
- "onionshare",
- "onionshare.web",
- "onionshare_gui",
- "onionshare_gui.tab",
- "onionshare_gui.tab.mode",
- "onionshare_gui.tab.mode.share_mode",
- "onionshare_gui.tab.mode.receive_mode",
- "onionshare_gui.tab.mode.website_mode",
- "onionshare_gui.tab.mode.chat_mode",
- ],
- include_package_data=True,
- scripts=["install/scripts/onionshare", "install/scripts/onionshare-gui"],
- data_files=data_files,
-)
diff --git a/share/version.txt b/share/version.txt
deleted file mode 100644
index 4804c3be..00000000
--- a/share/version.txt
+++ /dev/null
@@ -1 +0,0 @@
-2.3.dev1 \ No newline at end of file
diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml
new file mode 100644
index 00000000..e53cd449
--- /dev/null
+++ b/snap/snapcraft.yaml
@@ -0,0 +1,147 @@
+name: onionshare
+base: core18
+version: '2.3.dev2'
+summary: Securely and anonymously share files, host websites, and chat using Tor
+description: |
+ OnionShare lets you securely and anonymously send and receive files. It works by starting
+ a web server, making it accessible as a Tor onion service, and generating an unguessable
+ web address so others can download files from you, or upload files to you. It does _not_
+ require setting up a separate server or using a third party file-sharing service.
+
+grade: devel # must be 'stable' to release into candidate/stable channels
+confinement: strict
+
+apps:
+ onionshare:
+ common-id: org.onionshare.OnionShare
+ command: onionshare
+ plugs:
+ - desktop
+ - home
+ - network
+ - network-bind
+ - removable-media
+ extensions:
+ - gnome-3-34
+
+ cli:
+ common-id: org.onionshare.OnionShareCli
+ command: onionshare-cli
+ plugs:
+ - home
+ - network
+ - network-bind
+ - removable-media
+
+parts:
+ onionshare:
+ source: ./desktop/src
+ plugin: python
+ python-version: python3
+ python-packages:
+ - psutil
+ - pyside2==5.15.1
+ - qrcode
+ stage-packages:
+ - libasound2
+ - libatk1.0-0
+ - libcairo2
+ - libcairo-gobject2
+ - libcups2
+ - libdrm2
+ - libegl1
+ - libfreetype6
+ - libgdk-pixbuf2.0-0
+ - libgl1
+ - libglvnd0
+ - libglx0
+ - libgtk-3-0
+ - libharfbuzz0b
+ - libicu60
+ - libjpeg8
+ - liblcms2-2
+ - libnspr4
+ - libnss3
+ - libodbc1
+ - libpango-1.0-0
+ - libpangocairo-1.0-0
+ - libpng16-16
+ - libpq5
+ - libpulse-mainloop-glib0
+ - librsvg2-2
+ - libspeechd2
+ - libwayland-client0
+ - libwayland-cursor0
+ - libwayland-egl1
+ - libwayland-server0
+ - libx11-6
+ - libx11-xcb1
+ - libxau6
+ - libxcb1
+ - libxcb-glx0
+ - libxcb-icccm4
+ - libxcb-image0
+ - libxcb-keysyms1
+ - libxcb-render0
+ - libxcb-render-util0
+ - libxcb-shm0
+ - libxcb-sync1
+ - libxcb-xfixes0
+ - libxcb-xinerama0
+ - libxcb-xkb1
+ - libxcomposite1
+ - libxcursor1
+ - libxdamage1
+ - libxdmcp6
+ - libxext6
+ - libxfixes3
+ - libxi6
+ - libxkbcommon0
+ - libxkbcommon-x11-0
+ - libxml2
+ - libxrandr2
+ - libxrender1
+ - libxslt1.1
+ - libxtst6
+ after: [onionshare-cli, tor, obfs4]
+
+ onionshare-cli:
+ source: ./cli
+ plugin: python
+ python-version: python3
+ python-packages:
+ - poetry
+ - click
+ - flask
+ - flask-httpauth
+ - flask-socketio
+ - pycryptodome
+ - pysocks
+ - requests
+ - stem
+ - urllib3
+ - eventlet
+ after: [tor, obfs4]
+
+ tor:
+ source: https://dist.torproject.org/tor-0.4.4.5.tar.gz
+ source-checksum: sha256/a45ca00afe765e3baa839767c9dd6ac9a46dd01720a3a8ff4d86558c12359926
+ source-type: tar
+ plugin: autotools
+ build-packages:
+ - libssl-dev
+ - zlib1g-dev
+ after: [libevent]
+
+ libevent:
+ source: https://github.com/libevent/libevent/releases/download/release-2.1.12-stable/libevent-2.1.12-stable.tar.gz
+ source-checksum: sha256/92e6de1be9ec176428fd2367677e61ceffc2ee1cb119035037a27d346b0403bb
+ source-type: tar
+ plugin: autotools
+
+ obfs4:
+ source: pass
+ plugin: go
+ go-importpath: gitlab.com/yawning/obfs4
+ source: https://gitlab.com/yawning/obfs4
+ source-type: git
diff --git a/stdeb.cfg b/stdeb.cfg
deleted file mode 100644
index dd59abf6..00000000
--- a/stdeb.cfg
+++ /dev/null
@@ -1,6 +0,0 @@
-[DEFAULT]
-Package3: onionshare
-Depends3: python3, python3-flask, python3-flask-httpauth, python3-stem, python3-pyqt5, python3-crypto, python3-socks, python3-distutils, python3-nautilus, tor, obfs4proxy, python3-psutil, python3-socketio, python3-flask-socketio, python3-qrcode
-Build-Depends: python3, python3-all, python3-pytest, python3-requests, python3-flask, python3-flask-httpauth, python3-stem, python3-pyqt5, python3-crypto, python3-socks, python3-distutils, python3-psutil, python3-socketio, python3-flask-socketio, python3-qrcode
-Suite: disco
-X-Python3-Version: >= 3.6
diff --git a/tests/run.bat b/tests/run.bat
deleted file mode 100644
index 5db3f14a..00000000
--- a/tests/run.bat
+++ /dev/null
@@ -1,9 +0,0 @@
-pytest -vvv tests\test_cli.py
-pytest -vvv tests\test_cli_common.py
-pytest -vvv tests\test_cli_settings.py
-pytest -vvv tests\test_cli_strings.py
-pytest -vvv tests\test_cli_web.py
-pytest -vvv --rungui tests\test_gui_tabs.py
-pytest -vvv --rungui tests\test_gui_share.py
-pytest -vvv --rungui tests\test_gui_receive.py
-pytest -vvv --rungui tests\test_gui_website.py
diff --git a/tests/run.sh b/tests/run.sh
deleted file mode 100755
index 184dfc16..00000000
--- a/tests/run.sh
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/bin/bash
-
-# The script runs python tests
-# Firstly, all CLI tests are run
-# Then, all the GUI tests are run individually
-# to avoid segmentation fault
-
-PARAMS=""
-
-while [ ! $# -eq 0 ]
-do
- case "$1" in
- --rungui)
- PARAMS="$PARAMS --rungui"
- ;;
- --runtor)
- PARAMS="$PARAMS --runtor"
- ;;
- esac
- shift
-done
-
-pytest $PARAMS -vvv ./tests/test_cli*.py || exit 1
-for filename in ./tests/test_gui_*.py; do
- pytest $PARAMS -vvv --no-qt-log $filename || exit 1
-done
diff --git a/tests/test_cli_strings.py b/tests/test_cli_strings.py
deleted file mode 100644
index 8c90240f..00000000
--- a/tests/test_cli_strings.py
+++ /dev/null
@@ -1,46 +0,0 @@
-# -*- coding: utf-8 -*-
-import types
-
-import pytest
-
-from onionshare import strings
-from onionshare.settings import Settings
-
-# # Stub get_resource_path so it finds the correct path while running tests
-# def get_resource_path(filename):
-# resources_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'share')
-# path = os.path.join(resources_dir, filename)
-# return path
-# common.get_resource_path = get_resource_path
-
-
-def test_underscore_is_function():
- assert callable(strings._) and isinstance(strings._, types.FunctionType)
-
-
-class TestLoadStrings:
- def test_load_strings_defaults_to_english(
- self, common_obj, locale_en, sys_onionshare_dev_mode
- ):
- """ load_strings() loads English by default """
- common_obj.settings = Settings(common_obj)
- strings.load_strings(common_obj)
- assert strings._("not_a_readable_file") == "{0:s} is not a readable file."
-
- def test_load_strings_loads_other_languages(
- self, common_obj, locale_fr, sys_onionshare_dev_mode
- ):
- """ load_strings() loads other languages in different locales """
- common_obj.settings = Settings(common_obj)
- common_obj.settings.set("locale", "fr")
- strings.load_strings(common_obj)
- assert strings._("not_a_readable_file") == "{0:s} n’est pas un fichier lisible."
-
- def test_load_invalid_locale(
- self, common_obj, locale_invalid, sys_onionshare_dev_mode
- ):
- """ load_strings() raises a KeyError for an invalid locale """
- with pytest.raises(KeyError):
- common_obj.settings = Settings(common_obj)
- common_obj.settings.set("locale", "XX")
- strings.load_strings(common_obj)