diff options
Diffstat (limited to 'onionshare_gui/settings_dialog.py')
-rw-r--r-- | onionshare_gui/settings_dialog.py | 650 |
1 files changed, 423 insertions, 227 deletions
diff --git a/onionshare_gui/settings_dialog.py b/onionshare_gui/settings_dialog.py index c2dca97c..2933784c 100644 --- a/onionshare_gui/settings_dialog.py +++ b/onionshare_gui/settings_dialog.py @@ -2,7 +2,7 @@ """ OnionShare | https://onionshare.org/ -Copyright (C) 2018 Micah Lee <micah@micahflee.com> +Copyright (C) 2014-2018 Micah Lee <micah@micahflee.com> This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -24,7 +24,7 @@ from onionshare import strings, common from onionshare.settings import Settings from onionshare.onion import * -from .alert import Alert +from .widgets import Alert from .update_checker import * from .tor_connection_dialog import TorConnectionDialog @@ -34,93 +34,194 @@ class SettingsDialog(QtWidgets.QDialog): """ settings_saved = QtCore.pyqtSignal() - def __init__(self, onion, qtapp, config=False): + def __init__(self, common, onion, qtapp, config=False, local_only=False): super(SettingsDialog, self).__init__() - common.log('SettingsDialog', '__init__') + + self.common = common + + self.common.log('SettingsDialog', '__init__') self.onion = onion self.qtapp = qtapp self.config = config + self.local_only = local_only self.setModal(True) - self.setWindowTitle(strings._('gui_settings_window_title', True)) - self.setWindowIcon(QtGui.QIcon(common.get_resource_path('images/logo.png'))) + self.setWindowTitle(strings._('gui_settings_window_title')) + self.setWindowIcon(QtGui.QIcon(self.common.get_resource_path('images/logo.png'))) self.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 use a shutdown timer + # General settings + + # Use a slug or not ('public mode') + self.public_mode_checkbox = QtWidgets.QCheckBox() + self.public_mode_checkbox.setCheckState(QtCore.Qt.Unchecked) + self.public_mode_checkbox.setText(strings._("gui_settings_public_mode_checkbox")) + public_mode_label = QtWidgets.QLabel(strings._("gui_settings_whats_this").format("https://github.com/micahflee/onionshare/wiki/Public-Mode")) + public_mode_label.setStyleSheet(self.common.css['settings_whats_this']) + public_mode_label.setTextInteractionFlags(QtCore.Qt.TextBrowserInteraction) + public_mode_label.setOpenExternalLinks(True) + public_mode_label.setMinimumSize(public_mode_label.sizeHint()) + public_mode_layout = QtWidgets.QHBoxLayout() + public_mode_layout.addWidget(self.public_mode_checkbox) + public_mode_layout.addWidget(public_mode_label) + public_mode_layout.addStretch() + public_mode_layout.setContentsMargins(0,0,0,0) + self.public_mode_widget = QtWidgets.QWidget() + self.public_mode_widget.setLayout(public_mode_layout) + + # Whether or not to use a shutdown ('auto-stop') timer self.shutdown_timeout_checkbox = QtWidgets.QCheckBox() self.shutdown_timeout_checkbox.setCheckState(QtCore.Qt.Checked) - self.shutdown_timeout_checkbox.setText(strings._("gui_settings_shutdown_timeout_checkbox", True)) - - # Whether or not to save the Onion private key for reuse + self.shutdown_timeout_checkbox.setText(strings._("gui_settings_shutdown_timeout_checkbox")) + shutdown_timeout_label = QtWidgets.QLabel(strings._("gui_settings_whats_this").format("https://github.com/micahflee/onionshare/wiki/Using-the-Auto-Stop-Timer")) + shutdown_timeout_label.setStyleSheet(self.common.css['settings_whats_this']) + shutdown_timeout_label.setTextInteractionFlags(QtCore.Qt.TextBrowserInteraction) + shutdown_timeout_label.setOpenExternalLinks(True) + shutdown_timeout_label.setMinimumSize(public_mode_label.sizeHint()) + shutdown_timeout_layout = QtWidgets.QHBoxLayout() + shutdown_timeout_layout.addWidget(self.shutdown_timeout_checkbox) + shutdown_timeout_layout.addWidget(shutdown_timeout_label) + shutdown_timeout_layout.addStretch() + shutdown_timeout_layout.setContentsMargins(0,0,0,0) + self.shutdown_timeout_widget = QtWidgets.QWidget() + self.shutdown_timeout_widget.setLayout(shutdown_timeout_layout) + + # General settings layout + general_group_layout = QtWidgets.QVBoxLayout() + general_group_layout.addWidget(self.public_mode_widget) + general_group_layout.addWidget(self.shutdown_timeout_widget) + general_group = QtWidgets.QGroupBox(strings._("gui_settings_general_label")) + general_group.setLayout(general_group_layout) + + # Onion settings + + # Label telling user to connect to Tor for onion service settings + self.connect_to_tor_label = QtWidgets.QLabel(strings._("gui_connect_to_tor_for_onion_settings")) + self.connect_to_tor_label.setStyleSheet(self.common.css['settings_connect_to_tor']) + + # Whether or not to save the Onion private key for reuse (persistent URL mode) 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.shutdown_timeout_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 + self.save_private_key_checkbox.setText(strings._("gui_save_private_key_checkbox")) + save_private_key_label = QtWidgets.QLabel(strings._("gui_settings_whats_this").format("https://github.com/micahflee/onionshare/wiki/Using-a-Persistent-URL")) + save_private_key_label.setStyleSheet(self.common.css['settings_whats_this']) + save_private_key_label.setTextInteractionFlags(QtCore.Qt.TextBrowserInteraction) + save_private_key_label.setOpenExternalLinks(True) + save_private_key_layout = QtWidgets.QHBoxLayout() + save_private_key_layout.addWidget(self.save_private_key_checkbox) + save_private_key_layout.addWidget(save_private_key_label) + save_private_key_layout.addStretch() + save_private_key_layout.setContentsMargins(0,0,0,0) + self.save_private_key_widget = QtWidgets.QWidget() + self.save_private_key_widget.setLayout(save_private_key_layout) + + # Whether or not to use legacy v2 onions + self.use_legacy_v2_onions_checkbox = QtWidgets.QCheckBox() + self.use_legacy_v2_onions_checkbox.setCheckState(QtCore.Qt.Unchecked) + self.use_legacy_v2_onions_checkbox.setText(strings._("gui_use_legacy_v2_onions_checkbox")) + self.use_legacy_v2_onions_checkbox.clicked.connect(self.use_legacy_v2_onions_checkbox_clicked) + use_legacy_v2_onions_label = QtWidgets.QLabel(strings._("gui_settings_whats_this").format("https://github.com/micahflee/onionshare/wiki/Legacy-Addresses")) + use_legacy_v2_onions_label.setStyleSheet(self.common.css['settings_whats_this']) + use_legacy_v2_onions_label.setTextInteractionFlags(QtCore.Qt.TextBrowserInteraction) + use_legacy_v2_onions_label.setOpenExternalLinks(True) + use_legacy_v2_onions_layout = QtWidgets.QHBoxLayout() + use_legacy_v2_onions_layout.addWidget(self.use_legacy_v2_onions_checkbox) + use_legacy_v2_onions_layout.addWidget(use_legacy_v2_onions_label) + use_legacy_v2_onions_layout.addStretch() + use_legacy_v2_onions_layout.setContentsMargins(0,0,0,0) + self.use_legacy_v2_onions_widget = QtWidgets.QWidget() + self.use_legacy_v2_onions_widget.setLayout(use_legacy_v2_onions_layout) # 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) - stealth_details.setMinimumSize(stealth_details.sizeHint()) 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.setMinimumSize(hidservauth_details.sizeHint()) - hidservauth_details.hide() - - self.hidservauth_copy_button = QtWidgets.QPushButton(strings._('gui_copy_hidservauth', True)) + self.stealth_checkbox.setText(strings._("gui_settings_stealth_option")) + self.stealth_checkbox.clicked.connect(self.stealth_checkbox_clicked_connect) + use_stealth_label = QtWidgets.QLabel(strings._("gui_settings_whats_this").format("https://github.com/micahflee/onionshare/wiki/Stealth-Onion-Services")) + use_stealth_label.setStyleSheet(self.common.css['settings_whats_this']) + use_stealth_label.setTextInteractionFlags(QtCore.Qt.TextBrowserInteraction) + use_stealth_label.setOpenExternalLinks(True) + use_stealth_label.setMinimumSize(use_stealth_label.sizeHint()) + use_stealth_layout = QtWidgets.QHBoxLayout() + use_stealth_layout.addWidget(self.stealth_checkbox) + use_stealth_layout.addWidget(use_stealth_label) + use_stealth_layout.addStretch() + use_stealth_layout.setContentsMargins(0,0,0,0) + self.use_stealth_widget = QtWidgets.QWidget() + self.use_stealth_widget.setLayout(use_stealth_layout) + + self.hidservauth_details = QtWidgets.QLabel(strings._('gui_settings_stealth_hidservauth_string')) + self.hidservauth_details.setWordWrap(True) + self.hidservauth_details.setMinimumSize(self.hidservauth_details.sizeHint()) + self.hidservauth_details.hide() + + self.hidservauth_copy_button = QtWidgets.QPushButton(strings._('gui_copy_hidservauth')) 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) + # Onion settings widget + onion_settings_layout = QtWidgets.QVBoxLayout() + onion_settings_layout.setContentsMargins(0, 0, 0, 0) + onion_settings_layout.addWidget(self.save_private_key_widget) + onion_settings_layout.addWidget(self.use_legacy_v2_onions_widget) + onion_settings_layout.addWidget(self.use_stealth_widget) + onion_settings_layout.addWidget(self.hidservauth_details) + onion_settings_layout.addWidget(self.hidservauth_copy_button) + self.onion_settings_widget = QtWidgets.QWidget() + self.onion_settings_widget.setLayout(onion_settings_layout) + + # Onion settings layout + onion_group_layout = QtWidgets.QVBoxLayout() + onion_group_layout.addWidget(self.connect_to_tor_label) + onion_group_layout.addWidget(self.onion_settings_widget) + onion_group = QtWidgets.QGroupBox(strings._("gui_settings_onion_label")) + onion_group.setLayout(onion_group_layout) + + + # 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")) + + # Sharing options layout + sharing_group_layout = QtWidgets.QVBoxLayout() + sharing_group_layout.addWidget(self.close_after_first_download_checkbox) + sharing_group = QtWidgets.QGroupBox(strings._("gui_settings_sharing_label")) + sharing_group.setLayout(sharing_group_layout) + + # OnionShare data dir + data_dir_label = QtWidgets.QLabel(strings._('gui_settings_data_dir_label')); + self.data_dir_lineedit = QtWidgets.QLineEdit() + self.data_dir_lineedit.setReadOnly(True) + data_dir_button = QtWidgets.QPushButton(strings._('gui_settings_data_dir_browse_button')) + data_dir_button.clicked.connect(self.data_dir_button_clicked) + data_dir_layout = QtWidgets.QHBoxLayout() + data_dir_layout.addWidget(data_dir_label) + data_dir_layout.addWidget(self.data_dir_lineedit) + data_dir_layout.addWidget(data_dir_button) + + # Receiving options layout + receiving_group_layout = QtWidgets.QVBoxLayout() + receiving_group_layout.addLayout(data_dir_layout) + receiving_group = QtWidgets.QGroupBox(strings._("gui_settings_receiving_label")) + receiving_group.setLayout(receiving_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)) + self.autoupdate_checkbox.setText(strings._("gui_settings_autoupdate_option")) # 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 = QtWidgets.QPushButton(strings._('gui_settings_autoupdate_check_button')) 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: @@ -131,17 +232,32 @@ class SettingsDialog(QtWidgets.QDialog): 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 = QtWidgets.QGroupBox(strings._("gui_settings_autoupdate_label")) autoupdate_group.setLayout(autoupdate_group_layout) # Autoupdate is only available for Windows and Mac (Linux updates using package manager) if self.system != 'Windows' and self.system != 'Darwin': autoupdate_group.hide() + # Language settings + language_label = QtWidgets.QLabel(strings._("gui_settings_language_label")) + self.language_combobox = QtWidgets.QComboBox() + # Populate the dropdown with all of OnionShare's available languages + language_names_to_locales = {v: k for k, v in self.common.settings.available_locales.items()} + language_names = list(language_names_to_locales) + language_names.sort() + for language_name in language_names: + locale = language_names_to_locales[language_name] + self.language_combobox.addItem(language_name, QtCore.QVariant(locale)) + language_layout = QtWidgets.QHBoxLayout() + language_layout.addWidget(language_label) + language_layout.addWidget(self.language_combobox) + language_layout.addStretch() + # 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 = QtWidgets.QRadioButton(strings._('gui_settings_connection_type_bundled_option')) self.connection_type_bundled_radio.toggled.connect(self.connection_type_bundled_toggled) # Bundled Tor doesn't work on dev mode in Windows or Mac @@ -151,49 +267,34 @@ class SettingsDialog(QtWidgets.QDialog): # 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 = QtWidgets.QRadioButton(strings._('gui_settings_tor_bridges_no_bridges_radio_option')) 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() + (self.tor_path, self.tor_geo_ip_file_path, self.tor_geo_ipv6_file_path, self.obfs4proxy_file_path) = self.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 = QtWidgets.QRadioButton(strings._('gui_settings_tor_bridges_obfs4_radio_option_no_obfs4proxy')) 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 = QtWidgets.QRadioButton(strings._('gui_settings_tor_bridges_obfs4_radio_option')) self.tor_bridges_use_obfs4_radio.toggled.connect(self.tor_bridges_use_obfs4_radio_toggled) - # meek_lite-amazon option radio - # if the obfs4proxy binary is missing, we can't use meek_lite-amazon 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_meek_lite_amazon_radio = QtWidgets.QRadioButton(strings._('gui_settings_tor_bridges_meek_lite_amazon_radio_option_no_obfs4proxy', True)) - self.tor_bridges_use_meek_lite_amazon_radio.setEnabled(False) - else: - self.tor_bridges_use_meek_lite_amazon_radio = QtWidgets.QRadioButton(strings._('gui_settings_tor_bridges_meek_lite_amazon_radio_option', True)) - self.tor_bridges_use_meek_lite_amazon_radio.toggled.connect(self.tor_bridges_use_meek_lite_amazon_radio_toggled) - # meek_lite-azure option radio # if the obfs4proxy binary is missing, we can't use meek_lite-azure transports - (self.tor_path, self.tor_geo_ip_file_path, self.tor_geo_ipv6_file_path, self.obfs4proxy_file_path) = common.get_tor_paths() + (self.tor_path, self.tor_geo_ip_file_path, self.tor_geo_ipv6_file_path, self.obfs4proxy_file_path) = self.common.get_tor_paths() if not os.path.isfile(self.obfs4proxy_file_path): - self.tor_bridges_use_meek_lite_azure_radio = QtWidgets.QRadioButton(strings._('gui_settings_tor_bridges_meek_lite_azure_radio_option_no_obfs4proxy', True)) + self.tor_bridges_use_meek_lite_azure_radio = QtWidgets.QRadioButton(strings._('gui_settings_tor_bridges_meek_lite_azure_radio_option_no_obfs4proxy')) self.tor_bridges_use_meek_lite_azure_radio.setEnabled(False) else: - self.tor_bridges_use_meek_lite_azure_radio = QtWidgets.QRadioButton(strings._('gui_settings_tor_bridges_meek_lite_azure_radio_option', True)) + self.tor_bridges_use_meek_lite_azure_radio = QtWidgets.QRadioButton(strings._('gui_settings_tor_bridges_meek_lite_azure_radio_option')) self.tor_bridges_use_meek_lite_azure_radio.toggled.connect(self.tor_bridges_use_meek_lite_azure_radio_toggled) - # meek_lite currently not supported on the version of obfs4proxy bundled with TorBrowser - if self.system == 'Windows' or self.system == 'Darwin': - self.tor_bridges_use_meek_lite_amazon_radio.hide() - self.tor_bridges_use_meek_lite_azure_radio.hide() - # 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 = QtWidgets.QRadioButton(strings._('gui_settings_tor_bridges_custom_radio_option')) 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 = QtWidgets.QLabel(strings._('gui_settings_tor_bridges_custom_label')) 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() @@ -212,7 +313,6 @@ class SettingsDialog(QtWidgets.QDialog): 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_meek_lite_amazon_radio) bridges_layout.addWidget(self.tor_bridges_use_meek_lite_azure_radio) bridges_layout.addWidget(self.tor_bridges_use_custom_radio) bridges_layout.addWidget(self.tor_bridges_use_custom_textbox_options) @@ -221,14 +321,14 @@ class SettingsDialog(QtWidgets.QDialog): 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 = QtWidgets.QRadioButton(strings._('gui_settings_connection_type_automatic_option')) 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 = QtWidgets.QRadioButton(strings._('gui_settings_connection_type_control_port_option')) 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)) + connection_type_control_port_extras_label = QtWidgets.QLabel(strings._('gui_settings_control_port_label')) 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() @@ -241,10 +341,10 @@ class SettingsDialog(QtWidgets.QDialog): 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 = QtWidgets.QRadioButton(strings._('gui_settings_connection_type_socket_file_option')) 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)) + connection_type_socket_file_extras_label = QtWidgets.QLabel(strings._('gui_settings_socket_file_label')) 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) @@ -255,7 +355,7 @@ class SettingsDialog(QtWidgets.QDialog): self.connection_type_socket_file_extras.hide() # Tor SOCKS address and port - gui_settings_socks_label = QtWidgets.QLabel(strings._('gui_settings_socks_label', True)) + gui_settings_socks_label = QtWidgets.QLabel(strings._('gui_settings_socks_label')) self.connection_type_socks_address = QtWidgets.QLineEdit() self.connection_type_socks_port = QtWidgets.QLineEdit() connection_type_socks_layout = QtWidgets.QHBoxLayout() @@ -270,14 +370,14 @@ class SettingsDialog(QtWidgets.QDialog): # Authentication options # No authentication - self.authenticate_no_auth_radio = QtWidgets.QRadioButton(strings._('gui_settings_authenticate_no_auth_option', True)) + self.authenticate_no_auth_radio = QtWidgets.QRadioButton(strings._('gui_settings_authenticate_no_auth_option')) 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 = QtWidgets.QRadioButton(strings._('gui_settings_authenticate_password_option')) self.authenticate_password_radio.toggled.connect(self.authenticate_password_toggled) - authenticate_password_extras_label = QtWidgets.QLabel(strings._('gui_settings_password_label', True)) + authenticate_password_extras_label = QtWidgets.QLabel(strings._('gui_settings_password_label')) self.authenticate_password_extras_password = QtWidgets.QLineEdit('') authenticate_password_extras_layout = QtWidgets.QHBoxLayout() authenticate_password_extras_layout.addWidget(authenticate_password_extras_label) @@ -292,47 +392,49 @@ class SettingsDialog(QtWidgets.QDialog): 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 = QtWidgets.QGroupBox(strings._("gui_settings_authenticate_label")) 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 = QtWidgets.QGroupBox(strings._("gui_settings_connection_type_label")) 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 = QtWidgets.QGroupBox(strings._("gui_settings_tor_bridges")) self.connection_type_bridges_radio_group.setLayout(connection_type_bridges_radio_group_layout) self.connection_type_bridges_radio_group.hide() + # Test tor settings button + self.connection_type_test_button = QtWidgets.QPushButton(strings._('gui_settings_connection_type_test_button')) + self.connection_type_test_button.clicked.connect(self.test_tor_clicked) + connection_type_test_button_layout = QtWidgets.QHBoxLayout() + connection_type_test_button_layout.addWidget(self.connection_type_test_button) + connection_type_test_button_layout.addStretch() + + # Connection type layout + connection_type_layout = QtWidgets.QVBoxLayout() + connection_type_layout.addWidget(self.connection_type_control_port_extras) + connection_type_layout.addWidget(self.connection_type_socket_file_extras) + connection_type_layout.addWidget(self.connection_type_socks) + connection_type_layout.addWidget(self.authenticate_group) + connection_type_layout.addWidget(self.connection_type_bridges_radio_group) + connection_type_layout.addLayout(connection_type_test_button_layout) + # Buttons - self.save_button = QtWidgets.QPushButton(strings._('gui_settings_button_save', True)) + self.save_button = QtWidgets.QPushButton(strings._('gui_settings_button_save')) self.save_button.clicked.connect(self.save_clicked) - self.cancel_button = QtWidgets.QPushButton(strings._('gui_settings_button_cancel', True)) + self.cancel_button = QtWidgets.QPushButton(strings._('gui_settings_button_cancel')) self.cancel_button.clicked.connect(self.cancel_clicked) - version_label = QtWidgets.QLabel('OnionShare {0:s}'.format(common.get_version())) - version_label.setStyleSheet('color: #666666') - self.help_button = QtWidgets.QPushButton(strings._('gui_settings_button_help', True)) + version_label = QtWidgets.QLabel('OnionShare {0:s}'.format(self.common.version)) + version_label.setStyleSheet(self.common.css['settings_version']) + self.help_button = QtWidgets.QPushButton(strings._('gui_settings_button_help')) self.help_button.clicked.connect(self.help_clicked) buttons_layout = QtWidgets.QHBoxLayout() buttons_layout.addWidget(version_label) @@ -343,20 +445,22 @@ class SettingsDialog(QtWidgets.QDialog): # Tor network connection status self.tor_status = QtWidgets.QLabel() - self.tor_status.setStyleSheet('background-color: #ffffff; color: #000000; padding: 10px') + self.tor_status.setStyleSheet(self.common.css['settings_tor_status']) self.tor_status.hide() # Layout left_col_layout = QtWidgets.QVBoxLayout() + left_col_layout.addWidget(general_group) + left_col_layout.addWidget(onion_group) left_col_layout.addWidget(sharing_group) - left_col_layout.addWidget(stealth_group) + left_col_layout.addWidget(receiving_group) left_col_layout.addWidget(autoupdate_group) + left_col_layout.addLayout(language_layout) 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.addLayout(connection_type_layout) right_col_layout.addWidget(self.tor_status) right_col_layout.addStretch() @@ -371,8 +475,11 @@ class SettingsDialog(QtWidgets.QDialog): self.setLayout(layout) self.cancel_button.setFocus() + self.reload_settings() + + def reload_settings(self): # Load settings, and fill them in - self.old_settings = Settings(self.config) + self.old_settings = Settings(self.common, self.config) self.old_settings.load() close_after_first_download = self.old_settings.get('close_after_first_download') @@ -381,12 +488,6 @@ class SettingsDialog(QtWidgets.QDialog): 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) - shutdown_timeout = self.old_settings.get('shutdown_timeout') if shutdown_timeout: self.shutdown_timeout_checkbox.setCheckState(QtCore.Qt.Checked) @@ -399,11 +500,30 @@ class SettingsDialog(QtWidgets.QDialog): else: self.save_private_key_checkbox.setCheckState(QtCore.Qt.Unchecked) + use_legacy_v2_onions = self.old_settings.get('use_legacy_v2_onions') + + if use_legacy_v2_onions: + self.use_legacy_v2_onions_checkbox.setCheckState(QtCore.Qt.Checked) + self.use_stealth_widget.show() + else: + self.use_stealth_widget.hide() + + data_dir = self.old_settings.get('data_dir') + self.data_dir_lineedit.setText(data_dir) + + public_mode = self.old_settings.get('public_mode') + if public_mode: + self.public_mode_checkbox.setCheckState(QtCore.Qt.Checked) + else: + self.public_mode_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() + # Legacy v2 mode is forced on if Stealth is enabled + self.use_legacy_v2_onions_checkbox.setEnabled(False) + if save_private_key and self.old_settings.get('hidservauth_string') != "": + self.hidservauth_details.show() self.hidservauth_copy_button.show() else: self.stealth_checkbox.setCheckState(QtCore.Qt.Unchecked) @@ -417,6 +537,10 @@ class SettingsDialog(QtWidgets.QDialog): autoupdate_timestamp = self.old_settings.get('autoupdate_timestamp') self._update_autoupdate_timestamp(autoupdate_timestamp) + locale = self.old_settings.get('locale') + locale_index = self.language_combobox.findData(QtCore.QVariant(locale)) + self.language_combobox.setCurrentIndex(locale_index) + connection_type = self.old_settings.get('connection_type') if connection_type == 'bundled': if self.connection_type_bundled_radio.isEnabled(): @@ -445,13 +569,11 @@ class SettingsDialog(QtWidgets.QDialog): 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_meek_lite_amazon_radio.setChecked(False) self.tor_bridges_use_meek_lite_azure_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')) - self.tor_bridges_use_meek_lite_amazon_radio.setChecked(self.old_settings.get('tor_bridges_use_meek_lite_amazon')) self.tor_bridges_use_meek_lite_azure_radio.setChecked(self.old_settings.get('tor_bridges_use_meek_lite_azure')) if self.old_settings.get('tor_bridges_use_custom_bridges'): @@ -466,11 +588,29 @@ class SettingsDialog(QtWidgets.QDialog): new_bridges = ''.join(new_bridges) self.tor_bridges_use_custom_textbox.setPlainText(new_bridges) + # If we're connected to Tor, show onion service settings, show label if not + if self.onion.is_authenticated(): + self.connect_to_tor_label.hide() + self.onion_settings_widget.show() + + # If v3 onion services are supported, allow using legacy mode + if self.onion.supports_v3_onions: + self.common.log('SettingsDialog', '__init__', 'v3 onions are supported') + self.use_legacy_v2_onions_checkbox.show() + else: + self.common.log('SettingsDialog', '__init__', 'v3 onions are not supported') + self.use_legacy_v2_onions_widget.hide() + self.use_legacy_v2_onions_checkbox_clicked(True) + else: + self.connect_to_tor_label.show() + self.onion_settings_widget.hide() + + def connection_type_bundled_toggled(self, checked): """ Connection type bundled was toggled. If checked, hide authentication fields. """ - common.log('SettingsDialog', 'connection_type_bundled_toggled') + self.common.log('SettingsDialog', 'connection_type_bundled_toggled') if checked: self.authenticate_group.hide() self.connection_type_socks.hide() @@ -490,19 +630,15 @@ class SettingsDialog(QtWidgets.QDialog): if checked: self.tor_bridges_use_custom_textbox_options.hide() - def tor_bridges_use_meek_lite_amazon_radio_toggled(self, checked): - """ - meek_lite-amazon bridges option was toggled. If checked, disable custom bridge options. - """ - if checked: - self.tor_bridges_use_custom_textbox_options.hide() - def tor_bridges_use_meek_lite_azure_radio_toggled(self, checked): """ meek_lite_azure bridges option was toggled. If checked, disable custom bridge options. """ if checked: self.tor_bridges_use_custom_textbox_options.hide() + # Alert the user about meek's costliness if it looks like they're turning it on + if not self.old_settings.get('tor_bridges_use_meek_lite_azure'): + Alert(self.common, strings._('gui_settings_meek_lite_expensive_warning'), QtWidgets.QMessageBox.Warning) def tor_bridges_use_custom_radio_toggled(self, checked): """ @@ -515,7 +651,7 @@ class SettingsDialog(QtWidgets.QDialog): """ Connection type automatic was toggled. If checked, hide authentication fields. """ - common.log('SettingsDialog', 'connection_type_automatic_toggled') + self.common.log('SettingsDialog', 'connection_type_automatic_toggled') if checked: self.authenticate_group.hide() self.connection_type_socks.hide() @@ -526,7 +662,7 @@ class SettingsDialog(QtWidgets.QDialog): 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') + self.common.log('SettingsDialog', 'connection_type_control_port_toggled') if checked: self.authenticate_group.show() self.connection_type_control_port_extras.show() @@ -541,7 +677,7 @@ class SettingsDialog(QtWidgets.QDialog): 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') + self.common.log('SettingsDialog', 'connection_type_socket_file_toggled') if checked: self.authenticate_group.show() self.connection_type_socket_file_extras.show() @@ -554,14 +690,14 @@ class SettingsDialog(QtWidgets.QDialog): """ Authentication option no authentication was toggled. """ - common.log('SettingsDialog', 'authenticate_no_auth_toggled') + self.common.log('SettingsDialog', 'authenticate_no_auth_toggled') 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') + self.common.log('SettingsDialog', 'authenticate_password_toggled') if checked: self.authenticate_password_extras.show() else: @@ -572,16 +708,47 @@ class SettingsDialog(QtWidgets.QDialog): Toggle the 'Copy HidServAuth' button to copy the saved HidServAuth to clipboard. """ - common.log('SettingsDialog', 'hidservauth_copy_button_clicked', 'HidServAuth was copied to clipboard') + self.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 use_legacy_v2_onions_checkbox_clicked(self, checked): + """ + Show the legacy settings if the legacy mode is enabled. + """ + if checked: + self.use_stealth_widget.show() + else: + self.use_stealth_widget.hide() + + def stealth_checkbox_clicked_connect(self, checked): + """ + Prevent the v2 legacy mode being switched off if stealth is enabled + """ + if checked: + self.use_legacy_v2_onions_checkbox.setCheckState(QtCore.Qt.Checked) + self.use_legacy_v2_onions_checkbox.setEnabled(False) + else: + self.use_legacy_v2_onions_checkbox.setEnabled(True) + + def data_dir_button_clicked(self): + """ + Browse for a new OnionShare data directory + """ + data_dir = self.data_dir_lineedit.text() + selected_dir = QtWidgets.QFileDialog.getExistingDirectory(self, + strings._('gui_settings_data_dir_label'), data_dir) + + if selected_dir: + self.common.log('SettingsDialog', 'data_dir_button_clicked', 'selected dir: {}'.format(selected_dir)) + self.data_dir_lineedit.setText(selected_dir) + 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') + self.common.log('SettingsDialog', 'test_tor_clicked') settings = self.settings_from_fields() try: @@ -596,17 +763,17 @@ class SettingsDialog(QtWidgets.QDialog): else: tor_status_update_func = None - onion = Onion() - onion.connect(settings=settings, config=self.config, tor_status_update_func=tor_status_update_func) + onion = Onion(self.common) + onion.connect(custom_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)) + Alert(self.common, strings._('settings_test_success').format(onion.tor_version, onion.supports_ephemeral, onion.supports_stealth, onion.supports_v3_onions)) # Clean up onion.cleanup() except (TorErrorInvalidSetting, TorErrorAutomatic, TorErrorSocketPort, TorErrorSocketFile, TorErrorMissingPassword, TorErrorUnreadableCookieFile, TorErrorAuthError, TorErrorProtocolError, BundledTorNotSupported, BundledTorTimeout) as e: - Alert(e.args[0], QtWidgets.QMessageBox.Warning) + Alert(self.common, e.args[0], QtWidgets.QMessageBox.Warning) if settings.get('connection_type') == 'bundled': self.tor_status.hide() self._enable_buttons() @@ -615,14 +782,14 @@ class SettingsDialog(QtWidgets.QDialog): """ Check for Updates button clicked. Manually force an update check. """ - common.log('SettingsDialog', 'check_for_updates') + self.common.log('SettingsDialog', 'check_for_updates') # Disable buttons self._disable_buttons() self.qtapp.processEvents() def update_timestamp(): # Update the last checked label - settings = Settings(self.config) + settings = Settings(self.common, self.config) settings.load() autoupdate_timestamp = settings.get('autoupdate_timestamp') self._update_autoupdate_timestamp(autoupdate_timestamp) @@ -636,22 +803,22 @@ class SettingsDialog(QtWidgets.QDialog): # Check for updates def update_available(update_url, installed_version, latest_version): - Alert(strings._("update_available", True).format(update_url, installed_version, latest_version)) + Alert(self.common, strings._("update_available").format(update_url, installed_version, latest_version)) close_forced_update_thread() def update_not_available(): - Alert(strings._('update_not_available', True)) + Alert(self.common, strings._('update_not_available')) close_forced_update_thread() def update_error(): - Alert(strings._('update_error_check_error', True), QtWidgets.QMessageBox.Warning) + Alert(self.common, strings._('update_error_check_error'), QtWidgets.QMessageBox.Warning) close_forced_update_thread() - def update_invalid_version(): - Alert(strings._('update_error_invalid_latest_version', True).format(e.latest_version), QtWidgets.QMessageBox.Warning) + def update_invalid_version(latest_version): + Alert(self.common, strings._('update_error_invalid_latest_version').format(latest_version), QtWidgets.QMessageBox.Warning) close_forced_update_thread() - forced_update_thread = UpdateThread(self.onion, self.config, force=True) + forced_update_thread = UpdateThread(self.common, self.onion, self.config, force=True) forced_update_thread.update_available.connect(update_available) forced_update_thread.update_not_available.connect(update_not_available) forced_update_thread.update_error.connect(update_error) @@ -662,57 +829,73 @@ class SettingsDialog(QtWidgets.QDialog): """ Save button clicked. Save current settings to disk. """ - common.log('SettingsDialog', 'save_clicked') + self.common.log('SettingsDialog', 'save_clicked') + + 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 settings = self.settings_from_fields() if settings: + # If language changed, inform user they need to restart OnionShare + if changed(settings, self.old_settings, ['locale']): + # Look up error message in different locale + new_locale = settings.get('locale') + if new_locale in strings.translations and 'gui_settings_language_changed_notice' in strings.translations[new_locale]: + notice = strings.translations[new_locale]['gui_settings_language_changed_notice'] + else: + notice = strings._('gui_settings_language_changed_notice') + Alert(self.common, notice, QtWidgets.QMessageBox.Information) + + # Save the new 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']): - + if not self.local_only: + if self.onion.is_authenticated(): + self.common.log('SettingsDialog', 'save_clicked', 'Connected to Tor') + + 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_azure', + 'tor_bridges_use_custom_bridges']): + + reboot_onion = True + + else: + self.common.log('SettingsDialog', 'save_clicked', 'Not connected to Tor') + # Tor isn't connected, so try connecting 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 + self.common.log('SettingsDialog', 'save_clicked', 'rebooting the Onion') + self.onion.cleanup() - # 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.common, self.qtapp, self.onion, settings) + tor_con.start() - tor_con = TorConnectionDialog(self.qtapp, settings, self.onion) - tor_con.start() + self.common.log('SettingsDialog', 'save_clicked', 'Onion done rebooting, connected to Tor: {}'.format(self.onion.connected_to_tor)) - 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() - if self.onion.is_authenticated() and not tor_con.wasCanceled(): + else: self.settings_saved.emit() self.close() - else: self.settings_saved.emit() self.close() @@ -721,9 +904,9 @@ class SettingsDialog(QtWidgets.QDialog): """ Cancel button clicked. """ - common.log('SettingsDialog', 'cancel_clicked') - if not self.onion.is_authenticated(): - Alert(strings._('gui_tor_connection_canceled', True), QtWidgets.QMessageBox.Warning) + self.common.log('SettingsDialog', 'cancel_clicked') + if not self.local_only and not self.onion.is_authenticated(): + Alert(self.common, strings._('gui_tor_connection_canceled'), QtWidgets.QMessageBox.Warning) sys.exit() else: self.close() @@ -732,21 +915,31 @@ class SettingsDialog(QtWidgets.QDialog): """ Help button clicked. """ - common.log('SettingsDialog', 'help_clicked') - help_site = 'https://github.com/micahflee/onionshare/wiki' - QtGui.QDesktopServices.openUrl(QtCore.QUrl(help_site)) + self.common.log('SettingsDialog', 'help_clicked') + SettingsDialog.open_help() + + @staticmethod + def open_help(): + help_url = 'https://github.com/micahflee/onionshare/wiki' + QtGui.QDesktopServices.openUrl(QtCore.QUrl(help_url)) 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) + self.common.log('SettingsDialog', 'settings_from_fields') + settings = Settings(self.common, 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('shutdown_timeout', self.shutdown_timeout_checkbox.isChecked()) + + # Complicated logic here to force v2 onion mode on or off depending on other settings + if self.use_legacy_v2_onions_checkbox.isChecked(): + use_legacy_v2_onions = True + else: + use_legacy_v2_onions = False + if self.save_private_key_checkbox.isChecked(): settings.set('save_private_key', True) settings.set('private_key', self.old_settings.get('private_key')) @@ -758,11 +951,25 @@ class SettingsDialog(QtWidgets.QDialog): settings.set('slug', '') # Also unset the HidServAuth if we are removing our reusable private key settings.set('hidservauth_string', '') + + if use_legacy_v2_onions: + settings.set('use_legacy_v2_onions', True) + else: + settings.set('use_legacy_v2_onions', False) + + settings.set('data_dir', self.data_dir_lineedit.text()) + settings.set('public_mode', self.public_mode_checkbox.isChecked()) 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', '') + # Language + locale_index = self.language_combobox.currentIndex() + locale = self.language_combobox.itemData(locale_index) + settings.set('locale', locale) + + # Tor connection if self.connection_type_bundled_radio.isChecked(): settings.set('connection_type', 'bundled') if self.connection_type_automatic_radio.isChecked(): @@ -795,31 +1002,21 @@ class SettingsDialog(QtWidgets.QDialog): 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_meek_lite_amazon', False) settings.set('tor_bridges_use_meek_lite_azure', 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_meek_lite_amazon', False) - settings.set('tor_bridges_use_meek_lite_azure', False) - settings.set('tor_bridges_use_custom_bridges', '') - if self.tor_bridges_use_meek_lite_amazon_radio.isChecked(): - settings.set('no_bridges', False) - settings.set('tor_bridges_use_obfs4', False) - settings.set('tor_bridges_use_meek_lite_amazon', True) settings.set('tor_bridges_use_meek_lite_azure', False) settings.set('tor_bridges_use_custom_bridges', '') if self.tor_bridges_use_meek_lite_azure_radio.isChecked(): settings.set('no_bridges', False) settings.set('tor_bridges_use_obfs4', False) - settings.set('tor_bridges_use_meek_lite_amazon', False) settings.set('tor_bridges_use_meek_lite_azure', 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) - settings.set('tor_bridges_use_meek_lite_amazon', False) settings.set('tor_bridges_use_meek_lite_azure', False) # Insert a 'Bridge' line at the start of each bridge. @@ -835,10 +1032,8 @@ class SettingsDialog(QtWidgets.QDialog): ipv6_pattern = re.compile("(obfs4\s+)?\[(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\]:[0-9]+\s+[A-Z0-9]+(.+)$") meek_lite_pattern = re.compile("(meek_lite)(\s)+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+:[0-9]+)(\s)+([0-9A-Z]+)(\s)+url=(.+)(\s)+front=(.+)") if ipv4_pattern.match(bridge) or \ - ipv6_pattern.match(bridge): - new_bridges.append(''.join(['Bridge ', bridge, '\n'])) - bridges_valid = True - if self.system != 'Windows' and self.system != 'Darwin' and meek_lite_pattern.match(bridge): + ipv6_pattern.match(bridge) or \ + meek_lite_pattern.match(bridge): new_bridges.append(''.join(['Bridge ', bridge, '\n'])) bridges_valid = True @@ -846,41 +1041,42 @@ class SettingsDialog(QtWidgets.QDialog): new_bridges = ''.join(new_bridges) settings.set('tor_bridges_use_custom_bridges', new_bridges) else: - Alert(strings._('gui_settings_tor_bridges_invalid', True)) + Alert(self.common, strings._('gui_settings_tor_bridges_invalid')) settings.set('no_bridges', True) return False return settings def closeEvent(self, e): - common.log('SettingsDialog', 'closeEvent') + self.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') + if not self.local_only: + if not self.onion.is_authenticated(): + self.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) + # Wait 1ms for the event loop to finish, then quit + QtCore.QTimer.singleShot(1, self.qtapp.quit) def _update_autoupdate_timestamp(self, autoupdate_timestamp): - common.log('SettingsDialog', '_update_autoupdate_timestamp') + self.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)) + last_checked = strings._('gui_settings_autoupdate_timestamp_never') + self.autoupdate_timestamp.setText(strings._('gui_settings_autoupdate_timestamp').format(last_checked)) def _tor_status_update(self, progress, summary): - self.tor_status.setText('<strong>{}</strong><br>{}% {}'.format(strings._('connecting_to_tor', True), progress, summary)) + self.tor_status.setText('<strong>{}</strong><br>{}% {}'.format(strings._('connecting_to_tor'), progress, summary)) self.qtapp.processEvents() if 'Done' in summary: self.tor_status.hide() self._enable_buttons() def _disable_buttons(self): - common.log('SettingsDialog', '_disable_buttons') + self.common.log('SettingsDialog', '_disable_buttons') self.check_for_updates_button.setEnabled(False) self.connection_type_test_button.setEnabled(False) @@ -888,7 +1084,7 @@ class SettingsDialog(QtWidgets.QDialog): self.cancel_button.setEnabled(False) def _enable_buttons(self): - common.log('SettingsDialog', '_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) |