diff --git a/plinth/modules/config/__init__.py b/plinth/modules/config/__init__.py index 9d63ec457..af28b5a8f 100644 --- a/plinth/modules/config/__init__.py +++ b/plinth/modules/config/__init__.py @@ -156,9 +156,9 @@ def init(): # Register domain with Name Services module. domainname = get_domainname() if domainname: - domain_added.send_robust( - sender='config', domain_type='domainname', name=domainname, - description=ugettext_lazy('Domain Name'), services='__all__') + domain_added.send_robust(sender='config', + domain_type='domain-type-static', + name=domainname, services='__all__') def setup(helper, old_version=None): diff --git a/plinth/modules/config/views.py b/plinth/modules/config/views.py index f50814e61..b7ffb7f8c 100644 --- a/plinth/modules/config/views.py +++ b/plinth/modules/config/views.py @@ -82,7 +82,7 @@ def _apply_changes(request, old_status, new_status): if old_status['domainname'] != new_status['domainname']: try: - set_domainname(new_status['domainname']) + set_domainname(new_status['domainname'], old_status['domainname']) except Exception as exception: messages.error( request, @@ -141,7 +141,7 @@ def set_hostname(hostname): actions.superuser_run('domainname-change', [domainname]) -def set_domainname(domainname): +def set_domainname(domainname, old_domainname): """Sets machine domain name to domainname""" old_domainname = config.get_domainname() @@ -156,8 +156,12 @@ def set_domainname(domainname): new_domainname=domainname) # Update domain registered with Name Services module. - domain_removed.send_robust(sender='config', domain_type='domainname') + if old_domainname: + domain_removed.send_robust(sender='config', + domain_type='domain-type-static', + name=old_domainname) + if domainname: - domain_added.send_robust(sender='config', domain_type='domainname', - name=domainname, description=_('Domain Name'), - services='__all__') + domain_added.send_robust(sender='config', + domain_type='domain-type-static', + name=domainname, services='__all__') diff --git a/plinth/modules/dynamicdns/__init__.py b/plinth/modules/dynamicdns/__init__.py index 884851e65..a06b343fc 100644 --- a/plinth/modules/dynamicdns/__init__.py +++ b/plinth/modules/dynamicdns/__init__.py @@ -87,9 +87,8 @@ def init(): current_status = get_status() if current_status['enabled']: domain_added.send_robust( - sender='dynamicdns', domain_type='dynamicdnsservice', - name=current_status['dynamicdns_domain'], - description=_('Dynamic DNS Service'), services='__all__') + sender='dynamicdns', domain_type='domain-type-dynamic', + name=current_status['dynamicdns_domain'], services='__all__') app.set_enabled(True) diff --git a/plinth/modules/dynamicdns/views.py b/plinth/modules/dynamicdns/views.py index 14729e741..af5160ada 100644 --- a/plinth/modules/dynamicdns/views.py +++ b/plinth/modules/dynamicdns/views.py @@ -156,15 +156,14 @@ def _apply_changes(request, old_status, new_status): if old_status['enabled']: domain_removed.send_robust(sender='dynamicdns', - domain_type='dynamicdnsservice', + domain_type='domain-type-dynamic', name=old_status['dynamicdns_domain']) _run(['stop']) if new_status['enabled']: domain_added.send_robust( - sender='dynamicdns', domain_type='dynamicdnsservice', - name=new_status['dynamicdns_domain'], - description=_('Dynamic DNS Service'), services='__all__') + sender='dynamicdns', domain_type='domain-type-dynamic', + name=new_status['dynamicdns_domain'], services='__all__') _run(['start']) messages.success(request, _('Configuration updated')) diff --git a/plinth/modules/letsencrypt/__init__.py b/plinth/modules/letsencrypt/__init__.py index 17a250706..882cae8e9 100644 --- a/plinth/modules/letsencrypt/__init__.py +++ b/plinth/modules/letsencrypt/__init__.py @@ -160,7 +160,7 @@ def on_domainname_change(sender, old_domainname, new_domainname, **kwargs): def on_domain_added(sender, domain_type='', name='', description='', services=None, **kwargs): """Obtain a certificate for the new domain""" - if domain_type == 'hiddenservice': + if domain_type == 'domain-type-tor': return False # Check if a cert if already available diff --git a/plinth/modules/letsencrypt/tests/test_domain_name_changes.py b/plinth/modules/letsencrypt/tests/test_domain_name_changes.py index b83f66bd2..1a0f776f0 100644 --- a/plinth/modules/letsencrypt/tests/test_domain_name_changes.py +++ b/plinth/modules/letsencrypt/tests/test_domain_name_changes.py @@ -26,7 +26,7 @@ pytestmark = pytest.mark.usefixtures('needs_root', 'needs_sudo') def test_add_onion_domain(): - assert not on_domain_added('test', 'hiddenservice', 'ddddd.onion') + assert not on_domain_added('test', 'domain-type-tor', 'ddddd.onion') @pytest.mark.usefixtures('load_cfg') diff --git a/plinth/modules/names/__init__.py b/plinth/modules/names/__init__.py index 747e962da..39338f908 100644 --- a/plinth/modules/names/__init__.py +++ b/plinth/modules/names/__init__.py @@ -27,23 +27,15 @@ from plinth import cfg, menu from plinth.signals import domain_added, domain_removed from plinth.utils import format_lazy +from . import components from .manifest import backup # noqa, pylint: disable=unused-import -SERVICES = ( - ('http', _('HTTP'), 80), - ('https', _('HTTPS'), 443), - ('ssh', _('SSH'), 22), -) - version = 1 is_essential = True name = _('Name Services') -domain_types = {} -domains = {} - logger = logging.getLogger(__name__) manual_page = 'NameServices' @@ -89,70 +81,27 @@ def on_domain_added(sender, domain_type, name='', description='', if not domain_type: return - domain_types[domain_type] = description - if not name: return if not services: services = [] - if domain_type not in domains: - # new domain_type - domains[domain_type] = {} - domains[domain_type][name] = services + components.DomainName('domain-' + sender + '-' + name, name, domain_type, + services) logger.info('Added domain %s of type %s with services %s', name, domain_type, str(services)) def on_domain_removed(sender, domain_type, name='', **kwargs): """Remove domain from global list.""" - if domain_type in domains: - if name == '': # remove all domains of this type - domains[domain_type] = {} - logger.info('Removed all domains of type %s', domain_type) - elif name in domains[domain_type]: - del domains[domain_type][name] - logger.info('Removed domain %s of type %s', name, domain_type) + if name: + component_id = 'domain-' + sender + '-' + name + components.DomainName.get(component_id).remove() + logger.info('Removed domain %s of type %s', name, domain_type) + else: + for domain_name in components.DomainName.list(): + if domain_name.domain_type.component_id == domain_type: + domain_name.remove() - -def get_domain_types(): - """Get list of domain_types.""" - return list(domain_types.keys()) - - -def get_description(domain_type): - """Get description of a domain_type, if available.""" - if domain_type in domain_types: - return domain_types[domain_type] - - return domain_type - - -def get_domain(domain_type): - """ - Get domain of type domain_type. - - This function is meant for use with single-domain domain_types. If there is - more than one domain, any one of the domains may be returned. - """ - if domain_type in domains and domains[domain_type]: - return list(domains[domain_type].keys())[0] - - return None - - -def get_enabled_services(domain_type, domain): - """Get list of enabled services for a domain.""" - try: - return domains[domain_type][domain] - except KeyError: - # domain_type or domain not registered - return [] - - -def get_services_status(domain_type, domain): - """Get list of whether each service is enabled for a domain.""" - enabled = get_enabled_services(domain_type, domain) - return [ - enabled == '__all__' or service[0] in enabled for service in SERVICES - ] + logger.info('Remove domain %s of type %s', domain_name.name, + domain_type) diff --git a/plinth/modules/names/templates/names.html b/plinth/modules/names/templates/names.html index df791e519..f94664e5f 100644 --- a/plinth/modules/names/templates/names.html +++ b/plinth/modules/names/templates/names.html @@ -26,31 +26,39 @@ - - {% for service in status.services %} - - {% endfor %} + + + + - {% for name_service in status.name_services %} - - - {% for service in name_service.services_enabled %} - - {% endfor %} - + {% for domain in status.domains|dictsort:"domain_type.display_name" %} + + + + + + + {% endfor %} + + {% for domain_type in status.unused_domain_types %} + + + + + + {% endfor %}
-
{{ service }}
-
TypeDomain NameServices
- {{ name_service.type }}
- {{ name_service.name }} -
- {% if service %} - {% trans "Enabled" %} - {% else %} - {% trans "Disabled" %} - {% endif %} -
{{ domain.domain_type.display_name }}{{ domain.name }}{{ domain.get_readable_services|join:', ' }} + + {% trans "Configure" %} + +
{{ domain_type.display_name }}-- + + {% trans "Configure" %} + +
diff --git a/plinth/modules/names/tests/test_names.py b/plinth/modules/names/tests/test_names.py index 32f17cfb0..a2af0887a 100644 --- a/plinth/modules/names/tests/test_names.py +++ b/plinth/modules/names/tests/test_names.py @@ -20,99 +20,39 @@ Tests for names module. import pytest -from .. import domain_types, domains from .. import on_domain_added, on_domain_removed -from .. import get_domain_types, get_description -from .. import get_domain, get_enabled_services, get_services_status +from ..components import DomainName, DomainType @pytest.fixture(name='clean_domains') def fixture_clean_domains(): """Test fixture to start a test with clean domains list.""" - old_domain_types = dict(domain_types) - old_domains = dict(domains) - domain_types.clear() - domains.clear() - yield - domain_types.clear() - domains.clear() - domain_types.update(old_domain_types) - domains.update(old_domains) + DomainName._all = {} # pylint: disable=protected-access @pytest.mark.usefixtures('clean_domains') def test_on_domain_added(): """Test adding a domain to the global list.""" on_domain_added('', '') - assert '' not in domain_types - assert '' not in domains + assert not DomainName.list() - on_domain_added('', 'hiddenservice', 'ddddd.onion') - on_domain_added('', 'hiddenservice', 'eeeee.onion') - assert 'ddddd.onion' in domains['hiddenservice'] - assert 'eeeee.onion' in domains['hiddenservice'] + DomainType('domain-type-tor', 'Tor Domain', 'torurl') + on_domain_added('tor', 'domain-type-tor', 'ddddd.onion') + on_domain_added('tor', 'domain-type-tor', 'eeeee.onion') + DomainName.get('domain-tor-ddddd.onion') + DomainName.get('domain-tor-eeeee.onion') @pytest.mark.usefixtures('clean_domains') def test_on_domain_removed(): """Test removing a domain from the global list.""" - on_domain_added('', 'domainname', 'fffff') - on_domain_removed('', 'domainname', 'fffff') - assert 'fffff' not in domains['domainname'] - - on_domain_added('', 'pagekite', 'ggggg.pagekite.me') - on_domain_added('', 'pagekite', 'hhhhh.pagekite.me') - on_domain_removed('', 'pagekite') - assert 'ggggg.pagekite.me' not in domains['pagekite'] - assert 'hhhhh.pagekite.me' not in domains['pagekite'] + DomainType('domain-type-tor', 'Tor Domain', 'torurl') + on_domain_added('tor', 'domain-type-tor', 'ddddd.onion') + on_domain_removed('tor', 'domain-type-tor', 'ddddd.onion') + with pytest.raises(KeyError): + DomainName.get('domain-tor-ddddd.onion') # try to remove things that don't exist on_domain_removed('', '') - on_domain_removed('', 'domainname', 'iiiii') - - -@pytest.mark.usefixtures('clean_domains') -def test_get_domain_types(): - """Test getting domain types.""" - on_domain_added('', 'domainname') - assert 'domainname' in get_domain_types() - - -@pytest.mark.usefixtures('clean_domains') -def test_get_description(): - """Test getting domain type description.""" - on_domain_added('', 'pagekite', '', 'Pagekite') - assert get_description('pagekite') == 'Pagekite' - - assert get_description('asdfasdf') == 'asdfasdf' - - -@pytest.mark.usefixtures('clean_domains') -def test_get_domain(): - """Test getting a domain of domain_type.""" - on_domain_added('', 'hiddenservice', 'aaaaa.onion') - assert get_domain('hiddenservice') == 'aaaaa.onion' - - assert get_domain('abcdef') is None - - on_domain_removed('', 'hiddenservice') - assert get_domain('hiddenservice') is None - - -@pytest.mark.usefixtures('clean_domains') -def test_get_enabled_services(): - """Test getting enabled services for a domain.""" - on_domain_added('', 'domainname', 'bbbbb', '', ['http', 'https', 'ssh']) - assert get_enabled_services('domainname', - 'bbbbb') == ['http', 'https', 'ssh'] - - assert get_enabled_services('xxxxx', 'yyyyy') == [] - assert get_enabled_services('domainname', 'zzzzz') == [] - - -@pytest.mark.usefixtures('clean_domains') -def test_get_services_status(): - """Test getting whether each service is enabled for a domain.""" - on_domain_added('', 'pagekite', 'ccccc.pagekite.me', '', ['http', 'https']) - assert get_services_status('pagekite', 'ccccc.pagekite.me') == \ - [True, True, False] + with pytest.raises(KeyError): + on_domain_removed('', 'domainname', 'iiiii') diff --git a/plinth/modules/names/views.py b/plinth/modules/names/views.py index ce0acd4ff..103768a33 100644 --- a/plinth/modules/names/views.py +++ b/plinth/modules/names/views.py @@ -19,12 +19,10 @@ FreedomBox app for name services. """ from django.template.response import TemplateResponse -from django.utils.translation import ugettext as _ from plinth.modules import names -from . import (SERVICES, get_description, get_domain, get_domain_types, - get_services_status) +from . import components def index(request): @@ -42,16 +40,11 @@ def index(request): def get_status(): """Get configured services per name.""" - name_services = [] - for domain_type in sorted(get_domain_types()): - domain = get_domain(domain_type) - name_services.append({ - 'type': get_description(domain_type), - 'name': domain or _('Not Available'), - 'services_enabled': get_services_status(domain_type, domain), - }) + domains = components.DomainName.list() + used_domain_types = {domain.domain_type for domain in domains} + unused_domain_types = [ + domain_type for domain_type in components.DomainType.list().values() + if domain_type not in used_domain_types + ] - return { - 'services': [service[1] for service in SERVICES], - 'name_services': name_services, - } + return {'domains': domains, 'unused_domain_types': unused_domain_types} diff --git a/plinth/modules/pagekite/utils.py b/plinth/modules/pagekite/utils.py index b85ba2db3..1414bddd3 100644 --- a/plinth/modules/pagekite/utils.py +++ b/plinth/modules/pagekite/utils.py @@ -260,7 +260,8 @@ def update_names_module(initial_registration=False, enabled=None, - enabled: Boolean (optional) whether PageKite is enabled - kite_name: String (optional) """ - domain_removed.send_robust(sender='pagekite', domain_type='pagekite') + domain_removed.send_robust(sender='pagekite', + domain_type='domain-type-pagekite') if enabled is None: try: @@ -284,9 +285,9 @@ def update_names_module(initial_registration=False, enabled=None, kite_name = None if initial_registration or (enabled and kite_name): - domain_added.send_robust(sender='pagekite', domain_type='pagekite', - name=kite_name, description=_('Pagekite'), - services=enabled_services) + domain_added.send_robust(sender='pagekite', + domain_type='domain-type-pagekite', + name=kite_name, services=enabled_services) if __name__ == "__main__": diff --git a/plinth/modules/tor/__init__.py b/plinth/modules/tor/__init__.py index 562bb5294..aebfc6833 100644 --- a/plinth/modules/tor/__init__.py +++ b/plinth/modules/tor/__init__.py @@ -27,7 +27,6 @@ from plinth import app as app_module from plinth import menu from plinth.daemon import Daemon from plinth.modules.firewall.components import Firewall -from plinth.modules.names import SERVICES from plinth.modules.names.components import DomainType from plinth.signals import domain_added, domain_removed @@ -110,21 +109,13 @@ def init(): # Register hidden service name with Name Services module. status = utils.get_status() hostname = status['hs_hostname'] - hs_virtports = [port['virtport'] for port in status['hs_ports']] + services = [int(port['virtport']) for port in status['hs_ports']] if status['enabled'] and status['is_running'] and \ status['hs_enabled'] and status['hs_hostname']: - hs_services = [] - for service_type in SERVICES: - if str(service_type[2]) in hs_virtports: - hs_services.append(service_type[0]) - else: - hostname = None - hs_services = None - - domain_added.send_robust( - sender='tor', domain_type='hiddenservice', name=hostname, - description=_('Tor Hidden Service'), services=hs_services) + domain_added.send_robust(sender='tor', + domain_type='domain-type-tor', + name=hostname, services=services) def setup(helper, old_version=None): @@ -146,14 +137,13 @@ def update_hidden_service_domain(status=None): if not status: status = utils.get_status() - domain_removed.send_robust(sender='tor', domain_type='hiddenservice') + domain_removed.send_robust(sender='tor', domain_type='domain-type-tor') if status['enabled'] and status['is_running'] and \ status['hs_enabled'] and status['hs_hostname']: - domain_added.send_robust(sender='tor', domain_type='hiddenservice', - name=status['hs_hostname'], - description=_('Tor Hidden Service'), - services=status['hs_services']) + services = [int(port['virtport']) for port in status['hs_ports']] + domain_added.send_robust(sender='tor', domain_type='domain-type-tor', + name=status['hs_hostname'], services=services) def diagnose(): diff --git a/plinth/modules/tor/templates/tor.html b/plinth/modules/tor/templates/tor.html index 3f369c7aa..c4f6473f2 100644 --- a/plinth/modules/tor/templates/tor.html +++ b/plinth/modules/tor/templates/tor.html @@ -74,9 +74,7 @@ {{ status.hs_hostname }} {{ status.hs_status }} - {% for service in status.hs_services %} - {{ service }} - {% endfor %} + {{ status.hs_services|join:', ' }} diff --git a/plinth/modules/tor/utils.py b/plinth/modules/tor/utils.py index dc93d42b5..4b6b04b08 100644 --- a/plinth/modules/tor/utils.py +++ b/plinth/modules/tor/utils.py @@ -27,7 +27,7 @@ import augeas from plinth import actions from plinth.daemon import app_is_running from plinth.modules import tor -from plinth.modules.names import SERVICES +from plinth.modules.names.components import DomainName APT_SOURCES_URI_PATHS = ('/files/etc/apt/sources.list/*/uri', '/files/etc/apt/sources.list.d/*/*/uri') @@ -41,10 +41,13 @@ def get_status(): hs_info = status['hidden_service'] hs_services = [] - hs_virtports = [port['virtport'] for port in hs_info['ports']] - for service_type in SERVICES: - if str(service_type[2]) in hs_virtports: - hs_services.append(service_type[0]) + if hs_info['hostname']: + try: + domain = DomainName.get('domain-tor-' + hs_info['hostname']) + except KeyError: + pass + else: + hs_services = domain.get_readable_services() # Filter out obfs3/4 ports when bridge relay is disabled ports = {