From 3e9b9b2f930a514986c27b52e9c52f1a6c4d2705 Mon Sep 17 00:00:00 2001 From: Miguel Jacq Date: Fri, 15 Oct 2021 14:24:27 +1100 Subject: [PATCH] Add early (non-domain-fronted!) methods for interacting with the planned Tor censorship circumvention moat endpoints. This is based on loose specs from https://gitlab.torproject.org/tpo/anti-censorship/bridgedb/-/issues/40025 --- cli/onionshare_cli/common.py | 69 ++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/cli/onionshare_cli/common.py b/cli/onionshare_cli/common.py index dd92eb0b..195de2fe 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 @@ -504,6 +505,74 @@ class Common: total_size += os.path.getsize(fp) return total_size + def censorship_obtain_map(self): + """ + Retrieves the Circumvention map from Tor Project and store it + locally for further look-ups if required. + """ + endpoint = "https://bridges.torproject.org/moat/circumvention/map" + # @TODO this needs to be using domain fronting to defeat censorship + # of the lookup itself. + response = requests.get(endpoint) + self.censorship_map = response.json() + self.log("Common", "censorship_obtain_map", self.censorship_map) + + def censorship_obtain_settings_from_api(self): + """ + Retrieves the Circumvention Settings from Tor Project, which + will return recommended settings based on the country code of + the requesting IP. + """ + endpoint = "https://bridges.torproject.org/moat/circumvention/settings" + # @TODO this needs to be using domain fronting to defeat censorship + # of the lookup itself. + response = requests.get(endpoint) + self.censorship_settings = response.json() + self.log( + "Common", "censorship_obtain_settings_from_api", self.censorship_settings + ) + + def censorship_obtain_settings_from_map(self, country): + """ + Retrieves the Circumvention Settings for this country from the + circumvention map we have stored locally, rather than from the + API endpoint. + + This is for when the user has specified the country themselves + rather than requesting auto-detection. + """ + try: + # Fetch the map. + self.censorship_obtain_map() + self.censorship_settings = self.censorship_map[country] + self.log( + "Common", + "censorship_obtain_settings_from_map", + f"Settings are {self.censorship_settings}", + ) + except KeyError: + self.log( + "Common", + "censorship_obtain_settings_from_map", + "No censorship settings found for this country", + ) + return False + + def censorship_obtain_builtin_bridges(self): + """ + Retrieves the list of built-in bridges from the Tor Project. + """ + endpoint = "https://bridges.torproject.org/moat/circumvention/builtin" + # @TODO this needs to be using domain fronting to defeat censorship + # of the lookup itself. + response = requests.get(endpoint) + self.censorship_builtin_bridges = response.json() + self.log( + "Common", + "censorship_obtain_builtin_bridges", + self.censorship_builtin_bridges, + ) + class AutoStopTimer(threading.Thread): """