aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiguel Jacq <mig@mig5.net>2021-11-27 10:35:25 +1100
committerMiguel Jacq <mig@mig5.net>2021-11-27 10:35:25 +1100
commit55c8ada6ef0a2f8852ee2be1b7ee6c66815ae6fc (patch)
treecdb8a3cf284222b841b6f2faaf9ba8bb7c1bd8d6
parent06a3599fe185902ce8f3c704f8ea652504a1fab7 (diff)
downloadonionshare-55c8ada6ef0a2f8852ee2be1b7ee6c66815ae6fc.tar.gz
onionshare-55c8ada6ef0a2f8852ee2be1b7ee6c66815ae6fc.zip
Move the ability to use Tor vs Meek into the CensorshipCircumvention class so that we can use those endpoints over Tor elsewhere later
-rw-r--r--cli/onionshare_cli/censorship.py51
-rw-r--r--cli/onionshare_cli/onion.py66
2 files changed, 60 insertions, 57 deletions
diff --git a/cli/onionshare_cli/censorship.py b/cli/onionshare_cli/censorship.py
index f84b1058..9f41d61c 100644
--- a/cli/onionshare_cli/censorship.py
+++ b/cli/onionshare_cli/censorship.py
@@ -25,21 +25,46 @@ from .meek import MeekNotRunning
class CensorshipCircumvention(object):
"""
Connect to the Tor Moat APIs to retrieve censorship
- circumvention recommendations, over the Meek client.
+ circumvention recommendations or the latest bridges.
+
+ We support reaching this API over Tor, or Meek
+ (domain fronting) if Tor is not connected.
"""
- def __init__(self, common, meek, domain_fronting=True):
+ def __init__(self, common, meek=None, onion=None):
"""
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()
+ self.api_proxies = {}
+ if meek:
+ self.meek = meek
+ if not self.meek.meek_proxies:
+ raise MeekNotRunning()
+ else:
+ self.common.log(
+ "CensorshipCircumvention",
+ "__init__",
+ "Using Meek with CensorShipCircumvention API",
+ )
+ self.api_proxies = self.meek.meek_proxies
+ if onion:
+ self.onion = onion
+ if not self.onion.is_authenticated:
+ return False
+ else:
+ self.common.log(
+ "CensorshipCircumvention",
+ "__init__",
+ "Using Tor with CensorShipCircumvention API",
+ )
+ (socks_address, socks_port) = self.onion.get_tor_socks_port()
+ self.api_proxies = {
+ "http": f"socks5h://{socks_address}:{socks_port}",
+ "https": f"socks5h://{socks_address}:{socks_port}",
+ }
def request_map(self, country=False):
"""
@@ -52,6 +77,8 @@ class CensorshipCircumvention(object):
Note that this API endpoint doesn't return actual bridges,
it just returns the recommended bridge type countries.
"""
+ if not self.api_proxies:
+ return False
endpoint = "https://bridges.torproject.org/moat/circumvention/map"
data = {}
if country:
@@ -61,7 +88,7 @@ class CensorshipCircumvention(object):
endpoint,
json=data,
headers={"Content-Type": "application/vnd.api+json"},
- proxies=self.meek.meek_proxies,
+ proxies=self.api_proxies,
)
if r.status_code != 200:
self.common.log(
@@ -95,6 +122,8 @@ class CensorshipCircumvention(object):
Optionally, a list of transports can be specified in order to
return recommended settings for just that transport type.
"""
+ if not self.api_proxies:
+ return False
endpoint = "https://bridges.torproject.org/moat/circumvention/settings"
data = {}
if country:
@@ -105,7 +134,7 @@ class CensorshipCircumvention(object):
endpoint,
json=data,
headers={"Content-Type": "application/vnd.api+json"},
- proxies=self.meek.meek_proxies,
+ proxies=self.api_proxies,
)
if r.status_code != 200:
self.common.log(
@@ -142,11 +171,13 @@ class CensorshipCircumvention(object):
"""
Retrieves the list of built-in bridges from the Tor Project.
"""
+ if not self.api_proxies:
+ return False
endpoint = "https://bridges.torproject.org/moat/circumvention/builtin"
r = requests.post(
endpoint,
headers={"Content-Type": "application/vnd.api+json"},
- proxies=self.meek.meek_proxies,
+ proxies=self.api_proxies,
)
if r.status_code != 200:
self.common.log(
diff --git a/cli/onionshare_cli/onion.py b/cli/onionshare_cli/onion.py
index c0a4e6e1..bd8e28df 100644
--- a/cli/onionshare_cli/onion.py
+++ b/cli/onionshare_cli/onion.py
@@ -914,7 +914,8 @@ class Onion(object):
Use the CensorshipCircumvention API to fetch the latest built-in bridges
and update them in settings.
"""
- got_builtin_bridges = False
+ builtin_bridges = False
+ meek = None
# Try obtaining bridges over Tor, if we're connected to it.
if self.is_authenticated:
self.common.log(
@@ -922,43 +923,14 @@ class Onion(object):
"update_builtin_bridges",
"Updating the built-in bridges. Trying over Tor first",
)
- (socks_address, socks_port) = self.get_tor_socks_port()
- tor_proxies = {
- "http": f"socks5h://{socks_address}:{socks_port}",
- "https": f"socks5h://{socks_address}:{socks_port}",
- }
- # Request a bridge
- r = requests.post(
- "https://bridges.torproject.org/moat/circumvention/builtin",
- headers={"Content-Type": "application/vnd.api+json"},
- proxies=tor_proxies,
+ self.censorship_circumvention = CensorshipCircumvention(
+ self.common, None, self
)
- if r.status_code != 200:
- self.common.log(
- "Onion",
- "update_builtin_bridges",
- f"Trying over Tor failed: status_code={r.status_code}",
- )
-
- try:
- builtin_bridges = r.json()
- if "errors" in builtin_bridges:
- self.common.log(
- "Onion",
- "update_builtin_bridges",
- f"Trying over Tor failed: errors={builtin_bridges['errors']}",
- )
- else:
- got_builtin_bridges = builtin_bridges
- except Exception as e:
- self.common.log(
- "Onion",
- "update_builtin_bridges",
- f"Hit exception when trying over Tor: {e}",
- )
+ builtin_bridges = self.censorship_circumvention.request_builtin_bridges()
- if not got_builtin_bridges:
- # Fall back to using Meek, without Tor
+ if not builtin_bridges:
+ # Tor was not running or it failed to hit the Tor API.
+ # Fall back to using Meek (domain-fronting).
self.common.log(
"Onion",
"update_builtin_bridges",
@@ -966,35 +938,35 @@ class Onion(object):
)
meek = Meek(self.common)
meek.start()
- self.censorship_circumvention = CensorshipCircumvention(self.common, meek)
- got_builtin_bridges = (
- self.censorship_circumvention.request_builtin_bridges()
+ self.censorship_circumvention = CensorshipCircumvention(
+ self.common, meek, None
)
+ builtin_bridges = self.censorship_circumvention.request_builtin_bridges()
meek.cleanup()
- # If we got to this point, we have bridges
- if got_builtin_bridges:
+ if builtin_bridges:
+ # If we got to this point, we have bridges
self.common.log(
"Onion",
"update_builtin_bridges",
- f"Obtained bridges: {got_builtin_bridges}",
+ f"Obtained bridges: {builtin_bridges}",
)
- if got_builtin_bridges["meek"]:
+ if builtin_bridges["meek"]:
# Meek bridge needs to be defined as "meek_lite", not "meek",
# for it to work with obfs4proxy.
# We also refer to this bridge type as 'meek-azure' in our settings.
# So first, rename the key in the dict
- got_builtin_bridges["meek-azure"] = got_builtin_bridges.pop("meek")
+ builtin_bridges["meek-azure"] = builtin_bridges.pop("meek")
new_meek_bridges = []
# Now replace the values. They also need the url/front params appended
- for item in got_builtin_bridges["meek-azure"]:
+ for item in builtin_bridges["meek-azure"]:
newline = item.replace("meek", "meek_lite")
new_meek_bridges.append(
f"{newline} url=https://meek.azureedge.net/ front=ajax.aspnetcdn.com"
)
- got_builtin_bridges["meek-azure"] = new_meek_bridges
+ builtin_bridges["meek-azure"] = new_meek_bridges
# Save the new settings
- self.settings.set("bridges_builtin", got_builtin_bridges)
+ self.settings.set("bridges_builtin", builtin_bridges)
self.settings.save()
else:
self.common.log(