From 6001b0f7af7d846ca1c194f4e48f72e96f171eb4 Mon Sep 17 00:00:00 2001 From: axolotle Date: Tue, 1 Feb 2022 18:23:38 +0100 Subject: [PATCH 01/13] rework domains cache logic --- src/domain.py | 118 ++++++++++++++++++++++++-------------------------- 1 file changed, 57 insertions(+), 61 deletions(-) diff --git a/src/domain.py b/src/domain.py index 14b28940a..eab56761b 100644 --- a/src/domain.py +++ b/src/domain.py @@ -24,7 +24,7 @@ Manage domains """ import os -from typing import Dict, Any +from typing import List, Any from moulinette import m18n, Moulinette from moulinette.core import MoulinetteError @@ -47,7 +47,47 @@ logger = getActionLogger("yunohost.domain") DOMAIN_SETTINGS_DIR = "/etc/yunohost/domains" # Lazy dev caching to avoid re-query ldap every time we need the domain list -domain_list_cache: Dict[str, Any] = {} +domain_list_cache: List[str] = [] +main_domain_cache: str = None + + +def _get_maindomain(no_cache=False): + global main_domain_cache + if not main_domain_cache or no_cache: + with open("/etc/yunohost/current_host", "r") as f: + main_domain_cache = f.readline().rstrip() + + return main_domain_cache + + +def _get_domains(exclude_subdomains=False, no_cache=False): + global domain_list_cache + if not domain_list_cache or no_cache: + from yunohost.utils.ldap import _get_ldap_interface + + ldap = _get_ldap_interface() + result = [ + entry["virtualdomain"][0] + for entry in ldap.search("ou=domains", "virtualdomain=*", ["virtualdomain"]) + ] + + def cmp_domain(domain): + # Keep the main part of the domain and the extension together + # eg: this.is.an.example.com -> ['example.com', 'an', 'is', 'this'] + domain = domain.split(".") + domain[-1] = domain[-2] + domain.pop() + return list(reversed(domain)) + + domain_list_cache = sorted(result, key=cmp_domain) + + if exclude_subdomains: + return [ + domain + for domain in domain_list_cache + if not _get_parent_domain_of(domain, return_self=False) + ] + + return domain_list_cache def domain_list(exclude_subdomains=False): @@ -58,47 +98,11 @@ def domain_list(exclude_subdomains=False): exclude_subdomains -- Filter out domains that are subdomains of other declared domains """ - global domain_list_cache - if not exclude_subdomains and domain_list_cache: - return domain_list_cache - - from yunohost.utils.ldap import _get_ldap_interface - - ldap = _get_ldap_interface() - result = [ - entry["virtualdomain"][0] - for entry in ldap.search("ou=domains", "virtualdomain=*", ["virtualdomain"]) - ] - - result_list = [] - for domain in result: - if exclude_subdomains: - parent_domain = domain.split(".", 1)[1] - if parent_domain in result: - continue - - result_list.append(domain) - - def cmp_domain(domain): - # Keep the main part of the domain and the extension together - # eg: this.is.an.example.com -> ['example.com', 'an', 'is', 'this'] - domain = domain.split(".") - domain[-1] = domain[-2] + domain.pop() - domain = list(reversed(domain)) - return domain - - result_list = sorted(result_list, key=cmp_domain) - - # Don't cache answer if using exclude_subdomains - if exclude_subdomains: - return {"domains": result_list, "main": _get_maindomain()} - - domain_list_cache = {"domains": result_list, "main": _get_maindomain()} - return domain_list_cache + return {"domains": _get_domains(exclude_subdomains), "main": _get_maindomain()} def _assert_domain_exists(domain): - if domain not in domain_list()["domains"]: + if domain not in _get_domains(): raise YunohostValidationError("domain_unknown", domain=domain) @@ -107,26 +111,24 @@ def _list_subdomains_of(parent_domain): _assert_domain_exists(parent_domain) out = [] - for domain in domain_list()["domains"]: + for domain in _get_domains(): if domain.endswith(f".{parent_domain}"): out.append(domain) return out -def _get_parent_domain_of(domain): +def _get_parent_domain_of(domain, return_self=True): _assert_domain_exists(domain) - if "." not in domain: - return domain + domains = _get_domains() + while "." in domain: + domain = domain.split(".", 1)[1] + if domain in domains: + return domain - parent_domain = domain.split(".", 1)[-1] - if parent_domain not in domain_list()["domains"]: - return domain # Domain is its own parent - - else: - return _get_parent_domain_of(parent_domain) + return domain if return_self else None @is_unit_operation() @@ -198,7 +200,7 @@ def domain_add(operation_logger, domain, dyndns=False): raise YunohostError("domain_creation_failed", domain=domain, error=e) finally: global domain_list_cache - domain_list_cache = {} + domain_list_cache = [] # Don't regen these conf if we're still in postinstall if os.path.exists("/etc/yunohost/installed"): @@ -255,7 +257,7 @@ def domain_remove(operation_logger, domain, remove_apps=False, force=False): # Check domain is not the main domain if domain == _get_maindomain(): - other_domains = domain_list()["domains"] + other_domains = _get_domains() other_domains.remove(domain) if other_domains: @@ -316,7 +318,7 @@ def domain_remove(operation_logger, domain, remove_apps=False, force=False): raise YunohostError("domain_deletion_failed", domain=domain, error=e) finally: global domain_list_cache - domain_list_cache = {} + domain_list_cache = [] stuff_to_delete = [ f"/etc/yunohost/certs/{domain}", @@ -380,8 +382,8 @@ def domain_main_domain(operation_logger, new_main_domain=None): # Apply changes to ssl certs try: write_to_file("/etc/yunohost/current_host", new_main_domain) - global domain_list_cache - domain_list_cache = {} + global main_domain_cache + main_domain_cache = None _set_hostname(new_main_domain) except Exception as e: logger.warning(str(e), exc_info=1) @@ -409,12 +411,6 @@ def domain_url_available(domain, path): return len(_get_conflicting_apps(domain, path)) == 0 -def _get_maindomain(): - with open("/etc/yunohost/current_host", "r") as f: - maindomain = f.readline().rstrip() - return maindomain - - def domain_config_get(domain, key="", full=False, export=False): """ Display a domain configuration From 77471c41403fb8c39c2e14b9b65d8c170d844012 Mon Sep 17 00:00:00 2001 From: axolotle Date: Tue, 1 Feb 2022 18:38:01 +0100 Subject: [PATCH 02/13] add tree option on domain_list() --- share/actionsmap.yml | 3 +++ src/domain.py | 46 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/share/actionsmap.yml b/share/actionsmap.yml index 78271b4cc..e7f935b3e 100644 --- a/share/actionsmap.yml +++ b/share/actionsmap.yml @@ -443,6 +443,9 @@ domain: --exclude-subdomains: help: Filter out domains that are obviously subdomains of other declared domains action: store_true + --tree: + help: Display domains as a tree + action: store_true ### domain_add() add: diff --git a/src/domain.py b/src/domain.py index eab56761b..beb8cd161 100644 --- a/src/domain.py +++ b/src/domain.py @@ -90,15 +90,42 @@ def _get_domains(exclude_subdomains=False, no_cache=False): return domain_list_cache -def domain_list(exclude_subdomains=False): +def domain_list(exclude_subdomains=False, tree=False): """ List domains Keyword argument: exclude_subdomains -- Filter out domains that are subdomains of other declared domains + tree -- Display domains as a hierarchy tree """ - return {"domains": _get_domains(exclude_subdomains), "main": _get_maindomain()} + from collections import OrderedDict + + domains = _get_domains(exclude_subdomains) + main = _get_maindomain() + + if not tree: + return {"domains": domains, "main": main} + + if tree and exclude_subdomains: + return { + "domains": OrderedDict({domain: {} for domain in domains}), + "main": main, + } + + def get_parent_dict(tree, child): + # If parent exists it should be the last added (see `_get_domains` ordering) + possible_parent = next(reversed(tree)) if tree else None + if possible_parent and child.endswith(f".{possible_parent}"): + return get_parent_dict(tree[possible_parent], child) + return tree + + result = OrderedDict() + for domain in domains: + parent = get_parent_dict(result, domain) + parent[domain] = OrderedDict() + + return {"domains": result, "main": main} def _assert_domain_exists(domain): @@ -118,6 +145,21 @@ def _list_subdomains_of(parent_domain): return out +# def _get_parent_domain_of(domain): +# +# _assert_domain_exists(domain) +# +# if "." not in domain: +# return domain +# +# parent_domain = domain.split(".", 1)[-1] +# if parent_domain not in _get_domains(): +# return domain # Domain is its own parent +# +# else: +# return _get_parent_domain_of(parent_domain) + + def _get_parent_domain_of(domain, return_self=True): _assert_domain_exists(domain) From d848837bc65c5de06f5bca130bd7907718c42c98 Mon Sep 17 00:00:00 2001 From: axolotle Date: Tue, 1 Feb 2022 18:51:21 +0100 Subject: [PATCH 03/13] add new domain_info() command to get a domain's dns, certs and apps infos --- share/actionsmap.yml | 9 ++++++ src/domain.py | 76 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) diff --git a/share/actionsmap.yml b/share/actionsmap.yml index e7f935b3e..e4c66b82b 100644 --- a/share/actionsmap.yml +++ b/share/actionsmap.yml @@ -447,6 +447,15 @@ domain: help: Display domains as a tree action: store_true + ### domain_info() + info: + action_help: Get domains aggredated data + api: GET /domains/ + arguments: + domains: + help: Domains to check + nargs: "*" + ### domain_add() add: action_help: Create a custom domain diff --git a/src/domain.py b/src/domain.py index beb8cd161..034e0f935 100644 --- a/src/domain.py +++ b/src/domain.py @@ -128,6 +128,82 @@ def domain_list(exclude_subdomains=False, tree=False): return {"domains": result, "main": main} +def domain_info(domains): + """ + Print aggregate data about domains (all by default) + + Keyword argument: + domains -- Domains to be checked + + """ + + from collections import OrderedDict + from yunohost.app import app_info + from yunohost.dns import _get_registar_settings + from yunohost.utils.dns import is_special_use_tld + + # If no domains given, consider all yunohost domains + if domains == []: + domains = _get_domains() + # Else, validate that yunohost knows the domains given + else: + for domain in domains: + _assert_domain_exists(domain) + + def get_dns_config(domain): + if is_special_use_tld(domain): + return {"method": "none"} + + registrar, registrar_credentials = _get_registar_settings(domain) + + if not registrar or registrar == "None": # yes it's None as a string + return {"method": "manual", "semi_auto_status": "unavailable"} + if registrar == "parent_domain": + return {"method": "handled_in_parent"} + if registrar == "yunohost": + return {"method": "auto", "registrar": registrar} + if not all(registrar_credentials.values()): + return { + "method": "manual", + "semi_auto_status": "activable", + "registrar": registrar, + } + + return { + "method": "semi_auto", + "registrar": registrar, + "semi_auto_status": "activated", + } + + certs = domain_cert_status(domains, full=True)["certificates"] + apps = {domain: [] for domain in domains} + + for app in _installed_apps(): + settings = _get_app_settings(app) + if settings["domain"] in domains: + apps[settings["domain"]].append( + {"name": app_info(app)["name"], "id": app, "path": settings["path"]} + ) + + result = OrderedDict() + for domain in domains: + result[domain] = OrderedDict( + { + "certificate": { + "authority": certs[domain]["CA_type"]["code"], + "validity": certs[domain]["validity"], + "ACME_eligible": certs[domain]["ACME_eligible"], + }, + "dns": get_dns_config(domain), + } + ) + + if apps[domain]: + result[domain]["apps"] = apps[domain] + + return {"domains": result} + + def _assert_domain_exists(domain): if domain not in _get_domains(): raise YunohostValidationError("domain_unknown", domain=domain) From 7b7c5f0b13ab38fd1f1341f7b3a135e70c60074d Mon Sep 17 00:00:00 2001 From: axolotle Date: Tue, 1 Feb 2022 18:53:43 +0100 Subject: [PATCH 04/13] changed cert acme status to a string to add 'unknown' status (when not diagnosed) --- src/certificate.py | 10 +++++++--- src/domain.py | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/certificate.py b/src/certificate.py index 076a12980..45453e170 100644 --- a/src/certificate.py +++ b/src/certificate.py @@ -98,9 +98,13 @@ def certificate_status(domains, full=False): if full: try: _check_domain_is_ready_for_ACME(domain) - status["ACME_eligible"] = True - except Exception: - status["ACME_eligible"] = False + status["acme_status"] = 'eligible' + except Exception as e: + if e.key == 'certmanager_domain_not_diagnosed_yet': + status["acme_status"] = 'unknown' + else: + status["acme_status"] = 'ineligible' + del status["domain"] certificates[domain] = status diff --git a/src/domain.py b/src/domain.py index 034e0f935..c66924fe7 100644 --- a/src/domain.py +++ b/src/domain.py @@ -192,7 +192,7 @@ def domain_info(domains): "certificate": { "authority": certs[domain]["CA_type"]["code"], "validity": certs[domain]["validity"], - "ACME_eligible": certs[domain]["ACME_eligible"], + "acme_status": certs[domain]["acme_status"], }, "dns": get_dns_config(domain), } From 81b90d79cbc3b36e39e79d84a6055fe8b59ad9f2 Mon Sep 17 00:00:00 2001 From: axolotle Date: Tue, 1 Feb 2022 19:06:03 +0100 Subject: [PATCH 05/13] remove previous _get_parent_domain_of() --- src/domain.py | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/domain.py b/src/domain.py index c66924fe7..9dff5a779 100644 --- a/src/domain.py +++ b/src/domain.py @@ -221,21 +221,6 @@ def _list_subdomains_of(parent_domain): return out -# def _get_parent_domain_of(domain): -# -# _assert_domain_exists(domain) -# -# if "." not in domain: -# return domain -# -# parent_domain = domain.split(".", 1)[-1] -# if parent_domain not in _get_domains(): -# return domain # Domain is its own parent -# -# else: -# return _get_parent_domain_of(parent_domain) - - def _get_parent_domain_of(domain, return_self=True): _assert_domain_exists(domain) From 96233ea6005c5a450055a0ee09dc8005a0bfdbda Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 5 Oct 2022 15:06:04 +0200 Subject: [PATCH 06/13] Rework domain_info --- share/actionsmap.yml | 9 +++--- src/domain.py | 77 ++++++++++---------------------------------- 2 files changed, 22 insertions(+), 64 deletions(-) diff --git a/share/actionsmap.yml b/share/actionsmap.yml index e4c66b82b..90146db89 100644 --- a/share/actionsmap.yml +++ b/share/actionsmap.yml @@ -449,12 +449,13 @@ domain: ### domain_info() info: - action_help: Get domains aggredated data + action_help: Get domain aggredated data api: GET /domains/ arguments: - domains: - help: Domains to check - nargs: "*" + domain: + help: Domain to check + extra: + pattern: *pattern_domain ### domain_add() add: diff --git a/src/domain.py b/src/domain.py index 9dff5a779..677441469 100644 --- a/src/domain.py +++ b/src/domain.py @@ -25,6 +25,7 @@ """ import os from typing import List, Any +from collections import OrderedDict from moulinette import m18n, Moulinette from moulinette.core import MoulinetteError @@ -99,7 +100,6 @@ def domain_list(exclude_subdomains=False, tree=False): tree -- Display domains as a hierarchy tree """ - from collections import OrderedDict domains = _get_domains(exclude_subdomains) main = _get_maindomain() @@ -128,80 +128,37 @@ def domain_list(exclude_subdomains=False, tree=False): return {"domains": result, "main": main} -def domain_info(domains): +def domain_info(domain): """ - Print aggregate data about domains (all by default) + Print aggregate data for a specific domain Keyword argument: - domains -- Domains to be checked - + domain -- Domain to be checked """ - from collections import OrderedDict from yunohost.app import app_info from yunohost.dns import _get_registar_settings - from yunohost.utils.dns import is_special_use_tld - # If no domains given, consider all yunohost domains - if domains == []: - domains = _get_domains() - # Else, validate that yunohost knows the domains given - else: - for domain in domains: - _assert_domain_exists(domain) + _assert_domain_exists(domain) - def get_dns_config(domain): - if is_special_use_tld(domain): - return {"method": "none"} - - registrar, registrar_credentials = _get_registar_settings(domain) - - if not registrar or registrar == "None": # yes it's None as a string - return {"method": "manual", "semi_auto_status": "unavailable"} - if registrar == "parent_domain": - return {"method": "handled_in_parent"} - if registrar == "yunohost": - return {"method": "auto", "registrar": registrar} - if not all(registrar_credentials.values()): - return { - "method": "manual", - "semi_auto_status": "activable", - "registrar": registrar, - } - - return { - "method": "semi_auto", - "registrar": registrar, - "semi_auto_status": "activated", - } - - certs = domain_cert_status(domains, full=True)["certificates"] - apps = {domain: [] for domain in domains} + registrar, _ = _get_registar_settings(domain) + certificate = domain_cert_status([domain], full=True)["certificates"][domain] + apps = [] for app in _installed_apps(): settings = _get_app_settings(app) - if settings["domain"] in domains: - apps[settings["domain"]].append( + if settings.get("domain") == domain: + apps.append( {"name": app_info(app)["name"], "id": app, "path": settings["path"]} ) - result = OrderedDict() - for domain in domains: - result[domain] = OrderedDict( - { - "certificate": { - "authority": certs[domain]["CA_type"]["code"], - "validity": certs[domain]["validity"], - "acme_status": certs[domain]["acme_status"], - }, - "dns": get_dns_config(domain), - } - ) - - if apps[domain]: - result[domain]["apps"] = apps[domain] - - return {"domains": result} + return { + "certificate": certificate, + "registrar": registrar, + "apps": apps, + "main": _get_maindomain() == domain, + # TODO : add parent / child domains ? + } def _assert_domain_exists(domain): From 1a543fe4166f00aa332be6ee99d703d6cdab38f6 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 5 Oct 2022 15:35:51 +0200 Subject: [PATCH 07/13] Fix acme_status / ACME_eligible --- share/config_domain.toml | 4 ++-- src/certificate.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/share/config_domain.toml b/share/config_domain.toml index 28c394cf1..a3607811b 100644 --- a/share/config_domain.toml +++ b/share/config_domain.toml @@ -90,13 +90,13 @@ i18n = "domain_config" [cert.cert.acme_eligible_explain] type = "alert" style = "warning" - visible = "acme_eligible == false" + visible = "acme_eligible == false || acme_elligible == null" [cert.cert.cert_no_checks] ask = "Ignore diagnosis checks" type = "boolean" default = false - visible = "acme_eligible == false" + visible = "acme_eligible == false || acme_elligible == null" [cert.cert.cert_install] type = "button" diff --git a/src/certificate.py b/src/certificate.py index 45453e170..5ca29ce55 100644 --- a/src/certificate.py +++ b/src/certificate.py @@ -98,12 +98,12 @@ def certificate_status(domains, full=False): if full: try: _check_domain_is_ready_for_ACME(domain) - status["acme_status"] = 'eligible' + status["ACME_eligible"] = True except Exception as e: if e.key == 'certmanager_domain_not_diagnosed_yet': - status["acme_status"] = 'unknown' + status["ACME_eligible"] = None # = unknown status else: - status["acme_status"] = 'ineligible' + status["ACME_eligible"] = False del status["domain"] From caf1534ce61293771e7e9a2af84379f5579c2afe Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 5 Oct 2022 15:37:03 +0200 Subject: [PATCH 08/13] Typomg --- share/actionsmap.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/actionsmap.yml b/share/actionsmap.yml index 90146db89..9df002bcf 100644 --- a/share/actionsmap.yml +++ b/share/actionsmap.yml @@ -450,7 +450,7 @@ domain: ### domain_info() info: action_help: Get domain aggredated data - api: GET /domains/ + api: GET /domains/ arguments: domain: help: Domain to check From 23b83b5ef7a75c3ef898f4f4b4f477e571103f40 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Fri, 7 Oct 2022 13:59:54 +0200 Subject: [PATCH 09/13] Unused import --- src/domain.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/domain.py b/src/domain.py index 677441469..dd84d6f09 100644 --- a/src/domain.py +++ b/src/domain.py @@ -24,7 +24,7 @@ Manage domains """ import os -from typing import List, Any +from typing import List from collections import OrderedDict from moulinette import m18n, Moulinette From 73a7f93740e46fa320401ccfd7d0ebb001398736 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Fri, 7 Oct 2022 14:19:15 +0200 Subject: [PATCH 10/13] domains: make the domain cache expire after 15 seconds to prevent inconsistencies between CLI and API --- src/domain.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/domain.py b/src/domain.py index dd84d6f09..78e3c2597 100644 --- a/src/domain.py +++ b/src/domain.py @@ -24,6 +24,7 @@ Manage domains """ import os +import time from typing import List from collections import OrderedDict @@ -48,22 +49,30 @@ logger = getActionLogger("yunohost.domain") DOMAIN_SETTINGS_DIR = "/etc/yunohost/domains" # Lazy dev caching to avoid re-query ldap every time we need the domain list +# The cache automatically expire every 15 seconds, to prevent desync between +# yunohost CLI and API which run in different processes domain_list_cache: List[str] = [] +domain_list_cache_timestamp = 0 main_domain_cache: str = None +main_domain_cache_timestamp = 0 +DOMAIN_CACHE_DURATION = 15 -def _get_maindomain(no_cache=False): +def _get_maindomain(): global main_domain_cache - if not main_domain_cache or no_cache: + global main_domain_cache_timestamp + if not main_domain_cache or abs(main_domain_cache_timestamp - time.time()) > DOMAIN_CACHE_DURATION: with open("/etc/yunohost/current_host", "r") as f: main_domain_cache = f.readline().rstrip() + main_domain_cache_timestamp = time.time() return main_domain_cache -def _get_domains(exclude_subdomains=False, no_cache=False): +def _get_domains(exclude_subdomains=False): global domain_list_cache - if not domain_list_cache or no_cache: + global domain_list_cache_timestamp + if not domain_list_cache or abs(domain_list_cache_timestamp - time.time()) > DOMAIN_CACHE_DURATION: from yunohost.utils.ldap import _get_ldap_interface ldap = _get_ldap_interface() @@ -80,6 +89,7 @@ def _get_domains(exclude_subdomains=False, no_cache=False): return list(reversed(domain)) domain_list_cache = sorted(result, key=cmp_domain) + domain_list_cache_timestamp = time.time() if exclude_subdomains: return [ @@ -443,7 +453,7 @@ def domain_main_domain(operation_logger, new_main_domain=None): try: write_to_file("/etc/yunohost/current_host", new_main_domain) global main_domain_cache - main_domain_cache = None + main_domain_cache = new_main_domain _set_hostname(new_main_domain) except Exception as e: logger.warning(str(e), exc_info=1) From 4d025010c421b1b22f4c67b8ea157a830fc2314e Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Fri, 7 Oct 2022 14:21:21 +0200 Subject: [PATCH 11/13] domain: add proper panel names in config panel --- share/config_domain.toml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/share/config_domain.toml b/share/config_domain.toml index a3607811b..0a3ba96cc 100644 --- a/share/config_domain.toml +++ b/share/config_domain.toml @@ -5,12 +5,13 @@ i18n = "domain_config" # Other things we may want to implement in the future: # # - maindomain handling -# - default app # - autoredirect www in nginx conf # - ? # [feature] +name = "Features" + [feature.app] [feature.app.default_app] type = "app" @@ -46,6 +47,7 @@ i18n = "domain_config" default = 0 [dns] +name = "DNS" [dns.registrar] optional = true @@ -61,6 +63,7 @@ i18n = "domain_config" [cert] +name = "Certificate" [cert.status] name = "Status" From 435084c20b47f92b82a75c5111db639049163fbf Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Fri, 7 Oct 2022 14:48:02 +0200 Subject: [PATCH 12/13] domain: _get_parent_domain_of call tweaking --- src/certificate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/certificate.py b/src/certificate.py index 5ca29ce55..299095af0 100644 --- a/src/certificate.py +++ b/src/certificate.py @@ -798,7 +798,7 @@ def _check_domain_is_ready_for_ACME(domain): or {} ) - parent_domain = _get_parent_domain_of(domain) + parent_domain = _get_parent_domain_of(domain, return_self=True) dnsrecords = ( Diagnoser.get_cached_report( From b30962a44f17a368e7dbf6d314e542c61e6b7337 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Fri, 7 Oct 2022 15:07:48 +0200 Subject: [PATCH 13/13] domain_info: add 'topest_parent' info + fix small bug with return_self option for _get_parent_domain_of --- src/domain.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/domain.py b/src/domain.py index 78e3c2597..650b5e20f 100644 --- a/src/domain.py +++ b/src/domain.py @@ -167,6 +167,7 @@ def domain_info(domain): "registrar": registrar, "apps": apps, "main": _get_maindomain() == domain, + "topest_parent": _get_parent_domain_of(domain, return_self=True, topest=True), # TODO : add parent / child domains ? } @@ -188,15 +189,17 @@ def _list_subdomains_of(parent_domain): return out -def _get_parent_domain_of(domain, return_self=True): +def _get_parent_domain_of(domain, return_self=True, topest=False): _assert_domain_exists(domain) - domains = _get_domains() - while "." in domain: - domain = domain.split(".", 1)[1] - if domain in domains: - return domain + domains = _get_domains(exclude_subdomains=topest) + + domain_ = domain + while "." in domain_: + domain_ = domain_.split(".", 1)[1] + if domain_ in domains: + return domain_ return domain if return_self else None