Make automatic detection flip through country names while it's running meek

This commit is contained in:
Micah Lee 2021-12-06 20:54:03 -08:00
parent feaecc9e4d
commit 8416d089f4
No known key found for this signature in database
GPG key ID: 403C2657CD994F73
7 changed files with 96 additions and 217 deletions

View file

@ -115,7 +115,6 @@ class Settings(object):
"persistent_tabs": [],
"locale": None, # this gets defined in fill_in_defaults()
"theme": 0,
"censorship_circumvention": False,
}
self._settings = {}
self.fill_in_defaults()

View file

@ -20,6 +20,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import json
import os
import random
from PySide2 import QtCore, QtWidgets, QtGui
from onionshare_cli.settings import Settings
@ -75,13 +76,15 @@ class AutoConnectTab(QtWidgets.QWidget):
# First launch widget
self.first_launch_widget = AutoConnectFirstLaunchWidget(self.common)
self.first_launch_widget.toggle_auto_connect.connect(self.toggle_auto_connect)
self.first_launch_widget.connect_clicked.connect(self.connect_clicked)
self.first_launch_widget.connect_clicked.connect(
self.first_launch_widget_connect_clicked
)
self.first_launch_widget.open_tor_settings.connect(self.open_tor_settings)
self.first_launch_widget.show()
# Use bridge widget
self.use_bridge_widget = AutoConnectUseBridgeWidget(self.common)
self.use_bridge_widget.connect_clicked.connect(self.connect_clicked)
self.use_bridge_widget.connect_clicked.connect(self.use_bridge_connect_clicked)
self.use_bridge_widget.back_clicked.connect(self.back_clicked)
self.use_bridge_widget.open_tor_settings.connect(self.open_tor_settings)
self.use_bridge_widget.hide()
@ -119,7 +122,7 @@ class AutoConnectTab(QtWidgets.QWidget):
self.first_launch_widget.enable_autoconnect_checkbox.setCheckState(
QtCore.Qt.Checked
)
self.connect_clicked()
self.first_launch_widget_connect_clicked()
def toggle_auto_connect(self):
"""
@ -135,17 +138,12 @@ class AutoConnectTab(QtWidgets.QWidget):
def open_tor_settings(self):
self.parent.open_tor_settings_tab()
def connect_clicked(self):
def first_launch_widget_connect_clicked(self):
"""
Connect button clicked. Try to connect to tor.
Connect button in first launch widget clicked. Try to connect to tor.
"""
self.common.log("AutoConnectTab", "connect_clicked")
# Hide the buttons
if self.first_launch_widget.isVisible():
self.first_launch_widget.hide_buttons()
elif self.use_bridge_widget.isVisible():
self.use_bridge_widget.hide_buttons()
self.common.log("AutoConnectTab", "first_launch_widget_connect_clicked")
self.first_launch_widget.hide_buttons()
if not self.common.gui.local_only:
self.tor_con.show()
@ -153,6 +151,33 @@ class AutoConnectTab(QtWidgets.QWidget):
else:
self.close_this_tab.emit()
def use_bridge_connect_clicked(self):
"""
Connect button in use bridge widget clicked.
"""
self.common.log(
"AutoConnectTab",
"use_bridge_connect_clicked",
"Trying to automatically obtain bridges",
)
self.use_bridge_widget.hide_buttons()
self.use_bridge_widget.start_autodetecting_location()
# 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()
def back_clicked(self):
"""
Switch from use bridge widget back to first launch widget
@ -174,7 +199,7 @@ class AutoConnectTab(QtWidgets.QWidget):
# Close the tab
self.close_this_tab.emit()
def tor_con_fail(self, msg):
def tor_con_fail(self):
"""
Finished testing tor connection.
"""
@ -312,6 +337,11 @@ class AutoConnectUseBridgeWidget(QtWidgets.QWidget):
for country_code in countries:
self.country_combobox.addItem(countries[country_code], country_code)
# Task label
self.task_label = QtWidgets.QLabel()
self.task_label.setStyleSheet(common.gui.css["enable_autoconnect"])
self.task_label.hide()
# Buttons
self.connect_button = QtWidgets.QPushButton(
strings._("gui_autoconnect_bridge_start")
@ -346,6 +376,7 @@ class AutoConnectUseBridgeWidget(QtWidgets.QWidget):
layout.addWidget(description_label)
layout.addLayout(detect_layout)
layout.addWidget(self.country_combobox)
layout.addWidget(self.task_label)
layout.addWidget(cta_widget)
self.setLayout(layout)
@ -353,12 +384,39 @@ class AutoConnectUseBridgeWidget(QtWidgets.QWidget):
def hide_buttons(self):
self.connect_button.hide()
self.back_button.hide()
self.configure_button.hide()
def show_buttons(self):
self.connect_button.show()
self.back_button.show()
self.configure_button.show()
def start_autodetecting_location(self):
self.detect_automatic_radio.setEnabled(False)
self.detect_manual_radio.setEnabled(False)
self.country_combobox.setEnabled(False)
self.country_combobox.show()
# 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 _autodetecting_timer_callback(self):
new_index = random.randrange(0, self.country_combobox.count())
self.country_combobox.setCurrentIndex(new_index)
def _detect_automatic_toggled(self):
self.country_combobox.setEnabled(False)
self.country_combobox.hide()

View file

@ -40,6 +40,7 @@ from onionshare_cli.onion import (
TorTooOldStealth,
PortNotAvailable,
)
from onionshare_cli.meek import Meek
class GuiCommon:
@ -78,6 +79,9 @@ class GuiCommon:
os.makedirs(self.events_dir, 0o700, True)
self.events_filename = os.path.join(self.events_dir, "events")
# Instantiate Meek, which is used to bypass censorship
self.meek = Meek(self.common, get_tor_paths=self.get_tor_paths)
self.css = self.get_css(qtapp.color_mode)
self.color_mode = qtapp.color_mode
@ -185,6 +189,11 @@ class GuiCommon:
color: #666666;
}
""",
"autoconnect_task_label": """
QLabel {
font-weight: bold;
}
""",
# Common styles between modes and their child widgets
"mode_settings_toggle_advanced": """
QPushButton {

View file

@ -26,10 +26,10 @@ from . import strings
from .widgets import Alert
from .update_checker import UpdateThread
from .tab_widget import TabWidget
from .settings_tab import SettingsTab
from .gui_common import GuiCommon
from .threads import OnionCleanupThread
from onionshare_cli.meek import Meek
class MainWindow(QtWidgets.QMainWindow):
"""
@ -53,7 +53,7 @@ class MainWindow(QtWidgets.QMainWindow):
self.settings_action = menu.addAction(strings._("gui_settings_window_title"))
self.settings_action.triggered.connect(self.open_settings)
self.help_action = menu.addAction(strings._("gui_settings_button_help"))
self.help_action.triggered.connect(lambda: SettingsDialog.help_clicked(self))
self.help_action.triggered.connect(lambda: SettingsTab.open_help())
exit_action = menu.addAction(strings._("systray_menu_exit"))
exit_action.triggered.connect(self.close)
@ -160,23 +160,6 @@ class MainWindow(QtWidgets.QMainWindow):
self.setCentralWidget(central_widget)
self.show()
<<<<<<< HEAD
=======
# Instantiate Meek, which the TorConnectionDialog may use to resolve
# connection issues by automatically obtaining bridges.
self.meek = Meek(self.common, get_tor_paths=self.common.gui.get_tor_paths)
# Start the "Connecting to Tor" dialog, which calls onion.connect()
tor_con = TorConnectionDialog(self.common, self.meek)
tor_con.canceled.connect(self.tor_connection_canceled)
tor_con.open_tor_settings.connect(self.tor_connection_open_tor_settings)
if not self.common.gui.local_only:
tor_con.start()
self.settings_have_changed()
# After connecting to Tor, check for updates
self.check_for_updates()
>>>>>>> mig5-censorship_automatically_attempt_and_reconnect
# Create the close warning dialog -- the dialog widget needs to be in the constructor
# in order to test it
self.close_dialog = QtWidgets.QMessageBox()

View file

@ -45,12 +45,13 @@
"gui_autoconnect_description": "OnionShare relies on the Tor Network, run by thousands of volunteers around the world.",
"gui_enable_autoconnect_checkbox": "Enable automatically connecting to Tor",
"gui_autoconnect_bridge_description": "<b>Failed connecting to Tor.</b> This could be because your internet is being censored. You might be able to bypass this censorship by using a bridge.",
"gui_autoconnect_bridge_detect_automatic": "Automatically determine my location to bypass country-specific censorship",
"gui_autoconnect_bridge_detect_automatic": "Automatically determine my country to bypass country-specific censorship",
"gui_autoconnect_bridge_detect_manual": "Manually select my country",
"gui_autoconnect_start": "Connect to Tor",
"gui_autoconnect_configure": "Network Settings",
"gui_autoconnect_bridge_start": "Use a Bridge",
"gui_autoconnect_bridge_back": "Back",
"gui_autoconnect_task_detect_location": "Automatically determining your country...",
"gui_settings_window_title": "Settings",
"gui_settings_autoupdate_label": "Check for new version",
"gui_settings_autoupdate_option": "Notify me when a new version is available",
@ -243,4 +244,4 @@
"moat_captcha_error": "The solution is not correct. Please try again.",
"moat_solution_empty_error": "You must enter the characters from the image",
"mode_tor_not_connected_label": "OnionShare is not connected to the Tor network"
}
}

View file

@ -168,7 +168,7 @@ class TabWidget(QtWidgets.QTabWidget):
self.add_tab()
else:
self.open_connection_tab()
def check_autoconnect_tab(self):
if type(self.tabs[0]) is AutoConnectTab:
self.tabs[0].check_autoconnect()
@ -218,7 +218,9 @@ class TabWidget(QtWidgets.QTabWidget):
self.setCurrentIndex(self.indexOf(self.tabs[tab_id]))
return
connection_tab = AutoConnectTab(self.common, self.current_tab_id, self.status_bar, parent=self)
connection_tab = AutoConnectTab(
self.common, self.current_tab_id, self.status_bar, parent=self
)
connection_tab.close_this_tab.connect(self.close_connection_tab)
self.tabs[self.current_tab_id] = connection_tab
self.current_tab_id += 1

View file

@ -39,153 +39,9 @@ from onionshare_cli.onion import (
)
from . import strings
from .gui_common import GuiCommon
from .widgets import Alert
from onionshare_cli.censorship import CensorshipCircumvention
class TorConnectionDialog(QtWidgets.QProgressDialog):
"""
Connecting to Tor dialog.
"""
open_tor_settings = QtCore.Signal()
success = QtCore.Signal()
def __init__(
self, common, meek, custom_settings=False, testing_settings=False, onion=None
):
super(TorConnectionDialog, self).__init__(None)
self.common = common
self.testing_settings = testing_settings
self.meek = meek
if custom_settings:
self.settings = custom_settings
else:
self.settings = self.common.settings
self.common.log("TorConnectionDialog", "__init__")
if self.testing_settings:
self.title = strings._("gui_settings_connection_type_test_button")
self.onion = onion
else:
self.title = "OnionShare"
self.onion = self.common.gui.onion
self.setWindowTitle(self.title)
self.setWindowIcon(QtGui.QIcon(GuiCommon.get_resource_path("images/logo.png")))
self.setModal(True)
self.setFixedSize(400, 150)
# Label
self.setLabelText(strings._("connecting_to_tor"))
# Progress bar ticks from 0 to 100
self.setRange(0, 100)
# Don't show if connection takes less than 100ms (for non-bundled tor)
self.setMinimumDuration(100)
# Start displaying the status at 0
self._tor_status_update(0, "")
def start(self):
self.common.log("TorConnectionDialog", "start")
t = TorConnectionThread(self.common, self.settings, self)
t.tor_status_update.connect(self._tor_status_update)
t.connected_to_tor.connect(self._connected_to_tor)
t.canceled_connecting_to_tor.connect(self._canceled_connecting_to_tor)
t.error_connecting_to_tor.connect(self._error_connecting_to_tor)
t.start()
# The main thread needs to remain active, and checking for Qt events,
# until the thread is finished. Otherwise it won't be able to handle
# accepting signals.
self.active = True
while self.active:
time.sleep(0.1)
self.common.gui.qtapp.processEvents()
def _tor_status_update(self, progress, summary):
self.setValue(int(progress))
self.setLabelText(
f"<strong>{strings._('connecting_to_tor')}</strong><br>{summary}"
)
def _connected_to_tor(self):
self.common.log("TorConnectionDialog", "_connected_to_tor")
self.active = False
# Close the dialog after connecting
self.setValue(self.maximum())
def _canceled_connecting_to_tor(self):
self.common.log("TorConnectionDialog", "_canceled_connecting_to_tor")
self.active = False
self.onion.cleanup()
# Cancel connecting to Tor
QtCore.QTimer.singleShot(1, self.cancel)
def _error_connecting_to_tor(self, msg):
self.common.log("TorConnectionDialog", "_error_connecting_to_tor")
self.active = False
if self.testing_settings:
# If testing, just display the error but don't open settings
def alert():
Alert(self.common, msg, QtWidgets.QMessageBox.Warning, title=self.title)
# If we are allowed to try automatically resolving connection issues
# (e.g possible censorship) by obtaining bridges for the user, do so
elif self.settings.get("censorship_circumvention"):
def alert():
return
# Automatically try to obtain bridges from the Censorship Circumvention API
self.common.log(
"TorConnectionDialog",
"_error_connecting_to_tor",
"Trying to automatically obtain bridges",
)
self.meek.start()
self.censorship_circumvention = CensorshipCircumvention(
self.common, self.meek
)
bridge_settings = self.censorship_circumvention.request_settings(
country="tm"
)
self.meek.cleanup()
if bridge_settings and self.censorship_circumvention.save_settings(
self.settings, bridge_settings
):
# Try and connect again
self.start()
else:
# If not testing, open settings after displaying the error
def alert():
Alert(
self.common,
f"{msg}\n\n{strings._('gui_tor_connection_error_settings')}",
QtWidgets.QMessageBox.Warning,
title=self.title,
)
# Open settings
self.open_tor_settings.emit()
QtCore.QTimer.singleShot(1, alert)
# Cancel connecting to Tor
QtCore.QTimer.singleShot(1, self.cancel)
class TorConnectionWidget(QtWidgets.QWidget):
"""
Connecting to Tor widget, with a progress bar
@ -193,9 +49,9 @@ class TorConnectionWidget(QtWidgets.QWidget):
open_tor_settings = QtCore.Signal()
success = QtCore.Signal()
fail = QtCore.Signal(str)
fail = QtCore.Signal()
def __init__(self, common, status_bar, meek):
def __init__(self, common, status_bar):
super(TorConnectionWidget, self).__init__(None)
self.common = common
self.common.log("TorConnectionWidget", "__init__")
@ -211,8 +67,6 @@ class TorConnectionWidget(QtWidgets.QWidget):
)
self.cancel_button.clicked.connect(self.cancel_clicked)
self.meek = meek
progress_layout = QtWidgets.QHBoxLayout()
progress_layout.addWidget(self.progress)
progress_layout.addWidget(self.cancel_button)
@ -259,7 +113,7 @@ class TorConnectionWidget(QtWidgets.QWidget):
def cancel_clicked(self):
self.was_canceled = True
self.fail.emit("")
self.fail.emit()
def wasCanceled(self):
return self.was_canceled
@ -288,44 +142,17 @@ class TorConnectionWidget(QtWidgets.QWidget):
# Cancel connecting to Tor
QtCore.QTimer.singleShot(1, self.cancel_clicked)
def _error_connecting_to_tor(self, msg):
def _error_connecting_to_tor(self):
self.common.log("TorConnectionWidget", "_error_connecting_to_tor")
self.active = False
# If we are allowed to try automatically resolving connection issues
# (e.g possible censorship) by obtaining bridges for the user, do so
if self.settings.get("censorship_circumvention"):
# Automatically try to obtain bridges from the Censorship Circumvention API
self.common.log(
"TorConnectionWidget",
"_error_connecting_to_tor",
"Trying to automatically obtain bridges",
)
self.meek.start()
self.censorship_circumvention = CensorshipCircumvention(
self.common, self.meek
)
bridge_settings = self.censorship_circumvention.request_settings(
country="tm"
)
self.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()
else:
self.fail.emit()
self.fail.emit()
class TorConnectionThread(QtCore.QThread):
tor_status_update = QtCore.Signal(str, str)
connected_to_tor = QtCore.Signal()
canceled_connecting_to_tor = QtCore.Signal()
error_connecting_to_tor = QtCore.Signal(str)
error_connecting_to_tor = QtCore.Signal()
def __init__(self, common, settings, parent):
super(TorConnectionThread, self).__init__()
@ -370,7 +197,7 @@ class TorConnectionThread(QtCore.QThread):
self.common.log(
"TorConnectionThread", "run", f"caught exception: {message}"
)
self.error_connecting_to_tor.emit(message)
self.error_connecting_to_tor.emit()
def _tor_status_update(self, progress, summary):
self.tor_status_update.emit(progress, summary)