From 33d48ae574bd5c159643a319f507837eb5ab50ac Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Tue, 26 Nov 2019 21:56:06 -0800 Subject: [PATCH 01/24] Use relative paths for data_files in setup.py --- setup.py | 43 +++++++++++-------------------------------- 1 file changed, 11 insertions(+), 32 deletions(-) diff --git a/setup.py b/setup.py index 9af72fc1..73020077 100644 --- a/setup.py +++ b/setup.py @@ -69,42 +69,21 @@ classifiers = [ "Environment :: Web Environment", ] data_files = [ - ( - os.path.join(sys.prefix, "share/applications"), - ["install/org.onionshare.OnionShare.desktop"], - ), - ( - os.path.join(sys.prefix, "share/icons/hicolor/scalable/apps"), - ["install/org.onionshare.OnionShare.svg"], - ), - ( - os.path.join(sys.prefix, "share/metainfo"), - ["install/org.onionshare.OnionShare.appdata.xml"], - ), - (os.path.join(sys.prefix, "share/onionshare"), file_list("share")), - (os.path.join(sys.prefix, "share/onionshare/images"), file_list("share/images")), - (os.path.join(sys.prefix, "share/onionshare/locale"), file_list("share/locale")), - ( - os.path.join(sys.prefix, "share/onionshare/templates"), - file_list("share/templates"), - ), - ( - os.path.join(sys.prefix, "share/onionshare/static/css"), - file_list("share/static/css"), - ), - ( - os.path.join(sys.prefix, "share/onionshare/static/img"), - file_list("share/static/img"), - ), - ( - os.path.join(sys.prefix, "share/onionshare/static/js"), - file_list("share/static/js"), - ), + ("share/applications", ["install/org.onionshare.OnionShare.desktop"]), + ("share/icons/hicolor/scalable/apps", ["install/org.onionshare.OnionShare.svg"]), + ("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( ( - "/usr/share/nautilus-python/extensions/", + "share/nautilus-python/extensions/", ["install/scripts/onionshare-nautilus.py"], ) ) From c18a790c6171ca5a176f17fbadb5a707f5f858f5 Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Tue, 26 Nov 2019 22:05:08 -0800 Subject: [PATCH 02/24] Update appdata xml, and add note to BUILD.md to update the version in the appdata on each release --- BUILD.md | 3 ++- install/org.onionshare.OnionShare.appdata.xml | 13 +++---------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/BUILD.md b/BUILD.md index 9456e617..808a2e91 100644 --- a/BUILD.md +++ b/BUILD.md @@ -245,7 +245,8 @@ This section documents the release process. Unless you're a core OnionShare deve Before making a release, all of these should be complete: * `share/version.txt` should have the correct version -* `install/onionshare.nsi` should have the correct version, for the Windows installer +* `install/org.onionshare.OnionShare.appdata.xml` should have the correct version +* `install/onionshare.nsi` should have the correct version * `CHANGELOG.md` should be updated to include a list of all major changes since the last release * There must be a PGP-signed git tag for the version, e.g. for OnionShare 2.1, the tag must be `v2.1` diff --git a/install/org.onionshare.OnionShare.appdata.xml b/install/org.onionshare.OnionShare.appdata.xml index 6ae1b5b6..c0a02350 100644 --- a/install/org.onionshare.OnionShare.appdata.xml +++ b/install/org.onionshare.OnionShare.appdata.xml @@ -8,17 +8,10 @@ Securely and anonymously share a file of any size

- 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. + 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.

- If you want to send files to someone, OnionShare hosts them on your own computer and uses a Tor onion - service to make them temporarily accessible over the internet. The receiving user just needs to open the web - address in Tor Browser to download the files. If you want to receive files, OnionShare hosts an anonymous - dropbox directly on your computer and uses a Tor onion service to make it temporarily accessible over the - internet. Other users can upload files to you from by loading the web address in Tor Browser. + If you want to send files to someone, OnionShare hosts them on your own computer and uses a Tor onion service to make them temporarily accessible over the internet. The receiving user just needs to open the web address in Tor Browser to download the files. If you want to receive files, OnionShare hosts an anonymous dropbox directly on your computer and uses a Tor onion service to make it temporarily accessible over the internet. Other users can upload files to you from by loading the web address in Tor Browser.

org.onionshare.OnionShare.desktop @@ -47,6 +40,6 @@ micah@micahflee.com - + From 4eab66614e25da622f91f6cb9144159b4d6a227d Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Tue, 26 Nov 2019 22:14:25 -0800 Subject: [PATCH 03/24] Remove tag from appdata xml --- install/org.onionshare.OnionShare.appdata.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/org.onionshare.OnionShare.appdata.xml b/install/org.onionshare.OnionShare.appdata.xml index c0a02350..c9a0b11c 100644 --- a/install/org.onionshare.OnionShare.appdata.xml +++ b/install/org.onionshare.OnionShare.appdata.xml @@ -8,7 +8,7 @@ Securely and anonymously share a file of any size

- 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. + 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.

If you want to send files to someone, OnionShare hosts them on your own computer and uses a Tor onion service to make them temporarily accessible over the internet. The receiving user just needs to open the web address in Tor Browser to download the files. If you want to receive files, OnionShare hosts an anonymous dropbox directly on your computer and uses a Tor onion service to make it temporarily accessible over the internet. Other users can upload files to you from by loading the web address in Tor Browser. From 38b3b1a933b78b001c753900e6482a5eb82c2578 Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Wed, 27 Nov 2019 14:54:41 -0800 Subject: [PATCH 04/24] Make Common.get_resource_path find the resource path relative to the binary, instead of using an absolute path --- onionshare/common.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/onionshare/common.py b/onionshare/common.py index d97f0ccb..48f52098 100644 --- a/onionshare/common.py +++ b/onionshare/common.py @@ -97,8 +97,10 @@ class Common(object): ) elif self.platform == "BSD" or self.platform == "Linux": - # Assume OnionShare is installed systemwide in Linux, since we're not running in dev mode - prefix = os.path.join(sys.prefix, "share/onionshare") + # 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" From 3c2c6e2327017042fa65a3f8ff826408614d2e5a Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Wed, 27 Nov 2019 15:41:37 -0800 Subject: [PATCH 05/24] Update tor paths to use paths relative to the binary, instead of absolute paths --- onionshare/common.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/onionshare/common.py b/onionshare/common.py index 48f52098..e447ea34 100644 --- a/onionshare/common.py +++ b/onionshare/common.py @@ -114,10 +114,11 @@ class Common(object): def get_tor_paths(self): if self.platform == "Linux": - tor_path = "/usr/bin/tor" - tor_geo_ip_file_path = "/usr/share/tor/geoip" - tor_geo_ipv6_file_path = "/usr/share/tor/geoip6" - obfs4proxy_file_path = "/usr/bin/obfs4proxy" + prefix = os.path.dirname(os.path.dirname(sys.argv[0])) + tor_path = os.path.join(prefix, "bin/tor") + tor_geo_ip_file_path = os.path.join(prefix, "share/tor/geoip") + tor_geo_ipv6_file_path = os.path.join(prefix, "share/tor/geoip6") + obfs4proxy_file_path = os.path.join(prefix, "bin/obfs4proxy") elif self.platform == "Windows": base_path = os.path.join( os.path.dirname(os.path.dirname(self.get_resource_path(""))), "tor" From 4d3b587eb06a7015fb1605be5e06bf2ccfcdf273 Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Sun, 5 Apr 2020 21:16:15 -0700 Subject: [PATCH 06/24] Update poetry dependencies --- poetry.lock | 74 ++++++++++++++++++++++++++--------------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/poetry.lock b/poetry.lock index 7c4603ba..400669a2 100644 --- a/poetry.lock +++ b/poetry.lock @@ -34,7 +34,7 @@ description = "Python package for providing Mozilla's CA Bundle." name = "certifi" optional = false python-versions = "*" -version = "2019.11.28" +version = "2020.4.5.1" [[package]] category = "main" @@ -76,7 +76,7 @@ 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.1" +version = "1.1.2" [package.dependencies] Jinja2 = ">=2.10.1" @@ -123,7 +123,7 @@ 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.5.0" +version = "1.6.0" [package.dependencies] zipp = ">=0.5" @@ -275,7 +275,7 @@ description = "Python parsing module" name = "pyparsing" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" -version = "2.4.6" +version = "2.4.7" [[package]] category = "main" @@ -294,7 +294,7 @@ description = "The sip module support for PyQt5" name = "pyqt5-sip" optional = false python-versions = ">=3.5" -version = "12.7.1" +version = "12.7.2" [[package]] category = "main" @@ -423,7 +423,7 @@ description = "Measures number of Terminal column cells of wide-character codes" name = "wcwidth" optional = false python-versions = "*" -version = "0.1.8" +version = "0.1.9" [[package]] category = "main" @@ -431,10 +431,10 @@ 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.0" +version = "1.0.1" [package.extras] -dev = ["pytest", "coverage", "tox", "sphinx", "pallets-sphinx-themes", "sphinx-issues"] +dev = ["pytest", "pytest-timeout", "coverage", "tox", "sphinx", "pallets-sphinx-themes", "sphinx-issues"] watchdog = ["watchdog"] [[package]] @@ -468,8 +468,8 @@ attrs = [ {file = "attrs-19.3.0.tar.gz", hash = "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"}, ] certifi = [ - {file = "certifi-2019.11.28-py2.py3-none-any.whl", hash = "sha256:017c25db2a153ce562900032d5bc68e9f191e44e9a0f762f373977de9df1fbb3"}, - {file = "certifi-2019.11.28.tar.gz", hash = "sha256:25b64c7da4cd7479594d035c08c2d809eb4aab3a26e5a990ea98cc450c320f1f"}, + {file = "certifi-2020.4.5.1-py2.py3-none-any.whl", hash = "sha256:1d987a998c75633c40847cc966fcf5904906c920a7f17ef374f5aa4282abd304"}, + {file = "certifi-2020.4.5.1.tar.gz", hash = "sha256:51fcb31174be6e6664c5f69e3e1691a2d72a1a12e90f872cbdb1567eb47b6519"}, ] chardet = [ {file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"}, @@ -489,8 +489,8 @@ dis3 = [ {file = "dis3-0.1.3.tar.gz", hash = "sha256:9259b881fc1df02ed12ac25f82d4a85b44241854330b1a651e40e0c675cb2d1e"}, ] flask = [ - {file = "Flask-1.1.1-py2.py3-none-any.whl", hash = "sha256:45eb5a6fd193d6cf7e0cf5d8a5b31f83d5faae0293695626f539a823e93b13f6"}, - {file = "Flask-1.1.1.tar.gz", hash = "sha256:13f9f196f330c7c2c5d7a5cf91af894110ca0215ac051b5844701f2bfd934d52"}, + {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-3.3.0.tar.gz", hash = "sha256:6ef8b761332e780f9ff74d5f9056c2616f52babc1998b01d9f361a1e439e61b9"}, @@ -504,8 +504,8 @@ idna = [ {file = "idna-2.9.tar.gz", hash = "sha256:7588d1c14ae4c77d74036e8c22ff447b26d0fde8f007354fd48a7814db15b7cb"}, ] importlib-metadata = [ - {file = "importlib_metadata-1.5.0-py2.py3-none-any.whl", hash = "sha256:b97607a1a18a5100839aec1dc26a1ea17ee0d93b20b0f008d80a5a050afb200b"}, - {file = "importlib_metadata-1.5.0.tar.gz", hash = "sha256:06f5b3a99029c7134207dd882428a66992a9de2bef7c2b699b5641f9886c3302"}, + {file = "importlib_metadata-1.6.0-py2.py3-none-any.whl", hash = "sha256:2a688cbaa90e0cc587f1df48bdc97a6eadccdcd9c35fb3f976a09e3b5016d90f"}, + {file = "importlib_metadata-1.6.0.tar.gz", hash = "sha256:34513a8a0c4962bc66d35b359558fd8a5e10cd472d37aec5f66858addef32c1e"}, ] itsdangerous = [ {file = "itsdangerous-1.1.0-py2.py3-none-any.whl", hash = "sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749"}, @@ -625,8 +625,8 @@ pyinstaller = [ {file = "PyInstaller-3.6.tar.gz", hash = "sha256:3730fa80d088f8bb7084d32480eb87cbb4ddb64123363763cf8f2a1378c1c4b7"}, ] pyparsing = [ - {file = "pyparsing-2.4.6-py2.py3-none-any.whl", hash = "sha256:c342dccb5250c08d45fd6f8b4a559613ca603b57498511740e65cd11a2e7dcec"}, - {file = "pyparsing-2.4.6.tar.gz", hash = "sha256:4c830582a84fb022400b85429791bc551f1f4871c33f23e44f353119e92f969f"}, + {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"}, @@ -636,23 +636,23 @@ pyqt5 = [ {file = "PyQt5-5.14.0.tar.gz", hash = "sha256:0145a6b7de15756366decb736c349a0cb510d706c83fda5b8cd9e0557bc1da72"}, ] pyqt5-sip = [ - {file = "PyQt5_sip-12.7.1-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:f314f31f5fd39b06897f013f425137e511d45967150eb4e424a363d8138521c6"}, - {file = "PyQt5_sip-12.7.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:b42021229424aa44e99b3b49520b799fd64ff6ae8b53f79f903bbd85719a28e4"}, - {file = "PyQt5_sip-12.7.1-cp35-cp35m-win32.whl", hash = "sha256:6b4860c4305980db509415d0af802f111d15f92016c9422eb753bc8883463456"}, - {file = "PyQt5_sip-12.7.1-cp35-cp35m-win_amd64.whl", hash = "sha256:d46b0f8effc554de52a1466b1bd80e5cb4bce635a75ac4e7ad6247c965dec5b9"}, - {file = "PyQt5_sip-12.7.1-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:3f665376d9e52faa9855c3736a66ce6d825f85c86d7774d3c393f09da23f4f86"}, - {file = "PyQt5_sip-12.7.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:1115728644bbadcde5fc8a16e7918bd31915a42dd6fb36b10d4afb78c582753e"}, - {file = "PyQt5_sip-12.7.1-cp36-cp36m-win32.whl", hash = "sha256:cbeeae6b45234a1654657f79943f8bccd3d14b4e7496746c62cf6fbce69442c7"}, - {file = "PyQt5_sip-12.7.1-cp36-cp36m-win_amd64.whl", hash = "sha256:8da842d3d7bf8931d1093105fb92702276b6dbb7e801abbaaa869405d616171a"}, - {file = "PyQt5_sip-12.7.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:1f4289276d355b6521dc2cc956189315da6f13adfb6bbab8f25ebd15e3bce1d4"}, - {file = "PyQt5_sip-12.7.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:c1e730a9eb2ec3869ed5d81b0f99f6e2460fb4d77750444c0ec183b771d798f7"}, - {file = "PyQt5_sip-12.7.1-cp37-cp37m-win32.whl", hash = "sha256:b5b4906445fe980aee76f20400116b6904bf5f30d0767489c13370e42a764020"}, - {file = "PyQt5_sip-12.7.1-cp37-cp37m-win_amd64.whl", hash = "sha256:7ffa39763097f64de129cf5cc770a651c3f65d2466b4fe05bef2bd2efbaa38e6"}, - {file = "PyQt5_sip-12.7.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:288c6dc18a8d6a20981c07b715b5695d9b66880778565f3792bc6e38f14f20fb"}, - {file = "PyQt5_sip-12.7.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:ee1a12f09d5af2304273bfd2f6b43835c1467d5ed501a6c95f5405637fa7750a"}, - {file = "PyQt5_sip-12.7.1-cp38-cp38-win32.whl", hash = "sha256:8a18e6f45d482ddfe381789979d09ee13aa6450caa3a0476503891bccb3ac709"}, - {file = "PyQt5_sip-12.7.1-cp38-cp38-win_amd64.whl", hash = "sha256:e28c3abc9b62a1b7e796891648b9f14f8167b31c8e7990fae79654777252bb4d"}, - {file = "PyQt5_sip-12.7.1.tar.gz", hash = "sha256:e6078f5ee7d31c102910d0c277a110e1c2a20a3fc88cd017a39e170120586d3f"}, + {file = "PyQt5_sip-12.7.2-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:df4f5cdb86f47df5f6fc35be29cc45df7b5a2c171d07dbf377d558b226554ea3"}, + {file = "PyQt5_sip-12.7.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:360de29634e2ce1df84d2b588bd8c1a29b768f3a5225869d63adb03bc21bd32a"}, + {file = "PyQt5_sip-12.7.2-cp35-cp35m-win32.whl", hash = "sha256:31c74602ccd6b70e4352550eb41aa980dc1d6009444f3c8eb1b844e84bd144cf"}, + {file = "PyQt5_sip-12.7.2-cp35-cp35m-win_amd64.whl", hash = "sha256:168a6d700daf366b7cf255a8cabf8d07bfe2294859e6b3b2636c36c2f89265c9"}, + {file = "PyQt5_sip-12.7.2-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:b68cfe632a512c0551e8860f35c1fcab5cd1ad5e168b4814fddd88121f447b0a"}, + {file = "PyQt5_sip-12.7.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:b068f4791e97427d82a27e7df28cc3ee33f7e4353f48ed6a123f8cdba44266b2"}, + {file = "PyQt5_sip-12.7.2-cp36-cp36m-win32.whl", hash = "sha256:9dd5769e83e64d017d02981563c8159d825425b6c4998c937a880888f4dcb7a3"}, + {file = "PyQt5_sip-12.7.2-cp36-cp36m-win_amd64.whl", hash = "sha256:16a9a4daf85bfaa3aec35237ff28d8773a3ec937d9f8dc7fc3db7716de42d4a9"}, + {file = "PyQt5_sip-12.7.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3cb9076ba0e574b2f026759103eb0e12051128714f5aa136cca53229d3ad72d1"}, + {file = "PyQt5_sip-12.7.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:65fceeea2ac738a92f7e3e459ece1b4e2fbf49fd1d6b732a73d0d4bcfc434452"}, + {file = "PyQt5_sip-12.7.2-cp37-cp37m-win32.whl", hash = "sha256:11f8cc2de287c3457fee53e781f06fb71f04251e7ae408ed22696ed65fd2bcf4"}, + {file = "PyQt5_sip-12.7.2-cp37-cp37m-win_amd64.whl", hash = "sha256:85e68b8936f1756060ddcb3ef0a84af78ce89993fa6594b3049a0eca53d6d2fa"}, + {file = "PyQt5_sip-12.7.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4f87d59d29ca1c5a4005bbec27af002be787210dc5f8f87fe5d747883a836083"}, + {file = "PyQt5_sip-12.7.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:b34c1f227a8f8e97059f20e5424f117f66a302b42e34d4039158494c6371b1ce"}, + {file = "PyQt5_sip-12.7.2-cp38-cp38-win32.whl", hash = "sha256:01919371d32b26208b2f0318f1e15680d3aa60d1ced1812a5dac8bdb483fea69"}, + {file = "PyQt5_sip-12.7.2-cp38-cp38-win_amd64.whl", hash = "sha256:a8a6c0512641fc042726b6253b2d5f3f3f800098334d198d8ebdf337d85ab3d7"}, + {file = "PyQt5_sip-12.7.2.tar.gz", hash = "sha256:16a19b9f36985b8bff30b89fb8859d831713dd528fba5600563e36ff077960a2"}, ] pysocks = [ {file = "PySocks-1.7.1-py27-none-any.whl", hash = "sha256:08e69f092cc6dbe92a0fdd16eeb9b9ffbc13cadfe5ca4c7bd92ffb078b293299"}, @@ -690,12 +690,12 @@ watchdog = [ {file = "watchdog-0.10.2.tar.gz", hash = "sha256:c560efb643faed5ef28784b2245cf8874f939569717a4a12826a173ac644456b"}, ] wcwidth = [ - {file = "wcwidth-0.1.8-py2.py3-none-any.whl", hash = "sha256:8fd29383f539be45b20bd4df0dc29c20ba48654a41e661925e612311e9f3c603"}, - {file = "wcwidth-0.1.8.tar.gz", hash = "sha256:f28b3e8a6483e5d49e7f8949ac1a78314e740333ae305b4ba5defd3e74fb37a8"}, + {file = "wcwidth-0.1.9-py2.py3-none-any.whl", hash = "sha256:cafe2186b3c009a04067022ce1dcd79cb38d8d65ee4f4791b8888d6599d1bbe1"}, + {file = "wcwidth-0.1.9.tar.gz", hash = "sha256:ee73862862a156bf77ff92b09034fc4825dd3af9cf81bc5b360668d425f3c5f1"}, ] werkzeug = [ - {file = "Werkzeug-1.0.0-py2.py3-none-any.whl", hash = "sha256:6dc65cf9091cf750012f56f2cad759fa9e879f511b5ff8685e456b4e3bf90d16"}, - {file = "Werkzeug-1.0.0.tar.gz", hash = "sha256:169ba8a33788476292d04186ab33b01d6add475033dfc07215e6d219cc077096"}, + {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"}, From b9b0558750e96b629ed34ba62feb48c4d296818c Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Mon, 6 Apr 2020 19:04:55 -0700 Subject: [PATCH 07/24] Make .desktop file not use absolute path for Exec --- install/org.onionshare.OnionShare.desktop | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/org.onionshare.OnionShare.desktop b/install/org.onionshare.OnionShare.desktop index 02592a72..190e2f26 100644 --- a/install/org.onionshare.OnionShare.desktop +++ b/install/org.onionshare.OnionShare.desktop @@ -5,7 +5,7 @@ Comment=Share a file securely and anonymously over Tor Comment[da]=Del en fil sikkert og anonymt over Tor Comment[de]=Teile Dateien sicher und anonym über das Tor-Netzwerk Comment[hr]=Dijeli datoteku sigurno i anonimno preko Tora -Exec=/usr/bin/onionshare-gui +Exec=onionshare-gui Terminal=false Type=Application Icon=org.onionshare.OnionShare From a5a761ddb8535088d3cb9209d2f7a67a99240dd6 Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Mon, 6 Apr 2020 19:26:45 -0700 Subject: [PATCH 08/24] Remove watchdog, replace with a simple background thread --- onionshare_gui/event_handler.py | 89 --------------------------------- onionshare_gui/tab_widget.py | 17 +++---- onionshare_gui/threads.py | 82 ++++++++++++++++++++++++++++++ poetry.lock | 30 +---------- pyproject.toml | 1 - 5 files changed, 90 insertions(+), 129 deletions(-) delete mode 100644 onionshare_gui/event_handler.py diff --git a/onionshare_gui/event_handler.py b/onionshare_gui/event_handler.py deleted file mode 100644 index f4d10c24..00000000 --- a/onionshare_gui/event_handler.py +++ /dev/null @@ -1,89 +0,0 @@ -# -*- coding: utf-8 -*- -""" -OnionShare | https://onionshare.org/ - -Copyright (C) 2014-2018 Micah Lee - -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 . -""" -import json -import os -from watchdog.observers import Observer -from watchdog.events import FileSystemEventHandler, FileModifiedEvent -from PyQt5 import QtCore - - -class EventHandler(FileSystemEventHandler, QtCore.QObject): - """ - To trigger an event, write a JSON line to the events file. When that file changes, - each line will be handled as an event. Valid events are: - {"type": "new_tab"} - {"type": "new_share_tab", "filenames": ["file1", "file2"]} - """ - - new_tab = QtCore.pyqtSignal() - new_share_tab = QtCore.pyqtSignal(list) - - def __init__(self, common): - super(EventHandler, self).__init__() - self.common = common - - def on_modified(self, event): - if ( - type(event) == FileModifiedEvent - and event.src_path == self.common.gui.events_filename - ): - # Read all the lines in the events, then delete it - with open(self.common.gui.events_filename, "r") as f: - lines = f.readlines() - os.remove(self.common.gui.events_filename) - - self.common.log( - "EventHandler", "on_modified", f"processing {len(lines)} lines" - ) - for line in lines: - try: - obj = json.loads(line) - if "type" not in obj: - self.common.log( - "EventHandler", - "on_modified", - f"event does not have a type: {obj}", - ) - continue - except json.decoder.JSONDecodeError: - self.common.log( - "EventHandler", "on_modified", f"ignoring invalid line: {line}" - ) - continue - - if obj["type"] == "new_tab": - self.common.log("EventHandler", "on_modified", "new_tab event") - self.new_tab.emit() - - elif obj["type"] == "new_share_tab": - if "filenames" in obj and type(obj["filenames"]) is list: - self.new_share_tab.emit(obj["filenames"]) - else: - self.common.log( - "EventHandler", - "on_modified", - f"invalid new_share_tab event: {obj}", - ) - - else: - self.common.log( - "EventHandler", "on_modified", f"invalid event type: {obj}" - ) - diff --git a/onionshare_gui/tab_widget.py b/onionshare_gui/tab_widget.py index d69931c0..7d8283fc 100644 --- a/onionshare_gui/tab_widget.py +++ b/onionshare_gui/tab_widget.py @@ -18,13 +18,12 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ from PyQt5 import QtCore, QtWidgets, QtGui -from watchdog.observers import Observer from onionshare import strings from onionshare.mode_settings import ModeSettings from .tab import Tab -from .event_handler import EventHandler +from .threads import EventHandlerThread class TabWidget(QtWidgets.QTabWidget): @@ -72,17 +71,15 @@ class TabWidget(QtWidgets.QTabWidget): self.move_new_tab_button() # Watch the events file for changes - self.event_handler = EventHandler(common) - self.event_handler.new_tab.connect(self.add_tab) - self.event_handler.new_share_tab.connect(self.new_share_tab) - self.observer = Observer() - self.observer.schedule(self.event_handler, self.common.gui.events_dir) - self.observer.start() + self.event_handler_t = EventHandlerThread(common) + self.event_handler_t.new_tab.connect(self.add_tab) + self.event_handler_t.new_share_tab.connect(self.new_share_tab) + self.event_handler_t.start() def cleanup(self): # Stop the event thread - self.observer.stop() - self.observer.join() + self.event_handler_t.stop() + self.event_handler_t.join() # Clean up each tab for index in range(self.count()): diff --git a/onionshare_gui/threads.py b/onionshare_gui/threads.py index 785e6ece..f3e01c12 100644 --- a/onionshare_gui/threads.py +++ b/onionshare_gui/threads.py @@ -18,6 +18,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ import time +import json +import os from PyQt5 import QtCore from onionshare import strings @@ -166,3 +168,83 @@ class AutoStartTimer(QtCore.QThread): except ValueError as e: self.error.emit(e.args[0]) return + + +class EventHandlerThread(QtCore.QThread): + """ + To trigger an event, write a JSON line to the events file. When that file changes, + each line will be handled as an event. Valid events are: + {"type": "new_tab"} + {"type": "new_share_tab", "filenames": ["file1", "file2"]} + """ + + new_tab = QtCore.pyqtSignal() + new_share_tab = QtCore.pyqtSignal(list) + + def __init__(self, common): + super(EventHandler, self).__init__() + self.common = common + self.common.log("EventHandlerThread", "__init__") + + def run(self): + self.common.log("EventHandlerThread", "run") + + mtime = os.stat(self.common.gui.events_filename).st_mtime + + while True: + if os.path.exist(self.common.gui.events_filename): + # Events file exists + if os.stat(self.common.gui.events_filename).st_mtime != mtime: + # Events file has been modified, load events + try: + with open(self.common.gui.events_filename, "r") as f: + lines = f.readlines() + os.remove(self.common.gui.events_filename) + + self.common.log( + "EventHandler", "run", f"processing {len(lines)} lines" + ) + for line in lines: + try: + obj = json.loads(line) + if "type" not in obj: + self.common.log( + "EventHandler", + "run", + f"event does not have a type: {obj}", + ) + continue + except json.decoder.JSONDecodeError: + self.common.log( + "EventHandler", + "run", + f"ignoring invalid line: {line}", + ) + continue + + if obj["type"] == "new_tab": + self.common.log("EventHandler", "run", "new_tab event") + self.new_tab.emit() + + elif obj["type"] == "new_share_tab": + if ( + "filenames" in obj + and type(obj["filenames"]) is list + ): + self.new_share_tab.emit(obj["filenames"]) + else: + self.common.log( + "EventHandler", + "run", + f"invalid new_share_tab event: {obj}", + ) + + else: + self.common.log( + "EventHandler", "run", f"invalid event type: {obj}" + ) + + except: + pass + + time.sleep(0.2) diff --git a/poetry.lock b/poetry.lock index 400669a2..cc053fa4 100644 --- a/poetry.lock +++ b/poetry.lock @@ -193,14 +193,6 @@ version = "20.3" pyparsing = ">=2.0.2" six = "*" -[[package]] -category = "main" -description = "File system general utilities" -name = "pathtools" -optional = false -python-versions = "*" -version = "0.1.2" - [[package]] category = "main" description = "Python PE parsing module" @@ -403,20 +395,6 @@ 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 || >1.5.7,<2.0)"] -[[package]] -category = "main" -description = "Filesystem events monitoring" -name = "watchdog" -optional = false -python-versions = "*" -version = "0.10.2" - -[package.dependencies] -pathtools = ">=0.1.1" - -[package.extras] -watchmedo = ["PyYAML (>=3.10)", "argh (>=0.24.1)"] - [[package]] category = "dev" description = "Measures number of Terminal column cells of wide-character codes" @@ -451,7 +429,7 @@ docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] testing = ["jaraco.itertools", "func-timeout"] [metadata] -content-hash = "41d68ea93701fdaa1aa56159195db7a65863e3b34cc7305ef4a3f5d02f2bdf13" +content-hash = "7a4a60fcd1c6d6345fec30e7fbe87681288929468d069896acad0f23b9e90f5a" python-versions = "^3.7" [metadata.files] @@ -562,9 +540,6 @@ packaging = [ {file = "packaging-20.3-py2.py3-none-any.whl", hash = "sha256:82f77b9bee21c1bafbf35a84905d604d5d1223801d639cf3ed140bd651c08752"}, {file = "packaging-20.3.tar.gz", hash = "sha256:3c292b474fda1671ec57d46d739d072bfd495a4f51ad01a055121d81e952b7a3"}, ] -pathtools = [ - {file = "pathtools-0.1.2.tar.gz", hash = "sha256:7c35c5421a39bb82e58018febd90e3b6e5db34c5443aaaf742b3f33d4655f1c0"}, -] pefile = [ {file = "pefile-2019.4.18.tar.gz", hash = "sha256:a5d6e8305c6b210849b47a6174ddf9c452b2888340b8177874b862ba6c207645"}, ] @@ -686,9 +661,6 @@ urllib3 = [ {file = "urllib3-1.25.8-py2.py3-none-any.whl", hash = "sha256:2f3db8b19923a873b3e5256dc9c2dedfa883e33d87c690d9c7913e1f40673cdc"}, {file = "urllib3-1.25.8.tar.gz", hash = "sha256:87716c2d2a7121198ebcb7ce7cccf6ce5e9ba539041cfbaeecfb641dc0bf6acc"}, ] -watchdog = [ - {file = "watchdog-0.10.2.tar.gz", hash = "sha256:c560efb643faed5ef28784b2245cf8874f939569717a4a12826a173ac644456b"}, -] wcwidth = [ {file = "wcwidth-0.1.9-py2.py3-none-any.whl", hash = "sha256:cafe2186b3c009a04067022ce1dcd79cb38d8d65ee4f4791b8888d6599d1bbe1"}, {file = "wcwidth-0.1.9.tar.gz", hash = "sha256:ee73862862a156bf77ff92b09034fc4825dd3af9cf81bc5b360668d425f3c5f1"}, diff --git a/pyproject.toml b/pyproject.toml index 53ce5858..a5bcf469 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,7 +28,6 @@ requests = "*" stem = "*" urllib3 = "*" Werkzeug = "*" -watchdog = "*" psutil = "*" [tool.poetry.dev-dependencies] From ef73f354b71cce1659e6c65e1bcbfb4710686ffd Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Mon, 6 Apr 2020 19:29:48 -0700 Subject: [PATCH 09/24] Typos in EventHandlerThread --- onionshare_gui/threads.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/onionshare_gui/threads.py b/onionshare_gui/threads.py index f3e01c12..ba490868 100644 --- a/onionshare_gui/threads.py +++ b/onionshare_gui/threads.py @@ -182,17 +182,16 @@ class EventHandlerThread(QtCore.QThread): new_share_tab = QtCore.pyqtSignal(list) def __init__(self, common): - super(EventHandler, self).__init__() + super(EventHandlerThread, self).__init__() self.common = common self.common.log("EventHandlerThread", "__init__") def run(self): self.common.log("EventHandlerThread", "run") - mtime = os.stat(self.common.gui.events_filename).st_mtime - + mtime = 0 while True: - if os.path.exist(self.common.gui.events_filename): + if os.path.exists(self.common.gui.events_filename): # Events file exists if os.stat(self.common.gui.events_filename).st_mtime != mtime: # Events file has been modified, load events From a53b95867f4390a13a8b7910763a7752b363aff8 Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Mon, 6 Apr 2020 19:49:49 -0700 Subject: [PATCH 10/24] Fix linux tor paths, make event handler properly quit thread --- onionshare/common.py | 11 +++++++---- onionshare_gui/settings_dialog.py | 25 ++++++++++++++++--------- onionshare_gui/tab_widget.py | 5 +++-- onionshare_gui/threads.py | 3 +++ onionshare_gui/tor_connection_dialog.py | 6 ++---- 5 files changed, 31 insertions(+), 19 deletions(-) diff --git a/onionshare/common.py b/onionshare/common.py index 08c67899..b74534ff 100644 --- a/onionshare/common.py +++ b/onionshare/common.py @@ -28,6 +28,7 @@ import sys import tempfile import threading import time +import shutil from .settings import Settings @@ -100,7 +101,9 @@ class Common: # 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") + 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" @@ -114,11 +117,11 @@ class Common: def get_tor_paths(self): if self.platform == "Linux": - prefix = os.path.dirname(os.path.dirname(sys.argv[0])) - tor_path = os.path.join(prefix, "bin/tor") + 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") - obfs4proxy_file_path = os.path.join(prefix, "bin/obfs4proxy") elif self.platform == "Windows": base_path = os.path.join( os.path.dirname(os.path.dirname(self.get_resource_path(""))), "tor" diff --git a/onionshare_gui/settings_dialog.py b/onionshare_gui/settings_dialog.py index 45eef270..f8cb4204 100644 --- a/onionshare_gui/settings_dialog.py +++ b/onionshare_gui/settings_dialog.py @@ -142,7 +142,9 @@ class SettingsDialog(QtWidgets.QDialog): self.tor_geo_ipv6_file_path, self.obfs4proxy_file_path, ) = self.common.get_tor_paths() - if not os.path.isfile(self.obfs4proxy_file_path): + if not self.obfs4proxy_file_path or not os.path.isfile( + self.obfs4proxy_file_path + ): self.tor_bridges_use_obfs4_radio = QtWidgets.QRadioButton( strings._("gui_settings_tor_bridges_obfs4_radio_option_no_obfs4proxy") ) @@ -163,7 +165,9 @@ class SettingsDialog(QtWidgets.QDialog): self.tor_geo_ipv6_file_path, self.obfs4proxy_file_path, ) = self.common.get_tor_paths() - if not os.path.isfile(self.obfs4proxy_file_path): + if not self.obfs4proxy_file_path or not os.path.isfile( + self.obfs4proxy_file_path + ): self.tor_bridges_use_meek_lite_azure_radio = QtWidgets.QRadioButton( strings._( "gui_settings_tor_bridges_meek_lite_azure_radio_option_no_obfs4proxy" @@ -662,8 +666,7 @@ class SettingsDialog(QtWidgets.QDialog): onion = Onion(self.common, use_tmp_dir=True) 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 @@ -750,9 +753,7 @@ class SettingsDialog(QtWidgets.QDialog): ) close_forced_update_thread() - forced_update_thread = UpdateThread( - self.common, self.onion, force=True - ) + forced_update_thread = UpdateThread(self.common, self.onion, force=True) forced_update_thread.update_available.connect(update_available) forced_update_thread.update_not_available.connect(update_not_available) forced_update_thread.update_error.connect(update_error) @@ -850,7 +851,10 @@ class SettingsDialog(QtWidgets.QDialog): f"Onion done rebooting, connected to Tor: {self.common.gui.onion.connected_to_tor}", ) - if self.common.gui.onion.is_authenticated() and not tor_con.wasCanceled(): + if ( + self.common.gui.onion.is_authenticated() + and not tor_con.wasCanceled() + ): self.settings_saved.emit() self.close() @@ -866,7 +870,10 @@ class SettingsDialog(QtWidgets.QDialog): Cancel button clicked. """ self.common.log("SettingsDialog", "cancel_clicked") - if not self.common.gui.local_only and not self.common.gui.onion.is_authenticated(): + if ( + not self.common.gui.local_only + and not self.common.gui.onion.is_authenticated() + ): Alert( self.common, strings._("gui_tor_connection_canceled"), diff --git a/onionshare_gui/tab_widget.py b/onionshare_gui/tab_widget.py index 7d8283fc..e14d1f27 100644 --- a/onionshare_gui/tab_widget.py +++ b/onionshare_gui/tab_widget.py @@ -78,8 +78,9 @@ class TabWidget(QtWidgets.QTabWidget): def cleanup(self): # Stop the event thread - self.event_handler_t.stop() - self.event_handler_t.join() + self.event_handler_t.should_quit = True + self.event_handler_t.quit() + self.event_handler_t.wait(50) # Clean up each tab for index in range(self.count()): diff --git a/onionshare_gui/threads.py b/onionshare_gui/threads.py index ba490868..29554039 100644 --- a/onionshare_gui/threads.py +++ b/onionshare_gui/threads.py @@ -185,6 +185,7 @@ class EventHandlerThread(QtCore.QThread): super(EventHandlerThread, self).__init__() self.common = common self.common.log("EventHandlerThread", "__init__") + self.should_quit = False def run(self): self.common.log("EventHandlerThread", "run") @@ -246,4 +247,6 @@ class EventHandlerThread(QtCore.QThread): except: pass + if self.should_quit: + break time.sleep(0.2) diff --git a/onionshare_gui/tor_connection_dialog.py b/onionshare_gui/tor_connection_dialog.py index 37c0ebc3..9c17e65c 100644 --- a/onionshare_gui/tor_connection_dialog.py +++ b/onionshare_gui/tor_connection_dialog.py @@ -157,10 +157,8 @@ class TorConnectionThread(QtCore.QThread): self.canceled_connecting_to_tor.emit() except Exception as e: - self.common.log( - "TorConnectionThread", "run", f"caught exception: {e.args[0]}" - ) - self.error_connecting_to_tor.emit(str(e.args[0])) + self.common.log("TorConnectionThread", "run", f"caught exception: {e}") + self.error_connecting_to_tor.emit(str(e)) def _tor_status_update(self, progress, summary): self.tor_status_update.emit(progress, summary) From 8955b2b6c6c67ead7bd2973e64983d18b975005c Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Mon, 6 Apr 2020 19:53:34 -0700 Subject: [PATCH 11/24] In dev mode, when checking for existing onionshare, check for processes that start with python3 as well as python --- onionshare_gui/__init__.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/onionshare_gui/__init__.py b/onionshare_gui/__init__.py index f0186a18..90b6d7ac 100644 --- a/onionshare_gui/__init__.py +++ b/onionshare_gui/__init__.py @@ -138,7 +138,11 @@ def main(): # Dev mode onionshare? if proc.info["cmdline"] and len(proc.info["cmdline"]) >= 2: if ( - os.path.basename(proc.info["cmdline"][0]).lower() == "python" + ( + os.path.basename(proc.info["cmdline"][0]).lower() == "python" + or os.path.basename(proc.info["cmdline"][0]).lower() + == "python3" + ) and os.path.basename(proc.info["cmdline"][1]) == "onionshare-gui" and proc.status() != "zombie" ): From d2517681af2f5067123906561e616e7f8b2b1d90 Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Mon, 6 Apr 2020 20:05:48 -0700 Subject: [PATCH 12/24] Remove psutil dependency, and start using a lock file instead --- onionshare_gui/__init__.py | 35 ++++++++++------------------------- onionshare_gui/gui_common.py | 5 ++++- poetry.lock | 26 +------------------------- pyproject.toml | 1 - 4 files changed, 15 insertions(+), 52 deletions(-) diff --git a/onionshare_gui/__init__.py b/onionshare_gui/__init__.py index 90b6d7ac..9f8ca832 100644 --- a/onionshare_gui/__init__.py +++ b/onionshare_gui/__init__.py @@ -24,7 +24,6 @@ import platform import argparse import signal import json -import psutil from PyQt5 import QtCore, QtWidgets from onionshare.common import Common @@ -126,31 +125,11 @@ def main(): sys.exit() # Is there another onionshare-gui running? - existing_pid = None - for proc in psutil.process_iter(attrs=["pid", "name", "cmdline"]): - if proc.info["pid"] == os.getpid(): - continue + if os.path.exists(common.gui.lock_filename): + with open(common.gui.lock_filename, "r") as f: + existing_pid = int(f.read()) - if proc.info["name"] == "onionshare-gui" and proc.status() != "zombie": - existing_pid = proc.info["pid"] - break - else: - # Dev mode onionshare? - if proc.info["cmdline"] and len(proc.info["cmdline"]) >= 2: - if ( - ( - os.path.basename(proc.info["cmdline"][0]).lower() == "python" - or os.path.basename(proc.info["cmdline"][0]).lower() - == "python3" - ) - and os.path.basename(proc.info["cmdline"][1]) == "onionshare-gui" - and proc.status() != "zombie" - ): - existing_pid = proc.info["pid"] - break - - if existing_pid: - print(f"Opening tab in existing OnionShare window (pid {proc.info['pid']})") + print(f"Opening tab in existing OnionShare window (pid {existing_pid})") # Make an event for the existing OnionShare window if filenames: @@ -163,6 +142,11 @@ def main(): f.write(json.dumps(obj) + "\n") return + else: + # Write the lock file + with open(common.gui.lock_filename, "w") as f: + f.write(f"{os.getpid()}\n") + # Launch the gui main_window = MainWindow(common, filenames) @@ -173,6 +157,7 @@ def main(): # Clean up when app quits def shutdown(): main_window.cleanup() + os.remove(common.gui.lock_filename) qtapp.aboutToQuit.connect(shutdown) diff --git a/onionshare_gui/gui_common.py b/onionshare_gui/gui_common.py index 4381545e..18edded1 100644 --- a/onionshare_gui/gui_common.py +++ b/onionshare_gui/gui_common.py @@ -46,7 +46,10 @@ class GuiCommon: # Start the Onion self.onion = Onion(common) - # Directory to watch for events + # Lock filename + self.lock_filename = os.path.join(self.common.build_data_dir(), "lock") + + # Events filenames self.events_dir = os.path.join(self.common.build_data_dir(), "events") if not os.path.exists(self.events_dir): os.makedirs(self.events_dir, 0o700, True) diff --git a/poetry.lock b/poetry.lock index cc053fa4..294522d6 100644 --- a/poetry.lock +++ b/poetry.lock @@ -220,17 +220,6 @@ 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.0" - -[package.extras] -enum = ["enum34"] - [[package]] category = "dev" description = "library with cross-python path, ini-parsing, io, code, log facilities" @@ -429,7 +418,7 @@ docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] testing = ["jaraco.itertools", "func-timeout"] [metadata] -content-hash = "7a4a60fcd1c6d6345fec30e7fbe87681288929468d069896acad0f23b9e90f5a" +content-hash = "e341ce712d9198499f5e816edc1a62d75f5a913f22880ed631a8698c78d88fb7" python-versions = "^3.7" [metadata.files] @@ -547,19 +536,6 @@ 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.0-cp27-none-win32.whl", hash = "sha256:298af2f14b635c3c7118fd9183843f4e73e681bb6f01e12284d4d70d48a60953"}, - {file = "psutil-5.7.0-cp27-none-win_amd64.whl", hash = "sha256:75e22717d4dbc7ca529ec5063000b2b294fc9a367f9c9ede1f65846c7955fd38"}, - {file = "psutil-5.7.0-cp35-cp35m-win32.whl", hash = "sha256:f344ca230dd8e8d5eee16827596f1c22ec0876127c28e800d7ae20ed44c4b310"}, - {file = "psutil-5.7.0-cp35-cp35m-win_amd64.whl", hash = "sha256:e2d0c5b07c6fe5a87fa27b7855017edb0d52ee73b71e6ee368fae268605cc3f5"}, - {file = "psutil-5.7.0-cp36-cp36m-win32.whl", hash = "sha256:a02f4ac50d4a23253b68233b07e7cdb567bd025b982d5cf0ee78296990c22d9e"}, - {file = "psutil-5.7.0-cp36-cp36m-win_amd64.whl", hash = "sha256:1413f4158eb50e110777c4f15d7c759521703bd6beb58926f1d562da40180058"}, - {file = "psutil-5.7.0-cp37-cp37m-win32.whl", hash = "sha256:d008ddc00c6906ec80040d26dc2d3e3962109e40ad07fd8a12d0284ce5e0e4f8"}, - {file = "psutil-5.7.0-cp37-cp37m-win_amd64.whl", hash = "sha256:73f35ab66c6c7a9ce82ba44b1e9b1050be2a80cd4dcc3352cc108656b115c74f"}, - {file = "psutil-5.7.0-cp38-cp38-win32.whl", hash = "sha256:60b86f327c198561f101a92be1995f9ae0399736b6eced8f24af41ec64fb88d4"}, - {file = "psutil-5.7.0-cp38-cp38-win_amd64.whl", hash = "sha256:d84029b190c8a66a946e28b4d3934d2ca1528ec94764b180f7d6ea57b0e75e26"}, - {file = "psutil-5.7.0.tar.gz", hash = "sha256:685ec16ca14d079455892f25bd124df26ff9137664af445563c1bd36629b5e0e"}, -] py = [ {file = "py-1.8.1-py2.py3-none-any.whl", hash = "sha256:c20fdd83a5dbc0af9efd622bee9a5564e278f6380fffcacc43ba6f43db2813b0"}, {file = "py-1.8.1.tar.gz", hash = "sha256:5e27081401262157467ad6e7f851b7aa402c5852dbcb3dae06768434de5752aa"}, diff --git a/pyproject.toml b/pyproject.toml index a5bcf469..fa83d133 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,7 +28,6 @@ requests = "*" stem = "*" urllib3 = "*" Werkzeug = "*" -psutil = "*" [tool.poetry.dev-dependencies] atomicwrites = "*" From d1143504ac29fc0b39a21998250f9efb1bfcf50b Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Mon, 6 Apr 2020 20:19:35 -0700 Subject: [PATCH 13/24] Delete the lock file on Ctrl-C --- onionshare_gui/__init__.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/onionshare_gui/__init__.py b/onionshare_gui/__init__.py index 9f8ca832..d083f741 100644 --- a/onionshare_gui/__init__.py +++ b/onionshare_gui/__init__.py @@ -64,10 +64,6 @@ def main(): # Display OnionShare banner print(f"OnionShare {common.version} | https://onionshare.org/") - # Allow Ctrl-C to smoothly quit the program instead of throwing an exception - # https://stackoverflow.com/questions/42814093/how-to-handle-ctrlc-in-python-app-with-pyqt - signal.signal(signal.SIGINT, signal.SIG_DFL) - # Start the Qt app global qtapp qtapp = Application(common) @@ -147,6 +143,15 @@ def main(): with open(common.gui.lock_filename, "w") as f: f.write(f"{os.getpid()}\n") + # Allow Ctrl-C to smoothly quit the program instead of throwing an exception + def signal_handler(s, frame): + print("\nCtrl-C pressed, quitting") + if os.path.exists(common.gui.lock_filename): + os.remove(common.gui.lock_filename) + sys.exit(0) + + signal.signal(signal.SIGINT, signal_handler) + # Launch the gui main_window = MainWindow(common, filenames) From 80b1246df8c9861f6096f59a6d86f02158458af3 Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Mon, 6 Apr 2020 20:29:02 -0700 Subject: [PATCH 14/24] Open files in linux with xdg-open instead of nautilus --- onionshare_gui/tab/mode/history.py | 4 ++-- share/locale/en.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/onionshare_gui/tab/mode/history.py b/onionshare_gui/tab/mode/history.py index 0797320e..51d9c267 100644 --- a/onionshare_gui/tab/mode/history.py +++ b/onionshare_gui/tab/mode/history.py @@ -250,11 +250,11 @@ class ReceiveHistoryItemFile(QtWidgets.QWidget): if self.common.platform == "Linux" or self.common.platform == "BSD": try: # If nautilus is available, open it - subprocess.Popen(["nautilus", abs_filename]) + subprocess.Popen(["xdg-open", self.dir]) except: Alert( self.common, - strings._("gui_open_folder_error_nautilus").format(abs_filename), + strings._("gui_open_folder_error").format(abs_filename), ) # macOS diff --git a/share/locale/en.json b/share/locale/en.json index cca7d92e..d2a89971 100644 --- a/share/locale/en.json +++ b/share/locale/en.json @@ -141,7 +141,7 @@ "gui_settings_data_dir_label": "Save files to", "gui_settings_data_dir_browse_button": "Browse", "gui_settings_public_mode_checkbox": "Public mode", - "gui_open_folder_error_nautilus": "Cannot open folder because nautilus is not available. The file is here: {}", + "gui_open_folder_error": "Failed to open folder with xdg-open. The file is here: {}", "gui_settings_language_label": "Preferred language", "gui_settings_language_changed_notice": "Restart OnionShare for the new language to be applied.", "systray_menu_exit": "Quit", From da12325d1dccc85aa8a699c00ebf980f11302de1 Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Mon, 6 Apr 2020 21:19:17 -0700 Subject: [PATCH 15/24] Fix common.get_tor_paths test --- .circleci/config.yml | 2 +- BUILD.md | 2 +- tests/test_cli_common.py | 16 ++++++++++------ 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index dd84e371..67d8ab0e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -36,7 +36,7 @@ jobs: name: Install dependencies command: | sudo apt-get update - sudo apt-get install -y python3-pip xvfb + sudo apt-get install -y python3-pip xvfb tor obfs4proxy sudo pip3 install poetry flake8 poetry install diff --git a/BUILD.md b/BUILD.md index 1d324b38..2efd251e 100644 --- a/BUILD.md +++ b/BUILD.md @@ -32,7 +32,7 @@ cd onionshare The recommended way to develop OnionShare is to use the latest versions of all dependencies. -First, install `tor` from either the [official Debian repository](https://support.torproject.org/apt/tor-deb-repo/), or from your package manager. +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: diff --git a/tests/test_cli_common.py b/tests/test_cli_common.py index 1f230295..3592d1ba 100644 --- a/tests/test_cli_common.py +++ b/tests/test_cli_common.py @@ -227,12 +227,16 @@ class TestGetTorPaths: # @pytest.mark.skipif(sys.platform != 'Linux', reason='requires Linux') ? def test_get_tor_paths_linux(self, platform_linux, common_obj): - assert common_obj.get_tor_paths() == ( - "/usr/bin/tor", - "/usr/share/tor/geoip", - "/usr/share/tor/geoip6", - "/usr/bin/obfs4proxy", - ) + ( + tor_path, + tor_geo_ip_file_path, + tor_geo_ipv6_file_path, + _, # obfs4proxy is optional + ) = common_obj.get_tor_paths() + + assert os.path.basename(tor_path) == "tor" + assert tor_geo_ip_file_path == "/usr/share/tor/geoip" + assert tor_geo_ipv6_file_path == "/usr/share/tor/geoip6" # @pytest.mark.skipif(sys.platform != 'Windows', reason='requires Windows') ? def test_get_tor_paths_windows(self, platform_windows, common_obj, sys_frozen): From eb38e9d3ba50d9bfc85c2b88658b5e5e172569d2 Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Tue, 30 Jun 2020 11:26:44 -0700 Subject: [PATCH 16/24] Install setuptools for everything, not just windows --- poetry.lock | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/poetry.lock b/poetry.lock index 8e4a1f00..fedb16d0 100644 --- a/poetry.lock +++ b/poetry.lock @@ -469,7 +469,7 @@ docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] testing = ["jaraco.itertools", "func-timeout"] [metadata] -content-hash = "3f46cfec01bcb5166c9f354aaf4439064b477955f3ea2373fcfdb65d5b89276e" +content-hash = "3d46fa34e498a3bcac9efbde10ee25cabccbd7add2c585d82acc9a28c38203d4" python-versions = "^3.7" [metadata.files] diff --git a/pyproject.toml b/pyproject.toml index 411d03f1..e364db88 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,8 +43,8 @@ pytest-faulthandler = "*" pytest-qt = "*" six = "*" urllib3 = "*" +setuptools = "*" pyinstaller = {version = "*", platform = "darwin"} -setuptools = {version = "*", platform = "windows"} [build-system] requires = ["poetry>=0.12"] From 31eb742340347d0f8e05db307bfdd5c6d49f0997 Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Tue, 30 Jun 2020 14:18:59 -0700 Subject: [PATCH 17/24] Add flatpak detection --- onionshare_gui/gui_common.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/onionshare_gui/gui_common.py b/onionshare_gui/gui_common.py index 4b8fe5d4..7eb4f0e8 100644 --- a/onionshare_gui/gui_common.py +++ b/onionshare_gui/gui_common.py @@ -18,6 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ import os +import json from onionshare import strings from onionshare.onion import Onion @@ -37,6 +38,18 @@ class GuiCommon: self.qtapp = qtapp self.local_only = local_only + # Are we running in a flatpak package? + self.is_flatpak = False + if os.path.exists("/app/manifest.json"): + try: + with open("/app/manifest.json") as f: + manifest_data = json.loads(f.read()) + if manifest_data["id"] == "org.onionshare.OnionShare": + self.is_flatpak = True + self.common.log("GuiCommon", "__init__", "is_flatpak=True") + except: + pass + # Load settings self.common.load_settings() From 6fafee1ce8c8351099b81518532b0828e9448f24 Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Tue, 30 Jun 2020 14:27:32 -0700 Subject: [PATCH 18/24] Force saving files inside ~/OnionShare if running in flatpak --- onionshare_gui/tab/mode/receive_mode/__init__.py | 7 ++++++- share/locale/en.json | 3 ++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/onionshare_gui/tab/mode/receive_mode/__init__.py b/onionshare_gui/tab/mode/receive_mode/__init__.py index ba1fc8c4..c35a492c 100644 --- a/onionshare_gui/tab/mode/receive_mode/__init__.py +++ b/onionshare_gui/tab/mode/receive_mode/__init__.py @@ -24,7 +24,7 @@ from onionshare.web import Web from ..history import History, ToggleHistory, ReceiveHistoryItem from .. import Mode -from ....widgets import MinimumWidthWidget +from ....widgets import MinimumWidthWidget, Alert class ReceiveMode(Mode): @@ -135,6 +135,11 @@ class ReceiveMode(Mode): ) if selected_dir: + # If we're running inside a flatpak package, the data dir must be inside ~/OnionShare + if self.common.gui.is_flatpak: + if not selected_dir.startswith(os.path.expanduser("~/OnionShare")): + Alert(self.common, strings._("gui_receive_flatpak_data_dir")) + self.common.log( "ReceiveMode", "data_dir_button_clicked", diff --git a/share/locale/en.json b/share/locale/en.json index 5e19c42d..87cfd60f 100644 --- a/share/locale/en.json +++ b/share/locale/en.json @@ -22,6 +22,7 @@ "gui_receive_start_server": "Start Receive Mode", "gui_receive_stop_server": "Stop Receive Mode", "gui_receive_stop_server_autostop_timer": "Stop Receive Mode ({} remaining)", + "gui_receive_flatpak_data_dir": "Because you installed OnionShare using flatpak, you must save files to a folder in ~/OnionShare.", "gui_copy_url": "Copy Address", "gui_copy_hidservauth": "Copy HidServAuth", "gui_canceled": "Canceled", @@ -209,4 +210,4 @@ "mode_settings_receive_data_dir_label": "Save files to", "mode_settings_receive_data_dir_browse_button": "Browse", "mode_settings_website_disable_csp_checkbox": "Disable Content Security Policy header (allows your website to use third-party resources)" -} +} \ No newline at end of file From f34f4a1a2ad8fbdcf9ba12bb697bd23f151a150f Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Tue, 30 Jun 2020 14:29:33 -0700 Subject: [PATCH 19/24] Missing import --- onionshare_gui/tab/mode/receive_mode/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/onionshare_gui/tab/mode/receive_mode/__init__.py b/onionshare_gui/tab/mode/receive_mode/__init__.py index c35a492c..6d055483 100644 --- a/onionshare_gui/tab/mode/receive_mode/__init__.py +++ b/onionshare_gui/tab/mode/receive_mode/__init__.py @@ -17,6 +17,7 @@ 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 . """ +import os from PyQt5 import QtCore, QtWidgets, QtGui from onionshare import strings From 97b50f67527f16085b9febc1917dbad4cf080544 Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Tue, 30 Jun 2020 14:40:40 -0700 Subject: [PATCH 20/24] When giving flatpak warning, break before setting the selected dir --- onionshare_gui/tab/mode/receive_mode/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/onionshare_gui/tab/mode/receive_mode/__init__.py b/onionshare_gui/tab/mode/receive_mode/__init__.py index 6d055483..a49b86e5 100644 --- a/onionshare_gui/tab/mode/receive_mode/__init__.py +++ b/onionshare_gui/tab/mode/receive_mode/__init__.py @@ -140,6 +140,7 @@ class ReceiveMode(Mode): if self.common.gui.is_flatpak: if not selected_dir.startswith(os.path.expanduser("~/OnionShare")): Alert(self.common, strings._("gui_receive_flatpak_data_dir")) + break self.common.log( "ReceiveMode", From a3288e4a697dff725302d3cac8d31f3d8ac4d2a8 Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Tue, 30 Jun 2020 14:53:38 -0700 Subject: [PATCH 21/24] Simplify flatpak detection --- onionshare_gui/gui_common.py | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/onionshare_gui/gui_common.py b/onionshare_gui/gui_common.py index 7eb4f0e8..eb259301 100644 --- a/onionshare_gui/gui_common.py +++ b/onionshare_gui/gui_common.py @@ -18,7 +18,6 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ import os -import json from onionshare import strings from onionshare.onion import Onion @@ -39,16 +38,7 @@ class GuiCommon: self.local_only = local_only # Are we running in a flatpak package? - self.is_flatpak = False - if os.path.exists("/app/manifest.json"): - try: - with open("/app/manifest.json") as f: - manifest_data = json.loads(f.read()) - if manifest_data["id"] == "org.onionshare.OnionShare": - self.is_flatpak = True - self.common.log("GuiCommon", "__init__", "is_flatpak=True") - except: - pass + self.is_flatpak = os.path.exists("/.flatpak-info") # Load settings self.common.load_settings() From 2d282a2efd8c4b8fbb2f1296a640f4498e32be8f Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Tue, 30 Jun 2020 17:31:18 -0700 Subject: [PATCH 22/24] Oops, should be return instead of break --- onionshare_gui/tab/mode/receive_mode/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/onionshare_gui/tab/mode/receive_mode/__init__.py b/onionshare_gui/tab/mode/receive_mode/__init__.py index a49b86e5..92cd17fa 100644 --- a/onionshare_gui/tab/mode/receive_mode/__init__.py +++ b/onionshare_gui/tab/mode/receive_mode/__init__.py @@ -140,7 +140,7 @@ class ReceiveMode(Mode): if self.common.gui.is_flatpak: if not selected_dir.startswith(os.path.expanduser("~/OnionShare")): Alert(self.common, strings._("gui_receive_flatpak_data_dir")) - break + return self.common.log( "ReceiveMode", From b39a62455b438c03268260a3d947bf91df2d9016 Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Tue, 30 Jun 2020 17:47:37 -0700 Subject: [PATCH 23/24] Remove watchdog and psutil deps --- poetry.lock | 54 +------------------------------------------------- pyproject.toml | 2 -- 2 files changed, 1 insertion(+), 55 deletions(-) diff --git a/poetry.lock b/poetry.lock index fedb16d0..185428e1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -193,14 +193,6 @@ version = "20.4" pyparsing = ">=2.0.2" six = "*" -[[package]] -category = "main" -description = "File system general utilities" -name = "pathtools" -optional = false -python-versions = "*" -version = "0.1.2" - [[package]] category = "main" description = "Python PE parsing module" @@ -228,17 +220,6 @@ 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.0" - -[package.extras] -enum = ["enum34"] - [[package]] category = "dev" description = "library with cross-python path, ini-parsing, io, code, log facilities" @@ -421,20 +402,6 @@ 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 = "Filesystem events monitoring" -name = "watchdog" -optional = false -python-versions = "*" -version = "0.10.3" - -[package.dependencies] -pathtools = ">=0.1.1" - -[package.extras] -watchmedo = ["PyYAML (>=3.10)", "argh (>=0.24.1)"] - [[package]] category = "dev" description = "Measures the displayed width of unicode strings in a terminal" @@ -469,7 +436,7 @@ docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] testing = ["jaraco.itertools", "func-timeout"] [metadata] -content-hash = "3d46fa34e498a3bcac9efbde10ee25cabccbd7add2c585d82acc9a28c38203d4" +content-hash = "71c32a60a36f2e66745f800f5cab96e8d2551f5959acc8b07aa9003d6f3f702b" python-versions = "^3.7" [metadata.files] @@ -580,9 +547,6 @@ packaging = [ {file = "packaging-20.4-py2.py3-none-any.whl", hash = "sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181"}, {file = "packaging-20.4.tar.gz", hash = "sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8"}, ] -pathtools = [ - {file = "pathtools-0.1.2.tar.gz", hash = "sha256:7c35c5421a39bb82e58018febd90e3b6e5db34c5443aaaf742b3f33d4655f1c0"}, -] pefile = [ {file = "pefile-2019.4.18.tar.gz", hash = "sha256:a5d6e8305c6b210849b47a6174ddf9c452b2888340b8177874b862ba6c207645"}, ] @@ -590,19 +554,6 @@ 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.0-cp27-none-win32.whl", hash = "sha256:298af2f14b635c3c7118fd9183843f4e73e681bb6f01e12284d4d70d48a60953"}, - {file = "psutil-5.7.0-cp27-none-win_amd64.whl", hash = "sha256:75e22717d4dbc7ca529ec5063000b2b294fc9a367f9c9ede1f65846c7955fd38"}, - {file = "psutil-5.7.0-cp35-cp35m-win32.whl", hash = "sha256:f344ca230dd8e8d5eee16827596f1c22ec0876127c28e800d7ae20ed44c4b310"}, - {file = "psutil-5.7.0-cp35-cp35m-win_amd64.whl", hash = "sha256:e2d0c5b07c6fe5a87fa27b7855017edb0d52ee73b71e6ee368fae268605cc3f5"}, - {file = "psutil-5.7.0-cp36-cp36m-win32.whl", hash = "sha256:a02f4ac50d4a23253b68233b07e7cdb567bd025b982d5cf0ee78296990c22d9e"}, - {file = "psutil-5.7.0-cp36-cp36m-win_amd64.whl", hash = "sha256:1413f4158eb50e110777c4f15d7c759521703bd6beb58926f1d562da40180058"}, - {file = "psutil-5.7.0-cp37-cp37m-win32.whl", hash = "sha256:d008ddc00c6906ec80040d26dc2d3e3962109e40ad07fd8a12d0284ce5e0e4f8"}, - {file = "psutil-5.7.0-cp37-cp37m-win_amd64.whl", hash = "sha256:73f35ab66c6c7a9ce82ba44b1e9b1050be2a80cd4dcc3352cc108656b115c74f"}, - {file = "psutil-5.7.0-cp38-cp38-win32.whl", hash = "sha256:60b86f327c198561f101a92be1995f9ae0399736b6eced8f24af41ec64fb88d4"}, - {file = "psutil-5.7.0-cp38-cp38-win_amd64.whl", hash = "sha256:d84029b190c8a66a946e28b4d3934d2ca1528ec94764b180f7d6ea57b0e75e26"}, - {file = "psutil-5.7.0.tar.gz", hash = "sha256:685ec16ca14d079455892f25bd124df26ff9137664af445563c1bd36629b5e0e"}, -] py = [ {file = "py-1.9.0-py2.py3-none-any.whl", hash = "sha256:366389d1db726cd2fcfc79732e75410e5fe4d31db13692115529d34069a043c2"}, {file = "py-1.9.0.tar.gz", hash = "sha256:9ca6883ce56b4e8da7e79ac18787889fa5206c79dcc67fb065376cd2fe03f342"}, @@ -708,9 +659,6 @@ urllib3 = [ {file = "urllib3-1.25.9-py2.py3-none-any.whl", hash = "sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115"}, {file = "urllib3-1.25.9.tar.gz", hash = "sha256:3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527"}, ] -watchdog = [ - {file = "watchdog-0.10.3.tar.gz", hash = "sha256:4214e1379d128b0588021880ccaf40317ee156d4603ac388b9adcf29165e0c04"}, -] wcwidth = [ {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"}, {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"}, diff --git a/pyproject.toml b/pyproject.toml index e364db88..029297c0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,8 +28,6 @@ requests = "*" stem = "*" urllib3 = "*" Werkzeug = "*" -watchdog = "*" -psutil = "*" qrcode = "^6.1" [tool.poetry.dev-dependencies] From 25bd48251cb1d4725a87545badc43409286ba29f Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Sun, 5 Jul 2020 10:25:16 -0700 Subject: [PATCH 24/24] Switch icon to 512x512 png --- install/org.onionshare.OnionShare.png | Bin 0 -> 24613 bytes setup.py | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 install/org.onionshare.OnionShare.png diff --git a/install/org.onionshare.OnionShare.png b/install/org.onionshare.OnionShare.png new file mode 100644 index 0000000000000000000000000000000000000000..a4810d049cac1fd9927d228a5340ac1fd1a210c1 GIT binary patch literal 24613 zcmX_o2RzmP_y7A|F4xK>o4APVkwWG*qU=4hNk-Y(T>ILhWY0p9RYLYAgb+nmvNz>g z_x|7de1HFkM-M&jeZ9~7oaY&@bI$9$#Oi3NQjju{0sug9|DLiQ06@Y2LIF4t`0L1T z;uHWN$xcd2I`@^7knWyt51m{c0D$LN@UtfME*+ZQwvu$ZH<&WyS9T>@DzYNv6(OS< zIIZG4>&Xt8Q$*^m>%2lq;VvBt-ut)L*pQ#38c4$n;2c+QuvR+W{n_iI9Pj9bR$mIQ z2F;#Xprwr+hMk#Vw|zKzj5YF~7OSM5t7ecuTK(Ak7~ zw;?Itm!vNZ2_I>%v&-Mbgnu1-SKagbb`R7L zk*&I_GJwDQDQGE813w{gzh~+NDs$@cA4HKS+YkJZ*!#ZbUE*b87!@6qKe4kM0Fc0a zWd#GjA6q|tgJ^tkM0<`8eZ`!zS&?Cph*S;5wQCRs1H$Xf$~9B(13$jc`@J>yz2*I{ z?^@lx+F=x$cL|?y{6vP42%@0uDW9@aT(jrdlws^CwZVDEn?35V`<-G}uN}udm+#PzJt@YD>DXS*8WT1j+H7 z5CGhRq!1Q}p|yY|2nO<3)eBNar~@fzK2haG698(4WnAS2=@gaBL3<=Jg`V0-TL_Yr z&rZ}RAt^!2homwO8c7bwLhNth@43l2Pt^thO~BS8T#bIzCncSzYd+sT1*_Lg^t50w zFm%70X4kD6-dbK-4$ndkdQ_ENh_XoG(;5g5Q8lc+3it@+NmYEkWE%7E4kINM8Su;Hyhx%xJmZjk2DNqW$ma$Su@u2O{Ex+0EjgEFZ79I zq75jm3DEh#c^TQO= z%!c+yh*(vV#jmnv&UD|qgmh&2?n)0ld~c?mjS`vlCWZMnU?PCxK^S`MxNdGKB}AG4 zn4oSNC$&g4FQ753Bp>-Egg+)0uw>#FSd zmX)-CK}Zk5sKOWi6 zDz|hzVW3>N3FrgLH)%Bxo1+qh`5dbyB0Z$c13Z{iwz{R|gi5MAmb+p%KHv zIr0THphhF|RyTA(9~d8|J5=da5CCY7N}{zXJTOUQ$OUfTR|cHQ2#zS3@%d{SL?c=Q z=!}Zq&5%;+ehfT;rSvOfv~(Z~77DZ_BXwT{|4|Q<#U_@70Xv;zXMef46}`>G0V^_u zWu8lBQ<4X$YgmF)2Ddn4b_syxZy3^^pn3~5n>fD7ZlY1QNQf{2`sI`Va%!-TF5WEj z15m=;ip%0NkmfSqHF?}=|5Ok!RSl4mPmXife^qexiB91h0WvBU;Xecc@J6sdx#6F} zr7opdzUtrG{0P!H?|#G*N`967Aj=u30@=t0aT>V9sre3em&jd$SpJ#zBne^;*dvVx zK+1i~s>^-lMFEs(X^65Y6$hRd3e1Ja84nwI!G0m>0M8MsP=h>OohWI@ENC*Zh!YACHG~)s^>N*spZCQkUcndkF^M;N3!5=XkaB=Cb%#Ti-n=hN>2=%jR~;C z=v&;1G}WI086pz=FaB8YE3M!OwoG|T+6j8dkpq*mf*n7ac!=&$MgThNHZ17KA^^M+ zrDqTpkz73IN8ji$KgE3Lhb}PYmY*HFZn`r6vW6fjL>M(!p?gEb=Enf;;l~Vm zQBpd9RPUtsoQ8IT9}u!-Qa-w|vcgdvuUif1q-4xQLT7`bkg9Y*QILmf%g-5JE(Ba@PXv^?6_p>q zg8Es}P7;$jla(_NgC^3c+ctKKqMaF#5~bkSDDVV)vjta#8DM0<$>u`xEiT3O89>OM zNqPC97jQo5D!S`P(-B4)LXuaEQ%73Mp*u7pFfvHycAwhoY&x!L?7tRBffJJu`;c0` zvT=yUL-0v181O{ge2DlT(Ur1LCUiZdTa1F^pq3A)&k$TOO$Y~#L;_n3X(n25E>TdH z`+LV=*7;+W%jFaPo>5c^I{-mp2rKxB2lRBHsCyQCJ}R< zLb_lmxnJGbG21N(S~tZ(@j+l&`6&#|4l;Q@OJry$%wJ7MBSwnvz0rMgwkNS-^{(8R zJw~1ih6xKtR){fb8jF%v0y@$eMVcxNdvs|2Od={+8Ke7>xL3sY&pe>f-R_eAIza|~ z2wCg7h2d$ZRcen~kvgnO=xp1gLAOza7O#84O}ZAfl@&P1_(E2AAs{)jgRTQE!>U&3 zf;cFh!bV$>RgLg8O!$0&0&jE9jFKa>iRg6gMx(Ey-{GGE>80#(*sKcK8QLz z!PNujQBH_wy``gg1BI5?1s~B%!6M_V=F{xPB(>T{M+}Ehy;QmaJK5O_>8vKpRqid{Fu7B~I#XKzamd z*@Vyk3)6DMBAHGIs=7hw%R!%k=2QQmOavLKogA;MfLMtzK26JBCztAe-OXO3${|(i zt72=$v6Q-Gop8IeKn$tO2ECtZEy94{h-ybNBB+_dQ$`UODXM4$0ign#CvG%m4FX(g zA`mJi1FYR@yVl)1zu8B$41^rze=NqkIy;9C+eG|yQf+z78gtB|(vwGOuvOWx_| zVMY;HoXZ?L`&Rq2Yw#WZ|bGCZF3rj~=n2+eLNdw!ThxFLp4nz-Q0%e zb}bnncgDMwZO{+e@KO@4 z=pJHTULKbf$HXG#4xhX|DcOKWJ~t$dGo~xHm8RTT`*7v0&WLa|O@$4O01(18pCPXj zYbn2+_bfiLfzbQ@cKEbb4fzT~U5tyakzRDyi5LDGn}4i&Be3 zmc!W@f_AL0-?+iaB?gm{Wvf~w5qe2>=DXe38hlpm-}A5n*EU%;YdB#2VF0oa@V@6< z6g1ks$-OqR_P0a2(u&1OqD!e%3_)|&uS!ZdxWszggg=u#EiW%}Rb^CDQ`$;eT&i_@F_aBWpQ*g3&X^MJRVh#GS(%V9$0%}-D0(SoOY`X# z-;bzkJ<`?KuAb>SPkN=X=r%A+t}+skq3fgZoIsupb;o_0yW|-+0Y{4fy5$Fqxq5#3 zsz^Rz-oB>}(&@uy(SNMo;V(>yX`Zu6m=9@-643$Ll=wbCX5e~wyjE2gqj7$i?nyCn z^>eeDe7{M#01ux)XR_4=#xTD!e0;~Ar(@L=l$gg3lo%6ahm$ufqZExrem}Vji4bCm z^b(RMZY1!eqV1EGtZO&3>q$>Euikp=U~)2`Rwgv(%%GenWh3~ev$VH zTNB0@`5 z*mj34TjjYHe}TK>T8vuZwju-_lKy0~{^(Spn$t@l^s_s3P`MN``UP`>XOimx*Te#oBh z67NCN;LXJsZ$k6q*d4DZsHu<=6h5743zRn!G>xjl|G8a38^rk-SP~2u0JfQMzJOoi zeZr&(HUxAQLdYm`CFc0XZo0 zCIx;zV&r@KFqH?628a_pMHkUNbl{^>t`N^a;}iO`{dUH}0HXPu#IN=FULnd%~oOC&+c!mwALK1&JYy=Tam zJLla}-6HR9+d`vtL1q=`fW*)7L-7bg8xnNkdB|ScH9Z>Zfd0qfCT;NFvjl8&x?}dYfuxhCtl7gk{_@!Q%*i_kG~!V5Vt$b;)Av2RC@{7 zYM-FHY5{<#KwfOqVFu| z)tj;>mFi$hUi@rNRHFT42fERFjL0P zG8M3)0JK=yFq-i_+f_f46zqr;5Lhfpk-WYk?PmJBu9@TJ;c;l|drH3O>~|{{0)T?8 z-q0(Z7JWP?ntisd#ckuNzUZG%Z$x?zpz=lItkK`hY;e;F!fY4R<)7;*PTH9a4f<#% z=m;-dNwi9#vj5R` zV(YC9&)lS;PSle)&CEe4VnIV?+ycOT3H}kNtlMoUY!Nk+*OEwi$nIR)pyk0J;lt9| z6m567H2i>KuM$^#-I!ne_o_8ciRce6p#R*7#UO~F^~Y48>V;#;uP-lml#{nu$s_tT z|I+MsxE!}dUz6XmW|;e>1N+kqRw7&iK$yh&c!4biHk@sD>s~mT-?9PfZ~UA6R*suK zw`Y9`r)I|C7)#LKfT|e40i5*9Vxf-qA(d1LGGSck$OHB6J1@I)l;|BEq3fc6(x|5A2p7%=` z*}ZX)iv6sTAVIYThkT%`l#9pY~O7SBJXTy5RBleucYG-tefSMT_G zw8FC8@4&(RAM;jS>Hg*n(Tx||=Meb%N=+rO(rK!Xg*yX5(Ln~hn zZuV#!#7S8H+Pwt1&|8s@Am-`Sgnl}3^m|Yc{LI7ohjx%XPEX7^E81gLRaWVyn%|>u zN*UhYudh)wzfJA0!f{M(j{2Hdy`sF|mj!cK_^{uj$eLP4>MYSyGGqhUdsz&ozs^9i z*ZffeYjMEBdR4y4U$iU8Yu~5WzFlSUDmI(n-jxZxd5Fv#(@tNuh|}b?hwS~?OBQiZ zXn(+Bk;g6}y;|wzKL7TZz12&m3rPy}GH|MBvr_O^OgB2;AlM(ZO02y;qUWkcONQQ! z4uvZV04co}V=aUV?G#n>X#U+#)a->@M#^E`NJf#hAq9+DVrMUmnGth#A5i&w>*)MZ zQ*dB=o*T&;6dChb7@F}pcx*WE>GMccNBKC>644+ZVO`)QwxZRvpD`_B^3bSjY|WZy z=Y;^NZHBFWE7^4Lb)B|7Fq*zMRJgdpP6~Tme<5DmDPP0l+ zj!?&5Z_1@w+s*c5je+Lt!Z(HKpsf(Z@Wn_lk);#@?}uj#ieS@C5d|X?pBv3z!>z6` zD@qZB1gkPxxQO_T>#N0&KR!+r04!4k9oi_ZuOG`EXS(ka&f<=?F$qcb49W^Tw`6F# zMp&=BweCrJ5%jiz`L4t~lVmomy$g&m^aOr!XE|pN{?0lytmL^^r;w9J@L<*{0?3(U z;n98sq;356$enTH^yPPPnj~d6L}3#rhoETohB{=By}Vn#u0gu(*LLT_-V4iQ+aR2V zQopP3{iv(jpX}Vxf33J}Va*HA@Di{^zJ5!(AQ_7W8ANP=^byN1 zGlV~t(z*O&Z1u&7JL#Dbr2v?A(*xO%>+blCjEo5encHW)-XmLIL@;pRGS8IBI_7a6 zbY@iPGgQ1Q{C@Jm;;z-Bf*hz{L|5A{>RRf(^UhVUidvI=!}!K;afW{MPQ6&yT7w_l zPYltj(Rk;NtUQKnxco= z6a?!4q_eCdrGhfpi|neRgaz z(ML7w+;F%@%8Fm}01Lp4l!h-Jezv_= z*QBcXyB@X4K_dgt>vFL#z|I_NdD#;PqW7X?oBFr%`QW+mb#AVkRCk5)xy-6#^w?9*Wt|hH*Z1EzLL>u@@O)^hSz!|>hDYSp>Z>k< zBWlq%ioE#obwC%~D@#wHDUL&%{3t)-u)~L)XdZ~}&!Ut`;dmR6sy*dUv|*j?S==_b z{?sw*VX(!l!PfX0U$7-m`+6%GV(%I1UiF9Un->=vBcp~OJYxOI+@$8a*j`1PdEafccpeji^zvFmRnXz!Wb5r8PuJXmhM$;ZrJtSfZTRG2c_Y->Df8>xaA8{aybZdC!i5_2~ zMgp_~Y$u!a{1A|dWnNG)y|Yr=6Z%0$6&GVj=kmH*+E<3>FjV@oDv;B)Jw%OC?x->k zkdW-k3IC(9!pc$o*AV7%0LK1d*f^?E@tY|!lDxtV&=L6el=;gM!b)mBFKrp4p&UG z)lVnVgn%2qZQ+tWPzbJWqHYJ7$U`t*i(R%HFcEcufuwOD>0LiN+ID_e!O3U*VS~j* z8{wWeD88bz3ZH-w**uG1Kw&uY7N59-X*)g0s!TDk=*4wS5+hdm>D`Q|Yvl+0Dv7d(_lV`-Lji8{J_y1IUg|Mgi(z%pOCzha3=Jlqs ztLNjAA;cWuj?qjf)WwpcpUtF!cF0qx4((>3%BFXF$WV$z^$$<3wl+@gH2M?X3!hda(q~tq6bB9m1}re1K+3ik+z#8&~n|+B0+}D zh`R4*0UVwZEee$W1qp8Rc)IfPnSJzp3mLg*WoHCth!Q7eat=udA*`RdK z^==efsp?`q=$8&8sn;LtxqkkL<^yW4E za-e*C7 zh@i?08s7I8tpIpN!bKLoXXSUI8PN@@FpO7L`kMUE2_*4$ zBKfc7T8H}~RyDj&g2Pj1V!S^-50(cLHA~PcmEW;P-M{xmtM_2!rC36`qfbPW6|F$S zVT2|{Hs772q+o!$vE{?!O1)d}D}HWKI2%~sUUqwYs!8kW>LkB<6W%twE!l90EdN}t zV_}*2Bckq6g^RM1CV?x3c*6rB$t)Ix562OEz&$GJqrw0NMGAN_iRuGSmZeWU?3FGo zOHDnTd{U%THdL6{M1`Q2e#*VdH~l=%Le4vX3S0k<;b-g}Fl=C{obXp&x!t%)u<`R` z5@d_)&Uu}~>AP_VnyX#CoWI<|dIVx%WNh14a*fB*BH`!e(_i<7pFIthc{vW7p<;Gb zO$uH1BT>^jIpbL391TYKE+-A#4aoQI?&)T447^#iRNU|kJQXMoN59=^C4K8y5k0tQ zi@dRMeWT|MAa^)O3#5&GU}@)ha$~!3eK^}4XSgZ`m+-t}F;yBw zwo_pvb8XbaL3&W9_AQ~jFqYA!)ogr+Gcc5jjyZafp0ckxwkstsGwBO&ZsW7{=Np?F z9%q^L#m>gGU6PG*V8U-4$`81OYvb%ltVtdn>f-)(ZeO;6e0PImYOOwppN`A~>-Z)# zJz?=YTjcRLQf3CRv3h}#@CIwZb!A@ZbAN;Q310(j;AcGT^guu1aT#3TE^ z!xMjx->Bam`@|7+aB#!#;&iHJ18-DV@_a-VFQ(oIb6KfS=$L_(mAykLdlOQBy6$d> z>H>ci6jef-rgk1O++h9G$1DC@DZdKPh|S<=Ql2tuI7xyosiBZAu8+E-X_@za4_etC ztKneZSl=k=c??{shkfXBn_kW3%i?B#J%3svrS{LL5c8$s;B>~U+H7F{t~aRwx; zd@D#df);(c%l_6Xog3He^TG!^cP^XPw&E`k;ww7u`3+Kc=2GMNO)W_5kU6qDrocVR*~)26XH4F5L^kUZU3BirrdyY$j6q@yUA zj{So^PpW<@7&XYb`=gk<3gagW_huBMJ(_t+yBgJMc%_5%0Q>tPq$sy1#Pba&+u5SG zLV3Q?R*+>-BLwJ)q_(aIWVexPTVk&pg?vnnn9u$$ai`h_M-+7Sy&j_;ucVetgOPgH zL0D7iWKpx%74-ln`K)aEc~y%ga8PuZ5YBf_j}Dt@m*@)pN}HB4CQVQyYfDfS{iFm-Mhqs-nn!_$my3i<&IBkO9uUDHimrN_(`0|G?Axnv0{TU%IbSCu2m)ue97Zv>f@Z}aHa>{g)5o|XE-lbd; zkRbf{7Rcbxj798m&mJM!H>UR}mtO#(ZFk*62SS=p7v5$Z4zaNM69T0_W9z)8Y{8@; zmVJM#y%A4C}%+5CXq~4IsH6Y*7EW^>kELRK)?7w853HN4usyhR_)ZoEhGM0RIXJ5 z^PDz)@oc0`)w#{UTXXX>3L5;Cu}e2OfM<|4dOv1DfOm7-*4!goi{L{e&`)%t1{V=^ z!(aO+URNK{Ow#mTkF?c7Vp}sL`$hd<7;|96HTjUgoGdn1j+jQtq-2GyNbO_q$C~Wz zK#BH=bk+@ zc1|gPQ|4w)7-3mi1JCno0$p>7fsDOuInS~y-~4x z;i|#`G}143mXk`Uh(l!2Y-AzIJ8KWRed8RF5I$~EqIvvoAklt|!FOa^;q(iYWE$X( zK`UXq!3v9HS3W;P(7eU(c3#Fgp}=pt9Y3aVlX1+hJdTz3LO&(-Stkmrqxh1r;>3xf z{Mbk=VSc3%&Cydr^ARWU;WcpYzz*=t@Uo@|tt4d8HZ&XxaTA|wz)>`?1dTKpy%D12 zfA|jN_tL%p!T}!Mt^>s&;Ue5jHA{oEng7iLU3zW@9;>F3SQqV5wYFjXR= zMuJ&I85JLC+hRmm)_p{cMh$P%tT~{#+{A9pb4amu>1qYVr34kXjm}q};TQVWzbw+81(Kn!x51Fn--&R0l+!QJPc0ct ztc;Ui?uIhD$eRx4CTYF#*5`e?^E0-?@k%rew`dB0pkP>;GD8m{9I?a)YAEwclCr9|ed@<8krerE3tFo0^ehdMmMnT0q@M7+(n&|7tP{j+ zzYjT(FO@ZD@E#7@n(y1x(*UNaRZx+I%otf-9kq69=Ra->|C3*}s-^l^uh78S z_xlraSr;B{VnQ@{lxT9a&oRAmLZb~JkXzt^s7=8=66$8Hz1*NKuZ9p7Al`&b{=XEXNdYJrOWu?Q96eW+Jf7Uu@B zrnvHTk*ylEyk_Zk8{dUo$GHyeU0io=lGLlMmp56;V8(esrg8OQrFLqYD`zEYn2 z4vpcMWjJWF(TgMc!cv59+suZM0IEF%lw-aIiX0drxM!R7g8>(22E9z!f?uDB95*)3 zuJ?0_3(aCaC^+3)AMho{zU}Y7N7HQDj!Yuecl{hXV*wm+94rwk_`!gwmRq+jJ$Q?M zwl6nH#(8qf@bYM&+b7PBA%tg^A!&Q2-Y%3Xp9CmS*Shz`WyW>JEJ(V*uY6uGZfR}& zLY^iE+*z&)<)Y2!TV60fhoi@Ly5Aei#FvxiIsP?Xwe%NKdc?XY)Zz1a{J4~5hi_tR zNT;bQp9{UFY}oX6Z^h27bFQ0y6kBY05xAd}D4*kBZYATOR(oBZ44KL3?2E;7k7^Mk z{J-Lc&kC6gkFL$Vw81j+YIN?%HtCv~d=>#(Z1v|{ydW9Wx4G1!PWk*uQHTH0zbj9} z?xoC~I_{US?5i)Vk(@8L>V*Ql*B#dWY>1zIOq1iN=~>*-v*3j6?HjY;`WDxLBKhW^ zpMzl3w?~9JUN&GI7@ zqktv3^HSK&S^V5y{`*%8KmcIDfmPPy345o`p((7mTIjR9>?^!_wutu8w2NhuQh>Wh zgOt{ApZ3F&W*7_Z$Wi7R%FMX-BjH8wv68JPN7tTcu4PPWD)rWdL)Eup%*cd8tIihB z(>zZYYW3?MBI||!vGCV_H}-g;`VK=R8$+H%4m&`kdt(K6azmR32hk zEdi?!ISSaY4~CvC@m`Q-!L!iT8;TjZOuKT2*=E=b-vmF6ap>;gHu z7GGl<4?}LL8kzz~FGv`#u74lh_8AVrN@68wjVu$shkTi>xKM2iHXxweRL!$UVBnRQZ> zRE#{>JMgz${G=GYz?sQ;vyN5a)B|Q+>)|PbE(p}Q`R}#zS@@NpGNC-8y{N5c-_4TS zCAmD+wsv8t$c)Z^;LPdPyn{-I{Omvm6_}4a$r?dLWgP@U(C7lb|I8d$`RFPe=`vZ( z7&!LPM+?xt`A=F|bzFTUI~Ha8QhC@B30K@;g8}fk+f@JJ0!kOOcG@#OhRAwj;8V9^ zTuKAfT>}Eg>i7s)th$7GnT5MueiP`8BI)0iou1!GjCG>z)o^L zle{#%4`l~{FyRq*#3S&DXB?NVY)gVXc$Zbq6umGEwH^(Ez>l**$GoKC@Qu?bdf~1f z=G7l~r!rvkpAnd+n~^E)6(M*d`GHnT&`&{7I0|YLrU1V*_Q+Bo$PD=RsIZ0+xgYzb*-;0|)P-vxvaQ z*XfI<0tlt5F2fhds??n`Dru!X4qX~kVBz(pX@S6b$3aKIDa**XV)2&1tzgpjZ{2}zExcf7O$iC&JAWm#;DiQMTw)Alfx=8eM-yRa zFf;|poI@5caMZY40XTJOeEITwc3t@}VBt0}M>j8+$Bs}3Jg{d^u>`0H_yQ(fLRnw` z>amJ&TwIbZ9E6Sq*E-d%4}gPuhG6fGJPf4SHGk|!+P(t9RFaXw5DjwMy|{aWA21Sh zqiIS5)vO;xT?GNTTG~4%Frq>wrb}o9TgV=33CAVGDl5xq6a4p1lf)IW_Ql|s#+U%p zALv{EBV<0AB@EDV(ax&3R7_=9{`bawen3tLXfg$w1zWVGE+qzObJ5-|A~hU`6?kfM z9UBS9$1jcppb1N!2dhbbg6h2cooHxi1~W8loC?tOJhuP;^f?Szz8(<0m-un%rLt4; zU{i4PPLo)~e^hgoig++t@+6iPy2C9~gV8IL4*%gGR|MWc5LIUL1Sc2=nX4+J`GL7~ zX^xlwLooV1Z^awE97EYb2x{E8^Y$%qcj3Ra%l4MU{{h4q(>TK#Vn3Ti@`zTxDvW6?dJ-SEcl(+ z7})h>XG~7SbxGuZ0tNr>qeBOq%@v%H9`Bn1aw&N|H=xx2wAwx=Pl_(shK@dRQr5gn zar{JhGv_PgPhuZO#6Q(q%I*9nZ5O?AO|n~dmblkKBI!S20@FT2-E%gW=13OE8ZS;{ zE)DcbsPNe@8Z_La>YKy?PWG&^^b9pJCp&h3r~7~Wcf+RG_yMnt6$41w)Is#zM_cCO zr)-G3RB2E0|8Gs#%@L`pm1F3r#<)ZmeHGsd>n>+7@t^-eJXdpgOi*nX;u(`J;WwGb zH^Ex@J8zd@z2)mzU8pgU!lk8+Ko^)DxEyBBf>8*V#>I@me;@A_L#y>SnepzwZ9<5# z{RPh=kQ;aZ_m$}kxLflXfKkTv!k@p5Ea>`2eSt5ZP6Yn<{WdKC2?uR)Wmo)Ax+A7n z^S4siKb6R?Pe)wLlc927KVd@?3GTu{h&%KiFZxC%gJWQ1ZI2|=ffX>**2F;g7W z;sL-5A~4j9MAzH)xod$Z7K@xkTHRd7R-OMrBx|=RFyxu517y)U1()&&3$OY{Q&KR> z5{_9E|BuqyHHlyN2f)Wi!F|(v+e9J0*c2L}#jkzB4*#iar~Y*hv_Nt4oV2|pDtp1R z5o@ue#5ux9a+z!XQ|g=<1VN~92x~X9xx1dE7gCDV@m9PggkSwl9{$gJb0_p^fZKXM zDH7*N0O0kR2@v!+$BCu$SLgqD$WC(GtnlIL!$s~)<9R;Pysf>iO_Wmf`+35B74kbS z@HUsAd!%WIEQUCWLw`*or@?3#GvfPgYESu08+UBe_zySN`R4g0Qq=oIGwt=&s?g~2 z@>z=@*RACm%ofW462lMbao!^vcYgH-9kAGqzwZL}Es9-TK5AGTU}pHI zme8~Bi!%Fn(B1 zZpqNUIIoaB{AWc%y9qk#n)q$px!k3*vdCig@p(6`uVqIJ0hKYdff^irle>|-E=UVh zh7#y}Tl z)oaNYG~V5Cq~DSp_vZFxmru=0OOhr2TX00*`W_7FA55T<=QGRtJtYFN--SPTQvif; zc~J@L3*$}Qz=m`MEEQOrFtasMQN>b`N8HkODJ1~cSM-?9*@BmBDro^0GwmK}7w_W?q^>*9j3N8AfdL~=-#<*d%kvU@|+b8TwyeRgdgFKuE zV|>Z-cAx&m(i<{#-0vYu_aC{_wXv$1xPBz#-c%_r4x8W?tw0mWh3;y*Fen?8G6NnY zP??WqlF;9(t^KjHjvK%9J@y6Zl@NsXM_(?@hmtUvSN!!WC0IfI zbYPph_fLZMf)l8YUMv-T0!l-X+*eSZ3l0sS+(}fTh|#J27#XG$lh|a(^2BeC2=ht) zOUA>aFDQ*;hKlSyP)WNlH~wf{Y@2VJ=YrgrUo+3Gy`E2kjL3wN+#%_|mNAGt&(Nw; z!i$|2SJaZf&c-%aJGZeLU+Kuzo{vo#O}QE(_+Fb^9f)abGm|L|`I0b>v-qBsd|lns z5qNM$q@!mNJ|LmB!n}T-Ggr`8FcwiAh=0O@{R0pbiZchDSkIoFx4^}s>#%tHzXQwb zU@nK}To8PH-*h`2nsP1Gf*4XSYFIGvBXZWG@t&HdEkno`gl&8K7=do{dj?uH7(wAT zO8g+vuQ~eNyM6{(C;U7(n~l**>^(gR+mBWYcfw}gk|e0^Nrbi;qT@NMBexT}MqpR*%!UvRUN0bL6=NWFrnH{#4JMB?yS24p z({LOWNX2;V`^x;_rF&jq9bt<8Z(zRlRy-S?CUpxEj`LL(J!TK8wLOL|B8 z5|0k#1|ByyTnx-;`+vcI;J-ZO?wao-geQZC@b%_osE=|@G#oonq^Pa+YHzM2KKigw zVvSJ+4Msu+nE(-R#8B=AI!WwL?3)H$*rrX2R7ky8)ukMTQZa)bXHUY3 zNJ*5^l>jksp^#NQQU(Y0qp46KO?O3#TnNR5mah_!H2j@(@fdjglEpVaRMp|{Z^3XD zoSd%6h}7<(5k7c2Jy}5AlL5^;ge@a*Aa zz8ft%cwHl4A8nsb8tzUBJo9Ix{mM&7pmN0;0nsR(Djcbn z>u1W0`ZHe@^KPzJCmbU>fKhD=p!rprc>LY2x$f`IB|Dx#12}9#!72!Vq6L_yjzCj- zhmwD^dP;w3-EfU$?gI6#zLS?wL!W#%3Y@;6CZ+DGWQ|sp52BIv48WedjD5a@xazFK zRkUq>%Tw*aRuu4JMAaXv)q63!$Qp@*KsNsD)SNOva2w)6&Q5GH`;V03)3*Ip4wUTBn zTr4E#gu{!_Lvoo6cOGB={PwelHQ785!@X0h3AW_mQwE|0CP4S7?fr|6(|_cu2^uUx zf~_y!SP%qdKQ@mL80do7-#jbM5x-#@(2Hye74L#`=+@{m$U5EnwEVO~cpeW`O^YbR z)_}wAvwwFUH~hu9T;Muqt);Jl5lxH?^i$&Plf-Sg@RwYS;1#vMeKf_iGwySBs|uvQ z##19=dE(Zd{UopxzD5>5*y&4xedDz&MNf%4Rybn()+d~Ns?BYpMeL3}n@9t%O-;Uq zA^TF^o6}A-0g)p3VsOT(+oAhpIPl{@3r7MK7?IqM@<-VM)sKrjjk%Qe31s_@x+B=+ zF^9tPY*f7%^w}xFg<&V?G7gVJu*pB)!mP7{vo+I~=YUgp=5w3PxObAfS%=6dFIuDt z7dMyf?1abKk1GC;6|+$A9E5Yl!ZjxOc?VZ44t8)4jo=snz8_l@rsQqfGNoAp8Q8 z+u^5R;>u7N_*-fgx3t~Ak^TGIORPIr!5{GSolPW)3-hyT`g!j5#qhNNg5D3^PM=D8 zOJsphp3>(E!t0_f?o!mL)C|!oCN34&!Uf_Xzehw_8(9n(;z*U4r2|KyKFM)O@WPM6 z+3JI%6OQKK@tN5LZ>iUMWzWSoM+F=Mdm4WkQ-iJ?raoRXRWF#cQ1x*xp?}88t8Vgl+TYnXTK>FS5kF- zVeJ*Ubx%OPD!1Xv6dz{s2kaJ0QJ~G@EiUEt5wS>t(wH1 zEJ2?dTV_)8%z=pYG|>Gt&H>qHf?Zc^_8OEX4^O(&*=;psbQpuv1voUGA#{n*yWJOQ zmRAE8zia1HWbwZkpqOtekNbJINw=XDK{jWGj<`#FJ5%XFvZO|HFb7e-D8qW=`mCr) zmWsSgPWvD*c-}tog`>p#}BE2Zw`S#1fsEek*#jaM2 z;#G4Abza|!f?OJ{LWeCpKUueTL)K(#B~sH;$7GwNy#rcrP2~DXp~gdQnGe~`{^^*t z0ECD|(q`6_!4%xh)i0tRrWXTV&RYcUlo(7J*i5Bc@R%7zrY3S#v(^Uu*~DOyQOO;$ zDYs?FWY7L8KX7IFRN`|NthOYmjiLQsLf|#7{1XRA29w+A+8A}p;@S_?h7N{hb5@C9k87HFyPB=0>znnz zD~W}MsgQ6URNQj}-L>fIGLdfYSOpC|@}*C`h3WzH%00^L4@gxFG-$x-7bIWa)LAWI z%FF+ot7_cVEq;=(431ax0{DfGQjMxBGU0{4qHn@EHbmqE?&;@&*Ey4$4hcS8P(Ofl z&Hz}EBf4h))$HmC69z&mpXo^T8w=lj-5d}dBj04qe}3LJUgZ(*;Zygd1LWZN>r5`p z?A`D+iST`dZlA-^7kF7cT(9Z>wQ$t|Q9e)q?&uCdY49YZj|K@(IFLrE105J+Ehf(hI) zG-t(uahMh*9;W{QRCy2wqvtdsXOPUL9NBA?ijt{q49GhhL^T^h)_WJ|?993IT2zK>Y`)L=TpZp0kuR3KJmnqaVest^O&b?<+{ zzVdocdN6$3;U)vLT%<*2x0JEQ^4_PU)R%buNwmjY2H{f6gKTb-TT)wLd)lB4FA9 zVr69miaT64l|d@-HXqltw+n@AtF(87O+J@JSg9Eh}9FywsCMkk*?0K0bm897S1e;zrecGx}IAo0mlz^%zgnQmkc&CJCdIm3XK79 z#I47&fZL75$fO|21ghk!h`@6Y_=<;2O^FKTThB)(pvW}}VB+~5i1bQ1N-X9Ezzcn1 zUqkcs;exDPUZpR5ekVfXJ*tT4+LKU5e5WK|P2()T@3%Rmv2h$fm=Zcj@{VN=#PV+T z^5<6%j#_Gm&W*k-GobL{Jz7c=P#9{2(Y@XfNi`ek@XQDlvE3!AAGZx+cm9%Ye4O^? zr}!I~#TGdLlz^jqukoy!*xT}e%i=oVxEPOlTBgA#1YF!XQX-b$fJWzz@-Ua{^Jv8g z_zu_u@%F!Yz}I5oyEivN_kGZJ)Sk{=0W$Gvl~7EW18HEg7>0L=sM}2 z?*HOAosPHqge#xG=FNdBsw1n8&KeDR`?REU<7yP2Wc~0Hx>pF0(-XhYdFb6g97$m$ z2m}N~l9ozLq%6UWvYS7VKg~yOq-k7s@b3T^vIwU3aWE66&0gf`_5gp|`pD-5w(|!d zvCgEtM-Wx-mlDPAsIi`tt)>Ft=TXYGSJ=`W1k?|>MAts%0v4~uwMt&kjZM5FGwLI$ zyMy9W2m=r_Ld4Jmnl#cqv?qZ43v0Q7UadF?O=nJTg66Pgpml1Z{0kqx4keQIhS~OVzg{jfe=rA@4dIfxSoo?XA~7P{=gOu6AR?SJ7v(OfsR=zpMI)5 zD##)Hc8t7TbdZ>2d;i|&V8LT+t?d;ZTi))^KCMB{WV!Qp*N}%$7oK7Pc}F=#QSPu)My{ZYUkZCt*Z|Mt_YhG}jrt?3Rl5_fa*g zUikVtPkebNm34JR(sAwk#H7G1A*of8+~gDz&GCWqB8N9-OgVv% zb!bW+RF&uAyuk|72C2)z7^Joi&xXO>w!}5VePi+VvrTGjaD@8hYU|Q0k$CwDszY38 zWGedF@Een%Y+0+*hx!NNg#tf)@Fo~dcf|f^zO7a^L-#%?lrrekXg$_CDOt#a4Xf4< z)G;ZpV!3l1v~QE{I_`P<;h|{hR7#MqbO*Xc=u=>CA=3-?I8bPM(TXCDoAvP8k5D^fuf%|YQOQNj zu$A8)k`_+dV6-&>KHk%PZ@&i+IgyrORW0*-MJ6Ug83e)NdAAaT2v#)*eSWb3yppVs9dtC5l|cnu7X`tR}aU)(@as_f!;`kxYz_hAWdy^|3@R&TM`lXsW?BJ z`AmCk1*+5rdvKVK0dwgZ=!t=iM0QrpcN?0wc;^R_ReEfG!DFekwRAdvpGpnStWR=% zID3L#ZZH*}%7FZksRBjG#5hShbI)+II7aVC^)u^U2NAXUJglF0qXzu8c+)NnSX|4~ zgL%S7Ew5>EXCL|^1(}*8^|i=CgYo>BO!#0g&0ztu)DLxATH@O8;g08-FylbuR%`vr zLnO4;U%2Hfn0;T&^5_kCs86<#I@m`xLf0~*XT_D_IlYo!P!ayCtR&ZMcbK@|6wO3R zrPQr5uJ?hhjAuFgRXPjZMEs3|={*5Q5`}k4^p2VjP=Ko#%}mQILg}NP{}yPey>_He zI8OM$AQs1?kqDtsqRjkE-s-b~Y!bQU4H*?>cu>k6Dc7acEL$Qu9Y_cm<;?m%BP7>O zwR`b~&j=8jAUnMntaU{``b_xjoS9ql1%^7LCLD$?H5XwaP$zPp&Ig16=|J ze8UVE+CUD{w598$g}gkY~LGGNXZ^odTU#_dvtr#jppYO8*DY=vnq2iIw>ajXpN z@%D7N!-?iFK{l-YGxB!f?h!EiLD*c1V+b^kh3+4{*LL5e*G_u+`1MU~&3J_VcyO$# za&hWcO$|@#KUAb*iPNA}o3FL0P22}(%lDpUYXmm4v5bxOs|cmy7`NN5sWuhh_Cjn@YgT*Uhk#t)zibRPVkXk9W4Wux zWVLIzHJ|hLWWRcQDkgg-Ou3J~{?Xi{#2&+nB9xnm zOBBIfgLwO{$(jG5ecN99jIrJ-aoI(rG0)0qN{nmeQ8vWZWU-3T*M%#vty*t& ze)qT)G*`Mm*K(n;HL~^GI$n%R!wmg(2WPOBMdS9&mNX#0=!Uc$Fa@Wai!jy5UxuL; zWcpTJ#he?NZ5}#q`JtAr#tL!@Sizwr9pn15B51$Z7iws+H1A*zYv}^Ut0&#ef}aH) zAKP*%olkO)S$)CCIxQy=TRn14>-N0doG7FBeCjRsyY-22BT!wibC8}ux$!cFU9j9F-ZU#8Z!=D|s> zL_eDQm|oX$>D)JMa@aq7*~Gr*#=F6Pqq>=P^YkJeyz{ee*QD_@ng)_*mh$LO-tyO`Gwd2lN zwHO=4e-f3u`25l*lp_o0JPE$s)QYe1y#%GIJVdut2QK+-uf;vg)Xi!u1_@2y1&~o% zz#Dk3PS5*V+0u>IPc&KLu5d6-5uPT2NuB{0q!r0Kha4YCa1U!x_wqGnTQPrSAb^6% zOc`N_R;x!yOa6xWP^U& z`nTt}fC9<_VdeKXN`xsRIeI#yh#Xg4Z`a&6r`3WKSJKal-sl}J&>1)H>Hr}nwc<*F z^YUlCRjO-&`QR5|o0rM2ykZ5ca54slusa2K7y<=dRaFQ={GM3bS;I9~-x?ct;XU zh5?g3S?hSK7OPcla7P%()<)KZV?*DF{l~Sj_tr&5t3@W{5ZCUlwQZo~Wxv;L>M3VH zU9ydqb`WbVyJ^Gr6j(kJvM0~BWVK`oFB)fU$G_=!Ffsebt3@m0A)crrXD|~TPODs- zxVON)yWd{+^aYF3fjO4dbo6!Qw-?|uUzN7`HvR;}!Cj%VP=Ii7Bwr(1eYzp?(Y_m( zdj#($X7A5Er%I=J8JsvntJ&z1)-^6ro)IJfTdI&XPQ_!yK6gcMkV7z?Tl>u?KVq=-SWeKfUhI+r1Xe64P_hkffUn6Z4Sk&mN zgy2TfO7Cl{2qx}tf1INrN{)vPJpnHS@pdFVh4n| zM$;*u8qZTJ6Bd+|=B)mvoM@^EB{RAHsHgqqAUgx6)_hYJaK~SgP?ter35YkY^@bl( zWfGNy*kjiRvPRDRsgx<7`0PDyPkpA_QX99eQfvOYVNAo!&Aw-1(SjP~!3};2VnR|D zl`&1jP;zDbs!5vK>4!n;oySCX=R=TS&_-B65orzznNw$jvHzT;f+bC z#vqQ-h#=d}_}^w%lRa)qH*CZ-FjR}Te+ADq-P`wiJl&b|VUMNt`nz-Jr^{`yq8>VQ z#48Z*8Sx%uL4L%tEwL}jvuN37r_agMe@GWit4NB;aawHon&io}LyUQ68+k84xO=%d zjFX?+`m$lW*w>$tgDh1W_P2oGEOC3P>@guVDw+>`-UiL68dG$VkanwE`bR_~Y02Y% zag=Fd{IqHQ*yEYqPu*XxUW;b^{R3wmPDM@Gc7HSxvh8K{G~SSr*J&_CYtGqvgKR0^wR53F-iWa z-b(fFVp~^1A+_dZnp9jMf*e@h9@ISL6lJU|cXQu~pFfzL`1O=!Ck@OUG~f6(&pJKL zeRp2kGMy79AP2ljl<=He;_uhhsZ8@N!^U`^;OyroyEW-^*`6Rfhn|UxK`u~uU-~99 z%8d47p75%>cct_Z<9yN~zf^jVIi9QTNLBC7rzlKOQk74t{LXYe!7Fmr!56QL2Eu=H z3$Vr3@jT|gi z5oJb4PZ$3Fk+A${;EgaA27-Ix3ZFHO zEIIPU^`3Rz5JvAx4u^Mgphe}6<>I_%Z9Z_~zlTsq$l|bYst%+~u)UFA1QC7;MJpEZ z2qe>Esb?6!{GPsmeDkQWqY;|b7;Q}D5OD(O=A@vA9Y0WI6%yQ>|Lj>)7iM(pw0zd>bg| zA@smHS}*afnv27JPsBHW8|4PZ>6#M{Q)u}!TQvHrjD&`7qR#}NQ9+p}SqodLLT*%S z(TX!dO;f9mpY6l81Vct!+=()<&YN!}Z5PyD&=Z6!HiXj*l3}SYaRRRPV;UPvPay4m zCrEQbC^|cwkjHAO=7jF9Wk(2n4Up`;2H4~mBV`~vuW6(K0p(|mieqs#` zO{Oq{wJ!mXOb(EYR6bVkh|Uy3_#VPmn!HJQRG5Kg#Uzy^ix_hR4uKTytgxDJgm{as zgA4&ylsdpWm5i4n0E;ZvZRwj&nLFt>z|Sa@{Fu$^rb(w8spVgfzXB<-OwmY5!0eV( z_y&IUbu?&qsUav|5PKDKPPh-mHLy`f$O(Zccc)Pdw-!A2zmbF>SX~%uKO7IOyx3Qk z&!h#}7EPm^_uy$9PMINZNnr}%Xhl3yWHZX!Q5#*8`P=_C3aBkA<;V!X@dQ8TW|y*Z>V!=QEr|Z%;XK z69URv8NuD6`$u~LS;FZq*a%nT{*GGzATW-V*{0hCNTDPcvd}?*d&qs%pMk!*mJv;E zgs8*EuRnu7vZj%U3l|s2N9xQQIj9rW zl>?j^pm82=Q0X*-#qh`FNEblTF;z21Gbi&w!zEG{xo~uL)8jq60X??}xvrTS4IKEG z(KGdS*gz!{_#h!vvEKmq3OERBP>1A$deirPuaS@#aMoSJ+510uSBYGN=l7DJA4dR_ z@YmoN(OVK-LQzsEy~$~FATgrj``Kp#XfF_RHGIy54Bhlt0xvPJLF0tEP+{Q*#YRqI zT%<3-A9Xo_qp>Grj=SdNpmo5$9x$3#6QP&1Y0#r)Nl_P2aZGe0((PC%UDi z`xE!N)Ljx*$f-fLo6tS~j7Ca|zd!EX#^0adcVBq`eBFh@=+A;8P>PL(xM>kxuUqvr zF{|(I2>z0vPoGQhC2h_MFVbz~ArLdF5_@juDb|o0@N*Y5A&T|At;Bfcx6%zU*cCTS zHXQwZh-vBNx2EE}3wazk<%D)_gJ5$?fT`%72pfniM6!irhLrHNiYi3HZM>JdURP(>a?S`#QA0XOlL^T4t17fvI8#F>^o<{T@5=I>c zEUj`q`{n0iRpg(yxQ8)qYjnZTVyrX~S}T_&M8>l_?y{SJU;;n59;=SJS>f^DF0ips z@-4A=kOtKqxj}>I`i#BU4t+%(?O9=WPIft&fRvLNFOb=pyi+E*?eggb9%M1wTdV^} zrDmfZwQ+X~@&gH}#yfiS6^WLQhKpz6t~;Cay(PQ`E@~y{F&w04(`4nH!9%XY3JB=> z*}&t`pc5w+5=&oMp7O=La$>K}I@OmM3f#xxgeXO+0l3&er6b4+5)Z;?#*)hXEdwuj z(4Ve&%I-2C??xEwzB0P9{>{#O_5>y`gf*rP<>k1RPppUljPS|dNMMZToJaRPgpv#3 z4~H-WM}w&ETGHhVk(luPQpQSd>TrNl*5m>SEg>PJ6q9yml8jNK+ zf!zpzf4_=8)mqo)`d|aX_M}%<_zE_OEXxQKW1E6$RlDDY_;B>E;%H8~I~nTsJokN_ zg|O?$X`UatVP~NXbH*K!Cz3(Dye6-r1SGLCQKdWb+91TtB;%YJ2 z)pqA<_Gfmf5RaO#Tb>|E-hmm4f$;6gnTtDC3AS+^o#mTiTLid8@jFdTVXzIM+dtXf z2-3Zt#Ioi#=87r157V=Kf88wvB1J;@ft8E%0XC6J-eR!cS0Z8%00}_Jz@0K4{0Lt4 z)e*qehV&S;L_=}{FD6Y%8=V;+dqf;lwE#wo_Dkbz&a0D5|2Nn9UDb)l2Qpv25t=Fa zV_V2X0&bl_^zk}nS8_j)jMvAY|9#}`tmMNv*N$j#pbwdh>|uxav9Lzhr2n5wa_7pm zP3+KkJ>FX}28`iEg;uJD4xePL>i7|qU@H)mka6(LMITlS0)9&J>WETV(|7*^Ce%0q literal 0 HcmV?d00001 diff --git a/setup.py b/setup.py index e6953370..3e627eb2 100644 --- a/setup.py +++ b/setup.py @@ -70,7 +70,7 @@ classifiers = [ ] data_files = [ ("share/applications", ["install/org.onionshare.OnionShare.desktop"],), - ("share/icons/hicolor/scalable/apps", ["install/org.onionshare.OnionShare.svg"],), + ("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")),