def __init__(self, dialog, settings, onion): super(TorConnectionThread, self).__init__() common.log('TorConnectionThread', '__init__') self.dialog = dialog self.settings = settings self.onion = onion
def test_tor_clicked(self): """ Test Tor Settings button clicked. With the given settings, see if we can successfully connect and authenticate to Tor. """ common.log('SettingsDialog', 'test_tor_clicked') settings = self.settings_from_fields() try: # Show Tor connection status if connection type is bundled tor if settings.get('connection_type') == 'bundled': self.tor_status.show() self._disable_buttons() def tor_status_update_func(progress, summary): self._tor_status_update(progress, summary) return True else: tor_status_update_func = None onion = Onion() onion.connect(settings=settings, config=self.config, tor_status_update_func=tor_status_update_func) # If an exception hasn't been raised yet, the Tor settings work Alert(strings._('settings_test_success', True).format(onion.tor_version, onion.supports_ephemeral, onion.supports_stealth)) # Clean up onion.cleanup() except (TorErrorInvalidSetting, TorErrorAutomatic, TorErrorSocketPort, TorErrorSocketFile, TorErrorMissingPassword, TorErrorUnreadableCookieFile, TorErrorAuthError, TorErrorProtocolError, BundledTorNotSupported, BundledTorTimeout) as e: Alert(e.args[0], QtWidgets.QMessageBox.Warning) if settings.get('connection_type') == 'bundled': self.tor_status.hide() self._enable_buttons()
def start_server_step2(self): """ Step 2 in starting the onionshare server. Zipping up files. """ common.log('OnionShareGui', 'start_server_step2') # add progress bar to the status bar, indicating the crunching of files. self._zip_progress_bar = ZipProgressBar(0) self._zip_progress_bar.total_files_size = OnionShareGui._compute_total_size( self.file_selection.file_list.filenames) self.status_bar.clearMessage() self.status_bar.insertWidget(0, self._zip_progress_bar) # prepare the files for sending in a new thread def finish_starting_server(self): # prepare files to share def _set_processed_size(x): if self._zip_progress_bar != None: self._zip_progress_bar.update_processed_size_signal.emit(x) web.set_file_info(self.file_selection.file_list.filenames, processed_size_callback=_set_processed_size) self.app.cleanup_filenames.append(web.zip_filename) self.starting_server_step3.emit() # done self.start_server_finished.emit() #self.status_bar.showMessage(strings._('gui_starting_server2', True)) t = threading.Thread(target=finish_starting_server, kwargs={'self': self}) t.daemon = True t.start()
def copy_hidservauth(self): """ When the stealth onion service HidServAuth gets copied to the clipboard, display this in the status bar. """ common.log('OnionShareGui', 'copy_hidservauth') if self.systemTray.supportsMessages() and self.settings.get('systray_notifications'): self.systemTray.showMessage(strings._('gui_copied_hidservauth_title', True), strings._('gui_copied_hidservauth', True))
def _disable_buttons(self): common.log('SettingsDialog', '_disable_buttons') self.check_for_updates_button.setEnabled(False) self.connection_type_test_button.setEnabled(False) self.save_button.setEnabled(False) self.cancel_button.setEnabled(False)
def _tor_connection_canceled(self): """ If the user cancels before Tor finishes connecting, ask if they want to quit, or open settings. """ common.log('OnionShareGui', '_tor_connection_canceled') def ask(): a = Alert(strings._('gui_tor_connection_ask', True), QtWidgets.QMessageBox.Question, buttons=QtWidgets.QMessageBox.NoButton, autostart=False) settings_button = QtWidgets.QPushButton(strings._('gui_tor_connection_ask_open_settings', True)) quit_button = QtWidgets.QPushButton(strings._('gui_tor_connection_ask_quit', True)) a.addButton(settings_button, QtWidgets.QMessageBox.AcceptRole) a.addButton(quit_button, QtWidgets.QMessageBox.RejectRole) a.setDefaultButton(settings_button) a.exec_() if a.clickedButton() == settings_button: # Open settings common.log('OnionShareGui', '_tor_connection_canceled', 'Settings button clicked') self.open_settings() if a.clickedButton() == quit_button: # Quit common.log('OnionShareGui', '_tor_connection_canceled', 'Quit button clicked') # Wait 1ms for the event loop to finish, then quit QtCore.QTimer.singleShot(1, self.qtapp.quit) # Wait 100ms before asking QtCore.QTimer.singleShot(100, ask)
def help_clicked(self): """ Help button clicked. """ common.log('SettingsDialog', 'help_clicked') help_site = 'https://github.com/micahflee/onionshare/wiki' QtGui.QDesktopServices.openUrl(QtCore.QUrl(help_site))
def start_server_step3(self): """ Step 3 in starting the onionshare server. This displays the large filesize warning, if applicable. """ common.log('OnionShareGui', 'start_server_step3') # Remove zip progress bar if self._zip_progress_bar is not None: self.status_bar.removeWidget(self._zip_progress_bar) self._zip_progress_bar = None # warn about sending large files over Tor if web.zip_filesize >= 157286400: # 150mb self.filesize_warning.setText(strings._("large_filesize", True)) self.filesize_warning.show() if self.settings.get('shutdown_timeout'): # Convert the date value to seconds between now and then now = QtCore.QDateTime.currentDateTime() self.timeout = now.secsTo(self.server_status.timeout) # Set the shutdown timeout value if self.timeout > 0: self.app.shutdown_timer = common.close_after_seconds(self.timeout) self.app.shutdown_timer.start() # The timeout has actually already passed since the user clicked Start. Probably the Onion service took too long to start. else: self.stop_server() self.start_server_error(strings._('gui_server_started_after_timeout'))
def start_server_step2(self): """ Step 2 in starting the onionshare server. Zipping up files. """ common.log('OnionShareGui', 'start_server_step2') # add progress bar to the status bar, indicating the crunching of files. self._zip_progress_bar = ZipProgressBar(0) self.filenames = [] for index in range(self.file_selection.file_list.count()): self.filenames.append(self.file_selection.file_list.item(index).filename) self._zip_progress_bar.total_files_size = OnionShareGui._compute_total_size(self.filenames) self.status_bar.insertWidget(0, self._zip_progress_bar) # prepare the files for sending in a new thread def finish_starting_server(self): # prepare files to share def _set_processed_size(x): if self._zip_progress_bar != None: self._zip_progress_bar.update_processed_size_signal.emit(x) try: web.set_file_info(self.filenames, processed_size_callback=_set_processed_size) self.app.cleanup_filenames.append(web.zip_filename) self.starting_server_step3.emit() # done self.start_server_finished.emit() except OSError as e: self.starting_server_error.emit(e.strerror) return t = threading.Thread(target=finish_starting_server, kwargs={'self': self}) t.daemon = True t.start()
def check_for_updates(self): """ Check for Updates button clicked. Manually force an update check. """ common.log('SettingsDialog', 'check_for_updates') # Disable buttons self._disable_buttons() self.qtapp.processEvents() # Check for updates def update_available(update_url, installed_version, latest_version): Alert(strings._("update_available", True).format(update_url, installed_version, latest_version)) def update_not_available(): Alert(strings._('update_not_available', True)) u = UpdateChecker(self.onion) u.update_available.connect(update_available) u.update_not_available.connect(update_not_available) try: u.check(force=True) except UpdateCheckerCheckError: Alert(strings._('update_error_check_error', True), QtWidgets.QMessageBox.Warning) except UpdateCheckerInvalidLatestVersion as e: Alert(strings._('update_error_invalid_latest_version', True).format(e.latest_version), QtWidgets.QMessageBox.Warning) # Enable buttons self._enable_buttons() # Update the last checked label settings = Settings(self.config) settings.load() autoupdate_timestamp = settings.get('autoupdate_timestamp') self._update_autoupdate_timestamp(autoupdate_timestamp)
def open_settings(self): """ Open the SettingsDialog. """ common.log('OnionShareGui', 'open_settings') def reload_settings(): common.log('OnionShareGui', 'open_settings', 'settings have changed, reloading') self.settings.load() # We might've stopped the main requests timer if a Tor connection failed. # If we've reloaded settings, we probably succeeded in obtaining a new # connection. If so, restart the timer. if self.onion.is_authenticated(): if not self.timer.isActive(): self.timer.start(500) # If there were some files listed for sharing, we should be ok to # re-enable the 'Start Sharing' button now. if self.server_status.file_selection.get_num_files() > 0: self.server_status.server_button.setEnabled(True) self.status_bar.clearMessage() # If we switched off the shutdown timeout setting, ensure the widget is hidden. if not self.settings.get('shutdown_timeout'): self.server_status.shutdown_timeout_container.hide() d = SettingsDialog(self.onion, self.qtapp, self.config) d.settings_saved.connect(reload_settings) d.exec_() # When settings close, refresh the server status UI self.server_status.update()
def copy_url(self): """ When the URL gets copied to the clipboard, display this in the status bar. """ common.log('OnionShareGui', 'copy_url') if self.systemTray.supportsMessages() and self.settings.get('systray_notifications'): self.systemTray.showMessage(strings._('gui_copied_url_title', True), strings._('gui_copied_url', True))
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 hidservauth_copy_button_clicked(self): """ Toggle the 'Copy HidServAuth' button to copy the saved HidServAuth to clipboard. """ common.log('SettingsDialog', 'hidservauth_copy_button_clicked', 'HidServAuth was copied to clipboard') clipboard = self.qtapp.clipboard() clipboard.setText(self.old_settings.get('hidservauth_string'))
def _tor_connection_open_settings(self): """ The TorConnectionDialog wants to open the Settings dialog """ common.log('OnionShareGui', '_tor_connection_open_settings') # Wait 1ms for the event loop to finish closing the TorConnectionDialog QtCore.QTimer.singleShot(1, self.open_settings)
def connection_type_automatic_toggled(self, checked): """ Connection type automatic was toggled. If checked, hide authentication fields. """ common.log('SettingsDialog', 'connection_type_automatic_toggled') if checked: self.authenticate_group.hide() self.connection_type_socks.hide()
def save_clicked(self): """ Save button clicked. Save current settings to disk. """ common.log('SettingsDialog', 'save_clicked') settings = self.settings_from_fields() if settings: settings.save() # If Tor isn't connected, or if Tor settings have changed, Reinitialize # the Onion object reboot_onion = False if self.onion.is_authenticated(): common.log('SettingsDialog', 'save_clicked', 'Connected to Tor') def changed(s1, s2, keys): """ Compare the Settings objects s1 and s2 and return true if any values have changed for the given keys. """ for key in keys: if s1.get(key) != s2.get(key): return True return False if changed(settings, self.old_settings, [ 'connection_type', 'control_port_address', 'control_port_port', 'socks_address', 'socks_port', 'socket_file_path', 'auth_type', 'auth_password', 'no_bridges', 'tor_bridges_use_obfs4', 'tor_bridges_use_meek_lite_amazon', 'tor_bridges_use_meek_lite_azure', 'tor_bridges_use_custom_bridges']): reboot_onion = True else: common.log('SettingsDialog', 'save_clicked', 'Not connected to Tor') # Tor isn't connected, so try connecting reboot_onion = True # Do we need to reinitialize Tor? if reboot_onion: # Reinitialize the Onion object common.log('SettingsDialog', 'save_clicked', 'rebooting the Onion') self.onion.cleanup() tor_con = TorConnectionDialog(self.qtapp, settings, self.onion) tor_con.start() common.log('SettingsDialog', 'save_clicked', 'Onion done rebooting, connected to Tor: {}'.format(self.onion.connected_to_tor)) if self.onion.is_authenticated() and not tor_con.wasCanceled(): self.settings_saved.emit() self.close() else: self.settings_saved.emit() self.close()
def connection_type_bundled_toggled(self, checked): """ Connection type bundled was toggled. If checked, hide authentication fields. """ common.log('SettingsDialog', 'connection_type_bundled_toggled') if checked: self.authenticate_group.hide() self.connection_type_socks.hide() self.connection_type_bridges_radio_group.show()
def _update_autoupdate_timestamp(self, autoupdate_timestamp): common.log('SettingsDialog', '_update_autoupdate_timestamp') if autoupdate_timestamp: dt = datetime.datetime.fromtimestamp(autoupdate_timestamp) last_checked = dt.strftime('%B %d, %Y %H:%M') else: last_checked = strings._('gui_settings_autoupdate_timestamp_never', True) self.autoupdate_timestamp.setText(strings._('gui_settings_autoupdate_timestamp', True).format(last_checked))
def closeEvent(self, e): common.log('SettingsDialog', 'closeEvent') # On close, if Tor isn't connected, then quit OnionShare altogether if not self.onion.is_authenticated(): common.log('SettingsDialog', 'closeEvent', 'Closing while not connected to Tor') # Wait 1ms for the event loop to finish, then quit QtCore.QTimer.singleShot(1, self.qtapp.quit)
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 _enable_buttons(self): common.log('SettingsDialog', '_enable_buttons') # We can't check for updates if we're still not connected to Tor if not self.onion.connected_to_tor: self.check_for_updates_button.setEnabled(False) else: self.check_for_updates_button.setEnabled(True) self.connection_type_test_button.setEnabled(True) self.save_button.setEnabled(True) self.cancel_button.setEnabled(True)
def authenticate_password_toggled(self, checked): """ Authentication option password was toggled. If checked, show extra fields for password auth. If unchecked, hide those extra fields. """ common.log('SettingsDialog', 'authenticate_password_toggled') if checked: self.authenticate_password_extras.show() else: self.authenticate_password_extras.hide()
def cancel_clicked(self): """ Cancel button clicked. """ common.log('SettingsDialog', 'cancel_clicked') if not self.onion.is_authenticated(): Alert(strings._('gui_tor_connection_canceled', True), QtWidgets.QMessageBox.Warning) sys.exit() else: self.close()
def start_server_error(self, error): """ If there's an error when trying to start the onion service """ common.log('OnionShareGui', 'start_server_error') self.set_server_active(False) Alert(error, QtWidgets.QMessageBox.Warning) self.server_status.stop_server() self.status_bar.clearMessage()
def __init__(self, message, icon=QtWidgets.QMessageBox.NoIcon, buttons=QtWidgets.QMessageBox.Ok, autostart=True): super(Alert, self).__init__(None) common.log('Alert', '__init__') self.setWindowTitle("OnionShare") self.setWindowIcon(QtGui.QIcon(common.get_resource_path('images/logo.png'))) self.setText(message) self.setIcon(icon) self.setStandardButtons(buttons) if autostart: self.exec_()
def connection_type_socket_file_toggled(self, checked): """ Connection type socket file was toggled. If checked, show extra fields for socket file. If unchecked, hide those extra fields. """ common.log('SettingsDialog', 'connection_type_socket_file_toggled') if checked: self.authenticate_group.show() self.connection_type_socket_file_extras.show() self.connection_type_socks.show() else: self.connection_type_socket_file_extras.hide()
def connection_type_control_port_toggled(self, checked): """ Connection type control port was toggled. If checked, show extra fields for Tor control address and port. If unchecked, hide those extra fields. """ common.log('SettingsDialog', 'connection_type_control_port_toggled') if checked: self.authenticate_group.show() self.connection_type_control_port_extras.show() self.connection_type_socks.show() else: self.connection_type_control_port_extras.hide()
def update_server_status_indicator(self): common.log('OnionShareGui', 'update_server_status_indicator') # Set the status image if self.server_status.status == self.server_status.STATUS_STOPPED: self.server_status_image_label.setPixmap(QtGui.QPixmap.fromImage(self.server_status_image_stopped)) self.server_status_label.setText(strings._('gui_status_indicator_stopped', True)) elif self.server_status.status == self.server_status.STATUS_WORKING: self.server_status_image_label.setPixmap(QtGui.QPixmap.fromImage(self.server_status_image_working)) self.server_status_label.setText(strings._('gui_status_indicator_working', True)) elif self.server_status.status == self.server_status.STATUS_STARTED: self.server_status_image_label.setPixmap(QtGui.QPixmap.fromImage(self.server_status_image_started)) self.server_status_label.setText(strings._('gui_status_indicator_started', True))
def test_output(self, set_debug_true, time_strftime): def dummy_func(): pass # From: https://stackoverflow.com/questions/1218933 with io.StringIO() as buf, contextlib.redirect_stdout(buf): common.log('TestModule', dummy_func) common.log('TestModule', dummy_func, 'TEST_MSG') output = buf.getvalue() line_one, line_two, _ = output.split('\n') assert LOG_MSG_REGEX.match(line_one) assert LOG_MSG_REGEX.match(line_two)
def start_server(self): """ Start the onionshare server. This uses multiple threads to start the Tor onion server and the web app. """ common.log('OnionShareGui', 'start_server') self.set_server_active(True) self.app.set_stealth(self.settings.get('use_stealth')) # Hide and reset the downloads if we have previously shared self.downloads_container.hide() self.downloads.reset_downloads() self.status_bar.clearMessage() # Reset web counters web.download_count = 0 web.error404_count = 0 web.set_gui_mode() # start the onion service in a new thread def start_onion_service(self): try: self.app.start_onion_service() self.starting_server_step2.emit() except (TorTooOld, TorErrorInvalidSetting, TorErrorAutomatic, TorErrorSocketPort, TorErrorSocketFile, TorErrorMissingPassword, TorErrorUnreadableCookieFile, TorErrorAuthError, TorErrorProtocolError, BundledTorTimeout, OSError) as e: self.starting_server_error.emit(e.args[0]) return self.app.stay_open = not self.settings.get( 'close_after_first_download') # start onionshare http service in new thread t = threading.Thread(target=web.start, args=(self.app.port, self.app.stay_open)) t.daemon = True t.start() # 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()
def reload_settings(): common.log('OnionShareGui', 'open_settings', 'settings have changed, reloading') self.settings.load() # We might've stopped the main requests timer if a Tor connection failed. # If we've reloaded settings, we probably succeeded in obtaining a new # connection. If so, restart the timer. if self.onion.is_authenticated(): if not self.timer.isActive(): self.timer.start(500) # If there were some files listed for sharing, we should be ok to # re-enable the 'Start Sharing' button now. if self.server_status.file_selection.get_num_files() > 0: self.server_status.server_button.setEnabled(True) self.status_bar.clearMessage()
def _error_connecting_to_tor(self, msg): common.log('TorConnectionDialog', '_error_connecting_to_tor') self.active = False def alert_and_open_settings(): # Display the exception in an alert box Alert("{}\n\n{}".format(msg, strings._('gui_tor_connection_error_settings', True)), QtWidgets.QMessageBox.Warning) # Open settings self.open_settings.emit() QtCore.QTimer.singleShot(1, alert_and_open_settings) # Cancel connecting to Tor QtCore.QTimer.singleShot(1, self.cancel)
def start_server_step3(self): """ Step 3 in starting the onionshare server. This displays the large filesize warning, if applicable. """ common.log('OnionShareGui', 'start_server_step3') # Remove zip progress bar if self._zip_progress_bar is not None: self.status_bar.removeWidget(self._zip_progress_bar) self._zip_progress_bar = None # warn about sending large files over Tor if web.zip_filesize >= 157286400: # 150mb self.filesize_warning.setText(strings._("large_filesize", True)) self.filesize_warning.show()
def stop_server(self): """ Stop the onionshare server. """ common.log('OnionShareGui', 'stop_server') if self.server_status.status != self.server_status.STATUS_STOPPED: try: web.stop(self.app.port) except: # Probably we had no port to begin with (Onion service didn't start) pass self.app.cleanup() self.filesize_warning.hide() self.stop_server_finished.emit() self.set_server_active(False)
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.start() # 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 __init__(self, message, icon=QtWidgets.QMessageBox.NoIcon, buttons=QtWidgets.QMessageBox.Ok, autostart=True): super(Alert, self).__init__(None) common.log('Alert', '__init__') self.setWindowTitle("OnionShare") self.setWindowIcon( QtGui.QIcon(common.get_resource_path('images/logo.png'))) self.setText(message) self.setIcon(icon) self.setStandardButtons(buttons) if autostart: self.exec_()
def settings_from_fields(self): """ Return a Settings object that's full of values from the settings dialog. """ common.log('SettingsDialog', 'settings_from_fields') settings = Settings(self.config) settings.load() # To get the last update timestamp settings.set('close_after_first_download', self.close_after_first_download_checkbox.isChecked()) settings.set('systray_notifications', self.systray_notifications_checkbox.isChecked()) settings.set('different_temporary_folder', self._update_different_temporary_folder) settings.set('use_stealth', self.stealth_checkbox.isChecked()) if self.connection_type_bundled_radio.isChecked(): settings.set('connection_type', 'bundled') if self.connection_type_automatic_radio.isChecked(): settings.set('connection_type', 'automatic') if self.connection_type_control_port_radio.isChecked(): settings.set('connection_type', 'control_port') if self.connection_type_socket_file_radio.isChecked(): settings.set('connection_type', 'socket_file') settings.set('control_port_address', self.connection_type_control_port_extras_address.text()) settings.set('control_port_port', self.connection_type_control_port_extras_port.text()) settings.set('socket_file_path', self.connection_type_socket_file_extras_path.text()) settings.set('socks_address', self.connection_type_socks_address.text()) settings.set('socks_port', self.connection_type_socks_port.text()) if self.authenticate_no_auth_radio.isChecked(): settings.set('auth_type', 'no_auth') if self.authenticate_password_radio.isChecked(): settings.set('auth_type', 'password') settings.set('auth_password', self.authenticate_password_extras_password.text()) return settings
def test_tor_clicked(self): """ Test Tor Settings button clicked. With the given settings, see if we can successfully connect and authenticate to Tor. """ common.log('SettingsDialog', 'test_tor_clicked') settings = self.settings_from_fields() try: # Show Tor connection status if connection type is bundled tor if settings.get('connection_type') == 'bundled': self.tor_status.show() self._disable_buttons() def tor_status_update_func(progress, summary): self._tor_status_update(progress, summary) return True else: tor_status_update_func = None onion = Onion() onion.connect(settings=settings, config=self.config, tor_status_update_func=tor_status_update_func) # If an exception hasn't been raised yet, the Tor settings work Alert( strings._('settings_test_success', True).format(onion.tor_version, onion.supports_ephemeral, onion.supports_stealth)) # Clean up onion.cleanup() except (TorErrorInvalidSetting, TorErrorAutomatic, TorErrorSocketPort, TorErrorSocketFile, TorErrorMissingPassword, TorErrorUnreadableCookieFile, TorErrorAuthError, TorErrorProtocolError, BundledTorNotSupported, BundledTorTimeout) as e: Alert(e.args[0], QtWidgets.QMessageBox.Warning) if settings.get('connection_type') == 'bundled': self.tor_status.hide() self._enable_buttons()
def update_server_status_indicator(self): common.log('OnionShareGui', 'update_server_status_indicator') # Set the status image if self.server_status.status == self.server_status.STATUS_STOPPED: self.server_status_image_label.setPixmap( QtGui.QPixmap.fromImage(self.server_status_image_stopped)) self.server_status_label.setText( strings._('gui_status_indicator_stopped', True)) elif self.server_status.status == self.server_status.STATUS_WORKING: self.server_status_image_label.setPixmap( QtGui.QPixmap.fromImage(self.server_status_image_working)) self.server_status_label.setText( strings._('gui_status_indicator_working', True)) elif self.server_status.status == self.server_status.STATUS_STARTED: self.server_status_image_label.setPixmap( QtGui.QPixmap.fromImage(self.server_status_image_started)) self.server_status_label.setText( strings._('gui_status_indicator_started', True))
def check_for_updates(self): """ Check for Updates button clicked. Manually force an update check. """ common.log('SettingsDialog', 'check_for_updates') # Disable buttons self._disable_buttons() self.qtapp.processEvents() # Check for updates def update_available(update_url, installed_version, latest_version): Alert( strings._("update_available", True).format(update_url, installed_version, latest_version)) def update_not_available(): Alert(strings._('update_not_available', True)) u = UpdateChecker(self.onion) u.update_available.connect(update_available) u.update_not_available.connect(update_not_available) try: u.check(force=True) except UpdateCheckerCheckError: Alert(strings._('update_error_check_error', True), QtWidgets.QMessageBox.Warning) except UpdateCheckerInvalidLatestVersion as e: Alert( strings._('update_error_invalid_latest_version', True).format(e.latest_version), QtWidgets.QMessageBox.Warning) # Enable buttons self._enable_buttons() # Update the last checked label settings = Settings(self.config) settings.load() autoupdate_timestamp = settings.get('autoupdate_timestamp') self._update_autoupdate_timestamp(autoupdate_timestamp)
def ask(): a = Alert(strings._('gui_tor_connection_ask', True), QtWidgets.QMessageBox.Question, buttons=QtWidgets.QMessageBox.NoButton, autostart=False) settings_button = QtWidgets.QPushButton(strings._('gui_tor_connection_ask_open_settings', True)) quit_button = QtWidgets.QPushButton(strings._('gui_tor_connection_ask_quit', True)) a.addButton(settings_button, QtWidgets.QMessageBox.AcceptRole) a.addButton(quit_button, QtWidgets.QMessageBox.RejectRole) a.setDefaultButton(settings_button) a.exec_() if a.clickedButton() == settings_button: # Open settings common.log('OnionShareGui', '_tor_connection_canceled', 'Settings button clicked') self.open_settings() if a.clickedButton() == quit_button: # Quit common.log('OnionShareGui', '_tor_connection_canceled', 'Quit button clicked') # Wait 1ms for the event loop to finish, then quit QtCore.QTimer.singleShot(1, self.qtapp.quit)
def stop_server(self): """ Stop the onionshare server. """ common.log('OnionShareGui', 'stop_server') if self.server_status.status != self.server_status.STATUS_STOPPED: try: web.stop(self.app.port) except: # Probably we had no port to begin with (Onion service didn't start) pass self.app.cleanup() # Remove ephemeral service, but don't disconnect from Tor self.onion.cleanup(stop_tor=False) self.filesize_warning.hide() self.persistent_url_label.hide() self.stop_server_finished.emit() self.set_server_active(False)
def start_server_step2(self): """ Step 2 in starting the onionshare server. Zipping up files. """ common.log('OnionShareGui', 'start_server_step2') # add progress bar to the status bar, indicating the crunching of files. self._zip_progress_bar = ZipProgressBar(0) self.filenames = [] for index in range(self.file_selection.file_list.count()): self.filenames.append( self.file_selection.file_list.item(index).filename) self._zip_progress_bar.total_files_size = OnionShareGui._compute_total_size( self.filenames) self.status_bar.insertWidget(0, self._zip_progress_bar) # prepare the files for sending in a new thread def finish_starting_server(self): # prepare files to share def _set_processed_size(x): if self._zip_progress_bar != None: self._zip_progress_bar.update_processed_size_signal.emit(x) try: web.set_file_info(self.filenames, processed_size_callback=_set_processed_size) self.app.cleanup_filenames.append(web.zip_filename) self.starting_server_step3.emit() # done self.start_server_finished.emit() except OSError as e: self.starting_server_error.emit(e.strerror) return t = threading.Thread(target=finish_starting_server, kwargs={'self': self}) t.daemon = True t.start()
def closeEvent(self, e): common.log('OnionShareGui', 'closeEvent') try: if self.server_status.status != self.server_status.STATUS_STOPPED: dialog = QtWidgets.QMessageBox() dialog.setWindowTitle("OnionShare") dialog.setText(strings._('gui_quit_warning', True)) quit_button = dialog.addButton(strings._('gui_quit_warning_quit', True), QtWidgets.QMessageBox.YesRole) dont_quit_button = dialog.addButton(strings._('gui_quit_warning_dont_quit', True), QtWidgets.QMessageBox.NoRole) dialog.setDefaultButton(dont_quit_button) reply = dialog.exec_() # Quit if reply == 0: self.stop_server() e.accept() # Don't Quit else: e.ignore() except: e.accept()
def stop_server(self): """ Stop the onionshare server. """ common.log('OnionShareGui', 'stop_server') if self.server_status.status != self.server_status.STATUS_STOPPED: try: web.stop(self.app.port) except: # Probably we had no port to begin with (Onion service didn't start) pass self.app.cleanup() # Remove ephemeral service, but don't disconnect from Tor self.onion.cleanup(stop_tor=False) self.filesize_warning.hide() self.downloads_in_progress = 0 self.downloads_completed = 0 self.update_downloads_in_progress(0) self.file_selection.file_list.adjustSize() self.set_server_active(False) self.stop_server_finished.emit()
def __init__(self, qtapp, settings, onion): super(TorConnectionDialog, self).__init__(None) common.log('TorConnectionDialog', '__init__') self.qtapp = qtapp self.settings = settings self.onion = onion self.setWindowTitle("OnionShare") self.setWindowIcon(QtGui.QIcon(common.get_resource_path('images/logo.png'))) self.setModal(True) self.setFixedSize(400, 150) # Label self.setLabelText(strings._('connecting_to_tor', True)) # 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 save_clicked(self): """ Save button clicked. Save current settings to disk. """ common.log('SettingsDialog', 'save_clicked') settings = self.settings_from_fields() settings.save() # If Tor isn't connected, or if Tor settings have changed, Reinitialize # the Onion object reboot_onion = False if self.onion.connected_to_tor: def changed(s1, s2, keys): """ Compare the Settings objects s1 and s2 and return true if any values have changed for the given keys. """ for key in keys: if s1.get(key) != s2.get(key): return True return False if changed(settings, self.old_settings, [ 'connection_type', 'control_port_address', 'control_port_port', 'socks_address', 'socks_port', 'socket_file_path', 'auth_type', 'auth_password' ]): reboot_onion = True else: # Tor isn't connected, so try connecting reboot_onion = True # Do we need to reinitialize Tor? if reboot_onion: # Reinitialize the Onion object common.log('SettingsDialog', 'save_clicked', 'rebooting the Onion') self.onion.cleanup() tor_con = TorConnectionDialog(self.qtapp, settings, self.onion) tor_con.start() common.log( 'SettingsDialog', 'save_clicked', 'Onion done rebooting, connected to Tor: {}'.format( self.onion.connected_to_tor)) if self.onion.connected_to_tor and not tor_con.wasCanceled(): self.settings_saved.emit() self.close() else: self.settings_saved.emit() self.close()
def run(self): common.log('TorConnectionThread', 'run') # Connect to the Onion try: self.onion.connect(self.settings, self._tor_status_update) if self.onion.connected_to_tor: self.connected_to_tor.emit() else: self.canceled_connecting_to_tor.emit() except BundledTorCanceled as e: common.log('TorConnectionThread', 'run', 'caught exception: BundledTorCanceled') self.canceled_connecting_to_tor.emit() except Exception as e: common.log('TorConnectionThread', 'run', 'caught exception: {}'.format(e.args[0])) self.error_connecting_to_tor.emit(str(e.args[0]))
def settings_from_fields(self): """ Return a Settings object that's full of values from the settings dialog. """ common.log('SettingsDialog', 'settings_from_fields') settings = Settings(self.config) settings.load() # To get the last update timestamp settings.set('close_after_first_download', self.close_after_first_download_checkbox.isChecked()) settings.set('systray_notifications', self.systray_notifications_checkbox.isChecked()) if self.save_private_key_checkbox.isChecked(): settings.set('save_private_key', True) settings.set('private_key', self.old_settings.get('private_key')) settings.set('slug', self.old_settings.get('slug')) settings.set('hidservauth_string', self.old_settings.get('hidservauth_string')) else: settings.set('save_private_key', False) settings.set('private_key', '') settings.set('slug', '') # Also unset the HidServAuth if we are removing our reusable private key settings.set('hidservauth_string', '') settings.set('use_stealth', self.stealth_checkbox.isChecked()) # Always unset the HidServAuth if Stealth mode is unset if not self.stealth_checkbox.isChecked(): settings.set('hidservauth_string', '') if self.connection_type_bundled_radio.isChecked(): settings.set('connection_type', 'bundled') if self.connection_type_automatic_radio.isChecked(): settings.set('connection_type', 'automatic') if self.connection_type_control_port_radio.isChecked(): settings.set('connection_type', 'control_port') if self.connection_type_socket_file_radio.isChecked(): settings.set('connection_type', 'socket_file') if self.autoupdate_checkbox.isChecked(): settings.set('use_autoupdate', True) else: settings.set('use_autoupdate', False) settings.set('control_port_address', self.connection_type_control_port_extras_address.text()) settings.set('control_port_port', self.connection_type_control_port_extras_port.text()) settings.set('socket_file_path', self.connection_type_socket_file_extras_path.text()) settings.set('socks_address', self.connection_type_socks_address.text()) settings.set('socks_port', self.connection_type_socks_port.text()) if self.authenticate_no_auth_radio.isChecked(): settings.set('auth_type', 'no_auth') if self.authenticate_password_radio.isChecked(): settings.set('auth_type', 'password') settings.set('auth_password', self.authenticate_password_extras_password.text()) # Whether we use bridges if self.tor_bridges_no_bridges_radio.isChecked(): settings.set('no_bridges', True) settings.set('tor_bridges_use_obfs4', False) settings.set('tor_bridges_use_custom_bridges', '') if self.tor_bridges_use_obfs4_radio.isChecked(): settings.set('no_bridges', False) settings.set('tor_bridges_use_obfs4', True) settings.set('tor_bridges_use_custom_bridges', '') if self.tor_bridges_use_custom_radio.isChecked(): settings.set('no_bridges', False) settings.set('tor_bridges_use_obfs4', False) # Insert a 'Bridge' line at the start of each bridge. # This makes it easier to copy/paste a set of bridges # provided from https://bridges.torproject.org new_bridges = [] bridges = self.tor_bridges_use_custom_textbox.toPlainText().split( '\n') bridges_valid = False for bridge in bridges: if bridge != '': # Check the syntax of the custom bridge to make sure it looks legitimate pattern = re.compile("[0-9.]+:[0-9]+\s[A-Z0-9]+$") if pattern.match(bridge): new_bridges.append(''.join(['Bridge ', bridge, '\n'])) bridges_valid = True if bridges_valid: new_bridges = ''.join(new_bridges) settings.set('tor_bridges_use_custom_bridges', new_bridges) else: Alert(strings._('gui_settings_tor_bridges_invalid', True)) settings.set('no_bridges', True) return settings
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') self.active = False # Cancel connecting to Tor QtCore.QTimer.singleShot(1, self.cancel)
def __init__(self, onion, qtapp, app, filenames, config=False): super(OnionShareGui, self).__init__() self._initSystemTray() common.log('OnionShareGui', '__init__') self.onion = onion self.qtapp = qtapp self.app = app self.setWindowTitle('OnionShare') self.setWindowIcon( QtGui.QIcon(common.get_resource_path('images/logo.png'))) # Load settings self.config = config self.settings = Settings(self.config) self.settings.load() # File selection self.file_selection = FileSelection() if filenames: for filename in filenames: self.file_selection.file_list.add_file(filename) # Server status self.server_status = ServerStatus(self.qtapp, self.app, web, self.file_selection) self.server_status.server_started.connect( self.file_selection.server_started) self.server_status.server_started.connect(self.start_server) self.server_status.server_stopped.connect( self.file_selection.server_stopped) self.server_status.server_stopped.connect(self.stop_server) self.start_server_finished.connect(self.clear_message) self.start_server_finished.connect( self.server_status.start_server_finished) self.stop_server_finished.connect( self.server_status.stop_server_finished) self.file_selection.file_list.files_updated.connect( self.server_status.update) self.server_status.url_copied.connect(self.copy_url) self.server_status.hidservauth_copied.connect(self.copy_hidservauth) self.starting_server_step2.connect(self.start_server_step2) self.starting_server_step3.connect(self.start_server_step3) self.starting_server_error.connect(self.start_server_error) # Filesize warning self.filesize_warning = QtWidgets.QLabel() self.filesize_warning.setStyleSheet( 'padding: 10px 0; font-weight: bold; color: #333333;') self.filesize_warning.hide() # Downloads self.downloads = Downloads() self.downloads_container = QtWidgets.QScrollArea() self.downloads_container.setWidget(self.downloads) self.downloads_container.setWidgetResizable(True) self.downloads_container.setMaximumHeight(200) self.downloads_container.setMinimumHeight(75) self.vbar = self.downloads_container.verticalScrollBar() self.downloads_container.hide() # downloads start out hidden self.new_download = False # Status bar self.status_bar = QtWidgets.QStatusBar() self.status_bar.setSizeGripEnabled(False) self.status_bar.setStyleSheet("QStatusBar::item { border: 0px; }") version_label = QtWidgets.QLabel('v{0:s}'.format(common.get_version())) version_label.setStyleSheet('color: #666666') self.settings_button = QtWidgets.QPushButton() self.settings_button.setDefault(False) self.settings_button.setFlat(True) self.settings_button.setIcon( QtGui.QIcon(common.get_resource_path('images/settings.png'))) self.settings_button.clicked.connect(self.open_settings) self.status_bar.addPermanentWidget(version_label) self.status_bar.addPermanentWidget(self.settings_button) self.setStatusBar(self.status_bar) # Status bar, zip progress bar self._zip_progress_bar = None # Main layout self.layout = QtWidgets.QVBoxLayout() self.layout.addLayout(self.file_selection) self.layout.addLayout(self.server_status) self.layout.addWidget(self.filesize_warning) self.layout.addWidget(self.downloads_container) central_widget = QtWidgets.QWidget() central_widget.setLayout(self.layout) self.setCentralWidget(central_widget) self.show() # Check for requests frequently self.timer = QtCore.QTimer() self.timer.timeout.connect(self.check_for_requests) self.timer.start(500) # Always start with focus on file selection self.file_selection.setFocus() # The server isn't active yet self.set_server_active(False) # Start the "Connecting to Tor" dialog, which calls onion.connect() 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() # After connecting to Tor, check for updates self.check_for_updates()
def copy_url(self): """ When the URL gets copied to the clipboard, display this in the status bar. """ common.log('OnionShareGui', 'copy_url') self.status_bar.showMessage(strings._('gui_copied_url', True), 2000)
def authenticate_no_auth_toggled(self, checked): """ Authentication option no authentication was toggled. """ common.log('SettingsDialog', 'authenticate_no_auth_toggled')
def __init__(self, onion, qtapp, config=False): super(SettingsDialog, self).__init__() common.log('SettingsDialog', '__init__') self.onion = onion self.qtapp = qtapp self.config = config self.setModal(True) self.setWindowTitle(strings._('gui_settings_window_title', True)) self.setWindowIcon( QtGui.QIcon(common.get_resource_path('images/logo.png'))) system = platform.system() # Sharing options # Close after first download self.close_after_first_download_checkbox = QtWidgets.QCheckBox() self.close_after_first_download_checkbox.setCheckState( QtCore.Qt.Checked) self.close_after_first_download_checkbox.setText( strings._("gui_settings_close_after_first_download_option", True)) # Whether or not to show systray notifications self.systray_notifications_checkbox = QtWidgets.QCheckBox() self.systray_notifications_checkbox.setCheckState(QtCore.Qt.Checked) self.systray_notifications_checkbox.setText( strings._("gui_settings_systray_notifications", True)) # Sharing options layout sharing_group_layout = QtWidgets.QVBoxLayout() sharing_group_layout.addWidget( self.close_after_first_download_checkbox) sharing_group_layout.addWidget(self.systray_notifications_checkbox) sharing_group = QtWidgets.QGroupBox( strings._("gui_settings_sharing_label", True)) sharing_group.setLayout(sharing_group_layout) # Stealth options # Stealth stealth_details = QtWidgets.QLabel( strings._("gui_settings_stealth_option_details", True)) stealth_details.setWordWrap(True) self.stealth_checkbox = QtWidgets.QCheckBox() self.stealth_checkbox.setCheckState(QtCore.Qt.Unchecked) self.stealth_checkbox.setText( strings._("gui_settings_stealth_option", True)) # Stealth options layout stealth_group_layout = QtWidgets.QVBoxLayout() stealth_group_layout.addWidget(stealth_details) stealth_group_layout.addWidget(self.stealth_checkbox) stealth_group = QtWidgets.QGroupBox( strings._("gui_settings_stealth_label", True)) stealth_group.setLayout(stealth_group_layout) # Automatic updates options # Autoupdate self.autoupdate_checkbox = QtWidgets.QCheckBox() self.autoupdate_checkbox.setCheckState(QtCore.Qt.Unchecked) self.autoupdate_checkbox.setText( strings._("gui_settings_autoupdate_option", True)) # Last update time self.autoupdate_timestamp = QtWidgets.QLabel() # Check for updates button self.check_for_updates_button = QtWidgets.QPushButton( strings._('gui_settings_autoupdate_check_button', True)) self.check_for_updates_button.clicked.connect(self.check_for_updates) # Autoupdate options layout autoupdate_group_layout = QtWidgets.QVBoxLayout() autoupdate_group_layout.addWidget(self.autoupdate_checkbox) autoupdate_group_layout.addWidget(self.autoupdate_timestamp) autoupdate_group_layout.addWidget(self.check_for_updates_button) autoupdate_group = QtWidgets.QGroupBox( strings._("gui_settings_autoupdate_label", True)) autoupdate_group.setLayout(autoupdate_group_layout) # Autoupdate is only available for Windows and Mac (Linux updates using package manager) if system != 'Windows' and system != 'Darwin': autoupdate_group.hide() # Connection type: either automatic, control port, or socket file # Bundled Tor self.connection_type_bundled_radio = QtWidgets.QRadioButton( strings._('gui_settings_connection_type_bundled_option', True)) self.connection_type_bundled_radio.toggled.connect( self.connection_type_bundled_toggled) # Bundled Tor doesn't work on dev mode in Windows or Mac if (system == 'Windows' or system == 'Darwin') and getattr( sys, 'onionshare_dev_mode', False): self.connection_type_bundled_radio.setEnabled(False) # Automatic self.connection_type_automatic_radio = QtWidgets.QRadioButton( strings._('gui_settings_connection_type_automatic_option', True)) self.connection_type_automatic_radio.toggled.connect( self.connection_type_automatic_toggled) # Control port self.connection_type_control_port_radio = QtWidgets.QRadioButton( strings._('gui_settings_connection_type_control_port_option', True)) self.connection_type_control_port_radio.toggled.connect( self.connection_type_control_port_toggled) connection_type_control_port_extras_label = QtWidgets.QLabel( strings._('gui_settings_control_port_label', True)) self.connection_type_control_port_extras_address = QtWidgets.QLineEdit( ) self.connection_type_control_port_extras_port = QtWidgets.QLineEdit() connection_type_control_port_extras_layout = QtWidgets.QHBoxLayout() connection_type_control_port_extras_layout.addWidget( connection_type_control_port_extras_label) connection_type_control_port_extras_layout.addWidget( self.connection_type_control_port_extras_address) connection_type_control_port_extras_layout.addWidget( self.connection_type_control_port_extras_port) self.connection_type_control_port_extras = QtWidgets.QWidget() self.connection_type_control_port_extras.setLayout( connection_type_control_port_extras_layout) self.connection_type_control_port_extras.hide() # Socket file self.connection_type_socket_file_radio = QtWidgets.QRadioButton( strings._('gui_settings_connection_type_socket_file_option', True)) self.connection_type_socket_file_radio.toggled.connect( self.connection_type_socket_file_toggled) connection_type_socket_file_extras_label = QtWidgets.QLabel( strings._('gui_settings_socket_file_label', True)) self.connection_type_socket_file_extras_path = QtWidgets.QLineEdit() connection_type_socket_file_extras_layout = QtWidgets.QHBoxLayout() connection_type_socket_file_extras_layout.addWidget( connection_type_socket_file_extras_label) connection_type_socket_file_extras_layout.addWidget( self.connection_type_socket_file_extras_path) self.connection_type_socket_file_extras = QtWidgets.QWidget() self.connection_type_socket_file_extras.setLayout( connection_type_socket_file_extras_layout) self.connection_type_socket_file_extras.hide() # Tor SOCKS address and port gui_settings_socks_label = QtWidgets.QLabel( strings._('gui_settings_socks_label', True)) self.connection_type_socks_address = QtWidgets.QLineEdit() self.connection_type_socks_port = QtWidgets.QLineEdit() connection_type_socks_layout = QtWidgets.QHBoxLayout() connection_type_socks_layout.addWidget(gui_settings_socks_label) connection_type_socks_layout.addWidget( self.connection_type_socks_address) connection_type_socks_layout.addWidget(self.connection_type_socks_port) self.connection_type_socks = QtWidgets.QWidget() self.connection_type_socks.setLayout(connection_type_socks_layout) self.connection_type_socks.hide() # Authentication options # No authentication self.authenticate_no_auth_radio = QtWidgets.QRadioButton( strings._('gui_settings_authenticate_no_auth_option', True)) self.authenticate_no_auth_radio.toggled.connect( self.authenticate_no_auth_toggled) # Password self.authenticate_password_radio = QtWidgets.QRadioButton( strings._('gui_settings_authenticate_password_option', True)) self.authenticate_password_radio.toggled.connect( self.authenticate_password_toggled) authenticate_password_extras_label = QtWidgets.QLabel( strings._('gui_settings_password_label', True)) self.authenticate_password_extras_password = QtWidgets.QLineEdit('') authenticate_password_extras_layout = QtWidgets.QHBoxLayout() authenticate_password_extras_layout.addWidget( authenticate_password_extras_label) authenticate_password_extras_layout.addWidget( self.authenticate_password_extras_password) self.authenticate_password_extras = QtWidgets.QWidget() self.authenticate_password_extras.setLayout( authenticate_password_extras_layout) self.authenticate_password_extras.hide() # Authentication options layout authenticate_group_layout = QtWidgets.QVBoxLayout() authenticate_group_layout.addWidget(self.authenticate_no_auth_radio) authenticate_group_layout.addWidget(self.authenticate_password_radio) authenticate_group_layout.addWidget(self.authenticate_password_extras) self.authenticate_group = QtWidgets.QGroupBox( strings._("gui_settings_authenticate_label", True)) self.authenticate_group.setLayout(authenticate_group_layout) # Test tor settings button self.connection_type_test_button = QtWidgets.QPushButton( strings._('gui_settings_connection_type_test_button', True)) self.connection_type_test_button.clicked.connect(self.test_tor_clicked) # Put the radios into their own group so they are exclusive connection_type_radio_group_layout = QtWidgets.QVBoxLayout() connection_type_radio_group_layout.addWidget( self.connection_type_bundled_radio) connection_type_radio_group_layout.addWidget( self.connection_type_automatic_radio) connection_type_radio_group_layout.addWidget( self.connection_type_control_port_radio) connection_type_radio_group_layout.addWidget( self.connection_type_socket_file_radio) connection_type_radio_group = QtWidgets.QGroupBox( strings._("gui_settings_connection_type_label", True)) connection_type_radio_group.setLayout( connection_type_radio_group_layout) # Connection type layout connection_type_group_layout = QtWidgets.QVBoxLayout() connection_type_group_layout.addWidget( self.connection_type_control_port_extras) connection_type_group_layout.addWidget( self.connection_type_socket_file_extras) connection_type_group_layout.addWidget(self.connection_type_socks) connection_type_group_layout.addWidget(self.authenticate_group) connection_type_group_layout.addWidget( self.connection_type_test_button) connection_type_group = QtWidgets.QGroupBox() connection_type_group.setLayout(connection_type_group_layout) # Buttons self.save_button = QtWidgets.QPushButton( strings._('gui_settings_button_save', True)) self.save_button.clicked.connect(self.save_clicked) self.cancel_button = QtWidgets.QPushButton( strings._('gui_settings_button_cancel', True)) self.cancel_button.clicked.connect(self.cancel_clicked) self.help_button = QtWidgets.QPushButton( strings._('gui_settings_button_help', True)) self.help_button.clicked.connect(self.help_clicked) buttons_layout = QtWidgets.QHBoxLayout() buttons_layout.addWidget(self.help_button) buttons_layout.addStretch() buttons_layout.addWidget(self.save_button) buttons_layout.addWidget(self.cancel_button) # Tor network connection status self.tor_status = QtWidgets.QLabel() self.tor_status.setStyleSheet( 'background-color: #ffffff; color: #000000; padding: 10px') self.tor_status.hide() # Layout left_col_layout = QtWidgets.QVBoxLayout() left_col_layout.addWidget(sharing_group) left_col_layout.addWidget(stealth_group) left_col_layout.addWidget(autoupdate_group) left_col_layout.addStretch() right_col_layout = QtWidgets.QVBoxLayout() right_col_layout.addWidget(connection_type_radio_group) right_col_layout.addWidget(connection_type_group) right_col_layout.addWidget(self.tor_status) right_col_layout.addStretch() col_layout = QtWidgets.QHBoxLayout() col_layout.addLayout(left_col_layout) col_layout.addLayout(right_col_layout) layout = QtWidgets.QVBoxLayout() layout.addLayout(col_layout) layout.addLayout(buttons_layout) self.setLayout(layout) self.cancel_button.setFocus() # Load settings, and fill them in self.old_settings = Settings(self.config) self.old_settings.load() close_after_first_download = self.old_settings.get( 'close_after_first_download') if close_after_first_download: self.close_after_first_download_checkbox.setCheckState( QtCore.Qt.Checked) else: self.close_after_first_download_checkbox.setCheckState( QtCore.Qt.Unchecked) systray_notifications = self.old_settings.get('systray_notifications') if systray_notifications: self.systray_notifications_checkbox.setCheckState( QtCore.Qt.Checked) else: self.systray_notifications_checkbox.setCheckState( QtCore.Qt.Unchecked) use_stealth = self.old_settings.get('use_stealth') if use_stealth: self.stealth_checkbox.setCheckState(QtCore.Qt.Checked) else: self.stealth_checkbox.setCheckState(QtCore.Qt.Unchecked) use_autoupdate = self.old_settings.get('use_autoupdate') if use_autoupdate: self.autoupdate_checkbox.setCheckState(QtCore.Qt.Checked) else: self.autoupdate_checkbox.setCheckState(QtCore.Qt.Unchecked) autoupdate_timestamp = self.old_settings.get('autoupdate_timestamp') self._update_autoupdate_timestamp(autoupdate_timestamp) connection_type = self.old_settings.get('connection_type') if connection_type == 'bundled': if self.connection_type_bundled_radio.isEnabled(): self.connection_type_bundled_radio.setChecked(True) else: # If bundled tor is disabled, fallback to automatic self.connection_type_automatic_radio.setChecked(True) elif connection_type == 'automatic': self.connection_type_automatic_radio.setChecked(True) elif connection_type == 'control_port': self.connection_type_control_port_radio.setChecked(True) elif connection_type == 'socket_file': self.connection_type_socket_file_radio.setChecked(True) self.connection_type_control_port_extras_address.setText( self.old_settings.get('control_port_address')) self.connection_type_control_port_extras_port.setText( str(self.old_settings.get('control_port_port'))) self.connection_type_socket_file_extras_path.setText( self.old_settings.get('socket_file_path')) self.connection_type_socks_address.setText( self.old_settings.get('socks_address')) self.connection_type_socks_port.setText( str(self.old_settings.get('socks_port'))) auth_type = self.old_settings.get('auth_type') if auth_type == 'no_auth': self.authenticate_no_auth_radio.setChecked(True) elif auth_type == 'password': self.authenticate_password_radio.setChecked(True) self.authenticate_password_extras_password.setText( self.old_settings.get('auth_password'))
def __init__(self, onion, qtapp, config=False): super(SettingsDialog, self).__init__() common.log('SettingsDialog', '__init__') self.onion = onion self.qtapp = qtapp self.config = config self.setModal(True) self.setWindowTitle(strings._('gui_settings_window_title', True)) self.setWindowIcon( QtGui.QIcon(common.get_resource_path('images/logo.png'))) system = platform.system() # Sharing options # Close after first download self.close_after_first_download_checkbox = QtWidgets.QCheckBox() self.close_after_first_download_checkbox.setCheckState( QtCore.Qt.Checked) self.close_after_first_download_checkbox.setText( strings._("gui_settings_close_after_first_download_option", True)) # Whether or not to show systray notifications self.systray_notifications_checkbox = QtWidgets.QCheckBox() self.systray_notifications_checkbox.setCheckState(QtCore.Qt.Checked) self.systray_notifications_checkbox.setText( strings._("gui_settings_systray_notifications", True)) # Whether or not to save the Onion private key for reuse self.save_private_key_checkbox = QtWidgets.QCheckBox() self.save_private_key_checkbox.setCheckState(QtCore.Qt.Unchecked) self.save_private_key_checkbox.setText( strings._("gui_save_private_key_checkbox", True)) # Sharing options layout sharing_group_layout = QtWidgets.QVBoxLayout() sharing_group_layout.addWidget( self.close_after_first_download_checkbox) sharing_group_layout.addWidget(self.systray_notifications_checkbox) sharing_group_layout.addWidget(self.save_private_key_checkbox) sharing_group = QtWidgets.QGroupBox( strings._("gui_settings_sharing_label", True)) sharing_group.setLayout(sharing_group_layout) # Stealth options # Stealth stealth_details = QtWidgets.QLabel( strings._("gui_settings_stealth_option_details", True)) stealth_details.setWordWrap(True) stealth_details.setTextInteractionFlags( QtCore.Qt.TextBrowserInteraction) stealth_details.setOpenExternalLinks(True) self.stealth_checkbox = QtWidgets.QCheckBox() self.stealth_checkbox.setCheckState(QtCore.Qt.Unchecked) self.stealth_checkbox.setText( strings._("gui_settings_stealth_option", True)) hidservauth_details = QtWidgets.QLabel( strings._('gui_settings_stealth_hidservauth_string', True)) hidservauth_details.setWordWrap(True) hidservauth_details.hide() self.hidservauth_copy_button = QtWidgets.QPushButton( strings._('gui_copy_hidservauth', True)) self.hidservauth_copy_button.clicked.connect( self.hidservauth_copy_button_clicked) self.hidservauth_copy_button.hide() # Stealth options layout stealth_group_layout = QtWidgets.QVBoxLayout() stealth_group_layout.addWidget(stealth_details) stealth_group_layout.addWidget(self.stealth_checkbox) stealth_group_layout.addWidget(hidservauth_details) stealth_group_layout.addWidget(self.hidservauth_copy_button) stealth_group = QtWidgets.QGroupBox( strings._("gui_settings_stealth_label", True)) stealth_group.setLayout(stealth_group_layout) # Automatic updates options # Autoupdate self.autoupdate_checkbox = QtWidgets.QCheckBox() self.autoupdate_checkbox.setCheckState(QtCore.Qt.Unchecked) self.autoupdate_checkbox.setText( strings._("gui_settings_autoupdate_option", True)) # Last update time self.autoupdate_timestamp = QtWidgets.QLabel() # Check for updates button self.check_for_updates_button = QtWidgets.QPushButton( strings._('gui_settings_autoupdate_check_button', True)) self.check_for_updates_button.clicked.connect(self.check_for_updates) # We can't check for updates if not connected to Tor if not self.onion.connected_to_tor: self.check_for_updates_button.setEnabled(False) # Autoupdate options layout autoupdate_group_layout = QtWidgets.QVBoxLayout() autoupdate_group_layout.addWidget(self.autoupdate_checkbox) autoupdate_group_layout.addWidget(self.autoupdate_timestamp) autoupdate_group_layout.addWidget(self.check_for_updates_button) autoupdate_group = QtWidgets.QGroupBox( strings._("gui_settings_autoupdate_label", True)) autoupdate_group.setLayout(autoupdate_group_layout) # Autoupdate is only available for Windows and Mac (Linux updates using package manager) if system != 'Windows' and system != 'Darwin': autoupdate_group.hide() # Connection type: either automatic, control port, or socket file # Bundled Tor self.connection_type_bundled_radio = QtWidgets.QRadioButton( strings._('gui_settings_connection_type_bundled_option', True)) self.connection_type_bundled_radio.toggled.connect( self.connection_type_bundled_toggled) # Bundled Tor doesn't work on dev mode in Windows or Mac if (system == 'Windows' or system == 'Darwin') and getattr( sys, 'onionshare_dev_mode', False): self.connection_type_bundled_radio.setEnabled(False) # Bridge options for bundled tor # No bridges option radio self.tor_bridges_no_bridges_radio = QtWidgets.QRadioButton( strings._('gui_settings_tor_bridges_no_bridges_radio_option', True)) self.tor_bridges_no_bridges_radio.toggled.connect( self.tor_bridges_no_bridges_radio_toggled) # obfs4 option radio # if the obfs4proxy binary is missing, we can't use obfs4 transports (self.tor_path, self.tor_geo_ip_file_path, self.tor_geo_ipv6_file_path, self.obfs4proxy_file_path) = common.get_tor_paths() if not os.path.isfile(self.obfs4proxy_file_path): self.tor_bridges_use_obfs4_radio = QtWidgets.QRadioButton( strings. _('gui_settings_tor_bridges_obfs4_radio_option_no_obfs4proxy', True)) self.tor_bridges_use_obfs4_radio.setEnabled(False) else: self.tor_bridges_use_obfs4_radio = QtWidgets.QRadioButton( strings._('gui_settings_tor_bridges_obfs4_radio_option', True)) self.tor_bridges_use_obfs4_radio.toggled.connect( self.tor_bridges_use_obfs4_radio_toggled) # Custom bridges radio and textbox self.tor_bridges_use_custom_radio = QtWidgets.QRadioButton( strings._('gui_settings_tor_bridges_custom_radio_option', True)) self.tor_bridges_use_custom_radio.toggled.connect( self.tor_bridges_use_custom_radio_toggled) self.tor_bridges_use_custom_label = QtWidgets.QLabel( strings._('gui_settings_tor_bridges_custom_label', True)) self.tor_bridges_use_custom_label.setTextInteractionFlags( QtCore.Qt.TextBrowserInteraction) self.tor_bridges_use_custom_label.setOpenExternalLinks(True) self.tor_bridges_use_custom_textbox = QtWidgets.QPlainTextEdit() self.tor_bridges_use_custom_textbox.setMaximumHeight(200) self.tor_bridges_use_custom_textbox.setPlaceholderText( '[address:port] [identifier]') tor_bridges_use_custom_textbox_options_layout = QtWidgets.QVBoxLayout() tor_bridges_use_custom_textbox_options_layout.addWidget( self.tor_bridges_use_custom_label) tor_bridges_use_custom_textbox_options_layout.addWidget( self.tor_bridges_use_custom_textbox) self.tor_bridges_use_custom_textbox_options = QtWidgets.QWidget() self.tor_bridges_use_custom_textbox_options.setLayout( tor_bridges_use_custom_textbox_options_layout) self.tor_bridges_use_custom_textbox_options.hide() # Bridges layout/widget bridges_layout = QtWidgets.QVBoxLayout() bridges_layout.addWidget(self.tor_bridges_no_bridges_radio) bridges_layout.addWidget(self.tor_bridges_use_obfs4_radio) bridges_layout.addWidget(self.tor_bridges_use_custom_radio) bridges_layout.addWidget(self.tor_bridges_use_custom_textbox_options) self.bridges = QtWidgets.QWidget() self.bridges.setLayout(bridges_layout) # Automatic self.connection_type_automatic_radio = QtWidgets.QRadioButton( strings._('gui_settings_connection_type_automatic_option', True)) self.connection_type_automatic_radio.toggled.connect( self.connection_type_automatic_toggled) # Control port self.connection_type_control_port_radio = QtWidgets.QRadioButton( strings._('gui_settings_connection_type_control_port_option', True)) self.connection_type_control_port_radio.toggled.connect( self.connection_type_control_port_toggled) connection_type_control_port_extras_label = QtWidgets.QLabel( strings._('gui_settings_control_port_label', True)) self.connection_type_control_port_extras_address = QtWidgets.QLineEdit( ) self.connection_type_control_port_extras_port = QtWidgets.QLineEdit() connection_type_control_port_extras_layout = QtWidgets.QHBoxLayout() connection_type_control_port_extras_layout.addWidget( connection_type_control_port_extras_label) connection_type_control_port_extras_layout.addWidget( self.connection_type_control_port_extras_address) connection_type_control_port_extras_layout.addWidget( self.connection_type_control_port_extras_port) self.connection_type_control_port_extras = QtWidgets.QWidget() self.connection_type_control_port_extras.setLayout( connection_type_control_port_extras_layout) self.connection_type_control_port_extras.hide() # Socket file self.connection_type_socket_file_radio = QtWidgets.QRadioButton( strings._('gui_settings_connection_type_socket_file_option', True)) self.connection_type_socket_file_radio.toggled.connect( self.connection_type_socket_file_toggled) connection_type_socket_file_extras_label = QtWidgets.QLabel( strings._('gui_settings_socket_file_label', True)) self.connection_type_socket_file_extras_path = QtWidgets.QLineEdit() connection_type_socket_file_extras_layout = QtWidgets.QHBoxLayout() connection_type_socket_file_extras_layout.addWidget( connection_type_socket_file_extras_label) connection_type_socket_file_extras_layout.addWidget( self.connection_type_socket_file_extras_path) self.connection_type_socket_file_extras = QtWidgets.QWidget() self.connection_type_socket_file_extras.setLayout( connection_type_socket_file_extras_layout) self.connection_type_socket_file_extras.hide() # Tor SOCKS address and port gui_settings_socks_label = QtWidgets.QLabel( strings._('gui_settings_socks_label', True)) self.connection_type_socks_address = QtWidgets.QLineEdit() self.connection_type_socks_port = QtWidgets.QLineEdit() connection_type_socks_layout = QtWidgets.QHBoxLayout() connection_type_socks_layout.addWidget(gui_settings_socks_label) connection_type_socks_layout.addWidget( self.connection_type_socks_address) connection_type_socks_layout.addWidget(self.connection_type_socks_port) self.connection_type_socks = QtWidgets.QWidget() self.connection_type_socks.setLayout(connection_type_socks_layout) self.connection_type_socks.hide() # Authentication options # No authentication self.authenticate_no_auth_radio = QtWidgets.QRadioButton( strings._('gui_settings_authenticate_no_auth_option', True)) self.authenticate_no_auth_radio.toggled.connect( self.authenticate_no_auth_toggled) # Password self.authenticate_password_radio = QtWidgets.QRadioButton( strings._('gui_settings_authenticate_password_option', True)) self.authenticate_password_radio.toggled.connect( self.authenticate_password_toggled) authenticate_password_extras_label = QtWidgets.QLabel( strings._('gui_settings_password_label', True)) self.authenticate_password_extras_password = QtWidgets.QLineEdit('') authenticate_password_extras_layout = QtWidgets.QHBoxLayout() authenticate_password_extras_layout.addWidget( authenticate_password_extras_label) authenticate_password_extras_layout.addWidget( self.authenticate_password_extras_password) self.authenticate_password_extras = QtWidgets.QWidget() self.authenticate_password_extras.setLayout( authenticate_password_extras_layout) self.authenticate_password_extras.hide() # Authentication options layout authenticate_group_layout = QtWidgets.QVBoxLayout() authenticate_group_layout.addWidget(self.authenticate_no_auth_radio) authenticate_group_layout.addWidget(self.authenticate_password_radio) authenticate_group_layout.addWidget(self.authenticate_password_extras) self.authenticate_group = QtWidgets.QGroupBox( strings._("gui_settings_authenticate_label", True)) self.authenticate_group.setLayout(authenticate_group_layout) # Test tor settings button self.connection_type_test_button = QtWidgets.QPushButton( strings._('gui_settings_connection_type_test_button', True)) self.connection_type_test_button.clicked.connect(self.test_tor_clicked) # Put the radios into their own group so they are exclusive connection_type_radio_group_layout = QtWidgets.QVBoxLayout() connection_type_radio_group_layout.addWidget( self.connection_type_bundled_radio) connection_type_radio_group_layout.addWidget( self.connection_type_automatic_radio) connection_type_radio_group_layout.addWidget( self.connection_type_control_port_radio) connection_type_radio_group_layout.addWidget( self.connection_type_socket_file_radio) connection_type_radio_group = QtWidgets.QGroupBox( strings._("gui_settings_connection_type_label", True)) connection_type_radio_group.setLayout( connection_type_radio_group_layout) # Connection type layout connection_type_group_layout = QtWidgets.QVBoxLayout() connection_type_group_layout.addWidget( self.connection_type_control_port_extras) connection_type_group_layout.addWidget( self.connection_type_socket_file_extras) connection_type_group_layout.addWidget(self.connection_type_socks) connection_type_group_layout.addWidget(self.authenticate_group) connection_type_group_layout.addWidget( self.connection_type_test_button) connection_type_group = QtWidgets.QGroupBox() connection_type_group.setLayout(connection_type_group_layout) # 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) self.connection_type_bridges_radio_group = QtWidgets.QGroupBox( strings._("gui_settings_tor_bridges", True)) self.connection_type_bridges_radio_group.setLayout( connection_type_bridges_radio_group_layout) self.connection_type_bridges_radio_group.hide() # Buttons self.save_button = QtWidgets.QPushButton( strings._('gui_settings_button_save', True)) self.save_button.clicked.connect(self.save_clicked) self.cancel_button = QtWidgets.QPushButton( strings._('gui_settings_button_cancel', True)) self.cancel_button.clicked.connect(self.cancel_clicked) self.help_button = QtWidgets.QPushButton( strings._('gui_settings_button_help', True)) self.help_button.clicked.connect(self.help_clicked) buttons_layout = QtWidgets.QHBoxLayout() buttons_layout.addWidget(self.help_button) buttons_layout.addStretch() buttons_layout.addWidget(self.save_button) buttons_layout.addWidget(self.cancel_button) # Tor network connection status self.tor_status = QtWidgets.QLabel() self.tor_status.setStyleSheet( 'background-color: #ffffff; color: #000000; padding: 10px') self.tor_status.hide() # Layout left_col_layout = QtWidgets.QVBoxLayout() left_col_layout.addWidget(sharing_group) left_col_layout.addWidget(stealth_group) left_col_layout.addWidget(autoupdate_group) left_col_layout.addStretch() right_col_layout = QtWidgets.QVBoxLayout() right_col_layout.addWidget(connection_type_radio_group) right_col_layout.addWidget(connection_type_group) right_col_layout.addWidget(self.connection_type_bridges_radio_group) right_col_layout.addWidget(self.tor_status) right_col_layout.addStretch() col_layout = QtWidgets.QHBoxLayout() col_layout.addLayout(left_col_layout) col_layout.addLayout(right_col_layout) layout = QtWidgets.QVBoxLayout() layout.addLayout(col_layout) layout.addLayout(buttons_layout) self.setLayout(layout) self.cancel_button.setFocus() # Load settings, and fill them in self.old_settings = Settings(self.config) self.old_settings.load() close_after_first_download = self.old_settings.get( 'close_after_first_download') if close_after_first_download: self.close_after_first_download_checkbox.setCheckState( QtCore.Qt.Checked) else: self.close_after_first_download_checkbox.setCheckState( QtCore.Qt.Unchecked) systray_notifications = self.old_settings.get('systray_notifications') if systray_notifications: self.systray_notifications_checkbox.setCheckState( QtCore.Qt.Checked) else: self.systray_notifications_checkbox.setCheckState( QtCore.Qt.Unchecked) save_private_key = self.old_settings.get('save_private_key') if save_private_key: self.save_private_key_checkbox.setCheckState(QtCore.Qt.Checked) else: self.save_private_key_checkbox.setCheckState(QtCore.Qt.Unchecked) use_stealth = self.old_settings.get('use_stealth') if use_stealth: self.stealth_checkbox.setCheckState(QtCore.Qt.Checked) if save_private_key: hidservauth_details.show() self.hidservauth_copy_button.show() else: self.stealth_checkbox.setCheckState(QtCore.Qt.Unchecked) use_autoupdate = self.old_settings.get('use_autoupdate') if use_autoupdate: self.autoupdate_checkbox.setCheckState(QtCore.Qt.Checked) else: self.autoupdate_checkbox.setCheckState(QtCore.Qt.Unchecked) autoupdate_timestamp = self.old_settings.get('autoupdate_timestamp') self._update_autoupdate_timestamp(autoupdate_timestamp) connection_type = self.old_settings.get('connection_type') if connection_type == 'bundled': if self.connection_type_bundled_radio.isEnabled(): self.connection_type_bundled_radio.setChecked(True) else: # If bundled tor is disabled, fallback to automatic self.connection_type_automatic_radio.setChecked(True) elif connection_type == 'automatic': self.connection_type_automatic_radio.setChecked(True) elif connection_type == 'control_port': self.connection_type_control_port_radio.setChecked(True) elif connection_type == 'socket_file': self.connection_type_socket_file_radio.setChecked(True) self.connection_type_control_port_extras_address.setText( self.old_settings.get('control_port_address')) self.connection_type_control_port_extras_port.setText( str(self.old_settings.get('control_port_port'))) self.connection_type_socket_file_extras_path.setText( self.old_settings.get('socket_file_path')) self.connection_type_socks_address.setText( self.old_settings.get('socks_address')) self.connection_type_socks_port.setText( str(self.old_settings.get('socks_port'))) auth_type = self.old_settings.get('auth_type') if auth_type == 'no_auth': self.authenticate_no_auth_radio.setChecked(True) elif auth_type == 'password': self.authenticate_password_radio.setChecked(True) self.authenticate_password_extras_password.setText( self.old_settings.get('auth_password')) if self.old_settings.get('no_bridges'): self.tor_bridges_no_bridges_radio.setChecked(True) self.tor_bridges_use_obfs4_radio.setChecked(False) self.tor_bridges_use_custom_radio.setChecked(False) else: self.tor_bridges_no_bridges_radio.setChecked(False) self.tor_bridges_use_obfs4_radio.setChecked( self.old_settings.get('tor_bridges_use_obfs4')) if self.old_settings.get('tor_bridges_use_custom_bridges'): self.tor_bridges_use_custom_radio.setChecked(True) # Remove the 'Bridge' lines at the start of each bridge. # They are added automatically to provide compatibility with # copying/pasting bridges provided from https://bridges.torproject.org new_bridges = [] bridges = self.old_settings.get( 'tor_bridges_use_custom_bridges').split('Bridge ') for bridge in bridges: new_bridges.append(bridge) new_bridges = ''.join(new_bridges) self.tor_bridges_use_custom_textbox.setPlainText(new_bridges)
def cancel_clicked(self): """ Cancel button clicked. """ common.log('SettingsDialog', 'cancel_clicked') self.close()
def reload_settings(): common.log('OnionShareGui', 'open_settings', 'settings have changed, reloading') self.settings.load()
def copy_hidservauth(self): """ When the stealth onion service HidServAuth gets copied to the clipboard, display this in the status bar. """ common.log('OnionShareGui', 'copy_hidservauth') self.status_bar.showMessage(strings._('gui_copied_hidservauth', True), 2000)