commit 3aa83a9de0056425c47d3f3695ec6a299218c4f0 Author: Damian Johnson atagar@torproject.org Date: Thu Apr 10 09:13:47 2014 -0700
Using Stem's connect() method
Replacing our connection and authentication code in favor of stem's shiny new method for this. --- arm/__init__.py | 2 +- arm/arguments.py | 2 +- arm/config/strings.cfg | 38 --------------------- arm/starter.py | 21 ++++++++---- arm/util/__init__.py | 77 +++--------------------------------------- test/util/authenticate.py | 73 --------------------------------------- test/util/init_controller.py | 67 ------------------------------------ 7 files changed, 21 insertions(+), 259 deletions(-)
diff --git a/arm/__init__.py b/arm/__init__.py index c203b5f..25e322f 100644 --- a/arm/__init__.py +++ b/arm/__init__.py @@ -2,7 +2,7 @@ Scripts involved in validating user input, system state, and initializing arm. """
-__all__ = ["starter", "prereq", "version", "config_panel", "controller", "header_panel", "log_panel", "popups", "torrc_panel"] +__all__ = ["starter", "arguments", "prereq", "version", "config_panel", "controller", "header_panel", "log_panel", "popups", "torrc_panel"]
__version__ = '1.4.6_dev' __release_date__ = 'April 28, 2011' diff --git a/arm/arguments.py b/arm/arguments.py index 3d4a656..b527564 100644 --- a/arm/arguments.py +++ b/arm/arguments.py @@ -25,7 +25,7 @@ DEFAULT_ARGS = { 'print_help': False, }
-OPT = 'i:s:c:d:bl:vh' +OPT = 'i:s:c:d:l:vh'
OPT_EXPANDED = [ 'interface=', diff --git a/arm/config/strings.cfg b/arm/config/strings.cfg index 17a9cd7..3ac3b3c 100644 --- a/arm/config/strings.cfg +++ b/arm/config/strings.cfg @@ -3,7 +3,6 @@ # User facing strings. These are sorted into the following namespaces... # # * config parsing or handling configuration options -# * connect connection and authentication to tor # * debug concerns the --debug argument # * misc anything that doesn't fit into a present namespace # * setup notificaitons or issues arising while starting arm @@ -18,15 +17,6 @@ msg.config.unable_to_load_settings Unable to load arm's internal configurations: msg.config.unable_to_read_file Failed to load configuration (using defaults): "{error}" msg.config.nothing_loaded No armrc loaded, using defaults. You can customize arm by placing a configuration file at {path} (see the armrc.sample for its options).
-msg.connect.general_auth_failure Unable to authenticate: {error} -msg.connect.incorrect_password Incorrect password -msg.connect.no_control_port Unable to connect to tor. Maybe it's running without a ControlPort? -msg.connect.password_prompt Tor controller password: -msg.connect.socket_doesnt_exist The socket file you specified ({path}) doesn't exist -msg.connect.tor_isnt_running Unable to connect to tor. Are you sure it's running? -msg.connect.unable_to_use_port Unable to connect to {address}:{port}: {error} -msg.connect.unable_to_use_socket Unable to connect to '{path}': {error} - msg.debug.saving_to_path Saving a debug log to {path}, please check it for sensitive information before sharing it. msg.debug.unable_to_write_file Unable to write to our debug log file ({path}): {error}
@@ -53,26 +43,6 @@ msg.usage.not_a_valid_port '{port_input}' isn't a valid port number msg.usage.unrecognized_log_flags Unrecognized event flags: {flags} msg.usage.unable_to_set_color_override "{color}" isn't a valid color
-msg.connect.missing_password_bug -|BUG: You provided a password but despite this stem reported that it was -|missing. This shouldn't happen - please let us know about it! -| -| http://bugs.torproject.org - -msg.connect.unreadable_cookie_file -|We were unable to read tor's authentication cookie... -| -| Path: {path} -| Issue: {issue} - -msg.connect.wrong_port_type -|Please check in your torrc that {port} is the ControlPort. Maybe you -|configured it to be the ORPort or SocksPort instead? - -msg.connect.wrong_socket_type -|Unable to connect to tor. Are you sure the interface you specified belongs to -|tor? - msg.debug.header |Arm {arm_version} Debug Dump |Stem Version: {stem_version} @@ -99,14 +69,6 @@ msg.setup.unknown_term |Either update your terminfo database or run arm using "TERM=xterm arm". |
-msg.uncrcognized_auth_type -|Tor is using a type of authentication we do not recognize... -| -| {auth_methods} -| -|Please check that arm is up to date and if there is an existing issue on -|'http://bugs.torproject.org'. If there isn't one then let us know! - msg.usage.help_output |Usage arm [OPTION] |Terminal status monitor for Tor relays. diff --git a/arm/starter.py b/arm/starter.py index 9493415..ba7c9af 100644 --- a/arm/starter.py +++ b/arm/starter.py @@ -22,11 +22,12 @@ import arm.util.tracker import arm.util.ui_tools
import stem +import stem.connection import stem.util.conf import stem.util.log import stem.util.system
-from arm.util import BASE_DIR, init_controller, authenticate, msg, trace, info, notice, warn, load_settings +from arm.util import BASE_DIR, init_controller, msg, trace, info, notice, warn, load_settings
CONFIG = stem.util.conf.get_config('arm')
@@ -64,13 +65,21 @@ def main():
_load_user_armrc(args.config)
- try: - controller = init_controller(args) - authenticate(controller, CONFIG.get('tor.password', None), CONFIG.get('tor.chroot', '')) - except ValueError as exc: - print exc + control_port = None if args.user_provided_socket else (args.control_address, args.control_port) + control_socket = None if args.user_provided_port else args.control_socket + + controller = stem.connection.connect( + control_port = control_port, + control_socket = control_socket, + password = CONFIG.get('tor.password', None), + password_prompt = True, + chroot_path = CONFIG.get('tor.chroot', ''), + ) + + if controller is None: exit(1)
+ init_controller(controller) _warn_if_root(controller) _warn_if_unable_to_get_pid(controller) _setup_freebsd_chroot(controller) diff --git a/arm/util/__init__.py b/arm/util/__init__.py index d94173b..d606a43 100644 --- a/arm/util/__init__.py +++ b/arm/util/__init__.py @@ -6,7 +6,6 @@ and safely working with curses (hiding some of the gory details).
__all__ = ["connections", "panel", "sysTools", "text_input", "tor_config", "tor_tools", "tracker", "ui_tools"]
-import getpass import os
import stem @@ -29,57 +28,15 @@ def tor_controller(): return TOR_CONTROLLER
-def init_controller(args): +def init_controller(controller): """ - Provides a Controller for the endpoint specified in the given arguments. + Sets the Controller used by arm.
- :param namedtuple args: arguments that arm was started with - - :returns: :class:`~stem.control.Controller` for the given arguments - - :raises: **ValueError** if unable to acquire a controller connection + :param Controller controller: control connection to be used by arm """
global TOR_CONTROLLER - TOR_CONTROLLER = _get_controller(args) - return TOR_CONTROLLER - - -def authenticate(controller, password, chroot_path = ''): - """ - Authenticates to the given Controller. - - :param stem.control.Controller controller: controller to be authenticated - :param str password: password to authenticate with, **None** if nothing was - provided - :param str chroot_path: chroot tor resides within - - :raises: **ValueError** if unable to authenticate - """ - - try: - controller.authenticate(password = password, chroot_path = chroot_path) - except stem.connection.IncorrectSocketType: - control_socket = controller.get_socket() - - if isinstance(control_socket, stem.socket.ControlPort): - raise ValueError(msg('connect.wrong_port_type', port = control_socket.get_port())) - else: - raise ValueError(msg('connect.wrong_socket_type')) - except stem.connection.UnrecognizedAuthMethods as exc: - raise ValueError(msg('uncrcognized_auth_type', auth_methods = ', '.join(exc.unknown_auth_methods))) - except stem.connection.IncorrectPassword: - raise ValueError(msg('connect.incorrect_password')) - except stem.connection.MissingPassword: - if password: - raise ValueError(msg('connect.missing_password_bug')) - - password = getpass.getpass(msg('connect.password_prompt') + ' ') - return authenticate(controller, password) - except stem.connection.UnreadableCookieFile as exc: - raise ValueError(msg('connect.unreadable_cookie_file', path = exc.cookie_path, issue = str(exc))) - except stem.connection.AuthenticationFailure as exc: - raise ValueError(msg('connect.general_auth_failure', error = exc)) + TOR_CONTROLLER = controller
def msg(message, **attr): @@ -155,29 +112,3 @@ def _log(runlevel, message, **attr): """
stem.util.log.log(runlevel, msg(message, **attr)) - - -def _get_controller(args): - """ - Provides a Controller for the endpoint specified in the given arguments. - """ - - if os.path.exists(args.control_socket): - try: - return stem.control.Controller.from_socket_file(args.control_socket) - except stem.SocketError as exc: - if args.user_provided_socket: - raise ValueError(msg('connect.unable_to_use_socket', path = args.control_socket, error = exc)) - elif args.user_provided_socket: - raise ValueError(msg('connect.socket_doesnt_exist', path = args.control_socket)) - - try: - return stem.control.Controller.from_port(args.control_address, args.control_port) - except stem.SocketError as exc: - if args.user_provided_port: - raise ValueError(msg('connect.unable_to_use_port', address = args.control_address, port = args.control_port, error = exc)) - - if not stem.util.system.is_running('tor'): - raise ValueError(msg('connect.tor_isnt_running')) - else: - raise ValueError(msg('connect.no_control_port')) diff --git a/test/util/authenticate.py b/test/util/authenticate.py deleted file mode 100644 index 9dae10b..0000000 --- a/test/util/authenticate.py +++ /dev/null @@ -1,73 +0,0 @@ -import unittest - -from mock import Mock, patch - -from arm.util import ( - init_controller, - authenticate, -) - -import stem -import stem.connection -import stem.socket - - -class TestAuthenticate(unittest.TestCase): - def test_success(self): - controller = Mock() - - authenticate(controller, None) - controller.authenticate.assert_called_with(password = None, chroot_path = '') - controller.authenticate.reset_mock() - - authenticate(controller, 's3krit!!!', '/my/chroot') - controller.authenticate.assert_called_with(password = 's3krit!!!', chroot_path = '/my/chroot') - - @patch('getpass.getpass') - def test_success_with_password_prompt(self, getpass_mock): - controller = Mock() - - def authenticate_mock(password, **kwargs): - if password is None: - raise stem.connection.MissingPassword('no password') - elif password == 'my_password': - return None # success - else: - raise ValueError("Unexpected authenticate_mock input: %s" % password) - - controller.authenticate.side_effect = authenticate_mock - getpass_mock.return_value = 'my_password' - - authenticate(controller, None) - controller.authenticate.assert_any_call(password = None, chroot_path = '') - controller.authenticate.assert_any_call(password = 'my_password', chroot_path = '') - - def test_failure(self): - controller = Mock() - - controller.authenticate.side_effect = stem.connection.IncorrectSocketType('unable to connect to socket') - controller.get_socket.return_value = stem.socket.ControlPort(connect = False) - self._assert_authenticate_fails_with(controller, 'Please check in your torrc that 9051 is the ControlPort.') - - controller.get_socket.return_value = stem.socket.ControlSocketFile(connect = False) - self._assert_authenticate_fails_with(controller, 'Are you sure the interface you specified belongs to') - - controller.authenticate.side_effect = stem.connection.UnrecognizedAuthMethods('unable to connect', ['telepathy']) - self._assert_authenticate_fails_with(controller, 'Tor is using a type of authentication we do not recognize...\n\n telepathy') - - controller.authenticate.side_effect = stem.connection.IncorrectPassword('password rejected') - self._assert_authenticate_fails_with(controller, 'Incorrect password') - - controller.authenticate.side_effect = stem.connection.UnreadableCookieFile('permission denied', '/tmp/my_cookie', False) - self._assert_authenticate_fails_with(controller, "We were unable to read tor's authentication cookie...\n\n Path: /tmp/my_cookie\n Issue: permission denied") - - controller.authenticate.side_effect = stem.connection.OpenAuthRejected('crazy failure') - self._assert_authenticate_fails_with(controller, 'Unable to authenticate: crazy failure') - - def _assert_authenticate_fails_with(self, controller, msg): - try: - init_controller(authenticate(controller, None)) - self.fail() - except ValueError as exc: - if not msg in str(exc): - self.fail("Expected...\n\n%s\n\n... which couldn't be found in...\n\n%s" % (msg, exc)) diff --git a/test/util/init_controller.py b/test/util/init_controller.py deleted file mode 100644 index cbbeffa..0000000 --- a/test/util/init_controller.py +++ /dev/null @@ -1,67 +0,0 @@ -import unittest - -from mock import Mock, patch - -from arm.arguments import parse -from arm.util import init_controller - -import stem -import stem.connection -import stem.socket - - -class TestGetController(unittest.TestCase): - @patch('os.path.exists', Mock(return_value = True)) - @patch('stem.util.system.is_running') - @patch('stem.control.Controller.from_socket_file', Mock(side_effect = stem.SocketError('failed'))) - @patch('stem.control.Controller.from_port', Mock(side_effect = stem.SocketError('failed'))) - def test_failue_with_the_default_endpoint(self, is_running_mock): - is_running_mock.return_value = False - self._assert_init_controller_fails_with([], "Unable to connect to tor. Are you sure it's running?") - - is_running_mock.return_value = True - self._assert_init_controller_fails_with([], "Unable to connect to tor. Maybe it's running without a ControlPort?") - - @patch('os.path.exists') - @patch('stem.util.system.is_running', Mock(return_value = True)) - @patch('stem.control.Controller.from_socket_file', Mock(side_effect = stem.SocketError('failed'))) - @patch('stem.control.Controller.from_port', Mock(side_effect = stem.SocketError('failed'))) - def test_failure_with_a_custom_endpoint(self, path_exists_mock): - path_exists_mock.return_value = True - self._assert_init_controller_fails_with(['--interface', '80'], "Unable to connect to 127.0.0.1:80: failed") - self._assert_init_controller_fails_with(['--socket', '/tmp/my_socket'], "Unable to connect to '/tmp/my_socket': failed") - - path_exists_mock.return_value = False - self._assert_init_controller_fails_with(['--interface', '80'], "Unable to connect to 127.0.0.1:80: failed") - self._assert_init_controller_fails_with(['--socket', '/tmp/my_socket'], "The socket file you specified (/tmp/my_socket) doesn't exist") - - @patch('os.path.exists', Mock(return_value = False)) - @patch('stem.control.Controller.from_port') - def test_getting_a_control_port(self, from_port_mock): - from_port_mock.return_value = 'success' - - self.assertEqual('success', init_controller(parse([]))) - from_port_mock.assert_called_once_with('127.0.0.1', 9051) - from_port_mock.reset_mock() - - self.assertEqual('success', init_controller(parse(['--interface', '255.0.0.10:80']))) - from_port_mock.assert_called_once_with('255.0.0.10', 80) - - @patch('os.path.exists', Mock(return_value = True)) - @patch('stem.control.Controller.from_socket_file') - def test_getting_a_control_socket(self, from_socket_file_mock): - from_socket_file_mock.return_value = 'success' - - self.assertEqual('success', init_controller(parse([]))) - from_socket_file_mock.assert_called_once_with('/var/run/tor/control') - from_socket_file_mock.reset_mock() - - self.assertEqual('success', init_controller(parse(['--socket', '/tmp/my_socket']))) - from_socket_file_mock.assert_called_once_with('/tmp/my_socket') - - def _assert_init_controller_fails_with(self, args, msg): - try: - init_controller(parse(args)) - self.fail() - except ValueError as exc: - self.assertEqual(msg, str(exc))