diff --git a/plinth/modules/tor/__init__.py b/plinth/modules/tor/__init__.py index cae907cde..122d8fe57 100644 --- a/plinth/modules/tor/__init__.py +++ b/plinth/modules/tor/__init__.py @@ -8,7 +8,7 @@ from plinth import app as app_module from plinth import cfg, menu from plinth.daemon import (Daemon, app_is_running, diagnose_netcat, diagnose_port_listening) -from plinth.modules.apache.components import diagnose_url +from plinth.modules.apache.components import Webserver, diagnose_url from plinth.modules.backups.components import BackupRestore from plinth.modules.firewall.components import Firewall from plinth.modules.names.components import DomainType @@ -37,7 +37,7 @@ class TorApp(app_module.App): app_id = 'tor' - _version = 5 + _version = 6 def __init__(self): """Create components for the app.""" @@ -81,6 +81,10 @@ class TorApp(app_module.App): (9040, 'tcp6'), (9053, 'udp4'), (9053, 'udp6')]) self.add(daemon) + webserver = Webserver('webserver-onion-location', + 'onion-location-freedombox') + self.add(webserver) + users_and_groups = UsersAndGroups('users-and-groups-tor', reserved_usernames=['debian-tor']) self.add(users_and_groups) @@ -168,8 +172,20 @@ class TorApp(app_module.App): if not old_version: privileged.configure(apt_transport_tor=True) - update_hidden_service_domain() - self.enable() + update_hidden_service_domain(utils.get_status()) + + # Enable/disable Onion-Location component based on app status. + # Component was introduced in version 6. + if old_version and old_version < 6: + daemon_component = self.get_component('daemon-tor') + component = self.get_component('webserver-onion-location') + if daemon_component.is_enabled(): + component.enable() + else: + component.disable() + + if not old_version: + self.enable() def update_hidden_service_domain(status=None): diff --git a/plinth/modules/tor/manifest.py b/plinth/modules/tor/manifest.py index a26fbeac2..0657b6c06 100644 --- a/plinth/modules/tor/manifest.py +++ b/plinth/modules/tor/manifest.py @@ -4,6 +4,8 @@ from django.utils.translation import gettext_lazy as _ from plinth.clients import store_url +from . import privileged + _orbot_package_id = 'org.torproject.android' _tor_browser_download_url = \ 'https://www.torproject.org/download/download-easy.html' @@ -42,7 +44,8 @@ clients = [{ backup = { 'config': { - 'directories': ['/etc/tor/'] + 'directories': ['/etc/tor/'], + 'files': [str(privileged.TOR_APACHE_SITE)] }, 'secrets': { 'directories': ['/var/lib/tor/', '/var/lib/tor-instances/'] diff --git a/plinth/modules/tor/privileged.py b/plinth/modules/tor/privileged.py index 75b572001..d799e4739 100644 --- a/plinth/modules/tor/privileged.py +++ b/plinth/modules/tor/privileged.py @@ -3,6 +3,7 @@ import codecs import os +import pathlib import re import socket import subprocess @@ -20,6 +21,7 @@ SERVICE_FILE = '/etc/firewalld/services/tor-{0}.xml' TOR_CONFIG = '/files/etc/tor/instances/plinth/torrc' TOR_STATE_FILE = '/var/lib/tor-instances/plinth/state' TOR_AUTH_COOKIE = '/var/run/tor-instances/plinth/control.authcookie' +TOR_APACHE_SITE = '/etc/apache2/conf-available/onion-location-freedombox.conf' @privileged @@ -30,6 +32,7 @@ def setup(old_version: int): return _first_time_setup() + _set_onion_header(_get_hidden_service(aug=None)) def _first_time_setup(): @@ -391,6 +394,7 @@ def _enable_hs(aug=None): aug.set(TOR_CONFIG + '/HiddenServicePort[2]', '80 127.0.0.1:80') aug.set(TOR_CONFIG + '/HiddenServicePort[3]', '443 127.0.0.1:443') aug.save() + _set_onion_header(_get_hidden_service(aug)) def _disable_hs(aug=None): @@ -404,6 +408,7 @@ def _disable_hs(aug=None): aug.remove(TOR_CONFIG + '/HiddenServiceDir') aug.remove(TOR_CONFIG + '/HiddenServicePort') aug.save() + _set_onion_header(None) def _enable_apt_transport_tor(): @@ -486,3 +491,22 @@ def augeas_load(): '/etc/tor/instances/plinth/torrc') aug.load() return aug + + +def _set_onion_header(hidden_service): + """Set Apache configuration for the Onion-Location header.""" + config_file = pathlib.Path(TOR_APACHE_SITE) + if hidden_service and hidden_service['enabled']: + # https://community.torproject.org/onion-services/advanced/onion-location/ + hostname = hidden_service['hostname'] + config_contents = f'''# This file is managed by FreedomBox + + Header set Onion-Location "http://{hostname}%{{REQUEST_URI}}s" + +''' + config_file.write_text(config_contents, encoding='utf-8') + else: + config_file.write_text('# This file is managed by FreedomBox\n', + encoding='utf-8') + + action_utils.service_reload('apache2')