mirror of
https://github.com/onionshare/onionshare.git
synced 2025-12-15 16:29:35 -05:00
Remove v2 legacy onion support, and its corresponding client auth functionality. Update the v3 Client Auth to take its place in settings
This commit is contained in:
parent
4aa6d6f3ec
commit
286d7703d6
68 changed files with 62 additions and 552 deletions
|
|
@ -120,26 +120,12 @@ def main(cwd=None):
|
|||
default=0,
|
||||
help="Stop onion service at schedule time (N seconds from now)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--legacy",
|
||||
action="store_true",
|
||||
dest="legacy",
|
||||
default=False,
|
||||
help="Use legacy address (v2 onion service, not recommended)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--client-auth",
|
||||
action="store_true",
|
||||
dest="client_auth",
|
||||
default=False,
|
||||
help="Use V2 client authorization (requires --legacy)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--client-auth-v3",
|
||||
action="store_true",
|
||||
dest="client_auth_v3",
|
||||
default=False,
|
||||
help="Use V3 client authorization",
|
||||
help="Use client authorization",
|
||||
)
|
||||
# Share args
|
||||
parser.add_argument(
|
||||
|
|
@ -201,9 +187,7 @@ def main(cwd=None):
|
|||
public = bool(args.public)
|
||||
autostart_timer = int(args.autostart_timer)
|
||||
autostop_timer = int(args.autostop_timer)
|
||||
legacy = bool(args.legacy)
|
||||
client_auth = bool(args.client_auth)
|
||||
client_auth_v3 = bool(args.client_auth_v3)
|
||||
autostop_sharing = not bool(args.no_autostop_sharing)
|
||||
data_dir = args.data_dir
|
||||
webhook_url = args.webhook_url
|
||||
|
|
@ -222,20 +206,6 @@ def main(cwd=None):
|
|||
# Verbose mode?
|
||||
common.verbose = verbose
|
||||
|
||||
# client_auth can only be set if legacy is also set
|
||||
if client_auth and not legacy:
|
||||
print(
|
||||
"Client authentication (--client-auth) is only supported with legacy onion services (--legacy)"
|
||||
)
|
||||
sys.exit()
|
||||
|
||||
# client_auth_v3 and legacy cannot be both set
|
||||
if client_auth_v3 and legacy:
|
||||
print(
|
||||
"V3 Client authentication (--client-auth-v3) cannot be used with legacy onion services (--legacy)"
|
||||
)
|
||||
sys.exit()
|
||||
|
||||
# Re-load settings, if a custom config was passed in
|
||||
if config_filename:
|
||||
common.load_settings(config_filename)
|
||||
|
|
@ -256,9 +226,7 @@ def main(cwd=None):
|
|||
mode_settings.set("general", "public", public)
|
||||
mode_settings.set("general", "autostart_timer", autostart_timer)
|
||||
mode_settings.set("general", "autostop_timer", autostop_timer)
|
||||
mode_settings.set("general", "legacy", legacy)
|
||||
mode_settings.set("general", "client_auth", client_auth)
|
||||
mode_settings.set("general", "client_auth_v3", client_auth_v3)
|
||||
if mode == "share":
|
||||
mode_settings.set("share", "autostop_sharing", autostop_sharing)
|
||||
if mode == "receive":
|
||||
|
|
@ -379,30 +347,20 @@ def main(cwd=None):
|
|||
)
|
||||
print("")
|
||||
if mode_settings.get("general", "client_auth"):
|
||||
print(
|
||||
f"Give this address and HidServAuth line to your sender, and tell them it won't be accessible until: {schedule.strftime('%I:%M:%S%p, %b %d, %y')}"
|
||||
)
|
||||
print(app.auth_string)
|
||||
elif mode_settings.get("general", "client_auth_v3"):
|
||||
print(
|
||||
f"Give this address and ClientAuth line to your sender, and tell them it won't be accessible until: {schedule.strftime('%I:%M:%S%p, %b %d, %y')}"
|
||||
)
|
||||
print(app.auth_string_v3)
|
||||
print(f"ClientAuth: {app.auth_string}")
|
||||
else:
|
||||
print(
|
||||
f"Give this address to your sender, and tell them it won't be accessible until: {schedule.strftime('%I:%M:%S%p, %b %d, %y')}"
|
||||
)
|
||||
else:
|
||||
if mode_settings.get("general", "client_auth"):
|
||||
print(
|
||||
f"Give this address and HidServAuth line to your recipient, and tell them it won't be accessible until: {schedule.strftime('%I:%M:%S%p, %b %d, %y')}"
|
||||
)
|
||||
print(app.auth_string)
|
||||
elif mode_settings.get("general", "client_auth_v3"):
|
||||
print(
|
||||
f"Give this address and ClientAuth line to your recipient, and tell them it won't be accessible until: {schedule.strftime('%I:%M:%S%p, %b %d, %y')}"
|
||||
)
|
||||
print(app.auth_string_v3)
|
||||
print(f"ClientAuth: {app.auth_string}")
|
||||
else:
|
||||
print(
|
||||
f"Give this address to your recipient, and tell them it won't be accessible until: {schedule.strftime('%I:%M:%S%p, %b %d, %y')}"
|
||||
|
|
@ -484,25 +442,17 @@ def main(cwd=None):
|
|||
print("")
|
||||
|
||||
if mode_settings.get("general", "client_auth"):
|
||||
print("Give this address and HidServAuth to the sender:")
|
||||
print(url)
|
||||
print(app.auth_string)
|
||||
elif mode_settings.get("general", "client_auth_v3"):
|
||||
print("Give this address and ClientAuth to the sender:")
|
||||
print(url)
|
||||
print(app.auth_string_v3)
|
||||
print(f"ClientAuth: {app.auth_string}")
|
||||
else:
|
||||
print("Give this address to the sender:")
|
||||
print(url)
|
||||
else:
|
||||
if mode_settings.get("general", "client_auth"):
|
||||
print("Give this address and HidServAuth line to the recipient:")
|
||||
print(url)
|
||||
print(app.auth_string)
|
||||
elif mode_settings.get("general", "client_auth_v3"):
|
||||
print("Give this address and ClientAuth line to the recipient:")
|
||||
print(url)
|
||||
print(app.auth_string_v3)
|
||||
print(f"ClientAuth: {app.auth_string}")
|
||||
else:
|
||||
print("Give this address to the recipient:")
|
||||
print(url)
|
||||
|
|
|
|||
|
|
@ -48,9 +48,7 @@ class ModeSettings:
|
|||
"public": False,
|
||||
"autostart_timer": False,
|
||||
"autostop_timer": False,
|
||||
"legacy": False,
|
||||
"client_auth": False,
|
||||
"client_auth_v3": False,
|
||||
"service_id": None,
|
||||
},
|
||||
"share": {"autostop_sharing": True, "filenames": []},
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
from stem.control import Controller
|
||||
from stem import ProtocolError, SocketClosed
|
||||
from stem.connection import MissingPassword, UnreadableCookieFile, AuthenticationFailure
|
||||
from Crypto.PublicKey import RSA
|
||||
import base64
|
||||
import nacl.public
|
||||
import os
|
||||
|
|
@ -167,7 +166,6 @@ class Onion(object):
|
|||
|
||||
# Assigned later if we are using stealth mode
|
||||
self.auth_string = None
|
||||
self.auth_string_v3 = None
|
||||
|
||||
# Keep track of onions where it's important to gracefully close to prevent truncated downloads
|
||||
self.graceful_close_onions = []
|
||||
|
|
@ -586,22 +584,6 @@ class Onion(object):
|
|||
callable(list_ephemeral_hidden_services) and self.tor_version >= "0.2.7.1"
|
||||
)
|
||||
|
||||
# Do the versions of stem and tor that I'm using support v2 stealth onion services?
|
||||
try:
|
||||
res = self.c.create_ephemeral_hidden_service(
|
||||
{1: 1},
|
||||
basic_auth={"onionshare": None},
|
||||
await_publication=False,
|
||||
key_type="NEW",
|
||||
key_content="RSA1024",
|
||||
)
|
||||
tmp_service_id = res.service_id
|
||||
self.c.remove_ephemeral_hidden_service(tmp_service_id)
|
||||
self.supports_stealth = True
|
||||
except:
|
||||
# ephemeral stealth onion services are not supported
|
||||
self.supports_stealth = False
|
||||
|
||||
# Do the versions of stem and tor that I'm using support v3 stealth onion services?
|
||||
try:
|
||||
res = self.c.create_ephemeral_hidden_service(
|
||||
|
|
@ -614,20 +596,16 @@ class Onion(object):
|
|||
)
|
||||
tmp_service_id = res.service_id
|
||||
self.c.remove_ephemeral_hidden_service(tmp_service_id)
|
||||
self.supports_stealth_v3 = True
|
||||
self.supports_stealth = True
|
||||
except:
|
||||
# ephemeral v3 stealth onion services are not supported
|
||||
self.supports_stealth_v3 = False
|
||||
self.supports_stealth = False
|
||||
|
||||
# Does this version of Tor support next-gen ('v3') onions?
|
||||
# Note, this is the version of Tor where this bug was fixed:
|
||||
# https://trac.torproject.org/projects/tor/ticket/28619
|
||||
self.supports_v3_onions = self.tor_version >= Version("0.3.5.7")
|
||||
|
||||
# Does this version of Tor support legacy ('v2') onions?
|
||||
# v2 onions have been phased out as of Tor 0.4.6.1.
|
||||
self.supports_v2_onions = self.tor_version < Version("0.4.6.1")
|
||||
|
||||
|
||||
def is_authenticated(self):
|
||||
"""
|
||||
|
|
@ -650,85 +628,45 @@ class Onion(object):
|
|||
"Your version of Tor is too old, ephemeral onion services are not supported"
|
||||
)
|
||||
raise TorTooOldEphemeral()
|
||||
if mode_settings.get("general", "client_auth") and not self.supports_stealth:
|
||||
print(
|
||||
"Your version of Tor is too old, stealth onion services are not supported"
|
||||
)
|
||||
raise TorTooOldStealth()
|
||||
|
||||
if mode_settings.get("general", "client_auth_v3") and not self.supports_stealth_v3:
|
||||
print(
|
||||
"Your version of Tor is too old, stealth v3 onion services are not supported"
|
||||
)
|
||||
raise TorTooOldStealth()
|
||||
|
||||
auth_cookie = None
|
||||
if mode_settings.get("general", "client_auth"):
|
||||
if mode_settings.get("onion", "hidservauth_string"):
|
||||
auth_cookie = mode_settings.get("onion", "hidservauth_string").split()[
|
||||
2
|
||||
]
|
||||
if auth_cookie:
|
||||
basic_auth = {"onionshare": auth_cookie}
|
||||
else:
|
||||
# If we had neither a scheduled auth cookie or a persistent hidservauth string,
|
||||
# set the cookie to 'None', which means Tor will create one for us
|
||||
basic_auth = {"onionshare": None}
|
||||
else:
|
||||
# Not using client auth at all
|
||||
basic_auth = None
|
||||
client_auth_v3_pub_key = None
|
||||
|
||||
if mode_settings.get("onion", "private_key"):
|
||||
key_content = mode_settings.get("onion", "private_key")
|
||||
if self.is_v2_key(key_content) and self.supports_v2_onions:
|
||||
key_type = "RSA1024"
|
||||
else:
|
||||
# Assume it was a v3 key. Stem will throw an error if it's something illegible
|
||||
key_type = "ED25519-V3"
|
||||
key_type = "ED25519-V3"
|
||||
else:
|
||||
key_content = "ED25519-V3"
|
||||
key_type = "NEW"
|
||||
# Work out if we can support v3 onion services, which are preferred
|
||||
if self.supports_v3_onions and not mode_settings.get("general", "legacy") and not self.supports_v2_onions:
|
||||
key_content = "ED25519-V3"
|
||||
else:
|
||||
# fall back to v2 onion services
|
||||
key_content = "RSA1024"
|
||||
|
||||
if (
|
||||
(key_type == "ED25519-V3"
|
||||
or key_content == "ED25519-V3")
|
||||
and mode_settings.get("general", "client_auth_v3")
|
||||
):
|
||||
if key_type == "NEW" or not mode_settings.get("onion", "client_auth_v3_priv_key"):
|
||||
# Generate a new key pair for Client Auth on new onions, or if
|
||||
# it's a persistent onion but for some reason we don't them
|
||||
client_auth_v3_priv_key_raw = nacl.public.PrivateKey.generate()
|
||||
client_auth_v3_priv_key = self.key_str(client_auth_v3_priv_key_raw)
|
||||
client_auth_v3_pub_key = self.key_str(client_auth_v3_priv_key_raw.public_key)
|
||||
else:
|
||||
# These should have been saved in settings from the previous run of a persistent onion
|
||||
client_auth_v3_priv_key = mode_settings.get("onion", "client_auth_v3_priv_key")
|
||||
client_auth_v3_pub_key = mode_settings.get("onion", "client_auth_v3_pub_key")
|
||||
|
||||
self.common.log(
|
||||
"Onion", "start_onion-service", f"ClientAuthV3 private key (for Tor Browser: {client_auth_v3_priv_key}"
|
||||
)
|
||||
self.common.log(
|
||||
"Onion", "start_onion-service", f"ClientAuthV3 public key (for Onion service: {client_auth_v3_pub_key}"
|
||||
)
|
||||
# basic_auth is only for v2 onions
|
||||
basic_auth = None
|
||||
|
||||
debug_message = f"key_type={key_type}"
|
||||
if key_type == "NEW":
|
||||
debug_message += f", key_content={key_content}"
|
||||
self.common.log("Onion", "start_onion_service", debug_message)
|
||||
|
||||
if mode_settings.get("general", "client_auth"):
|
||||
if not self.supports_stealth:
|
||||
print(
|
||||
"Your version of Tor is too old, stealth onion services are not supported"
|
||||
)
|
||||
raise TorTooOldStealth()
|
||||
else:
|
||||
if key_type == "NEW" or not mode_settings.get("onion", "client_auth_v3_priv_key"):
|
||||
# Generate a new key pair for Client Auth on new onions, or if
|
||||
# it's a persistent onion but for some reason we don't them
|
||||
client_auth_v3_priv_key_raw = nacl.public.PrivateKey.generate()
|
||||
client_auth_v3_priv_key = self.key_str(client_auth_v3_priv_key_raw)
|
||||
client_auth_v3_pub_key = self.key_str(client_auth_v3_priv_key_raw.public_key)
|
||||
else:
|
||||
# These should have been saved in settings from the previous run of a persistent onion
|
||||
client_auth_v3_priv_key = mode_settings.get("onion", "client_auth_v3_priv_key")
|
||||
client_auth_v3_pub_key = mode_settings.get("onion", "client_auth_v3_pub_key")
|
||||
else:
|
||||
client_auth_v3_priv_key = None
|
||||
client_auth_v3_pub_key = None
|
||||
|
||||
try:
|
||||
res = self.c.create_ephemeral_hidden_service(
|
||||
{80: port},
|
||||
await_publication=await_publication,
|
||||
basic_auth=basic_auth,
|
||||
basic_auth=None,
|
||||
key_type=key_type,
|
||||
key_content=key_content,
|
||||
client_auth_v3=client_auth_v3_pub_key,
|
||||
|
|
@ -750,25 +688,20 @@ class Onion(object):
|
|||
# Save the private key and hidservauth string
|
||||
if not mode_settings.get("onion", "private_key"):
|
||||
mode_settings.set("onion", "private_key", res.private_key)
|
||||
if mode_settings.get("general", "client_auth") and not mode_settings.get(
|
||||
"onion", "hidservauth_string"
|
||||
):
|
||||
auth_cookie = list(res.client_auth.values())[0]
|
||||
self.auth_string = f"HidServAuth {onion_host} {auth_cookie}"
|
||||
mode_settings.set("onion", "hidservauth_string", self.auth_string)
|
||||
|
||||
# If using V3 onions and Client Auth, save both the private and public key
|
||||
# because we need to send the public key to ADD_ONION, and the private key
|
||||
# to the other user for their Tor Browser.
|
||||
if mode_settings.get("general", "client_auth_v3"):
|
||||
# because we need to send the public key to ADD_ONION (if we restart this
|
||||
# same share at a later date), and the private key to the other user for
|
||||
# their Tor Browser.
|
||||
if mode_settings.get("general", "client_auth"):
|
||||
mode_settings.set("onion", "client_auth_v3_priv_key", client_auth_v3_priv_key)
|
||||
mode_settings.set("onion", "client_auth_v3_pub_key", client_auth_v3_pub_key)
|
||||
# If we were pasting the client auth directly into the filesystem behind a Tor client,
|
||||
# it would need to be in the format below. However, let's just set the private key
|
||||
# by itself, as this can be pasted directly into Tor Browser, which is likely to
|
||||
# be the most common use case.
|
||||
# self.auth_string_v3 = f"{onion_host}:x25519:{client_auth_v3_priv_key}"
|
||||
self.auth_string_v3 = client_auth_v3_priv_key
|
||||
# self.auth_string = f"{onion_host}:x25519:{client_auth_v3_priv_key}"
|
||||
self.auth_string = client_auth_v3_priv_key
|
||||
|
||||
return onion_host
|
||||
|
||||
|
|
@ -900,15 +833,3 @@ class Onion(object):
|
|||
return ("127.0.0.1", 9150)
|
||||
else:
|
||||
return (self.settings.get("socks_address"), self.settings.get("socks_port"))
|
||||
|
||||
def is_v2_key(self, key):
|
||||
"""
|
||||
Helper function for determining if a key is RSA1024 (v2) or not.
|
||||
"""
|
||||
try:
|
||||
# Import the key
|
||||
key = RSA.importKey(base64.b64decode(key))
|
||||
# Is this a v2 Onion key? (1024 bits) If so, we should keep using it.
|
||||
return key.n.bit_length() == 1024
|
||||
except:
|
||||
return False
|
||||
|
|
|
|||
|
|
@ -83,9 +83,6 @@ class OnionShare(object):
|
|||
if mode_settings.get("general", "client_auth"):
|
||||
self.auth_string = self.onion.auth_string
|
||||
|
||||
if mode_settings.get("general", "client_auth_v3"):
|
||||
self.auth_string_v3 = self.onion.auth_string_v3
|
||||
|
||||
def stop_onion_service(self, mode_settings):
|
||||
"""
|
||||
Stop the onion service
|
||||
|
|
|
|||
42
cli/poetry.lock
generated
42
cli/poetry.lock
generated
|
|
@ -278,14 +278,6 @@ optional = false
|
|||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
version = "2.20"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Cryptographic library for Python"
|
||||
name = "pycryptodome"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
version = "3.10.1"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Python binding to the Networking and Cryptography (NaCl) library"
|
||||
|
|
@ -473,7 +465,7 @@ 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 = "ace423d1b657b80c33a6fddb308d7d2a458847cfb14630c17da256c9e50f1f1d"
|
||||
content-hash = "8c04afd6b4605961ef8da2340c99f1d3dabc790bca8b57c1bdfb3e29130dc94d"
|
||||
python-versions = "^3.6"
|
||||
|
||||
[metadata.files]
|
||||
|
|
@ -710,38 +702,6 @@ pycparser = [
|
|||
{file = "pycparser-2.20-py2.py3-none-any.whl", hash = "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"},
|
||||
{file = "pycparser-2.20.tar.gz", hash = "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0"},
|
||||
]
|
||||
pycryptodome = [
|
||||
{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"},
|
||||
]
|
||||
pynacl = [
|
||||
{file = "PyNaCl-1.4.0-cp27-cp27m-macosx_10_10_x86_64.whl", hash = "sha256:ea6841bc3a76fa4942ce00f3bda7d436fda21e2d91602b9e21b7ca9ecab8f3ff"},
|
||||
{file = "PyNaCl-1.4.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:d452a6746f0a7e11121e64625109bc4468fc3100452817001dbe018bb8b08514"},
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ flask = "*"
|
|||
flask-httpauth = "*"
|
||||
flask-socketio = "*"
|
||||
psutil = "*"
|
||||
pycryptodome = "*"
|
||||
pysocks = "*"
|
||||
requests = {extras = ["socks"], version = "^2.25.1"}
|
||||
stem = "*"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue