From f4d71182d68458df6e6b42154a7eb7a1709dbaaf Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Sun, 11 Apr 2021 13:25:40 -0700 Subject: [PATCH 1/7] Update poetry deps, and add requests[socks] --- cli/poetry.lock | 390 ++++++++++++++++++++++----------------------- cli/pyproject.toml | 2 +- 2 files changed, 188 insertions(+), 204 deletions(-) diff --git a/cli/poetry.lock b/cli/poetry.lock index e1672272..e507395b 100644 --- a/cli/poetry.lock +++ b/cli/poetry.lock @@ -1,33 +1,32 @@ [[package]] -category = "dev" -description = "Atomic file writes." -marker = "sys_platform == \"win32\"" name = "atomicwrites" +version = "1.4.0" +description = "Atomic file writes." +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "1.4.0" [[package]] -category = "dev" -description = "Classes Without Boilerplate" name = "attrs" +version = "20.3.0" +description = "Classes Without Boilerplate" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "20.3.0" [package.extras] -dev = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "furo", "sphinx", "pre-commit"] +dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "furo", "sphinx", "pre-commit"] docs = ["furo", "sphinx", "zope.interface"] -tests = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] -tests_no_zope = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"] +tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] +tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"] [[package]] -category = "main" -description = "The bidirectional mapping library for Python." name = "bidict" +version = "0.21.2" +description = "The bidirectional mapping library for Python." +category = "main" optional = false python-versions = ">=3.6" -version = "0.21.2" [package.extras] coverage = ["coverage (<6)", "pytest-cov (<3)"] @@ -37,57 +36,56 @@ precommit = ["pre-commit (<3)"] test = ["hypothesis (<6)", "py (<2)", "pytest (<7)", "pytest-benchmark (>=3.2.0,<4)", "sortedcollections (<2)", "sortedcontainers (<3)", "Sphinx (<4)", "sphinx-autodoc-typehints (<2)"] [[package]] -category = "main" -description = "Python package for providing Mozilla's CA Bundle." name = "certifi" +version = "2020.12.5" +description = "Python package for providing Mozilla's CA Bundle." +category = "main" optional = false python-versions = "*" -version = "2020.12.5" [[package]] -category = "main" -description = "Universal encoding detector for Python 2 and 3" name = "chardet" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" version = "4.0.0" +description = "Universal encoding detector for Python 2 and 3" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] -category = "main" -description = "Composable command line interface toolkit" name = "click" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" version = "7.1.2" - -[[package]] -category = "dev" -description = "Cross-platform colored terminal text." -marker = "sys_platform == \"win32\"" -name = "colorama" +description = "Composable command line interface toolkit" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[[package]] +name = "colorama" +version = "0.4.4" +description = "Cross-platform colored terminal text." +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "0.4.4" [[package]] -category = "main" -description = "DNS toolkit" name = "dnspython" +version = "1.16.0" +description = "DNS toolkit" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "1.16.0" [package.extras] DNSSEC = ["pycryptodome", "ecdsa (>=0.13)"] IDNA = ["idna (>=2.1)"] [[package]] -category = "main" -description = "Highly concurrent networking library" name = "eventlet" +version = "0.30.2" +description = "Highly concurrent networking library" +category = "main" optional = false python-versions = "*" -version = "0.30.0" [package.dependencies] dnspython = ">=1.15.0,<2.0.0" @@ -95,18 +93,18 @@ greenlet = ">=0.3" six = ">=1.10.0" [[package]] -category = "main" -description = "A simple framework for building complex web applications." name = "flask" +version = "1.1.2" +description = "A simple framework for building complex web applications." +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "1.1.2" [package.dependencies] -Jinja2 = ">=2.10.1" -Werkzeug = ">=0.15" click = ">=5.1" itsdangerous = ">=0.24" +Jinja2 = ">=2.10.1" +Werkzeug = ">=0.15" [package.extras] dev = ["pytest", "coverage", "tox", "sphinx", "pallets-sphinx-themes", "sphinxcontrib-log-cabinet", "sphinx-issues"] @@ -114,90 +112,86 @@ docs = ["sphinx", "pallets-sphinx-themes", "sphinxcontrib-log-cabinet", "sphinx- dotenv = ["python-dotenv"] [[package]] -category = "main" -description = "Basic and Digest HTTP authentication for Flask routes" name = "flask-httpauth" +version = "4.2.0" +description = "Basic and Digest HTTP authentication for Flask routes" +category = "main" optional = false python-versions = "*" -version = "4.2.0" [package.dependencies] Flask = "*" [[package]] -category = "main" -description = "Socket.IO integration for Flask applications" name = "flask-socketio" +version = "5.0.1" +description = "Socket.IO integration for Flask applications" +category = "main" optional = false python-versions = "*" -version = "5.0.1" [package.dependencies] Flask = ">=0.9" python-socketio = ">=5.0.2" [[package]] -category = "main" -description = "Lightweight in-process concurrent programming" name = "greenlet" +version = "1.0.0" +description = "Lightweight in-process concurrent programming" +category = "main" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" -version = "1.0.0" [package.extras] docs = ["sphinx"] [[package]] -category = "main" -description = "Internationalized Domain Names in Applications (IDNA)" name = "idna" +version = "2.10" +description = "Internationalized Domain Names in Applications (IDNA)" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.10" [[package]] -category = "dev" -description = "Read metadata from Python packages" -marker = "python_version < \"3.8\"" name = "importlib-metadata" +version = "3.10.0" +description = "Read metadata from Python packages" +category = "dev" optional = false python-versions = ">=3.6" -version = "3.4.0" [package.dependencies] +typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} zipp = ">=0.5" -[package.dependencies.typing-extensions] -python = "<3.8" -version = ">=3.6.4" - [package.extras] docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=3.5,<3.7.3 || >3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] +testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] [[package]] -category = "dev" -description = "iniconfig: brain-dead simple config-ini parsing" name = "iniconfig" +version = "1.1.1" +description = "iniconfig: brain-dead simple config-ini parsing" +category = "dev" optional = false python-versions = "*" -version = "1.1.1" [[package]] -category = "main" -description = "Various helpers to pass data to untrusted environments and back." name = "itsdangerous" +version = "1.1.0" +description = "Various helpers to pass data to untrusted environments and back." +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "1.1.0" [[package]] -category = "main" -description = "A very fast and expressive template engine." name = "jinja2" +version = "2.11.3" +description = "A very fast and expressive template engine." +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "2.11.2" [package.dependencies] MarkupSafe = ">=0.23" @@ -206,127 +200,122 @@ MarkupSafe = ">=0.23" i18n = ["Babel (>=0.8)"] [[package]] -category = "main" -description = "Safely add untrusted strings to HTML/XML markup." name = "markupsafe" +version = "1.1.1" +description = "Safely add untrusted strings to HTML/XML markup." +category = "main" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" -version = "1.1.1" [[package]] -category = "dev" -description = "Core utilities for Python packages" name = "packaging" +version = "20.9" +description = "Core utilities for Python packages" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "20.9" [package.dependencies] pyparsing = ">=2.0.2" [[package]] -category = "dev" -description = "plugin and hook calling mechanisms for python" name = "pluggy" +version = "0.13.1" +description = "plugin and hook calling mechanisms for python" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "0.13.1" [package.dependencies] -[package.dependencies.importlib-metadata] -python = "<3.8" -version = ">=0.12" +importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} [package.extras] dev = ["pre-commit", "tox"] [[package]] -category = "main" -description = "Cross-platform lib for process and system monitoring in Python." name = "psutil" +version = "5.8.0" +description = "Cross-platform lib for process and system monitoring in Python." +category = "main" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "5.8.0" [package.extras] test = ["ipaddress", "mock", "unittest2", "enum34", "pywin32", "wmi"] [[package]] -category = "dev" -description = "library with cross-python path, ini-parsing, io, code, log facilities" name = "py" +version = "1.10.0" +description = "library with cross-python path, ini-parsing, io, code, log facilities" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "1.10.0" [[package]] -category = "main" -description = "Cryptographic library for Python" name = "pycryptodome" +version = "3.10.1" +description = "Cryptographic library for Python" +category = "main" optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "3.9.9" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] -category = "dev" -description = "Python parsing module" name = "pyparsing" +version = "2.4.7" +description = "Python parsing module" +category = "dev" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" -version = "2.4.7" [[package]] -category = "main" -description = "A Python SOCKS client module. See https://github.com/Anorov/PySocks for more information." name = "pysocks" +version = "1.7.1" +description = "A Python SOCKS client module. See https://github.com/Anorov/PySocks for more information." +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "1.7.1" [[package]] -category = "dev" -description = "pytest: simple powerful testing with Python" name = "pytest" +version = "6.2.3" +description = "pytest: simple powerful testing with Python" +category = "dev" optional = false python-versions = ">=3.6" -version = "6.2.2" [package.dependencies] -atomicwrites = ">=1.0" +atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} attrs = ">=19.2.0" -colorama = "*" +colorama = {version = "*", markers = "sys_platform == \"win32\""} +importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} iniconfig = "*" packaging = "*" pluggy = ">=0.12,<1.0.0a1" py = ">=1.8.2" toml = "*" -[package.dependencies.importlib-metadata] -python = "<3.8" -version = ">=0.12" - [package.extras] testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] [[package]] -category = "main" -description = "Engine.IO server" name = "python-engineio" +version = "4.0.1" +description = "Engine.IO server" +category = "main" optional = false python-versions = "*" -version = "4.0.0" [package.extras] asyncio_client = ["aiohttp (>=3.4)"] client = ["requests (>=2.21.0)", "websocket-client (>=0.54.0)"] [[package]] -category = "main" -description = "Socket.IO server" name = "python-socketio" +version = "5.1.0" +description = "Socket.IO server" +category = "main" optional = false python-versions = "*" -version = "5.0.4" [package.dependencies] bidict = ">=0.21.0" @@ -337,105 +326,105 @@ asyncio_client = ["aiohttp (>=3.4)", "websockets (>=7.0)"] client = ["requests (>=2.21.0)", "websocket-client (>=0.54.0)"] [[package]] -category = "main" -description = "Python HTTP for Humans." name = "requests" +version = "2.25.1" +description = "Python HTTP for Humans." +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "2.25.1" [package.dependencies] certifi = ">=2017.4.17" chardet = ">=3.0.2,<5" idna = ">=2.5,<3" +PySocks = {version = ">=1.5.6,<1.5.7 || >1.5.7", optional = true, markers = "extra == \"socks\""} urllib3 = ">=1.21.1,<1.27" [package.extras] security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"] -socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7)", "win-inet-pton"] +socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] [[package]] -category = "main" -description = "Python 2 and 3 compatibility utilities" name = "six" +version = "1.15.0" +description = "Python 2 and 3 compatibility utilities" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" -version = "1.15.0" [[package]] -category = "main" -description = "Stem is a Python controller library that allows applications to interact with Tor (https://www.torproject.org/)." name = "stem" +version = "1.8.0" +description = "Stem is a Python controller library that allows applications to interact with Tor (https://www.torproject.org/)." +category = "main" optional = false python-versions = "*" -version = "1.8.0" [[package]] -category = "dev" -description = "Python Library for Tom's Obvious, Minimal Language" name = "toml" +version = "0.10.2" +description = "Python Library for Tom's Obvious, Minimal Language" +category = "dev" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" -version = "0.10.2" [[package]] -category = "dev" -description = "Backported and Experimental Type Hints for Python 3.5+" -marker = "python_version < \"3.8\"" name = "typing-extensions" +version = "3.7.4.3" +description = "Backported and Experimental Type Hints for Python 3.5+" +category = "dev" optional = false python-versions = "*" -version = "3.7.4.3" [[package]] -category = "main" -description = "ASCII transliterations of Unicode text" name = "unidecode" +version = "1.2.0" +description = "ASCII transliterations of Unicode text" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "1.1.2" [[package]] -category = "main" -description = "HTTP library with thread-safe connection pooling, file post, and more." name = "urllib3" +version = "1.26.4" +description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" -version = "1.26.3" [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)"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] +brotli = ["brotlipy (>=0.6.0)"] [[package]] -category = "main" -description = "The comprehensive WSGI web application library." name = "werkzeug" +version = "1.0.1" +description = "The comprehensive WSGI web application library." +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "1.0.1" [package.extras] dev = ["pytest", "pytest-timeout", "coverage", "tox", "sphinx", "pallets-sphinx-themes", "sphinx-issues"] watchdog = ["watchdog"] [[package]] -category = "dev" -description = "Backport of pathlib-compatible object wrapper for zip files" -marker = "python_version < \"3.8\"" name = "zipp" +version = "3.4.1" +description = "Backport of pathlib-compatible object wrapper for zip files" +category = "dev" optional = false python-versions = ">=3.6" -version = "3.4.0" [package.extras] -docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=3.5,<3.7.3 || >3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "jaraco.test (>=3.2.0)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] +docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] +testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] [metadata] -content-hash = "f69ea4d5b4e409cfe082f8b14503967609add515991cc778b3f2ec4e311dcd1c" +lock-version = "1.1" python-versions = "^3.6" +content-hash = "27f9680e537bbe672c9dc3e65a88e3d9f19c4f849135153580a4209773bbced5" [metadata.files] atomicwrites = [ @@ -471,8 +460,8 @@ dnspython = [ {file = "dnspython-1.16.0.zip", hash = "sha256:36c5e8e38d4369a08b6780b7f27d790a292b2b08eea01607865bf0936c558e01"}, ] eventlet = [ - {file = "eventlet-0.30.0-py2.py3-none-any.whl", hash = "sha256:b33f31ae8d87eb2838dcb8467449211852374ee6dea97113c158fc84d9acff9b"}, - {file = "eventlet-0.30.0.tar.gz", hash = "sha256:19d6f3aa9525221ba60d0ec31b570508021af7ad5497fb77f77501fe9a7c34d3"}, + {file = "eventlet-0.30.2-py2.py3-none-any.whl", hash = "sha256:89cc6dbfef47c4629cefead5fde21c5f2b33464d57f7df5fc5148f8b4de3fbb5"}, + {file = "eventlet-0.30.2.tar.gz", hash = "sha256:1811b122d9a45eb5bafba092d36911bca825f835cb648a862bbf984030acff9d"}, ] flask = [ {file = "Flask-1.1.2-py2.py3-none-any.whl", hash = "sha256:8a4fdd8936eba2512e9c85df320a37e694c93945b33ef33c89946a340a238557"}, @@ -536,8 +525,8 @@ idna = [ {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"}, ] importlib-metadata = [ - {file = "importlib_metadata-3.4.0-py3-none-any.whl", hash = "sha256:ace61d5fc652dc280e7b6b4ff732a9c2d40db2c0f92bc6cb74e07b73d53a1771"}, - {file = "importlib_metadata-3.4.0.tar.gz", hash = "sha256:fa5daa4477a7414ae34e95942e4dd07f62adf589143c875c133c1e53c4eff38d"}, + {file = "importlib_metadata-3.10.0-py3-none-any.whl", hash = "sha256:d2d46ef77ffc85cbf7dac7e81dd663fde71c45326131bea8033b9bad42268ebe"}, + {file = "importlib_metadata-3.10.0.tar.gz", hash = "sha256:c9db46394197244adf2f0b08ec5bc3cf16757e9590b02af1fca085c16c0d600a"}, ] iniconfig = [ {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, @@ -548,8 +537,8 @@ itsdangerous = [ {file = "itsdangerous-1.1.0.tar.gz", hash = "sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19"}, ] jinja2 = [ - {file = "Jinja2-2.11.2-py2.py3-none-any.whl", hash = "sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035"}, - {file = "Jinja2-2.11.2.tar.gz", hash = "sha256:89aab215427ef59c34ad58735269eb58b1a5808103067f7bb9d5836c651b3bb0"}, + {file = "Jinja2-2.11.3-py2.py3-none-any.whl", hash = "sha256:03e47ad063331dd6a3f04a43eddca8a966a26ba0c5b7207a9a9e4e08f1b29419"}, + {file = "Jinja2-2.11.3.tar.gz", hash = "sha256:a6d58433de0ae800347cab1fa3043cebbabe8baa9d29e668f1c768cb87a333c6"}, ] markupsafe = [ {file = "MarkupSafe-1.1.1-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161"}, @@ -629,41 +618,36 @@ py = [ {file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"}, ] pycryptodome = [ - {file = "pycryptodome-3.9.9-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:5598dc6c9dbfe882904e54584322893eff185b98960bbe2cdaaa20e8a437b6e5"}, - {file = "pycryptodome-3.9.9-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:1cfdb92dca388e27e732caa72a1cc624520fe93752a665c3b6cd8f1a91b34916"}, - {file = "pycryptodome-3.9.9-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5f19e6ef750f677d924d9c7141f54bade3cd56695bbfd8a9ef15d0378557dfe4"}, - {file = "pycryptodome-3.9.9-cp27-cp27m-win32.whl", hash = "sha256:a3d8a9efa213be8232c59cdc6b65600276508e375e0a119d710826248fd18d37"}, - {file = "pycryptodome-3.9.9-cp27-cp27m-win_amd64.whl", hash = "sha256:50826b49fbca348a61529693b0031cdb782c39060fb9dca5ac5dff858159dc5a"}, - {file = "pycryptodome-3.9.9-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:19cb674df6c74a14b8b408aa30ba8a89bd1c01e23505100fb45f930fbf0ed0d9"}, - {file = "pycryptodome-3.9.9-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:28f75e58d02019a7edc7d4135203d2501dfc47256d175c72c9798f9a129a49a7"}, - {file = "pycryptodome-3.9.9-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:6d3baaf82681cfb1a842f1c8f77beac791ceedd99af911e4f5fabec32bae2259"}, - {file = "pycryptodome-3.9.9-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:946399d15eccebafc8ce0257fc4caffe383c75e6b0633509bd011e357368306c"}, - {file = "pycryptodome-3.9.9-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:eb01f9997e4d6a8ec8a1ad1f676ba5a362781ff64e8189fe2985258ba9cb9706"}, - {file = "pycryptodome-3.9.9-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:411745c6dce4eff918906eebcde78771d44795d747e194462abb120d2e537cd9"}, - {file = "pycryptodome-3.9.9-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:8f9f84059039b672a5a705b3c5aa21747867bacc30a72e28bf0d147cc8ef85ed"}, - {file = "pycryptodome-3.9.9-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:7798e73225a699651888489fbb1dbc565e03a509942a8ce6194bbe6fb582a41f"}, - {file = "pycryptodome-3.9.9-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:46e96aeb8a9ca8b1edf9b1fd0af4bf6afcf3f1ca7fa35529f5d60b98f3e4e959"}, - {file = "pycryptodome-3.9.9-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:843e5f10ecdf9d307032b8b91afe9da1d6ed5bb89d0bbec5c8dcb4ba44008e11"}, - {file = "pycryptodome-3.9.9-cp36-cp36m-win32.whl", hash = "sha256:b68794fba45bdb367eeb71249c26d23e61167510a1d0c3d6cf0f2f14636e62ee"}, - {file = "pycryptodome-3.9.9-cp36-cp36m-win_amd64.whl", hash = "sha256:60febcf5baf70c566d9d9351c47fbd8321da9a4edf2eff45c4c31c86164ca794"}, - {file = "pycryptodome-3.9.9-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:4ed27951b0a17afd287299e2206a339b5b6d12de9321e1a1575261ef9c4a851b"}, - {file = "pycryptodome-3.9.9-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:9000877383e2189dafd1b2fc68c6c726eca9a3cfb6d68148fbb72ccf651959b6"}, - {file = "pycryptodome-3.9.9-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:faa682c404c218e8788c3126c9a4b8fbcc54dc245b5b6e8ea5b46f3b63bd0c84"}, - {file = "pycryptodome-3.9.9-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:62c488a21c253dadc9f731a32f0ac61e4e436d81a1ea6f7d1d9146ed4d20d6bd"}, - {file = "pycryptodome-3.9.9-cp37-cp37m-win32.whl", hash = "sha256:834b790bbb6bd18956f625af4004d9c15eed12d5186d8e57851454ae76d52215"}, - {file = "pycryptodome-3.9.9-cp37-cp37m-win_amd64.whl", hash = "sha256:70d807d11d508433daf96244ec1c64e55039e8a35931fc5ea9eee94dbe3cb6b5"}, - {file = "pycryptodome-3.9.9-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:27397aee992af69d07502126561d851ba3845aa808f0e55c71ad0efa264dd7d4"}, - {file = "pycryptodome-3.9.9-cp38-cp38-manylinux1_i686.whl", hash = "sha256:d7ec2bd8f57c559dd24e71891c51c25266a8deb66fc5f02cc97c7fb593d1780a"}, - {file = "pycryptodome-3.9.9-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:e15bde67ccb7d4417f627dd16ffe2f5a4c2941ce5278444e884cb26d73ecbc61"}, - {file = "pycryptodome-3.9.9-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:5c3c4865730dfb0263f822b966d6d58429d8b1e560d1ddae37685fd9e7c63161"}, - {file = "pycryptodome-3.9.9-cp38-cp38-win32.whl", hash = "sha256:76b1a34d74bb2c91bce460cdc74d1347592045627a955e9a252554481c17c52f"}, - {file = "pycryptodome-3.9.9-cp38-cp38-win_amd64.whl", hash = "sha256:6e4227849e4231a3f5b35ea5bdedf9a82b3883500e5624f00a19156e9a9ef861"}, - {file = "pycryptodome-3.9.9-cp39-cp39-manylinux1_i686.whl", hash = "sha256:2a68df525b387201a43b27b879ce8c08948a430e883a756d6c9e3acdaa7d7bd8"}, - {file = "pycryptodome-3.9.9-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:a4599c0ca0fc027c780c1c45ed996d5bef03e571470b7b1c7171ec1e1a90914c"}, - {file = "pycryptodome-3.9.9-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:b4e6b269a8ddaede774e5c3adbef6bf452ee144e6db8a716d23694953348cd86"}, - {file = "pycryptodome-3.9.9-cp39-cp39-win32.whl", hash = "sha256:a199e9ca46fc6e999e5f47fce342af4b56c7de85fae893c69ab6aa17531fb1e1"}, - {file = "pycryptodome-3.9.9-cp39-cp39-win_amd64.whl", hash = "sha256:6e89bb3826e6f84501e8e3b205c22595d0c5492c2f271cbb9ee1c48eb1866645"}, - {file = "pycryptodome-3.9.9.tar.gz", hash = "sha256:910e202a557e1131b1c1b3f17a63914d57aac55cf9fb9b51644962841c3995c4"}, + {file = "pycryptodome-3.10.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:1c5e1ca507de2ad93474be5cfe2bfa76b7cf039a1a32fc196f40935944871a06"}, + {file = "pycryptodome-3.10.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:6260e24d41149268122dd39d4ebd5941e9d107f49463f7e071fd397e29923b0c"}, + {file = "pycryptodome-3.10.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:3f840c49d38986f6e17dbc0673d37947c88bc9d2d9dba1c01b979b36f8447db1"}, + {file = "pycryptodome-3.10.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:2dea65df54349cdfa43d6b2e8edb83f5f8d6861e5cf7b1fbc3e34c5694c85e27"}, + {file = "pycryptodome-3.10.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:e61e363d9a5d7916f3a4ce984a929514c0df3daf3b1b2eb5e6edbb131ee771cf"}, + {file = "pycryptodome-3.10.1-cp27-cp27m-manylinux2014_aarch64.whl", hash = "sha256:2603c98ae04aac675fefcf71a6c87dc4bb74a75e9071ae3923bbc91a59f08d35"}, + {file = "pycryptodome-3.10.1-cp27-cp27m-win32.whl", hash = "sha256:38661348ecb71476037f1e1f553159b80d256c00f6c0b00502acac891f7116d9"}, + {file = "pycryptodome-3.10.1-cp27-cp27m-win_amd64.whl", hash = "sha256:1723ebee5561628ce96748501cdaa7afaa67329d753933296321f0be55358dce"}, + {file = "pycryptodome-3.10.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:77997519d8eb8a4adcd9a47b9cec18f9b323e296986528186c0e9a7a15d6a07e"}, + {file = "pycryptodome-3.10.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:99b2f3fc51d308286071d0953f92055504a6ffe829a832a9fc7a04318a7683dd"}, + {file = "pycryptodome-3.10.1-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:e0a4d5933a88a2c98bbe19c0c722f5483dc628d7a38338ac2cb64a7dbd34064b"}, + {file = "pycryptodome-3.10.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:d3d6958d53ad307df5e8469cc44474a75393a434addf20ecd451f38a72fe29b8"}, + {file = "pycryptodome-3.10.1-cp27-cp27mu-manylinux2014_aarch64.whl", hash = "sha256:a8eb8b6ea09ec1c2535bf39914377bc8abcab2c7d30fa9225eb4fe412024e427"}, + {file = "pycryptodome-3.10.1-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:31c1df17b3dc5f39600a4057d7db53ac372f492c955b9b75dd439f5d8b460129"}, + {file = "pycryptodome-3.10.1-cp35-abi3-manylinux1_i686.whl", hash = "sha256:a3105a0eb63eacf98c2ecb0eb4aa03f77f40fbac2bdde22020bb8a536b226bb8"}, + {file = "pycryptodome-3.10.1-cp35-abi3-manylinux1_x86_64.whl", hash = "sha256:a92d5c414e8ee1249e850789052608f582416e82422502dc0ac8c577808a9067"}, + {file = "pycryptodome-3.10.1-cp35-abi3-manylinux2010_i686.whl", hash = "sha256:60386d1d4cfaad299803b45a5bc2089696eaf6cdd56f9fc17479a6f89595cfc8"}, + {file = "pycryptodome-3.10.1-cp35-abi3-manylinux2010_x86_64.whl", hash = "sha256:501ab36aae360e31d0ec370cf5ce8ace6cb4112060d099b993bc02b36ac83fb6"}, + {file = "pycryptodome-3.10.1-cp35-abi3-manylinux2014_aarch64.whl", hash = "sha256:fc7489a50323a0df02378bc2fff86eb69d94cc5639914346c736be981c6a02e7"}, + {file = "pycryptodome-3.10.1-cp35-abi3-win32.whl", hash = "sha256:9b6f711b25e01931f1c61ce0115245a23cdc8b80bf8539ac0363bdcf27d649b6"}, + {file = "pycryptodome-3.10.1-cp35-abi3-win_amd64.whl", hash = "sha256:7fd519b89585abf57bf47d90166903ec7b43af4fe23c92273ea09e6336af5c07"}, + {file = "pycryptodome-3.10.1-pp27-pypy_73-macosx_10_9_x86_64.whl", hash = "sha256:09c1555a3fa450e7eaca41ea11cd00afe7c91fef52353488e65663777d8524e0"}, + {file = "pycryptodome-3.10.1-pp27-pypy_73-manylinux1_x86_64.whl", hash = "sha256:758949ca62690b1540dfb24ad773c6da9cd0e425189e83e39c038bbd52b8e438"}, + {file = "pycryptodome-3.10.1-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:e3bf558c6aeb49afa9f0c06cee7fb5947ee5a1ff3bd794b653d39926b49077fa"}, + {file = "pycryptodome-3.10.1-pp27-pypy_73-win32.whl", hash = "sha256:f977cdf725b20f6b8229b0c87acb98c7717e742ef9f46b113985303ae12a99da"}, + {file = "pycryptodome-3.10.1-pp36-pypy36_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6d2df5223b12437e644ce0a3be7809471ffa71de44ccd28b02180401982594a6"}, + {file = "pycryptodome-3.10.1-pp36-pypy36_pp73-manylinux1_x86_64.whl", hash = "sha256:98213ac2b18dc1969a47bc65a79a8fca02a414249d0c8635abb081c7f38c91b6"}, + {file = "pycryptodome-3.10.1-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:12222a5edc9ca4a29de15fbd5339099c4c26c56e13c2ceddf0b920794f26165d"}, + {file = "pycryptodome-3.10.1-pp36-pypy36_pp73-win32.whl", hash = "sha256:6bbf7fee7b7948b29d7e71fcacf48bac0c57fb41332007061a933f2d996f9713"}, + {file = "pycryptodome-3.10.1.tar.gz", hash = "sha256:3e2e3a06580c5f190df843cdb90ea28d61099cf4924334d5297a995de68e4673"}, ] pyparsing = [ {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, @@ -675,16 +659,16 @@ pysocks = [ {file = "PySocks-1.7.1.tar.gz", hash = "sha256:3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0"}, ] pytest = [ - {file = "pytest-6.2.2-py3-none-any.whl", hash = "sha256:b574b57423e818210672e07ca1fa90aaf194a4f63f3ab909a2c67ebb22913839"}, - {file = "pytest-6.2.2.tar.gz", hash = "sha256:9d1edf9e7d0b84d72ea3dbcdfd22b35fb543a5e8f2a60092dd578936bf63d7f9"}, + {file = "pytest-6.2.3-py3-none-any.whl", hash = "sha256:6ad9c7bdf517a808242b998ac20063c41532a570d088d77eec1ee12b0b5574bc"}, + {file = "pytest-6.2.3.tar.gz", hash = "sha256:671238a46e4df0f3498d1c3270e5deb9b32d25134c99b7d75370a68cfbe9b634"}, ] python-engineio = [ - {file = "python-engineio-4.0.0.tar.gz", hash = "sha256:9f34afa4170f5ba6e3d9ff158752ccf8fbb2145f16554b2f0fc84646675be99a"}, - {file = "python_engineio-4.0.0-py2.py3-none-any.whl", hash = "sha256:33f7a214be5db35c867e97027bfe63676cb003d82aa17a607612b25ba5d84e5b"}, + {file = "python-engineio-4.0.1.tar.gz", hash = "sha256:bb575c1a3512b4b5d4706f3071d5cc36e592459e99a47d9a4b7faabeba941377"}, + {file = "python_engineio-4.0.1-py2.py3-none-any.whl", hash = "sha256:759ec99d91b3d36b29596124c77ba7c063c7ab97685d318fb23a166d9a4b9187"}, ] python-socketio = [ - {file = "python-socketio-5.0.4.tar.gz", hash = "sha256:f53fd0d5bd9f75a70492062f4ae6195ab5d34d67a29024d740f25e468392893e"}, - {file = "python_socketio-5.0.4-py2.py3-none-any.whl", hash = "sha256:870f8b00a63ef7c9a1f85fd70028624867bf246115e82625f28ef79def8847bb"}, + {file = "python-socketio-5.1.0.tar.gz", hash = "sha256:338cc29abb6f3ca14c88f1f8d05ed27c690df4648f62062b299f92625bbf7093"}, + {file = "python_socketio-5.1.0-py2.py3-none-any.whl", hash = "sha256:8a7ed43bfdbbb266eb8a661a0c9648dc94bcd9689566ae3ee08bf98eca8987af"}, ] requests = [ {file = "requests-2.25.1-py2.py3-none-any.whl", hash = "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"}, @@ -707,18 +691,18 @@ typing-extensions = [ {file = "typing_extensions-3.7.4.3.tar.gz", hash = "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c"}, ] unidecode = [ - {file = "Unidecode-1.1.2-py2.py3-none-any.whl", hash = "sha256:4c9d15d2f73eb0d2649a151c566901f80a030da1ccb0a2043352e1dbf647586b"}, - {file = "Unidecode-1.1.2.tar.gz", hash = "sha256:a039f89014245e0cad8858976293e23501accc9ff5a7bdbc739a14a2b7b85cdc"}, + {file = "Unidecode-1.2.0-py2.py3-none-any.whl", hash = "sha256:12435ef2fc4cdfd9cf1035a1db7e98b6b047fe591892e81f34e94959591fad00"}, + {file = "Unidecode-1.2.0.tar.gz", hash = "sha256:8d73a97d387a956922344f6b74243c2c6771594659778744b2dbdaad8f6b727d"}, ] urllib3 = [ - {file = "urllib3-1.26.3-py2.py3-none-any.whl", hash = "sha256:1b465e494e3e0d8939b50680403e3aedaa2bc434b7d5af64dfd3c958d7f5ae80"}, - {file = "urllib3-1.26.3.tar.gz", hash = "sha256:de3eedaad74a2683334e282005cd8d7f22f4d55fa690a2a1020a416cb0a47e73"}, + {file = "urllib3-1.26.4-py2.py3-none-any.whl", hash = "sha256:2f4da4594db7e1e110a944bb1b551fdf4e6c136ad42e4234131391e21eb5b0df"}, + {file = "urllib3-1.26.4.tar.gz", hash = "sha256:e7b021f7241115872f92f43c6508082facffbd1c048e3c6e2bb9c2a157e28937"}, ] werkzeug = [ {file = "Werkzeug-1.0.1-py2.py3-none-any.whl", hash = "sha256:2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43"}, {file = "Werkzeug-1.0.1.tar.gz", hash = "sha256:6c80b1e5ad3665290ea39320b91e1be1e0d5f60652b964a3070216de83d2e47c"}, ] zipp = [ - {file = "zipp-3.4.0-py3-none-any.whl", hash = "sha256:102c24ef8f171fd729d46599845e95c7ab894a4cf45f5de11a44cc7444fb1108"}, - {file = "zipp-3.4.0.tar.gz", hash = "sha256:ed5eee1974372595f9e416cc7bbeeb12335201d8081ca8a0743c954d4446e5cb"}, + {file = "zipp-3.4.1-py3-none-any.whl", hash = "sha256:51cb66cc54621609dd593d1787f286ee42a5c0adbb4b29abea5a63edc3e03098"}, + {file = "zipp-3.4.1.tar.gz", hash = "sha256:3607921face881ba3e026887d8150cca609d517579abe052ac81fc5aeffdbd76"}, ] diff --git a/cli/pyproject.toml b/cli/pyproject.toml index e393a8c5..ecf19e5d 100644 --- a/cli/pyproject.toml +++ b/cli/pyproject.toml @@ -24,7 +24,7 @@ flask-socketio = "*" psutil = "*" pycryptodome = "*" pysocks = "*" -requests = "*" +requests = {extras = ["socks"], version = "^2.25.1"} stem = "*" unidecode = "*" urllib3 = "*" From 29970d38ffebb10dcdcd4b9c7fad9a960c27daaf Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Sun, 11 Apr 2021 13:33:58 -0700 Subject: [PATCH 2/7] Implement receive mode webhooks in CLI --- cli/onionshare_cli/__init__.py | 28 +++++++++++++++++++++++--- cli/onionshare_cli/mode_settings.py | 5 ++++- cli/onionshare_cli/web/receive_mode.py | 25 +++++++++++++++++++++++ 3 files changed, 54 insertions(+), 4 deletions(-) diff --git a/cli/onionshare_cli/__init__.py b/cli/onionshare_cli/__init__.py index c40bf6a0..1bd0582c 100644 --- a/cli/onionshare_cli/__init__.py +++ b/cli/onionshare_cli/__init__.py @@ -193,6 +193,12 @@ def main(cwd=None): default=None, help="Receive files: Save files received to this directory", ) + parser.add_argument( + "--webhook-url", + metavar="webhook_url", + default=None, + help="Receive files: URL to receive webhook notifications", + ) # Website args parser.add_argument( "--disable_csp", @@ -235,6 +241,7 @@ def main(cwd=None): client_auth = bool(args.client_auth) autostop_sharing = not bool(args.no_autostop_sharing) data_dir = args.data_dir + webhook_url = args.webhook_url disable_csp = bool(args.disable_csp) verbose = bool(args.verbose) @@ -283,6 +290,8 @@ def main(cwd=None): if mode == "receive": if data_dir: mode_settings.set("receive", "data_dir", data_dir) + if webhook_url: + mode_settings.set("receive", "webhook_url", webhook_url) if mode == "website": mode_settings.set("website", "disable_csp", disable_csp) else: @@ -354,10 +363,23 @@ def main(cwd=None): # Start the onionshare app try: common.settings.load() - if not mode_settings.get("general", "public"): - web.generate_password(mode_settings.get("onion", "password")) - else: + + if mode_settings.get("general", "public"): web.password = None + else: + web.generate_password(mode_settings.get("onion", "password")) + + # Receive mode needs to know the tor proxy details for webhooks + if mode == "receive": + if local_only: + web.proxies = None + else: + (socks_address, socks_port) = onion.get_tor_socks_port() + web.proxies = { + "http": f"socks5://{socks_address}:{socks_port}", + "https": f"socks5://{socks_address}:{socks_port}", + } + app = OnionShare(common, onion, local_only, autostop_timer) app.choose_port() diff --git a/cli/onionshare_cli/mode_settings.py b/cli/onionshare_cli/mode_settings.py index 4f105653..c2e5e6cd 100644 --- a/cli/onionshare_cli/mode_settings.py +++ b/cli/onionshare_cli/mode_settings.py @@ -50,7 +50,10 @@ class ModeSettings: "service_id": None, }, "share": {"autostop_sharing": True, "filenames": []}, - "receive": {"data_dir": self.build_default_receive_data_dir()}, + "receive": { + "data_dir": self.build_default_receive_data_dir(), + "webhook_url": None, + }, "website": {"disable_csp": False, "filenames": []}, "chat": {"room": "default"}, } diff --git a/cli/onionshare_cli/web/receive_mode.py b/cli/onionshare_cli/web/receive_mode.py index 62415578..d3bd3c2b 100644 --- a/cli/onionshare_cli/web/receive_mode.py +++ b/cli/onionshare_cli/web/receive_mode.py @@ -21,6 +21,7 @@ along with this program. If not, see . import os import tempfile import json +import requests from datetime import datetime from flask import Request, request, render_template, make_response, flash, redirect from werkzeug.utils import secure_filename @@ -101,6 +102,14 @@ class ReceiveModeWeb: ) print(f"\nReceived: {local_path}") + # Send webhook if configured + if ( + self.web.settings.get("receive", "webhook_url") + and not request.upload_error + and len(files) > 0 + ): + self.send_websocket_notification(f"{len(files)} files uploaded") + if request.upload_error: self.common.log( "ReceiveModeWeb", @@ -172,6 +181,22 @@ class ReceiveModeWeb: return self.web.error403() return upload(ajax=True) + def send_websocket_notification(self, data): + self.common.log("ReceiveModeWeb", "send_websocket_notification", data) + try: + requests.post( + self.web.settings.get("receive", "webhook_url"), + data=data, + timeout=5, + proxies=self.web.proxies, + ) + except Exception as e: + self.common.log( + "ReceiveModeWeb", + "send_websocket_notification", + f"sending failed: {e}", + ) + class ReceiveModeWSGIMiddleware(object): """ From 84958ef7f3532859b9e861e7b7683d9a60fbcea6 Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Sun, 11 Apr 2021 13:49:51 -0700 Subject: [PATCH 3/7] Oops, webhook not websocket --- cli/onionshare_cli/web/receive_mode.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cli/onionshare_cli/web/receive_mode.py b/cli/onionshare_cli/web/receive_mode.py index d3bd3c2b..26ec0b65 100644 --- a/cli/onionshare_cli/web/receive_mode.py +++ b/cli/onionshare_cli/web/receive_mode.py @@ -108,7 +108,7 @@ class ReceiveModeWeb: and not request.upload_error and len(files) > 0 ): - self.send_websocket_notification(f"{len(files)} files uploaded") + self.send_webhook_notification(f"{len(files)} files uploaded") if request.upload_error: self.common.log( @@ -181,8 +181,8 @@ class ReceiveModeWeb: return self.web.error403() return upload(ajax=True) - def send_websocket_notification(self, data): - self.common.log("ReceiveModeWeb", "send_websocket_notification", data) + def send_webhook_notification(self, data): + self.common.log("ReceiveModeWeb", "send_webhook_notification", data) try: requests.post( self.web.settings.get("receive", "webhook_url"), @@ -193,7 +193,7 @@ class ReceiveModeWeb: except Exception as e: self.common.log( "ReceiveModeWeb", - "send_websocket_notification", + "send_webhook_notification", f"sending failed: {e}", ) From 91308bf51b90828611e0a951ba9362a101f1e1ff Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Sun, 11 Apr 2021 21:16:18 -0700 Subject: [PATCH 4/7] Add receive mode webhook to GUI --- .../src/onionshare/resources/locale/en.json | 1 + .../tab/mode/receive_mode/__init__.py | 60 ++++++++++++++++++- 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/desktop/src/onionshare/resources/locale/en.json b/desktop/src/onionshare/resources/locale/en.json index f7b8f7bb..74cac4ca 100644 --- a/desktop/src/onionshare/resources/locale/en.json +++ b/desktop/src/onionshare/resources/locale/en.json @@ -174,6 +174,7 @@ "mode_settings_share_autostop_sharing_checkbox": "Stop sharing after files have been sent (uncheck to allow downloading individual files)", "mode_settings_receive_data_dir_label": "Save files to", "mode_settings_receive_data_dir_browse_button": "Browse", + "mode_settings_receive_webhook_url_checkbox": "Use webhook URL", "mode_settings_website_disable_csp_checkbox": "Don't send Content Security Policy header (allows your website to use third-party resources)", "gui_all_modes_transfer_finished_range": "Transferred {} - {}", "gui_all_modes_transfer_finished": "Transferred {}", diff --git a/desktop/src/onionshare/tab/mode/receive_mode/__init__.py b/desktop/src/onionshare/tab/mode/receive_mode/__init__.py index 8a848128..5f65152e 100644 --- a/desktop/src/onionshare/tab/mode/receive_mode/__init__.py +++ b/desktop/src/onionshare/tab/mode/receive_mode/__init__.py @@ -60,6 +60,8 @@ class ReceiveMode(Mode): self.image.setLayout(image_layout) # Settings + + # Data dir data_dir_label = QtWidgets.QLabel( strings._("mode_settings_receive_data_dir_label") ) @@ -74,9 +76,36 @@ class ReceiveMode(Mode): data_dir_layout.addWidget(data_dir_label) data_dir_layout.addWidget(self.data_dir_lineedit) data_dir_layout.addWidget(data_dir_button) - self.mode_settings_widget.mode_specific_layout.addLayout(data_dir_layout) + # Webhook URL + webhook_url = self.settings.get("receive", "webhook_url") + self.webhook_url_checkbox = QtWidgets.QCheckBox() + self.webhook_url_checkbox.clicked.connect(self.webhook_url_checkbox_clicked) + self.webhook_url_checkbox.setText( + strings._("mode_settings_receive_webhook_url_checkbox") + ) + self.webhook_url_lineedit = QtWidgets.QLineEdit() + self.webhook_url_lineedit.editingFinished.connect( + self.webhook_url_editing_finished + ) + self.webhook_url_lineedit.setPlaceholderText( + "https://example.com/post-when-file-uploaded" + ) + webhook_url_layout = QtWidgets.QHBoxLayout() + webhook_url_layout.addWidget(self.webhook_url_checkbox) + webhook_url_layout.addWidget(self.webhook_url_lineedit) + if webhook_url is not None and webhook_url != "": + self.webhook_url_checkbox.setCheckState(QtCore.Qt.Checked) + self.webhook_url_lineedit.setText( + self.settings.get("receive", "webhook_url") + ) + self.show_webhook_url() + else: + self.webhook_url_checkbox.setCheckState(QtCore.Qt.Unchecked) + self.hide_webhook_url() + self.mode_settings_widget.mode_specific_layout.addLayout(webhook_url_layout) + # Server status self.server_status.set_mode("receive") self.server_status.server_started_finished.connect(self.update_primary_action) @@ -183,6 +212,25 @@ class ReceiveMode(Mode): self.data_dir_lineedit.setText(selected_dir) self.settings.set("receive", "data_dir", selected_dir) + def webhook_url_checkbox_clicked(self): + if self.webhook_url_checkbox.isChecked(): + if self.settings.get("receive", "webhook_url"): + self.webhook_url_lineedit.setText( + self.settings.get("receive", "webhook_url") + ) + self.show_webhook_url() + else: + self.hide_webhook_url() + + def webhook_url_editing_finished(self): + self.settings.set("receive", "webhook_url", self.webhook_url_lineedit.text()) + + def hide_webhook_url(self): + self.webhook_url_lineedit.hide() + + def show_webhook_url(self): + self.webhook_url_lineedit.show() + def get_stop_server_autostop_timer_text(self): """ Return the string to put on the stop server button, if there's an auto-stop timer @@ -220,6 +268,16 @@ class ReceiveMode(Mode): # Hide and reset the uploads if we have previously shared self.reset_info_counters() + # Set proxies for webhook URL + if self.common.gui.local_only: + self.web.proxies = None + else: + (socks_address, socks_port) = self.common.gui.onion.get_tor_socks_port() + self.web.proxies = { + "http": f"socks5://{socks_address}:{socks_port}", + "https": f"socks5://{socks_address}:{socks_port}", + } + def start_server_step2_custom(self): """ Step 2 in starting the server. From eb628ad0935df410f760a5b2558ea84d78339b96 Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Mon, 12 Apr 2021 07:53:14 -0700 Subject: [PATCH 5/7] Save state when unchecking webhook checkbox --- desktop/src/onionshare/tab/mode/receive_mode/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/desktop/src/onionshare/tab/mode/receive_mode/__init__.py b/desktop/src/onionshare/tab/mode/receive_mode/__init__.py index 5f65152e..5cc72201 100644 --- a/desktop/src/onionshare/tab/mode/receive_mode/__init__.py +++ b/desktop/src/onionshare/tab/mode/receive_mode/__init__.py @@ -220,6 +220,7 @@ class ReceiveMode(Mode): ) self.show_webhook_url() else: + self.settings.set("receive", "webhook_url", None) self.hide_webhook_url() def webhook_url_editing_finished(self): From 839b23f87a367a60f25f4f2979611547e6590b90 Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Mon, 12 Apr 2021 09:08:47 -0700 Subject: [PATCH 6/7] Improve webhook label in GUI, improve webhook message that gets POSTed, and display webhook errors without verbose mode --- cli/onionshare_cli/web/receive_mode.py | 12 ++++++------ desktop/src/onionshare/resources/locale/en.json | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cli/onionshare_cli/web/receive_mode.py b/cli/onionshare_cli/web/receive_mode.py index 26ec0b65..46f471a8 100644 --- a/cli/onionshare_cli/web/receive_mode.py +++ b/cli/onionshare_cli/web/receive_mode.py @@ -108,7 +108,11 @@ class ReceiveModeWeb: and not request.upload_error and len(files) > 0 ): - self.send_webhook_notification(f"{len(files)} files uploaded") + if len(files) == 1: + file_msg = "1 file" + else: + file_msg = f"{len(files)} files" + self.send_webhook_notification(f"{file_msg} uploaded to OnionShare") if request.upload_error: self.common.log( @@ -191,11 +195,7 @@ class ReceiveModeWeb: proxies=self.web.proxies, ) except Exception as e: - self.common.log( - "ReceiveModeWeb", - "send_webhook_notification", - f"sending failed: {e}", - ) + print(f"Webhook notification failed: {e}") class ReceiveModeWSGIMiddleware(object): diff --git a/desktop/src/onionshare/resources/locale/en.json b/desktop/src/onionshare/resources/locale/en.json index 74cac4ca..20569c57 100644 --- a/desktop/src/onionshare/resources/locale/en.json +++ b/desktop/src/onionshare/resources/locale/en.json @@ -174,7 +174,7 @@ "mode_settings_share_autostop_sharing_checkbox": "Stop sharing after files have been sent (uncheck to allow downloading individual files)", "mode_settings_receive_data_dir_label": "Save files to", "mode_settings_receive_data_dir_browse_button": "Browse", - "mode_settings_receive_webhook_url_checkbox": "Use webhook URL", + "mode_settings_receive_webhook_url_checkbox": "Use notification webhook", "mode_settings_website_disable_csp_checkbox": "Don't send Content Security Policy header (allows your website to use third-party resources)", "gui_all_modes_transfer_finished_range": "Transferred {} - {}", "gui_all_modes_transfer_finished": "Transferred {}", From 09975fb0f184c0f126c6c882b6d2eb04380d02f8 Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Mon, 12 Apr 2021 09:34:12 -0700 Subject: [PATCH 7/7] Test webhook in CLI --- cli/tests/test_cli_web.py | 48 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/cli/tests/test_cli_web.py b/cli/tests/test_cli_web.py index 421ee4f3..5856ba9a 100644 --- a/cli/tests/test_cli_web.py +++ b/cli/tests/test_cli_web.py @@ -4,6 +4,7 @@ import re import zipfile import tempfile import base64 +from io import BytesIO import pytest from werkzeug.datastructures import Headers @@ -12,6 +13,21 @@ from onionshare_cli.common import Common from onionshare_cli.web import Web from onionshare_cli.settings import Settings from onionshare_cli.mode_settings import ModeSettings +import onionshare_cli.web.receive_mode + +# Stub requests.post, for receive mode webhook tests +webhook_url = None +webhook_data = None + + +def requests_post_stub(url, data, timeout, proxies): + global webhook_url, webhook_data + webhook_url = url + webhook_data = data + + +onionshare_cli.web.receive_mode.requests.post = requests_post_stub + DEFAULT_ZW_FILENAME_REGEX = re.compile(r"^onionshare_[a-z2-7]{6}.zip$") RANDOM_STR_REGEX = re.compile(r"^[a-z2-7]+$") @@ -129,6 +145,38 @@ class TestWeb: res.get_data() assert res.status_code == 200 + def test_receive_mode_webhook(self, temp_dir, common_obj): + global webhook_url, webhook_data + webhook_url = None + webhook_data = None + + web = web_obj(temp_dir, common_obj, "receive") + assert web.mode == "receive" + web.settings.set("receive", "webhook_url", "http://127.0.0.1:1337/example") + web.proxies = None + assert ( + web.settings.get("receive", "webhook_url") + == "http://127.0.0.1:1337/example" + ) + + with web.app.test_client() as c: + res = c.get("/", headers=self._make_auth_headers(web.password)) + res.get_data() + assert res.status_code == 200 + + res = c.post( + "/upload-ajax", + buffered=True, + content_type="multipart/form-data", + data={"file[]": (BytesIO(b"THIS IS A TEST FILE"), "new_york.jpg")}, + headers=self._make_auth_headers(web.password), + ) + res.get_data() + assert res.status_code == 200 + + assert webhook_url == "http://127.0.0.1:1337/example" + assert webhook_data == "1 file uploaded to OnionShare" + def test_public_mode_on(self, temp_dir, common_obj): web = web_obj(temp_dir, common_obj, "receive") web.settings.set("general", "public", True)