diff --git a/onionshare/__init__.py b/onionshare/__init__.py index f799ea01..8a784e4b 100644 --- a/onionshare/__init__.py +++ b/onionshare/__init__.py @@ -44,6 +44,7 @@ def main(cwd=None): parser.add_argument('--stay-open', action='store_true', dest='stay_open', help=strings._("help_stay_open")) parser.add_argument('--stealth', action='store_true', dest='stealth', help=strings._("help_stealth")) parser.add_argument('--debug', action='store_true', dest='debug', help=strings._("help_debug")) + parser.add_argument('--config', metavar='config', default=False, help=strings._('help_config')) parser.add_argument('filename', metavar='filename', nargs='+', help=strings._('help_filename')) args = parser.parse_args() @@ -55,6 +56,7 @@ def main(cwd=None): debug = bool(args.debug) stay_open = bool(args.stay_open) stealth = bool(args.stealth) + config = args.config # Debug mode? if debug: @@ -76,7 +78,7 @@ def main(cwd=None): # Start the Onion object onion = Onion() try: - onion.connect() + onion.connect(settings=False, config=config) except (TorTooOld, TorErrorInvalidSetting, TorErrorAutomatic, TorErrorSocketPort, TorErrorSocketFile, TorErrorMissingPassword, TorErrorUnreadableCookieFile, TorErrorAuthError, TorErrorProtocolError, BundledTorNotSupported, BundledTorTimeout) as e: sys.exit(e.args[0]) except KeyboardInterrupt: diff --git a/onionshare/onion.py b/onionshare/onion.py index 41342b7e..efcd7ae2 100644 --- a/onionshare/onion.py +++ b/onionshare/onion.py @@ -148,14 +148,14 @@ class Onion(object): # Start out not connected to Tor self.connected_to_tor = False - def connect(self, settings=False, tor_status_update_func=None): + def connect(self, settings=False, config=False, tor_status_update_func=None): common.log('Onion', 'connect') # Either use settings that are passed in, or load them from disk if settings: self.settings = settings else: - self.settings = Settings() + self.settings = Settings(config) self.settings.load() # The Tor controller diff --git a/onionshare/settings.py b/onionshare/settings.py index 765b96d5..18e7dd26 100644 --- a/onionshare/settings.py +++ b/onionshare/settings.py @@ -29,11 +29,19 @@ class Settings(object): which is to attempt to connect automatically using default Tor Browser settings. """ - def __init__(self): + def __init__(self, config=False): common.log('Settings', '__init__') + # Default config self.filename = self.build_filename() + # If a readable config file was provided, use that instead + if config: + if os.path.isfile(config): + self.filename = config + else: + common.log('Settings', '__init__', 'Supplied config does not exist or is unreadable. Falling back to default location') + # These are the default settings. They will get overwritten when loading from disk self.default_settings = { 'version': common.get_version(), @@ -85,6 +93,7 @@ class Settings(object): # If the settings file exists, load it if os.path.exists(self.filename): try: + common.log('Settings', 'load', 'Trying to load {}'.format(self.filename)) with open(self.filename, 'r') as f: self._settings = json.loads(f.read()) self.fill_in_defaults() diff --git a/onionshare_gui/__init__.py b/onionshare_gui/__init__.py index b486b83d..4aa4ff83 100644 --- a/onionshare_gui/__init__.py +++ b/onionshare_gui/__init__.py @@ -66,6 +66,7 @@ def main(): parser.add_argument('--stay-open', action='store_true', dest='stay_open', help=strings._("help_stay_open")) parser.add_argument('--debug', action='store_true', dest='debug', help=strings._("help_debug")) parser.add_argument('--filenames', metavar='filenames', nargs='+', help=strings._('help_filename')) + parser.add_argument('--config', metavar='config', default=False, help=strings._('help_config')) args = parser.parse_args() filenames = args.filenames @@ -73,6 +74,8 @@ def main(): for i in range(len(filenames)): filenames[i] = os.path.abspath(filenames[i]) + config = args.config + local_only = bool(args.local_only) stay_open = bool(args.stay_open) debug = bool(args.debug) @@ -103,7 +106,7 @@ def main(): app = OnionShare(onion, local_only, stay_open) # Launch the gui - gui = OnionShareGui(onion, qtapp, app, filenames) + gui = OnionShareGui(onion, qtapp, app, filenames, config) # Clean up when app quits def shutdown(): diff --git a/onionshare_gui/onionshare_gui.py b/onionshare_gui/onionshare_gui.py index 1b1505d7..16e6444a 100644 --- a/onionshare_gui/onionshare_gui.py +++ b/onionshare_gui/onionshare_gui.py @@ -43,7 +43,7 @@ class OnionShareGui(QtWidgets.QMainWindow): starting_server_step3 = QtCore.pyqtSignal() starting_server_error = QtCore.pyqtSignal(str) - def __init__(self, onion, qtapp, app, filenames): + def __init__(self, onion, qtapp, app, filenames, config=False): super(OnionShareGui, self).__init__() self._initSystemTray() @@ -58,7 +58,8 @@ class OnionShareGui(QtWidgets.QMainWindow): self.setWindowIcon(QtGui.QIcon(common.get_resource_path('images/logo.png'))) # Load settings - self.settings = Settings() + self.config = config + self.settings = Settings(self.config) self.settings.load() # File selection @@ -219,7 +220,7 @@ class OnionShareGui(QtWidgets.QMainWindow): common.log('OnionShareGui', 'open_settings', 'settings have changed, reloading') self.settings.load() - d = SettingsDialog(self.onion, self.qtapp) + d = SettingsDialog(self.onion, self.qtapp, self.config) d.settings_saved.connect(reload_settings) d.exec_() @@ -351,7 +352,7 @@ class OnionShareGui(QtWidgets.QMainWindow): def update_available(update_url, installed_version, latest_version): Alert(strings._("update_available", True).format(update_url, installed_version, latest_version)) - self.update_thread = UpdateThread(self.onion) + self.update_thread = UpdateThread(self.onion, self.config) self.update_thread.update_available.connect(update_available) self.update_thread.start() diff --git a/onionshare_gui/settings_dialog.py b/onionshare_gui/settings_dialog.py index 71fc277a..fed4d1ab 100644 --- a/onionshare_gui/settings_dialog.py +++ b/onionshare_gui/settings_dialog.py @@ -34,12 +34,13 @@ class SettingsDialog(QtWidgets.QDialog): """ settings_saved = QtCore.pyqtSignal() - def __init__(self, onion, qtapp): + 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)) @@ -259,7 +260,7 @@ class SettingsDialog(QtWidgets.QDialog): self.cancel_button.setFocus() # Load settings, and fill them in - self.old_settings = Settings() + self.old_settings = Settings(self.config) self.old_settings.load() close_after_first_download = self.old_settings.get('close_after_first_download') @@ -397,7 +398,7 @@ class SettingsDialog(QtWidgets.QDialog): tor_status_update_func = None onion = Onion() - onion.connect(settings=settings, tor_status_update_func=tor_status_update_func) + 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)) @@ -441,7 +442,7 @@ class SettingsDialog(QtWidgets.QDialog): self._enable_buttons() # Update the last checked label - settings = Settings() + settings = Settings(self.config) settings.load() autoupdate_timestamp = settings.get('autoupdate_timestamp') self._update_autoupdate_timestamp(autoupdate_timestamp) @@ -519,7 +520,7 @@ class SettingsDialog(QtWidgets.QDialog): Return a Settings object that's full of values from the settings dialog. """ common.log('SettingsDialog', 'settings_from_fields') - settings = Settings() + 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()) diff --git a/onionshare_gui/update_checker.py b/onionshare_gui/update_checker.py index eeeeffe1..57fda0bd 100644 --- a/onionshare_gui/update_checker.py +++ b/onionshare_gui/update_checker.py @@ -52,15 +52,16 @@ class UpdateChecker(QtCore.QObject): update_available = QtCore.pyqtSignal(str, str, str) update_not_available = QtCore.pyqtSignal() - def __init__(self, onion): + def __init__(self, onion, config=False): super(UpdateChecker, self).__init__() common.log('UpdateChecker', '__init__') self.onion = onion + self.config = config - def check(self, force=False): + def check(self, force=False, config=False): common.log('UpdateChecker', 'check', 'force={}'.format(force)) # Load the settings - settings = Settings() + settings = Settings(config) settings.load() # If force=True, then definitely check @@ -146,20 +147,21 @@ class UpdateThread(QtCore.QThread): update_available = QtCore.pyqtSignal(str, str, str) update_not_available = QtCore.pyqtSignal() - def __init__(self, onion): + def __init__(self, onion, config=False): super(UpdateThread, self).__init__() common.log('UpdateThread', '__init__') self.onion = onion + self.config = config def run(self): common.log('UpdateThread', 'run') - u = UpdateChecker(self.onion) + u = UpdateChecker(self.onion, self.config) u.update_available.connect(self._update_available) u.update_not_available.connect(self._update_not_available) try: - u.check() + u.check(config=self.config) except Exception as e: # If update check fails, silently ignore common.log('UpdateThread', 'run', '{}'.format(e)) diff --git a/share/locale/en.json b/share/locale/en.json index 7352159e..cfd80455 100644 --- a/share/locale/en.json +++ b/share/locale/en.json @@ -29,6 +29,7 @@ "help_stealth": "Create stealth onion service (advanced)", "help_debug": "Log application errors to stdout, and log web errors to disk", "help_filename": "List of files or folders to share", + "help_config": "Path to a custom JSON config file (optional)", "gui_drag_and_drop": "Drag and drop\nfiles here", "gui_add": "Add", "gui_delete": "Delete",