diff options
-rw-r--r-- | .circleci/config.yml | 68 | ||||
-rw-r--r-- | .circleci/qt-installer-script.js | 75 | ||||
-rw-r--r-- | .gitignore | 11 | ||||
-rw-r--r-- | BUILD.md | 419 | ||||
-rw-r--r-- | CHANGELOG.md | 2 | ||||
-rw-r--r-- | MANIFEST.in | 13 | ||||
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | RELEASE.md | 234 | ||||
-rw-r--r-- | apparmor/abstractions/onionshare | 29 | ||||
-rw-r--r-- | apparmor/local/usr.bin.onionshare | 2 | ||||
-rw-r--r-- | apparmor/local/usr.bin.onionshare-gui | 2 | ||||
-rw-r--r-- | apparmor/usr.bin.onionshare | 10 | ||||
-rw-r--r-- | apparmor/usr.bin.onionshare-gui | 28 | ||||
-rwxr-xr-x | build-source.sh (renamed from install/build_source.sh) | 5 | ||||
-rw-r--r-- | cli/.circleci/config.yml | 38 | ||||
-rw-r--r-- | cli/README.md | 68 | ||||
-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) | bin | 847 -> 847 bytes | |||
-rw-r--r-- | cli/onionshare_cli/resources/static/img/favicon.ico (renamed from share/static/img/favicon.ico) | bin | 4286 -> 4286 bytes | |||
-rw-r--r-- | cli/onionshare_cli/resources/static/img/logo.png (renamed from share/images/logo.png) | bin | 3824 -> 3824 bytes | |||
-rw-r--r-- | cli/onionshare_cli/resources/static/img/logo_large.png (renamed from share/static/img/logo_large.png) | bin | 9663 -> 9663 bytes | |||
-rw-r--r-- | cli/onionshare_cli/resources/static/img/web_file.png (renamed from share/static/img/web_file.png) | bin | 251 -> 251 bytes | |||
-rw-r--r-- | cli/onionshare_cli/resources/static/img/web_folder.png (renamed from share/static/img/web_folder.png) | bin | 338 -> 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.txt | 1 | ||||
-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.lock | 603 | ||||
-rw-r--r-- | cli/pyproject.toml (renamed from pyproject.toml) | 58 | ||||
-rw-r--r-- | cli/setup.py | 70 | ||||
-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.md | 113 | ||||
-rwxr-xr-x | desktop/check_lacked_trans.py (renamed from install/check_lacked_trans.py) | 0 | ||||
-rwxr-xr-x | desktop/package/linux/build-appimage.py | 47 | ||||
-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-x | desktop/package/macos/build.py | 131 | ||||
-rw-r--r-- | desktop/package/windows/build.py | 66 | ||||
-rw-r--r-- | desktop/pyproject.toml | 42 | ||||
-rw-r--r-- | desktop/screenshots/appdata-onionshare-receive-client.png (renamed from screenshots/appdata-onionshare-receive-client.png) | bin | 361337 -> 361337 bytes | |||
-rw-r--r-- | desktop/screenshots/appdata-onionshare-receive-server.png (renamed from screenshots/appdata-onionshare-receive-server.png) | bin | 340924 -> 340924 bytes | |||
-rw-r--r-- | desktop/screenshots/appdata-onionshare-share-client.png (renamed from screenshots/appdata-onionshare-share-client.png) | bin | 372511 -> 372511 bytes | |||
-rw-r--r-- | desktop/screenshots/appdata-onionshare-share-server.png (renamed from screenshots/appdata-onionshare-share-server.png) | bin | 526914 -> 526914 bytes | |||
-rw-r--r-- | desktop/screenshots/onionshare-receive-client.png (renamed from screenshots/onionshare-receive-client.png) | bin | 589481 -> 589481 bytes | |||
-rw-r--r-- | desktop/screenshots/onionshare-receive-server.png (renamed from screenshots/onionshare-receive-server.png) | bin | 569260 -> 569260 bytes | |||
-rw-r--r-- | desktop/screenshots/onionshare-share-client.png (renamed from screenshots/onionshare-share-client.png) | bin | 43404 -> 43404 bytes | |||
-rw-r--r-- | desktop/screenshots/onionshare-share-server.png (renamed from screenshots/onionshare-share-server.png) | bin | 57758 -> 57758 bytes | |||
-rw-r--r-- | desktop/screenshots/onionshare-website-server.png (renamed from screenshots/onionshare-website-server.png) | bin | 148709 -> 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__.py | 0 | ||||
-rw-r--r-- | desktop/src/onionshare/resources/images/close_tab.png (renamed from share/images/close_tab.png) | bin | 688 -> 688 bytes | |||
-rw-r--r-- | desktop/src/onionshare/resources/images/file_delete.png (renamed from share/images/file_delete.png) | bin | 182 -> 182 bytes | |||
-rw-r--r-- | desktop/src/onionshare/resources/images/history_completed.png (renamed from share/images/history_completed.png) | bin | 646 -> 646 bytes | |||
-rw-r--r-- | desktop/src/onionshare/resources/images/history_completed_none.png (renamed from share/images/history_completed_none.png) | bin | 437 -> 437 bytes | |||
-rw-r--r-- | desktop/src/onionshare/resources/images/history_in_progress.png (renamed from share/images/history_in_progress.png) | bin | 638 -> 638 bytes | |||
-rw-r--r-- | desktop/src/onionshare/resources/images/history_in_progress_none.png (renamed from share/images/history_in_progress_none.png) | bin | 412 -> 412 bytes | |||
-rw-r--r-- | desktop/src/onionshare/resources/images/history_requests.png (renamed from share/images/history_requests.png) | bin | 738 -> 738 bytes | |||
-rw-r--r-- | desktop/src/onionshare/resources/images/history_requests_none.png (renamed from share/images/history_requests_none.png) | bin | 754 -> 754 bytes | |||
-rw-r--r-- | desktop/src/onionshare/resources/images/info.png (renamed from share/images/info.png) | bin | 435 -> 435 bytes | |||
-rw-r--r-- | desktop/src/onionshare/resources/images/logo.png (renamed from share/static/img/logo.png) | bin | 3824 -> 3824 bytes | |||
-rw-r--r-- | desktop/src/onionshare/resources/images/logo_grayscale.png (renamed from share/images/logo_grayscale.png) | bin | 2258 -> 2258 bytes | |||
-rw-r--r-- | desktop/src/onionshare/resources/images/logo_text.png (renamed from share/images/logo_text.png) | bin | 3798 -> 3798 bytes | |||
-rw-r--r-- | desktop/src/onionshare/resources/images/logo_transparent.png (renamed from share/images/logo_transparent.png) | bin | 3740 -> 3740 bytes | |||
-rw-r--r-- | desktop/src/onionshare/resources/images/mode_chat.png (renamed from share/images/mode_chat.png) | bin | 27306 -> 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) | bin | 5213 -> 5213 bytes | |||
-rw-r--r-- | desktop/src/onionshare/resources/images/mode_new_tab_receive.png (renamed from share/images/mode_new_tab_receive.png) | bin | 6470 -> 6470 bytes | |||
-rw-r--r-- | desktop/src/onionshare/resources/images/mode_new_tab_share.png (renamed from share/images/mode_new_tab_share.png) | bin | 4485 -> 4485 bytes | |||
-rw-r--r-- | desktop/src/onionshare/resources/images/mode_new_tab_website.png (renamed from share/images/mode_new_tab_website.png) | bin | 3860 -> 3860 bytes | |||
-rw-r--r-- | desktop/src/onionshare/resources/images/mode_receive.png (renamed from share/images/mode_receive.png) | bin | 37288 -> 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) | bin | 9472 -> 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) | bin | 8126 -> 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) | bin | 221 -> 221 bytes | |||
-rw-r--r-- | desktop/src/onionshare/resources/images/persistent_enabled.png (renamed from share/images/persistent_enabled.png) | bin | 3398 -> 3398 bytes | |||
-rw-r--r-- | desktop/src/onionshare/resources/images/receive_icon_toggle.png (renamed from share/images/receive_icon_toggle.png) | bin | 380 -> 380 bytes | |||
-rw-r--r-- | desktop/src/onionshare/resources/images/receive_icon_toggle_selected.png (renamed from share/images/receive_icon_toggle_selected.png) | bin | 468 -> 468 bytes | |||
-rw-r--r-- | desktop/src/onionshare/resources/images/receive_icon_transparent.png (renamed from share/images/receive_icon_transparent.png) | bin | 2138 -> 2138 bytes | |||
-rw-r--r-- | desktop/src/onionshare/resources/images/server_started.png (renamed from share/images/server_started.png) | bin | 347 -> 347 bytes | |||
-rw-r--r-- | desktop/src/onionshare/resources/images/server_stopped.png (renamed from share/images/server_stopped.png) | bin | 342 -> 342 bytes | |||
-rw-r--r-- | desktop/src/onionshare/resources/images/server_working.png (renamed from share/images/server_working.png) | bin | 349 -> 349 bytes | |||
-rw-r--r-- | desktop/src/onionshare/resources/images/settings.png (renamed from share/images/settings.png) | bin | 1157 -> 1157 bytes | |||
-rw-r--r-- | desktop/src/onionshare/resources/images/share_icon_toggle.png (renamed from share/images/share_icon_toggle.png) | bin | 389 -> 389 bytes | |||
-rw-r--r-- | desktop/src/onionshare/resources/images/share_icon_toggle_selected.png (renamed from share/images/share_icon_toggle_selected.png) | bin | 473 -> 473 bytes | |||
-rw-r--r-- | desktop/src/onionshare/resources/images/share_icon_transparent.png (renamed from share/images/share_icon_transparent.png) | bin | 2096 -> 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.png | bin | 0 -> 12788 bytes | |||
-rw-r--r-- | desktop/src/onionshare/resources/onionshare-16.png | bin | 0 -> 2437 bytes | |||
-rw-r--r-- | desktop/src/onionshare/resources/onionshare-256.png | bin | 0 -> 19034 bytes | |||
-rw-r--r-- | desktop/src/onionshare/resources/onionshare-32.png | bin | 0 -> 4051 bytes | |||
-rw-r--r-- | desktop/src/onionshare/resources/onionshare-512.png (renamed from install/org.onionshare.OnionShare.png) | bin | 24613 -> 24613 bytes | |||
-rw-r--r-- | desktop/src/onionshare/resources/onionshare-64.png | bin | 0 -> 8486 bytes | |||
-rw-r--r-- | desktop/src/onionshare/resources/onionshare.icns (renamed from install/onionshare.icns) | bin | 34168 -> 34168 bytes | |||
-rw-r--r-- | desktop/src/onionshare/resources/onionshare.ico (renamed from install/onionshare.ico) | bin | 15086 -> 15086 bytes | |||
-rw-r--r-- | desktop/src/onionshare/resources/onionshare.png | bin | 0 -> 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.py | 72 | ||||
-rw-r--r-- | desktop/tests/__init__.py | 0 | ||||
-rw-r--r-- | desktop/tests/conftest.py | 222 | ||||
-rw-r--r-- | desktop/tests/gui_base_test.py (renamed from tests/gui_base_test.py) | 32 | ||||
-rw-r--r-- | desktop/tests/run.bat | 4 | ||||
-rwxr-xr-x | desktop/tests/run.sh | 5 | ||||
-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-x | dev_scripts/onionshare | 30 | ||||
-rwxr-xr-x | dev_scripts/onionshare-gui | 30 | ||||
-rw-r--r-- | docs/pyproject.toml | 2 | ||||
-rw-r--r-- | docs/source/conf.py | 2 | ||||
-rw-r--r-- | docs/source/install.rst | 20 | ||||
-rw-r--r-- | flatpak/org.onionshare.OnionShare.yaml | 321 | ||||
-rw-r--r-- | git-hooks/README.md | 3 | ||||
-rwxr-xr-x | git-hooks/pre-push | 4 | ||||
-rwxr-xr-x | install/build_deb.sh | 25 | ||||
-rw-r--r-- | install/build_exe.bat | 17 | ||||
-rwxr-xr-x | install/build_osx.sh | 55 | ||||
-rwxr-xr-x | install/build_rpm.sh | 17 | ||||
-rw-r--r-- | install/onionshare.nsi | 111 | ||||
-rw-r--r-- | install/onionshare80.xpm | 257 | ||||
-rw-r--r-- | install/org.onionshare.OnionShare.svg | 2154 | ||||
-rwxr-xr-x | install/ppa_release.sh | 18 | ||||
-rw-r--r-- | install/pyinstaller.spec | 67 | ||||
-rwxr-xr-x | install/scripts/onionshare-gui | 23 | ||||
-rw-r--r-- | install/scripts/onionshare-nautilus.py | 105 | ||||
-rw-r--r-- | install/scripts/onionshare-pyinstaller | 47 | ||||
-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.lock | 956 | ||||
-rw-r--r-- | setup.cfg | 2 | ||||
-rw-r--r-- | setup.py | 98 | ||||
-rw-r--r-- | share/version.txt | 1 | ||||
-rw-r--r-- | snap/snapcraft.yaml | 147 | ||||
-rw-r--r-- | stdeb.cfg | 6 | ||||
-rw-r--r-- | tests/run.bat | 9 | ||||
-rwxr-xr-x | tests/run.sh | 26 | ||||
-rw-r--r-- | tests/test_cli_strings.py | 46 |
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() -} @@ -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 @@ -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 Binary files differindex 01d955aa..01d955aa 100644 --- a/share/static/img/ajax.gif +++ b/cli/onionshare_cli/resources/static/img/ajax.gif diff --git a/share/static/img/favicon.ico b/cli/onionshare_cli/resources/static/img/favicon.ico Binary files differindex 63e65d8b..63e65d8b 100644 --- a/share/static/img/favicon.ico +++ b/cli/onionshare_cli/resources/static/img/favicon.ico diff --git a/share/images/logo.png b/cli/onionshare_cli/resources/static/img/logo.png Binary files differindex 43884c1f..43884c1f 100644 --- a/share/images/logo.png +++ b/cli/onionshare_cli/resources/static/img/logo.png diff --git a/share/static/img/logo_large.png b/cli/onionshare_cli/resources/static/img/logo_large.png Binary files differindex ee8f26ac..ee8f26ac 100644 --- a/share/static/img/logo_large.png +++ b/cli/onionshare_cli/resources/static/img/logo_large.png diff --git a/share/static/img/web_file.png b/cli/onionshare_cli/resources/static/img/web_file.png Binary files differindex 1931aff0..1931aff0 100644 --- a/share/static/img/web_file.png +++ b/cli/onionshare_cli/resources/static/img/web_file.png diff --git a/share/static/img/web_folder.png b/cli/onionshare_cli/resources/static/img/web_folder.png Binary files differindex 3ca5df21..3ca5df21 100644 --- a/share/static/img/web_folder.png +++ b/cli/onionshare_cli/resources/static/img/web_folder.png 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 Binary files differindex 8edcc326..8edcc326 100644 --- a/screenshots/appdata-onionshare-receive-client.png +++ b/desktop/screenshots/appdata-onionshare-receive-client.png diff --git a/screenshots/appdata-onionshare-receive-server.png b/desktop/screenshots/appdata-onionshare-receive-server.png Binary files differindex 121eab48..121eab48 100644 --- a/screenshots/appdata-onionshare-receive-server.png +++ b/desktop/screenshots/appdata-onionshare-receive-server.png diff --git a/screenshots/appdata-onionshare-share-client.png b/desktop/screenshots/appdata-onionshare-share-client.png Binary files differindex c57fb2a8..c57fb2a8 100644 --- a/screenshots/appdata-onionshare-share-client.png +++ b/desktop/screenshots/appdata-onionshare-share-client.png diff --git a/screenshots/appdata-onionshare-share-server.png b/desktop/screenshots/appdata-onionshare-share-server.png Binary files differindex d85e45ce..d85e45ce 100644 --- a/screenshots/appdata-onionshare-share-server.png +++ b/desktop/screenshots/appdata-onionshare-share-server.png diff --git a/screenshots/onionshare-receive-client.png b/desktop/screenshots/onionshare-receive-client.png Binary files differindex 648d67ae..648d67ae 100644 --- a/screenshots/onionshare-receive-client.png +++ b/desktop/screenshots/onionshare-receive-client.png diff --git a/screenshots/onionshare-receive-server.png b/desktop/screenshots/onionshare-receive-server.png Binary files differindex 0e801d3d..0e801d3d 100644 --- a/screenshots/onionshare-receive-server.png +++ b/desktop/screenshots/onionshare-receive-server.png diff --git a/screenshots/onionshare-share-client.png b/desktop/screenshots/onionshare-share-client.png Binary files differindex 58f102d4..58f102d4 100644 --- a/screenshots/onionshare-share-client.png +++ b/desktop/screenshots/onionshare-share-client.png diff --git a/screenshots/onionshare-share-server.png b/desktop/screenshots/onionshare-share-server.png Binary files differindex 329fc8af..329fc8af 100644 --- a/screenshots/onionshare-share-server.png +++ b/desktop/screenshots/onionshare-share-server.png diff --git a/screenshots/onionshare-website-server.png b/desktop/screenshots/onionshare-website-server.png Binary files differindex 55e4fa27..55e4fa27 100644 --- a/screenshots/onionshare-website-server.png +++ b/desktop/screenshots/onionshare-website-server.png 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 Binary files differindex a7984a6d..a7984a6d 100644 --- a/share/images/close_tab.png +++ b/desktop/src/onionshare/resources/images/close_tab.png diff --git a/share/images/file_delete.png b/desktop/src/onionshare/resources/images/file_delete.png Binary files differindex b9057df5..b9057df5 100644 --- a/share/images/file_delete.png +++ b/desktop/src/onionshare/resources/images/file_delete.png diff --git a/share/images/history_completed.png b/desktop/src/onionshare/resources/images/history_completed.png Binary files differindex e68fe5a2..e68fe5a2 100644 --- a/share/images/history_completed.png +++ b/desktop/src/onionshare/resources/images/history_completed.png diff --git a/share/images/history_completed_none.png b/desktop/src/onionshare/resources/images/history_completed_none.png Binary files differindex 8dbd6939..8dbd6939 100644 --- a/share/images/history_completed_none.png +++ b/desktop/src/onionshare/resources/images/history_completed_none.png diff --git a/share/images/history_in_progress.png b/desktop/src/onionshare/resources/images/history_in_progress.png Binary files differindex 19694659..19694659 100644 --- a/share/images/history_in_progress.png +++ b/desktop/src/onionshare/resources/images/history_in_progress.png diff --git a/share/images/history_in_progress_none.png b/desktop/src/onionshare/resources/images/history_in_progress_none.png Binary files differindex 2d61dba4..2d61dba4 100644 --- a/share/images/history_in_progress_none.png +++ b/desktop/src/onionshare/resources/images/history_in_progress_none.png diff --git a/share/images/history_requests.png b/desktop/src/onionshare/resources/images/history_requests.png Binary files differindex 4965744d..4965744d 100644 --- a/share/images/history_requests.png +++ b/desktop/src/onionshare/resources/images/history_requests.png diff --git a/share/images/history_requests_none.png b/desktop/src/onionshare/resources/images/history_requests_none.png Binary files differindex 93a71ef3..93a71ef3 100644 --- a/share/images/history_requests_none.png +++ b/desktop/src/onionshare/resources/images/history_requests_none.png diff --git a/share/images/info.png b/desktop/src/onionshare/resources/images/info.png Binary files differindex 4be4e65e..4be4e65e 100644 --- a/share/images/info.png +++ b/desktop/src/onionshare/resources/images/info.png diff --git a/share/static/img/logo.png b/desktop/src/onionshare/resources/images/logo.png Binary files differindex 43884c1f..43884c1f 100644 --- a/share/static/img/logo.png +++ b/desktop/src/onionshare/resources/images/logo.png diff --git a/share/images/logo_grayscale.png b/desktop/src/onionshare/resources/images/logo_grayscale.png Binary files differindex 950d9ff6..950d9ff6 100644 --- a/share/images/logo_grayscale.png +++ b/desktop/src/onionshare/resources/images/logo_grayscale.png diff --git a/share/images/logo_text.png b/desktop/src/onionshare/resources/images/logo_text.png Binary files differindex 3b584acd..3b584acd 100644 --- a/share/images/logo_text.png +++ b/desktop/src/onionshare/resources/images/logo_text.png diff --git a/share/images/logo_transparent.png b/desktop/src/onionshare/resources/images/logo_transparent.png Binary files differindex 1e8ed196..1e8ed196 100644 --- a/share/images/logo_transparent.png +++ b/desktop/src/onionshare/resources/images/logo_transparent.png diff --git a/share/images/mode_chat.png b/desktop/src/onionshare/resources/images/mode_chat.png Binary files differindex 33114364..33114364 100644 --- a/share/images/mode_chat.png +++ b/desktop/src/onionshare/resources/images/mode_chat.png 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 Binary files differindex 50759d64..50759d64 100644 --- a/share/images/mode_new_tab_chat.png +++ b/desktop/src/onionshare/resources/images/mode_new_tab_chat.png diff --git a/share/images/mode_new_tab_receive.png b/desktop/src/onionshare/resources/images/mode_new_tab_receive.png Binary files differindex 9db809be..9db809be 100644 --- a/share/images/mode_new_tab_receive.png +++ b/desktop/src/onionshare/resources/images/mode_new_tab_receive.png diff --git a/share/images/mode_new_tab_share.png b/desktop/src/onionshare/resources/images/mode_new_tab_share.png Binary files differindex 92973175..92973175 100644 --- a/share/images/mode_new_tab_share.png +++ b/desktop/src/onionshare/resources/images/mode_new_tab_share.png diff --git a/share/images/mode_new_tab_website.png b/desktop/src/onionshare/resources/images/mode_new_tab_website.png Binary files differindex 86b45f66..86b45f66 100644 --- a/share/images/mode_new_tab_website.png +++ b/desktop/src/onionshare/resources/images/mode_new_tab_website.png diff --git a/share/images/mode_receive.png b/desktop/src/onionshare/resources/images/mode_receive.png Binary files differindex d57aa409..d57aa409 100644 --- a/share/images/mode_receive.png +++ b/desktop/src/onionshare/resources/images/mode_receive.png 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 Binary files differindex ec287db4..ec287db4 100644 --- a/share/images/mode_share.png +++ b/desktop/src/onionshare/resources/images/mode_share.png 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 Binary files differindex 37a556d9..37a556d9 100644 --- a/share/images/mode_website.png +++ b/desktop/src/onionshare/resources/images/mode_website.png 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 Binary files differindex 0a734c41..0a734c41 100644 --- a/share/images/open_folder.png +++ b/desktop/src/onionshare/resources/images/open_folder.png diff --git a/share/images/persistent_enabled.png b/desktop/src/onionshare/resources/images/persistent_enabled.png Binary files differindex 6c295db5..6c295db5 100644 --- a/share/images/persistent_enabled.png +++ b/desktop/src/onionshare/resources/images/persistent_enabled.png diff --git a/share/images/receive_icon_toggle.png b/desktop/src/onionshare/resources/images/receive_icon_toggle.png Binary files differindex 846ececb..846ececb 100644 --- a/share/images/receive_icon_toggle.png +++ b/desktop/src/onionshare/resources/images/receive_icon_toggle.png diff --git a/share/images/receive_icon_toggle_selected.png b/desktop/src/onionshare/resources/images/receive_icon_toggle_selected.png Binary files differindex 127ce208..127ce208 100644 --- a/share/images/receive_icon_toggle_selected.png +++ b/desktop/src/onionshare/resources/images/receive_icon_toggle_selected.png diff --git a/share/images/receive_icon_transparent.png b/desktop/src/onionshare/resources/images/receive_icon_transparent.png Binary files differindex 99207097..99207097 100644 --- a/share/images/receive_icon_transparent.png +++ b/desktop/src/onionshare/resources/images/receive_icon_transparent.png diff --git a/share/images/server_started.png b/desktop/src/onionshare/resources/images/server_started.png Binary files differindex 9c0c3176..9c0c3176 100644 --- a/share/images/server_started.png +++ b/desktop/src/onionshare/resources/images/server_started.png diff --git a/share/images/server_stopped.png b/desktop/src/onionshare/resources/images/server_stopped.png Binary files differindex 5c5b2ec0..5c5b2ec0 100644 --- a/share/images/server_stopped.png +++ b/desktop/src/onionshare/resources/images/server_stopped.png diff --git a/share/images/server_working.png b/desktop/src/onionshare/resources/images/server_working.png Binary files differindex e5c8b318..e5c8b318 100644 --- a/share/images/server_working.png +++ b/desktop/src/onionshare/resources/images/server_working.png diff --git a/share/images/settings.png b/desktop/src/onionshare/resources/images/settings.png Binary files differindex b6f8fa55..b6f8fa55 100644 --- a/share/images/settings.png +++ b/desktop/src/onionshare/resources/images/settings.png diff --git a/share/images/share_icon_toggle.png b/desktop/src/onionshare/resources/images/share_icon_toggle.png Binary files differindex 87303c9f..87303c9f 100644 --- a/share/images/share_icon_toggle.png +++ b/desktop/src/onionshare/resources/images/share_icon_toggle.png diff --git a/share/images/share_icon_toggle_selected.png b/desktop/src/onionshare/resources/images/share_icon_toggle_selected.png Binary files differindex 0ba52cff..0ba52cff 100644 --- a/share/images/share_icon_toggle_selected.png +++ b/desktop/src/onionshare/resources/images/share_icon_toggle_selected.png diff --git a/share/images/share_icon_transparent.png b/desktop/src/onionshare/resources/images/share_icon_transparent.png Binary files differindex 3648c3fb..3648c3fb 100644 --- a/share/images/share_icon_transparent.png +++ b/desktop/src/onionshare/resources/images/share_icon_transparent.png 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 Binary files differnew file mode 100644 index 00000000..856ab4e7 --- /dev/null +++ b/desktop/src/onionshare/resources/onionshare-128.png diff --git a/desktop/src/onionshare/resources/onionshare-16.png b/desktop/src/onionshare/resources/onionshare-16.png Binary files differnew file mode 100644 index 00000000..dea20940 --- /dev/null +++ b/desktop/src/onionshare/resources/onionshare-16.png diff --git a/desktop/src/onionshare/resources/onionshare-256.png b/desktop/src/onionshare/resources/onionshare-256.png Binary files differnew file mode 100644 index 00000000..b47cd94a --- /dev/null +++ b/desktop/src/onionshare/resources/onionshare-256.png diff --git a/desktop/src/onionshare/resources/onionshare-32.png b/desktop/src/onionshare/resources/onionshare-32.png Binary files differnew file mode 100644 index 00000000..14c849c9 --- /dev/null +++ b/desktop/src/onionshare/resources/onionshare-32.png diff --git a/install/org.onionshare.OnionShare.png b/desktop/src/onionshare/resources/onionshare-512.png Binary files differindex a4810d04..a4810d04 100644 --- a/install/org.onionshare.OnionShare.png +++ b/desktop/src/onionshare/resources/onionshare-512.png diff --git a/desktop/src/onionshare/resources/onionshare-64.png b/desktop/src/onionshare/resources/onionshare-64.png Binary files differnew file mode 100644 index 00000000..8468dc52 --- /dev/null +++ b/desktop/src/onionshare/resources/onionshare-64.png diff --git a/install/onionshare.icns b/desktop/src/onionshare/resources/onionshare.icns Binary files differindex f65ad12d..f65ad12d 100644 --- a/install/onionshare.icns +++ b/desktop/src/onionshare/resources/onionshare.icns diff --git a/install/onionshare.ico b/desktop/src/onionshare/resources/onionshare.ico Binary files differindex dcde4f1f..dcde4f1f 100644 --- a/install/onionshare.ico +++ b/desktop/src/onionshare/resources/onionshare.ico diff --git a/desktop/src/onionshare/resources/onionshare.png b/desktop/src/onionshare/resources/onionshare.png Binary files differnew file mode 100644 index 00000000..a4810d04 --- /dev/null +++ b/desktop/src/onionshare/resources/onionshare.png 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 -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 - ]]> - <![CDATA[ - 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 - ]]> - <![CDATA[ - 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 - ]]> - <![CDATA[ - ZZ1VFtQeAI/Quy4WgdqJBSEpDW/xWkmxQ3fUlcXggy60g6FoinOj2UrzuCLMt+r1RbO8LiZW1Qkp -ykywjDQp9/VIEBIwLGZCqh3S5Ow1rzIigVUW6c46oQVdkSFSzipOBX1VFiYjnKCqEVmELOOiaH/I -QjrSwWQlRuYlPCNh6S4srZgvOb6MEJ1AcdLWEneqVDvTnXQjGC/vqCfX88l4m6kMNmFMiH2a1NeN -IKT64MDUu+Fu1ChN4Cx+zTbJKL7iZXoF9ogUtJkRaCriocVGdjFpjNh32n5SGhePSOPoEcRB+53E -nxe4XMEb1zxKspFRmkq4HKqsbqcRWPzVz0IOHxXuFjAuWboslsOKPZnG6ndKqSvhUna0KTW1YkV6 -pz5pTG1FaZqsw2M9rkT1iswKrZ/IqeBJlTakZwolfNRd0ahQkRBQEvZkJdNEHY4bKrYNowy8Z/WI -TJgWO9nbXWo6/gKNgDdWj6gSmhSxa8vYNTExMfF5OK2Unqrr6AEzOryea7TUXyqLIzJEZjDnEjCN -7Q4KCl1slKIC2UDB2mAxEzOCztqJVN1kIhZ70sqL2jMSR9fHwtAA8Yp1NhVO9otqj8KA52qXkiaA -DZk9lxJPkJc4d6edebkK4pR1vrD32BbMmgSFqyei5zlmrU8T/FZcS5fGr4pVXLxxZA2ZG0sV7tSv -URLT8IpFlvHqUdp87CLWMnkhNaszC2mXmIxdLF6SSfXY0hdk34fxIPainVbNkfsSFfSjWADcF1h/ -2ifSb4tHWc5oVIZ9YL9qezEiqm0zYuZlZfqCu8L0lXa5+kRDYRC/XNHV4ga1T0lCTRU/XMXidKcV -l9BiSuEGY/ENsPCkk+sGqKeiAHTWP/TriGwwo4GSaUVZYZEkhR8zRt+C3jiG50Mqid7wCuEpnogN -EU6M2hCpsqVWBqRwhLFFx7ErvjKWAK6tI+76afUo/a5p1z6qvowUvgLbkxampdXjak+JxSBoki3+ -FUGEsrLaS6QRqISSGRJUsr22O822+vBuSMNhlHRu6u+LeUklyeHEkH2BE4OAuCdYppXDHlqK1L03 -ki8o6VT7RNCw0VbsIcPAuEwwcj6nHjVbdBxbtVNIZpoWcEQkJzMDthPbHBeI/XXTCoRPTFOXHFts -peRiZdIIkKqSc1dMl0ZIp5yTWf6YYWsIqhIOPKl+lHvXIJEcjREmkbiuwVTOKEoFO0QSis0lmp36 -3hmr946YmR7xCs2Pz+0ZQb1mFuz5Qg2vq0/mUG6kyuoqsqnQrbG9tCvLEuJGW5CNvmj+NUIi1n5F -TXYp2Y+GGqURmft31xpivKIDjS5F6Y2LyqaNK40k2adrWaMphDeaIfWZmsUTdSecvI6xTFiDsCz7 -6yAuLWGd+qssNlXQtsQXmkkQDzCEmq19aguFpSy9P2FizFN4OOqasAg6YYjqpIRChg1NDtUO5zOu -XBRUnL3a5IuVDGlIMBKJovAZw1wWK8bWVXQprf3mwJ2xyBfksHVBfVsrjV8Y3c4+WNEABWKkvaOr -a8QiXWDz5LY4icfO5zRBaIEZzVL3d/1WnZeBVeLya4MbwIcXD4CvYTCVZY6rU0jfV4B1h5dWVCqZ -IfZP4f0Y1cAQ1diJh4JJz6RIJ6hYz7KtJOP8+cYtZbjABzGO4qq4BcCwaGfhFPeGwXb2hsn9y9jM -GrAwY7EyBFq0MpPIpmBKzJZL0zgufVUWFGXM8e4Vrka3ZoSXVix7hdbQ2nUj8QbpFfjnfYL4BkZR -JU4nkxl3FU0FdHmP0Gpr+2mEaKir2V6FhI9CqwAvYFR4UnB1QmKrdR5MQmoMYOhIscHQISzQ9QQP -0mZgUMEJwJyK6WInSfmt/TKpj2C59WYiMo8gLBEjWrbt6UYRjGhu/URFwb69PSqhaeCzQW+pLvMr -QtH9pE/5Otrrs23Y2U5sGBfqitQs/AKMyBMGEpsJzbkQjJGOOVOIva2d3828qHaNzE885MQ5rIFL -EZ2ZcpzsaAZwqVFmZXeqTz6B33Gx85pJLfipMRsL+39jJFqPHA7y2REf2sjniBPQTwjdXvsq2UzG -MPhwNIrr/vPluNzPfiFSEs1M5eeHv/zdu7evXv/+8LObm+vPP//2q9++efeCsY8CcneecHwUCB+x -pwQha2llkkAAC5gtR8BgMX3SJWlwE4lREFTSCoggarLwAf9NbIHAlsldBpVZNA5EXOyS0g60cO0w -V3ASixq0tJt7PF1Z5kquLJO3p4R5Coff2tBy9IqzyadhQXVPYLL9LTba1SqZXFZ2tKXtS+Le+BD0 -hqWE55hAmT3HM28tZofUwKSvSCnUEEpkr2hnE6yx8ILZLkiRW6dWvQIeCNEBGiljZDvh7hw1WdkM -3Fb5OIKbXMJnJfmEzyoU7A/O/w+55v/n3/9gxPMkhIvhkLDLJf2TjJjofCKtWSyJ9jAO54p+Mh4b -WBm+gSjg9Lhc0xjBWogBrZ4YwTJ2L7BdjxJcSw+fs5TAGzRInBbCwDuN7MU6L3AMBxIWz6x1dMxP -oqysMUFGVE3SXnCs0OMrCFHiYrI2nOAtOllEmTCiUWKWiKzu2/ATYUK2HHaPcRUL2z34hwOguoYE -mi6BEYT7r4baEnxIe5zApoidYKW+Lm6Z9dicSHNFzahwh0lELVLEip+gDQ1IdMgR0UrvH1vYVHC8 -lYqa6+YYEsVNKw4bPJMoqU1qFRIJ/0qFd9u5fuGE1XGxNuLJRGIQhxe+Lq6lhceW1ZOj+Os1RQj4 -qVcmKBw26NoTjwbDa45tJt61S1xs75G67yBAMfv9uhMvUydiunYMSWND86oNBZXXraO4aS0ROn06 -ghgYrqjqgHM7+gHwATJKOpmmTQaUKBSx7DSTQzzLGs8CG14IGXEjtBw7CnihEi+U8S46/opkJ7yZ -j16A83lZtDzWGVFYctj42Y7dQrBPBLKO3YMzrYuhIF6a3E8s/cTRC4AxSpBAK0sMPEZJcDCKBmdQ -iFYAWMIsDVFPUGVuTsQDJIlS2BXQGa57Bo042v0yIGUyCmBC/knZQEIuBLix7PlwbqZw6SKw6who -TZheWASQKBXtN8wB4SgYrp4IYxnvh/gfdZHtwEGDTc2GFIp+Sj2gqdNo4j0YjF+NjS4ugcYvG+wK -uwRTLhyko/0tOiH5jAEoTR2X5Zq7DwP328IX21X44PFPbpGxNfcNH0gojSIWJltWap2r83OfOmOs -O2Yp+8E+TCxP8GgpTEaxITPzirs3sYcnY1PEXvPJIMTDxCipZpNHZTQ3jdL0Lr5O8rrZumseIcUi -M0KTEyOIT3Ki4hIUgWMfH5WoYl4CKk3UkqBXFoCERc1IkTmC8YmPTMSTPWAR09EA2UZVKyuTBnaB -dURtXd/IGjABWdkDoeLIRKw6lei7QMsG4+is4Gh9CQiIfa9h6K9YpMX6QzjfwVHoZa1DJ/yD2Ndh -TkrQE2oDgdGoTC21Dm0+LPCFicKpgIomnU2aEcAOmT5jsbdA/GIEqYhLrqt63L5xf72XtGyZUiDh -Mn7ShtOdEXiD8BtNmOQiRhkHI427pNZu4JTJ4QyuI90E01A8StyfeOEyG1DCdWxiwt81j5JbeoVE -RoPsCFEVZnbCXbCiIojNJ4Sc7BnNXK3dOYGlDeZJRvSCf0mDRJzadWukh2DL4m3FcsvkSHCjggLO -AniVDhjioVgA1l+LR9i+SrgmN5BLqkhpPXDCJuQ60lhg7TCkhBhK+MsxIhP1yqpHYIuK/fWHJKTg -EwBhMC6WRNzyZE5r8/AGI6anRhkmAm+SnIPtwKu1V8SsLTaYX0iQvYNlR2hEj6fZRryJ3yUM5LUe -kTAihUBeYXtKSyW+r7XFEbWEoRTUKH014QEcJ2uKQYQyr/IoEpOpi73ByQW4STFPO2BfIhz9OU5R -mBQ6P6YbIVp9U3wAbwiQEZnLjFhqKd2IxiuxYJ6K8EUxCWmPn1DcG1SUKTgVW5FiSKI8adYS5xoj -Hrq2iyOWKzNLzZ6IrkPIPKr2UeLiaUZ5ksGIm1kWeMxD1SPIEAYwho2rxRIpkl6Rj5+HXcp+mGzt -Wts+fmkmiXO7umNH+lPr6YQfrjU/XN7gSj5Z+7sBV+Dd2L/VyJLCfUY0A+ZnxswVs9QmxtAubKAZ -r4l22uJpxvvEAhVYoae5VpTmWFpQcXhUZfceOAHzXvDOlCXWd0ZgagTNTj1CG0LTUNiA2SMoQG6P -c1s6mq3hOxqxxcRBqCjaOgSQtS9oe6JOIrsofFNCfjQczfpIWw67IljIMsbENrz8YzAamwzS4DKv -wAhisanVMPhFnatnAkc7prGeqUJvKFFrn2BUmEnf18xXi9jGMkgpSCAG4DsL8Wwezx5LD7B9npDm -4px62ytz7KZ1JqoGc9Mz4isgANVvtNrKKiTygkb1dgMYocfErNeNgNEg1PR4idh9BqKBsiD5beih -3i65KGtDOOJbHJHKcXkpwTNRbOJvnoXpCm2ODTyaU3tEjhHaaKLE5Yq7E4NsoJR8HzLPuA/eTmhX -U5Yd6Z3adieUBqi+wMV0AxrfgtjEkYMJKnmov2YLHTRfg6pr94hogOMOi93XeIhQclYa+Wjz40iR -NLnCRY0iRhjGQtCcFSdUxoMz60G1WjTSXQlsTraygYsa4tY9OBpVeGGNmkKYSn0QZWgU0Z7V12kF -V1uSfiVStOd9wVJAG8SVphkYcUEDT0j2vOuiFQ/+iE8kNlFFmkvXWXBslVBv2mSVuBBbP9Rpcrgc -0uW7obiYm0nmoMlA4uKJOMET8ABuLhUnwr/OLxMd1RSwLfjx6FZF4uFQstQAI53EtsCncP8RBUJy -N0FBTEdN3a04Nws1SafmxXEwZD5wHo0HoAGAWvERQKr6PBm4oJuSxKYBY/jBQOhtWAwGmURnhGiO -URNovuLAK5eZiIkwIlnfkDiXyUtkT6pnnj0gsRgwlxwD8PU4VX4z56WhXOFawFDMtFsm/IfnhABh -xUVkRyp8xcRvvZrgmvRq10TuNLjafIXfrEbqLkv4p8SbQNLgDcth4YjvIsthWng10ZYXXLpAVEne -lCwqrYM3K+4ygCXwSYJS6P3YF6Jro5uWWVva4UJOgKWEhUjyx/qDq5P2r0XB07c8HVVr2INEdb3S -towc/JZOXxdGYDtlAht6TjbhYi8PkRfRQt8a4tFgOpqz1RPwDZw2ekEMNbjBoeKEmoFu0UuzLrb1 -YKDYehIH24hqU3HGztaOEX0Et4uTOb5eetSy4A+QxkG6yOHpI4hrao50gwoOa+6vspIAqzlEiTVe -CjxDrev2IkxI7RNi1ELBaIfk3Pbs8HRSxTwhHemAKFutL87SFwdvxuMRn29rC/9mbQlgxyiipRoF -+4N2gJEvoNMltaRMXxWi7ZWAd+vsD7BGhv1NkmUpbPFCpABbvCFW29j1EbJlILVG7MG2uFTJGaa0 -BidfjDHMnjrxGdwjU5J5EoJXfNrxAO3iZMB6G4Mr4RiVsXCooPNXXOgy5xa7jJdQ4Q== - ]]> - <![CDATA[ - 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 - ]]> - <![CDATA[ - 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 - ]]> - <![CDATA[ - PjIdGFwn9W8BvhBVyGBNGmPXFVap6w8lmgsUj4gSW9rKk7FqSzTe0xzNgEK2eR6j2JgmEbaBL4EY -J73L6LwIcjrpxd0Hys5DStthZBa67YGA/WDM7b3hywZMXNv7uyU10yQn1F0w+rM9uqMJOburwVd9 -+Q3FEMVRFtNFwGgjQCckTFdLN2OpTJNreKhGsnJzsrjxglVrnplGSM38EKsJvkr7n2MdvVgwwolr -N4ntJyIMwILhj41yDGLQKeqmuWgD+sHknCbCQk6mFOl0h5jrUWW6M27eFThCdhjIvbPCZ9Q94cYO -kYYzHh1/0Awwb8xpAjvgXTG3ZxN9irQqqW5t6x6G2Qc6FWlPNospdMZxk0vUx3ExP3uRwaDDXcj2 -Ruf40KL8kHTwfBj7O17ometc6H/8q28++/WLV68/u33z9R8/e/PP7of8V2/ffPt1XO/yN3778uuX -L969/OIz3eLsvuvhZz8//MN/HT7UMvmHr7dNdxvEDHVBXNq5GORevGmiGwcJpE4So0vOMkWbJllw -IFXgItEziaKepFE4MkI1ptL1FaqhUZZrJUufOFR2UUJYrgNp0hh8caoGgR8WC6fP0aG5aGoIeBSG -hkKNJ5RQMrXcpyjzR1o5zvWZ3paUkrfmhG8+E2Gj0ltx712aovpqpNu7DlsVwwYX3yyyA15J20OU -afLS+ud/8HcoXHgaOTmhhTBTg6GSVNGWyEiphi86ATPxoG0r8eqmaNSzp6898OrFfYp6qZ4RYwPs -Gg2B6RQMPOTJCStO6Xg53tAntesO2K8zCZu+j7tqVBI/yFCnSNf2dEs83UzLUZCtcbXHr0QJm7GX -HqCWOaUHqMbmlqNzy326cOsxXeMUJ3o9Ys8xZfKZY8CYPol9pJWh7hkrQ5CIhzMK/x+9znjBi0+S -muEnrL2eIyXKIIAZz67rMueIMxC/gGoIGpGqDVWZavCqIrscqqbySSrhO56hTh4mrQ5N4kF3KWXy -Id2Ti4hTd5ZTb9B5/XSbcd/CRsWZavlIRjw1pWf3r0zr1usRpSl7xALbdi8ZKpPkjpGeZxyo4b5m -lPsul8BzzFTjdGFUQlEzNVGpOB4lAaRMw7GdT205jjKOpJdCOhlPRM1UMhuomtSvvxpayajsaml5 -A3hWTIaoe02aDSMmN3gGGQ2O0cXWYwAgWQpjb1cI3CDL2+FPRiGY37uW7hRJiu79QGEAgtzN2rzM -IBomzx4Q9daKC2EQYKap1eqaVyWaPC7JuELUjM5RSjLakVwqqCE6So4uhABMoVpcosJQtqw5tc/1 -xLLzx0egJ6a25ipNi+uwGrpLpnpxq2liQFGQlZCnwyuRse32Vi1X57HZhCMtyq2fAK2ScIrZLUWY -oKHJkK4wJM9lVtVw8DkKwdTao1FI42KYuENC1ajWsEkwDEh0lLo3Zhe3WZDU1PjLjmHHt6nuKNMh -lV7xPVsiUNGyRKCZpl2ZtvBkbC7dlEAP7Y5H4sA09lnJsKOuFuh4V5egshQJXASEi+1i0u2iEqRz -D6SzAOxyQHhxpxcj4T3AKQX0cp56NVmiujjDQH5QMcf5ZwFqn+ywC8UcyJD2bnGHTipsSPAAWQe1 -bV0inpV5iCr7kfKIN73bJSh4lD2kymtDR+GtQbDy1hOuf4cxCcPoESOzZSHLllKPpDSXqI88TeZH -rbnii+UILBxlp3dnYRTZTIRnMedcP9GoVcq4kbJBVMv0SFdQsnWd1U8ckwLAVLA1PYIzT1vhhakX -XuAxEGsIpmSsd4oRjqRTiKFEVMkd7QgcYb+7t7oLJuBdnboYRRotUZmcTEfXl7PrnJaF1f6RFr3V -E5izsfdiKc7ZmOhteGlE7r06nYLXp8SjVvs2sPIsk5zaT/8Ma7RMSXVlbxyR0dHT2bfIRrgpRcdJ -kHOLIfCyT0b4TjRAQN+RKMjuF//kOuBs4V1A0dxY2c+y9mfBNn46IrvnX9wAVyzhEU4uU5+SqU8J -pgSPYOGx0C8eHDnNFqo9nhTMoCxdpOjhJHWvPPr2LV1MLQFLxfMYbdHH7tBudAV1GffF1UqIp1RQ -TR4BWItXHl2HfXGqGF4twxIZYYRty+79EF0Z6NdJlyEXinAf1NqTeioN1sOrTEcVd/9qrt64hNPW -ulKOMFt2m7Vq37ObC7gLiesTUxmrhv9aTJ9EHyCfyVvC7lVgYsxNBlQw0Sh3jHxwRiwjUU9cOVt1 -NLp6AqycAOavkWzjcLZYYHJsg9Qtqmg5vavEiChHSJyNzuLJvfHcbXlxGiTuTyeKkATVzTYaN+Pm -kiFFy7cpGonQZ7m5Wr4+p614PKfrA1eKixcPWF2ddYkE90rV6q39MjV9q1u4UMUl0lsI8JHeksbo -TL2QgcwInKCoW/brI/hJL2JENPVuaPBLtKYlpkm20ZbYn62LMFF4WFpPfcYVIk1Je4jqOuSwTFG6 -ZF1cdoRS5cF6VrQydjVCw/X5cm/vTsESnBO0RpxYcLHOPEchRvNtwKcus477knp1ZAs2c6kpQgv4 -IadeJ5NRmRdOBFRrVMMhGzG5MR0JF8UBXnefp4GFnZrj6gHu6UNS7ezO82QbbC1vSFJ2BTYSEKLB -Fvkr4Aywid313NaDQShLKEHmfZjIqVM25RByRIddEJvMhGi8TON6qra5EzPFMR04iKpwpltCQujH -IpMr+iDS9pWmT1Fux23PaVrUy0hlUrVo7zyuEcZENaRiFPkurhHJiIm+lLSAoXAl/CVKuZLJQJQI -BBYZfIA1XKx8iUBV3KAEXaYaLlkgd+Qgc4JmvWjDzWkvwAuJABIaZQVQG8gMYkQJQUcj5t7KBJ+o -VFZN0VTcoQMXDz3YXNZodsSPPFfXeWo9gpwNL0MgcD2xQuo3rf6WewsR30V0y4qgwYoDSjRCm32C -MBL5EUhKr/aCM69EA4hG+SaivGvU2qOUKpgo2kX7BK1Los0o+jS3T9G7azuZ0WTcTwJ5RIUqMCD0 -oXWx1Qb8w4Ab7JFy6h7DgmVQtW4GtbobQnHvGQDAMGZJ2xm7DIBEnCBHwic0knJjaLlxNU7OcZK6 -uSBJwFg+vg0FUYtb3Ex2vSxO3+9dYPwixPawipvNUloYP35xQj25LX26orSxfYnbic+3SYYjMsnk -IvlkCcgEDJGVQbGnilomkz0WmuLSPShMwR6XPVriW6ES6EvoypQpwo7Mru0ER8jFbiwU3NItf7gr -wGsr4mxjilkQtgBzC26ZTGI8WrTnTeTVANYi44OmxVNP+KX1NmgmFxqgBPbsyt/RUNsG4FgMdMWl -QS1Cd/Q20GpExSXbzg2ztl5z5A8Xd5ovrmvNxqTRuMFe2hujaz5RvhBzLDoOEw+mfgI1BHCz4HmP -y6GpNufh41XGzxrehJzsoyQ9AvGnl3W/0xTBdRMrmvRo/wMNg2PKRvuAWK7JbeupT2oEFY0BJFGM -uyAGsrrbEXO79Gxc2mC5RCFQWjfg4jnpOo0mDvrA3UlbZ5buBYtpIXbnNq/086LJ1RT6gU8QOEdd -reXp5WhlVNrWFrxcBQgGLHt223mQtC7SQHK3T9AO2M1iV9zheDd8jY4+YMbw4YKNBhByoL13ddAV -GiW4D3K6HChKzfl/7Boe2h1/6B7TvOlliLDbyfdJqERal4bgIRLMVk+ASsiM1bZxHZLSpx+nmf1g -0uxnCsZkF+JH4UEXR2MCm36g7EHZWq5NkXlAw52VjNIGNoGe0hQxIP7GtzCZSTOkvxOa2kRYCUyx -20iLVU8bgU6TextRoMGd66ZoMuFov9vT2Ts/4hiM5H+dWdxAao3OquTZZMfZ4oIGJrlnRVSp/YWr -zhRPBnENlLMSFbUnX3K2vE6WB1It9So2pXqtBvBddBhaXb0JR4/T42erzN7GYHZpq+kGsOtmIBUH -242u08PTnBbqwXBygjCiXbN+cP1aVH/QDsWx4uqo2uwqYAGmTCWKxciyJst5PQBgdLtwIiz2HpDn -I8FIrg5Yu7DHm/Np3YWPDBDXfQNvXGb3OF5Bh1JnAgFn9C54clC4enQiVge6GB8ngopcCfOGEl5a -B3pHsXvB/Tc62VOcBqYA9IQ4ixt3SfA65Y2OrQewc7WrsU7jELFdGRPrtA+qSq7ucABc7MpvmKMP -EJ4aewCpcbT0qtNOr5kPq23uaPWVCPiJe2Qn5kJMraeUUAuauuwu8RQvdnyOYozdiGeWtGMyQCKG -7O5Z4OCQD8AslqNHZnL9MPevIpGrdS2BE+KwQAPQOfQtCkI76N9ZDVEcQh3NvV02K3Q0GJZsPILG -nERvC6QB9hPhO6YQO8ioXxh4wtvCOo7tYPRst9Pc1wkfJE8AlVHGEOckGnr7/9l7k2TbkezKcip/ -BCbQWtH2UbAdbXZ9/KFrbcUzppvRTUjxzIzIjAadYv/qu7gAtDjFLhBwOc9JngD53PWc6836oLis -/qO1RuPM1mjNHk0FHaoFZiAFcxaq5BD4/9P6/D/tn/y3xIFFZkrHA6R0ziZSP/bIf7+lgyKwUUDb -YgNdAOBExTzo2C4OpN///e3RRT5nPV7eP9+W5a9GO8sfOE9NLED9gQ+acjREccRb2G/db6MWwLdV -hbnHuH2w/IQRSIcFcEy1KdBhqb1TfimsPX88Fbh/HOCtd1Gra/d/+HrmRNc5ju5Y+/1H8QF8ID84 -+8PPXfxnT/Jf+dL+b1Xt/X+bu8kBZtJLB7vInKfXaW2FqkiaupxZoHCo3hEoWL5H1oRawfsBdU9Q -9oh8VIWKmvpr/qTYWlMEjlMZuAwWIFVkhoqF8yPyCwYmOK+h8SgZEIlwVDJNfsm/MQLRXu2N1TW+ -gYLvZqKJ54rjgGWlXibW2b3lLerWvABi0GBB7cHSzxvWG2CxCm6VD6amfbQutr4qGLJFoIU9jUJ/ -u74+fK/kp6rrShj4TfFThKRIqotkcy78zBFGMnAkqPKQEXLovXf7rWBaKNyjjwPk5H1EzBAJoTlq -2p18GUtwYA84AaG6jqKcAhxnhHw4pfFvu6haweU9yRCPiK3kCrQD2D6skrHSKEvNq4MLytuaB2ea -Ml/MLezQ3sjoWiCbqmt9F8IcHbAwhhIzWrg6UE6oGezmKMLu/IJU88YS6UNdycm22Yki44xGrBZh -71XpZJSinJDsMKxXDp5irn61lmrJhJfgu1ne6MIbak2IJmCBQMP0S2NYlLTaVXhTTfLy4RhFjqcR -+UqForFYeRCNqt9ZsdP6OVPmGTeE8rmC5yDEynwih1AU9PE5dqHi1kCXkE+WSh5Am3Ib0LWNENR6 -VIHDtea9rVq6ZXqz8T9DrRC0+fggvMATWukkILd+KVBZyO3+fmvpPlwOS0LW2SzmWqynrt2v+NRs -mT2W+cWStftaGAHfbsKrGzfMijYaHQMcmHZGWTKheLhCFgTAzU4eL6BO4jr8wJpR67cxIpLqvm5i -AJRa4WlpihRhJr7XEq9/juU7I86VhiNa0fqn4ipjv0O3YqSnsKNzhN03ZH2/qAyExQ== - ]]> - <![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[ - hKd8420ENYi38WC5FzgH/gS3iCYCkQaLgKIAi8DdBtVKWM9U5Lsn9lVS7iCbXi+EzClhr9YAiF5+ -2nEY753QTlW4Sv/OGHs0PRNpGXCHZgmc0W4JlGS47EqH7kSpS59ylLzea1kHgYD64aCJwr3Brsu3 -PpXG7XmZ1pnern9pjfWdyJ/z3rkvtxpJIQRfJ4jFWauKGNrWShYc1yr0i7eyQHzEFhAj0DNCLy6/ -AqU7pHbIIYA/OH3QMLtOvg4iQAZFu9jCzqimAMtCcqjl9yJk1Ylz34zgKHm1eCTUZgRQgL6MxxyB -VBojarkKegWNX2YThof+jIG2As6ZK6CLk4IpGlDBu6NcjJ4xtbvMbBzcUN7ZXRN4MBKccU076Nhi -bqPrHY05XfsIY3Tm5NQGsrW1JBNd0USK3xNipobL149xTdSG0qZVd47zNTMI1YE+o9/DfOzK1YD5 -/MUd3hspgW2ibICTElrN6xJIGaXss2V+SFeMYrbCfOWBcyGiYZJNGtZ8YO1Vg/meEZ/CcSHLoCRD -QdKjYM7IF1J2gwRaKbWwQXaAAzih0FqqlL9AKT/vnXA767nj+MehoPpY4z29Yk4q3H7mKwunYf1+ -9k9X/gfH43At2mmGR53XDkCOg2hpHaf1tz6D1e8+t0fJjTYmfulImcI0+7HqpPOA/eNZ8o+SxaKY -bNZC+I2r6kPyuUlSdkyKOWOm6Gf/8mRBgT2K+iW+gen6vXfTL/ouU6fsN2kFB72J6+yxuxwc2BDT -zpn3WATTZ6d4A/v6MNvCQtZ01M84ljnQLOgSXGHlzAZz/mpH8xpWr8KDnJKaB9+k35mi2rWFjRhG -2xSgzDm/M3xd02h0qSh6WfqWqAaQkQWw0uKmA65hh0E6qG/kfrFxXqilpOJNwY2K9/lF3/cLlkZB -foUE4xPiOaKVxQQDPYCXD7HkdupwLJM20VxZX/BkTZdRaGedPxtQhSvi3VRKWsJ0oGoo2+6REap5 -tq74n6E+qrlnxAam6QiFi88GPRAqyGEN3hvUPrYb8OYQK3hiDh2b+BM90t9/EU/0kTzlegs1aWWO -0KCUREXWAo71oE2ZfM/3bABrnHQUiKZCY8zOJ9DXF7cxotFapIPOLSqIIACTZHzngE90t6KgXlGM -hV2xyqXLkNJ6RvHKlUMrELWcYiCAOQVAvwkX7iJsd1yaOAC1kRLOZwJGx375C2NTVvXGvNcZEciG -pCdZ7Bm6BJmqQXQnVXsuywS0LFWhigRhDQCWV1ItXXkA+s668gF/u6mragEU87RrIgrxDEGPnhIA -5pOEyScqVHBFO1Xu9EysZaEBrAg27J2Xf/1U0fhRPfEzxOB7agpFdBDj2R07pYlG8bhX4kDukicC -effJ00m7gCxGEcOjuTCIuKUcixU+OVQxJodRS6BFIoovE6+UOK92xM8pKJiCatRlrQ5o8k89pupf -RH5Hhv86KhZlvCp6EIDGG8l1QdwmiHnQG+cnINbcHAGggxzxwdFQWzFcnyqJbPmu9JINhmIhHWTe -W6LygQAeYHg69r47kFitq/RwKz494oBnS8IH2lHxL4WyxrujJkRuM3b46tQUoDtRUbL52OmbUEeV -Ycfs6bYafGMIScGDN9Omf46+PkXLiv0pRQROIiS3m1pZ8aFXEgA/2xkN8ToiucapBFNSFLpd7QrX -hbk8ZgzAqPsItHWxQNg6i4XVWpV8HjFbosJSjTxvSRDMJF7vOK1rHPJEHYlR52fGSFhRRApfpca0 -qSCQcOaKdtWzaLaoeCbCoEHK47RXJcPcSl0PwJ4iOL4QLEZVElmyDzODIwnHh3YW5Qtt8KnfI5Mp -QaWZ2hJxxtDQ/T1rZWvpdx7Z7cHwc0w1qGth13GeU9lULiUokedWIIrNR2e9BBXLfXVlmFcQj5mf -W3P7Ma5/MRAONidalLjBdiipBJdE7KoacsuvITdYRE5EesuaaAtMBWndb+TIngMikdfbYl/Ltqvd -OPlWtWbsdsWZr8JLCwv4q0RPXHQoKEtutljP9zXALTGWR7XkjZnizggytK9MAmNOCh0fJPfUEY4I -4Px+Cv/Xsly5cDS26qVvdVlaaIv6/jVlOu+qAp1mBPgHKGAUqmOoC3JPj+grHStRrNqjfGy2Mk/N -hVlGjZh6GxzL46Jaf18YqSX1Ep4M1g/EUfDSxrgva/1+K1n//WYIZ3/osczTswtZNnyneH8VgilY -4a6JKchnGzgVbLmxJRbKrObn8+T0DRQRoQAtRnzbLYvg284xRW4lp7hAAJsmM9YIKecTjjrjGIVi -IKNeM2hQEoOU5yy8key+26NlBDtOj5YUaRMrJCOm/SOSyWpipdB2zEnvYmcURl9QXCQRYezmy0UK -k6AHieaKolJJOt5jukIWB0feAZV9poMVeT4T9LvpgT4mFG/vDbI51lZSBuFjzV7CvFX4Z1mFt9NE -FZjdAc6N1xkh8nZ8bH66CvTIUkkVr6IxijO60ll6wCIDW80SnFmCjy6xf9Uy+6e9zv+WiDiX2FE9 -LFq/gg9ftYkLQITr3+92kweOpiPHDvrf2KQ1HIH8pWSWlYMXTbLlHFf/XAM+ndCfcCJ6d+dMprI9 -NTDZ/QrhI6aBZIIoP4wZ8+Gz+2kBbJkP7MaZSLRBnM+75gxj8qfaRmZKtS1J/lUMbyBubnSnKpgR -MUgRcnyl8QyEDYgRHwAZcxZSU08BuuOmA2GvM/XFZSr3qhl6D3z62bxShDPs5KzIvXVAxSWFEnNx -KlBIL8MXWMRUf/Um/pUv/38vEXFmxUnuyU66cYq13Z5nf1Z8Jik5HKEAjBdoYU01754mhX3AkzNj -F1Blu7DQMXhkbuLph9sENpGvXWHiLHjUgvfWnTMUOP1Mpwyssw0tMJijqdxSgUtm5C/ogBays+jc -R0vE7IqCDDUocC0/Zy2aBRZ+Khggzsbn8s0LejXd+oJuiic6oXeQPickOfqcSHdSOoGedUaglhgP -ZkDS9ErB06YwoNH0tHZbDKhNiB/dX5eFAZqwOE8iK1Zup/P/MsIKAcqw5c/+ukiNeZHMLj19VOpr -3C+909RrCMGHVM+aezWGhKxX108Cr3MApZ1pg5r21bCvO6xVz2B3X6SEhx3yHqkpPafn+rMRMwI5 -7cE56/cr8dQcZcqz3ojkVBPV/Su/hayU39Jj9i2TRiOc8d3Szi3FtlYRzErX9HJA/vhkTvhQt8a0 -+Fa2X3mmZDcgrXnyyH/wyHwlFNl4JU/5PtDFHGn5n76Rdga8WougjurODATrmBnAzYwfws1VJP32 -mKN156hiQZC7UMtxQ21NAQyxOWbprC3ewKsb3uAa1p3tQCud7XWEiW/T2fTows04/DRj7bxwYP0Q -Pm/uNc/+zEt8xWOW2zEl06pXuJIcTmWEArFsSe8U+kTi84JOINrWzLQ+n/FnAd7OgJQ6KFOg+lI/ -uDeygbe2xyiNv7t4+hcN1bpTCce7m9yxvStkdA8O7IFwVDvb91yaZ2oJgibU+YL5e0Ko1iTkahXw -6gdHPbFIeguvLCFGaBaMvaY2mIu4czvAJieN7fsNghphtZSLvDJEomiGi3uX4FzS0wA3DvKKLfRs -GTQedLZyRMT0EC28CBblI4mJZg+w0NhXQ58LNOXgBJUJB4wJEf2arYLECWjwNLcGRsqkit0MHV5x -tRG+ljMPwOqyUBRSmMR7Z81AwHwov3Fie83tVxjo0XAYJzC9LvBIYAKO2eYq74j4Izbp7cr5VLFy -CJTSjhXbPiOr86xQJhmhoKPOfVi4DZDUmXZYFXESNWSyexzkVpR6dheexF+baE4DeTD++1Z+MQSh -8kuT4toro1PYY2eaTLfpzGSU33SW29dQrV8LeX3jyIqGBV+t50xy+gPP1chr69wzmvzb/ZhQ5eu3 -WvZkL8gN+SGAfPLnSrrYCGRnKHTnN2hWgNejpfv8MtK3GCHIxHwQCL5UP/NnDmnyZ9NwskN9c86u -j06VtX0Q1NRkZOGc7dijgZz/HnHFDQg+/lL/U5NbOGWfuHVAYbsEFFZj9SdeAPUCACjsbk463swa -kSIwCqxwu/stjJJl1U8rolytiPiJc/pV0efVz98r62F7tSJzQGsXxInKDidhAP7uFEMKeovSQjgz -qoRquhAf2xfQ1GaL43o1/4WwUcMoYY3/8fMWI1Yhyfcwyajr2dVUAVxRIOCUQlnXp4AvK0/hoYA+ -Lx34EYYZSTQ4fDpCgcr9wwivBLiAeK1Oj8A/+Z6zpinag9rZumb7W978FkFDfxzR9Gv0ns7N3iuR -LOPqzahd7pMpeTLGxfwWjwWkMJFbgBm7IgmDvgewYYmFvlWN6dEh7eO+nKBfz6g6yn33uqMxMUYE -U8Q7VJyrCY4YoBgNjHwSCtAqb8TmAiZ8b0P2jDiHTowyCraGrA0sNTS7vcjGE06crX7ZCyBn0aRN -V+u5A+R/FG67Ztil3UePVgLreb5XQFrMf5oXs9vewP+oKv9qqeCZfelwRu2elLqiSArUn2iLbB6q -WLmhA+fseVzEl+rGyQsiyIUwELEOJGoQHGOdvZ+XsjbD5+bx8YDzQGEE26std5P9UfoKdc8L8VPi -RRk3pBnfLN9IyE38TaNmBI6AeFIv0xV1Zx2p1dLdoeA//L7PiooMagyLGVXnFfg3ZJLnYYDcD/B9 -LM/KClIA3syLFDWpmC2yMyLW7TjW0BqbV/eGvs+nPdAMMuaF0K5LyaZF/PiMWyRWqCAjsYIxiP+g -NCDNkq8xwwlFE6PSbu1ZRtBH0Oj4n+y9a3Mcx5Xm/wn4HfqNI+yJBVyZlVlZNXolypf1Lm3rL9kz -dmxsKCAQlLACAQ4IStZ8+v/5PSeru3EjqikQ6AZrLiK6Oruq8nbyXJ+nbeV4JvQZXTLpfBGGe+ee -w6SopO0CySjy0ilb4Ewd872sVUuHI5hZ2WF8VDxporrtYjeiABZHAaxOe1Y+TvsBF7AgQXt9IZU9 -Chiq8ogmnDUCrqPoxpnReuFTAiDSONdSL4NGAHw+B8pGlcbT11VOYJvsWt6/T14L4ZTbgFdXRiY5 -X8C1VDzGWbF7Z8VWFjwoqcDd4vcWXCwWNMdtUSDHpy5Xl2SjcnsHlRU8qelFrXBFCI71Cr2a6ORw -IWwhlF5SYtoRSiBLZZUvLTYQP1TKGbzhgwOY2FTocMwKUAEI3ftuhHiDKpqUO6cvpLpahajChCQd -MOA/p/q0G188iEbBBWHr8mNgA0TZkQqkgV8L6XwB40MIWFmyvVO9sRgCm+i2LpAYlCkK0EpguGzQ -zgF3lE5D6axsIVKVVPZDgTHvR0Ioo24txGiItUQ1K15clILKMQu7d3J2j1IBrcTEEEFgzc7eFVvn -mIVU3FuQ5kmLNK4NUv8Iopt1oHSca60oyHceEdat4i1Apcq5a4McvE4+BMH7Y4H2OuKVnEphT6i7 -RUx4RAgglS1u4gnDWfw+qg+ngon68CJnPcoZqYFR2X29t6DqQy2KZzwXkCBbgCLSig== - ]]> - <![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[ - 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 - ]]> - <![CDATA[ - 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 - ]]> - <![CDATA[ - YdVrJkhjVzoXpDbfppHomO/rIUA4LERMYBwoOgQaXBnqQOuHgKlrwawnBDrV1mbQplHA6/Ol547X -1mLvBVNpj8CY9ufVDn+hMI9dblJR9wlZJS/CYjh1EAyE9hQCXDWtvtN7kTqdR7Q8FaHN7qmuUieZ -1Am5yhhJHWL4vU9kqlLHRMzQFY99Xr6VF0WNqsgc0NqZgNaXB+/efoyIlhkjV4NaXLopruXyMw1X -w1vdlfAWv29Wf14JcnHp8q+v3vzWcJffePzrowa9TBQHsx+a4VLQa3X1xqBXJA2+3/K4F8OcLwe/ -/NIqYCUPa50QE59rkbB+LRLmv2qWf12KifmlvbUf7l2559768/auvc3au14KlY2vvx4cGh82BoPw -YfHh0tPGcFO7Hjxb9iGOj1pFk+qorH535Zbrj1uLSa1ef3nPtQ+/IMS2evalUFu7uPrKq+5cCbqt -xmk5FJfuezkCVz2Blwd5rStXYnHL4Vr++tq9NwrMDddLnrpLZRxtWn0OS+FxqZSjXYtE1M6H5Z+X -gnbjt+thCRm762GJMlyJ3A1hPShRR2hV2jE+Z1XdsdxpHqGIlzfaKqBHxuTlQo/mWqRiuO+QnvXP -lKK+MG+KfJmWTWb/WtzLo1UFkKJlKCqU0MYKVeNxr9jZ25VVEVHXN4ipvAromRnfdU2jCJbiXrE1 -+WfSKxKYmfYwD+i1vQnhQeUKiujZwLT9MKxH9D5+v57fY79qPM804lL6tXheG1JrSz79knjecFNx -1JRddaVE6o59dSnWN31nXQ74Tdxb67VTd+2uVRxw6v66j1Kq2KVrkcCSrkQC23C5lMqMnOulVN3V -Uqq08oSm60GFtO4JzStXaE0tHKOBRJovlVPlK8HAkK+VUynx8FI0cHGtz/eOEtbnYBuPzGePmJF/ -3CezCtciZhjVbVtPIQWxOjZfjutlR20uMrTHiBkWP2WUa+VUnb2RdUdxeUXM+mALkZKhNPVhtZyq -sYGNuVuChJnI6LS6ViBhH79jz++zY7WeyrYMInSMBBJ8KCbHdiESmOL1SGC3HsNwSbIWyBjFzVos -wy9dCWh0lwMaJtuvVVfZQF8pCfml25h4hiTZejwDI+VSPEM+7ivRjHA5mqHfXB6n+40OmnESYhMV -4w5Kd8kh2D+NghE1sJUbW3ClXQtsmdEmxLu1GFqbCGy1yxhaMTtH4mgZG0QxSCSi9zWGZj8Yent6 -ux6we//DPDrYJxtdJQ0pONgKP6+6NB+qW8/vs1sKDtpGb01fMkk9BgebHHHath8aHNS2uhYcnLax -LoUJp2+tq/VWd26ua+HC92+vVcBw4ga7FjCcssUmA4ndECSkLiHIIsYJipsujbUKnCjLv8IdIYdG -b9OExQozLN/gH7nuQ7fpCjZd1t/2uos9uIudJdZJJ4u3BRgGgo0UAr33Nn2voU+3xRM2fpmbwwfT -XmbIpqoPuaT1aEHns4HyJC/8WELSLf99xJloy10zYXpoc2fndZsm/8KZuPIyN8zE9Je5aSZuj9t8 -/FgNFTvsycy/L/h3z/9AzVr+pT9ePcveeLywbJKX/9aG13r0RBz4TKsiGY1ndzxxV/73Zxdnc3HK -XJwyF6cs5uKUmcBiJrCYCSxmAouZwGImsJgJLGYCi5nAYq5TmetUdqhO5WkTWNxdoaLyjKZF13K8 -JmmObVL5RTS57jhgdng0vVzT1iwJfKZT/WEALiY3WSW5qDUgCJFpXJ1fmNa9u8RShaXy/Ppi9q1y -X1s9yPYIv7ajWk720MjJFmx00+ojs9/6xz3xbDCZgv0iIEpUoevcgF74uSGgH4pgw77pzHGxvIW8 -dPXuem06hmLkPjxmNeuDQ3zpx2FY3tXaD6snvtAncHsogvGMhig0M9wfi2tD/IU2xe80/tmUHDe7 -2f8N6hyXtNB0KVHKYlZFbRNQ3EkTB/Cr4hRp1BtRRug3JQBcVEdGf9cZwTewmi0A3PiE8senwaaU -nGTdlU0ymNbWVTgkpSTz60E4RboEkA/Z4ORrL3+kC814oeu9KCh0uc5iAnlMKHGN1seV7o8VTShy -A1BUoBFlVTTZeLd96NN4xaa/77pIB4VWtfwcPUH98Nnyyl50VX15iz0Q1wZPMPHHjFcASQsqmBqv -mALUufDwm4yfl48ZL9T3GH8/vubVnhyOXVS4yxfUa/ctr1aUPoJYl0gqYYNEYRqslu2elrr1cEA5 -rsUAjUkylHpf3h259iQCLcdYV2x/I8OlINRLZvY1EdEHFFZnm5RIo60NLNfgTqlxt4RaNKMX0swL -bspTUda6pGT8bq2HoVu2I9fdTBZ+vtx4PEWpQzgHfG32HXXYDrLXp7R8y/HzqiPjlWVneVLohYVV -sJVjHbDxcRqv8TXsgxtHPtz8vZIma324M/ATkC1LADtTmCdV/SDZAdNdpOaWMpeu4WwtCJR4W5EY -ZnEeiCy/9zb9IJCufFtd2MYvc2MMbuLLULWD4MpXyr8uHV4fF3rO1kM/OBIbpfVeOenGquwaB2y0 -B6CNuiaSqXzsqnwVAlmFq0S051F6KFCIJezSlipKB0fzSg87/zhnhVTCgejnnwlPKitjFc/sM51E -48c8Hojsu34hnDt3M6Cz1UezW8HUHBz0jQ9gSTaKFtQ7BD92/ZhrWearDy+erbVa+/HqptZ87Xkv -9MkkkTbj6I+RKEm+wS+N8Hj82VDahAW9h8l+RASXhHGnSwlZisrkbQQMl6Qd1QtkDnzxrDbHrWBv -VByLT7CZdSJ45GqSGBI+uVoSbfpM69YQR89L6Pf5rC+p//NfD4NX4tilyPQH1aHqN35UhiDdThf8 -1GMuU6hTB+AmFVb+6VrXOfaQXULTs6dl9+wgkvrYry7hX5JLOpsyPpS1C6EirR4+W17aazm2pc3X -25iSkusarM9aXgGjr66l8RJlvt2wdp/xwupZ45XxdcZ7LN/3ap8O1dE8LqTXtZJ5uZL0sQPhMra+ -MSIqelmt1j30EPpoZmLnXGvSHpRq6WtBab0c1/Xcq1fC2rlXL6XlucfBwWZmRLO8V0GhkeW+aMbS -UF5IGii1ZDoX1jqkU2+te6tGaz9duyeqW9v04wN6r5jTnjO7LC1fcPy86sN4ZdlPe06QpaAC7UH1 -qmVtZzst3WpE10d6fRK+WOvAMm6zBbVejxfyPTn4+XGKt9IDxH3TY1Vp2VmAq6O/XKW1unpj9DcU -CEueTgD4F9ZkPWg8eIN6q60ID29YUPVUosX3UCt1LXh8Yz3H1SKpdvXdVsWSi1kFtq1xZY2ggBIP -ZqDkjUEBg3CL10ABUwlNt4olk8zbpa7FOPCIqwqYzFpOG3JHxa71oPBYHNWYaqzk2DW4w4/fs+f3 -2LORO8rEbWqEVFLhDoeWs6LbnljyvRRG3RBavmsjrQeZb9tKc6R5jjTPkeY50vzUI8031Tw9dKS5 -UKCMPyAty4PsfygDjAojbBKRbTsq+vIyImujGlLniWgeke1sLUPp0o0BWTNk+hQ7OBw3CjXbRupB -IR6LnhrKjODWWRY9PUS/nt9jv7zqaTDZ0xSnkfeqp2GQMJhDzRP308PRSsnF5DqM7GH5FINXZy3J -oBQm8U9j47vLa0C/WpXXdDect7dVtNi8mQYQe3+ZWzDFmrGyhURNuEVujrfk/Qx9z8DbTLhj0ygM -bCu9vS308gte8eYozIavqDqcZPsVSIaHIv/Zk2vUpLKWSecvuaz7H9l7vMGL9dYvng6pi3pbS2jC -h3tId6SE5uujg/PD7+camrmGZq6heXQn6WKuoZlraOYamrmGZq6hmT2bs2dz9mzOns2P79mca2jm -Gpq5hmY3amhux26qT2v30U8HT9dMYkVvbbEMSdmVAew9LnhGo6hNUInqUH+hpN4OF5pyS53rBX1M -qfemgMbsWp3KLCCBDo2yi2FMLp4+7yDJNCYl0g6F0FYmC7ul9JJSyx3QGVBmOJGCMixNVID7yEkS -WofI5ZRJUSmbDp1vgiTA92I7MAeBbprhgXOhjJmmts1ITCg4FwrpxFcH5y7CDDJuV4QZ9ssh3u3V -tdfuoaLBBdGb2sYCsRVjx94Nbs5Qqc41ju4IKdEGwRS4cBv/ewMFQ2+bPpmR4I+bdHfT9CH9s6cQ -9bjJ23uPr34zCNaHvrppF/shxbYl4b2s5+Vfrij7jlqgvhEObrJJDsgb69IgPkRbnloIBUJyJIxd -EBGDGNqHtLpwSM1XblTWVS+ZDm5Ssh+q7l08N9VrcIrX2Ki2p43OqmD6jlK7TWU2lYcykRyRQSYa -lDyOB4KXIcXZFpmWNuk0pP/auaKF3arSSduuH5afpQQq/3a8wmZl31r/ErQkmAnwdOIREyuH/cQM -BaXwm6EwUJTC5lWutrKOG7LFr4zcYU2Jt8/Rq5JKW1oPnFA2YNLXLCAkwuAbzcaDerzxfetHiNmR -lvVjqoOW9jk2kUrRtF163UUmhaEn4pfYpS5W7cFNL7PO1OO61Z2ZncqiOop7cVxKJioglyIHWaeA -vX4kHrNHtn7xqrgkEpNDKroGceeYXTlorUXcF52bWGKHXy2OeoHaKsIA7epSX2W3Z+f3SjWPuXh5 -U6GETJMWIKr3KrUotqseWhh7NCj/LWKzhwyEVVTI5D9k7JXybNMWe6aUeNRIQAI9y+La7NxuRf0C -oSbfsTT8kGyPs5M5AsOtgZu6D0xxSNQrmFzu7RS6BanPrEl7c4Ju0R4BzvvU2+PDKFD9mBVcXN/6 -aK9+W03RB746ZUZ2ppkiaP93iVRX/tSrx/3HDXd1fjDGWlz5miuuNbhbI6muVVpDHOv/OE2iKoZK -F0t1SrrSwAqvlROlKg12XMfk1qErDTA5aVt1VWmgIqDi4bdVaTAZ1fal1ji40tC5U8OlcBKkp/XL -C1MHJ6+pjD/sfxH8mH4l2SfitaRaxFI1HqjnpDR0q6LM0mf4kPaTmIW+uDY4Xg26Onb6peC0CZVj -viwLhDonSOqWJ47ddlAd0ChU6gXWrU6csLpmkitpPOm9e5k6L8XCHZVK6HqvrKlnjgmjrLouu3uE -eoiyVuK2oZ45NlSFPplRUs8cJgPPWVvPnEJUZUjL9xs/q7JDZ854JSQ/cyAzwgMVOj9z9hovXdJv -+np22uhK9bQRqoeOEwAuro7d8sxpXaphKSEj5fZselQG28tFxUc6c5L4wFYDOn5WxWw9Tv1KWw+e -1lYDZSixHjz2JuShaAYar4CK4wkS/ORBTjZ1ufjBg7jtRVeFhW0vqWrdOJ5YJsh9vk1sm+kldqta -i2W6QuiqEV9lO+puwO+4PHqs98TPV6ukXqC2qUld368uldFcYodAm1uWRw9LWW41qr5CHivFvFa1 -772k3c4e0Sz6yWNrSXxPh8yAvx32Ixti5CeEs0qS4eocHY6hoGHpetmCAp1mR8LPF2dvZi6mxczF -NHMxzVxMMxfTzMU0czHNXEwzF9PMxTRzMc1cTHd1bOZimrmYZi6mmYtp5mLaSS6mWw== - ]]> - <![CDATA[ - SJgIrCvWVuGv5ON2YKG1v/Td+yM+jQlxgmUe8SGdq9ugOMl0uFvrc9KKbue2cDWj0aTS33GbfrCn -WcP2lhjOxi9zc7Rm2stU7p8+dw9XcGRKcxA2k/598cyBvDxfYu2vEJ9aidGnw9LzH/bTmaVnrjCa -K4zmCqOJFUYrP0645MdZFk8Mi1WF0fBQFUYrP80l9+eUQqPyYIVGti3NGC5olhWGKGTrf8s+3BSG -yGRJ163BEBWzAIAJWBUaJVM1h5bctFqOAyJcLg0iZ7NCo54s2yYtC43MODfLK5WVx/Mhevb8Hns2 -Aiz1nV0YVoVGZp6Ypp7LPRUaTd0rV7ydD1JodGnHrDs1p9UbvXfX3IcXc6N6o3i93mjlxQxXvZiL -9WzrX1RvlO6uN4p31Rutd/i+XZg5xME2ArkX7ukjDBFTR0r96HtDDwipBt/ke7OdZQZHWHf0AXUd -HLtENTl925ml3a57MIcSUmPv142OviHGIQ/oP1MfVj2YNPz/2XvPhWSS5XH4vQHvAQOKAZgczERz -BHNEGBVFQMKG34f/tb9V3ZOZRHg2Hc+edYHp6VBdubq6WBJhIR5MSRbxiL+kWB7MX7+u7CTXpTsw -BRl+VWTTg4lOUNZ5ePgf68H8S5KNTK+KniFh86qMQ7M/yUY/yUb/a8lGUUnp35lsFKlgD3qsUZGB -jaNX5sjUswMMXabVa/TCH3hZPs/TQhf0TnQ8046Jq/pPilHfnDi+zA8irSUS+mmwTr3xFCdJTuUa -XxWBI7FuMOllo6Y9fFP0PCW9wj12a30gDQGcAl697/HN/l9RL+fBSKztiwWnQ1vNnaSEB9kZjjp9 -8cQsw8uGo1fRj+ca39BdzVHXr/09s04N5nSomGyCXcH0VDwyyulzxZzfmJGJRXDJ+kLeMbvBxjJ6 -OYgrgCP3t8cYszEe5BVop1RXNb4ZbxkdYRKEStKHSU1yOk5S0DdclWinpJWqWJ/pG7ZOUFEhayKv -YQKKAVOAtkRfQ7BZn1nFth6CXeSoLGv0gTqEZIxnVmBhCbh1aJN+VMn7m61HG9SsrfuiX0nSigVl -3Enjm0xLNrAGHK1Nt+0l5rFQvCDfVCwJoEMaTRTzi4kH9reIv1jHK1Z/TpaBpXLMLwLthkATdC3z -s6iHGIw3Q65Bw7wxPdIQKasEmJeIqYhY2wOVdm+fvExJlaRkcCDWeDBAfSrO8HxK5THWI0TvVlEZ -jLTJeELb5xq0sSbqnQw3wkRVETMJwAih3f5t1WkIE5OQiRGKFg0WB9yekWmpFkkRaMqdIggcrfGg -c3vJ5Pa8we0JK2DtHyQz0BX8iSaZCI5Pkl6VhkzK+qpgdhj+F+uO0bb4TdETTISY3gVr+2AUsAJT -wvMba/uvoFeyIKAwv1iAMrg92KG4FyqN92CJGmJJ0xiPrJO08Q2pVKBRH/t7tDQLwE8V0Bz9otNC -jskac0QOJuqpM4TLW1/IO7QLbEiO+5A+eMrik6zZlOSe6V0Sdmp+M94j7IXR2aeeHEgZvKjvsSrp -XZJmqmL7Qt/Ru6B3MRo9KByZJAEiZszQVwh7Nz+T9uRt3mDEnPE+Oc1ijGNWGmGI/NPBS/ogzNzj -m61HA1R6qgqnw1shrhHZhBWydeObztY5E3SCbOtKR3y9J3yXEWKyCViYoPVFj/nZXyIrZvV4IRuz -Zo8c3fwCIxrFVZCjm59F4w3W6Gvp4r8SUBwrVeTfEkZsNfpfWmy3/vZzXeFPMPEnmPgTTPy5rvDn -usKf6wp/riv0Cx/+XFf4c13hz3WFP9cVTjqC+HNd4U8E8SeC+HNd4RjXFVKP4hf5YPi8BJwl/YLa -AJkj+UIKWWMpbr0dOkN1f6TumAy5+orFgoJ6eAJlMh4XCgtS8DGBw7vBUI9TUVfzuaxO0m/BQ+kn -0Sr0HgEK6I2oaxJPK9EHdge6LuA1D1oVgwWYPQITY0zOIygx1OTgDxAiy4oyw/H2YAQ6HyX9HiM8 -Zkdu4GMwoYpc7MTTCAHepEN8/7ARtNgzueERVUMQzbJs/sDqFaSrU8YvaD/w5GpKEmgntdx5RHOG -3KIm4u1utNa5ivdUgmKJ0yYxaHIzjnErE4fqioA334Eugmq4/t0a0fgFdD+OUD6+yjM0jM0hZ3Ev -NtD8HBUFhZiIBeGx7DuuTuTprXgeG8ML+nVd1DZTyA0s3nEytLCwcnH0LhWZRGtFzjNHZ8xJesfI -hp8kiG8w7EFm2HN3JLzliHBw3FCwlb6mYP/IrUV4+akEsgfwA+M0yAeTQkrFS65i1HYS6M2BeOeZ -8YOFIcYvgn5poQQMipHwxi8a9TXmpZDp86S0ukiuR8T7yvASwUPQvUQBo/sqUAIxQfAKHLzSSmJB -ahhfbXRAf0AzC5ghH1PJLVs8YqnMizxWWnct95dgJd0eHsQC2m9Y7R4Uas5vg4A8Jbz+EGQz3uTF -qRLHKoIXboKBjHd2ccAF8BKuyB0D6qHTgJcEnp5e/CUT9sDTUSesAsEwHEMq6jovfvhrL/8jia1E -Bqv6URC8rM/4QhgsoLJCvyAPh15Fezv9MIP+4RUQWr8HjVXobXg69xeo9U9PWFDuz6WwDB+Kecr9 -JQAO0bf1HwCErETvSzN+kvDiDdD7yNWaLDXQFby6Tuf/MApLkjVV4P94+ymr0JA0aL1qzLgEFqWC -yOHVnfTSPOO7fUD9p6SiX+aK79JpwweqFFkLzcHCRf0mT3LHJ/AD6hShfEZOEUUYpgIaFrlmLonY -CC/g9YA0BMyTe9p48wfbZIyfeKRo6FnUGY1o+IcMBghT4Ij8Ew1GwyAT5cnBIcpogE+Ty23hCTIS -4OrUg0W/2iFAfwGGSE9OAxejV5Yq+pV3AwtGKFj4+xNV/LdFFQ9bv/8EFX+Cij9BxZ+gYqSgIolj -GIEN9EQ4Ah5IhMxfmJVI/B5WPFGMmpWo/GXxRFngVSB5WTJz9wQJ1DoJNPihc/dQTecUK3dP5Bgw -RuzxRJleRkauAyJRN7AoQHvgmWHjicACsCMznKhIoGVK9mvY/oqFZSe4MD2cKKl4/7vtIjb0TYrO -+7jHCCeGkgcQfyCB/IJERItI9EiiH5l4RBIDCWWcSCLasUNHEvmBSCKFtz2SiPg46UgiHx5JZMMi -ifYFTzwRURQkVmIY3szYk2URE+ZU1nbnWISUPVnCVDwFLwrX7xxjsGI7J4hWKqICVCgCLaIPnKbs -cQroKRKLRSWGSUWEXgWkdNFMRSQRB0WyRRL/ipVlJ7kyjCQCC8QLpch963okkedA0cLbun9CiTSU -qLriHyo/CbL9iST+RBL/1yKJESnpPxdI5I1AIk9jhxhHQscefiH+RBZ9bviZhBGx2IetlR5G5COG -ETFp3fKW4212EcOIPLkO2D+yJkpGoE5AukG3q3cUkRQz4iTYEIBxYHfQCboWQJzKIi8FRBFHmJt3 -EDH63EgQEaQoatySnbpYjjhvaQhDJqY+ZkOQOie0BAxNSsPzPcRBqaLURVc10cYwYsOju974gaUl -LchnLGRB82hSEh74kfSSLySWJ6J7VMDCeCia0NvKkliBKvMSjSES5U6FfUeCBJkPzAEPhYl4psj8 -rtug5DNqsRKDA4AZgqVHMFCDvpXYwCojBGqGRz0j7sGDKiUY4Qm/6ASXIsU99KgHmF2Kincte8Zp -UJMSAT4sXsEcuWNksRw5jIpZLwFxmnHm6xmmGW2+NEojiHiSjPs7wzSCEabRM3bRDsO4NX4h1cNY -iWfJ56T1hbQiFZMkI0FO0hOIAPeIu4hNkQI5X6i5EXskqVdmJIEaErbEUAVWDCJBd5mUGUjhncGs -9YN5x011yviNR0JjSKRGAgCivUOKmGHYBEtJyUBookhi9bB5IkNCECrSMYnXMCwprSbxvEyEDSEm -kJcqWkPGd8e4xm9gJpGiUFg+TeSIEYuaPLHSnIv+iVf8S+IVIn59Om41Tzv1Zg8mnUzSn0kUw/5g -6riNTxT65LTRh78nLx+wgqlEptZ60WLZTr/7HjuqNCtvWid20qlpncXgZzH6MFdpNOrAk9vv9are -sgxLS8f4WLuXip2jdZYebAuseyrhfAGQLOgNZ2Mx1iZdwAvFRqUX2r7c6lffBx6TLrrvxts1+ob9 -vXzlDRZtNNC36qQJH/R2pAu98VG/0asD9mjd9GIsRSEOW+SA94T3zWfBsD92cOJXhC/5P/3XEpBM -0FxHGpp3jczDP/ZxmV80rkjGRXwgwwJ3JQOp5P+/alBvzALEIDAnqapDrn2S+DGA0jAtitPwgYmR -0Jf+L4d/0I0J/2T2nrIdYKcNjbx5WH8BzvuUK0ET9QkB/JRpEsx/Q2791yzFg/iMFVmEB1+A/8aO -td+N9rD36ZihPNK34EmMdzVi0zH8h6f0DK8geaRjhEZYi1bMOxwmv4sqfQLCrtT7s6F1p9IHzdbv -TfIFhJ4eh0ofw0JAPKQzIBB/04yn6ZzuCSvWG7AgbJ97r9SbMdqA/rpIRaDeZAVke/qy3q2D2MEO -B3so9SrVz7F6GHYO2Uq3XrVepxtf6nVan1rs5PW1q/UWCfx93tdf2Gs0+kQVaHVSlTYIijTdHHhJ -08GXcHQaOwRQxgqvKNOhdbneI91xZJzGSUdvDBO06yGwF63euVZtgUSs4UPaTN8SmOX53xyfzvgf -ShCcZxJY6qpJ57XX2FpsKpawLQWVkcRes1tH3yquEVA2lsjXu+1G5U/6dZFuBNVp6KsUsMZrK1Nr -MQK72NoU7Eal0/PY7WxDa9aGQJbAvSCdWVsR8WyGBQDrfZ/ZBywk12rW+vVelEXYe5k4+SDyTgie -psZ60dUKv2nNk1oN4ULow4LyUKdgWMQ452kTbiKnTYgpau2kOcX/Ohr+h9Y0lS78oVX7OAfygLzr -JRBpVPVHKP57hGJk/vAjkX4k0t8jkbzE0LBnm36E0F+4poHDSH+DGFJ/xNCPGPoRQz9i6JeKoWFP -0vyIob9wTdzfbQvJzI8Q+hFCP0LoRwj9elsopp+4YRhy/PpH8Pxv2z8y+yN6fkTPj+j5ET0+oueX -ngSMIMt+ZNG/eU2RJFG2gTIBbwFvwL+9f7ZA+oeyhuDjToECzv4SeQdfSVXq3kLO48TU6NJt5+Tl -4xxQYjVmPwQWC1tN2n5oB3Axoc/D5ywHXiUkKwwnqRLHKYRdcSqvsIwiCALHEgYmqizLCwxeycsQ -tYyXOIFh8WSHxNL7S0RF4XiRUwWWlQkfDP/F7ygHtOQETCQC8hryRIcdTumLZr3aqmm+Mlw/OItP -YPtg8y8rnTo5aut4So78NbVu1/2YHIg13s1rbaD37onjofmq59NM862hOZ6I7hkNND/XYG1A9eWW -Y47kmWN+qvOZ94r+AbKCSYm/Qsn3XYtOe5EXM4njUjKHRXFZIClZVlUkIElSFQXz0RlOZggBSSKQ -m8CKCiPL5HAUkKQqCKqocIyKJUcYvJzKpB6sTBPlF38awxT44SnMC1t+EbvWLQU8GA== - ]]> - <![CDATA[ - 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 - ]]> - <![CDATA[ - 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 - ]]> - <![CDATA[ - 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 - ]]> - <![CDATA[ - YM7iBJibvENJzXOLhk+UMPq07lSjh5k9K7G6GVWEqqyhG+/FG4VAwCGa+mOaX1KX8Xa5U//C0qVX -0fMcfXAlnO/ktW6v3tSvmRya5djePo6aDGe8e06TTv+0XhyOkA7NvNag9emIiFlEbrYatIGnNA8f -d2HwNjTXC0FXHgbRiEsEWrgVKDdxmEpPI9fENCt197VrAYRTHrjJ3eclAriLrkaAULZlUAeLV1yP -U7qynllkRvtS/wV3tNXsnSMGRdMZPPWUQAIeuCIoCF18ZKgdbbxT44I0KjfD8czAi36ndRSxatM7 -sXwr7GCu0qZFXOtB2YJuFhSh6Skwtz0rYTWIho07gKM2zTqze32nAKzENtlgfk7pDXhI1EnYBXb5 -HcAbw0rUvXctpl//EOsal0f9/q41Y11651SlGbMr/4hJsUoXf7aScoxL3lPk1q4e6dzZ2Z+tfqwN -ex8DuaXRjSRD0+7eKvUm3mljG2glBoOZrzZh/rFeC7uoarE6uQCnEmtU/sRCwZU2vZQQZWK3X33H -6e1hUKn+1rS6oaM1AUR9mF3r1Rq+3o31m59NQPNUZGlR7dTbwfcAmEwLCOBKe8GbqMK3lV6LXzdy -0YKauu4hDTWssoEZ0cbSgLe221ow/xYIDPS7aKJiXzQpV+pVmjXzei+wWeFHqiTlTHPS7MV1/dJR -C/H1Cbjku+8VTXix8+AlQu4uutqb7RJNez1u13VZ7UrTliftk3jXtN2ZYF5aJAYl3Rkjli53UKpQ -+dKrD5Qwh+eEBsmVwXhnqHN/4XG+nHcmocJvhSbgtwcQoLN+r3Wgddz1ueFJWQP+P3jpLDy5rrQ9 -J10erOQCT07fXgfmA/tbrQ+mpMMTcs2qoyNzDV8vwNCIaBkcBC+xOmkOXqmrz8x5j+zaoLdjDY8a -qE+FZs0sP1HpoY8Y8PkpC9peE0cwnk0RPLf/4pk+uLwpPsvLW5cvaSa9fJRc3nrv8fiJE9bPVnnz -wZn5iTxY47fKvWz+Vd353J0936jkX5mbTfMpt7xxLr1PL/K7G9PJ9ML5VHx6efNzfXrx+FadXnmv -w6Pn19T0cn+1NL1ydJ2fTjJHHJPeuEmQ4cXp3OKZ0OW6RzC5/KewdfK8yWcVXpFupa/b9eRzsUWi -ptZTZvdJy03FO53NjZfMSvt4f/tA7W4qu+tXqWLrVrgsdO5vmfxt8aZc3MhsVNmljNxk0ifaBZ6x -4Zj90/Mcs/ssprnn6d0TdmXh/dI+EWHlHD9l4bX7DIFY/nNT3Z37cE2gO/2wkOcWNmfyriapdFfZ -4bZmdx/h606Dqc3f5A14HnY7nbXuZee+oRwwaaFEQUDSOo1ulZ34Nb99lkjAi2wTp3JiQbnzkFva -TvGHSn95c2d63gIbGVRonZeafoM+AsQent5L1rCOQTeexe+lNuM56KN0e+o36O5s4yV9aw0KELMN -uz591529vDn1HvRsY2FzNXe37zXo8lpVWPcZVHyfii/NbQlH3msVbq6ZIrN05DnoTLEmzcnni8de -gzLF8lXeGhT2xT6sNBs/LWUyfoM+Mzuztxfeg+4ktxf2XlLXXoPCvtx/VCR92NOFBdeu8mu9Ro0M -Cij5UnDu6k3ngds/xkEXB/c0dSdsHOWWYVChNRUfQKXH9aLvoGLjZKbnN2il8zgfv/QadCoO7xar -UnNB4smw7kG7mQfeb9BdoXV30/IedH0m0V2Q5ztkUMQxx7Cd/jMbX0xs3T14Dbq8vnbut1Jpdva7 -fyt7DYocRri5Y4oH66eeAJ4pfqlx4Th/5jUoU2zV930HnT860XbIoFPxgbUKNxqzczZ7672rx1dM -/DN9WYJB5bZr0O7CzpMB3ptkwhp0Kk6GFb8/S+d0rYX7z6Jj0NtN5nBP5XHQpYGV7n5+y0J2S/Aa -lDn8etXIoMgtHcOSQZWjwuOL36CPzEnjpOQ96MHC7UEq1eq4BoVRyLClI172WisZ9HBHOBB8Br0T -mPJeadFn0H6vdLhzJ0/FPdd6yfTqvoOWteP0u9+ge8zl48Kma1AYhQ57qC5cJqaPtzwHvUpezvsO -epVJrM36DVpnblc2gPN7r/V4T/uYri4lPAd9eJk58h30c7WxsO8aFEehw95vMY+PGcF70JPlmfYS -sHfPQZ/564TvoDM3j0tpIpE91ro+Pd3pFE8/cdDlAaI54baXZ5T1Kgy6+u3mSX22eakP+qkukUF1 -uU+G/X6SvzpkUJD2iV0HgBdPl1dbvQIOujJIqeV0/KR+dA6DbnfdKy0ctxmgSjpsb2vZxQrjzNwT -JRruobe672QPZ0yhcFHEQVODjDA+vaAl5BsYtNgng4IUs1jhRjp5RQfdYg+SrkFnyvtlyh74rYvD -Q/ugXK85zeV6VRyUGVjpJX8/Ff+4zq8vwbD7024AdzqFZUOqnn65nk5z6t6r/1O+upe0ng5IseXN -jVbD921gvfMd36dMYb22YjwtNQc5zOH27p3x/HKAwR+el58Cntaeq/5Pj6Ybb+buez0X5lL+T0/6 -nx/+T0uXqmo9HYAYU3ovZP3fLp+3TnyfdnornCHUdm48ePLlhfxtPL93Expz+Zbr+z+9mjudC3gq -3ScsiHk8333P+z+9Fe+W/Z8+fCZOrKeDEHtMCNf+bz++PWq+T0G4b256PdUhxgqXyYr/2xup1wv/ -p1lVEPyfHm/yrQCIsSffq2u+T1fn260n36fT88s50Xj61BmA2PTc0ean8fzFzfumOSb/5Xzadllg -yGbOTSN0XreSNtuL623gT0dNnflUzrP6p+f9LdM62N0o5z/ZXDa9f5Wf1fZL+a3lUllJTs/34dPO -6Xa6t5ArXt8Xa5b1Bh3MLlhSzGYAz6brGy+LsI0zBeDoW+cO3teZ4RY2TpNU90I7x7bSzVl+Afre -/yKsFe2cG7s+lj5SmgtgBV/3UYwger2uew0KHH2V9R2U2Dk+g0qzU3G0dB6sYR2D3tz7DgqqbZv3 -HxTtHAcmO4dFS+fNGHSnYR90fXrRPqhQmrOD91TkbIPW5udnrUHBskD93xyWdwwqvqP23/AeVFh8 -8B90plhJOfQx57BE+/cZFOxB0P6ffQa9efIdFNYyszMn+a6VaP8+g4JqADpFxW/Qc2tQqvU5AHx8 -cOk/KOoUTlSaw6cr5qekri4tbaTdu+/Tks8xEXpknpdWM8HtdG5JlC2LX6ATSaDvDHquFgh0LLfM -prpzneMWtpg9BAvvdnhtrhSIfwz+Q//kkks501wHrsTPneFv5xY1AVDFxeVsq3tM5wCf8ug3KJCR -XYwJhr84ha/zcaLz95eMAagSrA9gm8/pfNtoUtq2+56A6TH7Yjxu/dlsJ2plXWMmvdh9StAcJrr9 -TRs5/Hpkytn0u5aP459ZEzpLXp45WMFdnq3MLeyaAOQsbw9OebMQ1/+sHLW8JuWYUrEbOKVZduWC -XcE/d7rOr/tc9Jmd2IC+lSgcBANd/1O5zltWtWt9IF9whfzc2sGhtULv9eGfsP1bmPHaP9x9xw4i -fV7ZbRqP9aHyOtT+6R4Srx1ktA/tchhg+SMDXoHQ/bwK6ywSsrfYwkN3xwvuU/FhMWstFYFyXHC3 -QcwJ+afOZCiHec2lDEweAVgu1lO431xysp6CxXoM2jfXP+Ru3Kx0HAA0J+wAIO7+aWqeKmWDsCug -Nb1ne9s9m6f+AvD2oxUTdp7xAEKVjwXuoZ898GbcnlRJ/XEeS0vOeC1tgCpDlra1enYUsDRKQ4vz -hIasiTi55c1K26SxoFXtHMzru++B7IX7fNK1IDvnj7wgNOfseG6SoQPP5/HPuS5fBpH8scC8sjM3 -wwPGBRZLSlPfhVNOZxM62mwcpY2lU6eOd2fZW3XfR+TrXU3F/Ttz0V1lZmfZSXdFt8j3o7qpUJHx -wvWD6S5dn11dIX90HkgiIw600DEZJvo0E76hcbqhNu/3AG4UB3iguS/k+Taj9S7SAzN74Rc9EbYy -c8T5LjL93lresHQwC2IBW0I1RceW7IRpYQ7WQ/VkT+YDzWs77FL2o+itEJjKoq/G6JBin0ovWDBF -2F/SGCb/2PcSSzCKh/4UqD3tuPn0ILCW7GJXj4t5Tkqb8ZOV2+ZsIk0JFTpfWXlybjKAEOFB9i9Y -oQvV+W3NP9X4iPvnjFhRYF0mJ4YMl1ThIdbr+J2lg+c1NVRnzCQhxk4OYtwkIcaPBzFdLOuItjJo -uL7tMrWFSiHYKpmKoh1z2euaJ+fwUmj9+Fhvazqygu1NlW+7Tkt8HKrsbc0NaSiTeKwnjmWve/Fx -oIOzmXfNxlsfC4YOo1WeLiKaCue+a3kKoeRIE3EYeKhdhE7FYyIhhOuaiJduCVNx6ZYjTcRGqXqM -L8Q2rMz0djxE1C5xXUdAFdQtdUxf9jhmpPe4lch3gMTvcrbZPnTfelFxkeownm4NgM7Hnq9x7W1a -GwTiAiCs5aH77Svjvexh/yn5MgDT3o/IAEBXCBHLXgzAR4d56CXmJ7M+fuuyfET3ZSygA8jfQyWy -G2t9dPk9EtQbcX3201Bkhczrwvf1EP4MH5sccL9nuRUNy2J0YAkRkGEqIrAikbg3MgCBO+JiW+x+ -10Xi/Jza7ocbaSHeJeIh+dp3kvgIvgR+bjUx5zubqfgwRsW+2yXr7QgYcMl6cf6vfacGP9rShIS1 -NAdV+jk4vCbiFsuB7g1zLS50Z/f7TpNypAWp37xLg/X20gX6ffZJcDeC32cqHgKY19XEbQQfSLC/ -BnUYgE6Ax8aLFTg8DU5VOj2oSrcPEGJ2ZTp0AB9Vmt+6WJ4NoZdwpGofBMSkQsWgw6O4tXq2EMFv -66UJDy5tdXx6aR8QGRgVz70lMkwlzkZZVRCeH1hyz4TYSAtyizw/BjAV9/dwwjZNO8NoozAAAIs0 -FY8AmHBd9mBA0Plh8mwUXRaDVc7zG2f0t0Cqm4pMd8iEl0fECJvfEnMAhGDeF1XaYVer3Sj0EsHf -ip1t9MbmydelEYMUrl3DKM8QQs+3H3ek0NnLVDxyPxEp0KsX42wP7WfsSAXpZVDumTkjQ0g+vbNc -6i6qECVyP8AtjmHehEvfxN9SwZTjclThWnz8XtgZMxlxgzj2oS2FCUJ3jM8XlKWmFyg99sWugAZy -tMvWIEeD3zw4moljQ2gSSBvuKF4wR/OMVucGDlWMztGgq8P+VDycDUXhaPDgdHpsTen6YhyOZtE+ -7NsEOBr2MsjRvHAstJ+hOZqpKbn6GZ+jYS8GRzP9lvbQy5kVx/HWBZwbFmRB08Ch6Rv31lLadlJ5 -XlweVOivLyMEYCOeudq5aY9jRhunCGBDQzhj1OACduUOl/rE98PZLHbGR2UzxmlbL3Iu3N/7Gz4R -iflS1y4m0Y/TpTXYy1TEfoY8AuHlhyH9RDKpQ2fjffDIFuENUsndnQ3nyFp2nh9zS8P770FpCL8N -bVV7W3zIx9LjWnw5YCPX/RCLL7o0DD9NMRVdGlZmXkYlH0u+XF9NQr+HXfOQhcNLMQ== - ]]> - <![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) |