From 09b58a8b99a9903758e931d88680895b2a5a8774 Mon Sep 17 00:00:00 2001 From: James Valleroy Date: Sun, 11 Sep 2016 17:20:01 -0400 Subject: [PATCH] tor: Add option to use upstream bridges --- actions/tor | 72 ++++++++++++++++++++++++++- plinth/modules/tor/forms.py | 16 ++++++ plinth/modules/tor/templates/tor.html | 14 ++++++ plinth/modules/tor/utils.py | 2 + plinth/modules/tor/views.py | 22 +++++++- 5 files changed, 124 insertions(+), 2 deletions(-) diff --git a/actions/tor b/actions/tor index db9bace8f..472fabce9 100755 --- a/actions/tor +++ b/actions/tor @@ -63,6 +63,16 @@ def parse_arguments(): configure.add_argument('--apt-transport-tor', choices=['enable', 'disable'], help='Configure package download over Tor') + configure.add_argument('--use-upstream-bridges', + choices=['enable', 'disable'], + help='Configure use of upstream bridges') + + upstream = subparsers.add_parser( + 'set-upstream-bridges', help='Set list of upstream bridges') + upstream.add_argument('--bridges', + help='List of upstream bridges to use') + + subparsers.add_parser('restart', help='Restart Tor') return parser.parse_args() @@ -137,6 +147,11 @@ def subcommand_configure(arguments): if arguments.service == 'disable': _disable() + restart = arguments.service is None and \ + arguments.hidden_service is None and \ + arguments.relay is None and arguments.bridge_relay is None + _use_upstream_bridges(arguments.use_upstream_bridges, restart=restart) + restart = arguments.service is None and arguments.hidden_service is None _enable_relay(arguments.relay, arguments.bridge_relay, restart=restart) @@ -155,15 +170,50 @@ def subcommand_configure(arguments): _disable_apt_transport_tor() +def subcommand_set_upstream_bridges(arguments): + """Set list of upstream bridges.""" + aug = augeas_load() + + aug.remove(TOR_CONFIG + '/Bridge') + if arguments.bridges: + bridges = arguments.bridges.split('\n') + for bridge in bridges: + if bridge.strip(): + aug.set(TOR_CONFIG + '/Bridge[last() + 1]', bridge.strip()) + + aug.save() + + +def subcommand_restart(_): + """Restart Tor.""" + if is_enabled() and is_running(): + action_utils.service_restart('tor') + + def get_status(): """Return dict with Tor status.""" aug = augeas_load() - return {'relay_enabled': _is_relay_enabled(aug), + return {'use_upstream_bridges': _are_upstream_bridges_enabled(aug), + 'upstream_bridges': _get_upstream_bridges(aug), + 'relay_enabled': _is_relay_enabled(aug), 'bridge_relay_enabled': _is_bridge_relay_enabled(aug), 'ports': _get_ports(), 'hidden_service': _get_hidden_service(aug)} +def _are_upstream_bridges_enabled(aug): + """Return whether upstream bridges are being used.""" + use_bridges = aug.get(TOR_CONFIG + '/UseBridges') + return use_bridges == '1' + + +def _get_upstream_bridges(aug): + """Return upstream bridges separated by newlines.""" + matches = aug.match(TOR_CONFIG + '/Bridge') + bridges = [aug.get(match) for match in matches] + return '\n'.join(bridges) + + def _is_relay_enabled(aug): """Return whether a relay is enabled.""" orport = aug.get(TOR_CONFIG + '/ORPort') @@ -262,6 +312,26 @@ def _disable(): action_utils.service_disable('tor@plinth') +def _use_upstream_bridges(use_upstream_bridges=None, restart=True, aug=None): + """Enable use of upstream bridges.""" + if use_upstream_bridges is None: + return + + if not aug: + aug = augeas_load() + + if use_upstream_bridges == 'enable': + aug.set(TOR_CONFIG + '/UseBridges', '1') + elif use_upstream_bridges == 'disable': + aug.set(TOR_CONFIG + '/UseBridges', '0') + + aug.save() + + if restart: + if is_enabled() and is_running(): + action_utils.service_restart('tor') + + def _enable_relay(relay=None, bridge=None, restart=True, aug=None): """Enable Tor bridge relay.""" if relay is None and bridge is None: diff --git a/plinth/modules/tor/forms.py b/plinth/modules/tor/forms.py index 43ffe5091..5f6174c7f 100644 --- a/plinth/modules/tor/forms.py +++ b/plinth/modules/tor/forms.py @@ -20,6 +20,7 @@ Forms for configuring Tor. """ from django import forms +from django.forms import widgets from django.utils.translation import ugettext_lazy as _ from plinth import cfg @@ -62,3 +63,18 @@ class TorForm(forms.Form): # pylint: disable=W0232 'network for installations and upgrades. This adds a ' 'degree of privacy and security during software ' 'downloads.')) + use_upstream_bridges = forms.BooleanField( + label=_('Use upstream bridges to connect to Tor network'), + required=False, + help_text=_('When enabled, the bridges configured below will be used ' + 'to connect to the Tor network. This will disable relay ' + 'modes. Use this option only if you cannot connect to ' + 'the Tor network directly.')) + upstream_bridges = forms.CharField( + widget=widgets.Textarea, + label=_('Upstream bridges'), + required=False, + help_text=_('If you need to use a bridge to connect to Tor network, ' + 'you can get some bridges from ' + 'https://bridges.torproject.org/ and paste the bridge ' + 'information here.')) diff --git a/plinth/modules/tor/templates/tor.html b/plinth/modules/tor/templates/tor.html index db63a08cc..b0d708f7d 100644 --- a/plinth/modules/tor/templates/tor.html +++ b/plinth/modules/tor/templates/tor.html @@ -151,6 +151,20 @@ $('#id_tor-bridge_relay_enabled').prop('checked', false); } }).change(); + + $('#id_tor-use_upstream_bridges').change(function() { + if ($('#id_tor-use_upstream_bridges').prop('checked')) { + $('#id_tor-upstream_bridges').show('slow'); + $('label[for="id_tor-upstream_bridges"]').show('slow'); + $('label[for="id_tor-upstream_bridges"]').parent().show('slow'); + $('#id_tor-relay_enabled').prop('checked', false); + $('#id_tor-bridge_relay_enabled').prop('checked', false); + } else { + $('#id_tor-upstream_bridges').hide('slow'); + $('label[for="id_tor-upstream_bridges"]').hide('slow'); + $('label[for="id_tor-upstream_bridges"]').parent().hide('slow'); + } + }).change(); })(jQuery); // @license-end diff --git a/plinth/modules/tor/utils.py b/plinth/modules/tor/utils.py index 0c688d577..36f62ad68 100644 --- a/plinth/modules/tor/utils.py +++ b/plinth/modules/tor/utils.py @@ -64,6 +64,8 @@ def get_status(): return {'enabled': is_enabled(), 'is_running': is_running(), + 'use_upstream_bridges': status['use_upstream_bridges'], + 'upstream_bridges': status['upstream_bridges'], 'relay_enabled': status['relay_enabled'], 'bridge_relay_enabled': status['bridge_relay_enabled'], 'ports': ports, diff --git a/plinth/modules/tor/views.py b/plinth/modules/tor/views.py index e36ee33fe..7a7d43cde 100644 --- a/plinth/modules/tor/views.py +++ b/plinth/modules/tor/views.py @@ -74,6 +74,15 @@ def __apply_changes(request, old_status, new_status): # Already running a configuration task return + needs_restart = False + + if old_status['upstream_bridges'] != new_status['upstream_bridges']: + if new_status['enabled'] and new_status['use_upstream_bridges']: + actions.superuser_run( + 'tor', ['set-upstream-bridges', '--bridges', + new_status['upstream_bridges']]) + needs_restart = True + arguments = [] if old_status['enabled'] != new_status['enabled']: @@ -102,11 +111,22 @@ def __apply_changes(request, old_status, new_status): arg_value = 'enable' arguments.extend(['--apt-transport-tor', arg_value]) + if old_status['use_upstream_bridges'] != \ + new_status['use_upstream_bridges']: + arg_value = 'disable' + if new_status['enabled'] and new_status['use_upstream_bridges']: + arg_value = 'enable' + arguments.extend(['--use-upstream-bridges', arg_value]) + if arguments: config_process = actions.superuser_run( 'tor', ['configure'] + arguments, async=True) else: - messages.info(request, _('Setting unchanged')) + if needs_restart: + config_process = actions.superuser_run( + 'tor', ['restart'], async=True) + else: + messages.info(request, _('Setting unchanged')) def _collect_config_result(request):