diff --git a/onionshare/onion.py b/onionshare/onion.py index 05d479b2..90881513 100644 --- a/onionshare/onion.py +++ b/onionshare/onion.py @@ -25,6 +25,7 @@ import os, sys, tempfile, shutil, urllib from . import socks from . import helpers, strings +from .settings import Settings class NoTor(Exception): """ @@ -60,6 +61,8 @@ class Onion(object): self.transparent_torification = transparent_torification self.stealth = stealth + self.settings = Settings() + # files and dirs to delete on shutdown self.cleanup_filenames = [] self.service_id = None diff --git a/onionshare/settings.py b/onionshare/settings.py new file mode 100644 index 00000000..2bafbeef --- /dev/null +++ b/onionshare/settings.py @@ -0,0 +1,90 @@ +# -*- coding: utf-8 -*- +""" +OnionShare | https://onionshare.org/ + +Copyright (C) 2016 Micah Lee + +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 +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +""" + +import platform, os, json + +from . import helpers + +class Settings(object): + """ + This class stores all of the settings for OnionShare, specifically for how + to connect to Tor. If it can't find the settings file, it uses the default, + which is to attempt to connect automatically using default Tor Browser + settings. + """ + def __init__(self): + self.filename = self.build_filename() + self.load() + + def build_filename(self): + """ + Returns the path of the settings file. + """ + p = platform.system() + if p == 'Windows': + appdata = os.environ['APPDATA'] + return '{}\\OnionShare\\onionshare.json'.format(appdata) + elif p == 'Darwin': + return os.path.expanduser('~/Library/Application Support/OnionShare/onionshare.json') + else: + return os.path.expanduser('~/.config/onionshare/onionshare.json') + + def load(self): + """ + Load the settings from file. + """ + default_settings = { + 'version': helpers.get_version(), + 'connection_type': 'automatic', + 'control_port_address': '127.0.0.1', + 'control_port_port': '9051', + 'socket_file_path': '/var/run/tor/control', + 'auth_type': 'no_auth', + 'auth_password': '', + 'auth_cookie_path': '/var/run/tor/control.authcookie' + } + + if os.path.exists(self.filename): + # If the settings file exists, load it + try: + self._settings = json.loads(open(self.filename, 'r').read()) + except: + # If the settings don't work, use default ones instead + self._settings = default_settings + + else: + # Otherwise, use default settings + self._settings = default_settings + + def save(self): + """ + Save settings to file. + """ + os.mkdirs(os.path.dirname(self.filename)) + open(self.filename, 'w').write(json.dumps(self._settings)) + + def get(self, key): + """ + Set a setting. + """ + return self._settings[key] + + def set(self, key, val): + self._settings[key] = val diff --git a/onionshare_gui/settings_dialog.py b/onionshare_gui/settings_dialog.py index 93e94c1d..55a76d0b 100644 --- a/onionshare_gui/settings_dialog.py +++ b/onionshare_gui/settings_dialog.py @@ -20,6 +20,7 @@ along with this program. If not, see . from PyQt5 import QtCore, QtWidgets, QtGui from onionshare import strings +from onionshare.settings import Settings class SettingsDialog(QtWidgets.QDialog): """ @@ -42,8 +43,8 @@ class SettingsDialog(QtWidgets.QDialog): 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('127.0.0.1') - self.connection_type_control_port_extras_port = QtWidgets.QLineEdit('9051') + 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) @@ -58,7 +59,7 @@ class SettingsDialog(QtWidgets.QDialog): 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('/var/run/tor/control') + 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) @@ -103,7 +104,7 @@ class SettingsDialog(QtWidgets.QDialog): self.authenticate_cookie_radio.toggled.connect(self.authenticate_cookie_toggled) authenticate_cookie_extras_label = QtWidgets.QLabel(strings._('gui_settings_cookie_label', True)) - self.authenticate_cookie_extras_cookie_path = QtWidgets.QLineEdit('/var/run/tor/control.authcookie') + self.authenticate_cookie_extras_cookie_path = QtWidgets.QLineEdit() authenticate_cookie_extras_layout = QtWidgets.QHBoxLayout() authenticate_cookie_extras_layout.addWidget(authenticate_cookie_extras_label) authenticate_cookie_extras_layout.addWidget(self.authenticate_cookie_extras_cookie_path) @@ -143,9 +144,28 @@ class SettingsDialog(QtWidgets.QDialog): layout.addLayout(buttons_layout) self.setLayout(layout) - # Set default option - self.connection_type_automatic_radio.setChecked(True) - self.authenticate_no_auth_radio.setChecked(True) + + # Load settings, and fill them in + self.settings = Settings() + connection_type = self.settings.get('connection_type') + if connection_type == 'automatic': + self.connection_type_automatic_radio.setChecked(True) + elif connection_type == 'control_port': + self.connect_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.settings.get('control_port_address')) + self.connection_type_control_port_extras_port.setText(self.settings.get('control_port_port')) + self.connection_type_socket_file_extras_path.setText(self.settings.get('socket_file_path')) + auth_type = self.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) + elif auth_type == 'cookie': + self.authenticate_cookie_radio.setChecked(True) + self.authenticate_password_extras_password.setText(self.settings.get('auth_password')) + self.authenticate_cookie_extras_cookie_path.setText(self.settings.get('auth_cookie_path')) # Show the dialog self.exec_()