From 4432d28c098d85184bab20ad9f98851b1810b698 Mon Sep 17 00:00:00 2001 From: Gabriel Date: Thu, 4 Feb 2021 20:21:49 +0100 Subject: [PATCH 1/4] [muc subdomain] add to domain's certificate the alt subdomain muc --- data/templates/nginx/server.tpl.conf | 2 +- src/yunohost/certificate.py | 31 ++++++++++++++++------------ 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/data/templates/nginx/server.tpl.conf b/data/templates/nginx/server.tpl.conf index 8bd689a92..8a57dda55 100644 --- a/data/templates/nginx/server.tpl.conf +++ b/data/templates/nginx/server.tpl.conf @@ -6,7 +6,7 @@ map $http_upgrade $connection_upgrade { server { listen 80; listen [::]:80; - server_name {{ domain }} xmpp-upload.{{ domain }}; + server_name {{ domain }} xmpp-upload.{{ domain }} muc.{{ domain }}; access_by_lua_file /usr/share/ssowat/access.lua; diff --git a/src/yunohost/certificate.py b/src/yunohost/certificate.py index c48af2c07..f97cb42e5 100644 --- a/src/yunohost/certificate.py +++ b/src/yunohost/certificate.py @@ -659,34 +659,39 @@ def _prepare_certificate_signing_request(domain, key_file, output_folder): csr.get_subject().CN = domain from yunohost.domain import domain_list - - # For "parent" domains, include xmpp-upload subdomain in subject alternate names + # For "parent" domains, include xmpp-upload and muc subdomains in subject + # alternate names if domain in domain_list(exclude_subdomains=True)["domains"]: - subdomain = "xmpp-upload." + domain xmpp_records = ( Diagnoser.get_cached_report( "dnsrecords", item={"domain": domain, "category": "xmpp"} ).get("data") or {} ) - if xmpp_records.get("CNAME:xmpp-upload") == "OK": + sanlist = [] + for sub in ('xmpp-upload', 'muc'): + subdomain = sub + "." + domain + if xmpp_records.get("CNAME:" + sub) == "OK": + sanlist.append(("DNS:" + subdomain)) + else: + logger.warning( + m18n.n( + "certmanager_warning_subdomain_dns_record", + subdomain=subdomain, + domain=domain, + ) + ) + + if sanlist: csr.add_extensions( [ crypto.X509Extension( "subjectAltName".encode("utf8"), False, - ("DNS:" + subdomain).encode("utf8"), + (", ".join(sanlist)).encode("utf-8"), ) ] ) - else: - logger.warning( - m18n.n( - "certmanager_warning_subdomain_dns_record", - subdomain=subdomain, - domain=domain, - ) - ) # Set the key with open(key_file, "rt") as f: From 1fb42bb8aff46cfd41347a5016b9a0ae3c6a53a6 Mon Sep 17 00:00:00 2001 From: Gabriel Date: Tue, 9 Feb 2021 18:54:31 +0100 Subject: [PATCH 2/4] [muc subdomain] forbid admin to add a muc subdomain (reserved to xmpp) --- src/yunohost/domain.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/yunohost/domain.py b/src/yunohost/domain.py index c51039559..f28753311 100644 --- a/src/yunohost/domain.py +++ b/src/yunohost/domain.py @@ -103,6 +103,9 @@ def domain_add(operation_logger, domain, dyndns=False): if domain.startswith("xmpp-upload."): raise YunohostError("domain_cannot_add_xmpp_upload") + if domain.startswith("muc."): + raise YunohostError("domain_cannot_add_muc_upload") + ldap = _get_ldap_interface() try: From dbf19b585c898d5af84f9cde9a7998bf450b4680 Mon Sep 17 00:00:00 2001 From: Gabriel Date: Tue, 23 Feb 2021 20:17:53 +0100 Subject: [PATCH 3/4] [locales] add "domain_cannot_add_muc_upload" string to en.json --- locales/en.json | 1 + 1 file changed, 1 insertion(+) diff --git a/locales/en.json b/locales/en.json index 0acd2b734..88b3d6a9b 100644 --- a/locales/en.json +++ b/locales/en.json @@ -269,6 +269,7 @@ "diagnosis_processes_killed_by_oom_reaper": "Some processes were recently killed by the system because it ran out of memory. This is typically symptomatic of a lack of memory on the system or of a process that ate up to much memory. Summary of the processes killed:\n{kills_summary}", "domain_cannot_remove_main": "You cannot remove '{domain:s}' since it's the main domain, you first need to set another domain as the main domain using 'yunohost domain main-domain -n '; here is the list of candidate domains: {other_domains:s}", "domain_cannot_add_xmpp_upload": "You cannot add domains starting with 'xmpp-upload.'. This kind of name is reserved for the XMPP upload feature integrated in YunoHost.", + "domain_cannot_add_muc_upload": "You cannot add domains starting with 'muc.'. This kind of name is reserved for the XMPP multi-users chat feature integrated in YunoHost.", "domain_cannot_remove_main_add_new_one": "You cannot remove '{domain:s}' since it's the main domain and your only domain, you need to first add another domain using 'yunohost domain add ', then set is as the main domain using 'yunohost domain main-domain -n ' and then you can remove the domain '{domain:s}' using 'yunohost domain remove {domain:s}'.'", "domain_cert_gen_failed": "Could not generate certificate", "domain_created": "Domain created", From 867632d35506ee1e7e7735d9ba064da6dd9a7dd0 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sun, 27 Nov 2022 02:54:35 +0100 Subject: [PATCH 4/4] domains: propagate mail/xmpp enable/disable toggle to actual system configurations --- conf/nginx/server.tpl.conf | 8 +++++++- hooks/conf_regen/12-metronome | 8 +++++++- hooks/conf_regen/15-nginx | 19 ++++++++++++++++++- hooks/conf_regen/19-postfix | 4 ++-- hooks/conf_regen/25-dovecot | 2 +- hooks/conf_regen/31-rspamd | 3 ++- locales/en.json | 1 - share/actionsmap.yml | 3 +++ share/config_domain.toml | 29 +---------------------------- src/certificate.py | 6 +++--- src/domain.py | 34 +++++++++++++++++++++++++++++++++- 11 files changed, 77 insertions(+), 40 deletions(-) diff --git a/conf/nginx/server.tpl.conf b/conf/nginx/server.tpl.conf index d5b1d3bef..ecb9b7fb9 100644 --- a/conf/nginx/server.tpl.conf +++ b/conf/nginx/server.tpl.conf @@ -6,7 +6,7 @@ map $http_upgrade $connection_upgrade { server { listen 80; listen [::]:80; - server_name {{ domain }} xmpp-upload.{{ domain }}; + server_name {{ domain }}{% if xmpp_enabled != "True" %} xmpp-upload.{{ domain }}{% endif %}; access_by_lua_file /usr/share/ssowat/access.lua; @@ -16,9 +16,11 @@ server { alias /tmp/.well-known/ynh-diagnosis/; } + {% if mail_enabled == "True" %} location ^~ '/.well-known/autoconfig/mail/' { alias /var/www/.well-known/{{ domain }}/autoconfig/mail/; } + {% endif %} {# Note that this != "False" is meant to be failure-safe, in the case the redrect_to_https would happen to contain empty string or whatever value. We absolutely don't want to disable the HTTPS redirect *except* when it's explicitly being asked to be disabled. #} {% if redirect_to_https != "False" %} @@ -58,9 +60,11 @@ server { resolver_timeout 5s; {% endif %} + {% if mail_enabled == "True" %} location ^~ '/.well-known/autoconfig/mail/' { alias /var/www/.well-known/{{ domain }}/autoconfig/mail/; } + {% endif %} access_by_lua_file /usr/share/ssowat/access.lua; @@ -75,6 +79,7 @@ server { error_log /var/log/nginx/{{ domain }}-error.log; } +{% if xmpp_enabled == "True" %} # vhost dedicated to XMPP http_upload server { listen 443 ssl http2; @@ -117,3 +122,4 @@ server { access_log /var/log/nginx/xmpp-upload.{{ domain }}-access.log; error_log /var/log/nginx/xmpp-upload.{{ domain }}-error.log; } +{% endif %} diff --git a/hooks/conf_regen/12-metronome b/hooks/conf_regen/12-metronome index 220d18d58..cad8d3805 100755 --- a/hooks/conf_regen/12-metronome +++ b/hooks/conf_regen/12-metronome @@ -26,8 +26,14 @@ do_pre_regen() { | sed "s/{{ main_domain }}/${main_domain}/g" \ >"${metronome_dir}/metronome.cfg.lua" - # add domain conf files + # Trick such that old conf files are flagged as to remove for domain in $YNH_DOMAINS; do + touch "${metronome_conf_dir}/${domain}.cfg.lua" + done + + # add domain conf files + domain_list="$(yunohost domain list --features xmpp --output-as json | jq -r ".domains[]")" + for domain in $domain_list; do cat domain.tpl.cfg.lua \ | sed "s/{{ domain }}/${domain}/g" \ >"${metronome_conf_dir}/${domain}.cfg.lua" diff --git a/hooks/conf_regen/15-nginx b/hooks/conf_regen/15-nginx index fe5154cb9..aac3ff3e2 100755 --- a/hooks/conf_regen/15-nginx +++ b/hooks/conf_regen/15-nginx @@ -73,6 +73,8 @@ do_pre_regen() { cert_status=$(yunohost domain cert status --json) # add domain conf files + xmpp_domain_list="$(yunohost domain list --features xmpp --output-as json | jq -r ".domains[]")" + mail_domain_list="$(yunohost domain list --features mail_in mail_out --output-as json | jq -r ".domains[]")" for domain in $YNH_DOMAINS; do domain_conf_dir="${nginx_conf_dir}/${domain}.d" mkdir -p "$domain_conf_dir" @@ -84,9 +86,24 @@ do_pre_regen() { export domain_cert_ca=$(echo $cert_status \ | jq ".certificates.\"$domain\".CA_type" \ | tr -d '"') + if echo "$xmpp_domain_list" | grep -q "^$domain$" + then + export xmpp_enabled="True" + else + export xmpp_enabled="False" + fi + if echo "$mail_domain_list" | grep -q "^$domain$" + then + export mail_enabled="True" + else + export mail_enabled="False" + fi ynh_render_template "server.tpl.conf" "${nginx_conf_dir}/${domain}.conf" - ynh_render_template "autoconfig.tpl.xml" "${mail_autoconfig_dir}/config-v1.1.xml" + if [ $mail_enabled == "True" ] + then + ynh_render_template "autoconfig.tpl.xml" "${mail_autoconfig_dir}/config-v1.1.xml" + fi touch "${domain_conf_dir}/yunohost_local.conf" # Clean legacy conf files diff --git a/hooks/conf_regen/19-postfix b/hooks/conf_regen/19-postfix index 266cf5ba7..93de29165 100755 --- a/hooks/conf_regen/19-postfix +++ b/hooks/conf_regen/19-postfix @@ -46,13 +46,13 @@ do_pre_regen() { cat <<<"[${relay_host}]:${relay_port} ${relay_user}:${relay_password}" >${postfix_dir}/sasl_passwd fi export main_domain - export domain_list="$YNH_DOMAINS" + export domain_list="$(yunohost domain list --features mail_in mail_out --output-as json | jq -r ".domains[]" | tr '\n' ' ')" ynh_render_template "main.cf" "${postfix_dir}/main.cf" ynh_render_template "sni" "${postfix_dir}/sni" cat postsrsd \ | sed "s/{{ main_domain }}/${main_domain}/g" \ - | sed "s/{{ domain_list }}/${YNH_DOMAINS}/g" \ + | sed "s/{{ domain_list }}/${domain_list}/g" \ >"${default_dir}/postsrsd" # adapt it for IPv4-only hosts diff --git a/hooks/conf_regen/25-dovecot b/hooks/conf_regen/25-dovecot index da7e0fa75..adbb7761e 100755 --- a/hooks/conf_regen/25-dovecot +++ b/hooks/conf_regen/25-dovecot @@ -18,7 +18,7 @@ do_pre_regen() { export pop3_enabled="$(yunohost settings get 'email.pop3.pop3_enabled')" export main_domain=$(cat /etc/yunohost/current_host) - export domain_list="$YNH_DOMAINS" + export domain_list="$(yunohost domain list --features mail_in mail_out --output-as json | jq -r ".domains[]" | tr '\n' ' ')" ynh_render_template "dovecot.conf" "${dovecot_dir}/dovecot.conf" diff --git a/hooks/conf_regen/31-rspamd b/hooks/conf_regen/31-rspamd index 536aec7c2..6807ce0cd 100755 --- a/hooks/conf_regen/31-rspamd +++ b/hooks/conf_regen/31-rspamd @@ -26,7 +26,8 @@ do_post_regen() { chown _rspamd /etc/dkim # create DKIM key for domains - for domain in $YNH_DOMAINS; do + domain_list="$(yunohost domain list --features mail_in mail_out --output-as json | jq -r ".domains[]" | tr '\n' ' ')" + for domain in $domain_list; do domain_key="/etc/dkim/${domain}.mail.key" [ ! -f "$domain_key" ] && { # We use a 1024 bit size because nsupdate doesn't seem to be able to diff --git a/locales/en.json b/locales/en.json index d18f8791e..26cd3dd75 100644 --- a/locales/en.json +++ b/locales/en.json @@ -337,7 +337,6 @@ "domain_config_cert_summary_selfsigned": "WARNING: Current certificate is self-signed. Browsers will display a spooky warning to new visitors!", "domain_config_cert_validity": "Validity", "domain_config_default_app": "Default app", - "domain_config_features_disclaimer": "So far, enabling/disabling mail or XMPP features only impact the recommended and automatic DNS configuration, not system configurations!", "domain_config_mail_in": "Incoming emails", "domain_config_mail_out": "Outgoing emails", "domain_config_xmpp": "Instant messaging (XMPP)", diff --git a/share/actionsmap.yml b/share/actionsmap.yml index 98ae59a7b..13af8b83d 100644 --- a/share/actionsmap.yml +++ b/share/actionsmap.yml @@ -462,6 +462,9 @@ domain: --tree: help: Display domains as a tree action: store_true + --features: + help: List only domains with features enabled (xmpp, mail_in, mail_out) + nargs: "*" ### domain_info() info: diff --git a/share/config_domain.toml b/share/config_domain.toml index 87489999d..4257e6af8 100644 --- a/share/config_domain.toml +++ b/share/config_domain.toml @@ -1,14 +1,6 @@ version = "1.0" i18n = "domain_config" -# -# Other things we may want to implement in the future: -# -# - maindomain handling -# - autoredirect www in nginx conf -# - ? -# - [feature] name = "Features" @@ -19,12 +11,6 @@ name = "Features" default = "_none" [feature.mail] - #services = ['postfix', 'dovecot'] - - [feature.mail.features_disclaimer] - type = "alert" - style = "warning" - icon = "warning" [feature.mail.mail_out] type = "boolean" @@ -34,17 +20,12 @@ name = "Features" type = "boolean" default = 1 - #[feature.mail.backup_mx] - #type = "tags" - #default = [] - #pattern.regexp = '^([^\W_A-Z]+([-]*[^\W_A-Z]+)*\.)+((xn--)?[^\W_]{2,})$' - #pattern.error = "pattern_error" - [feature.xmpp] [feature.xmpp.xmpp] type = "boolean" default = 0 + help = "NB: some XMPP features will require that you update your DNS records and regenerate your Lets Encrypt certificate to be enabled" [dns] name = "DNS" @@ -52,14 +33,6 @@ name = "DNS" [dns.registrar] # This part is automatically generated in DomainConfigPanel -# [dns.advanced] -# -# [dns.advanced.ttl] -# type = "number" -# min = 0 -# default = 3600 - - [cert] name = "Certificate" diff --git a/src/certificate.py b/src/certificate.py index 3919e26ac..04a33dbfd 100644 --- a/src/certificate.py +++ b/src/certificate.py @@ -568,10 +568,10 @@ def _prepare_certificate_signing_request(domain, key_file, output_folder): # Set the domain csr.get_subject().CN = domain - from yunohost.domain import domain_list + from yunohost.domain import domain_list, domain_config_get - # For "parent" domains, include xmpp-upload subdomain in subject alternate names - if domain in domain_list(exclude_subdomains=True)["domains"]: + # If XMPP is enabled for this domain, add xmpp-upload domain + if domain_config_get(domain, key="feature.xmpp.xmpp") == 1: subdomain = "xmpp-upload." + domain xmpp_records = ( Diagnoser.get_cached_report( diff --git a/src/domain.py b/src/domain.py index d24f44ddd..489e48e16 100644 --- a/src/domain.py +++ b/src/domain.py @@ -98,7 +98,7 @@ def _get_domains(exclude_subdomains=False): return domain_list_cache -def domain_list(exclude_subdomains=False, tree=False): +def domain_list(exclude_subdomains=False, tree=False, features=[]): """ List domains @@ -111,6 +111,14 @@ def domain_list(exclude_subdomains=False, tree=False): domains = _get_domains(exclude_subdomains) main = _get_maindomain() + if features: + domains_filtered = [] + for domain in domains: + config = domain_config_get(domain, key="feature", export=True) + if any(config.get(feature) == 1 for feature in features): + domains_filtered.append(domain) + domains = domains_filtered + if not tree: return {"domains": domains, "main": main} @@ -545,6 +553,30 @@ class DomainConfigPanel(ConfigPanel): ): app_ssowatconf() + stuff_to_regen_conf = [] + if ( + "xmpp" in self.future_values + and self.future_values["xmpp"] != self.values["xmpp"] + ): + stuff_to_regen_conf.append("nginx") + stuff_to_regen_conf.append("metronome") + + if ( + "mail_in" in self.future_values + and self.future_values["mail_in"] != self.values["mail_in"] + ) or ( + "mail_out" in self.future_values + and self.future_values["mail_out"] != self.values["mail_out"] + ): + if "nginx" not in stuff_to_regen_conf: + stuff_to_regen_conf.append("nginx") + stuff_to_regen_conf.append("postfix") + stuff_to_regen_conf.append("dovecot") + stuff_to_regen_conf.append("rspamd") + + if stuff_to_regen_conf: + regen_conf(names=stuff_to_regen_conf) + def _get_toml(self): toml = super()._get_toml()