Optionally save the private key of a running share to settings for reuse

This commit is contained in:
Miguel Jacq 2017-12-07 12:45:29 +11:00
parent c9190f9d9a
commit 3a056803a9
No known key found for this signature in database
GPG key ID: EEA4341C6D97A0B6
6 changed files with 52 additions and 7 deletions

View file

@ -396,24 +396,31 @@ class Onion(object):
else: else:
basic_auth = None basic_auth = None
if self.settings.get('private_key'):
key_type = "RSA1024"
key_content = self.settings.get('private_key')
else:
key_type = "NEW"
key_content = "RSA1024"
try: 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) 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 # 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) res = self.c.create_ephemeral_hidden_service({ 80: port }, await_publication=True, key_type = key_type, key_content=key_content)
except ProtocolError: except ProtocolError:
raise TorErrorProtocolError(strings._('error_tor_protocol_error')) raise TorErrorProtocolError(strings._('error_tor_protocol_error'))
self.service_id = res.content()[0][2].split('=')[1] self.service_id = res.content()[0][2].split('=')[1]
onion_host = self.service_id + '.onion' onion_host = self.service_id + '.onion'
private_key = res.private_key
if self.stealth: if self.stealth:
auth_cookie = res.content()[2][2].split('=')[1].split(':')[1] auth_cookie = res.content()[2][2].split('=')[1].split(':')[1]
self.auth_string = 'HidServAuth {} {}'.format(onion_host, auth_cookie) self.auth_string = 'HidServAuth {} {}'.format(onion_host, auth_cookie)
return onion_host return (onion_host, private_key)
def cleanup(self): def cleanup(self):
""" """

View file

@ -76,7 +76,7 @@ class OnionShare(object):
if self.shutdown_timeout > 0: if self.shutdown_timeout > 0:
self.shutdown_timer = common.close_after_seconds(self.shutdown_timeout) self.shutdown_timer = common.close_after_seconds(self.shutdown_timeout)
self.onion_host = self.onion.start_onion_service(self.port) self.onion_host, self.private_key = self.onion.start_onion_service(self.port)
if self.stealth: if self.stealth:
self.auth_string = self.onion.auth_string self.auth_string = self.onion.auth_string

View file

@ -69,7 +69,7 @@ class OnionShareGui(QtWidgets.QMainWindow):
self.file_selection.file_list.add_file(filename) self.file_selection.file_list.add_file(filename)
# Server status # Server status
self.server_status = ServerStatus(self.qtapp, self.app, web, self.file_selection) self.server_status = ServerStatus(self.qtapp, self.app, web, self.file_selection, self.settings)
self.server_status.server_started.connect(self.file_selection.server_started) self.server_status.server_started.connect(self.file_selection.server_started)
self.server_status.server_started.connect(self.start_server) 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.file_selection.server_stopped)

View file

@ -22,6 +22,7 @@ from .alert import Alert
from PyQt5 import QtCore, QtWidgets, QtGui from PyQt5 import QtCore, QtWidgets, QtGui
from onionshare import strings, common from onionshare import strings, common
from onionshare.settings import Settings
class ServerStatus(QtWidgets.QVBoxLayout): class ServerStatus(QtWidgets.QVBoxLayout):
""" """
@ -31,12 +32,13 @@ class ServerStatus(QtWidgets.QVBoxLayout):
server_stopped = QtCore.pyqtSignal() server_stopped = QtCore.pyqtSignal()
url_copied = QtCore.pyqtSignal() url_copied = QtCore.pyqtSignal()
hidservauth_copied = QtCore.pyqtSignal() hidservauth_copied = QtCore.pyqtSignal()
private_key_saved = QtCore.pyqtSignal()
STATUS_STOPPED = 0 STATUS_STOPPED = 0
STATUS_WORKING = 1 STATUS_WORKING = 1
STATUS_STARTED = 2 STATUS_STARTED = 2
def __init__(self, qtapp, app, web, file_selection): def __init__(self, qtapp, app, web, file_selection, settings):
super(ServerStatus, self).__init__() super(ServerStatus, self).__init__()
self.status = self.STATUS_STOPPED self.status = self.STATUS_STOPPED
@ -44,6 +46,7 @@ class ServerStatus(QtWidgets.QVBoxLayout):
self.app = app self.app = app
self.web = web self.web = web
self.file_selection = file_selection self.file_selection = file_selection
self.settings = settings
# Helper boolean as this is used in a few places # Helper boolean as this is used in a few places
self.timer_enabled = False self.timer_enabled = False
@ -87,10 +90,13 @@ class ServerStatus(QtWidgets.QVBoxLayout):
self.copy_url_button.clicked.connect(self.copy_url) self.copy_url_button.clicked.connect(self.copy_url)
self.copy_hidservauth_button = QtWidgets.QPushButton(strings._('gui_copy_hidservauth', True)) self.copy_hidservauth_button = QtWidgets.QPushButton(strings._('gui_copy_hidservauth', True))
self.copy_hidservauth_button.clicked.connect(self.copy_hidservauth) self.copy_hidservauth_button.clicked.connect(self.copy_hidservauth)
self.save_private_key_button = QtWidgets.QPushButton(strings._('gui_save_private_key', True))
self.save_private_key_button.clicked.connect(self.save_private_key)
url_layout = QtWidgets.QHBoxLayout() url_layout = QtWidgets.QHBoxLayout()
url_layout.addWidget(self.url_label) url_layout.addWidget(self.url_label)
url_layout.addWidget(self.copy_url_button) url_layout.addWidget(self.copy_url_button)
url_layout.addWidget(self.copy_hidservauth_button) url_layout.addWidget(self.copy_hidservauth_button)
url_layout.addWidget(self.save_private_key_button)
# add the widgets # add the widgets
self.addLayout(shutdown_timeout_layout_group) self.addLayout(shutdown_timeout_layout_group)
@ -140,6 +146,8 @@ class ServerStatus(QtWidgets.QVBoxLayout):
self.url_label.setText('http://{0:s}/{1:s}'.format(self.app.onion_host, self.web.slug)) self.url_label.setText('http://{0:s}/{1:s}'.format(self.app.onion_host, self.web.slug))
self.url_label.show() self.url_label.show()
self.copy_url_button.show() self.copy_url_button.show()
if not self.settings.get('private_key'):
self.save_private_key_button.show()
if self.app.stealth: if self.app.stealth:
self.copy_hidservauth_button.show() self.copy_hidservauth_button.show()
@ -153,6 +161,7 @@ class ServerStatus(QtWidgets.QVBoxLayout):
self.url_label.hide() self.url_label.hide()
self.copy_url_button.hide() self.copy_url_button.hide()
self.copy_hidservauth_button.hide() self.copy_hidservauth_button.hide()
self.save_private_key_button.hide()
# button # button
if self.file_selection.get_num_files() == 0: if self.file_selection.get_num_files() == 0:
@ -249,3 +258,13 @@ class ServerStatus(QtWidgets.QVBoxLayout):
clipboard.setText(self.app.auth_string) clipboard.setText(self.app.auth_string)
self.hidservauth_copied.emit() self.hidservauth_copied.emit()
def save_private_key(self):
"""
Save the Onion private key to settings, so the Onion URL can be re-used.
"""
self.save_private_key_button.setEnabled(False)
self.settings.set('private_key', self.app.private_key)
self.settings.save()
self.private_key_saved.emit()

