diff --git a/onionshare/onion.py b/onionshare/onion.py index 05909a40..1e8d45e3 100644 --- a/onionshare/onion.py +++ b/onionshare/onion.py @@ -139,6 +139,9 @@ class Onion(object): # The tor process self.tor_proc = None + # Start out not connected to Tor + self.connected_to_tor = False + def connect(self, settings=False, tor_status_update_func=None): common.log('Onion', 'connect') @@ -332,6 +335,9 @@ class Onion(object): except AuthenticationFailure: raise TorErrorAuthError(strings._('settings_error_auth').format(self.settings.get('control_port_address'), self.settings.get('control_port_port'))) + # If we made it this far, we should be connected to Tor + self.connected_to_tor = True + # Get the tor version self.tor_version = self.c.get_version().version_str diff --git a/onionshare_gui/onionshare_gui.py b/onionshare_gui/onionshare_gui.py index 91ccc9ec..76811ccb 100644 --- a/onionshare_gui/onionshare_gui.py +++ b/onionshare_gui/onionshare_gui.py @@ -61,7 +61,7 @@ class OnionShareGui(QtWidgets.QMainWindow): self.settings.load() # Start the "Connecting to Tor" dialog, which calls onion.connect() - tor_con = TorConnectionDialog(self.settings, self.onion) + tor_con = TorConnectionDialog(self.qtapp, self.settings, self.onion) tor_con.canceled.connect(self._tor_connection_canceled) tor_con.open_settings.connect(self._tor_connection_open_settings) tor_con.start() diff --git a/onionshare_gui/tor_connection_dialog.py b/onionshare_gui/tor_connection_dialog.py index 5e072e8e..c0efd172 100644 --- a/onionshare_gui/tor_connection_dialog.py +++ b/onionshare_gui/tor_connection_dialog.py @@ -30,10 +30,11 @@ class TorConnectionDialog(QtWidgets.QProgressDialog): """ open_settings = QtCore.pyqtSignal() - def __init__(self, settings, onion): + def __init__(self, qtapp, settings, onion): super(TorConnectionDialog, self).__init__(None) common.log('TorConnectionDialog', '__init__') + self.qtapp = qtapp self.settings = settings self.onion = onion @@ -51,45 +52,53 @@ class TorConnectionDialog(QtWidgets.QProgressDialog): self.setMinimumDuration(100) # Start displaying the status at 0 - self.tor_status_update(0, '') + self._tor_status_update(0, '') def start(self): common.log('TorConnectionDialog', 'start') t = TorConnectionThread(self, self.settings, self.onion) - 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.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() - # Wait for the thread to start - time.sleep(0.1) + # The main thread needs to remain active, and checkign 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.qtapp.processEvents() - def tor_status_update(self, progress, summary): + def _tor_status_update(self, progress, summary): self.setValue(int(progress)) self.setLabelText("{}
{}".format(strings._('connecting_to_tor', True), summary)) - def connected_to_tor(self): - common.log('TorConnectionDialog', 'connected_to_tor') + def _connected_to_tor(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): - common.log('TorConnectionDialog', 'canceled_connecting_to_tor') + def _canceled_connecting_to_tor(self): + common.log('TorConnectionDialog', '_canceled_connecting_to_tor') + self.active = False # Cancel connecting to Tor self.cancel() - def error_connecting_to_tor(self): - common.log('TorConnectionDialog', 'error_connecting_to_tor') + def _error_connecting_to_tor(self, msg): + common.log('TorConnectionDialog', '_error_connecting_to_tor') + self.active = False # Cancel connecting to Tor self.cancel() # Display the exception in an alert box - Alert("{}\n\n{}".format(e.args[0], strings._('gui_tor_connection_error_settings', True)), QtWidgets.QMessageBox.Warning) + Alert("{}\n\n{}".format(msg, strings._('gui_tor_connection_error_settings', True)), QtWidgets.QMessageBox.Warning) # Open settings self.open_settings.emit() @@ -113,15 +122,18 @@ class TorConnectionThread(QtCore.QThread): # Connect to the Onion try: - common.log('TorConnectionThread', 'run', 'about to run onion.connect') self.onion.connect(self.settings, self._tor_status_update) - common.log('TorConnectionThread', 'run', 'onion.connect succeeded') - self.connected_to_tor.emit() + if self.onion.connected_to_tor: + self.connected_to_tor.emit() + else: + self.error_connecting_to_tor.emit(strings._('settings_error_unknown_error', True)) except BundledTorCanceled as e: - self.canceled_connecting_to_tor.emit() + common.log('TorConnectionThread', 'run', 'caught exception: BundledTorCanceled') + self.canceled_connecting_to_tor.emit(strings._('settings_error_bundled_tor_canceled')) except Exception as e: + common.log('TorConnectionThread', 'run', 'caught exception: {}'.format(e.args[0])) self.error_connecting_to_tor.emit(e.args[0]) def _tor_status_update(self, progress, summary): diff --git a/share/locale/en.json b/share/locale/en.json index cd346868..3cf17548 100644 --- a/share/locale/en.json +++ b/share/locale/en.json @@ -91,8 +91,10 @@ "settings_error_auth": "Connected to {}:{}, but can't authenticate. Maybe this isn't a Tor controller?", "settings_error_missing_password": "Connected to Tor controller, but it requires a password to authenticate.", "settings_error_unreadable_cookie_file": "Connected to Tor controller, but can't authenticate because your password may be wrong, and your user doesn't have permission to read the cookie file.", - "settings_error_bundled_tor_not_supported": "Bundled Tor is only supported in Windows and macOS. It's not supported when not using developer mode or the command line interface.", - "settings_error_bundled_tor_timeout": "Connecting to Tor is taking too long. Make sure you're online and your clock is accurate, then try again.", + "settings_error_bundled_tor_not_supported": "Bundled Tor is not supported when not using developer mode in Windows or macOS.", + "settings_error_bundled_tor_timeout": "Connecting to Tor is taking too long. Maybe your computer is offline, or your clock isn't accurate.", + "settings_error_bundled_tor_canceled": "The Tor process closed before it could finish connecting.", + "settings_error_unknown_error": "Failed connecting to Tor for an unknown reasons.", "settings_test_success": "Congratulations, OnionShare can connect to the Tor controller.\n\nTor version: {}\nSupports ephemeral onion services: {}\nSupports stealth onion services: {}", "error_tor_protocol_error": "Error talking to the Tor controller.\nIf you're using Whonix, check out https://www.whonix.org/wiki/onionshare to make OnionShare work.", "connecting_to_tor": "Connecting to the Tor network",