Merge pull request #18 from firstlookmedia/4_windows

Port to Windows
This commit is contained in:
Micah Lee 2020-02-20 09:47:42 -08:00 committed by GitHub
commit 2193be6882
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 971 additions and 530 deletions

129
BUILD.md
View file

@ -31,30 +31,28 @@ Create a .deb:
## macOS
## 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`.
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 pipenv (`pip3 install --user pipenv`). Then install dependencies:
If you don't have it already, install poetry (`pip3 install --user poetry`). Then install dependencies:
```sh
pipenv install --dev --pre
poetry install
```
Run from source tree:
```
pipenv run ./dev_scripts/dangerzone
poetry run ./dev_scripts/dangerzone
```
To create an app bundle and DMG for distribution, use the `build_app.py` script
```sh
pipenv run ./install/macos/build_app.py
poetry run ./install/macos/build_app.py
```
If you want to build for distribution, you'll need a codesigning certificate, and you'll also need to have [create-dmg](https://github.com/sindresorhus/create-dmg) installed:
@ -67,7 +65,124 @@ brew install graphicsmagick imagemagick
And then run `build_app.py --with-codesign`:
```sh
pipenv run ./install/macos/build_app.py --with-codesign
poetry run ./install/macos/build_app.py --with-codesign
```
The output is in the `dist` folder.
## 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.7.6, 32-bit (x86) from https://www.python.org/downloads/release/python-376/. I downloaded python-3.7.6.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.1 from https://www.qt.io/offline-installers. I downloaded qt-opensource-windows-x86-5.14.1.exe. In the installer, unfortunately you have login to an account. Then all you need `Qt` > `Qt 5.14.1` > `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
```
And add `%USERPROFILE%\.poetry\bin` to your path. Then open a command prompt and cd to the `dangerzone` folder, and install the poetry dependencies:
```
poetry install
```
After that you can launch dangerzone during development with:
```
poetry run python dev_scripts\dangerzone
```
### If you want to build a .exe
Download and install the [Windows 10 SDK](https://developer.microsoft.com/en-US/windows/downloads/windows-10-sdk/).
Add the following directories 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`
### If you want the .exe to not get falsely flagged as malicious by anti-virus software
Dangerzone 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.
Here's how to compile the PyInstaller bootloader:
Download and install [Microsoft Build Tools for Visual Studio 2017](https://www.visualstudio.com/downloads/#build-tools-for-visual-studio-2019). I downloaded `vs_buildtools__1378184674.1581551596.exe`. In the installer, check the box next to "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.6` tag:
```
git clone https://github.com/pyinstaller/pyinstaller.git
cd pyinstaller
git tag -v v3.6
```
(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 dangerzone
poetry shell
cd ..\pyinstaller
```
Then, compile the bootloader:
```
cd bootloader
python waf distclean all --target-arch=32bit --msvc_targets=x86
cd ..
```
Finally, install the PyInstaller module into your poetry environment:
```
python setup.py install
exit
```
Now the next time you use PyInstaller to build dangerzone, 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.05-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 dangerzone directory, and run:
```
poetry run pyinstaller install\pyinstaller\pyinstaller.spec
```
`dangerzone.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\windows\build_exe.bat` script, because it codesigns `dangerzone.exe`, `uninstall.exe`, and `dangerzone-setup.exe`.
Open a command prompt, cd to the dangerzone directory, and run:
```
poetry run 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\dangerzone-setup.exe`.

23
Pipfile
View file

@ -1,23 +0,0 @@
[[source]]
url = "https://pypi.python.org/simple"
verify_ssl = true
name = "pypi"
[packages]
PyQt5 = "*"
click = "*"
appdirs = "*"
pyxdg = {version = "*",platform_system = "== 'Linux'"}
pyobjc-core = {version = "*",platform_system = "== 'Darwin'"}
pyobjc-framework-launchservices = {version = "*",platform_system = "== 'Darwin'"}
requests = "*"
[dev-packages]
black = "*"
pyinstaller = "*"
[requires]
python_version = "3.7"
[pipenv]
allow_prereleases = true

281
Pipfile.lock generated
View file

@ -1,281 +0,0 @@
{
"_meta": {
"hash": {
"sha256": "695116394343f7849640651aff1c6957762111bbe2905e3e4d4473be4d6dfb43"
},
"pipfile-spec": 6,
"requires": {
"python_version": "3.7"
},
"sources": [
{
"name": "pypi",
"url": "https://pypi.python.org/simple",
"verify_ssl": true
}
]
},
"default": {
"appdirs": {
"hashes": [
"sha256:9e5896d1372858f8dd3344faf4e5014d21849c756c8d5701f78f8a103b372d92",
"sha256:d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e"
],
"index": "pypi",
"version": "==1.4.3"
},
"certifi": {
"hashes": [
"sha256:017c25db2a153ce562900032d5bc68e9f191e44e9a0f762f373977de9df1fbb3",
"sha256:25b64c7da4cd7479594d035c08c2d809eb4aab3a26e5a990ea98cc450c320f1f"
],
"version": "==2019.11.28"
},
"chardet": {
"hashes": [
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
],
"version": "==3.0.4"
},
"click": {
"hashes": [
"sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13",
"sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7"
],
"index": "pypi",
"version": "==7.0"
},
"idna": {
"hashes": [
"sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407",
"sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c"
],
"version": "==2.8"
},
"pyobjc-core": {
"hashes": [
"sha256:1a0fbf012fb575e0adf8c18cfd4453e657cc2c0deb2660c529bf524ba4c9149a",
"sha256:470ccd754efb468a59426942673dfc3c5c59f33a5b8cae8a7fc1be975c2d4128",
"sha256:751cdeb436cb181af2e2413015b072075590577c410c7f345080a38dd028b8ec",
"sha256:8ccf44511cbe438fa6562c423c0c5f1dad7cfc0eadd6d8f112840f8845b44fda"
],
"index": "pypi",
"markers": "platform_system == 'Darwin'",
"version": "==6.1"
},
"pyobjc-framework-cocoa": {
"hashes": [
"sha256:1dc428f867d35007ddf9de5b24eff5bfdf65c58b1d610abcb08bebd94c343312",
"sha256:245e19156739f8068db474ad9561079cc698f08ef525e299b8eedc5531e02801",
"sha256:32ba4d0ce811e2088bf0fc360c9545c06586934e895f7133655b8f2182e7019a",
"sha256:c4077d2e6f96e4f3fd9780d66778cf51d27f414822498b24410e9df7a6a4d531"
],
"version": "==6.1"
},
"pyobjc-framework-coreservices": {
"hashes": [
"sha256:0e28004a6fcc3d8928d7c8ddac2059651847851e2bad7fe2d1ed7fd12615065c",
"sha256:416c47d12640ddcdb773eee6a99e09d26326dadb15056d0f7734eff913d4ce7b",
"sha256:665f979403ebae16b4d9945d24829c12c2aeccc0338cd04a268a324b6cc654a2",
"sha256:a2977e948027677fca574a6c3fc4654f6644700bf9d2afa87c64afa2acf4b66e"
],
"version": "==6.1"
},
"pyobjc-framework-fsevents": {
"hashes": [
"sha256:3a403ce5997cc01f23f1a70f8b4c919311b9a6b1fdd3c3d02d19079d711f954c",
"sha256:7a635c86af744a1d17f0c6c3913bef87b5fd146e0311c03229eba9e512b81520",
"sha256:94c6953774b6d69e59d9781951f05ef57e352b3c530d4c236f463444852c3a88",
"sha256:d2ae8748d1791dc9e3d19b41d3873283ac34ed17ff8fca70f1a199336a0477b5"
],
"version": "==6.1"
},
"pyobjc-framework-launchservices": {
"hashes": [
"sha256:1c1896f356e9c7ac6255863422565ed922589c10bba3dc2850729df666794346",
"sha256:944b8ce7fb4215019bb55bd48b46685032d8db3fc2ff8cd80dfe56356cd99fd2"
],
"index": "pypi",
"markers": "platform_system == 'Darwin'",
"version": "==6.1"
},
"pyqt5": {
"hashes": [
"sha256:2d94ec761fb656707050c68b41958e3a9f755bb1df96c064470f4096d2899e32",
"sha256:2f230f2dbd767099de7a0cb915abdf0cbc3256a0b5bb910eb09b99117db7a65b",
"sha256:31b142a868152d60c6323e0527edb692fdf05fd7cb4fe2fe9ce07d1ce560221a",
"sha256:713b9a201f5e7b2fca8691373e5d5c8c2552a51d87ca9ffbb1461e34e3241211",
"sha256:a0bfe9fd718bca4de3e33000347e048f73126b6dc46530eb020b0251a638ee9d"
],
"index": "pypi",
"version": "==5.14.1"
},
"pyqt5-sip": {
"hashes": [
"sha256:1115728644bbadcde5fc8a16e7918bd31915a42dd6fb36b10d4afb78c582753e",
"sha256:1f4289276d355b6521dc2cc956189315da6f13adfb6bbab8f25ebd15e3bce1d4",
"sha256:288c6dc18a8d6a20981c07b715b5695d9b66880778565f3792bc6e38f14f20fb",
"sha256:3f665376d9e52faa9855c3736a66ce6d825f85c86d7774d3c393f09da23f4f86",
"sha256:6b4860c4305980db509415d0af802f111d15f92016c9422eb753bc8883463456",
"sha256:7ffa39763097f64de129cf5cc770a651c3f65d2466b4fe05bef2bd2efbaa38e6",
"sha256:8a18e6f45d482ddfe381789979d09ee13aa6450caa3a0476503891bccb3ac709",
"sha256:8da842d3d7bf8931d1093105fb92702276b6dbb7e801abbaaa869405d616171a",
"sha256:b42021229424aa44e99b3b49520b799fd64ff6ae8b53f79f903bbd85719a28e4",
"sha256:b5b4906445fe980aee76f20400116b6904bf5f30d0767489c13370e42a764020",
"sha256:c1e730a9eb2ec3869ed5d81b0f99f6e2460fb4d77750444c0ec183b771d798f7",
"sha256:cbeeae6b45234a1654657f79943f8bccd3d14b4e7496746c62cf6fbce69442c7",
"sha256:d46b0f8effc554de52a1466b1bd80e5cb4bce635a75ac4e7ad6247c965dec5b9",
"sha256:e28c3abc9b62a1b7e796891648b9f14f8167b31c8e7990fae79654777252bb4d",
"sha256:e6078f5ee7d31c102910d0c277a110e1c2a20a3fc88cd017a39e170120586d3f",
"sha256:ee1a12f09d5af2304273bfd2f6b43835c1467d5ed501a6c95f5405637fa7750a",
"sha256:f314f31f5fd39b06897f013f425137e511d45967150eb4e424a363d8138521c6"
],
"version": "==12.7.1"
},
"pyxdg": {
"hashes": [
"sha256:1948ff8e2db02156c0cccd2529b43c0cff56ebaa71f5f021bbd755bc1419190e",
"sha256:fe2928d3f532ed32b39c32a482b54136fe766d19936afc96c8f00645f9da1a06"
],
"index": "pypi",
"markers": "platform_system == 'Linux'",
"version": "==0.26"
},
"requests": {
"hashes": [
"sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4",
"sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31"
],
"index": "pypi",
"version": "==2.22.0"
},
"urllib3": {
"hashes": [
"sha256:2f3db8b19923a873b3e5256dc9c2dedfa883e33d87c690d9c7913e1f40673cdc",
"sha256:87716c2d2a7121198ebcb7ce7cccf6ce5e9ba539041cfbaeecfb641dc0bf6acc"
],
"version": "==1.25.8"
}
},
"develop": {
"altgraph": {
"hashes": [
"sha256:1f05a47122542f97028caf78775a095fbe6a2699b5089de8477eb583167d69aa",
"sha256:c623e5f3408ca61d4016f23a681b9adb100802ca3e3da5e718915a9e4052cebe"
],
"version": "==0.17"
},
"appdirs": {
"hashes": [
"sha256:9e5896d1372858f8dd3344faf4e5014d21849c756c8d5701f78f8a103b372d92",
"sha256:d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e"
],
"index": "pypi",
"version": "==1.4.3"
},
"attrs": {
"hashes": [
"sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c",
"sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"
],
"version": "==19.3.0"
},
"black": {
"hashes": [
"sha256:1b30e59be925fafc1ee4565e5e08abef6b03fe455102883820fe5ee2e4734e0b",
"sha256:c2edb73a08e9e0e6f65a0e6af18b059b8b1cdd5bef997d7a0b181df93dc81539"
],
"index": "pypi",
"version": "==19.10b0"
},
"click": {
"hashes": [
"sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13",
"sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7"
],
"index": "pypi",
"version": "==7.0"
},
"macholib": {
"hashes": [
"sha256:0c436bc847e7b1d9bda0560351bf76d7caf930fb585a828d13608839ef42c432",
"sha256:c500f02867515e6c60a27875b408920d18332ddf96b4035ef03beddd782d4281"
],
"version": "==1.14"
},
"pathspec": {
"hashes": [
"sha256:163b0632d4e31cef212976cf57b43d9fd6b0bac6e67c26015d611a647d5e7424",
"sha256:562aa70af2e0d434367d9790ad37aed893de47f1693e4201fd1d3dca15d19b96"
],
"version": "==0.7.0"
},
"pyinstaller": {
"hashes": [
"sha256:3730fa80d088f8bb7084d32480eb87cbb4ddb64123363763cf8f2a1378c1c4b7"
],
"index": "pypi",
"version": "==3.6"
},
"regex": {
"hashes": [
"sha256:07b39bf943d3d2fe63d46281d8504f8df0ff3fe4c57e13d1656737950e53e525",
"sha256:0932941cdfb3afcbc26cc3bcf7c3f3d73d5a9b9c56955d432dbf8bbc147d4c5b",
"sha256:0e182d2f097ea8549a249040922fa2b92ae28be4be4895933e369a525ba36576",
"sha256:10671601ee06cf4dc1bc0b4805309040bb34c9af423c12c379c83d7895622bb5",
"sha256:23e2c2c0ff50f44877f64780b815b8fd2e003cda9ce817a7fd00dea5600c84a0",
"sha256:26ff99c980f53b3191d8931b199b29d6787c059f2e029b2b0c694343b1708c35",
"sha256:27429b8d74ba683484a06b260b7bb00f312e7c757792628ea251afdbf1434003",
"sha256:3e77409b678b21a056415da3a56abfd7c3ad03da71f3051bbcdb68cf44d3c34d",
"sha256:4e8f02d3d72ca94efc8396f8036c0d3bcc812aefc28ec70f35bb888c74a25161",
"sha256:4eae742636aec40cf7ab98171ab9400393360b97e8f9da67b1867a9ee0889b26",
"sha256:6a6ae17bf8f2d82d1e8858a47757ce389b880083c4ff2498dba17c56e6c103b9",
"sha256:6a6ba91b94427cd49cd27764679024b14a96874e0dc638ae6bdd4b1a3ce97be1",
"sha256:7bcd322935377abcc79bfe5b63c44abd0b29387f267791d566bbb566edfdd146",
"sha256:98b8ed7bb2155e2cbb8b76f627b2fd12cf4b22ab6e14873e8641f266e0fb6d8f",
"sha256:bd25bb7980917e4e70ccccd7e3b5740614f1c408a642c245019cff9d7d1b6149",
"sha256:d0f424328f9822b0323b3b6f2e4b9c90960b24743d220763c7f07071e0778351",
"sha256:d58e4606da2a41659c84baeb3cfa2e4c87a74cec89a1e7c56bee4b956f9d7461",
"sha256:e3cd21cc2840ca67de0bbe4071f79f031c81418deb544ceda93ad75ca1ee9f7b",
"sha256:e6c02171d62ed6972ca8631f6f34fa3281d51db8b326ee397b9c83093a6b7242",
"sha256:e7c7661f7276507bce416eaae22040fd91ca471b5b33c13f8ff21137ed6f248c",
"sha256:ecc6de77df3ef68fee966bb8cb4e067e84d4d1f397d0ef6fce46913663540d77"
],
"version": "==2020.1.8"
},
"toml": {
"hashes": [
"sha256:229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c",
"sha256:235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e"
],
"version": "==0.10.0"
},
"typed-ast": {
"hashes": [
"sha256:0666aa36131496aed8f7be0410ff974562ab7eeac11ef351def9ea6fa28f6355",
"sha256:0c2c07682d61a629b68433afb159376e24e5b2fd4641d35424e462169c0a7919",
"sha256:249862707802d40f7f29f6e1aad8d84b5aa9e44552d2cc17384b209f091276aa",
"sha256:24995c843eb0ad11a4527b026b4dde3da70e1f2d8806c99b7b4a7cf491612652",
"sha256:269151951236b0f9a6f04015a9004084a5ab0d5f19b57de779f908621e7d8b75",
"sha256:4083861b0aa07990b619bd7ddc365eb7fa4b817e99cf5f8d9cf21a42780f6e01",
"sha256:498b0f36cc7054c1fead3d7fc59d2150f4d5c6c56ba7fb150c013fbc683a8d2d",
"sha256:4e3e5da80ccbebfff202a67bf900d081906c358ccc3d5e3c8aea42fdfdfd51c1",
"sha256:6daac9731f172c2a22ade6ed0c00197ee7cc1221aa84cfdf9c31defeb059a907",
"sha256:715ff2f2df46121071622063fc7543d9b1fd19ebfc4f5c8895af64a77a8c852c",
"sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3",
"sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b",
"sha256:8ce678dbaf790dbdb3eba24056d5364fb45944f33553dd5869b7580cdbb83614",
"sha256:aaee9905aee35ba5905cfb3c62f3e83b3bec7b39413f0a7f19be4e547ea01ebb",
"sha256:bcd3b13b56ea479b3650b82cabd6b5343a625b0ced5429e4ccad28a8973f301b",
"sha256:c9e348e02e4d2b4a8b2eedb48210430658df6951fa484e59de33ff773fbd4b41",
"sha256:d205b1b46085271b4e15f670058ce182bd1199e56b317bf2ec004b6a44f911f6",
"sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34",
"sha256:d5d33e9e7af3b34a40dc05f498939f0ebf187f07c385fd58d591c533ad8562fe",
"sha256:fc0fea399acb12edbf8a628ba8d2312f583bdbdb3335635db062fa98cf71fca4",
"sha256:fe460b922ec15dd205595c9b5b99e2f056fd98ae8f9f56b888e7a17dc2b757e7"
],
"version": "==1.4.1"
}
}
}

View file

@ -8,7 +8,12 @@ import time
from .common import Common
from .main_window import MainWindow
from .docker_installer import is_docker_installed, is_docker_ready, DockerInstaller
from .docker_installer import (
is_docker_installed,
is_docker_ready,
launch_docker_windows,
DockerInstaller,
)
dangerzone_version = "0.1.0"
@ -49,6 +54,30 @@ def main(filename):
return
if platform.system() == "Windows":
if not is_docker_installed(common):
print("Docker is not installed")
docker_installer = DockerInstaller(common)
docker_installer.start()
# Quit after the installer runs, because it requires rebooting
return
if not is_docker_ready(common):
print("Docker is not running")
launch_docker_windows(common)
# Wait up to 20 minutes for docker to be ready
for i in range(120):
if is_docker_ready(common):
main(filename)
return
print("Waiting for docker to be available ...")
time.sleep(1)
# Give up
print("Docker not available, giving up")
# Main window
main_window = MainWindow(common)

View file

@ -30,7 +30,13 @@ class Common(object):
# Temporary directory to store pixel data
# Note in macOS, temp dirs must be in /tmp (or a few other paths) for Docker to mount them
self.pixel_dir = tempfile.TemporaryDirectory(prefix="/tmp/dangerzone-pixel-")
if platform.system() == "Windows":
self.pixel_dir = tempfile.TemporaryDirectory(prefix="dangerzone-pixel-")
self.safe_dir = tempfile.TemporaryDirectory(prefix="dangerzone-safe-")
else:
self.pixel_dir = tempfile.TemporaryDirectory(
prefix="/tmp/dangerzone-pixel-"
)
self.safe_dir = tempfile.TemporaryDirectory(prefix="/tmp/dangerzone-safe-")
print(
f"Temporary directories created, dangerous={self.pixel_dir.name}, safe={self.safe_dir.name}"
@ -51,6 +57,10 @@ class Common(object):
# Container runtime
if platform.system() == "Darwin":
self.container_runtime = "/usr/local/bin/docker"
elif platform.system() == "Windows":
self.container_runtime = (
"C:\\Program Files\\Docker\\Docker\\resources\\bin\\docker.exe"
)
else:
self.container_runtime = "podman"
@ -331,3 +341,11 @@ class Common(object):
pass
return pdf_viewers
def get_subprocess_startupinfo(self):
if platform.system() == "Windows":
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
return startupinfo
else:
return None

View file

@ -5,10 +5,12 @@ import tempfile
import subprocess
import shutil
import time
import platform
from PyQt5 import QtCore, QtGui, QtWidgets
def is_docker_installed(common):
if platform.system() == "Darwin":
# Does the docker binary exist?
if os.path.isdir("/Applications/Docker.app") and os.path.exists(
common.container_runtime
@ -16,18 +18,33 @@ def is_docker_installed(common):
# Is it executable?
st = os.stat(common.container_runtime)
return bool(st.st_mode & stat.S_IXOTH)
if platform.system() == "Windows":
return os.path.exists(common.container_runtime)
return False
def is_docker_ready(common):
# Run `docker ps` without an error
try:
subprocess.run([common.container_runtime, "ps"], check=True)
subprocess.run(
[common.container_runtime, "ps"],
check=True,
startupinfo=common.get_subprocess_startupinfo(),
)
return True
except subprocess.CalledProcessError:
return False
def launch_docker_windows(common):
docker_desktop_path = "C:\\Program Files\\Docker\\Docker\\Docker Desktop.exe"
subprocess.Popen(
[docker_desktop_path], startupinfo=common.get_subprocess_startupinfo()
)
class DockerInstaller(QtWidgets.QDialog):
def __init__(self, common):
super(DockerInstaller, self).__init__()
@ -36,7 +53,11 @@ class DockerInstaller(QtWidgets.QDialog):
self.setWindowTitle("dangerzone")
self.setWindowIcon(QtGui.QIcon(self.common.get_resource_path("logo.png")))
label = QtWidgets.QLabel("Dangerzone for macOS requires Docker")
label = QtWidgets.QLabel()
if platform.system() == "Darwin":
label.setText("Dangerzone for macOS requires Docker")
elif platform.system() == "Windows":
label.setText("Dangerzone for Windows requires Docker")
label.setStyleSheet("QLabel { font-weight: bold; }")
label.setAlignment(QtCore.Qt.AlignCenter)
@ -50,16 +71,20 @@ class DockerInstaller(QtWidgets.QDialog):
self.install_button.setStyleSheet("QPushButton { font-weight: bold; }")
self.install_button.clicked.connect(self.install_clicked)
self.install_button.hide()
if platform.system() == "Darwin":
self.launch_button = QtWidgets.QPushButton("Launch Docker")
self.launch_button.setStyleSheet("QPushButton { font-weight: bold; }")
self.launch_button.clicked.connect(self.launch_clicked)
self.launch_button.hide()
self.cancel_button = QtWidgets.QPushButton("Cancel")
self.cancel_button.clicked.connect(self.cancel_clicked)
buttons_layout = QtWidgets.QHBoxLayout()
buttons_layout.addStretch()
buttons_layout.addWidget(self.install_button)
if platform.system() == "Darwin":
buttons_layout.addWidget(self.launch_button)
buttons_layout.addWidget(self.cancel_button)
buttons_layout.addStretch()
@ -72,8 +97,14 @@ class DockerInstaller(QtWidgets.QDialog):
layout.addStretch()
self.setLayout(layout)
if platform.system == "Darwin":
self.tmp_dir = tempfile.TemporaryDirectory(prefix="/tmp/dangerzone-docker-")
self.dmg_filename = os.path.join(self.tmp_dir.name, "Docker.dmg")
self.installer_filename = os.path.join(self.tmp_dir.name, "Docker.dmg")
else:
self.tmp_dir = tempfile.TemporaryDirectory(prefix="dangerzone-docker-")
self.installer_filename = os.path.join(
self.tmp_dir.name, "Docker for Windows Installer.exe"
)
# Threads
self.download_t = None
@ -105,19 +136,22 @@ class DockerInstaller(QtWidgets.QDialog):
self.timer.start(10)
def start_download(self):
self.download_t = Downloader(self.dmg_filename)
self.download_t = Downloader(self.installer_filename)
self.download_t.download_finished.connect(self.download_finished)
self.download_t.download_failed.connect(self.download_failed)
self.download_t.update_progress.connect(self.update_progress)
self.download_t.start()
def install_finished(self):
if platform.system() == "Darwin":
self.task_label.setText("Finished installing Docker")
self.launch_button.show()
self.cancel_button.setEnabled(True)
elif platform.system == "Windows":
self.task_label.setText("Reboot to finish installing Docker")
self.install_t = None
self.progress.hide()
self.install_button.hide()
self.launch_button.show()
self.cancel_button.setEnabled(True)
def install_failed(self, exception):
print(f"Install failed: {exception}")
@ -141,13 +175,14 @@ class DockerInstaller(QtWidgets.QDialog):
self.timer.start(10)
def start_installer(self):
self.install_t = Installer(self.dmg_filename)
self.install_t = Installer(self.common, self.installer_filename)
self.install_t.install_finished.connect(self.install_finished)
self.install_t.install_failed.connect(self.install_failed)
self.install_t.update_task_label.connect(self.update_task_label)
self.install_t.start()
def launch_clicked(self):
if system.platform() == "Darwin":
print("Launching Docker")
self.accept()
subprocess.Popen(["open", "-a", "Docker.app"])
@ -175,22 +210,25 @@ class Downloader(QtCore.QThread):
download_failed = QtCore.pyqtSignal(int)
update_progress = QtCore.pyqtSignal(int, int)
def __init__(self, dmg_filename):
def __init__(self, installer_filename):
super(Downloader, self).__init__()
self.dmg_filename = dmg_filename
self.installer_filename = installer_filename
if platform.system() == "Darwin":
self.installer_url = "https://download.docker.com/mac/stable/Docker.dmg"
elif platform.system() == "Windows":
self.installer_url = "https://download.docker.com/win/stable/Docker%20for%20Windows%20Installer.exe"
def run(self):
print(f"Downloading docker to {self.dmg_filename}")
with requests.get(
"https://download.docker.com/mac/stable/Docker.dmg", stream=True
) as r:
print(f"Downloading docker to {self.installer_filename}")
with requests.get(self.installer_url, stream=True) as r:
if r.status_code != 200:
self.download_failed.emit(r.status_code)
return
total_bytes = int(r.headers.get("content-length"))
downloaded_bytes = 0
with open(self.dmg_filename, "wb") as f:
with open(self.installer_filename, "wb") as f:
for chunk in r.iter_content(chunk_size=8192):
if chunk: # filter out keep-alive new chunks
downloaded_bytes += f.write(chunk)
@ -205,20 +243,27 @@ class Installer(QtCore.QThread):
install_failed = QtCore.pyqtSignal(str)
update_task_label = QtCore.pyqtSignal(str)
def __init__(self, dmg_filename):
def __init__(self, common, installer_filename):
super(Installer, self).__init__()
self.dmg_filename = dmg_filename
self.common = common
self.installer_filename = installer_filename
def run(self):
print(f"Installing Docker")
if platform.system() == "Darwin":
try:
# Mount the dmg
self.update_task_label.emit(f"Mounting Docker.dmg")
subprocess.run(["hdiutil", "attach", "-nobrowse", self.dmg_filename])
subprocess.run(
["hdiutil", "attach", "-nobrowse", self.installer_filename]
)
# Copy Docker.app to Applications
self.update_task_label.emit("Copying Docker into Applications")
shutil.copytree("/Volumes/Docker/Docker.app", "/Applications/Docker.app")
shutil.copytree(
"/Volumes/Docker/Docker.app", "/Applications/Docker.app"
)
# Sync
self.update_task_label.emit("Syncing filesystem")
@ -236,3 +281,17 @@ class Installer(QtCore.QThread):
except Exception as e:
self.install_failed.emit(str(e))
return
elif platform.system() == "Windows":
try:
# Run the installer
subprocess.run(
[self.installer_filename],
startupinfo=self.common.get_subprocess_startupinfo(),
)
self.install_finished.emit()
except Exception as e:
self.install_failed.emit(str(e))
return

View file

@ -31,6 +31,7 @@ class TaskBase(QtCore.QThread):
stderr=subprocess.PIPE,
bufsize=1,
universal_newlines=True,
startupinfo=self.common.get_subprocess_startupinfo(),
) as p:
if watch == "stdout":
pipe = p.stdout
@ -60,7 +61,12 @@ class PullImageTask(TaskBase):
self.update_label.emit("Pulling container image")
self.update_details.emit("")
args = ["pull", "ubuntu:20.04"]
self.exec_container(args, watch="stderr")
returncode, _ = self.exec_container(args, watch="stderr")
if returncode != 0:
self.task_failed.emit(f"Return code: {returncode}")
return
self.task_finished.emit()
@ -71,10 +77,15 @@ class BuildContainerTask(TaskBase):
def run(self):
container_path = self.common.get_resource_path("container")
self.update_label.emit("Building container")
self.update_label.emit("Building container (this might take a long time)")
self.update_details.emit("")
args = ["build", "-t", "dangerzone", container_path]
self.exec_container(args)
returncode, _ = self.exec_container(args)
if returncode != 0:
self.task_failed.emit(f"Return code: {returncode}")
return
self.task_finished.emit()

View file

@ -40,7 +40,7 @@ def main():
shutil.rmtree(dist_path)
print("○ Building app bundle")
run(["pyinstaller", "install/macos/pyinstaller.spec", "--clean"])
run(["pyinstaller", "install/pyinstaller/pyinstaller.spec", "--clean"])
shutil.rmtree(os.path.join(dist_path, "dangerzone"))
print(f"○ Finished build app: {app_path}")

View file

@ -1,159 +0,0 @@
# -*- mode: python -*-
import sys
import os
import inspect
# Get the version
root = os.path.dirname(
os.path.dirname(
os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
)
)
sys.path.insert(0, root)
import dangerzone
version = dangerzone.dangerzone_version
print("Flock Agent version: {}".format(version))
a = Analysis(
["dangerzone"],
pathex=["."],
binaries=None,
datas=[("../../share", "share"), ("document.icns", ".")],
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=[],
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="dangerzone",
debug=False,
strip=False,
upx=True,
console=False,
)
coll = COLLECT(
exe, a.binaries, a.zipfiles, a.datas, strip=False, upx=True, name="dangerzone"
)
app = BUNDLE(
coll,
name="Dangerzone.app",
icon="dangerzone.icns",
bundle_identifier="media.firstlook.dangerzone",
info_plist={
"NSHighResolutionCapable": True,
"CFBundleShortVersionString": version,
"CFBundleDocumentTypes": [
{
"CFBundleTypeExtensions": ["pdf"],
"CFBundleTypeIconFile": "document.icns",
"CFBundleTypeMIMETypes": ["application/pdf"],
"CFBundleTypeName": "PDF Document",
"CFBundleTypeRole": "Viewer",
},
{
"CFBundleTypeExtensions": ["docx", "doc"],
"CFBundleTypeIconFile": "document.icns",
"CFBundleTypeMIMETypes": [
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"application/msword",
],
"CFBundleTypeName": "Microsoft Word Document",
"CFBundleTypeRole": "Viewer",
},
{
"CFBundleTypeExtensions": ["xlsx", "xls"],
"CFBundleTypeIconFile": "document.icns",
"CFBundleTypeMIMETypes": [
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"application/vnd.ms-excel",
],
"CFBundleTypeName": "Microsoft Excel Document",
"CFBundleTypeRole": "Viewer",
},
{
"CFBundleTypeExtensions": ["pptx", "ppt"],
"CFBundleTypeIconFile": "document.icns",
"CFBundleTypeMIMETypes": [
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
"application/vnd.ms-powerpoint",
],
"CFBundleTypeName": "Microsoft PowerPoint Document",
"CFBundleTypeRole": "Viewer",
},
{
"CFBundleTypeExtensions": ["odg"],
"CFBundleTypeIconFile": "document.icns",
"CFBundleTypeMIMETypes": ["application/vnd.oasis.opendocument.text"],
"CFBundleTypeName": "ODF Text Document",
"CFBundleTypeRole": "Viewer",
},
{
"CFBundleTypeExtensions": ["ops"],
"CFBundleTypeIconFile": "document.icns",
"CFBundleTypeMIMETypes": [
"application/vnd.oasis.opendocument.spreadsheet"
],
"CFBundleTypeName": "ODF Spreadsheet Document",
"CFBundleTypeRole": "Viewer",
},
{
"CFBundleTypeExtensions": ["odp"],
"CFBundleTypeIconFile": "document.icns",
"CFBundleTypeMIMETypes": [
"application/vnd.oasis.opendocument.presentation"
],
"CFBundleTypeName": "ODF Presentation Document",
"CFBundleTypeRole": "Viewer",
},
{
"CFBundleTypeExtensions": ["odg"],
"CFBundleTypeIconFile": "document.icns",
"CFBundleTypeMIMETypes": [
"application/vnd.oasis.opendocument.graphics"
],
"CFBundleTypeName": "ODF Graphics Document",
"CFBundleTypeRole": "Viewer",
},
{
"CFBundleTypeExtensions": ["jpg", "jpeg"],
"CFBundleTypeIconFile": "document.icns",
"CFBundleTypeMIMETypes": ["image/jpeg"],
"CFBundleTypeName": "JPEG Image",
"CFBundleTypeRole": "Viewer",
},
{
"CFBundleTypeExtensions": ["gif"],
"CFBundleTypeIconFile": "document.icns",
"CFBundleTypeMIMETypes": ["image/gif"],
"CFBundleTypeName": "GIF Image",
"CFBundleTypeRole": "Viewer",
},
{
"CFBundleTypeExtensions": ["png"],
"CFBundleTypeIconFile": "document.icns",
"CFBundleTypeMIMETypes": ["image/png"],
"CFBundleTypeName": "PNG Image",
"CFBundleTypeRole": "Viewer",
},
{
"CFBundleTypeExtensions": ["tif", "tiff"],
"CFBundleTypeIconFile": "document.icns",
"CFBundleTypeMIMETypes": ["image/tiff", "image/x-tiff"],
"CFBundleTypeName": "TIFF Image",
"CFBundleTypeRole": "Viewer",
},
],
},
)

View file

@ -0,0 +1,171 @@
# -*- mode: python -*-
import sys
import os
import inspect
import platform
p = platform.system()
# Get the version
root = os.path.dirname(
os.path.dirname(
os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
)
)
sys.path.insert(0, root)
import dangerzone
version = dangerzone.dangerzone_version
print("Flock Agent version: {}".format(version))
if p == "Darwin":
datas = [("../../share", "share"), ("../macos/document.icns", ".")]
else:
datas = [("../../share", "share")]
a = Analysis(
["dangerzone"],
pathex=["."],
binaries=None,
datas=datas,
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=[],
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="dangerzone",
debug=False,
strip=False,
upx=True,
console=False,
)
coll = COLLECT(
exe, a.binaries, a.zipfiles, a.datas, strip=False, upx=True, name="dangerzone"
)
# The macOS app bundle
if p == "Darwin":
app = BUNDLE(
coll,
name="Dangerzone.app",
icon="dangerzone.icns",
bundle_identifier="media.firstlook.dangerzone",
info_plist={
"NSHighResolutionCapable": True,
"CFBundleShortVersionString": version,
"CFBundleDocumentTypes": [
{
"CFBundleTypeExtensions": ["pdf"],
"CFBundleTypeIconFile": "document.icns",
"CFBundleTypeMIMETypes": ["application/pdf"],
"CFBundleTypeName": "PDF Document",
"CFBundleTypeRole": "Viewer",
},
{
"CFBundleTypeExtensions": ["docx", "doc"],
"CFBundleTypeIconFile": "document.icns",
"CFBundleTypeMIMETypes": [
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"application/msword",
],
"CFBundleTypeName": "Microsoft Word Document",
"CFBundleTypeRole": "Viewer",
},
{
"CFBundleTypeExtensions": ["xlsx", "xls"],
"CFBundleTypeIconFile": "document.icns",
"CFBundleTypeMIMETypes": [
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"application/vnd.ms-excel",
],
"CFBundleTypeName": "Microsoft Excel Document",
"CFBundleTypeRole": "Viewer",
},
{
"CFBundleTypeExtensions": ["pptx", "ppt"],
"CFBundleTypeIconFile": "document.icns",
"CFBundleTypeMIMETypes": [
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
"application/vnd.ms-powerpoint",
],
"CFBundleTypeName": "Microsoft PowerPoint Document",
"CFBundleTypeRole": "Viewer",
},
{
"CFBundleTypeExtensions": ["odg"],
"CFBundleTypeIconFile": "document.icns",
"CFBundleTypeMIMETypes": [
"application/vnd.oasis.opendocument.text"
],
"CFBundleTypeName": "ODF Text Document",
"CFBundleTypeRole": "Viewer",
},
{
"CFBundleTypeExtensions": ["ops"],
"CFBundleTypeIconFile": "document.icns",
"CFBundleTypeMIMETypes": [
"application/vnd.oasis.opendocument.spreadsheet"
],
"CFBundleTypeName": "ODF Spreadsheet Document",
"CFBundleTypeRole": "Viewer",
},
{
"CFBundleTypeExtensions": ["odp"],
"CFBundleTypeIconFile": "document.icns",
"CFBundleTypeMIMETypes": [
"application/vnd.oasis.opendocument.presentation"
],
"CFBundleTypeName": "ODF Presentation Document",
"CFBundleTypeRole": "Viewer",
},
{
"CFBundleTypeExtensions": ["odg"],
"CFBundleTypeIconFile": "document.icns",
"CFBundleTypeMIMETypes": [
"application/vnd.oasis.opendocument.graphics"
],
"CFBundleTypeName": "ODF Graphics Document",
"CFBundleTypeRole": "Viewer",
},
{
"CFBundleTypeExtensions": ["jpg", "jpeg"],
"CFBundleTypeIconFile": "document.icns",
"CFBundleTypeMIMETypes": ["image/jpeg"],
"CFBundleTypeName": "JPEG Image",
"CFBundleTypeRole": "Viewer",
},
{
"CFBundleTypeExtensions": ["gif"],
"CFBundleTypeIconFile": "document.icns",
"CFBundleTypeMIMETypes": ["image/gif"],
"CFBundleTypeName": "GIF Image",
"CFBundleTypeRole": "Viewer",
},
{
"CFBundleTypeExtensions": ["png"],
"CFBundleTypeIconFile": "document.icns",
"CFBundleTypeMIMETypes": ["image/png"],
"CFBundleTypeName": "PNG Image",
"CFBundleTypeRole": "Viewer",
},
{
"CFBundleTypeExtensions": ["tif", "tiff"],
"CFBundleTypeIconFile": "document.icns",
"CFBundleTypeMIMETypes": ["image/tiff", "image/x-tiff"],
"CFBundleTypeName": "TIFF Image",
"CFBundleTypeRole": "Viewer",
},
],
},
)

473
poetry.lock generated Normal file
View file

@ -0,0 +1,473 @@
[[package]]
category = "main"
description = "Python graph (network) package"
name = "altgraph"
optional = false
python-versions = "*"
version = "0.17"
[[package]]
category = "main"
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.3"
[[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 = "2019.11.28"
[[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.*"
version = "7.0"
[[package]]
category = "dev"
description = "Python 2.7 backport of the \"dis\" module from Python 3.5+"
marker = "sys_platform == \"darwin\""
name = "dis3"
optional = false
python-versions = "*"
version = "0.1.3"
[[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.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 = "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.7.0"
[[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 = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
version = "3.6"
[package.dependencies]
altgraph = "*"
dis3 = "*"
setuptools = "*"
[[package]]
category = "main"
description = "Python<->ObjC Interoperability Module"
marker = "sys_platform == \"darwin\""
name = "pyobjc-core"
optional = false
python-versions = ">=3.6"
version = "6.1"
[[package]]
category = "main"
description = "Wrappers for the Cocoa frameworks on macOS"
marker = "sys_platform == \"darwin\""
name = "pyobjc-framework-cocoa"
optional = false
python-versions = ">=3.6"
version = "6.1"
[package.dependencies]
pyobjc-core = ">=6.1"
[[package]]
category = "main"
description = "Wrappers for the framework CoreServices on macOS"
marker = "sys_platform == \"darwin\""
name = "pyobjc-framework-coreservices"
optional = false
python-versions = ">=3.6"
version = "6.1"
[package.dependencies]
pyobjc-core = ">=6.1"
pyobjc-framework-FSEvents = ">=6.1"
[[package]]
category = "main"
description = "Wrappers for the framework FSEvents on macOS"
marker = "sys_platform == \"darwin\""
name = "pyobjc-framework-fsevents"
optional = false
python-versions = ">=3.6"
version = "6.1"
[package.dependencies]
pyobjc-core = ">=6.1"
pyobjc-framework-Cocoa = ">=6.1"
[[package]]
category = "main"
description = "Wrappers for the framework LaunchServices on macOS"
marker = "sys_platform == \"darwin\""
name = "pyobjc-framework-launchservices"
optional = false
python-versions = ">=3.6"
version = "6.1"
[package.dependencies]
pyobjc-core = ">=6.1"
pyobjc-framework-CoreServices = ">=6.1"
[[package]]
category = "main"
description = "Python bindings for the Qt cross platform application toolkit"
name = "pyqt5"
optional = false
python-versions = ">=3.5"
version = "5.14.1"
[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.7.1"
[[package]]
category = "main"
description = "Python for Window Extensions"
marker = "sys_platform == \"win32\""
name = "pywin32"
optional = false
python-versions = "*"
version = "227"
[[package]]
category = "main"
description = "PyXDG contains implementations of freedesktop.org standards in python."
marker = "sys_platform == \"linux\""
name = "pyxdg"
optional = false
python-versions = "*"
version = "0.26"
[[package]]
category = "dev"
description = "Alternative regular expression module, to replace re."
name = "regex"
optional = false
python-versions = "*"
version = "2020.1.8"
[[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.22.0"
[package.dependencies]
certifi = ">=2017.4.17"
chardet = ">=3.0.2,<3.1.0"
idna = ">=2.5,<2.9"
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)", "idna (>=2.0.0)"]
socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7)", "win-inet-pton"]
[[package]]
category = "dev"
description = "Python Library for Tom's Obvious, Minimal Language"
name = "toml"
optional = false
python-versions = "*"
version = "0.10.0"
[[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.8"
[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 || >1.5.7,<2.0)"]
[[package]]
category = "main"
description = "Windows Management Instrumentation"
marker = "sys_platform == \"windows\""
name = "wmi"
optional = false
python-versions = "*"
version = "1.4.9"
[metadata]
content-hash = "28c51f60ace8c8578c21279f8c46ba095d0ec1f1f86bb155c24cba67ac3291ee"
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.3-py2.py3-none-any.whl", hash = "sha256:d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e"},
{file = "appdirs-1.4.3.tar.gz", hash = "sha256:9e5896d1372858f8dd3344faf4e5014d21849c756c8d5701f78f8a103b372d92"},
]
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-2019.11.28-py2.py3-none-any.whl", hash = "sha256:017c25db2a153ce562900032d5bc68e9f191e44e9a0f762f373977de9df1fbb3"},
{file = "certifi-2019.11.28.tar.gz", hash = "sha256:25b64c7da4cd7479594d035c08c2d809eb4aab3a26e5a990ea98cc450c320f1f"},
]
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.0-py2.py3-none-any.whl", hash = "sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13"},
{file = "Click-7.0.tar.gz", hash = "sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7"},
]
dis3 = [
{file = "dis3-0.1.3-py2-none-any.whl", hash = "sha256:61f7720dd0d8749d23fda3d7227ce74d73da11c2fade993a67ab2f9852451b14"},
{file = "dis3-0.1.3-py3-none-any.whl", hash = "sha256:30b6412d33d738663e8ded781b138f4b01116437f0872aa56aa3adba6aeff218"},
{file = "dis3-0.1.3.tar.gz", hash = "sha256:9259b881fc1df02ed12ac25f82d4a85b44241854330b1a651e40e0c675cb2d1e"},
]
idna = [
{file = "idna-2.8-py2.py3-none-any.whl", hash = "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c"},
{file = "idna-2.8.tar.gz", hash = "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407"},
]
macholib = [
{file = "macholib-1.14-py2.py3-none-any.whl", hash = "sha256:c500f02867515e6c60a27875b408920d18332ddf96b4035ef03beddd782d4281"},
{file = "macholib-1.14.tar.gz", hash = "sha256:0c436bc847e7b1d9bda0560351bf76d7caf930fb585a828d13608839ef42c432"},
]
pathspec = [
{file = "pathspec-0.7.0-py2.py3-none-any.whl", hash = "sha256:163b0632d4e31cef212976cf57b43d9fd6b0bac6e67c26015d611a647d5e7424"},
{file = "pathspec-0.7.0.tar.gz", hash = "sha256:562aa70af2e0d434367d9790ad37aed893de47f1693e4201fd1d3dca15d19b96"},
]
pyinstaller = [
{file = "PyInstaller-3.6.tar.gz", hash = "sha256:3730fa80d088f8bb7084d32480eb87cbb4ddb64123363763cf8f2a1378c1c4b7"},
]
pyobjc-core = [
{file = "pyobjc-core-6.1.tar.gz", hash = "sha256:1a0fbf012fb575e0adf8c18cfd4453e657cc2c0deb2660c529bf524ba4c9149a"},
{file = "pyobjc_core-6.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:470ccd754efb468a59426942673dfc3c5c59f33a5b8cae8a7fc1be975c2d4128"},
{file = "pyobjc_core-6.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:751cdeb436cb181af2e2413015b072075590577c410c7f345080a38dd028b8ec"},
{file = "pyobjc_core-6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8ccf44511cbe438fa6562c423c0c5f1dad7cfc0eadd6d8f112840f8845b44fda"},
]
pyobjc-framework-cocoa = [
{file = "pyobjc-framework-Cocoa-6.1.tar.gz", hash = "sha256:c4077d2e6f96e4f3fd9780d66778cf51d27f414822498b24410e9df7a6a4d531"},
{file = "pyobjc_framework_Cocoa-6.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:32ba4d0ce811e2088bf0fc360c9545c06586934e895f7133655b8f2182e7019a"},
{file = "pyobjc_framework_Cocoa-6.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:245e19156739f8068db474ad9561079cc698f08ef525e299b8eedc5531e02801"},
{file = "pyobjc_framework_Cocoa-6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1dc428f867d35007ddf9de5b24eff5bfdf65c58b1d610abcb08bebd94c343312"},
]
pyobjc-framework-coreservices = [
{file = "pyobjc-framework-CoreServices-6.1.tar.gz", hash = "sha256:665f979403ebae16b4d9945d24829c12c2aeccc0338cd04a268a324b6cc654a2"},
{file = "pyobjc_framework_CoreServices-6.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:0e28004a6fcc3d8928d7c8ddac2059651847851e2bad7fe2d1ed7fd12615065c"},
{file = "pyobjc_framework_CoreServices-6.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a2977e948027677fca574a6c3fc4654f6644700bf9d2afa87c64afa2acf4b66e"},
{file = "pyobjc_framework_CoreServices-6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:416c47d12640ddcdb773eee6a99e09d26326dadb15056d0f7734eff913d4ce7b"},
]
pyobjc-framework-fsevents = [
{file = "pyobjc-framework-FSEvents-6.1.tar.gz", hash = "sha256:7a635c86af744a1d17f0c6c3913bef87b5fd146e0311c03229eba9e512b81520"},
{file = "pyobjc_framework_FSEvents-6.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:94c6953774b6d69e59d9781951f05ef57e352b3c530d4c236f463444852c3a88"},
{file = "pyobjc_framework_FSEvents-6.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3a403ce5997cc01f23f1a70f8b4c919311b9a6b1fdd3c3d02d19079d711f954c"},
{file = "pyobjc_framework_FSEvents-6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d2ae8748d1791dc9e3d19b41d3873283ac34ed17ff8fca70f1a199336a0477b5"},
]
pyobjc-framework-launchservices = [
{file = "pyobjc-framework-LaunchServices-6.1.tar.gz", hash = "sha256:1c1896f356e9c7ac6255863422565ed922589c10bba3dc2850729df666794346"},
{file = "pyobjc_framework_LaunchServices-6.1-py2.py3-none-any.whl", hash = "sha256:944b8ce7fb4215019bb55bd48b46685032d8db3fc2ff8cd80dfe56356cd99fd2"},
]
pyqt5 = [
{file = "PyQt5-5.14.1-5.14.1-cp35.cp36.cp37.cp38-abi3-macosx_10_6_intel.whl", hash = "sha256:a0bfe9fd718bca4de3e33000347e048f73126b6dc46530eb020b0251a638ee9d"},
{file = "PyQt5-5.14.1-5.14.1-cp35.cp36.cp37.cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:713b9a201f5e7b2fca8691373e5d5c8c2552a51d87ca9ffbb1461e34e3241211"},
{file = "PyQt5-5.14.1-5.14.1-cp35.cp36.cp37.cp38-none-win32.whl", hash = "sha256:2d94ec761fb656707050c68b41958e3a9f755bb1df96c064470f4096d2899e32"},
{file = "PyQt5-5.14.1-5.14.1-cp35.cp36.cp37.cp38-none-win_amd64.whl", hash = "sha256:31b142a868152d60c6323e0527edb692fdf05fd7cb4fe2fe9ce07d1ce560221a"},
{file = "PyQt5-5.14.1.tar.gz", hash = "sha256:2f230f2dbd767099de7a0cb915abdf0cbc3256a0b5bb910eb09b99117db7a65b"},
]
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"},
]
pywin32 = [
{file = "pywin32-227-cp27-cp27m-win32.whl", hash = "sha256:371fcc39416d736401f0274dd64c2302728c9e034808e37381b5e1b22be4a6b0"},
{file = "pywin32-227-cp27-cp27m-win_amd64.whl", hash = "sha256:4cdad3e84191194ea6d0dd1b1b9bdda574ff563177d2adf2b4efec2a244fa116"},
{file = "pywin32-227-cp35-cp35m-win32.whl", hash = "sha256:f4c5be1a293bae0076d93c88f37ee8da68136744588bc5e2be2f299a34ceb7aa"},
{file = "pywin32-227-cp35-cp35m-win_amd64.whl", hash = "sha256:a929a4af626e530383a579431b70e512e736e9588106715215bf685a3ea508d4"},
{file = "pywin32-227-cp36-cp36m-win32.whl", hash = "sha256:300a2db938e98c3e7e2093e4491439e62287d0d493fe07cce110db070b54c0be"},
{file = "pywin32-227-cp36-cp36m-win_amd64.whl", hash = "sha256:9b31e009564fb95db160f154e2aa195ed66bcc4c058ed72850d047141b36f3a2"},
{file = "pywin32-227-cp37-cp37m-win32.whl", hash = "sha256:47a3c7551376a865dd8d095a98deba954a98f326c6fe3c72d8726ca6e6b15507"},
{file = "pywin32-227-cp37-cp37m-win_amd64.whl", hash = "sha256:31f88a89139cb2adc40f8f0e65ee56a8c585f629974f9e07622ba80199057511"},
{file = "pywin32-227-cp38-cp38-win32.whl", hash = "sha256:7f18199fbf29ca99dff10e1f09451582ae9e372a892ff03a28528a24d55875bc"},
{file = "pywin32-227-cp38-cp38-win_amd64.whl", hash = "sha256:7c1ae32c489dc012930787f06244426f8356e129184a02c25aef163917ce158e"},
{file = "pywin32-227-cp39-cp39-win32.whl", hash = "sha256:c054c52ba46e7eb6b7d7dfae4dbd987a1bb48ee86debe3f245a2884ece46e295"},
{file = "pywin32-227-cp39-cp39-win_amd64.whl", hash = "sha256:f27cec5e7f588c3d1051651830ecc00294f90728d19c3bf6916e6dba93ea357c"},
]
pyxdg = [
{file = "pyxdg-0.26-py2.py3-none-any.whl", hash = "sha256:1948ff8e2db02156c0cccd2529b43c0cff56ebaa71f5f021bbd755bc1419190e"},
{file = "pyxdg-0.26.tar.gz", hash = "sha256:fe2928d3f532ed32b39c32a482b54136fe766d19936afc96c8f00645f9da1a06"},
]
regex = [
{file = "regex-2020.1.8-cp27-cp27m-win32.whl", hash = "sha256:4e8f02d3d72ca94efc8396f8036c0d3bcc812aefc28ec70f35bb888c74a25161"},
{file = "regex-2020.1.8-cp27-cp27m-win_amd64.whl", hash = "sha256:e6c02171d62ed6972ca8631f6f34fa3281d51db8b326ee397b9c83093a6b7242"},
{file = "regex-2020.1.8-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:4eae742636aec40cf7ab98171ab9400393360b97e8f9da67b1867a9ee0889b26"},
{file = "regex-2020.1.8-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:bd25bb7980917e4e70ccccd7e3b5740614f1c408a642c245019cff9d7d1b6149"},
{file = "regex-2020.1.8-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:3e77409b678b21a056415da3a56abfd7c3ad03da71f3051bbcdb68cf44d3c34d"},
{file = "regex-2020.1.8-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:07b39bf943d3d2fe63d46281d8504f8df0ff3fe4c57e13d1656737950e53e525"},
{file = "regex-2020.1.8-cp36-cp36m-win32.whl", hash = "sha256:23e2c2c0ff50f44877f64780b815b8fd2e003cda9ce817a7fd00dea5600c84a0"},
{file = "regex-2020.1.8-cp36-cp36m-win_amd64.whl", hash = "sha256:27429b8d74ba683484a06b260b7bb00f312e7c757792628ea251afdbf1434003"},
{file = "regex-2020.1.8-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:0e182d2f097ea8549a249040922fa2b92ae28be4be4895933e369a525ba36576"},
{file = "regex-2020.1.8-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:e3cd21cc2840ca67de0bbe4071f79f031c81418deb544ceda93ad75ca1ee9f7b"},
{file = "regex-2020.1.8-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:ecc6de77df3ef68fee966bb8cb4e067e84d4d1f397d0ef6fce46913663540d77"},
{file = "regex-2020.1.8-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:26ff99c980f53b3191d8931b199b29d6787c059f2e029b2b0c694343b1708c35"},
{file = "regex-2020.1.8-cp37-cp37m-win32.whl", hash = "sha256:7bcd322935377abcc79bfe5b63c44abd0b29387f267791d566bbb566edfdd146"},
{file = "regex-2020.1.8-cp37-cp37m-win_amd64.whl", hash = "sha256:10671601ee06cf4dc1bc0b4805309040bb34c9af423c12c379c83d7895622bb5"},
{file = "regex-2020.1.8-cp38-cp38-manylinux1_i686.whl", hash = "sha256:98b8ed7bb2155e2cbb8b76f627b2fd12cf4b22ab6e14873e8641f266e0fb6d8f"},
{file = "regex-2020.1.8-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:6a6ba91b94427cd49cd27764679024b14a96874e0dc638ae6bdd4b1a3ce97be1"},
{file = "regex-2020.1.8-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:6a6ae17bf8f2d82d1e8858a47757ce389b880083c4ff2498dba17c56e6c103b9"},
{file = "regex-2020.1.8-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:0932941cdfb3afcbc26cc3bcf7c3f3d73d5a9b9c56955d432dbf8bbc147d4c5b"},
{file = "regex-2020.1.8-cp38-cp38-win32.whl", hash = "sha256:d58e4606da2a41659c84baeb3cfa2e4c87a74cec89a1e7c56bee4b956f9d7461"},
{file = "regex-2020.1.8-cp38-cp38-win_amd64.whl", hash = "sha256:e7c7661f7276507bce416eaae22040fd91ca471b5b33c13f8ff21137ed6f248c"},
{file = "regex-2020.1.8.tar.gz", hash = "sha256:d0f424328f9822b0323b3b6f2e4b9c90960b24743d220763c7f07071e0778351"},
]
requests = [
{file = "requests-2.22.0-py2.py3-none-any.whl", hash = "sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31"},
{file = "requests-2.22.0.tar.gz", hash = "sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4"},
]
toml = [
{file = "toml-0.10.0-py2.7.egg", hash = "sha256:f1db651f9657708513243e61e6cc67d101a39bad662eaa9b5546f789338e07a3"},
{file = "toml-0.10.0-py2.py3-none-any.whl", hash = "sha256:235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e"},
{file = "toml-0.10.0.tar.gz", hash = "sha256:229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c"},
]
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.8-py2.py3-none-any.whl", hash = "sha256:2f3db8b19923a873b3e5256dc9c2dedfa883e33d87c690d9c7913e1f40673cdc"},
{file = "urllib3-1.25.8.tar.gz", hash = "sha256:87716c2d2a7121198ebcb7ce7cccf6ce5e9ba539041cfbaeecfb641dc0bf6acc"},
]
wmi = [
{file = "WMI-1.4.9.win32.exe", hash = "sha256:b1c57a5c7e27596736026ec7dd9a7c5318dad8248e7638f40c60c33cb33ac935"},
{file = "WMI-1.4.9.zip", hash = "sha256:192ccfad3d7bb3ef43116d753f4d5cf85c0a6b738f832cc131e928fd93cdd400"},
]

28
pyproject.toml Normal file
View file

@ -0,0 +1,28 @@
[tool.poetry]
name = "dangerzone"
version = "0.1.0"
description = "Take potentially dangerous PDFs, office documents, or images and convert them to a safe PDF"
authors = ["Micah Lee <micah.lee@theintercept.com>"]
license = "MIT"
[tool.poetry.dependencies]
python = "^3.7"
PyQt5 = "^5.14.1"
click = "^7.0"
appdirs = "^1.4.3"
requests = "^2.22.0"
pyxdg = {version = "^0.26", platform = "linux"}
pyobjc-core = {version = "^6.1", platform = "darwin"}
pyobjc-framework-launchservices = {version = "^6.1", platform = "darwin"}
macholib = "^1.14"
pywin32 = {version = "^227", platform = "win32"}
wmi = {version = "^1.4.9", platform = "windows"}
[tool.poetry.dev-dependencies]
black = "^19.10b0"
pyinstaller = {version = "^3.6", platform = "darwin"}
setuptools = {version = "^45.2.0", platform = "win32"}
[build-system]
requires = ["poetry>=0.12"]
build-backend = "poetry.masonry.api"