Onion now connects to the Tor controller using the settings in Settings (except automatic still needs some work), and the settings dialog handles error when testing settings

This commit is contained in:
Micah Lee 2016-12-29 09:58:13 -08:00
parent 943e23658e
commit 19d020f245
No known key found for this signature in database
GPG Key ID: 403C2657CD994F73
4 changed files with 113 additions and 67 deletions

View File

@ -27,6 +27,38 @@ from . import socks
from . import helpers, strings
from .settings import Settings
class TorErrorInvalidSetting(Exception):
"""
This exception is raised if the settings just don't make sense.
"""
pass
class TorErrorSocketPort(Exception):
"""
OnionShare can't connect to the Tor controller using the supplied address and port.
"""
pass
class TorErrorSocketFile(Exception):
"""
OnionShare can't connect to the Tor controller using the supplied socket file.
"""
pass
class TorErrorMissingPassword(Exception):
"""
OnionShare connected to the Tor controller, but it requires a password.
"""
pass
class TorErrorUnreadableCookieFile(Exception):
"""
OnionShare connected to the Tor controller, but your user does not have permission
to access the cookie file.
"""
pass
class NoTor(Exception):
"""
This exception is raised if onionshare can't find a Tor control port
@ -72,34 +104,69 @@ class Onion(object):
self.cleanup_filenames = []
self.service_id = None
# if the TOR_CONTROL_PORT environment variable is set, use that
# otherwise, default to Tor Browser, Tor Messenger, and system tor ports
env_port = os.environ.get('TOR_CONTROL_PORT')
if env_port:
ports = [int(env_port)]
else:
ports = [9151, 9153, 9051]
# if the TOR_AUTHENTICATION_PASSWORD is set, use that to authenticate
password = os.environ.get('TOR_AUTHENTICATION_PASSWORD')
# connect to the tor controlport
found_tor = False
# Try to connect to Tor
self.c = None
for port in ports:
if self.settings.get('connection_type') == 'automatic':
# Automatically try to guess the right way to connect to Tor Browser
# if the TOR_CONTROL_PORT environment variable is set, use that
# otherwise, default to Tor Browser, Tor Messenger, and system tor ports
env_port = os.environ.get('TOR_CONTROL_PORT')
if env_port:
ports = [int(env_port)]
else:
ports = [9151, 9153, 9051]
# connect to the tor controlport
found_tor = False
for port in ports:
try:
self.c = Controller.from_port(port=port)
self.c.authenticate()
found_tor = True
break
except SocketError:
pass
except MissingPassword:
raise NoTor(strings._("ctrlport_missing_password").format(str(ports)))
except UnreadableCookieFile:
raise NoTor(strings._("ctrlport_unreadable_cookie").format(str(ports)))
if not found_tor:
raise NoTor(strings._("cant_connect_ctrlport").format(str(ports)))
else:
# Use specific settings to connect to tor
# Try connecting
try:
self.c = Controller.from_port(port=port)
self.c.authenticate(password)
found_tor = True
break
if self.settings.get('connection_type') == 'control_port':
self.c = Controller.from_port(address=self.settings.get('control_port_address'), port=self.settings.get('control_port_port'))
elif self.settings.get('connection_type') == 'socket_file':
self.c = Controller.from_socket_file(path=self.settings.get('socket_file_path'))
else:
raise TorErrorInvalidSetting(strings._("settings_error_unknown"))
except SocketError:
pass
if self.settings.get('connection_type') == 'control_port':
raise TorErrorSocketPort(strings._("settings_error_socket_port").format(self.settings.get('control_port_address'), self.settings.get('control_port_port')))
else:
raise TorErrorSocketFile(strings._("settings_error_socket_file").format(self.settings.get('socket_file_path')))
# Try authenticating
try:
if self.settings.get('auth_type') == 'no_auth':
self.c.authenticate()
elif self.settings.get('auth_type') == 'password':
self.c.authenticate(self.settings.get('auth_password'))
else:
raise TorErrorInvalidSetting(strings._("settings_error_unknown"))
except MissingPassword:
raise NoTor(strings._("ctrlport_missing_password").format(str(ports)))
raise TorErrorMissingPassword(strings._('settings_error_missing_password'))
except UnreadableCookieFile:
raise NoTor(strings._("ctrlport_unreadable_cookie").format(str(ports)))
if not found_tor:
raise NoTor(strings._("cant_connect_ctrlport").format(str(ports)))
raise TorErrorUnreadableCookieFile(strings._('settings_error_unreadable_cookie_file'))
# do the versions of stem and tor that I'm using support ephemeral onion services?
tor_version = self.c.get_version().version_str
@ -107,8 +174,7 @@ class Onion(object):
self.supports_ephemeral = callable(list_ephemeral_hidden_services) and tor_version >= '0.2.7.1'
# do the versions of stem and tor that I'm using support stealth onion services?
if self.stealth:
self.check_for_stealth_support()
self.check_for_stealth_support()
def check_for_stealth_support(self):
try:

View File

@ -37,11 +37,10 @@ class Settings(object):
'version': helpers.get_version(),
'connection_type': 'automatic',
'control_port_address': '127.0.0.1',
'control_port_port': '9051',
'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'
'auth_password': ''
}
def build_filename(self):

View File

@ -21,7 +21,9 @@ from PyQt5 import QtCore, QtWidgets, QtGui
from onionshare import strings
from onionshare.settings import Settings
from onionshare.onion import Onion
from onionshare.onion import Onion, TorErrorInvalidSetting, TorErrorSocketPort, TorErrorSocketFile, TorErrorMissingPassword, TorErrorUnreadableCookieFile
from .alert import Alert
class SettingsDialog(QtWidgets.QDialog):
"""
@ -100,27 +102,11 @@ class SettingsDialog(QtWidgets.QDialog):
self.authenticate_password_extras.setLayout(authenticate_password_extras_layout)
self.authenticate_password_extras.hide()
# Cookie
self.authenticate_cookie_radio = QtWidgets.QRadioButton(strings._('gui_settings_authenticate_cookie_option', True))
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()
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)
self.authenticate_cookie_extras = QtWidgets.QWidget()
self.authenticate_cookie_extras.setLayout(authenticate_cookie_extras_layout)
self.authenticate_cookie_extras.hide()
# Authentication options layout
authenticate_group_layout = QtWidgets.QVBoxLayout()
authenticate_group_layout.addWidget(self.authenticate_no_auth_radio)
authenticate_group_layout.addWidget(self.authenticate_password_radio)
authenticate_group_layout.addWidget(self.authenticate_cookie_radio)
authenticate_group_layout.addWidget(self.authenticate_password_extras)
authenticate_group_layout.addWidget(self.authenticate_cookie_extras)
self.authenticate_group = QtWidgets.QGroupBox(strings._("gui_settings_authenticate_label", True))
self.authenticate_group.setLayout(authenticate_group_layout)
@ -158,17 +144,14 @@ class SettingsDialog(QtWidgets.QDialog):
elif connection_type == 'socket_file':
self.connection_type_socket_file_radio.setChecked(True)
self.connection_type_control_port_extras_address.setText(settings.get('control_port_address'))
self.connection_type_control_port_extras_port.setText(settings.get('control_port_port'))
self.connection_type_control_port_extras_port.setText(str(settings.get('control_port_port')))
self.connection_type_socket_file_extras_path.setText(settings.get('socket_file_path'))
auth_type = 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(settings.get('auth_password'))
self.authenticate_cookie_extras_cookie_path.setText(settings.get('auth_cookie_path'))
# Show the dialog
self.exec_()
@ -220,24 +203,20 @@ class SettingsDialog(QtWidgets.QDialog):
else:
self.authenticate_password_extras.hide()
def authenticate_cookie_toggled(self, checked):
"""
Authentication option cookie was toggled. If checked, show extra fields
for cookie auth. If unchecked, hide those extra fields.
"""
if checked:
self.authenticate_cookie_extras.show()
else:
self.authenticate_cookie_extras.hide()
def test_clicked(self):
"""
Test Settings button clicked. With the given settings, see if we can
successfully connect and authenticate to Tor.
"""
print("Testing settings")
settings = self.settings_from_fields()
onion = Onion(settings=settings)
try:
onion = Onion(settings=settings)
# If an exception hasn't been raised yet, the Tor settings work
except (TorErrorInvalidSetting, TorErrorSocketPort, TorErrorSocketFile, TorErrorMissingPassword, TorErrorUnreadableCookieFile) as e:
Alert(e.args[0])
def save_clicked(self):
"""
@ -267,17 +246,14 @@ class SettingsDialog(QtWidgets.QDialog):
settings.set('connection_type', 'socket_file')
settings.set('control_port_address', self.connection_type_control_port_extras_address.text())
settings.set('control_port_port', self.connection_type_control_port_extras_port.text())
settings.set('control_port_port', int(self.connection_type_control_port_extras_port.text()))
settings.set('socket_file_path', self.connection_type_socket_file_extras_path.text())
if self.authenticate_no_auth_radio.isChecked():
settings.set('auth_type', 'no_auth')
if self.authenticate_password_radio.isChecked():
settings.set('auth_type', 'password')
if self.authenticate_cookie_radio.isChecked():
settings.set('auth_type', 'cookie')
settings.set('auth_password', self.authenticate_password_extras_password.text())
settings.set('auth_cookie_path', self.authenticate_cookie_extras_cookie_path.text())
return settings

View File

@ -70,7 +70,7 @@
"gui_settings_control_port_label": "Control port",
"gui_settings_socket_file_label": "Socket file",
"gui_settings_authenticate_label": "Tor authentication options",
"gui_settings_authenticate_no_auth_option": "No authentication",
"gui_settings_authenticate_no_auth_option": "No authentication, or cookie authentication",
"gui_settings_authenticate_password_option": "Password",
"gui_settings_authenticate_cookie_option": "Cookie",
"gui_settings_password_label": "Password",
@ -78,5 +78,10 @@
"gui_settings_button_test": "Test Settings",
"gui_settings_button_save": "Save",
"gui_settings_button_cancel": "Cancel",
"settings_saved": "Settings saved to {}"
"settings_saved": "Settings saved to {}",
"settings_error_unknown": "Can't connect to Tor controller because the settings don't make sense.",
"settings_error_socket_port": "Can't connect to Tor controller on address {} with port {}.",
"settings_error_socket_file": "Can't connect to Tor controller using socket file {}.",
"settings_error_missing_password": "Connected to Tor controller, but it requires a password to authenticate.",
"settings_error_unreadable_cookie_file": "Connected to Tor controller, but can't authenticate because your password may be wrong, and your user doesn't have permission to read the cookie file."
}