From 07130b6007de5740283270d6b3389a7307522d32 Mon Sep 17 00:00:00 2001 From: James Valleroy Date: Wed, 16 Dec 2015 21:47:18 -0500 Subject: [PATCH] tor: Run configuration update as background task - Closes: #294. --- actions/tor | 3 +- plinth/modules/tor/templates/tor.html | 152 +++++++++++++++----------- plinth/modules/tor/views.py | 45 ++++++-- 3 files changed, 124 insertions(+), 76 deletions(-) diff --git a/actions/tor b/actions/tor index 10ce49986..c17b84fd2 100755 --- a/actions/tor +++ b/actions/tor @@ -309,8 +309,6 @@ def _update_ports(): # port information may not be available immediately after Tor started while not ready: - time.sleep(5) - ports = get_ports() ready = 'orport' in ports and 'obfs3' in ports and 'obfs4' in ports if ready: @@ -319,6 +317,7 @@ def _update_ports(): tries += 1 if tries >= 12: return + time.sleep(10) lines = """ diff --git a/plinth/modules/tor/templates/tor.html b/plinth/modules/tor/templates/tor.html index 4d4ebbd31..2b1b0f07e 100644 --- a/plinth/modules/tor/templates/tor.html +++ b/plinth/modules/tor/templates/tor.html @@ -21,6 +21,15 @@ {% load bootstrap %} {% load i18n %} +{% block page_head %} + + {% if config_running %} + + {% endif %} + +{% endblock %} + + {% block content %}

{% trans "Anonymity Network (Tor)" %}

@@ -38,89 +47,100 @@

{% trans "Status" %}

-

- {% if status.is_running %} + {% if config_running %} + +

- {% trans "Tor is running" %} - {% else %} - - {% trans "Tor is not running" %} + {% trans "Tor configuration is being updated" %} +

+ + {% else %} + +

+ {% if status.is_running %} + + {% trans "Tor is running" %} + {% else %} + + {% trans "Tor is not running" %} + {% endif %} +

+ + {% include "diagnostics_button.html" with module="tor" %} + + {% if status.hs_enabled %} +
+
+ + + + + + + + + + + + + +
{% trans "Hidden Service" %}{% trans "Port" %}
{{ status.hs_hostname }}{{ status.hs_ports }}
+
+
{% endif %} -

- {% include "diagnostics_button.html" with module="tor" %} +

{% trans "Configuration" %}

+ +
+ {% csrf_token %} + + {{ form|bootstrap }} + + +
+ +

{% trans "Bridge" %}

+ +

+ {% blocktrans trimmed %} + Your {{ box_name }} is configured as a Tor bridge with obfsproxy, + so it can help circumvent censorship. If your {{ box_name }} is + behind a router or firewall, you should make sure the following + ports are open, and port-forwarded, if necessary: + {% endblocktrans %} +

- {% if status.hs_enabled %}
- + - - - - + {% for name, port in status.ports.items %} + + + + + {% endfor %}
{% trans "Hidden Service" %}{% trans "Service" %} {% trans "Port" %}
{{ status.hs_hostname }}{{ status.hs_ports }}
{{ name }}{{ port }}
+ +

{% trans "SOCKS" %}

+ +

+ {% blocktrans trimmed %} + A Tor SOCKS port is available on your {{ box_name }} on TCP port + 9050. + {% endblocktrans %} +

+ {% endif %} -

{% trans "Configuration" %}

- -
- {% csrf_token %} - - {{ form|bootstrap }} - - -
- -

{% trans "Bridge" %}

- -

- {% blocktrans trimmed %} - Your {{ box_name }} is configured as a Tor bridge with obfsproxy, - so it can help circumvent censorship. If your {{ box_name }} is - behind a router or firewall, you should make sure the following - ports are open, and port-forwarded, if necessary: - {% endblocktrans %} -

- -
-
- - - - - - - - - {% for name, port in status.ports.items %} - - - - - {% endfor %} - -
{% trans "Service" %}{% trans "Port" %}
{{ name }}{{ port }}
-
-
- -

{% trans "SOCKS" %}

- -

- {% blocktrans trimmed %} - A Tor SOCKS port is available on your {{ box_name }} on TCP port - 9050. - {% endblocktrans %} -

- {% endblock %} diff --git a/plinth/modules/tor/views.py b/plinth/modules/tor/views.py index 864634b4d..8977970a4 100644 --- a/plinth/modules/tor/views.py +++ b/plinth/modules/tor/views.py @@ -31,6 +31,8 @@ from plinth.modules import tor from plinth.modules.names import SERVICES from plinth.signals import domain_added, domain_removed +config_process = None + def on_install(): """Setup Tor configuration as soon as it is installed.""" @@ -48,6 +50,9 @@ def index(request): """Serve configuration page.""" status = tor.get_status() + if config_process: + _collect_config_result(request, status) + form = None if request.method == 'POST': @@ -63,6 +68,7 @@ def index(request): return TemplateResponse(request, 'tor.html', {'title': _('Tor Control Panel'), 'status': status, + 'config_running': bool(config_process), 'form': form}) @@ -95,25 +101,48 @@ def __apply_changes(request, old_status, new_status): arguments.extend(['--apt-transport-tor', arg_value]) if arguments: - actions.superuser_run('tor', ['configure'] + arguments) - tor.socks_service.notify_enabled(None, new_status['enabled']) - tor.bridge_service.notify_enabled(None, new_status['enabled']) - messages.success(request, _('Configuration updated')) + global config_process + if not config_process: + config_process = actions.superuser_run( + 'tor', ['configure'] + arguments, async=True) else: messages.info(request, _('Setting unchanged')) + +def _collect_config_result(request, status): + """Handle config process completion.""" + global config_process + if not config_process: + return + + return_code = config_process.poll() + + # Config process is not complete yet + if return_code == None: + return + + tor.socks_service.notify_enabled(None, status['enabled']) + tor.bridge_service.notify_enabled(None, status['enabled']) + # Update hidden service name registered with Name Services module. domain_removed.send_robust( sender='tor', domain_type='hiddenservice') - (hs_enabled, hs_hostname, hs_ports) = tor.get_hs() - if tor.is_enabled() and tor.is_running() and hs_enabled and hs_hostname: + if status['enabled'] and status['is_running'] and \ + status['hs_enabled'] and status['hs_hostname']: hs_services = [] for service in SERVICES: - if str(service[2]) in hs_ports: + if str(service[2]) in status['hs_ports']: hs_services.append(service[0]) domain_added.send_robust( sender='tor', domain_type='hiddenservice', - name=hs_hostname, description=_('Tor Hidden Service'), + name=status['hs_hostname'], description=_('Tor Hidden Service'), services=hs_services) + + if not return_code: + messages.success(request, _('Configuration updated.')) + else: + messages.info(request, _('Error occurred during configuration.')) + + config_process = None