From 3f4cb6a02ea61157b5f3c6f2e99edaeb9ac15f90 Mon Sep 17 00:00:00 2001 From: Miguel Jacq Date: Tue, 14 Dec 2021 10:48:47 +1100 Subject: [PATCH] Use the CensorshipCircumvention methods to fetch bridges for the country/autodetection --- cli/onionshare_cli/censorship.py | 5 ++ desktop/src/onionshare/connection_tab.py | 69 ++++++++++------------ desktop/src/onionshare/threads.py | 32 ++++++++++ desktop/src/onionshare/tor_connection.py | 1 - desktop/src/onionshare/tor_settings_tab.py | 11 ++-- 5 files changed, 72 insertions(+), 46 deletions(-) diff --git a/cli/onionshare_cli/censorship.py b/cli/onionshare_cli/censorship.py index d9b02616..5d3e71e5 100644 --- a/cli/onionshare_cli/censorship.py +++ b/cli/onionshare_cli/censorship.py @@ -127,6 +127,11 @@ class CensorshipCircumvention(object): endpoint = "https://bridges.torproject.org/moat/circumvention/settings" data = {} if country: + self.common.log( + "CensorshipCircumvention", + "censorship_obtain_settings", + f"Trying to obtain bridges for country={country}", + ) data = {"country": country} if transports: data.append({"transports": transports}) diff --git a/desktop/src/onionshare/connection_tab.py b/desktop/src/onionshare/connection_tab.py index b4e8bc25..567b2713 100644 --- a/desktop/src/onionshare/connection_tab.py +++ b/desktop/src/onionshare/connection_tab.py @@ -21,11 +21,13 @@ along with this program. If not, see . import json import os import random +import time from PySide2 import QtCore, QtWidgets, QtGui from onionshare_cli.settings import Settings from . import strings +from .threads import CensorshipCircumventionThread from .gui_common import GuiCommon, ToggleCheckbox from .tor_connection import TorConnectionWidget @@ -146,6 +148,22 @@ class AutoConnectTab(QtWidgets.QWidget): self.tor_con.show() self.tor_con.start(self.curr_settings) + def _got_bridges(self): + # Try and connect again + self.common.log( + "AutoConnectTab", + "use_bridge_connect_clicked", + "Got bridges. Trying to reconnect to Tor", + ) + self.active = False + self.tor_con.show() + self.tor_con.start() + + def _got_no_bridges(self): + self.active = False + self.tor_con.fail.emit() + self.open_tor_settings() + def use_bridge_connect_clicked(self): """ Connect button in use bridge widget clicked. @@ -158,30 +176,18 @@ class AutoConnectTab(QtWidgets.QWidget): self.use_bridge_widget.hide_buttons() if self.use_bridge_widget.detect_automatic_radio.isChecked(): - self.use_bridge_widget.start_autodetecting_location() - - # TODO: In a separate thread, detect the country. When complete, call - # self.use_bridge_widget.stop_autodetecting_location() to stop the animation - pass - + country = False else: - # TODO: Connect using the selected country - pass + country = self.use_bridge_widget.country_code - # self.common.gui.meek.start() - # self.censorship_circumvention = CensorshipCircumvention( - # self.common, self.common.gui.meek - # ) - # bridge_settings = self.censorship_circumvention.request_settings(country="tm") - # self.common.gui.meek.cleanup() - - # if bridge_settings and self.censorship_circumvention.save_settings( - # self.settings, bridge_settings - # ): - # # Try and connect again - # self.start() - # else: - # self.fail.emit() + t = CensorshipCircumventionThread(self.common, self.curr_settings, country) + t.got_bridges.connect(self._got_bridges) + t.got_no_bridges.connect(self._got_no_bridges) + t.start() + self.active = True + while self.active: + time.sleep(0.1) + self.common.gui.qtapp.processEvents() def back_clicked(self): """ @@ -419,28 +425,13 @@ class AutoConnectUseBridgeWidget(QtWidgets.QWidget): self.back_button.show() self.configure_button.show() - def start_autodetecting_location(self): - # If we're automatically detecting it, randomly switch up the country - # dropdown until we detect the location - if self.detect_automatic_radio.isChecked(): - self.task_label.show() - self.task_label.setText(strings._("gui_autoconnect_task_detect_location")) - - self.autodetecting_timer = QtCore.QTimer() - self.autodetecting_timer.timeout.connect(self._autodetecting_timer_callback) - self.autodetecting_timer.start(200) - - def stop_autodetecting_location(self): - self.task_label.hide() - self.autodetecting_timer.stop() - def _country_changed(self, index=None): - country_code = str(self.country_combobox.currentData()).lower() + self.country_code = str(self.country_combobox.currentData()).lower() path = GuiCommon.get_resource_path( os.path.join( "images", "countries", - f"{country_code}-{self.common.gui.color_mode}.png", + f"{self.country_code}-{self.common.gui.color_mode}.png", ) ) self.country_image_label.setPixmap(QtGui.QPixmap.fromImage(QtGui.QImage(path))) diff --git a/desktop/src/onionshare/threads.py b/desktop/src/onionshare/threads.py index b02c6f21..fa296567 100644 --- a/desktop/src/onionshare/threads.py +++ b/desktop/src/onionshare/threads.py @@ -39,6 +39,8 @@ from onionshare_cli.onion import ( PortNotAvailable, ) +from onionshare_cli.censorship import CensorshipCircumvention + from . import strings @@ -268,3 +270,33 @@ class OnionCleanupThread(QtCore.QThread): def run(self): self.common.log("OnionCleanupThread", "run") self.common.gui.onion.cleanup() + + +class CensorshipCircumventionThread(QtCore.QThread): + got_bridges = QtCore.Signal() + got_no_bridges = QtCore.Signal() + + def __init__(self, common, settings, country): + super(CensorshipCircumventionThread, self).__init__() + self.common = common + self.common.log("CensorshipCircumventionThread", "__init__") + self.settings = settings + self.country = country + + def run(self): + self.common.log("CensorshipCircumventionThread", "run") + + self.common.gui.meek.start() + self.censorship_circumvention = CensorshipCircumvention( + self.common, self.common.gui.meek + ) + bridge_settings = self.censorship_circumvention.request_settings( + country=self.country + ) + + if bridge_settings and self.censorship_circumvention.save_settings( + self.settings, bridge_settings + ): + self.got_bridges.emit() + else: + self.got_no_bridges.emit() diff --git a/desktop/src/onionshare/tor_connection.py b/desktop/src/onionshare/tor_connection.py index fe3274a6..c69342ae 100644 --- a/desktop/src/onionshare/tor_connection.py +++ b/desktop/src/onionshare/tor_connection.py @@ -39,7 +39,6 @@ from onionshare_cli.onion import ( ) from . import strings -from onionshare_cli.censorship import CensorshipCircumvention class TorConnectionWidget(QtWidgets.QWidget): diff --git a/desktop/src/onionshare/tor_settings_tab.py b/desktop/src/onionshare/tor_settings_tab.py index 1241f09d..cf30d320 100644 --- a/desktop/src/onionshare/tor_settings_tab.py +++ b/desktop/src/onionshare/tor_settings_tab.py @@ -42,7 +42,9 @@ class TorSettingsTab(QtWidgets.QWidget): tor_is_connected = QtCore.Signal() tor_is_disconnected = QtCore.Signal() - def __init__(self, common, tab_id, are_tabs_active, status_bar, from_autoconnect=False): + def __init__( + self, common, tab_id, are_tabs_active, status_bar, from_autoconnect=False + ): super(TorSettingsTab, self).__init__() self.common = common @@ -314,9 +316,7 @@ class TorSettingsTab(QtWidgets.QWidget): self.autoconnect_checkbox = QtWidgets.QCheckBox( strings._("gui_enable_autoconnect_checkbox") ) - self.autoconnect_checkbox.toggled.connect( - self.autoconnect_toggled - ) + self.autoconnect_checkbox.toggled.connect(self.autoconnect_toggled) left_column_settings = QtWidgets.QVBoxLayout() connection_type_radio_group.setFixedHeight(300) left_column_settings.addWidget(connection_type_radio_group) @@ -327,7 +327,6 @@ class TorSettingsTab(QtWidgets.QWidget): left_column_setting_widget = QtWidgets.QWidget() left_column_setting_widget.setLayout(left_column_settings) - # The Bridges options are not exclusive (enabling Bridges offers obfs4 or custom bridges) connection_type_bridges_radio_group_layout = QtWidgets.QVBoxLayout() connection_type_bridges_radio_group_layout.addWidget(self.bridges) @@ -355,7 +354,7 @@ class TorSettingsTab(QtWidgets.QWidget): columns_wrapper.setLayout(columns_layout) # Tor connection widget - self.tor_con = TorConnectionWidget(self.common, self.status_bar, self.meek) + self.tor_con = TorConnectionWidget(self.common, self.status_bar) self.tor_con.success.connect(self.tor_con_success) self.tor_con.fail.connect(self.tor_con_fail) self.tor_con.hide()