From 08c2e106f81fa5f432a10e11f4c0a492e451a76f Mon Sep 17 00:00:00 2001 From: Miguel Jacq Date: Sat, 9 Dec 2017 06:49:34 +1100 Subject: [PATCH] Save the HidServAuth string to settings when private key is also saved. Allow to copy it to clipboard from the SettingsDialog too. --- onionshare/onion.py | 32 ++++++++++++++++++++++++------- onionshare_gui/server_status.py | 3 +++ onionshare_gui/settings_dialog.py | 27 ++++++++++++++++++++++++++ share/locale/en.json | 1 + 4 files changed, 56 insertions(+), 7 deletions(-) diff --git a/onionshare/onion.py b/onionshare/onion.py index 00b7dd51..409c9ad8 100644 --- a/onionshare/onion.py +++ b/onionshare/onion.py @@ -368,7 +368,7 @@ class Onion(object): # Do the versions of stem and tor that I'm using support stealth onion services? try: res = self.c.create_ephemeral_hidden_service({1:1}, basic_auth={'onionshare':None}, await_publication=False) - tmp_service_id = res.content()[0][2].split('=')[1] + tmp_service_id = res.service_id self.c.remove_ephemeral_hidden_service(tmp_service_id) self.supports_stealth = True except: @@ -392,20 +392,27 @@ class Onion(object): print(strings._('using_ephemeral')) if self.stealth: - basic_auth = {'onionshare':None} + if self.settings.get('hidservauth_string'): + hidservauth_string = self.settings.get('hidservauth_string').split()[2] + basic_auth = {'onionshare':hidservauth_string} + else: + basic_auth = {'onionshare':None} else: basic_auth = None if self.settings.get('private_key'): key_type = "RSA1024" key_content = self.settings.get('private_key') + common.log('Onion', 'Starting a hidden service with a saved private key') else: key_type = "NEW" key_content = "RSA1024" + common.log('Onion', 'Starting a hidden service with a new private key') + try: - if basic_auth != None : + if basic_auth != None: res = self.c.create_ephemeral_hidden_service({ 80: port }, await_publication=True, basic_auth=basic_auth, key_type = key_type, key_content=key_content) - else : + else: # if the stem interface is older than 1.5.0, basic_auth isn't a valid keyword arg res = self.c.create_ephemeral_hidden_service({ 80: port }, await_publication=True, key_type = key_type, key_content=key_content) @@ -414,11 +421,22 @@ class Onion(object): self.service_id = res.content()[0][2].split('=')[1] onion_host = self.service_id + '.onion' - self.private_key = res.private_key + + # A new private key was generated and is in the Control port response. + if not self.settings.get('private_key'): + self.private_key = res.private_key if self.stealth: - auth_cookie = res.content()[2][2].split('=')[1].split(':')[1] - self.auth_string = 'HidServAuth {} {}'.format(onion_host, auth_cookie) + # Similar to the PrivateKey, the Control port only returns the ClientAuth + # in the response if it was responsible for creating the basic_auth password + # in the first place. + # If we sent the basic_auth (due to a saved hidservauth_string in the settings), + # there is no response here, so use the saved value from settings. + if self.settings.get('hidservauth_string'): + self.auth_string = self.settings.get('hidservauth_string') + else: + auth_cookie = list(res.client_auth.values())[0] + self.auth_string = 'HidServAuth {} {}'.format(onion_host, auth_cookie) return onion_host diff --git a/onionshare_gui/server_status.py b/onionshare_gui/server_status.py index c2cb8f47..77964677 100644 --- a/onionshare_gui/server_status.py +++ b/onionshare_gui/server_status.py @@ -265,6 +265,9 @@ class ServerStatus(QtWidgets.QVBoxLayout): """ self.save_private_key_button.setEnabled(False) self.settings.set('private_key', self.app.private_key) + if self.app.stealth: + self.settings.set('hidservauth_string', self.app.auth_string) self.settings.save() + self.settings.load() self.private_key_saved.emit() diff --git a/onionshare_gui/settings_dialog.py b/onionshare_gui/settings_dialog.py index 3421255d..22b24fc5 100644 --- a/onionshare_gui/settings_dialog.py +++ b/onionshare_gui/settings_dialog.py @@ -82,10 +82,20 @@ class SettingsDialog(QtWidgets.QDialog): 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) @@ -291,6 +301,9 @@ class SettingsDialog(QtWidgets.QDialog): 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) @@ -390,6 +403,15 @@ class SettingsDialog(QtWidgets.QDialog): else: self.authenticate_password_extras.hide() + 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 test_tor_clicked(self): """ Test Tor Settings button clicked. With the given settings, see if we can @@ -546,7 +568,12 @@ class SettingsDialog(QtWidgets.QDialog): settings.set('private_key', settings.get('private_key')) else: settings.set('private_key', '') + # 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') diff --git a/share/locale/en.json b/share/locale/en.json index 88113fba..2ec21580 100644 --- a/share/locale/en.json +++ b/share/locale/en.json @@ -68,6 +68,7 @@ "gui_settings_stealth_label": "Stealth (advanced)", "gui_settings_stealth_option": "Create stealth onion services", "gui_settings_stealth_option_details": "This makes OnionShare more secure, but also more difficult for the recipient to connect to it.
More information.", + "gui_settings_stealth_hidservauth_string": "You have saved the private key for reuse, so your HidServAuth string is also reused.\nClick below to copy the HidServAuth.", "gui_settings_autoupdate_label": "Check for updates", "gui_settings_autoupdate_option": "Notify me when updates are available", "gui_settings_autoupdate_timestamp": "Last checked: {}",