diff --git a/onionshare/onion.py b/onionshare/onion.py index 887650c9..068648ba 100644 --- a/onionshare/onion.py +++ b/onionshare/onion.py @@ -488,8 +488,8 @@ class Onion(object): auth_cookie = list(res.client_auth.values())[0] self.auth_string = 'HidServAuth {} {}'.format(onion_host, auth_cookie) - self.settings.save() if onion_host is not None: + self.settings.save() return onion_host else: raise TorErrorProtocolError(strings._('error_tor_protocol_error')) @@ -500,13 +500,19 @@ class Onion(object): """ common.log('Onion', 'cleanup') - # Cleanup the ephemeral onion service - if self.service_id: - try: - self.c.remove_ephemeral_hidden_service(self.service_id) - except: - pass - self.service_id = None + # Cleanup the ephemeral onion services, if we have any + try: + onions = self.c.list_ephemeral_hidden_services() + for onion in onions: + try: + common.log('Onion', 'cleanup', 'trying to remove onion {}'.format(onion)) + self.c.remove_ephemeral_hidden_service(onion) + except: + common.log('Onion', 'cleanup', 'could not remove onion {}.. moving on anyway'.format(onion)) + pass + except: + pass + self.service_id = None if stop_tor: # Stop tor process diff --git a/onionshare_gui/onionshare_gui.py b/onionshare_gui/onionshare_gui.py index 4f664225..5df87dc0 100644 --- a/onionshare_gui/onionshare_gui.py +++ b/onionshare_gui/onionshare_gui.py @@ -78,6 +78,9 @@ class OnionShareGui(QtWidgets.QMainWindow): self.server_status.server_stopped.connect(self.stop_server) self.server_status.server_stopped.connect(self.update_server_status_indicator) self.server_status.server_stopped.connect(self.update_primary_action) + self.server_status.server_canceled.connect(self.cancel_server) + self.server_status.server_canceled.connect(self.file_selection.server_stopped) + self.server_status.server_canceled.connect(self.update_primary_action) self.start_server_finished.connect(self.clear_message) self.start_server_finished.connect(self.server_status.start_server_finished) self.start_server_finished.connect(self.update_server_status_indicator) @@ -398,9 +401,10 @@ class OnionShareGui(QtWidgets.QMainWindow): # wait for modules in thread to load, preventing a thread-related cx_Freeze crash time.sleep(0.2) - t = threading.Thread(target=start_onion_service, kwargs={'self': self}) - t.daemon = True - t.start() + common.log('OnionshareGui', 'start_server', 'Starting an onion thread') + self.t = OnionThread(function=start_onion_service, kwargs={'self': self}) + self.t.daemon = True + self.t.start() def start_server_step2(self): """ @@ -483,6 +487,14 @@ class OnionShareGui(QtWidgets.QMainWindow): self._zip_progress_bar = None self.status_bar.clearMessage() + def cancel_server(self): + """ + Cancel the server while it is preparing to start + """ + if self.t: + self.t.quit() + self.stop_server() + def stop_server(self): """ Stop the onionshare server. @@ -777,3 +789,26 @@ class ZipProgressBar(QtWidgets.QProgressBar): self.setValue(100) else: self.setValue(0) + + +class OnionThread(QtCore.QThread): + """ + A QThread for starting our Onion Service. + By using QThread rather than threading.Thread, we are able + to call quit() or terminate() on the startup if the user + decided to cancel (in which case do not proceed with obtaining + the Onion address and starting the web server). + """ + def __init__(self, function, kwargs=None): + super(OnionThread, self).__init__() + common.log('OnionThread', '__init__') + self.function = function + if not kwargs: + self.kwargs = {} + else: + self.kwargs = kwargs + + def run(self): + common.log('OnionThread', 'run') + + self.function(**self.kwargs) diff --git a/onionshare_gui/server_status.py b/onionshare_gui/server_status.py index 6c5cc080..03540415 100644 --- a/onionshare_gui/server_status.py +++ b/onionshare_gui/server_status.py @@ -29,6 +29,7 @@ class ServerStatus(QtWidgets.QWidget): """ server_started = QtCore.pyqtSignal() server_stopped = QtCore.pyqtSignal() + server_canceled = QtCore.pyqtSignal() button_clicked = QtCore.pyqtSignal() url_copied = QtCore.pyqtSignal() hidservauth_copied = QtCore.pyqtSignal() @@ -190,7 +191,7 @@ class ServerStatus(QtWidgets.QWidget): self.server_button.setToolTip(strings._('gui_stop_server_shutdown_timeout_tooltip', True).format(self.timeout)) elif self.status == self.STATUS_WORKING: self.server_button.setStyleSheet(button_working_style) - self.server_button.setEnabled(False) + self.server_button.setEnabled(True) self.server_button.setText(strings._('gui_please_wait')) if self.settings.get('shutdown_timeout'): self.shutdown_timeout_container.hide() @@ -218,6 +219,8 @@ class ServerStatus(QtWidgets.QWidget): self.start_server() elif self.status == self.STATUS_STARTED: self.stop_server() + elif self.status == self.STATUS_WORKING: + self.cancel_server() self.button_clicked.emit() def start_server(self): @@ -245,6 +248,16 @@ class ServerStatus(QtWidgets.QWidget): self.update() self.server_stopped.emit() + def cancel_server(self): + """ + Cancel the server. + """ + common.log('ServerStatus', 'cancel_server', 'Canceling the server mid-startup') + self.status = self.STATUS_WORKING + self.shutdown_timeout_reset() + self.update() + self.server_canceled.emit() + def stop_server_finished(self): """ The server has finished stopping. diff --git a/share/locale/en.json b/share/locale/en.json index 3c426c67..6cd5b4e2 100644 --- a/share/locale/en.json +++ b/share/locale/en.json @@ -52,7 +52,7 @@ "gui_copied_hidservauth": "The HidServAuth line has been copied to clipboard", "gui_starting_server1": "Starting Tor onion service...", "gui_starting_server2": "Crunching files...", - "gui_please_wait": "Please wait...", + "gui_please_wait": "Starting... Click to cancel", "error_hs_dir_cannot_create": "Cannot create onion service dir {0:s}", "error_hs_dir_not_writable": "onion service dir {0:s} is not writable", "using_ephemeral": "Starting ephemeral Tor onion service and awaiting publication",