View file

@ -60,10 +60,16 @@ class SettingsDialog(QtWidgets.QDialog):
self.systray_notifications_checkbox.setCheckState(QtCore.Qt.Checked) self.systray_notifications_checkbox.setCheckState(QtCore.Qt.Checked)
self.systray_notifications_checkbox.setText(strings._("gui_settings_systray_notifications", True)) 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 options layout
sharing_group_layout = QtWidgets.QVBoxLayout() sharing_group_layout = QtWidgets.QVBoxLayout()
sharing_group_layout.addWidget(self.close_after_first_download_checkbox) sharing_group_layout.addWidget(self.close_after_first_download_checkbox)
sharing_group_layout.addWidget(self.systray_notifications_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 = QtWidgets.QGroupBox(strings._("gui_settings_sharing_label", True))
sharing_group.setLayout(sharing_group_layout) sharing_group.setLayout(sharing_group_layout)
@ -275,6 +281,13 @@ class SettingsDialog(QtWidgets.QDialog):
else: else:
self.systray_notifications_checkbox.setCheckState(QtCore.Qt.Unchecked) self.systray_notifications_checkbox.setCheckState(QtCore.Qt.Unchecked)
save_private_key = self.old_settings.get('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)
self.save_private_key_checkbox.hide()
use_stealth = self.old_settings.get('use_stealth') use_stealth = self.old_settings.get('use_stealth')
if use_stealth: if use_stealth:
self.stealth_checkbox.setCheckState(QtCore.Qt.Checked) self.stealth_checkbox.setCheckState(QtCore.Qt.Checked)
@ -529,6 +542,10 @@ class SettingsDialog(QtWidgets.QDialog):
settings.set('close_after_first_download', self.close_after_first_download_checkbox.isChecked()) settings.set('close_after_first_download', self.close_after_first_download_checkbox.isChecked())
settings.set('systray_notifications', self.systray_notifications_checkbox.isChecked()) settings.set('systray_notifications', self.systray_notifications_checkbox.isChecked())
if self.save_private_key_checkbox.isChecked():
settings.set('private_key', settings.get('private_key'))
else:
settings.set('private_key', '')
settings.set('use_stealth', self.stealth_checkbox.isChecked()) settings.set('use_stealth', self.stealth_checkbox.isChecked())
if self.connection_type_bundled_radio.isChecked(): if self.connection_type_bundled_radio.isChecked():

View file

@ -121,5 +121,7 @@
"gui_tor_connection_canceled": "OnionShare cannot connect to Tor.\n\nMake sure you're connected to the internet, then re-open OnionShare to configure the Tor connection.", "gui_tor_connection_canceled": "OnionShare cannot connect to Tor.\n\nMake sure you're connected to the internet, then re-open OnionShare to configure the Tor connection.",
"gui_server_started_after_timeout": "The server started after your chosen auto-timeout.\nPlease start a new share.", "gui_server_started_after_timeout": "The server started after your chosen auto-timeout.\nPlease start a new share.",
"gui_server_timeout_expired": "The chosen timeout has already expired.\nPlease update the timeout and then you may start sharing.", "gui_server_timeout_expired": "The chosen timeout has already expired.\nPlease update the timeout and then you may start sharing.",
"share_via_onionshare": "Share via OnionShare" "share_via_onionshare": "Share via OnionShare",
"gui_save_private_key": "Save private key?",
"gui_save_private_key_checkbox": "Should the private key be saved for re-use?\nThis makes the Onion share URL persistent.\nUnchecking will remove the private key from settings."
} }