aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMicah Lee <micah@micahflee.com>2022-03-28 19:31:39 -0700
committerMicah Lee <micah@micahflee.com>2022-03-28 19:31:39 -0700
commit792ee59e9300b6e71f906c210f336109054edf07 (patch)
tree52766ce90d781c4e1ca8625d46cde47c79f6180b
parent0d58475c34313814566ccdaef6f827951134dfdc (diff)
parent15eda5ed046153749616cf07df8e3f7b33f091d3 (diff)
downloadonionshare-792ee59e9300b6e71f906c210f336109054edf07.tar.gz
onionshare-792ee59e9300b6e71f906c210f336109054edf07.zip
Merge branch 'develop' of github.com:onionshare/onionshare into upgrade-flask
-rw-r--r--cli/onionshare_cli/censorship.py113
-rw-r--r--cli/onionshare_cli/meek.py18
-rw-r--r--desktop/onionshare/connection_tab.py16
-rw-r--r--desktop/onionshare/moat_dialog.py12
4 files changed, 93 insertions, 66 deletions
diff --git a/cli/onionshare_cli/censorship.py b/cli/onionshare_cli/censorship.py
index 4ab5c366..9268f578 100644
--- a/cli/onionshare_cli/censorship.py
+++ b/cli/onionshare_cli/censorship.py
@@ -19,8 +19,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
import requests
-from .meek import MeekNotRunning
-
class CensorshipCircumventionError(Exception):
"""
@@ -47,15 +45,12 @@ class CensorshipCircumvention(object):
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
+ 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:
@@ -100,7 +95,7 @@ class CensorshipCircumvention(object):
if r.status_code != 200:
self.common.log(
"CensorshipCircumvention",
- "censorship_obtain_map",
+ "request_map",
f"status_code={r.status_code}",
)
return False
@@ -110,7 +105,7 @@ class CensorshipCircumvention(object):
if "errors" in result:
self.common.log(
"CensorshipCircumvention",
- "censorship_obtain_map",
+ "request_map",
f"errors={result['errors']}",
)
return False
@@ -138,7 +133,7 @@ class CensorshipCircumvention(object):
if country:
self.common.log(
"CensorshipCircumvention",
- "censorship_obtain_settings",
+ "request_settings",
f"Trying to obtain bridges for country={country}",
)
data = {"country": country}
@@ -154,7 +149,7 @@ class CensorshipCircumvention(object):
if r.status_code != 200:
self.common.log(
"CensorshipCircumvention",
- "censorship_obtain_settings",
+ "request_settings",
f"status_code={r.status_code}",
)
return False
@@ -164,7 +159,7 @@ class CensorshipCircumvention(object):
if "errors" in result:
self.common.log(
"CensorshipCircumvention",
- "censorship_obtain_settings",
+ "request_settings",
f"errors={result['errors']}",
)
return False
@@ -175,7 +170,7 @@ class CensorshipCircumvention(object):
if not "settings" in result:
self.common.log(
"CensorshipCircumvention",
- "censorship_obtain_settings",
+ "request_settings",
"No settings found for this country",
)
return False
@@ -200,7 +195,7 @@ class CensorshipCircumvention(object):
if r.status_code != 200:
self.common.log(
"CensorshipCircumvention",
- "censorship_obtain_builtin_bridges",
+ "request_builtin_bridges",
f"status_code={r.status_code}",
)
return False
@@ -210,7 +205,7 @@ class CensorshipCircumvention(object):
if "errors" in result:
self.common.log(
"CensorshipCircumvention",
- "censorship_obtain_builtin_bridges",
+ "request_builtin_bridges",
f"errors={result['errors']}",
)
return False
@@ -237,42 +232,15 @@ class CensorshipCircumvention(object):
f"Obtained bridges: {bridges}",
)
bridge_strings = bridges["bridge_strings"]
- bridge_type = bridges["type"]
- bridge_source = bridges["source"]
-
- # If the recommended bridge source is to use the built-in
- # bridges, set that in our settings, as if the user had
- # selected the built-in bridges for a specific PT themselves.
- #
- if bridge_source == "builtin":
- self.common.log(
- "CensorshipCircumvention",
- "save_settings",
- "Will be using built-in bridges",
- )
- self.settings.set("bridges_type", "built-in")
- if bridge_type == "obfs4":
- self.settings.set("bridges_builtin_pt", "obfs4")
- if bridge_type == "snowflake":
- self.settings.set("bridges_builtin_pt", "snowflake")
- if bridge_type == "meek":
- self.settings.set("bridges_builtin_pt", "meek-azure")
- bridges_ok = True
- else:
- self.common.log(
- "CensorshipCircumvention",
- "save_settings",
- "Will be using custom bridges",
- )
- # Any other type of bridge we can treat as custom.
- self.settings.set("bridges_type", "custom")
- # Sanity check the bridges provided from the Tor API before saving
- bridges_checked = self.common.check_bridges_valid(bridge_strings)
+ self.settings.set("bridges_type", "custom")
- if bridges_checked:
- self.settings.set("bridges_custom", "\n".join(bridges_checked))
- bridges_ok = True
+ # Sanity check the bridges provided from the Tor API before saving
+ bridges_checked = self.common.check_bridges_valid(bridge_strings)
+
+ if bridges_checked:
+ self.settings.set("bridges_custom", "\n".join(bridges_checked))
+ bridges_ok = True
# If we got any good bridges, save them to settings and return.
if bridges_ok:
@@ -291,3 +259,42 @@ class CensorshipCircumvention(object):
"Could not use any of the obtained bridges.",
)
return False
+
+
+ def request_default_bridges(self):
+ """
+ Retrieves the list of default fall-back bridges from the Tor Project.
+
+ These are intended for when no censorship settings were found for a
+ specific country, but maybe there was some connection issue anyway.
+ """
+ if not self.api_proxies:
+ return False
+ endpoint = "https://bridges.torproject.org/moat/circumvention/defaults"
+ try:
+ r = requests.get(
+ endpoint,
+ headers={"Content-Type": "application/vnd.api+json"},
+ proxies=self.api_proxies,
+ )
+ if r.status_code != 200:
+ self.common.log(
+ "CensorshipCircumvention",
+ "request_default_bridges",
+ f"status_code={r.status_code}",
+ )
+ return False
+
+ result = r.json()
+
+ if "errors" in result:
+ self.common.log(
+ "CensorshipCircumvention",
+ "request_default_bridges",
+ f"errors={result['errors']}",
+ )
+ return False
+
+ return result
+ except requests.exceptions.RequestException as e:
+ raise CensorshipCircumventionError(e)
diff --git a/cli/onionshare_cli/meek.py b/cli/onionshare_cli/meek.py
index 777c0ab6..81ef6c6e 100644
--- a/cli/onionshare_cli/meek.py
+++ b/cli/onionshare_cli/meek.py
@@ -69,7 +69,7 @@ class Meek(object):
if self.meek_client_file_path is None or not os.path.exists(
self.meek_client_file_path
):
- raise MeekNotFound()
+ raise MeekNotFound(self.common)
# Start the Meek Client as a subprocess.
self.common.log("Meek", "start", "Starting meek client")
@@ -128,7 +128,7 @@ class Meek(object):
if "CMETHOD-ERROR" in line:
self.cleanup()
- raise MeekNotRunning()
+ raise MeekNotRunning(self.common, line)
break
if self.meek_port:
@@ -137,9 +137,8 @@ class Meek(object):
"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()
+ raise MeekNotRunning(self.common, "Could not obtain the meek port")
def cleanup(self):
"""
@@ -182,8 +181,19 @@ class MeekNotRunning(Exception):
number it started on, in order to do domain fronting.
"""
+ def __init__(self, common, info=None):
+ self.common = common
+ msg = "Meek experienced an error starting up"
+ if info:
+ msg = msg + f": {info}"
+ self.common.log("MeekNotRunning", "__init__", msg)
+
class MeekNotFound(Exception):
"""
We were unable to find the Meek Client binary.
"""
+
+ def __init__(self, common):
+ self.common = common
+ self.common.log("MeekNotFound", "__init__", "Could not find the meek binary")
diff --git a/desktop/onionshare/connection_tab.py b/desktop/onionshare/connection_tab.py
index 1cf3c376..d7b49563 100644
--- a/desktop/onionshare/connection_tab.py
+++ b/desktop/onionshare/connection_tab.py
@@ -181,7 +181,9 @@ class AutoConnectTab(QtWidgets.QWidget):
self.tor_con.start(self.curr_settings)
def _got_no_bridges(self):
- # If we got no bridges, try connecting again using built-in obfs4 bridges
+ # If we got no bridges, even after trying the default bridges
+ # provided by the Censorship API, try connecting again using
+ # our built-in obfs4 bridges
self.curr_settings.set("bridges_type", "built-in")
self.curr_settings.set("bridges_builtin_pt", "obfs4")
self.curr_settings.set("bridges_enabled", True)
@@ -244,6 +246,18 @@ class AutoConnectTab(QtWidgets.QWidget):
bridge_settings = self.censorship_circumvention.request_settings(
country=country
)
+
+ if not bridge_settings:
+ # Fall back to trying the default bridges from the API
+ self.common.log(
+ "AutoConnectTab",
+ "use_bridge_connect_clicked",
+ "Falling back to trying default bridges provided by the Censorship Circumvention API",
+ )
+ bridge_settings = (
+ self.censorship_circumvention.request_default_bridges()
+ )
+
self.common.gui.meek.cleanup()
if bridge_settings and self.censorship_circumvention.save_settings(
diff --git a/desktop/onionshare/moat_dialog.py b/desktop/onionshare/moat_dialog.py
index fd04ee9c..db4bdf29 100644
--- a/desktop/onionshare/moat_dialog.py
+++ b/desktop/onionshare/moat_dialog.py
@@ -236,14 +236,10 @@ class MoatThread(QtCore.QThread):
# Start Meek so that we can do domain fronting
try:
self.meek.start()
- except MeekNotFound:
- self.common.log("MoatThread", "run", f"Could not find meek-client")
- self.bridgedb_error.emit()
- return
- except MeekNotRunning:
- self.common.log(
- "MoatThread", "run", f"Ran meek-client, but there was an error"
- )
+ except (
+ MeekNotFound,
+ MeekNotRunning,
+ ):
self.bridgedb_error.emit()
return