aboutsummaryrefslogtreecommitdiff
path: root/cli
diff options
context:
space:
mode:
authorMiguel Jacq <mig@mig5.net>2021-11-12 10:56:15 +1100
committerMiguel Jacq <mig@mig5.net>2021-11-12 10:56:15 +1100
commitdbae142a873c0bb326d0b6fa9ab3a4872280fe9b (patch)
treea2563db6480eb0d39d32ce6518147b57a5aafaa1 /cli
parent627c185fcb3c369f291b285910421d9cdcbf2f86 (diff)
parentda94b92d1807fd2126f748836c79bcbf38a4c0a4 (diff)
downloadonionshare-dbae142a873c0bb326d0b6fa9ab3a4872280fe9b.tar.gz
onionshare-dbae142a873c0bb326d0b6fa9ab3a4872280fe9b.zip
Resolve conflicts in locale
Diffstat (limited to 'cli')
-rw-r--r--cli/onionshare_cli/__init__.py32
-rw-r--r--cli/onionshare_cli/censorship.py169
-rw-r--r--cli/onionshare_cli/common.py11
-rw-r--r--cli/onionshare_cli/meek.py210
-rw-r--r--cli/onionshare_cli/onion.py108
-rw-r--r--cli/onionshare_cli/resources/torrc_template4
-rw-r--r--cli/onionshare_cli/resources/torrc_template-meek_lite_amazon2
-rw-r--r--cli/onionshare_cli/resources/torrc_template-meek_lite_azure3
-rw-r--r--cli/onionshare_cli/resources/torrc_template-obfs41
-rw-r--r--cli/onionshare_cli/resources/torrc_template-snowflake3
-rw-r--r--cli/onionshare_cli/settings.py9
-rw-r--r--cli/poetry.lock508
-rw-r--r--cli/tests/test_cli_common.py18
-rw-r--r--cli/tests/test_cli_settings.py24
14 files changed, 767 insertions, 335 deletions
diff --git a/cli/onionshare_cli/__init__.py b/cli/onionshare_cli/__init__.py
index 4041c5ea..4155a32a 100644
--- a/cli/onionshare_cli/__init__.py
+++ b/cli/onionshare_cli/__init__.py
@@ -27,13 +27,10 @@ from datetime import datetime
from datetime import timedelta
from .common import Common, CannotFindTor
+from .censorship import CensorshipCircumvention
+from .meek import Meek, MeekNotRunning
from .web import Web
-from .onion import (
- TorErrorProtocolError,
- TorTooOldEphemeral,
- TorTooOldStealth,
- Onion,
-)
+from .onion import TorErrorProtocolError, TorTooOldEphemeral, TorTooOldStealth, Onion
from .onionshare import OnionShare
from .mode_settings import ModeSettings
@@ -94,12 +91,7 @@ def main(cwd=None):
help="Filename of persistent session",
)
# General args
- parser.add_argument(
- "--title",
- metavar="TITLE",
- default=None,
- help="Set a title",
- )
+ parser.add_argument("--title", metavar="TITLE", default=None, help="Set a title")
parser.add_argument(
"--public",
action="store_true",
@@ -308,6 +300,20 @@ def main(cwd=None):
# Create the Web object
web = Web(common, False, mode_settings, mode)
+ # Create the Meek object and start the meek client
+ # meek = Meek(common)
+ # meek.start()
+
+ # Create the CensorshipCircumvention object to make
+ # API calls to Tor over Meek
+ censorship = CensorshipCircumvention(common, meek)
+ # Example: request recommended bridges, pretending to be from China, using
+ # domain fronting.
+ # censorship_recommended_settings = censorship.request_settings(country="cn")
+ # print(censorship_recommended_settings)
+ # Clean up the meek subprocess once we're done working with the censorship circumvention API
+ # meek.cleanup()
+
# Start the Onion object
try:
onion = Onion(common, use_tmp_dir=True)
@@ -424,7 +430,7 @@ def main(cwd=None):
sys.exit(1)
# Warn about sending large files over Tor
- if web.share_mode.download_filesize >= 157286400: # 150mb
+ if web.share_mode.download_filesize >= 157_286_400: # 150mb
print("")
print("Warning: Sending a large share could take hours")
print("")
diff --git a/cli/onionshare_cli/censorship.py b/cli/onionshare_cli/censorship.py
new file mode 100644
index 00000000..f84b1058
--- /dev/null
+++ b/cli/onionshare_cli/censorship.py
@@ -0,0 +1,169 @@
+# -*- coding: utf-8 -*-
+"""
+OnionShare | https://onionshare.org/
+
+Copyright (C) 2014-2021 Micah Lee, et al. <micah@micahflee.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+"""
+import requests
+
+from .meek import MeekNotRunning
+
+
+class CensorshipCircumvention(object):
+ """
+ Connect to the Tor Moat APIs to retrieve censorship
+ circumvention recommendations, over the Meek client.
+ """
+
+ def __init__(self, common, meek, domain_fronting=True):
+ """
+ Set up the CensorshipCircumvention object to hold
+ common and meek objects.
+ """
+ self.common = common
+ self.meek = meek
+ self.common.log("CensorshipCircumvention", "__init__")
+
+ # Bail out if we requested domain fronting but we can't use meek
+ if domain_fronting and not self.meek.meek_proxies:
+ raise MeekNotRunning()
+
+ def request_map(self, country=False):
+ """
+ Retrieves the Circumvention map from Tor Project and store it
+ locally for further look-ups if required.
+
+ Optionally pass a country code in order to get recommended settings
+ just for that country.
+
+ Note that this API endpoint doesn't return actual bridges,
+ it just returns the recommended bridge type countries.
+ """
+ endpoint = "https://bridges.torproject.org/moat/circumvention/map"
+ data = {}
+ if country:
+ data = {"country": country}
+
+ r = requests.post(
+ endpoint,
+ json=data,
+ headers={"Content-Type": "application/vnd.api+json"},
+ proxies=self.meek.meek_proxies,
+ )
+ if r.status_code != 200:
+ self.common.log(
+ "CensorshipCircumvention",
+ "censorship_obtain_map",
+ f"status_code={r.status_code}",
+ )
+ return False
+
+ result = r.json()
+
+ if "errors" in result:
+ self.common.log(
+ "CensorshipCircumvention",
+ "censorship_obtain_map",
+ f"errors={result['errors']}",
+ )
+ return False
+
+ return result
+
+ def request_settings(self, country=False, transports=False):
+ """
+ Retrieves the Circumvention Settings from Tor Project, which
+ will return recommended settings based on the country code of
+ the requesting IP.
+
+ Optionally, a country code can be specified in order to override
+ the IP detection.
+
+ Optionally, a list of transports can be specified in order to
+ return recommended settings for just that transport type.
+ """
+ endpoint = "https://bridges.torproject.org/moat/circumvention/settings"
+ data = {}
+ if country:
+ data = {"country": country}
+ if transports:
+ data.append({"transports": transports})
+ r = requests.post(
+ endpoint,
+ json=data,
+ headers={"Content-Type": "application/vnd.api+json"},
+ proxies=self.meek.meek_proxies,
+ )
+ if r.status_code != 200:
+ self.common.log(
+ "CensorshipCircumvention",
+ "censorship_obtain_settings",
+ f"status_code={r.status_code}",
+ )
+ return False
+
+ result = r.json()
+
+ if "errors" in result:
+ self.common.log(
+ "CensorshipCircumvention",
+ "censorship_obtain_settings",
+ f"errors={result['errors']}",
+ )
+ return False
+
+ # There are no settings - perhaps this country doesn't require censorship circumvention?
+ # This is not really an error, so we can just check if False and assume direct Tor
+ # connection will work.
+ if not "settings" in result:
+ self.common.log(
+ "CensorshipCircumvention",
+ "censorship_obtain_settings",
+ "No settings found for this country",
+ )
+ return False
+
+ return result
+
+ def request_builtin_bridges(self):
+ """
+ Retrieves the list of built-in bridges from the Tor Project.
+ """
+ endpoint = "https://bridges.torproject.org/moat/circumvention/builtin"
+ r = requests.post(
+ endpoint,
+ headers={"Content-Type": "application/vnd.api+json"},
+ proxies=self.meek.meek_proxies,
+ )
+ if r.status_code != 200:
+ self.common.log(
+ "CensorshipCircumvention",
+ "censorship_obtain_builtin_bridges",
+ f"status_code={r.status_code}",
+ )
+ return False
+
+ result = r.json()
+
+ if "errors" in result:
+ self.common.log(
+ "CensorshipCircumvention",
+ "censorship_obtain_builtin_bridges",
+ f"errors={result['errors']}",
+ )
+ return False
+
+ return result
diff --git a/cli/onionshare_cli/common.py b/cli/onionshare_cli/common.py
index dd92eb0b..bab3fd86 100644
--- a/cli/onionshare_cli/common.py
+++ b/cli/onionshare_cli/common.py
@@ -22,6 +22,7 @@ import hashlib
import os
import platform
import random
+import requests
import socket
import sys
import threading
@@ -313,6 +314,8 @@ class Common:
if not tor_path:
raise CannotFindTor()
obfs4proxy_file_path = shutil.which("obfs4proxy")
+ snowflake_file_path = shutil.which("snowflake-client")
+ meek_client_file_path = shutil.which("meek-client")
prefix = os.path.dirname(os.path.dirname(tor_path))
tor_geo_ip_file_path = os.path.join(prefix, "share/tor/geoip")
tor_geo_ipv6_file_path = os.path.join(prefix, "share/tor/geoip6")
@@ -320,6 +323,8 @@ class Common:
base_path = self.get_resource_path("tor")
tor_path = os.path.join(base_path, "Tor", "tor.exe")
obfs4proxy_file_path = os.path.join(base_path, "Tor", "obfs4proxy.exe")
+ snowflake_file_path = os.path.join(base_path, "Tor", "snowflake-client.exe")
+ meek_client_file_path = os.path.join(base_path, "Tor", "meek-client.exe")
tor_geo_ip_file_path = os.path.join(base_path, "Data", "Tor", "geoip")
tor_geo_ipv6_file_path = os.path.join(base_path, "Data", "Tor", "geoip6")
elif self.platform == "Darwin":
@@ -327,6 +332,8 @@ class Common:
if not tor_path:
raise CannotFindTor()
obfs4proxy_file_path = shutil.which("obfs4proxy")
+ snowflake_file_path = shutil.which("snowflake-client")
+ meek_client_file_path = shutil.which("meek-client")
prefix = os.path.dirname(os.path.dirname(tor_path))
tor_geo_ip_file_path = os.path.join(prefix, "share/tor/geoip")
tor_geo_ipv6_file_path = os.path.join(prefix, "share/tor/geoip6")
@@ -335,12 +342,16 @@ class Common:
tor_geo_ip_file_path = "/usr/local/share/tor/geoip"
tor_geo_ipv6_file_path = "/usr/local/share/tor/geoip6"
obfs4proxy_file_path = "/usr/local/bin/obfs4proxy"
+ snowflake_file_path = "/usr/local/bin/snowflake-client"
+ meek_client_file_path = "/usr/local/bin/meek-client"
return (
tor_path,
tor_geo_ip_file_path,
tor_geo_ipv6_file_path,
obfs4proxy_file_path,
+ snowflake_file_path,
+ meek_client_file_path,
)
def build_data_dir(self):
diff --git a/cli/onionshare_cli/meek.py b/cli/onionshare_cli/meek.py
new file mode 100644
index 00000000..c5df7b7f
--- /dev/null
+++ b/cli/onionshare_cli/meek.py
@@ -0,0 +1,210 @@
+# -*- coding: utf-8 -*-
+"""
+OnionShare | https://onionshare.org/
+
+Copyright (C) 2014-2021 Micah Lee, et al. <micah@micahflee.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+"""
+import os
+import subprocess
+import time
+from queue import Queue, Empty
+from threading import Thread
+
+
+class Meek(object):
+ """
+ The Meek object starts the meek-client as a subprocess.
+ This process is used to do domain-fronting to connect to
+ the Tor APIs for censorship circumvention and retrieving
+ bridges, before connecting to Tor.
+ """
+
+ def __init__(self, common, get_tor_paths=None):
+ """
+ Set up the Meek object
+ """
+
+ self.common = common
+ self.common.log("Meek", "__init__")
+
+ # Set the path of the meek binary
+ if not get_tor_paths:
+ get_tor_paths = self.common.get_tor_paths
+ (
+ self.tor_path,
+ self.tor_geo_ip_file_path,
+ self.tor_geo_ipv6_file_path,
+ self.obfs4proxy_file_path,
+ self.snowflake_file_path,
+ self.meek_client_file_path,
+ ) = get_tor_paths()
+
+ self.meek_proxies = {}
+ self.meek_url = "https://moat.torproject.org.global.prod.fastly.net/"
+ self.meek_front = "cdn.sstatic.net"
+ self.meek_env = {
+ "TOR_PT_MANAGED_TRANSPORT_VER": "1",
+ "TOR_PT_CLIENT_TRANSPORTS": "meek",
+ }
+ self.meek_host = "127.0.0.1"
+ self.meek_port = None
+
+ def start(self):
+ """
+ Start the Meek Client and populate the SOCKS proxies dict
+ for use with requests to the Tor Moat API.
+ """
+ # Small method to read stdout from the subprocess.
+ # We use this to obtain the random port that Meek
+ # started on
+ def enqueue_output(out, queue):
+ for line in iter(out.readline, b""):
+ queue.put(line)
+ out.close()
+
+ # Abort early if we can't find the Meek client
+ if self.meek_client_file_path is None or not os.path.exists(
+ self.meek_client_file_path
+ ):
+ raise MeekNotFound()
+
+ # Start the Meek Client as a subprocess.
+ self.common.log("Meek", "start", "Starting meek client")
+
+ if self.common.platform == "Windows":
+ env = os.environ.copy()
+ for key in self.meek_env:
+ env[key] = self.meek_env[key]
+
+ # In Windows, hide console window when opening meek-client.exe subprocess
+ startupinfo = subprocess.STARTUPINFO()
+ startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
+ self.meek_proc = subprocess.Popen(
+ [
+ self.meek_client_file_path,
+ "--url",
+ self.meek_url,
+ "--front",
+ self.meek_front,
+ ],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ startupinfo=startupinfo,
+ bufsize=1,
+ env=env,
+ text=True,
+ )
+ else:
+ self.meek_proc = subprocess.Popen(
+ [
+ self.meek_client_file_path,
+ "--url",
+ self.meek_url,
+ "--front",
+ self.meek_front,
+ ],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ bufsize=1,
+ env=self.meek_env,
+ text=True,
+ )
+
+ # Queue up the stdout from the subprocess for polling later
+ q = Queue()
+ t = Thread(target=enqueue_output, args=(self.meek_proc.stdout, q))
+ t.daemon = True # thread dies with the program
+ t.start()
+
+ while True:
+ # read stdout without blocking
+ try:
+ line = q.get_nowait()
+ self.common.log("Meek", "start", line.strip())
+ except Empty:
+ # no stdout yet?
+ pass
+ else: # we got stdout
+ if "CMETHOD meek socks5" in line:
+ self.meek_host = line.split(" ")[3].split(":")[0]
+ self.meek_port = line.split(" ")[3].split(":")[1]
+ self.common.log(
+ "Meek",
+ "start",
+ f"Meek running on {self.meek_host}:{self.meek_port}",
+ )
+ break
+
+ if "CMETHOD-ERROR" in line:
+ self.cleanup()
+ raise MeekNotRunning()
+
+ if self.meek_port:
+ self.meek_proxies = {
+ "http": f"socks5h://{self.meek_host}:{self.meek_port}",
+ "https": f"socks5h://{self.meek_host}:{self.meek_port}",
+ }
+ else:
+ self.common.log("Meek", "start", "Could not obtain the meek port")
+ self.cleanup()
+ raise MeekNotRunning()
+
+ def cleanup(self):
+ """
+ Kill any meek subprocesses.
+ """
+ self.common.log("Meek", "cleanup")
+
+ if self.meek_proc:
+ self.meek_proc.terminate()
+ time.sleep(0.2)
+ if self.meek_proc.poll() is None:
+ self.common.log(
+ "Meek",
+ "cleanup",
+ "Tried to terminate meek-client process but it's still running",
+ )
+ try:
+ self.meek_proc.kill()
+ time.sleep(0.2)
+ if self.meek_proc.poll() is None:
+ self.common.log(
+ "Meek",
+ "cleanup",
+ "Tried to kill meek-client process but it's still running",
+ )
+ except Exception:
+ self.common.log(
+ "Meek", "cleanup", "Exception while killing meek-client process"
+ )
+ self.meek_proc = None
+
+ # Reset other Meek settings
+ self.meek_proxies = {}
+ self.meek_port = None
+
+
+class MeekNotRunning(Exception):
+ """
+ We were unable to start Meek or obtain the port
+ number it started on, in order to do domain fronting.
+ """
+
+
+class MeekNotFound(Exception):
+ """
+ We were unable to find the Meek Client binary.
+ """
diff --git a/cli/onionshare_cli/onion.py b/cli/onionshare_cli/onion.py
index 7f6faa17..536b9ba0 100644
--- a/cli/onionshare_cli/onion.py
+++ b/cli/onionshare_cli/onion.py
@@ -153,6 +153,8 @@ class Onion(object):
self.tor_geo_ip_file_path,
self.tor_geo_ipv6_file_path,
self.obfs4proxy_file_path,
+ self.snowflake_file_path,
+ self.meek_client_file_path,
) = get_tor_paths()
# The tor process
@@ -178,10 +180,10 @@ class Onion(object):
key_bytes = bytes(key)
key_b32 = base64.b32encode(key_bytes)
# strip trailing ====
- assert key_b32[-4:] == b'===='
+ assert key_b32[-4:] == b"===="
key_b32 = key_b32[:-4]
# change from b'ASDF' to ASDF
- s = key_b32.decode('utf-8')
+ s = key_b32.decode("utf-8")
return s
def connect(
@@ -198,8 +200,6 @@ class Onion(object):
)
return
- self.common.log("Onion", "connect")
-
# Either use settings that are passed in, or use them from common
if custom_settings:
self.settings = custom_settings
@@ -210,6 +210,12 @@ class Onion(object):
self.common.load_settings()
self.settings = self.common.settings
+ self.common.log(
+ "Onion",
+ "connect",
+ f"connection_type={self.settings.get('connection_type')}",
+ )
+
# The Tor controller
self.c = None
@@ -302,43 +308,50 @@ class Onion(object):
torrc_template = torrc_template.replace(
"{{socks_port}}", str(self.tor_socks_port)
)
+ torrc_template = torrc_template.replace(
+ "{{obfs4proxy_path}}", str(self.obfs4proxy_file_path)
+ )
+ torrc_template = torrc_template.replace(
+ "{{snowflake_path}}", str(self.snowflake_file_path)
+ )
with open(self.tor_torrc, "w") as f:
f.write(torrc_template)
# Bridge support
- if self.settings.get("tor_bridges_use_obfs4"):
- f.write(
- f"ClientTransportPlugin obfs4 exec {self.obfs4proxy_file_path}\n"
- )
- with open(
- self.common.get_resource_path("torrc_template-obfs4")
- ) as o:
- for line in o:
- f.write(line)
- elif self.settings.get("tor_bridges_use_meek_lite_azure"):
- f.write(
- f"ClientTransportPlugin meek_lite exec {self.obfs4proxy_file_path}\n"
- )
- with open(
- self.common.get_resource_path("torrc_template-meek_lite_azure")
- ) as o:
- for line in o:
- f.write(line)
-
- if self.settings.get("tor_bridges_use_custom_bridges"):
- if "obfs4" in self.settings.get("tor_bridges_use_custom_bridges"):
- f.write(
- f"ClientTransportPlugin obfs4 exec {self.obfs4proxy_file_path}\n"
- )
- elif "meek_lite" in self.settings.get(
- "tor_bridges_use_custom_bridges"
- ):
- f.write(
- f"ClientTransportPlugin meek_lite exec {self.obfs4proxy_file_path}\n"
- )
- f.write(self.settings.get("tor_bridges_use_custom_bridges"))
- f.write("\nUseBridges 1")
+ if self.settings.get("bridges_enabled"):
+ if self.settings.get("bridges_type") == "built-in":
+ if self.settings.get("bridges_builtin_pt") == "obfs4":
+ with open(
+ self.common.get_resource_path("torrc_template-obfs4")
+ ) as o:
+ f.write(o.read())
+ elif self.settings.get("bridges_builtin_pt") == "meek-azure":
+ with open(
+ self.common.get_resource_path(
+ "torrc_template-meek_lite_azure"
+ )
+ ) as o:
+ f.write(o.read())
+ elif self.settings.get("bridges_builtin_pt") == "snowflake":
+ with open(
+ self.common.get_resource_path(
+ "torrc_template-snowflake"
+ )
+ ) as o:
+ f.write(o.read())
+
+ elif self.settings.get("bridges_type") == "moat":
+ for line in self.settings.get("bridges_moat").split("\n"):
+ if line.strip() != "":
+ f.write(f"Bridge {line}\n")
+ f.write("\nUseBridges 1\n")
+
+ elif self.settings.get("bridges_type") == "custom":
+ for line in self.settings.get("bridges_custom").split("\n"):
+ if line.strip() != "":
+ f.write(f"Bridge {line}\n")
+ f.write("\nUseBridges 1\n")
# Execute a tor subprocess
start_ts = time.time()
@@ -357,6 +370,7 @@ class Onion(object):
[self.tor_path, "-f", self.tor_torrc],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
+ env={"LD_LIBRARY_PATH": os.path.dirname(self.tor_path)},
)
# Wait for the tor controller to start
@@ -410,11 +424,7 @@ class Onion(object):
time.sleep(0.2)
# If using bridges, it might take a bit longer to connect to Tor
- if (
- self.settings.get("tor_bridges_use_custom_bridges")
- or self.settings.get("tor_bridges_use_obfs4")
- or self.settings.get("tor_bridges_use_meek_lite_azure")
- ):
+ if self.settings.get("bridges_enabled"):
# Only override timeout if a custom timeout has not been passed in
if connect_timeout == 120:
connect_timeout = 150
@@ -650,16 +660,24 @@ class Onion(object):
)
raise TorTooOldStealth()
else:
- if key_type == "NEW" or not mode_settings.get("onion", "client_auth_priv_key"):
+ if key_type == "NEW" or not mode_settings.get(
+ "onion", "client_auth_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_priv_key_raw = nacl.public.PrivateKey.generate()
client_auth_priv_key = self.key_str(client_auth_priv_key_raw)
- client_auth_pub_key = self.key_str(client_auth_priv_key_raw.public_key)
+ client_auth_pub_key = self.key_str(
+ client_auth_priv_key_raw.public_key
+ )
else:
# These should have been saved in settings from the previous run of a persistent onion
- client_auth_priv_key = mode_settings.get("onion", "client_auth_priv_key")
- client_auth_pub_key = mode_settings.get("onion", "client_auth_pub_key")
+ client_auth_priv_key = mode_settings.get(
+ "onion", "client_auth_priv_key"
+ )
+ client_auth_pub_key = mode_settings.get(
+ "onion", "client_auth_pub_key"
+ )
try:
if not self.supports_stealth:
diff --git a/cli/onionshare_cli/resources/torrc_template b/cli/onionshare_cli/resources/torrc_template
index 8ac9e1ef..70e1cb35 100644
--- a/cli/onionshare_cli/resources/torrc_template
+++ b/cli/onionshare_cli/resources/torrc_template
@@ -6,3 +6,7 @@ AvoidDiskWrites 1
Log notice stdout
GeoIPFile {{geo_ip_file}}
GeoIPv6File {{geo_ipv6_file}}
+
+# Bridge configurations
+ClientTransportPlugin meek_lite,obfs2,obfs3,obfs4,scramblesuit exec {{obfs4proxy_path}}
+ClientTransportPlugin snowflake exec {{snowflake_path}} -url https://snowflake-broker.torproject.net.global.prod.fastly.net/ -front cdn.sstatic.net -ice stun:stun.l.google.com:19302,stun:stun.voip.blackberry.com:3478,stun:stun.altar.com.pl:3478,stun:stun.antisip.com:3478,stun:stun.bluesip.net:3478,stun:stun.dus.net:3478,stun:stun.epygi.com:3478,stun:stun.sonetel.com:3478,stun:stun.sonetel.net:3478,stun:stun.stunprotocol.org:3478,stun:stun.uls.co.za:3478,stun:stun.voipgate.com:3478,stun:stun.voys.nl:3478
diff --git a/cli/onionshare_cli/resources/torrc_template-meek_lite_amazon b/cli/onionshare_cli/resources/torrc_template-meek_lite_amazon
deleted file mode 100644
index 606ae889..00000000
--- a/cli/onionshare_cli/resources/torrc_template-meek_lite_amazon
+++ /dev/null
@@ -1,2 +0,0 @@
-Bridge meek_lite 0.0.2.0:2 B9E7141C594AF25699E0079C1F0146F409495296 url=https://d2cly7j4zqgua7.cloudfront.net/ front=a0.awsstatic.com
-UseBridges 1 \ No newline at end of file
diff --git a/cli/onionshare_cli/resources/torrc_template-meek_lite_azure b/cli/onionshare_cli/resources/torrc_template-meek_lite_azure
index a9b374ba..6f601681 100644
--- a/cli/onionshare_cli/resources/torrc_template-meek_lite_azure
+++ b/cli/onionshare_cli/resources/torrc_template-meek_lite_azure
@@ -1,2 +1,3 @@
+# Enable built-in meek-azure bridge
Bridge meek_lite 0.0.2.0:3 97700DFE9F483596DDA6264C4D7DF7641E1E39CE url=https://meek.azureedge.net/ front=ajax.aspnetcdn.com
-UseBridges 1 \ No newline at end of file
+UseBridges 1
diff --git a/cli/onionshare_cli/resources/torrc_template-obfs4 b/cli/onionshare_cli/resources/torrc_template-obfs4
index 8c52a011..720cc28c 100644
--- a/cli/onionshare_cli/resources/torrc_template-obfs4
+++ b/cli/onionshare_cli/resources/torrc_template-obfs4
@@ -1,3 +1,4 @@
+# Enable built-in obfs4-bridge
Bridge obfs4 192.95.36.142:443 CDF2E852BF539B82BD10E27E9115A31734E378C2 cert=qUVQ0srL1JI/vO6V6m/24anYXiJD3QP2HgzUKQtQ7GRqqUvs7P+tG43RtAqdhLOALP7DJQ iat-mode=1
Bridge obfs4 38.229.1.78:80 C8CBDB2464FC9804A69531437BCF2BE31FDD2EE4 cert=Hmyfd2ev46gGY7NoVxA9ngrPF2zCZtzskRTzoWXbxNkzeVnGFPWmrTtILRyqCTjHR+s9dg iat-mode=1
Bridge obfs4 38.229.33.83:80 0BAC39417268B96B9F514E7F63FA6FBA1A788955 cert=VwEFpk9F/UN9JED7XpG1XOjm/O8ZCXK80oPecgWnNDZDv5pdkhq1OpbAH0wNqOT6H6BmRQ iat-mode=1
diff --git a/cli/onionshare_cli/resources/torrc_template-snowflake b/cli/onionshare_cli/resources/torrc_template-snowflake
new file mode 100644
index 00000000..4100d3be
--- /dev/null
+++ b/cli/onionshare_cli/resources/torrc_template-snowflake
@@ -0,0 +1,3 @@
+# Enable built-in snowflake bridge
+Bridge snowflake 192.0.2.3:1 2B280B23E1107BB62ABFC40DDCC8824814F80A72
+UseBridges 1
diff --git a/cli/onionshare_cli/settings.py b/cli/onionshare_cli/settings.py
index 4755d5b3..c7d74a70 100644
--- a/cli/onionshare_cli/settings.py
+++ b/cli/onionshare_cli/settings.py
@@ -105,10 +105,11 @@ class Settings(object):
"auth_password": "",
"use_autoupdate": True,
"autoupdate_timestamp": None,
- "no_bridges": True,
- "tor_bridges_use_obfs4": False,
- "tor_bridges_use_meek_lite_azure": False,
- "tor_bridges_use_custom_bridges": "",
+ "bridges_enabled": False,
+ "bridges_type": "built-in", # "built-in", "moat", or "custom"
+ "bridges_builtin_pt": "obfs4", # "obfs4", "meek-azure", or "snowflake"
+ "bridges_moat": "",
+ "bridges_custom": "",
"persistent_tabs": [],
"locale": None, # this gets defined in fill_in_defaults()
"theme": 0,
diff --git a/cli/poetry.lock b/cli/poetry.lock
index c51e1d62..9314b096 100644
--- a/cli/poetry.lock
+++ b/cli/poetry.lock
@@ -1,122 +1,120 @@
[[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 = "21.2.0"
+description = "Classes Without Boilerplate"
+category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
-version = "21.2.0"
[package.extras]
-dev = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit"]
+dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit"]
docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"]
-tests = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"]
-tests_no_zope = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"]
+tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"]
+tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"]
[[package]]
-category = "main"
-description = "The bidirectional mapping library for Python."
name = "bidict"
+version = "0.21.3"
+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)"]
-dev = ["setuptools-scm", "hypothesis (<6)", "py (<2)", "pytest (<7)", "pytest-benchmark (>=3.2.0,<4)", "sortedcollections (<2)", "sortedcontainers (<3)", "Sphinx (<4)", "sphinx-autodoc-typehints (<2)", "coverage (<6)", "pytest-cov (<3)", "pre-commit (<3)", "tox (<4)"]
-docs = ["Sphinx (<4)", "sphinx-autodoc-typehints (<2)"]
-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 = "2021.10.8"
+description = "Python package for providing Mozilla's CA Bundle."
+category = "main"
optional = false
python-versions = "*"
-version = "2021.5.30"
[[package]]
-category = "main"
-description = "Foreign Function Interface for Python calling C code."
name = "cffi"
+version = "1.14.6"
+description = "Foreign Function Interface for Python calling C code."
+category = "main"
optional = false
python-versions = "*"
-version = "1.14.6"
[package.dependencies]
pycparser = "*"
[[package]]
+name = "charset-normalizer"
+version = "2.0.7"
+description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
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"
+python-versions = ">=3.5.0"
+
+[package.extras]
+unicode_backport = ["unicodedata2"]
[[package]]
-category = "main"
-description = "Composable command line interface toolkit"
name = "click"
+version = "7.1.2"
+description = "Composable command line interface toolkit"
+category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
-version = "7.1.2"
[[package]]
-category = "main"
-description = "Cross-platform colored terminal text."
name = "colorama"
+version = "0.4.4"
+description = "Cross-platform colored terminal text."
+category = "main"
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 = "2.1.0"
+description = "DNS toolkit"
+category = "main"
optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-version = "1.16.0"
+python-versions = ">=3.6"
[package.extras]
-DNSSEC = ["pycryptodome", "ecdsa (>=0.13)"]
-IDNA = ["idna (>=2.1)"]
+dnssec = ["cryptography (>=2.6)"]
+doh = ["requests", "requests-toolbelt"]
+idna = ["idna (>=2.1)"]
+curio = ["curio (>=1.2)", "sniffio (>=1.1)"]
+trio = ["trio (>=0.14.0)", "sniffio (>=1.1)"]
[[package]]
-category = "main"
-description = "Highly concurrent networking library"
name = "eventlet"
+version = "0.32.0"
+description = "Highly concurrent networking library"
+category = "main"
optional = false
python-versions = "*"
-version = "0.31.0"
[package.dependencies]
-dnspython = ">=1.15.0,<2.0.0"
+dnspython = ">=1.15.0"
greenlet = ">=0.3"
six = ">=1.10.0"
[[package]]
-category = "main"
-description = "A simple framework for building complex web applications."
name = "flask"
+version = "1.1.4"
+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.4"
[package.dependencies]
-Jinja2 = ">=2.10.1,<3.0"
-Werkzeug = ">=0.15,<2.0"
click = ">=5.1,<8.0"
itsdangerous = ">=0.24,<2.0"
+Jinja2 = ">=2.10.1,<3.0"
+Werkzeug = ">=0.15,<2.0"
[package.extras]
dev = ["pytest", "coverage", "tox", "sphinx", "pallets-sphinx-themes", "sphinxcontrib-log-cabinet", "sphinx-issues"]
@@ -124,79 +122,76 @@ docs = ["sphinx", "pallets-sphinx-themes", "sphinxcontrib-log-cabinet", "sphinx-
dotenv = ["python-dotenv"]
[[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.1.2"
+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.1.0"
[package.extras]
docs = ["sphinx"]
[[package]]
-category = "main"
-description = "Internationalized Domain Names in Applications (IDNA)"
name = "idna"
+version = "3.2"
+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"
+python-versions = ">=3.5"
[[package]]
-category = "dev"
-description = "Read metadata from Python packages"
-marker = "python_version < \"3.8\""
name = "importlib-metadata"
+version = "4.8.1"
+description = "Read metadata from Python packages"
+category = "dev"
optional = false
python-versions = ">=3.6"
-version = "4.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 (>=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)"]
+perf = ["ipython"]
+testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "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.3"
[package.dependencies]
MarkupSafe = ">=0.23"
@@ -205,74 +200,73 @@ MarkupSafe = ">=0.23"
i18n = ["Babel (>=0.8)"]
[[package]]
-category = "main"
-description = "Safely add untrusted strings to HTML/XML markup."
name = "markupsafe"
+version = "2.0.1"
+description = "Safely add untrusted strings to HTML/XML markup."
+category = "main"
optional = false
python-versions = ">=3.6"
-version = "2.0.1"
[[package]]
-category = "dev"
-description = "Core utilities for Python packages"
name = "packaging"
+version = "21.0"
+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"
+python-versions = ">=3.6"
[package.dependencies]
pyparsing = ">=2.0.2"
[[package]]
-category = "dev"
-description = "plugin and hook calling mechanisms for python"
name = "pluggy"
+version = "1.0.0"
+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"
+python-versions = ">=3.6"
[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"]
+testing = ["pytest", "pytest-benchmark"]
[[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 = "C parser in Python"
name = "pycparser"
+version = "2.20"
+description = "C parser in Python"
+category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-version = "2.20"
[[package]]
-category = "main"
-description = "Python binding to the Networking and Cryptography (NaCl) library"
name = "pynacl"
+version = "1.4.0"
+description = "Python binding to the Networking and Cryptography (NaCl) library"
+category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-version = "1.4.0"
[package.dependencies]
cffi = ">=1.4.1"
@@ -280,186 +274,181 @@ six = "*"
[package.extras]
docs = ["sphinx (>=1.6.5)", "sphinx-rtd-theme"]
-tests = ["pytest (>=3.2.1,<3.3.0 || >3.3.0)", "hypothesis (>=3.27.0)"]
+tests = ["pytest (>=3.2.1,!=3.3.0)", "hypothesis (>=3.27.0)"]
[[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.5"
+description = "pytest: simple powerful testing with Python"
+category = "dev"
optional = false
python-versions = ">=3.6"
-version = "6.2.4"
[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"
+pluggy = ">=0.12,<2.0"
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.2.1"
+description = "Engine.IO server and client for Python"
+category = "main"
optional = false
-python-versions = "*"
-version = "4.2.0"
+python-versions = ">=3.6"
[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.4.0"
+description = "Socket.IO server and client for Python"
+category = "main"
optional = false
-python-versions = "*"
-version = "5.3.0"
+python-versions = ">=3.6"
[package.dependencies]
bidict = ">=0.21.0"
python-engineio = ">=4.1.0"
[package.extras]
-asyncio_client = ["aiohttp (>=3.4)", "websockets (>=7.0)"]
+asyncio_client = ["aiohttp (>=3.4)"]
client = ["requests (>=2.21.0)", "websocket-client (>=0.54.0)"]
[[package]]
-category = "main"
-description = "Python HTTP for Humans."
name = "requests"
+version = "2.26.0"
+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"
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
[package.dependencies]
certifi = ">=2017.4.17"
-chardet = ">=3.0.2,<5"
-idna = ">=2.5,<3"
+charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""}
+idna = {version = ">=2.5,<4", markers = "python_version >= \"3\""}
+PySocks = {version = ">=1.5.6,<1.5.7 || >1.5.7", optional = true, markers = "extra == \"socks\""}
urllib3 = ">=1.21.1,<1.27"
-[package.dependencies.PySocks]
-optional = true
-version = ">=1.5.6,<1.5.7 || >1.5.7"
-
[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"]
+use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"]
[[package]]
-category = "main"
-description = "Python 2 and 3 compatibility utilities"
name = "six"
+version = "1.16.0"
+description = "Python 2 and 3 compatibility utilities"
+category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
-version = "1.16.0"
[[package]]
-category = "main"
-description = ""
name = "stem"
+version = "1.8.1"
+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.1"
+develop = false
[package.source]
-reference = "de3d03a03c7ee57c74c80e9c63cb88072d833717"
type = "git"
url = "https://github.com/onionshare/stem.git"
+reference = "1.8.1"
+resolved_reference = "de3d03a03c7ee57c74c80e9c63cb88072d833717"
[[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.10.0.2"
+description = "Backported and Experimental Type Hints for Python 3.5+"
+category = "dev"
optional = false
python-versions = "*"
-version = "3.10.0.0"
[[package]]
-category = "main"
-description = "ASCII transliterations of Unicode text"
name = "unidecode"
+version = "1.3.2"
+description = "ASCII transliterations of Unicode text"
+category = "main"
optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-version = "1.2.0"
+python-versions = ">=3.5"
[[package]]
-category = "main"
-description = "HTTP library with thread-safe connection pooling, file post, and more."
name = "urllib3"
+version = "1.26.7"
+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.5"
[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)"]
[[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.6.0"
+description = "Backport of pathlib-compatible object wrapper for zip files"
+category = "dev"
optional = false
python-versions = ">=3.6"
-version = "3.4.1"
[package.extras]
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"]
+testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"]
[metadata]
-content-hash = "181891640e59dac730905019444d42ef8e99da0c34c96fb8a616781661bae537"
+lock-version = "1.1"
python-versions = "^3.6"
+content-hash = "181891640e59dac730905019444d42ef8e99da0c34c96fb8a616781661bae537"
[metadata.files]
atomicwrites = [
@@ -471,12 +460,12 @@ attrs = [
{file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"},
]
bidict = [
- {file = "bidict-0.21.2-py2.py3-none-any.whl", hash = "sha256:929d056e8d0d9b17ceda20ba5b24ac388e2a4d39802b87f9f4d3f45ecba070bf"},
- {file = "bidict-0.21.2.tar.gz", hash = "sha256:4fa46f7ff96dc244abfc437383d987404ae861df797e2fd5b190e233c302be09"},
+ {file = "bidict-0.21.3-py3-none-any.whl", hash = "sha256:2cce0d01eb3db9b3fa85db501c00aaa3389ee4cab7ef82178604552dfa943a1b"},
+ {file = "bidict-0.21.3.tar.gz", hash = "sha256:d50bd81fae75e34198ffc94979a0eb0939ff9adb3ef32bcc93a913d8b3e3ed1d"},
]
certifi = [
- {file = "certifi-2021.5.30-py2.py3-none-any.whl", hash = "sha256:50b1e4f8446b06f41be7dd6338db18e0990601dce795c2b1686458aa7e8fa7d8"},
- {file = "certifi-2021.5.30.tar.gz", hash = "sha256:2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee"},
+ {file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"},
+ {file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"},
]
cffi = [
{file = "cffi-1.14.6-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:22b9c3c320171c108e903d61a3723b51e37aaa8c81255b5e7ce102775bd01e2c"},
@@ -525,9 +514,9 @@ cffi = [
{file = "cffi-1.14.6-cp39-cp39-win_amd64.whl", hash = "sha256:818014c754cd3dba7229c0f5884396264d51ffb87ec86e927ef0be140bfdb0d2"},
{file = "cffi-1.14.6.tar.gz", hash = "sha256:c9a875ce9d7fe32887784274dd533c57909b7b1dcadcc128a2ac21331a9765dd"},
]
-chardet = [
- {file = "chardet-4.0.0-py2.py3-none-any.whl", hash = "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"},
- {file = "chardet-4.0.0.tar.gz", hash = "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa"},
+charset-normalizer = [
+ {file = "charset-normalizer-2.0.7.tar.gz", hash = "sha256:e019de665e2bcf9c2b64e2e5aa025fa991da8720daa3c1138cadd2fd1856aed0"},
+ {file = "charset_normalizer-2.0.7-py3-none-any.whl", hash = "sha256:f7af805c321bfa1ce6714c51f254e0d5bb5e5834039bc17db7ebe3a4cec9492b"},
]
click = [
{file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"},
@@ -538,12 +527,12 @@ colorama = [
{file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"},
]
dnspython = [
- {file = "dnspython-1.16.0-py2.py3-none-any.whl", hash = "sha256:f69c21288a962f4da86e56c4905b49d11aba7938d3d740e80d9e366ee4f1632d"},
- {file = "dnspython-1.16.0.zip", hash = "sha256:36c5e8e38d4369a08b6780b7f27d790a292b2b08eea01607865bf0936c558e01"},
+ {file = "dnspython-2.1.0-py3-none-any.whl", hash = "sha256:95d12f6ef0317118d2a1a6fc49aac65ffec7eb8087474158f42f26a639135216"},
+ {file = "dnspython-2.1.0.zip", hash = "sha256:e4a87f0b573201a0f3727fa18a516b055fd1107e0e5477cded4a2de497df1dd4"},
]
eventlet = [
- {file = "eventlet-0.31.0-py2.py3-none-any.whl", hash = "sha256:27ae41fad9deed9bbf4166f3e3b65acc15d524d42210a518e5877da85a6b8c5d"},
- {file = "eventlet-0.31.0.tar.gz", hash = "sha256:b36ec2ecc003de87fc87b93197d77fea528aa0f9204a34fdf3b2f8d0f01e017b"},
+ {file = "eventlet-0.32.0-py2.py3-none-any.whl", hash = "sha256:a3a67b02f336e97a1894b277bc33b695831525758781eb024f4da00e75ce5e25"},
+ {file = "eventlet-0.32.0.tar.gz", hash = "sha256:2f0bb8ed0dc0ab21d683975d5d8ab3c054d588ce61def9faf7a465ee363e839b"},
]
flask = [
{file = "Flask-1.1.4-py2.py3-none-any.whl", hash = "sha256:c34f04500f2cbbea882b1acb02002ad6fe6b7ffa64a6164577995657f50aed22"},
@@ -554,63 +543,64 @@ flask-socketio = [
{file = "Flask_SocketIO-5.0.1-py2.py3-none-any.whl", hash = "sha256:5d9a4438bafd806c5a3b832e74b69758781a8ee26fb6c9b1dbdda9b4fced432e"},
]
greenlet = [
- {file = "greenlet-1.1.0-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:60848099b76467ef09b62b0f4512e7e6f0a2c977357a036de602b653667f5f4c"},
- {file = "greenlet-1.1.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:f42ad188466d946f1b3afc0a9e1a266ac8926461ee0786c06baac6bd71f8a6f3"},
- {file = "greenlet-1.1.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:76ed710b4e953fc31c663b079d317c18f40235ba2e3d55f70ff80794f7b57922"},
- {file = "greenlet-1.1.0-cp27-cp27m-win32.whl", hash = "sha256:b33b51ab057f8a20b497ffafdb1e79256db0c03ef4f5e3d52e7497200e11f821"},
- {file = "greenlet-1.1.0-cp27-cp27m-win_amd64.whl", hash = "sha256:ed1377feed808c9c1139bdb6a61bcbf030c236dd288d6fca71ac26906ab03ba6"},
- {file = "greenlet-1.1.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:da862b8f7de577bc421323714f63276acb2f759ab8c5e33335509f0b89e06b8f"},
- {file = "greenlet-1.1.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:5f75e7f237428755d00e7460239a2482fa7e3970db56c8935bd60da3f0733e56"},
- {file = "greenlet-1.1.0-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:258f9612aba0d06785143ee1cbf2d7361801c95489c0bd10c69d163ec5254a16"},
- {file = "greenlet-1.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d928e2e3c3906e0a29b43dc26d9b3d6e36921eee276786c4e7ad9ff5665c78a"},
- {file = "greenlet-1.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cc407b68e0a874e7ece60f6639df46309376882152345508be94da608cc0b831"},
- {file = "greenlet-1.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c557c809eeee215b87e8a7cbfb2d783fb5598a78342c29ade561440abae7d22"},
- {file = "greenlet-1.1.0-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:3d13da093d44dee7535b91049e44dd2b5540c2a0e15df168404d3dd2626e0ec5"},
- {file = "greenlet-1.1.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:b3090631fecdf7e983d183d0fad7ea72cfb12fa9212461a9b708ff7907ffff47"},
- {file = "greenlet-1.1.0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:06ecb43b04480e6bafc45cb1b4b67c785e183ce12c079473359e04a709333b08"},
- {file = "greenlet-1.1.0-cp35-cp35m-win32.whl", hash = "sha256:944fbdd540712d5377a8795c840a97ff71e7f3221d3fddc98769a15a87b36131"},
- {file = "greenlet-1.1.0-cp35-cp35m-win_amd64.whl", hash = "sha256:c767458511a59f6f597bfb0032a1c82a52c29ae228c2c0a6865cfeaeaac4c5f5"},
- {file = "greenlet-1.1.0-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:2325123ff3a8ecc10ca76f062445efef13b6cf5a23389e2df3c02a4a527b89bc"},
- {file = "greenlet-1.1.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:598bcfd841e0b1d88e32e6a5ea48348a2c726461b05ff057c1b8692be9443c6e"},
- {file = "greenlet-1.1.0-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:be9768e56f92d1d7cd94185bab5856f3c5589a50d221c166cc2ad5eb134bd1dc"},
- {file = "greenlet-1.1.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dfe7eac0d253915116ed0cd160a15a88981a1d194c1ef151e862a5c7d2f853d3"},
- {file = "greenlet-1.1.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a6b035aa2c5fcf3dbbf0e3a8a5bc75286fc2d4e6f9cfa738788b433ec894919"},
- {file = "greenlet-1.1.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca1c4a569232c063615f9e70ff9a1e2fee8c66a6fb5caf0f5e8b21a396deec3e"},
- {file = "greenlet-1.1.0-cp36-cp36m-win32.whl", hash = "sha256:3096286a6072553b5dbd5efbefc22297e9d06a05ac14ba017233fedaed7584a8"},
- {file = "greenlet-1.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:c35872b2916ab5a240d52a94314c963476c989814ba9b519bc842e5b61b464bb"},
- {file = "greenlet-1.1.0-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:b97c9a144bbeec7039cca44df117efcbeed7209543f5695201cacf05ba3b5857"},
- {file = "greenlet-1.1.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:16183fa53bc1a037c38d75fdc59d6208181fa28024a12a7f64bb0884434c91ea"},
- {file = "greenlet-1.1.0-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:6b1d08f2e7f2048d77343279c4d4faa7aef168b3e36039cba1917fffb781a8ed"},
- {file = "greenlet-1.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14927b15c953f8f2d2a8dffa224aa78d7759ef95284d4c39e1745cf36e8cdd2c"},
- {file = "greenlet-1.1.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9bdcff4b9051fb1aa4bba4fceff6a5f770c6be436408efd99b76fc827f2a9319"},
- {file = "greenlet-1.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c70c7dd733a4c56838d1f1781e769081a25fade879510c5b5f0df76956abfa05"},
- {file = "greenlet-1.1.0-cp37-cp37m-win32.whl", hash = "sha256:0de64d419b1cb1bfd4ea544bedea4b535ef3ae1e150b0f2609da14bbf48a4a5f"},
- {file = "greenlet-1.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:8833e27949ea32d27f7e96930fa29404dd4f2feb13cce483daf52e8842ec246a"},
- {file = "greenlet-1.1.0-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:c1580087ab493c6b43e66f2bdd165d9e3c1e86ef83f6c2c44a29f2869d2c5bd5"},
- {file = "greenlet-1.1.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:ad80bb338cf9f8129c049837a42a43451fc7c8b57ad56f8e6d32e7697b115505"},
- {file = "greenlet-1.1.0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:a9017ff5fc2522e45562882ff481128631bf35da444775bc2776ac5c61d8bcae"},
- {file = "greenlet-1.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7920e3eccd26b7f4c661b746002f5ec5f0928076bd738d38d894bb359ce51927"},
- {file = "greenlet-1.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:408071b64e52192869129a205e5b463abda36eff0cebb19d6e63369440e4dc99"},
- {file = "greenlet-1.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be13a18cec649ebaab835dff269e914679ef329204704869f2f167b2c163a9da"},
- {file = "greenlet-1.1.0-cp38-cp38-win32.whl", hash = "sha256:22002259e5b7828b05600a762579fa2f8b33373ad95a0ee57b4d6109d0e589ad"},
- {file = "greenlet-1.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:206295d270f702bc27dbdbd7651e8ebe42d319139e0d90217b2074309a200da8"},
- {file = "greenlet-1.1.0-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:096cb0217d1505826ba3d723e8981096f2622cde1eb91af9ed89a17c10aa1f3e"},
- {file = "greenlet-1.1.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:03f28a5ea20201e70ab70518d151116ce939b412961c33827519ce620957d44c"},
- {file = "greenlet-1.1.0-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:7db68f15486d412b8e2cfcd584bf3b3a000911d25779d081cbbae76d71bd1a7e"},
- {file = "greenlet-1.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70bd1bb271e9429e2793902dfd194b653221904a07cbf207c3139e2672d17959"},
- {file = "greenlet-1.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f92731609d6625e1cc26ff5757db4d32b6b810d2a3363b0ff94ff573e5901f6f"},
- {file = "greenlet-1.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06d7ac89e6094a0a8f8dc46aa61898e9e1aec79b0f8b47b2400dd51a44dbc832"},
- {file = "greenlet-1.1.0-cp39-cp39-win32.whl", hash = "sha256:adb94a28225005890d4cf73648b5131e885c7b4b17bc762779f061844aabcc11"},
- {file = "greenlet-1.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:aa4230234d02e6f32f189fd40b59d5a968fe77e80f59c9c933384fe8ba535535"},
- {file = "greenlet-1.1.0.tar.gz", hash = "sha256:c87df8ae3f01ffb4483c796fe1b15232ce2b219f0b18126948616224d3f658ee"},
+ {file = "greenlet-1.1.2-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:58df5c2a0e293bf665a51f8a100d3e9956febfbf1d9aaf8c0677cf70218910c6"},
+ {file = "greenlet-1.1.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:aec52725173bd3a7b56fe91bc56eccb26fbdff1386ef123abb63c84c5b43b63a"},
+ {file = "greenlet-1.1.2-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:833e1551925ed51e6b44c800e71e77dacd7e49181fdc9ac9a0bf3714d515785d"},
+ {file = "greenlet-1.1.2-cp27-cp27m-win32.whl", hash = "sha256:aa5b467f15e78b82257319aebc78dd2915e4c1436c3c0d1ad6f53e47ba6e2713"},
+ {file = "greenlet-1.1.2-cp27-cp27m-win_amd64.whl", hash = "sha256:40b951f601af999a8bf2ce8c71e8aaa4e8c6f78ff8afae7b808aae2dc50d4c40"},
+ {file = "greenlet-1.1.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:95e69877983ea39b7303570fa6760f81a3eec23d0e3ab2021b7144b94d06202d"},
+ {file = "greenlet-1.1.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:356b3576ad078c89a6107caa9c50cc14e98e3a6c4874a37c3e0273e4baf33de8"},
+ {file = "greenlet-1.1.2-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:8639cadfda96737427330a094476d4c7a56ac03de7265622fcf4cfe57c8ae18d"},
+ {file = "greenlet-1.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97e5306482182170ade15c4b0d8386ded995a07d7cc2ca8f27958d34d6736497"},
+ {file = "greenlet-1.1.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e6a36bb9474218c7a5b27ae476035497a6990e21d04c279884eb10d9b290f1b1"},
+ {file = "greenlet-1.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:abb7a75ed8b968f3061327c433a0fbd17b729947b400747c334a9c29a9af6c58"},
+ {file = "greenlet-1.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:14d4f3cd4e8b524ae9b8aa567858beed70c392fdec26dbdb0a8a418392e71708"},
+ {file = "greenlet-1.1.2-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:17ff94e7a83aa8671a25bf5b59326ec26da379ace2ebc4411d690d80a7fbcf23"},
+ {file = "greenlet-1.1.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9f3cba480d3deb69f6ee2c1825060177a22c7826431458c697df88e6aeb3caee"},
+ {file = "greenlet-1.1.2-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:fa877ca7f6b48054f847b61d6fa7bed5cebb663ebc55e018fda12db09dcc664c"},
+ {file = "greenlet-1.1.2-cp35-cp35m-win32.whl", hash = "sha256:7cbd7574ce8e138bda9df4efc6bf2ab8572c9aff640d8ecfece1b006b68da963"},
+ {file = "greenlet-1.1.2-cp35-cp35m-win_amd64.whl", hash = "sha256:903bbd302a2378f984aef528f76d4c9b1748f318fe1294961c072bdc7f2ffa3e"},
+ {file = "greenlet-1.1.2-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:049fe7579230e44daef03a259faa24511d10ebfa44f69411d99e6a184fe68073"},
+ {file = "greenlet-1.1.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:dd0b1e9e891f69e7675ba5c92e28b90eaa045f6ab134ffe70b52e948aa175b3c"},
+ {file = "greenlet-1.1.2-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:7418b6bfc7fe3331541b84bb2141c9baf1ec7132a7ecd9f375912eca810e714e"},
+ {file = "greenlet-1.1.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9d29ca8a77117315101425ec7ec2a47a22ccf59f5593378fc4077ac5b754fce"},
+ {file = "greenlet-1.1.2-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21915eb821a6b3d9d8eefdaf57d6c345b970ad722f856cd71739493ce003ad08"},
+ {file = "greenlet-1.1.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eff9d20417ff9dcb0d25e2defc2574d10b491bf2e693b4e491914738b7908168"},
+ {file = "greenlet-1.1.2-cp36-cp36m-win32.whl", hash = "sha256:32ca72bbc673adbcfecb935bb3fb1b74e663d10a4b241aaa2f5a75fe1d1f90aa"},
+ {file = "greenlet-1.1.2-cp36-cp36m-win_amd64.whl", hash = "sha256:f0214eb2a23b85528310dad848ad2ac58e735612929c8072f6093f3585fd342d"},
+ {file = "greenlet-1.1.2-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:b92e29e58bef6d9cfd340c72b04d74c4b4e9f70c9fa7c78b674d1fec18896dc4"},
+ {file = "greenlet-1.1.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:fdcec0b8399108577ec290f55551d926d9a1fa6cad45882093a7a07ac5ec147b"},
+ {file = "greenlet-1.1.2-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:93f81b134a165cc17123626ab8da2e30c0455441d4ab5576eed73a64c025b25c"},
+ {file = "greenlet-1.1.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e12bdc622676ce47ae9abbf455c189e442afdde8818d9da983085df6312e7a1"},
+ {file = "greenlet-1.1.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c790abda465726cfb8bb08bd4ca9a5d0a7bd77c7ac1ca1b839ad823b948ea28"},
+ {file = "greenlet-1.1.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f276df9830dba7a333544bd41070e8175762a7ac20350786b322b714b0e654f5"},
+ {file = "greenlet-1.1.2-cp37-cp37m-win32.whl", hash = "sha256:64e6175c2e53195278d7388c454e0b30997573f3f4bd63697f88d855f7a6a1fc"},
+ {file = "greenlet-1.1.2-cp37-cp37m-win_amd64.whl", hash = "sha256:b11548073a2213d950c3f671aa88e6f83cda6e2fb97a8b6317b1b5b33d850e06"},
+ {file = "greenlet-1.1.2-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:9633b3034d3d901f0a46b7939f8c4d64427dfba6bbc5a36b1a67364cf148a1b0"},
+ {file = "greenlet-1.1.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:eb6ea6da4c787111adf40f697b4e58732ee0942b5d3bd8f435277643329ba627"},
+ {file = "greenlet-1.1.2-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:f3acda1924472472ddd60c29e5b9db0cec629fbe3c5c5accb74d6d6d14773478"},
+ {file = "greenlet-1.1.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e859fcb4cbe93504ea18008d1df98dee4f7766db66c435e4882ab35cf70cac43"},
+ {file = "greenlet-1.1.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:00e44c8afdbe5467e4f7b5851be223be68adb4272f44696ee71fe46b7036a711"},
+ {file = "greenlet-1.1.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec8c433b3ab0419100bd45b47c9c8551248a5aee30ca5e9d399a0b57ac04651b"},
+ {file = "greenlet-1.1.2-cp38-cp38-win32.whl", hash = "sha256:288c6a76705dc54fba69fbcb59904ae4ad768b4c768839b8ca5fdadec6dd8cfd"},
+ {file = "greenlet-1.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:8d2f1fb53a421b410751887eb4ff21386d119ef9cde3797bf5e7ed49fb51a3b3"},
+ {file = "greenlet-1.1.2-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:166eac03e48784a6a6e0e5f041cfebb1ab400b394db188c48b3a84737f505b67"},
+ {file = "greenlet-1.1.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:572e1787d1460da79590bf44304abbc0a2da944ea64ec549188fa84d89bba7ab"},
+ {file = "greenlet-1.1.2-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:be5f425ff1f5f4b3c1e33ad64ab994eed12fc284a6ea71c5243fd564502ecbe5"},
+ {file = "greenlet-1.1.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1692f7d6bc45e3200844be0dba153612103db241691088626a33ff1f24a0d88"},
+ {file = "greenlet-1.1.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7227b47e73dedaa513cdebb98469705ef0d66eb5a1250144468e9c3097d6b59b"},
+ {file = "greenlet-1.1.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ff61ff178250f9bb3cd89752df0f1dd0e27316a8bd1465351652b1b4a4cdfd3"},
+ {file = "greenlet-1.1.2-cp39-cp39-win32.whl", hash = "sha256:f70a9e237bb792c7cc7e44c531fd48f5897961701cdaa06cf22fc14965c496cf"},
+ {file = "greenlet-1.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:013d61294b6cd8fe3242932c1c5e36e5d1db2c8afb58606c5a67efce62c1f5fd"},
+ {file = "greenlet-1.1.2.tar.gz", hash = "sha256:e30f5ea4ae2346e62cedde8794a56858a67b878dd79f7df76a0767e356b1744a"},
]
idna = [
- {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"},
- {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"},
+ {file = "idna-3.2-py3-none-any.whl", hash = "sha256:14475042e284991034cb48e06f6851428fb14c4dc953acd9be9a5e95c7b6dd7a"},
+ {file = "idna-3.2.tar.gz", hash = "sha256:467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3"},
]
importlib-metadata = [
- {file = "importlib_metadata-4.4.0-py3-none-any.whl", hash = "sha256:960d52ba7c21377c990412aca380bf3642d734c2eaab78a2c39319f67c6a5786"},
- {file = "importlib_metadata-4.4.0.tar.gz", hash = "sha256:e592faad8de1bda9fe920cf41e15261e7131bcf266c30306eec00e8e225c1dd5"},
+ {file = "importlib_metadata-4.8.1-py3-none-any.whl", hash = "sha256:b618b6d2d5ffa2f16add5697cf57a46c76a56229b0ed1c438322e4e95645bd15"},
+ {file = "importlib_metadata-4.8.1.tar.gz", hash = "sha256:f284b3e11256ad1e5d03ab86bb2ccd6f5339688ff17a4d797a0fe7df326f23b1"},
]
iniconfig = [
{file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"},
@@ -681,12 +671,12 @@ markupsafe = [
{file = "MarkupSafe-2.0.1.tar.gz", hash = "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a"},
]
packaging = [
- {file = "packaging-20.9-py2.py3-none-any.whl", hash = "sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a"},
- {file = "packaging-20.9.tar.gz", hash = "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5"},
+ {file = "packaging-21.0-py3-none-any.whl", hash = "sha256:c86254f9220d55e31cc94d69bade760f0847da8000def4dfe1c6b872fd14ff14"},
+ {file = "packaging-21.0.tar.gz", hash = "sha256:7dc96269f53a4ccec5c0670940a4281106dd0bb343f47b7471f779df49c2fbe7"},
]
pluggy = [
- {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"},
- {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"},
+ {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"},
+ {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"},
]
psutil = [
{file = "psutil-5.8.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:0066a82f7b1b37d334e68697faba68e5ad5e858279fd6351c8ca6024e8d6ba64"},
@@ -756,20 +746,20 @@ pysocks = [
{file = "PySocks-1.7.1.tar.gz", hash = "sha256:3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0"},
]
pytest = [
- {file = "pytest-6.2.4-py3-none-any.whl", hash = "sha256:91ef2131a9bd6be8f76f1f08eac5c5317221d6ad1e143ae03894b862e8976890"},
- {file = "pytest-6.2.4.tar.gz", hash = "sha256:50bcad0a0b9c5a72c8e4e7c9855a3ad496ca6a881a3641b4260605450772c54b"},
+ {file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"},
+ {file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"},
]
python-engineio = [
- {file = "python-engineio-4.2.0.tar.gz", hash = "sha256:4e97c1189c23923858f5bb6dc47cfcd915005383c3c039ff01c89f2c00d62077"},
- {file = "python_engineio-4.2.0-py2.py3-none-any.whl", hash = "sha256:c6c119c2039fcb6f64d260211ca92c0c61b2b888a28678732a961f2aaebcc848"},
+ {file = "python-engineio-4.2.1.tar.gz", hash = "sha256:d510329b6d8ed5662547862f58bc73659ae62defa66b66d745ba021de112fa62"},
+ {file = "python_engineio-4.2.1-py3-none-any.whl", hash = "sha256:f3ef9a2c048d08990f294c5f8991f6f162c3b12ecbd368baa0d90441de907d1c"},
]
python-socketio = [
- {file = "python-socketio-5.3.0.tar.gz", hash = "sha256:3dcc9785aaeef3a9eeb36c3818095662342744bdcdabd050fe697cdb826a1c2b"},
- {file = "python_socketio-5.3.0-py2.py3-none-any.whl", hash = "sha256:d74314fd4241342c8a55c4f66d5cfea8f1a8fffd157af216c67e1c3a649a2444"},
+ {file = "python-socketio-5.4.0.tar.gz", hash = "sha256:ca807c9e1f168e96dea412d64dd834fb47c470d27fd83da0504aa4b248ba2544"},
+ {file = "python_socketio-5.4.0-py3-none-any.whl", hash = "sha256:7ed57f6c024abdfeb9b25c74c0c00ffc18da47d903e8d72deecb87584370d1fc"},
]
requests = [
- {file = "requests-2.25.1-py2.py3-none-any.whl", hash = "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"},
- {file = "requests-2.25.1.tar.gz", hash = "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804"},
+ {file = "requests-2.26.0-py2.py3-none-any.whl", hash = "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24"},
+ {file = "requests-2.26.0.tar.gz", hash = "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7"},
]
six = [
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
@@ -781,23 +771,23 @@ toml = [
{file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
]
typing-extensions = [
- {file = "typing_extensions-3.10.0.0-py2-none-any.whl", hash = "sha256:0ac0f89795dd19de6b97debb0c6af1c70987fd80a2d62d1958f7e56fcc31b497"},
- {file = "typing_extensions-3.10.0.0-py3-none-any.whl", hash = "sha256:779383f6086d90c99ae41cf0ff39aac8a7937a9283ce0a414e5dd782f4c94a84"},
- {file = "typing_extensions-3.10.0.0.tar.gz", hash = "sha256:50b6f157849174217d0656f99dc82fe932884fb250826c18350e159ec6cdf342"},
+ {file = "typing_extensions-3.10.0.2-py2-none-any.whl", hash = "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7"},
+ {file = "typing_extensions-3.10.0.2-py3-none-any.whl", hash = "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"},
+ {file = "typing_extensions-3.10.0.2.tar.gz", hash = "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e"},
]
unidecode = [
- {file = "Unidecode-1.2.0-py2.py3-none-any.whl", hash = "sha256:12435ef2fc4cdfd9cf1035a1db7e98b6b047fe591892e81f34e94959591fad00"},
- {file = "Unidecode-1.2.0.tar.gz", hash = "sha256:8d73a97d387a956922344f6b74243c2c6771594659778744b2dbdaad8f6b727d"},
+ {file = "Unidecode-1.3.2-py3-none-any.whl", hash = "sha256:215fe33c9d1c889fa823ccb66df91b02524eb8cc8c9c80f9c5b8129754d27829"},
+ {file = "Unidecode-1.3.2.tar.gz", hash = "sha256:669898c1528912bcf07f9819dc60df18d057f7528271e31f8ec28cc88ef27504"},
]
urllib3 = [
- {file = "urllib3-1.26.5-py2.py3-none-any.whl", hash = "sha256:753a0374df26658f99d826cfe40394a686d05985786d946fbe4165b5148f5a7c"},
- {file = "urllib3-1.26.5.tar.gz", hash = "sha256:a7acd0977125325f516bda9735fa7142b909a8d01e8b2e4c8108d0984e6e0098"},
+ {file = "urllib3-1.26.7-py2.py3-none-any.whl", hash = "sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844"},
+ {file = "urllib3-1.26.7.tar.gz", hash = "sha256:4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece"},
]
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.1-py3-none-any.whl", hash = "sha256:51cb66cc54621609dd593d1787f286ee42a5c0adbb4b29abea5a63edc3e03098"},
- {file = "zipp-3.4.1.tar.gz", hash = "sha256:3607921face881ba3e026887d8150cca609d517579abe052ac81fc5aeffdbd76"},
+ {file = "zipp-3.6.0-py3-none-any.whl", hash = "sha256:9fe5ea21568a0a70e50f273397638d39b03353731e6cbbb3fd8502a33fec40bc"},
+ {file = "zipp-3.6.0.tar.gz", hash = "sha256:71c644c5369f4a6e07636f0aa966270449561fcea2e3d6747b8d23efaa9d7832"},
]
diff --git a/cli/tests/test_cli_common.py b/cli/tests/test_cli_common.py
index 9f113a84..9a64d762 100644
--- a/cli/tests/test_cli_common.py
+++ b/cli/tests/test_cli_common.py
@@ -162,11 +162,19 @@ class TestGetTorPaths:
tor_geo_ip_file_path = os.path.join(base_path, "Resources", "Tor", "geoip")
tor_geo_ipv6_file_path = os.path.join(base_path, "Resources", "Tor", "geoip6")
obfs4proxy_file_path = os.path.join(base_path, "Resources", "Tor", "obfs4proxy")
+ meek_client_file_path = os.path.join(
+ base_path, "Resources", "Tor", "meek-client"
+ )
+ snowflake_file_path = os.path.join(
+ base_path, "Resources", "Tor", "snowflake-client"
+ )
assert common_obj.get_tor_paths() == (
tor_path,
tor_geo_ip_file_path,
tor_geo_ipv6_file_path,
obfs4proxy_file_path,
+ snowflake_file_path,
+ meek_client_file_path,
)
@pytest.mark.skipif(sys.platform != "linux", reason="requires Linux")
@@ -176,6 +184,8 @@ class TestGetTorPaths:
tor_geo_ip_file_path,
tor_geo_ipv6_file_path,
_, # obfs4proxy is optional
+ _, # snowflake-client is optional
+ _, # meek-client is optional
) = common_obj.get_tor_paths()
assert os.path.basename(tor_path) == "tor"
@@ -199,6 +209,12 @@ class TestGetTorPaths:
obfs4proxy_file_path = os.path.join(
os.path.join(base_path, "Tor"), "obfs4proxy.exe"
)
+ snowflake_file_path = os.path.join(
+ os.path.join(base_path, "Tor"), "snowflake-client.exe"
+ )
+ meek_client_file_path = os.path.join(
+ os.path.join(base_path, "Tor"), "meek-client.exe"
+ )
tor_geo_ip_file_path = os.path.join(
os.path.join(os.path.join(base_path, "Data"), "Tor"), "geoip"
)
@@ -210,6 +226,8 @@ class TestGetTorPaths:
tor_geo_ip_file_path,
tor_geo_ipv6_file_path,
obfs4proxy_file_path,
+ snowflake_file_path,
+ meek_client_file_path,
)
diff --git a/cli/tests/test_cli_settings.py b/cli/tests/test_cli_settings.py
index ed8d5bb9..9513b013 100644
--- a/cli/tests/test_cli_settings.py
+++ b/cli/tests/test_cli_settings.py
@@ -29,12 +29,13 @@ class TestSettings:
"auth_password": "",
"use_autoupdate": True,
"autoupdate_timestamp": None,
- "no_bridges": True,
- "tor_bridges_use_obfs4": False,
- "tor_bridges_use_meek_lite_azure": False,
- "tor_bridges_use_custom_bridges": "",
+ "bridges_enabled": False,
+ "bridges_type": "built-in",
+ "bridges_builtin_pt": "obfs4",
+ "bridges_moat": "",
+ "bridges_custom": "",
"persistent_tabs": [],
- "theme":0
+ "theme": 0,
}
for key in settings_obj._settings:
# Skip locale, it will not always default to the same thing
@@ -93,10 +94,11 @@ class TestSettings:
assert settings_obj.get("use_autoupdate") is True
assert settings_obj.get("autoupdate_timestamp") is None
assert settings_obj.get("autoupdate_timestamp") is None
- assert settings_obj.get("no_bridges") is True
- assert settings_obj.get("tor_bridges_use_obfs4") is False
- assert settings_obj.get("tor_bridges_use_meek_lite_azure") is False
- assert settings_obj.get("tor_bridges_use_custom_bridges") == ""
+ assert settings_obj.get("bridges_enabled") is False
+ assert settings_obj.get("bridges_type") == "built-in"
+ assert settings_obj.get("bridges_builtin_pt") == "obfs4"
+ assert settings_obj.get("bridges_moat") == ""
+ assert settings_obj.get("bridges_custom") == ""
def test_set_version(self, settings_obj):
settings_obj.set("version", "CUSTOM_VERSION")
@@ -139,10 +141,10 @@ class TestSettings:
def test_set_custom_bridge(self, settings_obj):
settings_obj.set(
- "tor_bridges_use_custom_bridges",
+ "bridges_custom",
"Bridge 45.3.20.65:9050 21300AD88890A49C429A6CB9959CFD44490A8F6E",
)
assert (
- settings_obj._settings["tor_bridges_use_custom_bridges"]
+ settings_obj._settings["bridges_custom"]
== "Bridge 45.3.20.65:9050 21300AD88890A49C429A6CB9959CFD44490A8F6E"
)