From 7372dc207962c6e16a5f9e73c6d082b39861b9cd Mon Sep 17 00:00:00 2001 From: Kay0u Date: Thu, 24 Nov 2022 14:42:43 +0100 Subject: [PATCH 01/67] be able to change the loginShell of a user --- src/user.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/user.py b/src/user.py index 84923106c6..74a11e99d5 100644 --- a/src/user.py +++ b/src/user.py @@ -134,6 +134,7 @@ def user_create( lastname=None, mailbox_quota="0", admin=False, + loginShell="/bin/bash", from_import=False, ): @@ -253,7 +254,7 @@ def user_create( "gidNumber": [uid], "uidNumber": [uid], "homeDirectory": ["/home/" + username], - "loginShell": ["/bin/bash"], + "loginShell": [loginShell], } try: @@ -363,6 +364,7 @@ def user_update( mailbox_quota=None, from_import=False, fullname=None, + loginShell=None, ): if firstname or lastname: @@ -524,6 +526,10 @@ def user_update( new_attr_dict["mailuserquota"] = [mailbox_quota] env_dict["YNH_USER_MAILQUOTA"] = mailbox_quota + if loginShell is not None: + new_attr_dict["loginShell"] = [loginShell] + env_dict["YNH_USER_LOGINSHELL"] = loginShell + if not from_import: operation_logger.start() @@ -532,6 +538,10 @@ def user_update( except Exception as e: raise YunohostError("user_update_failed", user=username, error=e) + # Invalidate passwd and group to update the loginShell + subprocess.call(["nscd", "-i", "passwd"]) + subprocess.call(["nscd", "-i", "group"]) + # Trigger post_user_update hooks hook_callback("post_user_update", env=env_dict) From af1c1d8c02507a36d8e882fd79e08c0506704582 Mon Sep 17 00:00:00 2001 From: Kay0u Date: Thu, 24 Nov 2022 15:13:59 +0100 Subject: [PATCH 02/67] check if the shell exists --- locales/en.json | 1 + src/user.py | 36 ++++++++++++++++++++++++++++++++++-- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/locales/en.json b/locales/en.json index d18f8791ea..4dc4037f8e 100644 --- a/locales/en.json +++ b/locales/en.json @@ -459,6 +459,7 @@ "invalid_number_max": "Must be lesser than {max}", "invalid_number_min": "Must be greater than {min}", "invalid_regex": "Invalid regex:'{regex}'", + "invalid_shell": "Invalid shell: {shell}", "ip6tables_unavailable": "You cannot play with ip6tables here. You are either in a container or your kernel does not support it", "iptables_unavailable": "You cannot play with iptables here. You are either in a container or your kernel does not support it", "ldap_attribute_already_exists": "LDAP attribute '{attribute}' already exists with value '{value}'", diff --git a/src/user.py b/src/user.py index 74a11e99d5..6583b32e87 100644 --- a/src/user.py +++ b/src/user.py @@ -122,6 +122,29 @@ def display_default(values, _): return {"users": users} +def list_shells(): + import ctypes + import ctypes.util + import os + import sys + + """List the shells from /etc/shells.""" + libc = ctypes.CDLL(ctypes.util.find_library("c")) + getusershell = libc.getusershell + getusershell.restype = ctypes.c_char_p + libc.setusershell() + while True: + shell = getusershell() + if not shell: + break + yield shell.decode() + libc.endusershell() + + +def shellexists(shell): + """Check if the provided shell exists and is executable.""" + return os.path.isfile(shell) and os.access(shell, os.X_OK) + @is_unit_operation([("username", "user")]) def user_create( @@ -134,8 +157,8 @@ def user_create( lastname=None, mailbox_quota="0", admin=False, - loginShell="/bin/bash", from_import=False, + loginShell=None, ): if firstname or lastname: @@ -235,6 +258,12 @@ def user_create( uid = str(random.randint(1001, 65000)) uid_guid_found = uid not in all_uid and uid not in all_gid + if not loginShell: + loginShell = "/bin/bash" + else: + if not shellexists(loginShell) or loginShell not in list_shells(): + raise YunohostValidationError("invalid_shell", shell=loginShell) + attr_dict = { "objectClass": [ "mailAccount", @@ -527,6 +556,8 @@ def user_update( env_dict["YNH_USER_MAILQUOTA"] = mailbox_quota if loginShell is not None: + if not shellexists(loginShell) or loginShell not in list_shells(): + raise YunohostValidationError("invalid_shell", shell=loginShell) new_attr_dict["loginShell"] = [loginShell] env_dict["YNH_USER_LOGINSHELL"] = loginShell @@ -563,7 +594,7 @@ def user_info(username): ldap = _get_ldap_interface() - user_attrs = ["cn", "mail", "uid", "maildrop", "mailuserquota"] + user_attrs = ["cn", "mail", "uid", "maildrop", "mailuserquota", "loginShell"] if len(username.split("@")) == 2: filter = "mail=" + username @@ -581,6 +612,7 @@ def user_info(username): "username": user["uid"][0], "fullname": user["cn"][0], "mail": user["mail"][0], + "loginShell": user["loginShell"][0], "mail-aliases": [], "mail-forward": [], } From dda5095157b4d6e5d947df4a65d54c9eb17c0dfa Mon Sep 17 00:00:00 2001 From: Kay0u Date: Thu, 24 Nov 2022 15:14:06 +0100 Subject: [PATCH 03/67] add actionsmap parameters --- share/actionsmap.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/share/actionsmap.yml b/share/actionsmap.yml index 98ae59a7b6..72c515e6f3 100644 --- a/share/actionsmap.yml +++ b/share/actionsmap.yml @@ -124,6 +124,11 @@ user: pattern: &pattern_mailbox_quota - !!str ^(\d+[bkMGT])|0$ - "pattern_mailbox_quota" + -s: + full: --loginShell + help: The login shell used + default: "/bin/bash" + ### user_delete() delete: @@ -203,6 +208,10 @@ user: metavar: "{SIZE|0}" extra: pattern: *pattern_mailbox_quota + -s: + full: --loginShell + help: The login shell used + default: "/bin/bash" ### user_info() info: From 21c72ad1c5378da21513f45c15addad2dd9e7596 Mon Sep 17 00:00:00 2001 From: Kay0u Date: Thu, 24 Nov 2022 17:30:05 +0100 Subject: [PATCH 04/67] fix linter --- src/user.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/user.py b/src/user.py index 6583b32e87..61060a9ef6 100644 --- a/src/user.py +++ b/src/user.py @@ -125,8 +125,6 @@ def display_default(values, _): def list_shells(): import ctypes import ctypes.util - import os - import sys """List the shells from /etc/shells.""" libc = ctypes.CDLL(ctypes.util.find_library("c")) From ea20b1581d6998ed6aa8d6c9cd6c8fc5d8b3cb9a Mon Sep 17 00:00:00 2001 From: Tagadda <36127788+Tagadda@users.noreply.github.com> Date: Sat, 26 Mar 2022 14:11:37 +0000 Subject: [PATCH 05/67] enh: ipv6 only global setting --- share/config_global.toml | 6 ++++++ src/diagnosers/10-ip.py | 5 +++-- src/diagnosers/14-ports.py | 5 +++-- src/diagnosers/21-web.py | 9 +++++---- src/diagnosers/24-mail.py | 5 +++-- src/dns.py | 5 +++-- src/settings.py | 2 ++ 7 files changed, 25 insertions(+), 12 deletions(-) diff --git a/share/config_global.toml b/share/config_global.toml index 1f3cc1b39d..405157c5f1 100644 --- a/share/config_global.toml +++ b/share/config_global.toml @@ -160,3 +160,9 @@ name = "Other" [misc.backup.backup_compress_tar_archives] type = "boolean" default = false + + [misc.network] + name = "Network" + [misc.network.network_ipv6_only] + type = "boolean" + default = false diff --git a/src/diagnosers/10-ip.py b/src/diagnosers/10-ip.py index b2bedc802e..098bd569c0 100644 --- a/src/diagnosers/10-ip.py +++ b/src/diagnosers/10-ip.py @@ -28,6 +28,7 @@ from yunohost.diagnosis import Diagnoser from yunohost.utils.network import get_network_interfaces +from yunohost.settings import settings_get logger = log.getActionLogger("yunohost.diagnosis") @@ -121,7 +122,7 @@ def get_local_ip(version): yield dict( meta={"test": "ipv4"}, data={"global": ipv4, "local": get_local_ip("ipv4")}, - status="SUCCESS" if ipv4 else "ERROR", + status="SUCCESS" if ipv4 else "WARNING" if settings_get("network_ipv6_only") else "ERROR", summary="diagnosis_ip_connected_ipv4" if ipv4 else "diagnosis_ip_no_ipv4", details=["diagnosis_ip_global", "diagnosis_ip_local"] if ipv4 else None, ) @@ -129,7 +130,7 @@ def get_local_ip(version): yield dict( meta={"test": "ipv6"}, data={"global": ipv6, "local": get_local_ip("ipv6")}, - status="SUCCESS" if ipv6 else "WARNING", + status="SUCCESS" if ipv6 else "ERROR" if settings_get("network_ipv6_only") else "WARNING", summary="diagnosis_ip_connected_ipv6" if ipv6 else "diagnosis_ip_no_ipv6", details=["diagnosis_ip_global", "diagnosis_ip_local"] if ipv6 diff --git a/src/diagnosers/14-ports.py b/src/diagnosers/14-ports.py index 5671211b57..0ca39a42cb 100644 --- a/src/diagnosers/14-ports.py +++ b/src/diagnosers/14-ports.py @@ -21,6 +21,7 @@ from yunohost.diagnosis import Diagnoser from yunohost.service import _get_services +from yunohost.settings import settings_get class MyDiagnoser(Diagnoser): @@ -46,7 +47,7 @@ def run(self): ipversions = [] ipv4 = Diagnoser.get_cached_report("ip", item={"test": "ipv4"}) or {} - if ipv4.get("status") == "SUCCESS": + if ipv4.get("status") == "SUCCESS" and not settings_get("network_ipv6_only"): ipversions.append(4) # To be discussed: we could also make this check dependent on the @@ -120,7 +121,7 @@ def ipv6_is_important(): for record in dnsrecords.get("items", []) ) - if failed == 4 or ipv6_is_important(): + if failed == 4 and not settings_get("network_ipv6_only") or ipv6_is_important(): yield dict( meta={"port": port}, data={ diff --git a/src/diagnosers/21-web.py b/src/diagnosers/21-web.py index 4a69895b25..bdba89f78d 100644 --- a/src/diagnosers/21-web.py +++ b/src/diagnosers/21-web.py @@ -26,6 +26,7 @@ from yunohost.diagnosis import Diagnoser from yunohost.domain import domain_list from yunohost.utils.dns import is_special_use_tld +from yunohost.settings import settings_get DIAGNOSIS_SERVER = "diagnosis.yunohost.org" @@ -76,7 +77,7 @@ def run(self): ipversions = [] ipv4 = Diagnoser.get_cached_report("ip", item={"test": "ipv4"}) or {} - if ipv4.get("status") == "SUCCESS": + if ipv4.get("status") == "SUCCESS" and not settings_get("network_ipv6_only"): ipversions.append(4) # To be discussed: we could also make this check dependent on the @@ -96,7 +97,7 @@ def run(self): # "curl --head the.global.ip" will simply timeout... if self.do_hairpinning_test: global_ipv4 = ipv4.get("data", {}).get("global", None) - if global_ipv4: + if global_ipv4 and not settings_get("network_ipv6_only"): try: requests.head("http://" + global_ipv4, timeout=5) except requests.exceptions.Timeout: @@ -147,7 +148,7 @@ def test_http(self, domains, ipversions): if all( results[ipversion][domain]["status"] == "ok" for ipversion in ipversions ): - if 4 in ipversions: + if 4 in ipversions and not settings_get("network_ipv6_only"): self.do_hairpinning_test = True yield dict( meta={"domain": domain}, @@ -185,7 +186,7 @@ def ipv6_is_important_for_this_domain(): ) AAAA_status = dnsrecords.get("data", {}).get("AAAA:@") - return AAAA_status in ["OK", "WRONG"] + return AAAA_status in ["OK", "WRONG"] or settings_get("network_ipv6_only") if failed == 4 or ipv6_is_important_for_this_domain(): yield dict( diff --git a/src/diagnosers/24-mail.py b/src/diagnosers/24-mail.py index 88d6a8259c..536f870b39 100644 --- a/src/diagnosers/24-mail.py +++ b/src/diagnosers/24-mail.py @@ -31,6 +31,7 @@ from yunohost.domain import _get_maindomain, domain_list from yunohost.settings import settings_get from yunohost.utils.dns import dig +from yunohost.settings import settings_get DEFAULT_DNS_BLACKLIST = "/usr/share/yunohost/dnsbl_list.yml" @@ -301,13 +302,13 @@ def get_ips_checked(self): outgoing_ipversions = [] outgoing_ips = [] ipv4 = Diagnoser.get_cached_report("ip", {"test": "ipv4"}) or {} - if ipv4.get("status") == "SUCCESS": + if ipv4.get("status") == "SUCCESS" and not settings_get("network_ipv6_only"): outgoing_ipversions.append(4) global_ipv4 = ipv4.get("data", {}).get("global", {}) if global_ipv4: outgoing_ips.append(global_ipv4) - if settings_get("email.smtp.smtp_allow_ipv6"): + if settings_get("email.smtp.smtp_allow_ipv6") or settings_get("network_ipv6_only"): ipv6 = Diagnoser.get_cached_report("ip", {"test": "ipv6"}) or {} if ipv6.get("status") == "SUCCESS": outgoing_ipversions.append(6) diff --git a/src/dns.py b/src/dns.py index 1c6b99cf08..cc7ebd7e7a 100644 --- a/src/dns.py +++ b/src/dns.py @@ -38,6 +38,7 @@ from yunohost.utils.dns import dig, is_yunohost_dyndns_domain, is_special_use_tld from yunohost.utils.error import YunohostValidationError, YunohostError from yunohost.utils.network import get_public_ip +from yunohost.settings import settings_get from yunohost.log import is_unit_operation from yunohost.hook import hook_callback @@ -185,7 +186,7 @@ def _build_dns_conf(base_domain, include_empty_AAAA_if_no_ipv6=False): ########################### # Basic ipv4/ipv6 records # ########################### - if ipv4: + if ipv4 and not settings_get("network_ipv6_only"): basic.append([basename, ttl, "A", ipv4]) if ipv6: @@ -240,7 +241,7 @@ def _build_dns_conf(base_domain, include_empty_AAAA_if_no_ipv6=False): # Only recommend wildcard and CAA for the top level if domain == base_domain: - if ipv4: + if ipv4 and not settings_get("network_ipv6_only"): extra.append([f"*{suffix}", ttl, "A", ipv4]) if ipv6: diff --git a/src/settings.py b/src/settings.py index d9ea600a43..f525747858 100644 --- a/src/settings.py +++ b/src/settings.py @@ -310,6 +310,7 @@ def regen_ssowatconf(setting_name, old_value, new_value): @post_change_hook("nginx_compatibility") @post_change_hook("webadmin_allowlist_enabled") @post_change_hook("webadmin_allowlist") +@post_change_hook("network_ipv6_only") def reconfigure_nginx(setting_name, old_value, new_value): if old_value != new_value: regen_conf(names=["nginx"]) @@ -341,6 +342,7 @@ def reconfigure_ssh_and_fail2ban(setting_name, old_value, new_value): @post_change_hook("smtp_relay_user") @post_change_hook("smtp_relay_password") @post_change_hook("postfix_compatibility") +@post_change_hook("network_ipv6_only") def reconfigure_postfix(setting_name, old_value, new_value): if old_value != new_value: regen_conf(names=["postfix"]) From 029c3b76863cf0646a2f8e1137a2b9325fbdaf79 Mon Sep 17 00:00:00 2001 From: Tagadda <36127788+Tagadda@users.noreply.github.com> Date: Tue, 11 Oct 2022 18:01:56 +0000 Subject: [PATCH 06/67] Change to select --- share/config_global.toml | 9 ++++++--- src/diagnosers/10-ip.py | 4 ++-- src/diagnosers/14-ports.py | 4 ++-- src/diagnosers/21-web.py | 8 ++++---- src/diagnosers/24-mail.py | 4 ++-- src/dns.py | 4 ++-- src/settings.py | 4 ++-- 7 files changed, 20 insertions(+), 17 deletions(-) diff --git a/share/config_global.toml b/share/config_global.toml index 405157c5f1..40b71ab195 100644 --- a/share/config_global.toml +++ b/share/config_global.toml @@ -163,6 +163,9 @@ name = "Other" [misc.network] name = "Network" - [misc.network.network_ipv6_only] - type = "boolean" - default = false + [misc.network.dns_exposure] + type = "select" + choices.both = "Both" + choices.ipv4 = "IPv4 Only" + choices.ipv6 = "IPv6 Only" + default = "both" diff --git a/src/diagnosers/10-ip.py b/src/diagnosers/10-ip.py index 098bd569c0..7de4623342 100644 --- a/src/diagnosers/10-ip.py +++ b/src/diagnosers/10-ip.py @@ -122,7 +122,7 @@ def get_local_ip(version): yield dict( meta={"test": "ipv4"}, data={"global": ipv4, "local": get_local_ip("ipv4")}, - status="SUCCESS" if ipv4 else "WARNING" if settings_get("network_ipv6_only") else "ERROR", + status="SUCCESS" if ipv4 else "ERROR" if settings_get("dns_exposure") == "ipv4" else "WARNING", summary="diagnosis_ip_connected_ipv4" if ipv4 else "diagnosis_ip_no_ipv4", details=["diagnosis_ip_global", "diagnosis_ip_local"] if ipv4 else None, ) @@ -130,7 +130,7 @@ def get_local_ip(version): yield dict( meta={"test": "ipv6"}, data={"global": ipv6, "local": get_local_ip("ipv6")}, - status="SUCCESS" if ipv6 else "ERROR" if settings_get("network_ipv6_only") else "WARNING", + status="SUCCESS" if ipv6 else "ERROR" if settings_get("dns_exposure") == "ipv6" else "WARNING", summary="diagnosis_ip_connected_ipv6" if ipv6 else "diagnosis_ip_no_ipv6", details=["diagnosis_ip_global", "diagnosis_ip_local"] if ipv6 diff --git a/src/diagnosers/14-ports.py b/src/diagnosers/14-ports.py index 0ca39a42cb..2d7eee717c 100644 --- a/src/diagnosers/14-ports.py +++ b/src/diagnosers/14-ports.py @@ -47,7 +47,7 @@ def run(self): ipversions = [] ipv4 = Diagnoser.get_cached_report("ip", item={"test": "ipv4"}) or {} - if ipv4.get("status") == "SUCCESS" and not settings_get("network_ipv6_only"): + if ipv4.get("status") == "SUCCESS" or not settings_get("dns_exposure") == "ipv6": ipversions.append(4) # To be discussed: we could also make this check dependent on the @@ -121,7 +121,7 @@ def ipv6_is_important(): for record in dnsrecords.get("items", []) ) - if failed == 4 and not settings_get("network_ipv6_only") or ipv6_is_important(): + if failed == 4 and not settings_get("dns_exposure") == "ipv6" or ipv6_is_important(): yield dict( meta={"port": port}, data={ diff --git a/src/diagnosers/21-web.py b/src/diagnosers/21-web.py index bdba89f78d..eaac0d25fc 100644 --- a/src/diagnosers/21-web.py +++ b/src/diagnosers/21-web.py @@ -77,7 +77,7 @@ def run(self): ipversions = [] ipv4 = Diagnoser.get_cached_report("ip", item={"test": "ipv4"}) or {} - if ipv4.get("status") == "SUCCESS" and not settings_get("network_ipv6_only"): + if ipv4.get("status") == "SUCCESS" and not settings_get("dns_exposure") == "ipv6": ipversions.append(4) # To be discussed: we could also make this check dependent on the @@ -97,7 +97,7 @@ def run(self): # "curl --head the.global.ip" will simply timeout... if self.do_hairpinning_test: global_ipv4 = ipv4.get("data", {}).get("global", None) - if global_ipv4 and not settings_get("network_ipv6_only"): + if global_ipv4 and settings_get("dns_exposure") != "ipv6": try: requests.head("http://" + global_ipv4, timeout=5) except requests.exceptions.Timeout: @@ -148,7 +148,7 @@ def test_http(self, domains, ipversions): if all( results[ipversion][domain]["status"] == "ok" for ipversion in ipversions ): - if 4 in ipversions and not settings_get("network_ipv6_only"): + if 4 in ipversions and settings_get("dns_exposure") != "ipv6": self.do_hairpinning_test = True yield dict( meta={"domain": domain}, @@ -186,7 +186,7 @@ def ipv6_is_important_for_this_domain(): ) AAAA_status = dnsrecords.get("data", {}).get("AAAA:@") - return AAAA_status in ["OK", "WRONG"] or settings_get("network_ipv6_only") + return AAAA_status in ["OK", "WRONG"] or settings_get("dns_exposure") != "ipv4" if failed == 4 or ipv6_is_important_for_this_domain(): yield dict( diff --git a/src/diagnosers/24-mail.py b/src/diagnosers/24-mail.py index 536f870b39..43273aebf3 100644 --- a/src/diagnosers/24-mail.py +++ b/src/diagnosers/24-mail.py @@ -302,13 +302,13 @@ def get_ips_checked(self): outgoing_ipversions = [] outgoing_ips = [] ipv4 = Diagnoser.get_cached_report("ip", {"test": "ipv4"}) or {} - if ipv4.get("status") == "SUCCESS" and not settings_get("network_ipv6_only"): + if ipv4.get("status") == "SUCCESS" and settings_get("dns_exposure") != "ipv6": outgoing_ipversions.append(4) global_ipv4 = ipv4.get("data", {}).get("global", {}) if global_ipv4: outgoing_ips.append(global_ipv4) - if settings_get("email.smtp.smtp_allow_ipv6") or settings_get("network_ipv6_only"): + if settings_get("email.smtp.smtp_allow_ipv6") or settings_get("dns_exposure") != "ipv4": ipv6 = Diagnoser.get_cached_report("ip", {"test": "ipv6"}) or {} if ipv6.get("status") == "SUCCESS": outgoing_ipversions.append(6) diff --git a/src/dns.py b/src/dns.py index cc7ebd7e7a..31c91d5907 100644 --- a/src/dns.py +++ b/src/dns.py @@ -186,7 +186,7 @@ def _build_dns_conf(base_domain, include_empty_AAAA_if_no_ipv6=False): ########################### # Basic ipv4/ipv6 records # ########################### - if ipv4 and not settings_get("network_ipv6_only"): + if ipv4 and not settings_get("dns_exposure") == "ipv6": basic.append([basename, ttl, "A", ipv4]) if ipv6: @@ -241,7 +241,7 @@ def _build_dns_conf(base_domain, include_empty_AAAA_if_no_ipv6=False): # Only recommend wildcard and CAA for the top level if domain == base_domain: - if ipv4 and not settings_get("network_ipv6_only"): + if ipv4 and settings_get("dns_exposure") != "ipv6": extra.append([f"*{suffix}", ttl, "A", ipv4]) if ipv6: diff --git a/src/settings.py b/src/settings.py index f525747858..96f11caebd 100644 --- a/src/settings.py +++ b/src/settings.py @@ -310,7 +310,7 @@ def regen_ssowatconf(setting_name, old_value, new_value): @post_change_hook("nginx_compatibility") @post_change_hook("webadmin_allowlist_enabled") @post_change_hook("webadmin_allowlist") -@post_change_hook("network_ipv6_only") +@post_change_hook("dns_exposure") def reconfigure_nginx(setting_name, old_value, new_value): if old_value != new_value: regen_conf(names=["nginx"]) @@ -342,7 +342,7 @@ def reconfigure_ssh_and_fail2ban(setting_name, old_value, new_value): @post_change_hook("smtp_relay_user") @post_change_hook("smtp_relay_password") @post_change_hook("postfix_compatibility") -@post_change_hook("network_ipv6_only") +@post_change_hook("dns_exposure") def reconfigure_postfix(setting_name, old_value, new_value): if old_value != new_value: regen_conf(names=["postfix"]) From f4b396219cbf76e3785f0b24dc130b590a2d2464 Mon Sep 17 00:00:00 2001 From: Tagadda <36127788+Tagadda@users.noreply.github.com> Date: Tue, 11 Oct 2022 18:06:57 +0000 Subject: [PATCH 07/67] Clarify conditions --- src/diagnosers/14-ports.py | 4 ++-- src/diagnosers/21-web.py | 2 +- src/dns.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/diagnosers/14-ports.py b/src/diagnosers/14-ports.py index 2d7eee717c..1483dbb968 100644 --- a/src/diagnosers/14-ports.py +++ b/src/diagnosers/14-ports.py @@ -47,7 +47,7 @@ def run(self): ipversions = [] ipv4 = Diagnoser.get_cached_report("ip", item={"test": "ipv4"}) or {} - if ipv4.get("status") == "SUCCESS" or not settings_get("dns_exposure") == "ipv6": + if ipv4.get("status") == "SUCCESS" or settings_get("dns_exposure") != "ipv6": ipversions.append(4) # To be discussed: we could also make this check dependent on the @@ -121,7 +121,7 @@ def ipv6_is_important(): for record in dnsrecords.get("items", []) ) - if failed == 4 and not settings_get("dns_exposure") == "ipv6" or ipv6_is_important(): + if failed == 4 and settings_get("dns_exposure") != "ipv6" or ipv6_is_important(): yield dict( meta={"port": port}, data={ diff --git a/src/diagnosers/21-web.py b/src/diagnosers/21-web.py index eaac0d25fc..f62d182bc0 100644 --- a/src/diagnosers/21-web.py +++ b/src/diagnosers/21-web.py @@ -77,7 +77,7 @@ def run(self): ipversions = [] ipv4 = Diagnoser.get_cached_report("ip", item={"test": "ipv4"}) or {} - if ipv4.get("status") == "SUCCESS" and not settings_get("dns_exposure") == "ipv6": + if ipv4.get("status") == "SUCCESS" and settings_get("dns_exposure") != "ipv6": ipversions.append(4) # To be discussed: we could also make this check dependent on the diff --git a/src/dns.py b/src/dns.py index 31c91d5907..a007f69be6 100644 --- a/src/dns.py +++ b/src/dns.py @@ -186,7 +186,7 @@ def _build_dns_conf(base_domain, include_empty_AAAA_if_no_ipv6=False): ########################### # Basic ipv4/ipv6 records # ########################### - if ipv4 and not settings_get("dns_exposure") == "ipv6": + if ipv4 and settings_get("dns_exposure") != "ipv6": basic.append([basename, ttl, "A", ipv4]) if ipv6: From c4c78f5daa785a9d3356e9365fdc8f6d1900fc92 Mon Sep 17 00:00:00 2001 From: Tagadda <36127788+Tagadda@users.noreply.github.com> Date: Mon, 24 Oct 2022 21:55:05 +0000 Subject: [PATCH 08/67] oops --- src/diagnosers/10-ip.py | 4 ++-- src/diagnosers/14-ports.py | 4 ++-- src/diagnosers/21-web.py | 8 ++++---- src/diagnosers/24-mail.py | 4 ++-- src/dns.py | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/diagnosers/10-ip.py b/src/diagnosers/10-ip.py index 7de4623342..954b9b4e84 100644 --- a/src/diagnosers/10-ip.py +++ b/src/diagnosers/10-ip.py @@ -122,7 +122,7 @@ def get_local_ip(version): yield dict( meta={"test": "ipv4"}, data={"global": ipv4, "local": get_local_ip("ipv4")}, - status="SUCCESS" if ipv4 else "ERROR" if settings_get("dns_exposure") == "ipv4" else "WARNING", + status="SUCCESS" if ipv4 else "ERROR" if settings_get("misc.network.dns_exposure") == "ipv4" else "WARNING", summary="diagnosis_ip_connected_ipv4" if ipv4 else "diagnosis_ip_no_ipv4", details=["diagnosis_ip_global", "diagnosis_ip_local"] if ipv4 else None, ) @@ -130,7 +130,7 @@ def get_local_ip(version): yield dict( meta={"test": "ipv6"}, data={"global": ipv6, "local": get_local_ip("ipv6")}, - status="SUCCESS" if ipv6 else "ERROR" if settings_get("dns_exposure") == "ipv6" else "WARNING", + status="SUCCESS" if ipv6 else "ERROR" if settings_get("misc.network.dns_exposure") == "ipv6" else "WARNING", summary="diagnosis_ip_connected_ipv6" if ipv6 else "diagnosis_ip_no_ipv6", details=["diagnosis_ip_global", "diagnosis_ip_local"] if ipv6 diff --git a/src/diagnosers/14-ports.py b/src/diagnosers/14-ports.py index 1483dbb968..1e265f78e8 100644 --- a/src/diagnosers/14-ports.py +++ b/src/diagnosers/14-ports.py @@ -47,7 +47,7 @@ def run(self): ipversions = [] ipv4 = Diagnoser.get_cached_report("ip", item={"test": "ipv4"}) or {} - if ipv4.get("status") == "SUCCESS" or settings_get("dns_exposure") != "ipv6": + if ipv4.get("status") == "SUCCESS" or settings_get(misc.network.dns_exposure") != "ipv6": ipversions.append(4) # To be discussed: we could also make this check dependent on the @@ -121,7 +121,7 @@ def ipv6_is_important(): for record in dnsrecords.get("items", []) ) - if failed == 4 and settings_get("dns_exposure") != "ipv6" or ipv6_is_important(): + if failed == 4 and settings_get(misc.network.dns_exposure") != "ipv6" or ipv6_is_important(): yield dict( meta={"port": port}, data={ diff --git a/src/diagnosers/21-web.py b/src/diagnosers/21-web.py index f62d182bc0..2024cf6ced 100644 --- a/src/diagnosers/21-web.py +++ b/src/diagnosers/21-web.py @@ -77,7 +77,7 @@ def run(self): ipversions = [] ipv4 = Diagnoser.get_cached_report("ip", item={"test": "ipv4"}) or {} - if ipv4.get("status") == "SUCCESS" and settings_get("dns_exposure") != "ipv6": + if ipv4.get("status") == "SUCCESS" and settings_get(misc.network.dns_exposure") != "ipv6": ipversions.append(4) # To be discussed: we could also make this check dependent on the @@ -97,7 +97,7 @@ def run(self): # "curl --head the.global.ip" will simply timeout... if self.do_hairpinning_test: global_ipv4 = ipv4.get("data", {}).get("global", None) - if global_ipv4 and settings_get("dns_exposure") != "ipv6": + if global_ipv4 and settings_get(misc.network.dns_exposure") != "ipv6": try: requests.head("http://" + global_ipv4, timeout=5) except requests.exceptions.Timeout: @@ -148,7 +148,7 @@ def test_http(self, domains, ipversions): if all( results[ipversion][domain]["status"] == "ok" for ipversion in ipversions ): - if 4 in ipversions and settings_get("dns_exposure") != "ipv6": + if 4 in ipversions and settings_get(misc.network.dns_exposure") != "ipv6": self.do_hairpinning_test = True yield dict( meta={"domain": domain}, @@ -186,7 +186,7 @@ def ipv6_is_important_for_this_domain(): ) AAAA_status = dnsrecords.get("data", {}).get("AAAA:@") - return AAAA_status in ["OK", "WRONG"] or settings_get("dns_exposure") != "ipv4" + return AAAA_status in ["OK", "WRONG"] or settings_get(misc.network.dns_exposure") != "ipv4" if failed == 4 or ipv6_is_important_for_this_domain(): yield dict( diff --git a/src/diagnosers/24-mail.py b/src/diagnosers/24-mail.py index 43273aebf3..590b0d9ba7 100644 --- a/src/diagnosers/24-mail.py +++ b/src/diagnosers/24-mail.py @@ -302,13 +302,13 @@ def get_ips_checked(self): outgoing_ipversions = [] outgoing_ips = [] ipv4 = Diagnoser.get_cached_report("ip", {"test": "ipv4"}) or {} - if ipv4.get("status") == "SUCCESS" and settings_get("dns_exposure") != "ipv6": + if ipv4.get("status") == "SUCCESS" and settings_get(misc.network.dns_exposure") != "ipv6": outgoing_ipversions.append(4) global_ipv4 = ipv4.get("data", {}).get("global", {}) if global_ipv4: outgoing_ips.append(global_ipv4) - if settings_get("email.smtp.smtp_allow_ipv6") or settings_get("dns_exposure") != "ipv4": + if settings_get("email.smtp.smtp_allow_ipv6") or settings_get(misc.network.dns_exposure") != "ipv4": ipv6 = Diagnoser.get_cached_report("ip", {"test": "ipv6"}) or {} if ipv6.get("status") == "SUCCESS": outgoing_ipversions.append(6) diff --git a/src/dns.py b/src/dns.py index a007f69be6..9d81391e53 100644 --- a/src/dns.py +++ b/src/dns.py @@ -186,7 +186,7 @@ def _build_dns_conf(base_domain, include_empty_AAAA_if_no_ipv6=False): ########################### # Basic ipv4/ipv6 records # ########################### - if ipv4 and settings_get("dns_exposure") != "ipv6": + if ipv4 and settings_get("misc.network.dns_exposure") != "ipv6": basic.append([basename, ttl, "A", ipv4]) if ipv6: @@ -241,7 +241,7 @@ def _build_dns_conf(base_domain, include_empty_AAAA_if_no_ipv6=False): # Only recommend wildcard and CAA for the top level if domain == base_domain: - if ipv4 and settings_get("dns_exposure") != "ipv6": + if ipv4 and settings_get("misc.network.dns_exposure") != "ipv6": extra.append([f"*{suffix}", ttl, "A", ipv4]) if ipv6: From 28e4b458065d39dc086dae105fa8596b8c3f1b25 Mon Sep 17 00:00:00 2001 From: Tagadda <36127788+Tagadda@users.noreply.github.com> Date: Mon, 24 Oct 2022 22:00:30 +0000 Subject: [PATCH 09/67] oops again... --- src/diagnosers/14-ports.py | 4 ++-- src/diagnosers/21-web.py | 8 ++++---- src/diagnosers/24-mail.py | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/diagnosers/14-ports.py b/src/diagnosers/14-ports.py index 1e265f78e8..0cd54efbad 100644 --- a/src/diagnosers/14-ports.py +++ b/src/diagnosers/14-ports.py @@ -47,7 +47,7 @@ def run(self): ipversions = [] ipv4 = Diagnoser.get_cached_report("ip", item={"test": "ipv4"}) or {} - if ipv4.get("status") == "SUCCESS" or settings_get(misc.network.dns_exposure") != "ipv6": + if ipv4.get("status") == "SUCCESS" or settings_get("misc.network.dns_exposure") != "ipv6": ipversions.append(4) # To be discussed: we could also make this check dependent on the @@ -121,7 +121,7 @@ def ipv6_is_important(): for record in dnsrecords.get("items", []) ) - if failed == 4 and settings_get(misc.network.dns_exposure") != "ipv6" or ipv6_is_important(): + if failed == 4 and settings_get("misc.network.dns_exposure") != "ipv6" or ipv6_is_important(): yield dict( meta={"port": port}, data={ diff --git a/src/diagnosers/21-web.py b/src/diagnosers/21-web.py index 2024cf6ced..74e3ca4833 100644 --- a/src/diagnosers/21-web.py +++ b/src/diagnosers/21-web.py @@ -77,7 +77,7 @@ def run(self): ipversions = [] ipv4 = Diagnoser.get_cached_report("ip", item={"test": "ipv4"}) or {} - if ipv4.get("status") == "SUCCESS" and settings_get(misc.network.dns_exposure") != "ipv6": + if ipv4.get("status") == "SUCCESS" and settings_get("misc.network.dns_exposure") != "ipv6": ipversions.append(4) # To be discussed: we could also make this check dependent on the @@ -97,7 +97,7 @@ def run(self): # "curl --head the.global.ip" will simply timeout... if self.do_hairpinning_test: global_ipv4 = ipv4.get("data", {}).get("global", None) - if global_ipv4 and settings_get(misc.network.dns_exposure") != "ipv6": + if global_ipv4 and settings_get("misc.network.dns_exposure") != "ipv6": try: requests.head("http://" + global_ipv4, timeout=5) except requests.exceptions.Timeout: @@ -148,7 +148,7 @@ def test_http(self, domains, ipversions): if all( results[ipversion][domain]["status"] == "ok" for ipversion in ipversions ): - if 4 in ipversions and settings_get(misc.network.dns_exposure") != "ipv6": + if 4 in ipversions and settings_get("misc.network.dns_exposure") != "ipv6": self.do_hairpinning_test = True yield dict( meta={"domain": domain}, @@ -186,7 +186,7 @@ def ipv6_is_important_for_this_domain(): ) AAAA_status = dnsrecords.get("data", {}).get("AAAA:@") - return AAAA_status in ["OK", "WRONG"] or settings_get(misc.network.dns_exposure") != "ipv4" + return AAAA_status in ["OK", "WRONG"] or settings_get("misc.network.dns_exposure") != "ipv4" if failed == 4 or ipv6_is_important_for_this_domain(): yield dict( diff --git a/src/diagnosers/24-mail.py b/src/diagnosers/24-mail.py index 590b0d9ba7..283f806812 100644 --- a/src/diagnosers/24-mail.py +++ b/src/diagnosers/24-mail.py @@ -302,13 +302,13 @@ def get_ips_checked(self): outgoing_ipversions = [] outgoing_ips = [] ipv4 = Diagnoser.get_cached_report("ip", {"test": "ipv4"}) or {} - if ipv4.get("status") == "SUCCESS" and settings_get(misc.network.dns_exposure") != "ipv6": + if ipv4.get("status") == "SUCCESS" and settings_get("misc.network.dns_exposure") != "ipv6": outgoing_ipversions.append(4) global_ipv4 = ipv4.get("data", {}).get("global", {}) if global_ipv4: outgoing_ips.append(global_ipv4) - if settings_get("email.smtp.smtp_allow_ipv6") or settings_get(misc.network.dns_exposure") != "ipv4": + if settings_get("email.smtp.smtp_allow_ipv6") or settings_get("misc.network.dns_exposure") != "ipv4": ipv6 = Diagnoser.get_cached_report("ip", {"test": "ipv6"}) or {} if ipv6.get("status") == "SUCCESS": outgoing_ipversions.append(6) From 1a07839b5fa5d390fe76314d2f052d0416d28c13 Mon Sep 17 00:00:00 2001 From: Tagadda <36127788+Tagadda@users.noreply.github.com> Date: Mon, 24 Oct 2022 22:20:12 +0000 Subject: [PATCH 10/67] diagnosis --- locales/en.json | 1 + src/diagnosers/10-ip.py | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/locales/en.json b/locales/en.json index e655acb83a..789ec5a4b5 100644 --- a/locales/en.json +++ b/locales/en.json @@ -245,6 +245,7 @@ "diagnosis_ip_no_ipv4": "The server does not have working IPv4.", "diagnosis_ip_no_ipv6": "The server does not have working IPv6.", "diagnosis_ip_no_ipv6_tip": "Having a working IPv6 is not mandatory for your server to work, but it is better for the health of the Internet as a whole. IPv6 should usually be automatically configured by the system or your provider if it's available. Otherwise, you might need to configure a few things manually as explained in the documentation here: https://yunohost.org/#/ipv6. If you cannot enable IPv6 or if it seems too technical for you, you can also safely ignore this warning.", + "diagnosis_ip_no_ipv6_tip_important": "IPv6 should usually be automatically configured by the system or your provider if it's available. Otherwise, you might need to configure a few things manually as explained in the documentation here: https://yunohost.org/#/ipv6.", "diagnosis_ip_not_connected_at_all": "The server does not seem to be connected to the Internet at all!?", "diagnosis_ip_weird_resolvconf": "DNS resolution seems to be working, but it looks like you're using a custom /etc/resolv.conf.", "diagnosis_ip_weird_resolvconf_details": "The file /etc/resolv.conf should be a symlink to /etc/resolvconf/run/resolv.conf itself pointing to 127.0.0.1 (dnsmasq). If you want to manually configure DNS resolvers, please edit /etc/resolv.dnsmasq.conf.", diff --git a/src/diagnosers/10-ip.py b/src/diagnosers/10-ip.py index 954b9b4e84..1d28be1430 100644 --- a/src/diagnosers/10-ip.py +++ b/src/diagnosers/10-ip.py @@ -119,10 +119,13 @@ def get_local_ip(version): else: return local_ip + def is_ipvx_important(x): + return settings_get("misc.network.dns_exposure") == "both" or "ipv"+str(x) + yield dict( meta={"test": "ipv4"}, data={"global": ipv4, "local": get_local_ip("ipv4")}, - status="SUCCESS" if ipv4 else "ERROR" if settings_get("misc.network.dns_exposure") == "ipv4" else "WARNING", + status="SUCCESS" if ipv4 else "ERROR" if is_ipvx_important(4) else "WARNING", summary="diagnosis_ip_connected_ipv4" if ipv4 else "diagnosis_ip_no_ipv4", details=["diagnosis_ip_global", "diagnosis_ip_local"] if ipv4 else None, ) @@ -130,11 +133,11 @@ def get_local_ip(version): yield dict( meta={"test": "ipv6"}, data={"global": ipv6, "local": get_local_ip("ipv6")}, - status="SUCCESS" if ipv6 else "ERROR" if settings_get("misc.network.dns_exposure") == "ipv6" else "WARNING", + status="SUCCESS" if ipv6 else "ERROR" if is_ipvx_important(6) else "WARNING", summary="diagnosis_ip_connected_ipv6" if ipv6 else "diagnosis_ip_no_ipv6", details=["diagnosis_ip_global", "diagnosis_ip_local"] if ipv6 - else ["diagnosis_ip_no_ipv6_tip"], + else ["diagnosis_ip_no_ipv6_tip_important" if is_ipvx_important(6) else "diagnosis_ip_no_ipv6_tip"], ) # TODO / FIXME : add some attempt to detect ISP (using whois ?) ? From e82849492baa6dff14cba2e34ee88d3a4fa9a4e9 Mon Sep 17 00:00:00 2001 From: Tagadda <36127788+Tagadda@users.noreply.github.com> Date: Mon, 24 Oct 2022 22:25:09 +0000 Subject: [PATCH 11/67] zblerg --- src/diagnosers/10-ip.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/diagnosers/10-ip.py b/src/diagnosers/10-ip.py index 1d28be1430..6b35731a05 100644 --- a/src/diagnosers/10-ip.py +++ b/src/diagnosers/10-ip.py @@ -120,7 +120,7 @@ def get_local_ip(version): return local_ip def is_ipvx_important(x): - return settings_get("misc.network.dns_exposure") == "both" or "ipv"+str(x) + return settings_get("misc.network.dns_exposure") in ["both", "ipv"+str(x)] yield dict( meta={"test": "ipv4"}, From 36b0f5899329a39e6e75204e91e08d26aa22be99 Mon Sep 17 00:00:00 2001 From: Kay0u Date: Thu, 19 Jan 2023 11:15:02 +0100 Subject: [PATCH 12/67] rewrite list_shells --- src/user.py | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/user.py b/src/user.py index 61060a9ef6..b3a2a22e6e 100644 --- a/src/user.py +++ b/src/user.py @@ -122,21 +122,17 @@ def display_default(values, _): return {"users": users} + def list_shells(): - import ctypes - import ctypes.util - - """List the shells from /etc/shells.""" - libc = ctypes.CDLL(ctypes.util.find_library("c")) - getusershell = libc.getusershell - getusershell.restype = ctypes.c_char_p - libc.setusershell() - while True: - shell = getusershell() - if not shell: - break - yield shell.decode() - libc.endusershell() + with open("/etc/shells", "r") as f: + content = f.readlines() + + shells = [] + for line in content: + if line.startswith("/"): + shells.append(line.replace("\n","")) + return shells + def shellexists(shell): From 13be9af65f6e76ab00be1c6096093e8ce61d2aa7 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 19 Jan 2023 16:24:50 +0100 Subject: [PATCH 13/67] Simplify code --- src/user.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/user.py b/src/user.py index b3a2a22e6e..05dce8f24f 100644 --- a/src/user.py +++ b/src/user.py @@ -127,12 +127,7 @@ def list_shells(): with open("/etc/shells", "r") as f: content = f.readlines() - shells = [] - for line in content: - if line.startswith("/"): - shells.append(line.replace("\n","")) - return shells - + return [line.strip() for line in content if line.startswith("/")] def shellexists(shell): From 95f98a9c68aad0d125ede8c3cfb80c2b85c0d266 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 19 Jan 2023 16:45:21 +0100 Subject: [PATCH 14/67] ipexposuresetting: replace confusing negations with explicit 'in' --- src/diagnosers/21-web.py | 8 ++++---- src/diagnosers/24-mail.py | 4 ++-- src/dns.py | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/diagnosers/21-web.py b/src/diagnosers/21-web.py index 74e3ca4833..25554fe9da 100644 --- a/src/diagnosers/21-web.py +++ b/src/diagnosers/21-web.py @@ -77,7 +77,7 @@ def run(self): ipversions = [] ipv4 = Diagnoser.get_cached_report("ip", item={"test": "ipv4"}) or {} - if ipv4.get("status") == "SUCCESS" and settings_get("misc.network.dns_exposure") != "ipv6": + if ipv4.get("status") == "SUCCESS" and settings_get("misc.network.dns_exposure") in ["both", "ipv4"]: ipversions.append(4) # To be discussed: we could also make this check dependent on the @@ -97,7 +97,7 @@ def run(self): # "curl --head the.global.ip" will simply timeout... if self.do_hairpinning_test: global_ipv4 = ipv4.get("data", {}).get("global", None) - if global_ipv4 and settings_get("misc.network.dns_exposure") != "ipv6": + if global_ipv4 and settings_get("misc.network.dns_exposure") in ["both", "ipv4"]: try: requests.head("http://" + global_ipv4, timeout=5) except requests.exceptions.Timeout: @@ -148,7 +148,7 @@ def test_http(self, domains, ipversions): if all( results[ipversion][domain]["status"] == "ok" for ipversion in ipversions ): - if 4 in ipversions and settings_get("misc.network.dns_exposure") != "ipv6": + if 4 in ipversions and settings_get("misc.network.dns_exposure") in ["both", "ipv4"]: self.do_hairpinning_test = True yield dict( meta={"domain": domain}, @@ -186,7 +186,7 @@ def ipv6_is_important_for_this_domain(): ) AAAA_status = dnsrecords.get("data", {}).get("AAAA:@") - return AAAA_status in ["OK", "WRONG"] or settings_get("misc.network.dns_exposure") != "ipv4" + return AAAA_status in ["OK", "WRONG"] or settings_get("misc.network.dns_exposure") in ["both", "ipv6"] if failed == 4 or ipv6_is_important_for_this_domain(): yield dict( diff --git a/src/diagnosers/24-mail.py b/src/diagnosers/24-mail.py index 283f806812..1ae1da8854 100644 --- a/src/diagnosers/24-mail.py +++ b/src/diagnosers/24-mail.py @@ -302,13 +302,13 @@ def get_ips_checked(self): outgoing_ipversions = [] outgoing_ips = [] ipv4 = Diagnoser.get_cached_report("ip", {"test": "ipv4"}) or {} - if ipv4.get("status") == "SUCCESS" and settings_get("misc.network.dns_exposure") != "ipv6": + if ipv4.get("status") == "SUCCESS" and settings_get("misc.network.dns_exposure") in ["both", "ipv4"]: outgoing_ipversions.append(4) global_ipv4 = ipv4.get("data", {}).get("global", {}) if global_ipv4: outgoing_ips.append(global_ipv4) - if settings_get("email.smtp.smtp_allow_ipv6") or settings_get("misc.network.dns_exposure") != "ipv4": + if settings_get("email.smtp.smtp_allow_ipv6") or settings_get("misc.network.dns_exposure") in ["both", "ipv6"]: ipv6 = Diagnoser.get_cached_report("ip", {"test": "ipv6"}) or {} if ipv6.get("status") == "SUCCESS": outgoing_ipversions.append(6) diff --git a/src/dns.py b/src/dns.py index 9d81391e53..d56e8e625d 100644 --- a/src/dns.py +++ b/src/dns.py @@ -186,7 +186,7 @@ def _build_dns_conf(base_domain, include_empty_AAAA_if_no_ipv6=False): ########################### # Basic ipv4/ipv6 records # ########################### - if ipv4 and settings_get("misc.network.dns_exposure") != "ipv6": + if ipv4 and settings_get("misc.network.dns_exposure") in ["both", "ipv4"]: basic.append([basename, ttl, "A", ipv4]) if ipv6: @@ -241,7 +241,7 @@ def _build_dns_conf(base_domain, include_empty_AAAA_if_no_ipv6=False): # Only recommend wildcard and CAA for the top level if domain == base_domain: - if ipv4 and settings_get("misc.network.dns_exposure") != "ipv6": + if ipv4 and settings_get("misc.network.dns_exposure") in ["both", "ipv4"]: extra.append([f"*{suffix}", ttl, "A", ipv4]) if ipv6: From b41d623ed4f595be6eb16ceb14de887dfa1dab62 Mon Sep 17 00:00:00 2001 From: yunohost-bot Date: Thu, 19 Jan 2023 15:53:22 +0000 Subject: [PATCH 15/67] [CI] Reformat / remove stale translated strings --- locales/de.json | 1 - locales/en.json | 3 +-- locales/es.json | 1 - locales/eu.json | 1 - locales/fr.json | 1 - locales/gl.json | 1 - locales/it.json | 1 - locales/pt.json | 1 - locales/ru.json | 1 - locales/sk.json | 1 - locales/uk.json | 1 - locales/zh_Hans.json | 1 - 12 files changed, 1 insertion(+), 13 deletions(-) diff --git a/locales/de.json b/locales/de.json index e09214f04d..c666a79047 100644 --- a/locales/de.json +++ b/locales/de.json @@ -565,7 +565,6 @@ "diagnosis_apps_issue": "Ein Problem für die App {app} ist aufgetreten", "config_validate_time": "Sollte eine zulässige Zeit wie HH:MM sein", "config_validate_url": "Sollte eine zulässige web URL sein", - "config_version_not_supported": "Konfigurationspanel Versionen '{version}' sind nicht unterstützt.", "diagnosis_apps_allgood": "Alle installierten Apps berücksichtigen die grundlegenden Paketierungspraktiken", "diagnosis_apps_broken": "Diese App ist im YunoHost-Applikationskatalog momentan als defekt gekennzeichnet. Es könnte sich dabei um einen vorübergehendes Problem handeln. Während der/die Betreuer:in versucht das Problem zu beheben, ist die Upgrade-Funktion für diese App gesperrt.", "diagnosis_apps_not_in_app_catalog": "Diese Applikation steht nicht im Applikationskatalog von YunoHost. Sie sollten in Betracht ziehen, sie zu deinstallieren, weil sie keine Aktualisierungen mehr erhält und die Integrität und die Sicherheit Ihres Systems kompromittieren könnte.", diff --git a/locales/en.json b/locales/en.json index e36f137368..0eca7b9bcb 100644 --- a/locales/en.json +++ b/locales/en.json @@ -27,7 +27,6 @@ "app_full_domain_unavailable": "Sorry, this app must be installed on a domain of its own, but other apps are already installed on the domain '{domain}'. You could use a subdomain dedicated to this app instead.", "app_id_invalid": "Invalid app ID", "app_install_failed": "Unable to install {app}: {error}", - "app_resource_failed": "Provisioning, deprovisioning, or updating resources for {app} failed: {error}", "app_install_files_invalid": "These files cannot be installed", "app_install_script_failed": "An error occurred inside the app installation script", "app_label_deprecated": "This command is deprecated! Please use the new command 'yunohost user permission update' to manage the app label.", @@ -50,6 +49,7 @@ "app_remove_after_failed_install": "Removing the app after installation failure...", "app_removed": "{app} uninstalled", "app_requirements_checking": "Checking requirements for {app}...", + "app_resource_failed": "Provisioning, deprovisioning, or updating resources for {app} failed: {error}", "app_restore_failed": "Could not restore {app}: {error}", "app_restore_script_failed": "An error occured inside the app restore script", "app_sources_fetch_failed": "Could not fetch source files, is the URL correct?", @@ -408,7 +408,6 @@ "global_settings_setting_nginx_redirect_to_https": "Force HTTPS", "global_settings_setting_nginx_redirect_to_https_help": "Redirect HTTP requests to HTTPs by default (DO NOT TURN OFF unless you really know what you're doing!)", "global_settings_setting_passwordless_sudo": "Allow admins to use 'sudo' without re-typing their passwords", - "global_settings_setting_passwordless_sudo_help": "FIXME", "global_settings_setting_pop3_enabled": "Enable POP3", "global_settings_setting_pop3_enabled_help": "Enable the POP3 protocol for the mail server", "global_settings_setting_portal_theme": "Portal theme", diff --git a/locales/es.json b/locales/es.json index ae2eb39fe7..9a92908a46 100644 --- a/locales/es.json +++ b/locales/es.json @@ -552,7 +552,6 @@ "config_validate_email": "Debe ser una dirección de correo correcta", "config_validate_time": "Debe ser una hora valida en formato HH:MM", "config_validate_url": "Debe ser una URL válida", - "config_version_not_supported": "Las versiones del panel de configuración '{version}' no están soportadas.", "domain_remove_confirm_apps_removal": "La supresión de este dominio también eliminará las siguientes aplicaciones:\n{apps}\n\n¿Seguro? [{answers}]", "domain_registrar_is_not_configured": "El registrador aún no ha configurado el dominio {domain}.", "diagnosis_apps_not_in_app_catalog": "Esta aplicación se encuentra ausente o ya no figura en el catálogo de aplicaciones de YunoHost. Deberías considerar desinstalarla ya que no recibirá actualizaciones y podría comprometer la integridad y seguridad de tu sistema.", diff --git a/locales/eu.json b/locales/eu.json index f53da2b346..4d212bf58f 100644 --- a/locales/eu.json +++ b/locales/eu.json @@ -49,7 +49,6 @@ "config_validate_email": "Benetazko posta elektronikoa izan behar da", "config_validate_time": "OO:MM formatua duen ordu bat izan behar da", "config_validate_url": "Benetazko URL bat izan behar da", - "config_version_not_supported": "Ezinezkoa da konfigurazio-panelaren '{version}' bertsioa erabiltzea.", "app_restore_script_failed": "Errorea gertatu da aplikazioa lehengoratzeko aginduan", "app_upgrade_some_app_failed": "Ezinezkoa izan da aplikazio batzuk eguneratzea", "app_install_failed": "Ezinezkoa izan da {app} instalatzea: {error}", diff --git a/locales/fr.json b/locales/fr.json index 33949f1fdb..9c5b9a9e35 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -590,7 +590,6 @@ "config_validate_email": "Doit être un email valide", "config_validate_time": "Doit être une heure valide comme HH:MM", "config_validate_url": "Doit être une URL Web valide", - "config_version_not_supported": "Les versions du panneau de configuration '{version}' ne sont pas prises en charge.", "danger": "Danger :", "invalid_number_min": "Doit être supérieur à {min}", "invalid_number_max": "Doit être inférieur à {max}", diff --git a/locales/gl.json b/locales/gl.json index 35419bcf42..a4f9d97728 100644 --- a/locales/gl.json +++ b/locales/gl.json @@ -590,7 +590,6 @@ "log_app_config_set": "Aplicar a configuración á app '{}'", "app_config_unable_to_apply": "Fallou a aplicación dos valores de configuración.", "config_cant_set_value_on_section": "Non podes establecer un valor único na sección completa de configuración.", - "config_version_not_supported": "A versión do panel de configuración '{version}' non está soportada.", "invalid_number_max": "Ten que ser menor de {max}", "service_not_reloading_because_conf_broken": "Non se recargou/reiniciou o servizo '{name}' porque a súa configuración está estragada: {errors}", "diagnosis_http_special_use_tld": "O dominio {domain} baséase nun dominio de alto-nivel (TLD) especial como .local ou .test e por isto non é de agardar que esté exposto fóra da rede local.", diff --git a/locales/it.json b/locales/it.json index bc65612f0e..e94a43a6d7 100644 --- a/locales/it.json +++ b/locales/it.json @@ -618,7 +618,6 @@ "domain_config_auth_consumer_key": "Chiave consumatore", "ldap_attribute_already_exists": "L’attributo LDAP '{attribute}' esiste già con il valore '{value}'", "config_validate_time": "È necessario inserire un orario valido, come HH:MM", - "config_version_not_supported": "Le versioni '{version}' del pannello di configurazione non sono supportate.", "danger": "Attenzione:", "log_domain_config_set": "Aggiorna la configurazione per il dominio '{}'", "domain_dns_push_managed_in_parent_domain": "La configurazione automatica del DNS è gestita nel dominio genitore {parent_domain}.", diff --git a/locales/pt.json b/locales/pt.json index 1df30f8e5b..0aa6b82233 100644 --- a/locales/pt.json +++ b/locales/pt.json @@ -204,7 +204,6 @@ "config_cant_set_value_on_section": "Você não pode setar um único valor na seção de configuração inteira.", "config_validate_time": "Deve ser um horário válido como HH:MM", "config_validate_url": "Deve ser uma URL válida", - "config_version_not_supported": "Versões do painel de configuração '{version}' não são suportadas.", "danger": "Perigo:", "diagnosis_basesystem_ynh_inconsistent_versions": "Você está executando versões inconsistentes dos pacotes YunoHost... provavelmente por causa de uma atualização parcial ou que falhou.", "diagnosis_description_basesystem": "Sistema base", diff --git a/locales/ru.json b/locales/ru.json index 40e7629e35..2c4e703da8 100644 --- a/locales/ru.json +++ b/locales/ru.json @@ -106,7 +106,6 @@ "certmanager_domain_dns_ip_differs_from_public_ip": "DNS-записи для домена '{domain}' отличаются от IP этого сервера. Пожалуйста, проверьте категорию 'DNS-записи' (основные) в диагностике для получения дополнительной информации. Если вы недавно изменили свою A-запись, пожалуйста, подождите, пока она распространится (некоторые программы проверки распространения DNS доступны в интернете). (Если вы знаете, что делаете, используйте '--no-checks', чтобы отключить эти проверки.)", "certmanager_domain_not_diagnosed_yet": "Для домена {domain} еще нет результатов диагностики. Пожалуйста, перезапустите диагностику для категорий 'DNS-записи' и 'Домены', чтобы проверить, готов ли домен к Let's Encrypt. (Или, если вы знаете, что делаете, используйте '--no-checks', чтобы отключить эти проверки.)", "config_validate_url": "Должна быть правильная ссылка", - "config_version_not_supported": "Версии конфигурационной панели '{version}' не поддерживаются.", "confirm_app_install_danger": "ОПАСНО! Это приложение все еще является экспериментальным (если не сказать, что оно явно не работает)! Вам НЕ следует устанавливать его, если вы НЕ знаете, что делаете. Если это приложение не будет работать или сломает вашу систему, мы НЕ будем оказывать техническую поддержку... Если вы все равно готовы рискнуть, введите '{answers}'", "confirm_app_install_thirdparty": "ВАЖНО! Это приложение не входит в каталог приложений YunoHost. Установка сторонних приложений может нарушить целостность и безопасность вашей системы. Вам НЕ следует устанавливать его, если вы НЕ знаете, что делаете. Если это приложение не будет работать или сломает вашу систему, мы НЕ будем оказывать техническую поддержку... Если вы все равно готовы рискнуть, введите '{answers}'", "config_apply_failed": "Не удалось применить новую конфигурацию: {error}", diff --git a/locales/sk.json b/locales/sk.json index 544fb6c0e3..359b2e5625 100644 --- a/locales/sk.json +++ b/locales/sk.json @@ -144,7 +144,6 @@ "config_validate_email": "Toto by mal byť platný e-mail", "config_validate_time": "Toto by mal byť platný čas vo formáte HH:MM", "config_validate_url": "Toto by mala byť platná URL adresa webu", - "config_version_not_supported": "Verzie konfiguračného panela '{version}' nie sú podporované.", "danger": "Nebezpečenstvo:", "confirm_app_install_danger": "NEBEZPEČENSTVO! Táto aplikácia je experimentálna (ak vôbec funguje)! Pravdepodobne by ste ju NEMALI inštalovať, pokiaľ si nie ste istý, čo robíte. NEPOSKYTNEME VÁM ŽIADNU POMOC, ak táto aplikácia nebude fungovať alebo rozbije Váš systém… Ak sa rozhodnete i napriek tomu podstúpiť toto riziko, zadajte '{answers}'", "confirm_app_install_thirdparty": "NEBEZPEČENSTVO! Táto aplikácia nie je súčasťou katalógu aplikácií YunoHost. Inštalovaním aplikácií tretích strán môžete ohroziť integritu a bezpečnosť Vášho systému. Pravdepodobne by ste NEMALI pokračovať v inštalácií, pokiaľ neviete, čo robíte. NEPOSKYTNEME VÁM ŽIADNU POMOC, ak táto aplikácia nebude fungovať alebo rozbije Váš systém… Ak sa rozhodnete i napriek tomu podstúpiť toto riziko, zadajte '{answers}'", diff --git a/locales/uk.json b/locales/uk.json index 02304a39c3..3c960e9fa5 100644 --- a/locales/uk.json +++ b/locales/uk.json @@ -587,7 +587,6 @@ "config_validate_email": "Е-пошта має бути дійсною", "config_validate_time": "Час має бути дійсним, наприклад ГГ:ХХ", "config_validate_url": "Вебадреса має бути дійсною", - "config_version_not_supported": "Версії конфігураційної панелі '{version}' не підтримуються.", "danger": "Небезпека:", "invalid_number_min": "Має бути більшим за {min}", "invalid_number_max": "Має бути меншим за {max}", diff --git a/locales/zh_Hans.json b/locales/zh_Hans.json index 59ceaf36f3..687064de6d 100644 --- a/locales/zh_Hans.json +++ b/locales/zh_Hans.json @@ -571,7 +571,6 @@ "config_validate_email": "是有效的电子邮件", "config_validate_time": "应该是像 HH:MM 这样的有效时间", "config_validate_url": "应该是有效的URL", - "config_version_not_supported": "不支持配置面板版本“{ version }”。", "danger": "警告:", "diagnosis_apps_allgood": "所有已安装的应用程序都遵守基本的打包原则", "diagnosis_apps_deprecated_practices": "此应用程序的安装 版本仍然使用一些超旧的弃用打包原则。推荐您升级它。", From be5b1c1b69c2674cb1d0c2e335452140a1c09dca Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 19 Jan 2023 16:49:48 +0100 Subject: [PATCH 16/67] debian: refresh catalog upon package upgrade --- debian/postinst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/debian/postinst b/debian/postinst index c9ad3d5620..3533174886 100644 --- a/debian/postinst +++ b/debian/postinst @@ -28,6 +28,9 @@ do_configure() { echo "Re-diagnosing server health..." yunohost diagnosis run --force + + echo "Refreshing app catalog..." + yunohost tools update apps || true fi # Trick to let yunohost handle the restart of the API, From 71be74ffe27723fce60b1062e3fac420a1d69d86 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 19 Jan 2023 17:01:16 +0100 Subject: [PATCH 17/67] ci: Attempt to fix the CI, gitlab-ci had some changes related to artefacts paths --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4d0f30679a..bb50f1c7ad 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -37,7 +37,7 @@ workflow: - when: always variables: - YNH_BUILD_DIR: "ynh-build" + YNH_BUILD_DIR: "./ynh-build" include: - template: Code-Quality.gitlab-ci.yml From 7addad59f0638e670e793e87e35077a373c8922a Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 19 Jan 2023 17:11:18 +0100 Subject: [PATCH 18/67] ci: friskies? --- .gitlab/ci/build.gitlab-ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitlab/ci/build.gitlab-ci.yml b/.gitlab/ci/build.gitlab-ci.yml index db691b9d2a..c603e95fba 100644 --- a/.gitlab/ci/build.gitlab-ci.yml +++ b/.gitlab/ci/build.gitlab-ci.yml @@ -31,7 +31,7 @@ build-yunohost: - mkdir -p $YNH_BUILD_DIR/$PACKAGE - cat archive.tar.gz | tar -xz -C $YNH_BUILD_DIR/$PACKAGE - rm archive.tar.gz - - DEBIAN_FRONTEND=noninteractive apt --assume-yes -o Dpkg::Options::="--force-confold" build-dep $(pwd)/$YNH_BUILD_DIR/$PACKAGE + - DEBIAN_FRONTEND=noninteractive apt --assume-yes -o Dpkg::Options::="--force-confold" build-dep $YNH_BUILD_DIR/$PACKAGE - *build_script @@ -42,7 +42,7 @@ build-ssowat: script: - DEBIAN_DEPENDS=$(cat debian/control | tr "," "\n" | grep -Po "ssowat \([>,=,<]+ .*\)" | grep -Po "[0-9\.]+") - git clone $YNH_SOURCE/$PACKAGE -b $CI_COMMIT_REF_NAME $YNH_BUILD_DIR/$PACKAGE --depth 1 || git clone $YNH_SOURCE/$PACKAGE -b $DEBIAN_DEPENDS $YNH_BUILD_DIR/$PACKAGE --depth 1 || git clone $YNH_SOURCE/$PACKAGE $YNH_BUILD_DIR/$PACKAGE --depth 1 - - DEBIAN_FRONTEND=noninteractive apt --assume-yes -o Dpkg::Options::="--force-confold" build-dep $(pwd)/$YNH_BUILD_DIR/$PACKAGE + - DEBIAN_FRONTEND=noninteractive apt --assume-yes -o Dpkg::Options::="--force-confold" build-dep $YNH_BUILD_DIR/$PACKAGE - *build_script build-moulinette: @@ -52,5 +52,5 @@ build-moulinette: script: - DEBIAN_DEPENDS=$(cat debian/control | tr "," "\n" | grep -Po "moulinette \([>,=,<]+ .*\)" | grep -Po "[0-9\.]+") - git clone $YNH_SOURCE/$PACKAGE -b $CI_COMMIT_REF_NAME $YNH_BUILD_DIR/$PACKAGE --depth 1 || git clone $YNH_SOURCE/$PACKAGE -b $DEBIAN_DEPENDS $YNH_BUILD_DIR/$PACKAGE --depth 1 || git clone $YNH_SOURCE/$PACKAGE $YNH_BUILD_DIR/$PACKAGE --depth 1 - - DEBIAN_FRONTEND=noninteractive apt --assume-yes -o Dpkg::Options::="--force-confold" build-dep $(pwd)/$YNH_BUILD_DIR/$PACKAGE + - DEBIAN_FRONTEND=noninteractive apt --assume-yes -o Dpkg::Options::="--force-confold" build-dep $YNH_BUILD_DIR/$PACKAGE - *build_script From 312ded8873b10969660c4b91b9308d0e1cde8617 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 19 Jan 2023 17:35:47 +0100 Subject: [PATCH 19/67] =?UTF-8?q?ci:=20friskies=3F=C2=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index bb50f1c7ad..0ec685143d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -37,7 +37,7 @@ workflow: - when: always variables: - YNH_BUILD_DIR: "./ynh-build" + YNH_BUILD_DIR: "$CI_PROJECT_DIR/ynh-build" include: - template: Code-Quality.gitlab-ci.yml From a65833647652119c7d6b6e76077da414876de9fe Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 19 Jan 2023 17:54:13 +0100 Subject: [PATCH 20/67] ci: add some boring debugging to have a clear view of where the .deb are -_-' --- .gitlab/ci/build.gitlab-ci.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitlab/ci/build.gitlab-ci.yml b/.gitlab/ci/build.gitlab-ci.yml index c603e95fba..855d94692a 100644 --- a/.gitlab/ci/build.gitlab-ci.yml +++ b/.gitlab/ci/build.gitlab-ci.yml @@ -17,6 +17,11 @@ - VERSION_NIGHTLY="${VERSION}+$(date +%Y%m%d%H%M)" - dch --package "${PACKAGE}" --force-bad-version -v "${VERSION_NIGHTLY}" -D "unstable" --force-distribution "Daily build." - debuild --no-lintian -us -uc + - ls -l + - ls -l ../ + - ls -l $YNH_BUILD_DIR + - ls -l $YNH_BUILD_DIR/$PACKAGE/ + - ls -l $YNH_BUILD_DIR/*.deb ######################################## # BUILD DEB From bf07cd6c47140e1ac79d3b83ba84eb7aa43c9cc2 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 19 Jan 2023 18:14:46 +0100 Subject: [PATCH 21/67] =?UTF-8?q?ci:=20friskies=3F=C2=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitlab/ci/build.gitlab-ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitlab/ci/build.gitlab-ci.yml b/.gitlab/ci/build.gitlab-ci.yml index 855d94692a..4faa23814c 100644 --- a/.gitlab/ci/build.gitlab-ci.yml +++ b/.gitlab/ci/build.gitlab-ci.yml @@ -8,7 +8,7 @@ - DEBIAN_FRONTEND=noninteractive apt update artifacts: paths: - - $YNH_BUILD_DIR/*.deb + - ./*.deb .build_script: &build_script - DEBIAN_FRONTEND=noninteractive apt --assume-yes -o Dpkg::Options::="--force-confold" install devscripts --no-install-recommends @@ -22,6 +22,7 @@ - ls -l $YNH_BUILD_DIR - ls -l $YNH_BUILD_DIR/$PACKAGE/ - ls -l $YNH_BUILD_DIR/*.deb + - cd $YNH_BUILD_DIR/ ######################################## # BUILD DEB From ece8d65601dc9e2889993d7d9f88b26075834472 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 19 Jan 2023 18:27:34 +0100 Subject: [PATCH 22/67] =?UTF-8?q?ci:=20friskies=3F=E2=81=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0ec685143d..f8d2fcd97a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -37,7 +37,7 @@ workflow: - when: always variables: - YNH_BUILD_DIR: "$CI_PROJECT_DIR/ynh-build" + YNH_BUILD_DIR: "$PWD/ynh-build" include: - template: Code-Quality.gitlab-ci.yml From a568c7eecd338fa3ff09533cd85013ac2ef949e7 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 19 Jan 2023 18:36:38 +0100 Subject: [PATCH 23/67] =?UTF-8?q?ci:=20friskies=3F=E2=81=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitlab/ci/build.gitlab-ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitlab/ci/build.gitlab-ci.yml b/.gitlab/ci/build.gitlab-ci.yml index 4faa23814c..26324cb3d2 100644 --- a/.gitlab/ci/build.gitlab-ci.yml +++ b/.gitlab/ci/build.gitlab-ci.yml @@ -22,7 +22,8 @@ - ls -l $YNH_BUILD_DIR - ls -l $YNH_BUILD_DIR/$PACKAGE/ - ls -l $YNH_BUILD_DIR/*.deb - - cd $YNH_BUILD_DIR/ + - cp ./*.deb ${CI_PROJECT_DIR}/ + - cd ${CI_PROJECT_DIR} ######################################## # BUILD DEB From 27305fe3fca38d798b8c19bb0ef7e125f0658b4f Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 19 Jan 2023 18:48:44 +0100 Subject: [PATCH 24/67] =?UTF-8?q?ci:=20friskies=3F=E2=81=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitlab-ci.yml | 2 +- .gitlab/ci/build.gitlab-ci.yml | 7 +------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f8d2fcd97a..11d920bd0b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -37,7 +37,7 @@ workflow: - when: always variables: - YNH_BUILD_DIR: "$PWD/ynh-build" + YNH_BUILD_DIR: "/ynh-build" include: - template: Code-Quality.gitlab-ci.yml diff --git a/.gitlab/ci/build.gitlab-ci.yml b/.gitlab/ci/build.gitlab-ci.yml index 26324cb3d2..610580dacd 100644 --- a/.gitlab/ci/build.gitlab-ci.yml +++ b/.gitlab/ci/build.gitlab-ci.yml @@ -17,12 +17,7 @@ - VERSION_NIGHTLY="${VERSION}+$(date +%Y%m%d%H%M)" - dch --package "${PACKAGE}" --force-bad-version -v "${VERSION_NIGHTLY}" -D "unstable" --force-distribution "Daily build." - debuild --no-lintian -us -uc - - ls -l - - ls -l ../ - - ls -l $YNH_BUILD_DIR - - ls -l $YNH_BUILD_DIR/$PACKAGE/ - - ls -l $YNH_BUILD_DIR/*.deb - - cp ./*.deb ${CI_PROJECT_DIR}/ + - cp $YNH_BUILD_DIR/*.deb ${CI_PROJECT_DIR}/ - cd ${CI_PROJECT_DIR} ######################################## From a5de20d757498c34f1558e3b5edfc0b4fa4830a6 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 19 Jan 2023 19:06:44 +0100 Subject: [PATCH 25/67] =?UTF-8?q?ci:=20friskies=3F=E2=81=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitlab/ci/install.gitlab-ci.yml | 4 ++-- .gitlab/ci/test.gitlab-ci.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitlab/ci/install.gitlab-ci.yml b/.gitlab/ci/install.gitlab-ci.yml index ecdfecfcdc..65409c6ebb 100644 --- a/.gitlab/ci/install.gitlab-ci.yml +++ b/.gitlab/ci/install.gitlab-ci.yml @@ -17,7 +17,7 @@ upgrade: image: "after-install" script: - apt-get update -o Acquire::Retries=3 - - DEBIAN_FRONTEND=noninteractive SUDO_FORCE_REMOVE=yes apt --assume-yes -o Dpkg::Options::="--force-confold" --allow-downgrades install ./$YNH_BUILD_DIR/*.deb + - DEBIAN_FRONTEND=noninteractive SUDO_FORCE_REMOVE=yes apt --assume-yes -o Dpkg::Options::="--force-confold" --allow-downgrades install ${CI_PROJECT_DIR}/*.deb install-postinstall: @@ -25,5 +25,5 @@ install-postinstall: image: "before-install" script: - apt-get update -o Acquire::Retries=3 - - DEBIAN_FRONTEND=noninteractive SUDO_FORCE_REMOVE=yes apt --assume-yes -o Dpkg::Options::="--force-confold" --allow-downgrades install ./$YNH_BUILD_DIR/*.deb + - DEBIAN_FRONTEND=noninteractive SUDO_FORCE_REMOVE=yes apt --assume-yes -o Dpkg::Options::="--force-confold" --allow-downgrades install ${CI_PROJECT_DIR}/*.deb - yunohost tools postinstall -d domain.tld -u syssa -F 'Syssa Mine' -p the_password --ignore-dyndns --force-diskspace diff --git a/.gitlab/ci/test.gitlab-ci.yml b/.gitlab/ci/test.gitlab-ci.yml index 804940aa2b..37edbda043 100644 --- a/.gitlab/ci/test.gitlab-ci.yml +++ b/.gitlab/ci/test.gitlab-ci.yml @@ -1,6 +1,6 @@ .install_debs: &install_debs - apt-get update -o Acquire::Retries=3 - - DEBIAN_FRONTEND=noninteractive SUDO_FORCE_REMOVE=yes apt --assume-yes -o Dpkg::Options::="--force-confold" --allow-downgrades install ./$YNH_BUILD_DIR/*.deb + - DEBIAN_FRONTEND=noninteractive SUDO_FORCE_REMOVE=yes apt --assume-yes -o Dpkg::Options::="--force-confold" --allow-downgrades install ${CI_PROJECT_DIR}/*.deb - pip3 install -U mock pip pytest pytest-cov pytest-mock pytest-sugar requests-mock tox ansi2html black jinja2 "packaging<22" .test-stage: From 5a412ce93c2f39aa959a4df9de87d8a24c713168 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 19 Jan 2023 23:09:50 +0100 Subject: [PATCH 26/67] Update changelog for 11.1.3 --- debian/changelog | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/debian/changelog b/debian/changelog index 536d1bdbf8..10172fa9b7 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,13 @@ +yunohost (11.1.3) testing; urgency=low + + - helpers: Include procedures in MySQL database backup ([#1570](https://github.com/yunohost/yunohost/pull/1570)) + - users: be able to change the loginShell of a user ([#1538](https://github.com/yunohost/yunohost/pull/1538)) + - debian: refresh catalog upon package upgrade (be5b1c1b) + + Thanks to all contributors <3 ! (Éric Gaspar, Kay0u, ljf, Metin Bektas) + + -- Alexandre Aubin Thu, 19 Jan 2023 23:08:10 +0100 + yunohost (11.1.2.2) testing; urgency=low - Minor technical fixes (b37d4baf, 68342171) From e00d60b0492ddea17e3be384ee30b3dcc96627f5 Mon Sep 17 00:00:00 2001 From: Tagada <36127788+Tagadda@users.noreply.github.com> Date: Sat, 21 Jan 2023 13:40:04 +0100 Subject: [PATCH 27/67] Apply suggestions from code review Co-authored-by: Alexandre Aubin --- src/diagnosers/14-ports.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/diagnosers/14-ports.py b/src/diagnosers/14-ports.py index 0cd54efbad..57fb7cd98f 100644 --- a/src/diagnosers/14-ports.py +++ b/src/diagnosers/14-ports.py @@ -121,7 +121,7 @@ def ipv6_is_important(): for record in dnsrecords.get("items", []) ) - if failed == 4 and settings_get("misc.network.dns_exposure") != "ipv6" or ipv6_is_important(): + if (failed == 4 and settings_get("misc.network.dns_exposure") in ["both", "ipv4"]) or (failed == 6 and ipv6_is_important()): yield dict( meta={"port": port}, data={ From c444dee4fe7e4b1c273ec831b60c4a3b89becae9 Mon Sep 17 00:00:00 2001 From: Kayou Date: Mon, 23 Jan 2023 15:18:44 +0100 Subject: [PATCH 28/67] add xmpp-upload. and muc. server_name only if xmpp_enabled is enabled --- conf/nginx/server.tpl.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/nginx/server.tpl.conf b/conf/nginx/server.tpl.conf index 40f85b328e..d3ff777146 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 }}{% if xmpp_enabled != "True" %} xmpp-upload.{{ domain }} muc.{{ domain }}{% endif %}; + server_name {{ domain }}{% if xmpp_enabled == "True" %} xmpp-upload.{{ domain }} muc.{{ domain }}{% endif %}; access_by_lua_file /usr/share/ssowat/access.lua; From b29ee31c7aa601a7aefe5965b0d07521d538a8a8 Mon Sep 17 00:00:00 2001 From: ppr Date: Tue, 10 Jan 2023 16:58:43 +0000 Subject: [PATCH 29/67] Translated using Weblate (French) Currently translated at 99.0% (743 of 750 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/fr/ --- locales/fr.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/locales/fr.json b/locales/fr.json index 9c5b9a9e35..b26f672155 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -747,5 +747,6 @@ "app_not_enough_disk": "Cette application nécessite {required} d'espace libre.", "app_not_enough_ram": "Cette application nécessite {required} de mémoire vive (RAM) pour être installée/mise à niveau mais seule {current} de mémoire est disponible actuellement.", "app_yunohost_version_not_supported": "Cette application nécessite une version de YunoHost >= {required}. La version installée est {current}", - "confirm_notifications_read": "AVERTISSEMENT : Vous devriez vérifier les notifications de l'application susmentionnée avant de continuer, il pourrait y avoir des éléments d'information importants à connaître. [{answers}]" -} \ No newline at end of file + "confirm_notifications_read": "AVERTISSEMENT : Vous devriez vérifier les notifications de l'application susmentionnée avant de continuer, il pourrait y avoir des éléments d'information importants à connaître. [{answers}]", + "global_settings_setting_passwordless_sudo_help": "RÉPAREZ-MOI" +} From 12d4c16309bb2ddb0ee1c05b8438dbbd4b11ddf1 Mon Sep 17 00:00:00 2001 From: ButterflyOfFire Date: Wed, 11 Jan 2023 17:39:43 +0000 Subject: [PATCH 30/67] Translated using Weblate (Arabic) Currently translated at 19.0% (143 of 750 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/ar/ --- locales/ar.json | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/locales/ar.json b/locales/ar.json index aa40f2420a..570f036ecc 100644 --- a/locales/ar.json +++ b/locales/ar.json @@ -11,7 +11,7 @@ "app_not_properly_removed": "لم يتم حذف تطبيق {app} بشكلٍ جيّد", "app_removed": "تمت إزالة تطبيق {app}", "app_requirements_checking": "جار فحص الحزم اللازمة لـ {app}…", - "app_sources_fetch_failed": "تعذرت عملية جلب مصادر الملفات", + "app_sources_fetch_failed": "تعذر جلب ملفات المصدر ، هل عنوان URL صحيح؟", "app_unknown": "برنامج مجهول", "app_upgrade_app_name": "جارٍ تحديث {app}…", "app_upgrade_failed": "تعذرت عملية ترقية {app}", @@ -39,7 +39,7 @@ "done": "تم", "downloading": "عملية التنزيل جارية …", "dyndns_ip_updated": "لقد تم تحديث عنوان الإيبي الخاص بك على نظام أسماء النطاقات الديناميكي", - "dyndns_key_generating": "عملية توليد مفتاح نظام أسماء النطاقات جارية. يمكن للعملية أن تستغرق بعضا من الوقت…", + "dyndns_key_generating": "جارٍ إنشاء مفتاح DNS ... قد يستغرق الأمر بعض الوقت.", "dyndns_key_not_found": "لم يتم العثور على مفتاح DNS الخاص باسم النطاق هذا", "extracting": "عملية فك الضغط جارية…", "installation_complete": "إكتملت عملية التنصيب", @@ -57,7 +57,7 @@ "service_add_failed": "تعذرت إضافة خدمة '{service}'", "service_already_stopped": "إنّ خدمة '{service}' متوقفة مِن قبلُ", "service_disabled": "لن يتم إطلاق خدمة '{service}' أثناء بداية تشغيل النظام.", - "service_enabled": "تم تنشيط خدمة '{service}'", + "service_enabled": "سيتم الآن بدء تشغيل الخدمة '{service}' تلقائيًا أثناء تمهيد النظام.", "service_removed": "تمت إزالة خدمة '{service}'", "service_started": "تم إطلاق تشغيل خدمة '{service}'", "service_stopped": "تمّ إيقاف خدمة '{service}'", @@ -119,7 +119,7 @@ "already_up_to_date": "كل شيء على ما يرام. ليس هناك ما يتطلّب تحديثًا.", "service_description_slapd": "يخزّن المستخدمين والنطاقات والمعلومات المتعلقة بها", "service_reloaded": "تم إعادة تشغيل خدمة '{service}'", - "service_restarted": "تم إعادة تشغيل خدمة '{service}'", + "service_restarted": "تم إعادة تشغيل خدمة '{service}'", "group_unknown": "الفريق '{group}' مجهول", "group_deletion_failed": "فشلت عملية حذف الفريق '{group}': {error}", "group_deleted": "تم حذف الفريق '{group}'", @@ -193,5 +193,16 @@ "diagnosis_ports_ok": "المنفذ {port} مفتوح ومتاح الوصول إليه مِن الخارج.", "global_settings_setting_smtp_allow_ipv6": "سماح IPv6", "disk_space_not_sufficient_update": "ليس هناك مساحة كافية لتحديث هذا التطبيق", - "domain_cert_gen_failed": "لا يمكن إعادة توليد الشهادة" -} \ No newline at end of file + "domain_cert_gen_failed": "لا يمكن إعادة توليد الشهادة", + "diagnosis_apps_issue": "تم العثور على مشكلة في تطبيق {app}", + "tools_upgrade": "تحديث حُزم النظام", + "service_description_yunomdns": "يسمح لك بالوصول إلى خادمك الخاص باستخدام 'yunohost.local' في شبكتك المحلية", + "good_practices_about_user_password": "أنت الآن على وشك تحديد كلمة مرور مستخدم جديدة. يجب أن تتكون كلمة المرور من 8 أحرف على الأقل - على الرغم من أنه من الممارسات الجيدة استخدام كلمة مرور أطول (أي عبارة مرور) و / أو مجموعة متنوعة من الأحرف (الأحرف الكبيرة والصغيرة والأرقام والأحرف الخاصة).", + "root_password_changed": "تم تغيير كلمة مرور الجذر", + "root_password_desynchronized": "تم تغيير كلمة مرور المسؤول ، لكن لم يتمكن YunoHost من نشرها على كلمة مرور الجذر!", + "user_import_bad_line": "سطر غير صحيح {line}: {details}", + "user_import_success": "تم استيراد المستخدمين بنجاح", + "visitors": "الزوار", + "password_too_simple_3": "يجب أن تتكون كلمة المرور من 8 أحرف على الأقل وأن تحتوي على أرقام وأرقام علوية وسفلية وأحرف خاصة", + "password_too_simple_4": "يجب أن تتكون كلمة المرور من 12 حرفًا على الأقل وأن تحتوي على أرقام وأرقام علوية وسفلية وأحرف خاصة" +} From ec22c2ad1f0b471b84568f02160280db6d9fdd11 Mon Sep 17 00:00:00 2001 From: ppr Date: Wed, 11 Jan 2023 17:06:27 +0000 Subject: [PATCH 31/67] Translated using Weblate (French) Currently translated at 99.0% (743 of 750 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/fr/ --- locales/fr.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/fr.json b/locales/fr.json index b26f672155..2045be8ace 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -748,5 +748,5 @@ "app_not_enough_ram": "Cette application nécessite {required} de mémoire vive (RAM) pour être installée/mise à niveau mais seule {current} de mémoire est disponible actuellement.", "app_yunohost_version_not_supported": "Cette application nécessite une version de YunoHost >= {required}. La version installée est {current}", "confirm_notifications_read": "AVERTISSEMENT : Vous devriez vérifier les notifications de l'application susmentionnée avant de continuer, il pourrait y avoir des éléments d'information importants à connaître. [{answers}]", - "global_settings_setting_passwordless_sudo_help": "RÉPAREZ-MOI" + "global_settings_setting_passwordless_sudo_help": "RÉPAREZ-MOI / AIDEZ-MOI" } From 087030ac7f1b024b134a7176000c23685314611f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20M?= Date: Thu, 12 Jan 2023 05:24:34 +0000 Subject: [PATCH 32/67] Translated using Weblate (Galician) Currently translated at 99.7% (748 of 750 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/gl/ --- locales/gl.json | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/locales/gl.json b/locales/gl.json index a4f9d97728..af3d491652 100644 --- a/locales/gl.json +++ b/locales/gl.json @@ -739,5 +739,12 @@ "domain_cannot_add_muc_upload": "Non podes engadir dominios que comecen por 'muc.'. Este tipo de dominio está reservado para as salas de conversa de XMPP integradas en YunoHost.", "global_settings_setting_passwordless_sudo": "Permitir a Admins usar 'sudo' sen ter que volver a escribir o contrasinal", "global_settings_setting_portal_theme": "Decorado do Portal", - "global_settings_setting_portal_theme_help": "Tes máis info acerca da creación de decorados para o portal de acceso en https://yunohost.org/theming" -} \ No newline at end of file + "global_settings_setting_portal_theme_help": "Tes máis info acerca da creación de decorados para o portal de acceso en https://yunohost.org/theming", + "app_arch_not_supported": "Esta app só pode ser instalada e arquitecturas {', '.join(required)} pero a arquitectura do teu servidor é {current}", + "app_not_enough_disk": "Esta app precisa {required} de espazo libre.", + "app_yunohost_version_not_supported": "Esta app require YunoHost >= {required} pero a versión actual instalada é {current}", + "confirm_app_insufficient_ram": "PERIGO! Esta app precisa {required} de RAM para instalar/actualizar pero só hai {current} dispoñibles. Incluso se a app funcionase, o seu proceso de instalación/actualización require gran cantidade de RAM e o teu servidor podería colgarse e fallar. Se queres asumir o risco, escribe '{answers}'", + "confirm_notifications_read": "AVISO: Deberías comprobar as notificacións da app antes de continuar, poderías ter información importante que revisar. [{answers}]", + "global_settings_setting_passwordless_sudo_help": "ARRÁNXAME", + "app_not_enough_ram": "Esta app require {required} de RAM para instalar/actualizar pero só hai {current} dispoñible." +} From 0d279baa2c48cecf49b9ddbb22f4cb794852f612 Mon Sep 17 00:00:00 2001 From: Weblate Date: Sat, 14 Jan 2023 15:42:30 +0100 Subject: [PATCH 33/67] Added translation using Weblate (Lithuanian) --- locales/lt.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 locales/lt.json diff --git a/locales/lt.json b/locales/lt.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/locales/lt.json @@ -0,0 +1 @@ +{} From 908fa1035716447fff15852d84594521c2077da6 Mon Sep 17 00:00:00 2001 From: cristian amoyao Date: Tue, 17 Jan 2023 20:26:15 +0000 Subject: [PATCH 34/67] Translated using Weblate (Spanish) Currently translated at 96.9% (727 of 750 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/es/ --- locales/es.json | 63 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 61 insertions(+), 2 deletions(-) diff --git a/locales/es.json b/locales/es.json index 9a92908a46..3d14ab7811 100644 --- a/locales/es.json +++ b/locales/es.json @@ -677,5 +677,64 @@ "config_action_failed": "Error al ejecutar la acción '{action}': {error}", "config_forbidden_readonly_type": "El tipo '{type}' no puede establecerse como solo lectura, utilice otro tipo para representar este valor (arg id relevante: '{id}').", "diagnosis_using_stable_codename": "apt (el gestor de paquetes del sistema) está configurado actualmente para instalar paquetes de nombre en clave 'estable', en lugar del nombre en clave de la versión actual de Debian (bullseye).", - "diagnosis_using_stable_codename_details": "Esto suele deberse a una configuración incorrecta de su proveedor de alojamiento. Esto es peligroso, porque tan pronto como la siguiente versión de Debian se convierta en la nueva 'estable', apt querrá actualizar todos los paquetes del sistema sin pasar por un procedimiento de migración adecuado. Se recomienda arreglar esto editando la fuente de apt para el repositorio base de Debian, y reemplazar la palabra clave stable por bullseye. El fichero de configuración correspondiente debería ser /etc/apt/sources.list, o un fichero en /etc/apt/sources.list.d/." -} \ No newline at end of file + "diagnosis_using_stable_codename_details": "Esto suele deberse a una configuración incorrecta de su proveedor de alojamiento. Esto es peligroso, porque tan pronto como la siguiente versión de Debian se convierta en la nueva 'estable', apt querrá actualizar todos los paquetes del sistema sin pasar por un procedimiento de migración adecuado. Se recomienda arreglar esto editando la fuente de apt para el repositorio base de Debian, y reemplazar la palabra clave stable por bullseye. El fichero de configuración correspondiente debería ser /etc/apt/sources.list, o un fichero en /etc/apt/sources.list.d/.", + "domain_config_cert_install": "Instalar el certificado Let's Encrypt", + "domain_cannot_add_muc_upload": "No puedes añadir dominios que empiecen por 'muc.'. Este tipo de nombre está reservado para la función de chat XMPP multi-usuarios integrada en YunoHost.", + "domain_config_cert_renew_help": "El certificado se renovará automáticamente durante los últimos 15 días de validez. Si lo desea, puede renovarlo manualmente. (No recomendado).", + "domain_config_cert_summary_expired": "CRÍTICO: ¡El certificado actual no es válido! ¡HTTPS no funcionará en absoluto!", + "domain_config_cert_summary_letsencrypt": "¡Muy bien! Estás utilizando un certificado Let's Encrypt válido.", + "global_settings_setting_postfix_compatibility": "Compatibilidad con Postfix", + "global_settings_setting_root_password_confirm": "Nueva contraseña de root (confirmar)", + "global_settings_setting_webadmin_allowlist_enabled": "Activar la lista de IPs permitidas para Webadmin", + "migration_0024_rebuild_python_venv_broken_app": "Omitiendo {app} porque virtualenv no puede ser reconstruido fácilmente para esta app. En su lugar, deberías arreglar la situación forzando la actualización de esta app usando `yunohost app upgrade --force {app}`.", + "migration_0024_rebuild_python_venv_in_progress": "Ahora intentando reconstruir el virtualenv de Python para `{app}`", + "confirm_app_insufficient_ram": "¡PELIGRO! Esta aplicación requiere {required} de RAM para ser instalada/actualizada, pero solo hay {current} disponible actualmente. Incluso si esta aplicación pudiera ejecutarse, su proceso de instalación/actualización requiere una gran cantidad de RAM, por lo que tu servidor puede congelarse y fallar miserablemente. Si estás dispuesto a asumir ese riesgo de todos modos, escribe '{answers}'", + "confirm_notifications_read": "ADVERTENCIA: Deberías revisar las notificaciones de la aplicación antes de continuar, puede haber información importante que debes conocer. [{answers}]", + "domain_config_cert_summary_selfsigned": "ADVERTENCIA: El certificado actual es autofirmado. ¡Los navegadores mostrarán una espeluznante advertencia a los nuevos visitantes!.", + "global_settings_setting_backup_compress_tar_archives": "Comprimir las copias de seguridad", + "global_settings_setting_root_access_explain": "En sistemas Linux, 'root' es el administrador absoluto. En el contexto de YunoHost, el acceso directo 'root' SSH está deshabilitado por defecto - excepto desde la red local del servidor. Los miembros del grupo 'admins' pueden usar el comando sudo para actuar como root desde la linea de comandos. Sin embargo, puede ser útil tener una contraseña de root (robusta) para depurar el sistema si por alguna razón los administradores regulares ya no pueden iniciar sesión.", + "migration_0021_not_buster2": "¡La distribución Debian actual no es Buster! Si ya ha ejecutado la migración Buster->Bullseye, entonces este error es sintomático del hecho de que el procedimiento de migración no fue 100% exitoso (de lo contrario YunoHost lo habría marcado como completado). Se recomienda investigar lo sucedido con el equipo de soporte, que necesitará el registro **completo** de la `migración, que se puede encontrar en Herramientas > Registros en el webadmin.", + "global_settings_reset_success": "Restablecer la configuración global", + "global_settings_setting_nginx_compatibility": "Compatibilidad con NGINX", + "global_settings_setting_nginx_redirect_to_https": "Forzar HTTPS", + "global_settings_setting_user_strength_help": "Estos requisitos sólo se aplican al inicializar o cambiar la contraseña", + "log_resource_snippet": "Aprovisionar/desaprovisionar/actualizar un recurso", + "global_settings_setting_pop3_enabled": "Habilitar POP3", + "global_settings_setting_smtp_allow_ipv6": "Permitir IPv6", + "global_settings_setting_security_experimental_enabled": "Funciones de seguridad experimentales", + "migration_0024_rebuild_python_venv_disclaimer_ignored": "Virtualenvs no puede reconstruirse automáticamente para esas aplicaciones. Necesitas forzar una actualización para ellas, lo que puede hacerse desde la línea de comandos con: `yunohost app upgrade --force APP`: {ignored_apps}", + "migration_0024_rebuild_python_venv_failed": "Error al reconstruir el virtualenv de Python para {app}. La aplicación puede no funcionar mientras esto no se resuelva. Deberías arreglar la situación forzando la actualización de esta app usando `yunohost app upgrade --force {app}`.", + "app_arch_not_supported": "Esta aplicación sólo puede instalarse en arquitecturas {', '.join(required)} pero la arquitectura de su servidor es {current}", + "app_resource_failed": "Falló la asignación, desasignación o actualización de recursos para {app}: {error}", + "app_not_enough_disk": "Esta aplicación requiere {required} espacio libre.", + "app_not_enough_ram": "Esta aplicación requiere {required} de RAM para ser instalada/actualizada, pero solo hay {current} disponible actualmente.", + "app_yunohost_version_not_supported": "Esta aplicación requiere YunoHost >= {required} pero la versión actualmente instalada es {current}", + "global_settings_setting_ssh_compatibility": "Compatibilidad con SSH", + "root_password_changed": "la contraseña de root fue cambiada", + "domain_config_acme_eligible_explain": "Este dominio no parece estar preparado para un certificado Let's Encrypt. Compruebe la configuración DNS y la accesibilidad del servidor HTTP. Las secciones \"Registros DNS\" y \"Web\" de la página de diagnóstico pueden ayudarte a entender qué está mal configurado.", + "domain_config_cert_no_checks": "Ignorar las comprobaciones de diagnóstico", + "domain_config_cert_renew": "Renovar el certificado Let's Encrypt", + "domain_config_cert_summary": "Estado del certificado", + "domain_config_cert_summary_abouttoexpire": "El certificado actual está a punto de caducar. Pronto debería renovarse automáticamente.", + "domain_config_cert_summary_ok": "Muy bien, ¡el certificado actual tiene buena pinta!", + "domain_config_cert_validity": "Validez", + "global_settings_setting_admin_strength_help": "Estos requisitos sólo se aplican al inicializar o cambiar la contraseña", + "global_settings_setting_pop3_enabled_help": "Habilitar el protocolo POP3 para el servidor de correo", + "log_settings_reset_all": "Restablecer todos los ajustes", + "log_settings_set": "Aplicar ajustes", + "pattern_fullname": "Debe ser un nombre completo válido (al menos 3 caracteres)", + "password_confirmation_not_the_same": "La contraseña y su confirmación no coinciden", + "password_too_long": "Elija una contraseña de menos de 127 caracteres", + "diagnosis_using_yunohost_testing": "apt (el gestor de paquetes del sistema) está actualmente configurado para instalar cualquier actualización de 'testing' para el núcleo de YunoHost.", + "diagnosis_using_yunohost_testing_details": "Esto probablemente esté bien si sabes lo que estás haciendo, ¡pero presta atención a las notas de la versión antes de instalar actualizaciones de YunoHost! Si quieres deshabilitar las actualizaciones de prueba, debes eliminar la palabra clave testing de /etc/apt/sources.list.d/yunohost.list.", + "global_settings_setting_passwordless_sudo": "Permitir a los administradores utilizar 'sudo' sin tener que volver a escribir sus contraseñas.", + "group_update_aliases": "Actualizando alias para el grupo '{group}'", + "group_no_change": "Nada que cambiar para el grupo '{group}'", + "global_settings_setting_portal_theme": "Tema del portal", + "global_settings_setting_portal_theme_help": "Más información sobre la creación de temas de portal personalizados en https://yunohost.org/theming", + "invalid_credentials": "Contraseña o nombre de usuario no válidos", + "global_settings_setting_root_password": "Nueva contraseña de root", + "global_settings_setting_webadmin_allowlist": "Lista de IPs permitidas para Webadmin", + "migration_0024_rebuild_python_venv_disclaimer_base": "Tras la actualización a Debian Bullseye, algunas aplicaciones Python necesitan ser parcialmente reconstruidas para ser convertidas a la nueva versión de Python distribuida en Debian (en términos técnicos: lo que se llama el 'virtualenv' necesita ser recreado). Mientras tanto, esas aplicaciones Python pueden no funcionar. YunoHost puede intentar reconstruir el virtualenv para algunas de ellas, como se detalla a continuación. Para otras aplicaciones, o si el intento de reconstrucción falla, necesitarás forzar manualmente una actualización para esas aplicaciones.", + "migration_description_0024_rebuild_python_venv": "Reparar la aplicación Python tras la migración a bullseye" +} From 3c6ab69ae62edf5f95e0978de35a60cc8df7f026 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Gaspar?= Date: Thu, 19 Jan 2023 15:58:35 +0000 Subject: [PATCH 35/67] Translated using Weblate (French) Currently translated at 100.0% (751 of 751 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/fr/ --- locales/fr.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/locales/fr.json b/locales/fr.json index 2045be8ace..3bb666bd38 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -743,10 +743,11 @@ "global_settings_setting_passwordless_sudo": "Permettre aux administrateurs d'utiliser 'sudo' sans retaper leur mot de passe", "app_arch_not_supported": "Cette application ne peut être installée que sur les architectures {', '.join(required)}. L'architecture de votre serveur est {current}", "app_resource_failed": "L'allocation automatique des ressources (provisioning), la suppression d'accès à ces ressources (déprovisioning) ou la mise à jour des ressources pour {app} a échoué : {error}", - "confirm_app_insufficient_ram": "ATTENTION ! Cette application requiert {required} de RAM pour l'installation/mise à niveau mais il n'y a que {current} de disponible actuellement. Même si cette application pouvait fonctionner, son processus d'installation/mise à niveau nécessite une grande quantité de RAM. Votre serveur pourrait donc geler (freezer) et planter lamentablement. Si vous êtes prêt à prendre ce risque, tapez '{answers}'", + "confirm_app_insufficient_ram": "ATTENTION ! Cette application requiert {required} de RAM pour l'installation/mise à niveau mais il n'y a que {current} de disponible actuellement. Même si cette application pouvait fonctionner, son processus d'installation/mise à niveau nécessite une grande quantité de RAM. Votre serveur pourrait donc geler et planter lamentablement. Si vous êtes prêt à prendre ce risque, tapez '{answers}'", "app_not_enough_disk": "Cette application nécessite {required} d'espace libre.", "app_not_enough_ram": "Cette application nécessite {required} de mémoire vive (RAM) pour être installée/mise à niveau mais seule {current} de mémoire est disponible actuellement.", "app_yunohost_version_not_supported": "Cette application nécessite une version de YunoHost >= {required}. La version installée est {current}", - "confirm_notifications_read": "AVERTISSEMENT : Vous devriez vérifier les notifications de l'application susmentionnée avant de continuer, il pourrait y avoir des éléments d'information importants à connaître. [{answers}]", - "global_settings_setting_passwordless_sudo_help": "RÉPAREZ-MOI / AIDEZ-MOI" + "confirm_notifications_read": "AVERTISSEMENT : Vous devriez vérifier les notifications de l'application susmentionnée avant de continuer, il pourrait y avoir des informations importantes à connaître. [{answers}]", + "global_settings_setting_passwordless_sudo_help": "RÉPAREZ-MOI / AIDEZ-MOI", + "invalid_shell": "Shell invalide : {shell}" } From 94b1338dc668b23b72df0ae1c0a0e46ef9966535 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Gaspar?= Date: Mon, 23 Jan 2023 11:48:41 +0000 Subject: [PATCH 36/67] Translated using Weblate (French) Currently translated at 100.0% (750 of 750 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/fr/ --- locales/fr.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/fr.json b/locales/fr.json index 3bb666bd38..426b84fcf2 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -655,7 +655,7 @@ "global_settings_setting_backup_compress_tar_archives_help": "Lors de la création de nouvelles sauvegardes, compresser automatiquement les archives (.tar.gz) au lieu des archives non compressées (.tar). N.B. : activer cette option permet de créer des archives plus légères, mais la procédure de sauvegarde initiale sera significativement plus longues et plus gourmandes en CPU.", "global_settings_setting_security_experimental_enabled": "Fonctionnalités de sécurité expérimentales", "global_settings_setting_security_experimental_enabled_help": "Activer les fonctionnalités de sécurité expérimentales (ne l'activez pas si vous ne savez pas ce que vous faites !)", - "global_settings_setting_nginx_compatibility_help": "Compromis 'compatibilité versus sécurité' pour le serveur web Nginx. Affecte les cryptogrammes utilisés (et d'autres aspects liés à la sécurité)", + "global_settings_setting_nginx_compatibility_help": "Compromis 'compatibilité versus sécurité' pour le serveur web NGINX. Affecte les cryptogrammes utilisés (et d'autres aspects liés à la sécurité)", "global_settings_setting_nginx_redirect_to_https_help": "Rediriger les requêtes HTTP vers HTTPS par défaut (NE PAS DÉSACTIVER à moins de savoir vraiment ce que vous faites !)", "global_settings_setting_admin_strength": "Critères pour les mots de passe administrateur", "global_settings_setting_user_strength": "Critères pour les mots de passe utilisateurs", From cba36d2cf53d441f71cf4bd91df6d034fb52f69d Mon Sep 17 00:00:00 2001 From: xabirequejo Date: Mon, 23 Jan 2023 23:29:11 +0000 Subject: [PATCH 37/67] Translated using Weblate (Basque) Currently translated at 98.2% (737 of 750 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/eu/ --- locales/eu.json | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/locales/eu.json b/locales/eu.json index 4d212bf58f..1754343c4e 100644 --- a/locales/eu.json +++ b/locales/eu.json @@ -735,5 +735,17 @@ "password_too_long": "Aukeratu 127 karaktere baino laburragoa den pasahitz bat", "diagnosis_using_stable_codename_details": "Ostatatzaileak zerbait oker ezarri duenean gertatu ohi da hau. Arriskutsua da, Debianen datorren bertsioa 'estable' (egonkorra) bilakatzen denean, apt-ek sistemaren pakete guztiak bertsio-berritzen saiatuko da, beharrezko migrazio-prozedurarik burutu gabe. Debianen repositorioan apt iturria editatzen konpontzea da gomendioa, stable gakoa bullseye gakoarekin ordezkatuz. Ezarpen-fitxategia /etc/apt/sources.list izan beharko litzateke, edo /etc/apt/sources.list.d/ direktorioko fitxategiren bat.", "group_update_aliases": "'{group}' taldearen aliasak eguneratzen", - "group_no_change": "Ez da ezer aldatu behar '{group}' talderako" -} \ No newline at end of file + "group_no_change": "Ez da ezer aldatu behar '{group}' talderako", + "app_not_enough_ram": "Aplikazio honek {required} RAM behar ditu instalatu edo bertsio-berritzeko, baina {current} bakarrik daude erabilgarri une honetan.", + "domain_cannot_add_muc_upload": "Ezin duzu 'muc.'-ekin hasten den domeinurik gehitu. Mota honetako izenak YunoHosten integratuta dagoen XMPP taldeko txatek erabil ditzaten gordeta daude.", + "confirm_app_insufficient_ram": "KONTUZ! Aplikazio honek {required} RAM behar ditu instalatu edo bertsio-berritzeko baina unean {current} bakarrik daude erabilgarri. Aplikazioa ibiliko balitz ere, instalazioak edo bertsio-berritzeak RAM koporu handia eskatzen du eta zure zerbitzaria izoztu eta huts egin lezake. Hala ere arriskatu nahi baduzu idatzi '{answers}'", + "confirm_notifications_read": "ADI: ikuskatu aplikazioaren jakinarazpenak jarraitu baino lehen, baliteke jakin beharreko zerbait esatea. [{answers}]", + "app_arch_not_supported": "Aplikazio hau {', '.join(required)} arkitekturan instala daiteke bakarrik, baina zure zerbitzariaren arkitektura {current} da", + "app_resource_failed": "Huts egin du {app} aplikaziorako baliabideak", + "app_not_enough_disk": "Aplikazio honek {required} espazio libre behar ditu.", + "app_yunohost_version_not_supported": "Aplikazio honek YunoHost >= {required} behar du baina unean instalatutako bertsioa {current} da", + "global_settings_setting_passwordless_sudo": "Baimendu administrariek 'sudo' erabiltzea pasahitzak berriro idatzi beharrik gabe", + "global_settings_setting_portal_theme": "Atariko gaia", + "global_settings_setting_portal_theme_help": "Atariko gai propioak sortzeari buruzko informazio gehiago: https://yunohost.org/theming", + "invalid_shell": "Shell baliogabea: {shell}" +} From dafdf1c4ba48ea880b39b1afab28b3303c03ebf3 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 24 Jan 2023 17:47:04 +0100 Subject: [PATCH 38/67] i18n: typo in fr string --- locales/fr.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/locales/fr.json b/locales/fr.json index 9c5b9a9e35..4551f294d0 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -708,7 +708,7 @@ "visitors": "Visiteurs", "global_settings_reset_success": "Réinitialisation des paramètres généraux", "domain_config_acme_eligible": "Éligibilité au protocole ACME (Automatic Certificate Management Environment, littéralement : environnement de gestion automatique de certificat)", - "domain_config_acme_eligible_explain": "Ce domaine ne semble pas près pour installer un certificat Let's Encrypt. Veuillez vérifier votre configuration DNS mais aussi que votre serveur est bien joignable en HTTP. Les sections 'Enregistrements DNS' et 'Web' de la page Diagnostic peuvent vous aider à comprendre ce qui est mal configuré.", + "domain_config_acme_eligible_explain": "Ce domaine ne semble pas prêt pour installer un certificat Let's Encrypt. Veuillez vérifier votre configuration DNS mais aussi que votre serveur est bien joignable en HTTP. Les sections 'Enregistrements DNS' et 'Web' de la page Diagnostic peuvent vous aider à comprendre ce qui est mal configuré.", "domain_config_cert_install": "Installer un certificat Let's Encrypt", "domain_config_cert_issuer": "Autorité de certification", "domain_config_cert_no_checks": "Ignorer les tests et autres vérifications du diagnostic", @@ -748,4 +748,4 @@ "app_not_enough_ram": "Cette application nécessite {required} de mémoire vive (RAM) pour être installée/mise à niveau mais seule {current} de mémoire est disponible actuellement.", "app_yunohost_version_not_supported": "Cette application nécessite une version de YunoHost >= {required}. La version installée est {current}", "confirm_notifications_read": "AVERTISSEMENT : Vous devriez vérifier les notifications de l'application susmentionnée avant de continuer, il pourrait y avoir des éléments d'information importants à connaître. [{answers}]" -} \ No newline at end of file +} From e28d8a9fe5e5c2b3fe160d438881469456ce2661 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 24 Jan 2023 17:54:51 +0100 Subject: [PATCH 39/67] i18n: funky fr translation --- locales/fr.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/fr.json b/locales/fr.json index 9ee8d421a9..db268bb566 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -627,7 +627,7 @@ "diagnosis_http_special_use_tld": "Le domaine {domain} est basé sur un domaine de premier niveau (TLD) à usage spécial tel que .local ou .test et n'est donc pas censé être exposé en dehors du réseau local.", "domain_dns_conf_special_use_tld": "Ce domaine est basé sur un domaine de premier niveau (TLD) à usage spécial tel que .local ou .test et ne devrait donc pas avoir d'enregistrements DNS réels.", "other_available_options": "... et {n} autres options disponibles non affichées", - "domain_config_auth_consumer_key": "La clé utilisateur", + "domain_config_auth_consumer_key": "Clé utilisateur", "domain_unknown": "Domaine '{domain}' inconnu", "migration_0021_start": "Démarrage de la migration vers Bullseye", "migration_0021_patching_sources_list": "Mise à jour du fichier sources.lists...", From c2998411944d05b5dfcae523370a9f774ad3056a Mon Sep 17 00:00:00 2001 From: yunohost-bot Date: Tue, 24 Jan 2023 17:19:38 +0000 Subject: [PATCH 40/67] [CI] Reformat / remove stale translated strings --- locales/ar.json | 2 +- locales/es.json | 2 +- locales/eu.json | 2 +- locales/fr.json | 2 +- locales/gl.json | 3 +-- locales/lt.json | 2 +- 6 files changed, 6 insertions(+), 7 deletions(-) diff --git a/locales/ar.json b/locales/ar.json index 570f036ecc..dd254096b9 100644 --- a/locales/ar.json +++ b/locales/ar.json @@ -205,4 +205,4 @@ "visitors": "الزوار", "password_too_simple_3": "يجب أن تتكون كلمة المرور من 8 أحرف على الأقل وأن تحتوي على أرقام وأرقام علوية وسفلية وأحرف خاصة", "password_too_simple_4": "يجب أن تتكون كلمة المرور من 12 حرفًا على الأقل وأن تحتوي على أرقام وأرقام علوية وسفلية وأحرف خاصة" -} +} \ No newline at end of file diff --git a/locales/es.json b/locales/es.json index 3d14ab7811..63100e04c0 100644 --- a/locales/es.json +++ b/locales/es.json @@ -737,4 +737,4 @@ "global_settings_setting_webadmin_allowlist": "Lista de IPs permitidas para Webadmin", "migration_0024_rebuild_python_venv_disclaimer_base": "Tras la actualización a Debian Bullseye, algunas aplicaciones Python necesitan ser parcialmente reconstruidas para ser convertidas a la nueva versión de Python distribuida en Debian (en términos técnicos: lo que se llama el 'virtualenv' necesita ser recreado). Mientras tanto, esas aplicaciones Python pueden no funcionar. YunoHost puede intentar reconstruir el virtualenv para algunas de ellas, como se detalla a continuación. Para otras aplicaciones, o si el intento de reconstrucción falla, necesitarás forzar manualmente una actualización para esas aplicaciones.", "migration_description_0024_rebuild_python_venv": "Reparar la aplicación Python tras la migración a bullseye" -} +} \ No newline at end of file diff --git a/locales/eu.json b/locales/eu.json index 1754343c4e..cf6b0abea9 100644 --- a/locales/eu.json +++ b/locales/eu.json @@ -748,4 +748,4 @@ "global_settings_setting_portal_theme": "Atariko gaia", "global_settings_setting_portal_theme_help": "Atariko gai propioak sortzeari buruzko informazio gehiago: https://yunohost.org/theming", "invalid_shell": "Shell baliogabea: {shell}" -} +} \ No newline at end of file diff --git a/locales/fr.json b/locales/fr.json index db268bb566..41e58a1c59 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -749,4 +749,4 @@ "app_yunohost_version_not_supported": "Cette application nécessite une version de YunoHost >= {required}. La version installée est {current}", "confirm_notifications_read": "AVERTISSEMENT : Vous devriez vérifier les notifications de l'application susmentionnée avant de continuer, il pourrait y avoir des informations importantes à connaître. [{answers}]", "invalid_shell": "Shell invalide : {shell}" -} +} \ No newline at end of file diff --git a/locales/gl.json b/locales/gl.json index af3d491652..c592c650f8 100644 --- a/locales/gl.json +++ b/locales/gl.json @@ -745,6 +745,5 @@ "app_yunohost_version_not_supported": "Esta app require YunoHost >= {required} pero a versión actual instalada é {current}", "confirm_app_insufficient_ram": "PERIGO! Esta app precisa {required} de RAM para instalar/actualizar pero só hai {current} dispoñibles. Incluso se a app funcionase, o seu proceso de instalación/actualización require gran cantidade de RAM e o teu servidor podería colgarse e fallar. Se queres asumir o risco, escribe '{answers}'", "confirm_notifications_read": "AVISO: Deberías comprobar as notificacións da app antes de continuar, poderías ter información importante que revisar. [{answers}]", - "global_settings_setting_passwordless_sudo_help": "ARRÁNXAME", "app_not_enough_ram": "Esta app require {required} de RAM para instalar/actualizar pero só hai {current} dispoñible." -} +} \ No newline at end of file diff --git a/locales/lt.json b/locales/lt.json index 0967ef424b..9e26dfeeb6 100644 --- a/locales/lt.json +++ b/locales/lt.json @@ -1 +1 @@ -{} +{} \ No newline at end of file From 36205a7b4c3968029de12d2b8021f31d3ed64bee Mon Sep 17 00:00:00 2001 From: quiwy Date: Wed, 25 Jan 2023 15:14:56 +0000 Subject: [PATCH 41/67] Translated using Weblate (Spanish) Currently translated at 100.0% (750 of 750 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/es/ --- locales/es.json | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/locales/es.json b/locales/es.json index 3d14ab7811..942c8dd13d 100644 --- a/locales/es.json +++ b/locales/es.json @@ -78,8 +78,8 @@ "pattern_backup_archive_name": "Debe ser un nombre de archivo válido con un máximo de 30 caracteres, solo se admiten caracteres alfanuméricos y los caracteres -_. (guiones y punto)", "pattern_domain": "El nombre de dominio debe ser válido (por ejemplo mi-dominio.org)", "pattern_email": "Debe ser una dirección de correo electrónico válida, sin el símbolo '+' (ej. alguien@ejemplo.com)", - "pattern_firstname": "Debe ser un nombre válido", - "pattern_lastname": "Debe ser un apellido válido", + "pattern_firstname": "Debe ser un nombre válido (al menos 3 caracteres)", + "pattern_lastname": "Debe ser un apellido válido (al menos 3 caracteres)", "pattern_mailbox_quota": "Debe ser un tamaño con el sufijo «b/k/M/G/T» o «0» para no tener una cuota", "pattern_password": "Debe contener al menos 3 caracteres", "pattern_port_or_range": "Debe ser un número de puerto válido (es decir entre 0-65535) o un intervalo de puertos (por ejemplo 100:200)", @@ -266,7 +266,7 @@ "migrations_failed_to_load_migration": "No se pudo cargar la migración {id}: {error}", "migrations_dependencies_not_satisfied": "Ejecutar estas migraciones: «{dependencies_id}» antes de migrar {id}.", "migrations_already_ran": "Esas migraciones ya se han realizado: {ids}", - "mail_unavailable": "Esta dirección de correo está reservada y será asignada automáticamente al primer usuario", + "mail_unavailable": "Esta dirección de correo electrónico está reservada para el grupo de administradores", "mailbox_disabled": "Correo desactivado para usuario {user}", "log_tools_reboot": "Reiniciar el servidor", "log_tools_shutdown": "Apagar el servidor", @@ -316,7 +316,7 @@ "dyndns_could_not_check_available": "No se pudo comprobar si {domain} está disponible en {provider}.", "domain_dns_conf_is_just_a_recommendation": "Este comando muestra la configuración *recomendada*. No configura las entradas DNS por ti. Es tu responsabilidad configurar la zona DNS en su registrador según esta recomendación.", "dpkg_lock_not_available": "Esta orden no se puede ejecutar en este momento ,parece que programa está usando el bloqueo de dpkg (el gestor de paquetes del sistema)", - "dpkg_is_broken": "No puede hacer esto en este momento porque dpkg/APT (los gestores de paquetes del sistema) parecen estar mal configurados... Puede tratar de solucionar este problema conectando a través de SSH y ejecutando `sudo apt install --fix-broken` y/o `sudo dpkg --configure -a`.", + "dpkg_is_broken": "No puede hacer esto en este momento porque dpkg/APT (los gestores de paquetes del sistema) parecen estar mal configurados... Puede tratar de solucionar este problema conectando a través de SSH y ejecutando `sudo apt install --fix-broken` y/o `sudo dpkg --configure -a` y/o `sudo dpkg --audit`.", "confirm_app_install_thirdparty": "¡PELIGRO! Esta aplicación no forma parte del catálogo de aplicaciones de YunoHost. La instalación de aplicaciones de terceros puede comprometer la integridad y seguridad de tu sistema. Probablemente NO deberías instalarla a menos que sepas lo que estás haciendo. NO se proporcionará NINGÚN SOPORTE si esta aplicación no funciona o rompe su sistema… Si de todos modos quieres correr ese riesgo, escribe '{answers}'", "confirm_app_install_danger": "¡PELIGRO! ¡Esta aplicación sigue siendo experimental (si no es expresamente no funcional)! Probablemente NO deberías instalarla a menos que sepas lo que estás haciendo. NO se proporcionará NINGÚN SOPORTE si esta aplicación no funciona o rompe tu sistema… Si de todos modos quieres correr ese riesgo, escribe '{answers}'", "confirm_app_install_warning": "Aviso: esta aplicación puede funcionar pero no está bien integrada en YunoHost. Algunas herramientas como la autentificación única y respaldo/restauración podrían no estar disponibles. ¿Instalar de todos modos? [{answers}] ", @@ -454,7 +454,7 @@ "diagnosis_ports_forwarding_tip": "Para solucionar este incidente, lo más seguro deberías configurar la redirección de los puertos en el router como se especifica en https://yunohost.org/isp_box_config", "certmanager_warning_subdomain_dns_record": "El subdominio '{subdomain}' no se resuelve en la misma dirección IP que '{domain}'. Algunas funciones no estarán disponibles hasta que solucione esto y regenere el certificado.", "domain_cannot_add_xmpp_upload": "No puede agregar dominios que comiencen con 'xmpp-upload'. Este tipo de nombre está reservado para la función de carga XMPP integrada en YunoHost.", - "yunohost_postinstall_end_tip": "¡La post-instalación completada! Para finalizar su configuración, por favor considere:\n - agregar un primer usuario a través de la sección 'Usuarios' del administrador web (o 'yunohost user create ' en la línea de comandos);\n - diagnosticar problemas potenciales a través de la sección 'Diagnóstico' del administrador web (o 'yunohost diagnosis run' en la línea de comandos);\n - leyendo las partes 'Finalizando su configuración' y 'Conociendo YunoHost' en la documentación del administrador: https://yunohost.org/admindoc.", + "yunohost_postinstall_end_tip": "¡La post-instalación completada! Para finalizar su configuración, por favor considere:\n - diagnosticar problemas potenciales a través de la sección 'Diagnóstico' del administrador web (o 'yunohost diagnosis run' en la línea de comandos);\n - leyendo las partes 'Finalizando su configuración' y 'Conociendo YunoHost' en la documentación del administrador: https://yunohost.org/admindoc.", "diagnosis_dns_point_to_doc": "Por favor, consulta la documentación en https://yunohost.org/dns_config si necesitas ayuda para configurar los registros DNS.", "diagnosis_ip_global": "IP Global: {global}", "diagnosis_mail_outgoing_port_25_ok": "El servidor de email SMTP puede mandar emails (puerto saliente 25 no está bloqueado).", @@ -598,7 +598,7 @@ "postinstall_low_rootfsspace": "El sistema de archivos raíz tiene un espacio total inferior a 10 GB, ¡lo cual es bastante preocupante! ¡Es probable que se quede sin espacio en disco muy rápidamente! Se recomienda tener al menos 16 GB para el sistema de archivos raíz. Si desea instalar YunoHost a pesar de esta advertencia, vuelva a ejecutar la instalación posterior con --force-diskspace", "migration_ldap_rollback_success": "Sistema revertido.", "permission_protected": "Permiso {permission} está protegido. No puede agregar o quitar el grupo de visitantes a/desde este permiso.", - "global_settings_setting_ssowat_panel_overlay_enabled": "Habilitar la superposición del panel SSOwat", + "global_settings_setting_ssowat_panel_overlay_enabled": "Habilitar el pequeño cuadrado de acceso directo al portal \"YunoHost\" en las aplicaciones", "migration_0021_start": "Iniciando migración a Bullseye", "migration_0021_patching_sources_list": "Parcheando los sources.lists...", "migration_0021_main_upgrade": "Iniciando actualización principal...", @@ -736,5 +736,10 @@ "global_settings_setting_root_password": "Nueva contraseña de root", "global_settings_setting_webadmin_allowlist": "Lista de IPs permitidas para Webadmin", "migration_0024_rebuild_python_venv_disclaimer_base": "Tras la actualización a Debian Bullseye, algunas aplicaciones Python necesitan ser parcialmente reconstruidas para ser convertidas a la nueva versión de Python distribuida en Debian (en términos técnicos: lo que se llama el 'virtualenv' necesita ser recreado). Mientras tanto, esas aplicaciones Python pueden no funcionar. YunoHost puede intentar reconstruir el virtualenv para algunas de ellas, como se detalla a continuación. Para otras aplicaciones, o si el intento de reconstrucción falla, necesitarás forzar manualmente una actualización para esas aplicaciones.", - "migration_description_0024_rebuild_python_venv": "Reparar la aplicación Python tras la migración a bullseye" + "migration_description_0024_rebuild_python_venv": "Reparar la aplicación Python tras la migración a bullseye", + "global_settings_setting_smtp_relay_enabled": "Activar el relé SMTP", + "domain_config_acme_eligible": "Elegibilidad ACME", + "global_settings_setting_ssh_password_authentication": "Autenticación por contraseña", + "domain_config_cert_issuer": "Autoridad de certificación", + "invalid_shell": "Shell inválido: {shell}" } From fd4ab9620c176a2b77cc69c6f0f3e206618d339a Mon Sep 17 00:00:00 2001 From: cristian amoyao Date: Wed, 25 Jan 2023 15:18:35 +0000 Subject: [PATCH 42/67] Translated using Weblate (Spanish) Currently translated at 100.0% (750 of 750 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/es/ --- locales/es.json | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/locales/es.json b/locales/es.json index 942c8dd13d..51bacba7ab 100644 --- a/locales/es.json +++ b/locales/es.json @@ -741,5 +741,12 @@ "domain_config_acme_eligible": "Elegibilidad ACME", "global_settings_setting_ssh_password_authentication": "Autenticación por contraseña", "domain_config_cert_issuer": "Autoridad de certificación", - "invalid_shell": "Shell inválido: {shell}" + "invalid_shell": "Shell inválido: {shell}", + "log_settings_reset": "Restablecer ajuste", + "migration_description_0026_new_admins_group": "Migrar al nuevo sistema de 'varios administradores'", + "visitors": "Visitantes", + "global_settings_setting_smtp_relay_host": "Host de retransmisión SMTP", + "migration_0024_rebuild_python_venv_disclaimer_rebuild": "Se intentará reconstruir el virtualenv para las siguientes apps (NB: ¡la operación puede llevar algún tiempo!): {rebuild_apps}", + "migration_description_0025_global_settings_to_configpanel": "Migración de la nomenclatura de ajustes globales heredada a la nomenclatura nueva y moderna", + "registrar_infos": "Información sobre el registrador" } From 31bc4d4f43dd19d5d18592af25a8fd94d02e2876 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alperen=20=C4=B0sa=20Nalbant?= Date: Mon, 30 Jan 2023 13:11:18 +0000 Subject: [PATCH 43/67] Translated using Weblate (Turkish) Currently translated at 2.2% (17 of 750 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/tr/ --- locales/tr.json | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/locales/tr.json b/locales/tr.json index 3ba829b957..6768f95e46 100644 --- a/locales/tr.json +++ b/locales/tr.json @@ -5,5 +5,15 @@ "already_up_to_date": "Yapılacak yeni bir şey yok. Her şey zaten güncel.", "app_action_broke_system": "Bu işlem bazı hizmetleri bozmuş olabilir: {services}", "good_practices_about_user_password": "Şimdi yeni bir kullanıcı şifresi tanımlamak üzeresiniz. Parola en az 8 karakter uzunluğunda olmalıdır - ancak daha uzun bir parola (yani bir parola) ve/veya çeşitli karakterler (büyük harf, küçük harf, rakamlar ve özel karakterler) daha iyidir.", - "aborting": "İptal ediliyor." -} \ No newline at end of file + "aborting": "İptal ediliyor.", + "app_action_failed": "{app} uygulaması için {action} eylemini çalıştırma başarısız", + "admins": "Yöneticiler", + "all_users": "Tüm YunoHost kullanıcıları", + "app_already_up_to_date": "{app} zaten güncel", + "app_already_installed": "{app} zaten kurulu", + "app_already_installed_cant_change_url": "Bu uygulama zaten kurulu. URL yalnızca bu işlev kullanarak değiştirilemez. Eğer varsa `app changeurl`'i kontrol edin.", + "additional_urls_already_added": "Ek URL '{url}' zaten '{permission}' izni için ek URL'ye eklendi", + "additional_urls_already_removed": "Ek URL '{url}', '{permission}' izni için ek URL'de zaten kaldırıldı", + "app_action_cannot_be_ran_because_required_services_down": "Bu eylemi gerçekleştirmek için şu servisler çalışıyor olmalıdır: {services}. Devam etmek için onları yeniden başlatın (ve muhtemelen neden çalışmadığını araştırın).", + "app_arch_not_supported": "Bu uygulama yalnızca {', '.join(required)} işlemci mimarisi üzerine kurulabilir ancak sunucunuzun işlemci mimarisi {current}." +} From 78036b555eb291562ae8af2130e0cedff17fc334 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Mon, 30 Jan 2023 15:48:10 +0100 Subject: [PATCH 44/67] Update changelog for 11.1.3.1 --- debian/changelog | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/debian/changelog b/debian/changelog index 10172fa9b7..fd3bcd742d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,12 @@ +yunohost (11.1.3.1) testing; urgency=low + + - nginx: add xmpp-upload. and muc. server_name only if xmpp_enabled is enabled (c444dee4) + - [i18n] Translations updated for Arabic, Basque, French, Galician, Spanish, Turkish + + Thanks to all contributors <3 ! (Alperen İsa Nalbant, ButterflyOfFire, cristian amoyao, Éric Gaspar, José M, Kayou, ppr, quiwy, xabirequejo) + + -- Alexandre Aubin Mon, 30 Jan 2023 15:44:30 +0100 + yunohost (11.1.3) testing; urgency=low - helpers: Include procedures in MySQL database backup ([#1570](https://github.com/yunohost/yunohost/pull/1570)) From b8f87e372d86b7f80485a60349a9023ad5826d2b Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Mon, 30 Jan 2023 16:14:49 +0100 Subject: [PATCH 45/67] dns_exposure setting: we don't want to regenconf nginx/postfix when values change --- src/settings.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/settings.py b/src/settings.py index 96f11caebd..d9ea600a43 100644 --- a/src/settings.py +++ b/src/settings.py @@ -310,7 +310,6 @@ def regen_ssowatconf(setting_name, old_value, new_value): @post_change_hook("nginx_compatibility") @post_change_hook("webadmin_allowlist_enabled") @post_change_hook("webadmin_allowlist") -@post_change_hook("dns_exposure") def reconfigure_nginx(setting_name, old_value, new_value): if old_value != new_value: regen_conf(names=["nginx"]) @@ -342,7 +341,6 @@ def reconfigure_ssh_and_fail2ban(setting_name, old_value, new_value): @post_change_hook("smtp_relay_user") @post_change_hook("smtp_relay_password") @post_change_hook("postfix_compatibility") -@post_change_hook("dns_exposure") def reconfigure_postfix(setting_name, old_value, new_value): if old_value != new_value: regen_conf(names=["postfix"]) From 56d3b4762b27eece9dfd37dce7dbbc03a6d1e497 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Mon, 30 Jan 2023 16:18:15 +0100 Subject: [PATCH 46/67] dns_exposure setting: add setting description + help --- locales/en.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/locales/en.json b/locales/en.json index 789ec5a4b5..98abb9812d 100644 --- a/locales/en.json +++ b/locales/en.json @@ -401,6 +401,8 @@ "firewall_rules_cmd_failed": "Some firewall rule commands have failed. More info in log.", "global_settings_reset_success": "Reset global settings", "global_settings_setting_passwordless_sudo": "Allow admins to use 'sudo' without re-typing their passwords", + "global_settings_setting_dns_exposure": "IP versions to consider for DNS configuration and diagnosis", + "global_settings_setting_dns_exposure_help": "NB: This only affects the recommended DNS configuration and diagnosis checks. This does not affect system configurations.", "global_settings_setting_admin_strength": "Admin password strength requirements", "global_settings_setting_admin_strength_help": "These requirements are only enforced when initializing or changing the password", "global_settings_setting_backup_compress_tar_archives": "Compress backups", From 26e539fea63f784955e52b567a4a8bdf68e2a547 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Mon, 30 Jan 2023 16:31:42 +0100 Subject: [PATCH 47/67] Update changelog for 11.1.4 --- debian/changelog | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/debian/changelog b/debian/changelog index fd3bcd742d..a6a30947ad 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +yunohost (11.1.4) testing; urgency=low + + - settings: Add DNS exposure setting given the IP version ([#1451](https://github.com/yunohost/yunohost/pull/1451)) + + Thanks to all contributors <3 ! (Tagada) + + -- Alexandre Aubin Mon, 30 Jan 2023 16:28:56 +0100 + yunohost (11.1.3.1) testing; urgency=low - nginx: add xmpp-upload. and muc. server_name only if xmpp_enabled is enabled (c444dee4) From 82d30f02e208f36433e5689d205ddd174555df98 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Mon, 30 Jan 2023 17:46:29 +0100 Subject: [PATCH 48/67] debian: don't dump upgradable apps during postinst's catalog update --- debian/postinst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/postinst b/debian/postinst index 3533174886..238817cd7b 100644 --- a/debian/postinst +++ b/debian/postinst @@ -30,7 +30,7 @@ do_configure() { yunohost diagnosis run --force echo "Refreshing app catalog..." - yunohost tools update apps || true + yunohost tools update apps --output-as none || true fi # Trick to let yunohost handle the restart of the API, From 2d024557a5784de37534cbca1461dbdc90ec68ca Mon Sep 17 00:00:00 2001 From: yunohost-bot Date: Mon, 30 Jan 2023 17:34:24 +0000 Subject: [PATCH 49/67] [CI] Format code with Black --- src/diagnosers/10-ip.py | 20 ++++++++++++++++---- src/diagnosers/14-ports.py | 10 ++++++++-- src/diagnosers/21-web.py | 18 ++++++++++++++---- src/diagnosers/24-mail.py | 8 ++++++-- 4 files changed, 44 insertions(+), 12 deletions(-) diff --git a/src/diagnosers/10-ip.py b/src/diagnosers/10-ip.py index 6b35731a05..a4df11dde8 100644 --- a/src/diagnosers/10-ip.py +++ b/src/diagnosers/10-ip.py @@ -120,12 +120,16 @@ def get_local_ip(version): return local_ip def is_ipvx_important(x): - return settings_get("misc.network.dns_exposure") in ["both", "ipv"+str(x)] + return settings_get("misc.network.dns_exposure") in ["both", "ipv" + str(x)] yield dict( meta={"test": "ipv4"}, data={"global": ipv4, "local": get_local_ip("ipv4")}, - status="SUCCESS" if ipv4 else "ERROR" if is_ipvx_important(4) else "WARNING", + status="SUCCESS" + if ipv4 + else "ERROR" + if is_ipvx_important(4) + else "WARNING", summary="diagnosis_ip_connected_ipv4" if ipv4 else "diagnosis_ip_no_ipv4", details=["diagnosis_ip_global", "diagnosis_ip_local"] if ipv4 else None, ) @@ -133,11 +137,19 @@ def is_ipvx_important(x): yield dict( meta={"test": "ipv6"}, data={"global": ipv6, "local": get_local_ip("ipv6")}, - status="SUCCESS" if ipv6 else "ERROR" if is_ipvx_important(6) else "WARNING", + status="SUCCESS" + if ipv6 + else "ERROR" + if is_ipvx_important(6) + else "WARNING", summary="diagnosis_ip_connected_ipv6" if ipv6 else "diagnosis_ip_no_ipv6", details=["diagnosis_ip_global", "diagnosis_ip_local"] if ipv6 - else ["diagnosis_ip_no_ipv6_tip_important" if is_ipvx_important(6) else "diagnosis_ip_no_ipv6_tip"], + else [ + "diagnosis_ip_no_ipv6_tip_important" + if is_ipvx_important(6) + else "diagnosis_ip_no_ipv6_tip" + ], ) # TODO / FIXME : add some attempt to detect ISP (using whois ?) ? diff --git a/src/diagnosers/14-ports.py b/src/diagnosers/14-ports.py index 57fb7cd98f..b3ea3d48df 100644 --- a/src/diagnosers/14-ports.py +++ b/src/diagnosers/14-ports.py @@ -47,7 +47,10 @@ def run(self): ipversions = [] ipv4 = Diagnoser.get_cached_report("ip", item={"test": "ipv4"}) or {} - if ipv4.get("status") == "SUCCESS" or settings_get("misc.network.dns_exposure") != "ipv6": + if ( + ipv4.get("status") == "SUCCESS" + or settings_get("misc.network.dns_exposure") != "ipv6" + ): ipversions.append(4) # To be discussed: we could also make this check dependent on the @@ -121,7 +124,10 @@ def ipv6_is_important(): for record in dnsrecords.get("items", []) ) - if (failed == 4 and settings_get("misc.network.dns_exposure") in ["both", "ipv4"]) or (failed == 6 and ipv6_is_important()): + if ( + failed == 4 + and settings_get("misc.network.dns_exposure") in ["both", "ipv4"] + ) or (failed == 6 and ipv6_is_important()): yield dict( meta={"port": port}, data={ diff --git a/src/diagnosers/21-web.py b/src/diagnosers/21-web.py index 25554fe9da..64775180c3 100644 --- a/src/diagnosers/21-web.py +++ b/src/diagnosers/21-web.py @@ -77,7 +77,9 @@ def run(self): ipversions = [] ipv4 = Diagnoser.get_cached_report("ip", item={"test": "ipv4"}) or {} - if ipv4.get("status") == "SUCCESS" and settings_get("misc.network.dns_exposure") in ["both", "ipv4"]: + if ipv4.get("status") == "SUCCESS" and settings_get( + "misc.network.dns_exposure" + ) in ["both", "ipv4"]: ipversions.append(4) # To be discussed: we could also make this check dependent on the @@ -97,7 +99,10 @@ def run(self): # "curl --head the.global.ip" will simply timeout... if self.do_hairpinning_test: global_ipv4 = ipv4.get("data", {}).get("global", None) - if global_ipv4 and settings_get("misc.network.dns_exposure") in ["both", "ipv4"]: + if global_ipv4 and settings_get("misc.network.dns_exposure") in [ + "both", + "ipv4", + ]: try: requests.head("http://" + global_ipv4, timeout=5) except requests.exceptions.Timeout: @@ -148,7 +153,10 @@ def test_http(self, domains, ipversions): if all( results[ipversion][domain]["status"] == "ok" for ipversion in ipversions ): - if 4 in ipversions and settings_get("misc.network.dns_exposure") in ["both", "ipv4"]: + if 4 in ipversions and settings_get("misc.network.dns_exposure") in [ + "both", + "ipv4", + ]: self.do_hairpinning_test = True yield dict( meta={"domain": domain}, @@ -186,7 +194,9 @@ def ipv6_is_important_for_this_domain(): ) AAAA_status = dnsrecords.get("data", {}).get("AAAA:@") - return AAAA_status in ["OK", "WRONG"] or settings_get("misc.network.dns_exposure") in ["both", "ipv6"] + return AAAA_status in ["OK", "WRONG"] or settings_get( + "misc.network.dns_exposure" + ) in ["both", "ipv6"] if failed == 4 or ipv6_is_important_for_this_domain(): yield dict( diff --git a/src/diagnosers/24-mail.py b/src/diagnosers/24-mail.py index 1ae1da8854..785f337033 100644 --- a/src/diagnosers/24-mail.py +++ b/src/diagnosers/24-mail.py @@ -302,13 +302,17 @@ def get_ips_checked(self): outgoing_ipversions = [] outgoing_ips = [] ipv4 = Diagnoser.get_cached_report("ip", {"test": "ipv4"}) or {} - if ipv4.get("status") == "SUCCESS" and settings_get("misc.network.dns_exposure") in ["both", "ipv4"]: + if ipv4.get("status") == "SUCCESS" and settings_get( + "misc.network.dns_exposure" + ) in ["both", "ipv4"]: outgoing_ipversions.append(4) global_ipv4 = ipv4.get("data", {}).get("global", {}) if global_ipv4: outgoing_ips.append(global_ipv4) - if settings_get("email.smtp.smtp_allow_ipv6") or settings_get("misc.network.dns_exposure") in ["both", "ipv6"]: + if settings_get("email.smtp.smtp_allow_ipv6") or settings_get( + "misc.network.dns_exposure" + ) in ["both", "ipv6"]: ipv6 = Diagnoser.get_cached_report("ip", {"test": "ipv6"}) or {} if ipv6.get("status") == "SUCCESS": outgoing_ipversions.append(6) From 90aa55599d8b35b5f06e54ebc5f754000af1a0c3 Mon Sep 17 00:00:00 2001 From: tituspijean Date: Tue, 31 Jan 2023 17:56:32 +0100 Subject: [PATCH 50/67] Output checksums if ynh_setup_source fails during their verification. --- helpers/utils | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helpers/utils b/helpers/utils index 344493ff3c..52ff245c8e 100644 --- a/helpers/utils +++ b/helpers/utils @@ -167,7 +167,7 @@ ynh_setup_source() { || ynh_die --message="$out" # Check the control sum echo "${src_sum} ${src_filename}" | ${src_sumprg} --check --status \ - || ynh_die --message="Corrupt source" + || ynh_die --message="Corrupt source for ${src_filename}: Expected ${src_sum} but got $(${src_sumprg} ${src_filename} | cut --delimiter=' ' --fields=1)." fi # Keep files to be backup/restored at the end of the helper From 7dd2b41eeff69cff92c3ad01d4de76b32d210611 Mon Sep 17 00:00:00 2001 From: tituspijean Date: Tue, 31 Jan 2023 18:07:25 +0100 Subject: [PATCH 51/67] Print size in error message if ynh_setup_source checksum fails Co-authored-by: Alexandre Aubin --- helpers/utils | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helpers/utils b/helpers/utils index 52ff245c8e..bc83888e98 100644 --- a/helpers/utils +++ b/helpers/utils @@ -167,7 +167,7 @@ ynh_setup_source() { || ynh_die --message="$out" # Check the control sum echo "${src_sum} ${src_filename}" | ${src_sumprg} --check --status \ - || ynh_die --message="Corrupt source for ${src_filename}: Expected ${src_sum} but got $(${src_sumprg} ${src_filename} | cut --delimiter=' ' --fields=1)." + || ynh_die --message="Corrupt source for ${src_filename}: Expected ${src_sum} but got $(${src_sumprg} ${src_filename} | cut --delimiter=' ' --fields=1) (size: $(du -hs ${src_filename} | cut --delimiter=' ' --fields=1))." fi # Keep files to be backup/restored at the end of the helper From c990cee63027f1c8669e72b4a65ab697c0279155 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 31 Jan 2023 18:17:08 +0100 Subject: [PATCH 52/67] metronome: Auto-enable/disable metronome if there's no/at least one domain configured for XMPP --- hooks/conf_regen/12-metronome | 18 ++++++++++++++++-- src/service.py | 4 ++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/hooks/conf_regen/12-metronome b/hooks/conf_regen/12-metronome index cad8d3805b..b039ace31c 100755 --- a/hooks/conf_regen/12-metronome +++ b/hooks/conf_regen/12-metronome @@ -74,8 +74,22 @@ do_post_regen() { chown -R metronome: /var/lib/metronome/ chown -R metronome: /etc/metronome/conf.d/ - [[ -z "$regen_conf_files" ]] \ - || systemctl restart metronome + if [[ -z "$(ls /etc/metronome/conf.d/*.cfg.lua 2>/dev/null)" ]] + then + if systemctl is-enabled metronome &>/dev/null + then + systemctl disable metronome --now 2>/dev/null + fi + else + if ! systemctl is-enabled metronome &>/dev/null + then + systemctl enable metronome --now 2>/dev/null + sleep 3 + fi + + [[ -z "$regen_conf_files" ]] \ + || systemctl restart metronome + fi } do_$1_regen ${@:2} diff --git a/src/service.py b/src/service.py index 1f1c35c446..e11c2b6090 100644 --- a/src/service.py +++ b/src/service.py @@ -712,6 +712,10 @@ def _get_services(): "category": "web", } + # Ignore metronome entirely if XMPP was disabled on all domains + if "metronome" in services and not glob("/etc/metronome/conf.d/*.cfg.lua"): + del services["metronome"] + # Remove legacy /var/log/daemon.log and /var/log/syslog from log entries # because they are too general. Instead, now the journalctl log is # returned by default which is more relevant. From 971b1b044ef32b9abe034859f802e8c81023f4a2 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 1 Feb 2023 17:11:31 +0100 Subject: [PATCH 53/67] Update changelog for 11.1.4.1 --- debian/changelog | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/debian/changelog b/debian/changelog index a6a30947ad..637a74bfd9 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,13 @@ +yunohost (11.1.4.1) testing; urgency=low + + - debian: don't dump upgradable apps during postinst's catalog update (82d30f02) + - ynh_setup_source: Output checksums when source is 'corrupt' ([#1578](https://github.com/yunohost/yunohost/pull/1578)) + - metronome: Auto-enable/disable metronome if there's no/at least one domain configured for XMPP (c990cee6) + + Thanks to all contributors <3 ! (tituspijean) + + -- Alexandre Aubin Wed, 01 Feb 2023 17:10:32 +0100 + yunohost (11.1.4) testing; urgency=low - settings: Add DNS exposure setting given the IP version ([#1451](https://github.com/yunohost/yunohost/pull/1451)) From ade92e431d7f95a297cddd8ac37311bcc3f65336 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 1 Feb 2023 17:55:32 +0100 Subject: [PATCH 54/67] diagnosis: we can't yield an ERROR if there's no IPv6, otherwise that blocks all subsequent network-related diagnoser because of the dependency system ... --- src/diagnosers/10-ip.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/diagnosers/10-ip.py b/src/diagnosers/10-ip.py index a4df11dde8..255b1165fb 100644 --- a/src/diagnosers/10-ip.py +++ b/src/diagnosers/10-ip.py @@ -140,7 +140,7 @@ def is_ipvx_important(x): status="SUCCESS" if ipv6 else "ERROR" - if is_ipvx_important(6) + if settings_get("misc.network.dns_exposure") == "ipv6" else "WARNING", summary="diagnosis_ip_connected_ipv6" if ipv6 else "diagnosis_ip_no_ipv6", details=["diagnosis_ip_global", "diagnosis_ip_local"] From b943c69c8be3b49626a84b074f9e61e3d925fbcd Mon Sep 17 00:00:00 2001 From: yunohost-bot Date: Wed, 1 Feb 2023 17:10:08 +0000 Subject: [PATCH 55/67] [CI] Format code with Black --- doc/generate_bash_completion.py | 2 -- doc/generate_helper_doc.py | 8 ----- doc/generate_manpages.py | 1 - doc/generate_resource_doc.py | 1 - maintenance/autofix_locale_format.py | 4 --- maintenance/missing_i18n_keys.py | 2 -- src/__init__.py | 4 --- src/app.py | 36 ------------------- src/app_catalog.py | 3 -- src/authenticators/ldap_admin.py | 5 --- src/backup.py | 9 ----- src/certificate.py | 12 ------- src/diagnosers/00-basesystem.py | 5 --- src/diagnosers/10-ip.py | 4 --- src/diagnosers/12-dnsrecords.py | 6 ---- src/diagnosers/14-ports.py | 2 -- src/diagnosers/21-web.py | 5 --- src/diagnosers/24-mail.py | 2 -- src/diagnosers/30-services.py | 3 -- src/diagnosers/50-systemresources.py | 3 -- src/diagnosers/70-regenconf.py | 3 -- src/diagnosers/80-apps.py | 4 --- src/diagnosis.py | 16 --------- src/dns.py | 12 ------- src/domain.py | 9 ----- src/dyndns.py | 2 -- src/firewall.py | 2 -- src/hook.py | 4 --- src/log.py | 6 ---- src/migrations/0021_migrate_to_bullseye.py | 6 ---- src/migrations/0022_php73_to_php74_pools.py | 2 -- src/migrations/0023_postgresql_11_to_13.py | 4 --- src/migrations/0024_rebuild_python_venv.py | 3 -- .../0025_global_settings_to_configpanel.py | 1 - src/migrations/0026_new_admins_group.py | 1 - src/permission.py | 4 --- src/regenconf.py | 4 --- src/service.py | 7 ---- src/settings.py | 6 ---- src/tests/conftest.py | 3 -- src/tests/test_app_catalog.py | 21 ----------- src/tests/test_app_config.py | 13 ------- src/tests/test_app_resources.py | 20 ----------- src/tests/test_apps.py | 36 ------------------- src/tests/test_appurl.py | 6 ---- src/tests/test_backuprestore.py | 33 ----------------- src/tests/test_dns.py | 3 -- src/tests/test_domains.py | 3 -- src/tests/test_ldapauth.py | 5 --- src/tests/test_permission.py | 3 -- src/tests/test_questions.py | 11 ------ src/tests/test_regenconf.py | 8 ----- src/tests/test_service.py | 15 -------- src/tests/test_settings.py | 2 -- src/tests/test_user-group.py | 4 --- src/tools.py | 17 --------- src/user.py | 11 ------ src/utils/config.py | 15 -------- src/utils/dns.py | 3 -- src/utils/error.py | 5 --- src/utils/ldap.py | 1 - src/utils/legacy.py | 7 ---- src/utils/network.py | 3 -- src/utils/password.py | 3 -- src/utils/resources.py | 28 --------------- src/utils/system.py | 7 ---- src/utils/yunopaste.py | 1 - 67 files changed, 500 deletions(-) diff --git a/doc/generate_bash_completion.py b/doc/generate_bash_completion.py index d55973010e..88aa273fd9 100644 --- a/doc/generate_bash_completion.py +++ b/doc/generate_bash_completion.py @@ -31,7 +31,6 @@ def get_dict_actions(OPTION_SUBTREE, category): with open(ACTIONSMAP_FILE, "r") as stream: - # Getting the dictionary containning what actions are possible per category OPTION_TREE = yaml.safe_load(stream) @@ -65,7 +64,6 @@ def get_dict_actions(OPTION_SUBTREE, category): os.makedirs(BASH_COMPLETION_FOLDER, exist_ok=True) with open(BASH_COMPLETION_FILE, "w") as generated_file: - # header of the file generated_file.write("#\n") generated_file.write("# completion for yunohost\n") diff --git a/doc/generate_helper_doc.py b/doc/generate_helper_doc.py index 5254825965..63fa109e60 100644 --- a/doc/generate_helper_doc.py +++ b/doc/generate_helper_doc.py @@ -20,7 +20,6 @@ def get_current_commit(): def render(helpers): - current_commit = get_current_commit() data = { @@ -56,20 +55,17 @@ def shell_to_html(shell): class Parser: def __init__(self, filename): - self.filename = filename self.file = open(filename, "r").readlines() self.blocks = None def parse_blocks(self): - self.blocks = [] current_reading = "void" current_block = {"name": None, "line": -1, "comments": [], "code": []} for i, line in enumerate(self.file): - if line.startswith("#!/bin/bash"): continue @@ -117,7 +113,6 @@ def parse_blocks(self): current_reading = "code" elif current_reading == "code": - if line == "}": # We're getting out of the function current_reading = "void" @@ -138,7 +133,6 @@ def parse_blocks(self): continue def parse_block(self, b): - b["brief"] = "" b["details"] = "" b["usage"] = "" @@ -164,7 +158,6 @@ def parse_block(self, b): elif subblock.startswith("usage"): for line in subblock.split("\n"): - if line.startswith("| arg"): linesplit = line.split() argname = linesplit[2] @@ -216,7 +209,6 @@ def malformed_error(line_number): def main(): - helper_files = sorted(glob.glob("../helpers/*")) helpers = [] diff --git a/doc/generate_manpages.py b/doc/generate_manpages.py index bdb1fcaeec..782dd8a90a 100644 --- a/doc/generate_manpages.py +++ b/doc/generate_manpages.py @@ -60,7 +60,6 @@ def main(): # man pages of "yunohost *" with open(ACTIONSMAP_FILE, "r") as actionsmap: - # Getting the dictionary containning what actions are possible per domain actionsmap = ordered_yaml_load(actionsmap) diff --git a/doc/generate_resource_doc.py b/doc/generate_resource_doc.py index 1e16a76d94..2063c4ab93 100644 --- a/doc/generate_resource_doc.py +++ b/doc/generate_resource_doc.py @@ -3,7 +3,6 @@ resources = sorted(AppResourceClassesByType.values(), key=lambda r: r.priority) for klass in resources: - doc = klass.__doc__.replace("\n ", "\n") print("") diff --git a/maintenance/autofix_locale_format.py b/maintenance/autofix_locale_format.py index 1c56ea3865..caa36f9f25 100644 --- a/maintenance/autofix_locale_format.py +++ b/maintenance/autofix_locale_format.py @@ -32,7 +32,6 @@ def _autofix_i18n_placeholders(locale_file): # We iterate over all keys/string in en.json for key, string in reference.items(): - # Ignore check if there's no translation yet for this key if key not in this_locale: continue @@ -89,7 +88,6 @@ def _autofix_i18n_placeholders(locale_file): def autofix_orthotypography_and_standardized_words(): def reformat(lang, transformations): - locale = open(f"{LOCALE_FOLDER}{lang}.json").read() for pattern, replace in transformations.items(): locale = re.compile(pattern).sub(replace, locale) @@ -146,11 +144,9 @@ def reformat(lang, transformations): def remove_stale_translated_strings(): - reference = json.loads(open(LOCALE_FOLDER + "en.json").read()) for locale_file in TRANSLATION_FILES: - print(locale_file) this_locale = json.loads( open(LOCALE_FOLDER + locale_file).read(), object_pairs_hook=OrderedDict diff --git a/maintenance/missing_i18n_keys.py b/maintenance/missing_i18n_keys.py index f49fc923e3..2ed7fd141a 100644 --- a/maintenance/missing_i18n_keys.py +++ b/maintenance/missing_i18n_keys.py @@ -19,7 +19,6 @@ def find_expected_string_keys(): - # Try to find : # m18n.n( "foo" # YunohostError("foo" @@ -197,7 +196,6 @@ def find_expected_string_keys(): mode = sys.argv[1].strip("-") if mode == "check": - # Unused keys are not too problematic, will be automatically # removed by the other autoreformat script, # but still informative to display them diff --git a/src/__init__.py b/src/__init__.py index af18e1fe45..4d4026fdf3 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -32,7 +32,6 @@ def is_installed(): def cli(debug, quiet, output_as, timeout, args, parser): - init_logging(interface="cli", debug=debug, quiet=quiet) # Check that YunoHost is installed @@ -51,7 +50,6 @@ def cli(debug, quiet, output_as, timeout, args, parser): def api(debug, host, port): - init_logging(interface="api", debug=debug) def is_installed_api(): @@ -71,7 +69,6 @@ def is_installed_api(): def check_command_is_valid_before_postinstall(args): - allowed_if_not_postinstalled = [ "tools postinstall", "tools versions", @@ -109,7 +106,6 @@ def init_i18n(): def init_logging(interface="cli", debug=False, quiet=False, logdir="/var/log/yunohost"): - logfile = os.path.join(logdir, "yunohost-%s.log" % interface) if not os.path.isdir(logdir): diff --git a/src/app.py b/src/app.py index 5b2e63e44d..205dec5053 100644 --- a/src/app.py +++ b/src/app.py @@ -238,7 +238,6 @@ def app_info(app, full=False, upgradable=False): def _app_upgradable(app_infos): - # Determine upgradability app_in_catalog = app_infos.get("from_catalog") @@ -374,7 +373,6 @@ def app_map(app=None, raw=False, user=None): ) for url in perm_all_urls: - # Here, we decide to completely ignore regex-type urls ... # Because : # - displaying them in regular "yunohost app map" output creates @@ -716,7 +714,6 @@ def app_upgrade(app=[], url=None, file=None, force=False, no_safety_backup=False ), ) finally: - # If upgrade failed, try to restore the safety backup if ( upgrade_failed @@ -762,7 +759,6 @@ def app_upgrade(app=[], url=None, file=None, force=False, no_safety_backup=False # If upgrade failed or broke the system, # raise an error and interrupt all other pending upgrades if upgrade_failed or broke_the_system: - # display this if there are remaining apps if apps[number + 1 :]: not_upgraded_apps = apps[number:] @@ -843,7 +839,6 @@ def app_upgrade(app=[], url=None, file=None, force=False, no_safety_backup=False def app_manifest(app, with_screenshot=False): - manifest, extracted_app_folder = _extract_app(app) raw_questions = manifest.get("install", {}).values() @@ -886,7 +881,6 @@ def app_manifest(app, with_screenshot=False): def _confirm_app_install(app, force=False): - # Ignore if there's nothing for confirm (good quality app), if --force is used # or if request on the API (confirm already implemented on the API side) if force or Moulinette.interface.type == "api": @@ -1036,7 +1030,6 @@ def app_install( # If packaging_format v2+, save all install questions as settings if packaging_format >= 2: for question in questions: - # Except user-provider passwords if question.type == "password": continue @@ -1135,7 +1128,6 @@ def app_install( # If the install failed or broke the system, we remove it if install_failed or broke_the_system: - # This option is meant for packagers to debug their apps more easily if no_remove_on_failure: raise YunohostError( @@ -1390,7 +1382,6 @@ def app_setting(app, key, value=None, delete=False): ) if is_legacy_permission_setting: - from yunohost.permission import ( user_permission_list, user_permission_update, @@ -1433,7 +1424,6 @@ def app_setting(app, key, value=None, delete=False): # SET else: - urls = value # If the request is about the root of the app (/), ( = the vast majority of cases) # we interpret this as a change for the main permission @@ -1445,7 +1435,6 @@ def app_setting(app, key, value=None, delete=False): else: user_permission_update(app + ".main", remove="visitors") else: - urls = urls.split(",") if key.endswith("_regex"): urls = ["re:" + url for url in urls] @@ -1604,7 +1593,6 @@ def app_ssowatconf(): ) for app in _installed_apps(): - app_settings = read_yaml(APPS_SETTING_PATH + app + "/settings.yml") or {} # Redirected @@ -1630,7 +1618,6 @@ def app_ssowatconf(): # New permission system for perm_name, perm_info in all_permissions.items(): - uris = ( [] + ([perm_info["url"]] if perm_info["url"] else []) @@ -1694,13 +1681,11 @@ def app_change_label(app, new_label): def app_action_list(app): - return AppConfigPanel(app).list_actions() @is_unit_operation() def app_action_run(operation_logger, app, action, args=None, args_file=None): - return AppConfigPanel(app).run_action( action, args=args, args_file=args_file, operation_logger=operation_logger ) @@ -2036,12 +2021,10 @@ def _get_manifest_of_app(path): def _parse_app_doc_and_notifications(path): - doc = {} notification_names = ["PRE_INSTALL", "POST_INSTALL", "PRE_UPGRADE", "POST_UPGRADE"] for filepath in glob.glob(os.path.join(path, "doc") + "/*.md"): - # to be improved : [a-z]{2,3} is a clumsy way of parsing the # lang code ... some lang code are more complex that this é_è m = re.match("([A-Z]*)(_[a-z]{2,3})?.md", filepath.split("/")[-1]) @@ -2091,11 +2074,9 @@ def _parse_app_doc_and_notifications(path): def _hydrate_app_template(template, data): - stuff_to_replace = set(re.findall(r"__[A-Z0-9]+?[A-Z0-9_]*?[A-Z0-9]*?__", template)) for stuff in stuff_to_replace: - varname = stuff.strip("_").lower() if varname in data: @@ -2105,7 +2086,6 @@ def _hydrate_app_template(template, data): def _convert_v1_manifest_to_v2(manifest): - manifest = copy.deepcopy(manifest) if "upstream" not in manifest: @@ -2186,7 +2166,6 @@ def _convert_v1_manifest_to_v2(manifest): def _set_default_ask_questions(questions, script_name="install"): - # arguments is something like # { "domain": # { @@ -2244,7 +2223,6 @@ def _set_default_ask_questions(questions, script_name="install"): def _is_app_repo_url(string: str) -> bool: - string = string.strip() # Dummy test for ssh-based stuff ... should probably be improved somehow @@ -2261,7 +2239,6 @@ def _app_quality(src: str) -> str: raw_app_catalog = _load_apps_catalog()["apps"] if src in raw_app_catalog or _is_app_repo_url(src): - # If we got an app name directly (e.g. just "wordpress"), we gonna test this name if src in raw_app_catalog: app_name_to_test = src @@ -2274,7 +2251,6 @@ def _app_quality(src: str) -> str: return "thirdparty" if app_name_to_test in raw_app_catalog: - state = raw_app_catalog[app_name_to_test].get("state", "notworking") level = raw_app_catalog[app_name_to_test].get("level", None) if state in ["working", "validated"]: @@ -2385,7 +2361,6 @@ def _extract_app_from_folder(path: str) -> Tuple[Dict, str]: def _extract_app_from_gitrepo( url: str, branch: Optional[str] = None, revision: str = "HEAD", app_info: Dict = {} ) -> Tuple[Dict, str]: - logger.debug("Checking default branch") try: @@ -2635,7 +2610,6 @@ def _check_manifest_requirements( def _guess_webapp_path_requirement(app_folder: str) -> str: - # If there's only one "domain" and "path", validate that domain/path # is an available url and normalize the path. @@ -2681,7 +2655,6 @@ def _guess_webapp_path_requirement(app_folder: str) -> str: def _validate_webpath_requirement( args: Dict[str, Any], path_requirement: str, ignore_app=None ) -> None: - domain = args.get("domain") path = args.get("path") @@ -2729,7 +2702,6 @@ def _get_conflicting_apps(domain, path, ignore_app=None): def _assert_no_conflicting_apps(domain, path, ignore_app=None, full_domain=False): - conflicts = _get_conflicting_apps(domain, path, ignore_app) if conflicts: @@ -2748,7 +2720,6 @@ def _assert_no_conflicting_apps(domain, path, ignore_app=None, full_domain=False def _make_environment_for_app_script( app, args={}, args_prefix="APP_ARG_", workdir=None, action=None ): - app_setting_path = os.path.join(APPS_SETTING_PATH, app) manifest = _get_manifest_of_app(app_setting_path) @@ -2777,7 +2748,6 @@ def _make_environment_for_app_script( if manifest["packaging_format"] >= 2: env_dict["app"] = app for setting_name, setting_value in _get_app_settings(app).items(): - # Ignore special internal settings like checksum__ # (not a huge deal to load them but idk...) if setting_name.startswith("checksum__"): @@ -2822,7 +2792,6 @@ def _parse_app_instance_name(app_instance_name: str) -> Tuple[str, int]: def _next_instance_number_for_app(app): - # Get list of sibling apps, such as {app}, {app}__2, {app}__4 apps = _installed_apps() sibling_app_ids = [a for a in apps if a == app or a.startswith(f"{app}__")] @@ -2840,7 +2809,6 @@ def _next_instance_number_for_app(app): def _make_tmp_workdir_for_app(app=None): - # Create parent dir if it doesn't exists yet if not os.path.exists(APP_TMP_WORKDIRS): os.makedirs(APP_TMP_WORKDIRS) @@ -2870,12 +2838,10 @@ def _make_tmp_workdir_for_app(app=None): def unstable_apps(): - output = [] deprecated_apps = ["mailman", "ffsync"] for infos in app_list(full=True)["apps"]: - if ( not infos.get("from_catalog") or infos.get("from_catalog").get("state") @@ -2891,7 +2857,6 @@ def unstable_apps(): def _assert_system_is_sane_for_app(manifest, when): - from yunohost.service import service_status logger.debug("Checking that required services are up and running...") @@ -2954,7 +2919,6 @@ def replace_alias(service): def app_dismiss_notification(app, name): - assert isinstance(name, str) name = name.lower() assert name in ["post_install", "post_upgrade"] diff --git a/src/app_catalog.py b/src/app_catalog.py index 5d43785440..59d2ebdc1c 100644 --- a/src/app_catalog.py +++ b/src/app_catalog.py @@ -157,7 +157,6 @@ def _read_apps_catalog_list(): def _actual_apps_catalog_api_url(base_url): - return f"{base_url}/v{APPS_CATALOG_API_VERSION}/apps.json" @@ -269,7 +268,6 @@ def _load_apps_catalog(): merged_catalog = {"apps": {}, "categories": [], "antifeatures": []} for apps_catalog_id in [L["id"] for L in _read_apps_catalog_list()]: - # Let's load the json from cache for this catalog cache_file = f"{APPS_CATALOG_CACHE}/{apps_catalog_id}.json" @@ -298,7 +296,6 @@ def _load_apps_catalog(): # Add apps from this catalog to the output for app, info in apps_catalog_content["apps"].items(): - # (N.B. : there's a small edge case where multiple apps catalog could be listing the same apps ... # in which case we keep only the first one found) if app in merged_catalog["apps"]: diff --git a/src/authenticators/ldap_admin.py b/src/authenticators/ldap_admin.py index 22b796e235..8637b38339 100644 --- a/src/authenticators/ldap_admin.py +++ b/src/authenticators/ldap_admin.py @@ -38,14 +38,12 @@ class Authenticator(BaseAuthenticator): - name = "ldap_admin" def __init__(self, *args, **kwargs): pass def _authenticate_credentials(self, credentials=None): - try: admins = ( _get_ldap_interface() @@ -125,7 +123,6 @@ def _reconnect(): con.unbind_s() def set_session_cookie(self, infos): - from bottle import response assert isinstance(infos, dict) @@ -145,7 +142,6 @@ def set_session_cookie(self, infos): ) def get_session_cookie(self, raise_if_no_session_exists=True): - from bottle import request try: @@ -174,7 +170,6 @@ def get_session_cookie(self, raise_if_no_session_exists=True): return infos def delete_session_cookie(self): - from bottle import response response.set_cookie("yunohost.admin", "", max_age=-1) diff --git a/src/backup.py b/src/backup.py index c3e47bddc7..0783996b9a 100644 --- a/src/backup.py +++ b/src/backup.py @@ -93,7 +93,6 @@ class BackupRestoreTargetsManager: """ def __init__(self): - self.targets = {} self.results = {"system": {}, "apps": {}} @@ -349,7 +348,6 @@ def _init_work_dir(self): if not os.path.isdir(self.work_dir): mkdir(self.work_dir, 0o750, parents=True) elif self.is_tmp_work_dir: - logger.debug( "temporary directory for backup '%s' already exists... attempting to clean it", self.work_dir, @@ -887,7 +885,6 @@ def __init__(self, name, method="tar"): @property def success(self): - successful_apps = self.targets.list("apps", include=["Success", "Warning"]) successful_system = self.targets.list("system", include=["Success", "Warning"]) @@ -1443,7 +1440,6 @@ def copytree(src, dst, symlinks=False, ignore=None): existing_groups = user_group_list()["groups"] for permission_name, permission_infos in permissions.items(): - if "allowed" not in permission_infos: logger.warning( f"'allowed' key corresponding to allowed groups for permission {permission_name} not found when restoring app {app_instance_name} … You might have to reconfigure permissions yourself." @@ -1547,7 +1543,6 @@ def copytree(src, dst, symlinks=False, ignore=None): self.targets.set_result("apps", app_instance_name, "Success") operation_logger.success() else: - self.targets.set_result("apps", app_instance_name, "Error") remove_script = os.path.join(app_scripts_in_archive, "remove") @@ -1938,12 +1933,10 @@ def copy(self, file, target): class TarBackupMethod(BackupMethod): - method_name = "tar" @property def _archive_file(self): - if isinstance(self.manager, BackupManager) and settings_get( "misc.backup.backup_compress_tar_archives" ): @@ -2430,7 +2423,6 @@ def remove_extension(f): def backup_download(name): - if Moulinette.interface.type != "api": logger.error( "This option is only meant for the API/webadmin and doesn't make sense for the command line." @@ -2571,7 +2563,6 @@ def backup_info(name, with_details=False, human_readable=False): if "size_details" in info.keys(): for category in ["apps", "system"]: for name, key_info in info[category].items(): - if category == "system": # Stupid legacy fix for weird format between 3.5 and 3.6 if isinstance(key_info, dict): diff --git a/src/certificate.py b/src/certificate.py index 928bea4998..0addca8582 100644 --- a/src/certificate.py +++ b/src/certificate.py @@ -124,10 +124,8 @@ def certificate_install(domain_list, force=False, no_checks=False, self_signed=F def _certificate_install_selfsigned(domain_list, force=False): - failed_cert_install = [] for domain in domain_list: - operation_logger = OperationLogger( "selfsigned_cert_install", [("domain", domain)], args={"force": force} ) @@ -238,7 +236,6 @@ def _certificate_install_letsencrypt(domains, force=False, no_checks=False): # certificates if domains == []: for domain in domain_list()["domains"]: - status = _get_status(domain) if status["CA_type"] != "selfsigned": continue @@ -260,7 +257,6 @@ def _certificate_install_letsencrypt(domains, force=False, no_checks=False): # Actual install steps failed_cert_install = [] for domain in domains: - if not no_checks: try: _check_domain_is_ready_for_ACME(domain) @@ -317,7 +313,6 @@ def certificate_renew(domains, force=False, no_checks=False, email=False): # certificates if domains == []: for domain in domain_list()["domains"]: - # Does it have a Let's Encrypt cert? status = _get_status(domain) if status["CA_type"] != "letsencrypt": @@ -342,7 +337,6 @@ def certificate_renew(domains, force=False, no_checks=False, email=False): # Else, validate the domain list given else: for domain in domains: - # Is it in Yunohost domain list? _assert_domain_exists(domain) @@ -369,7 +363,6 @@ def certificate_renew(domains, force=False, no_checks=False, email=False): # Actual renew steps failed_cert_install = [] for domain in domains: - if not no_checks: try: _check_domain_is_ready_for_ACME(domain) @@ -468,13 +461,11 @@ def _email_renewing_failed(domain, exception_message, stack=""): def _check_acme_challenge_configuration(domain): - domain_conf = f"/etc/nginx/conf.d/{domain}.conf" return "include /etc/nginx/conf.d/acme-challenge.conf.inc" in read_file(domain_conf) def _fetch_and_enable_new_certificate(domain, no_checks=False): - if not os.path.exists(ACCOUNT_KEY_FILE): _generate_account_key() @@ -628,7 +619,6 @@ def _prepare_certificate_signing_request(domain, key_file, output_folder): def _get_status(domain): - cert_file = os.path.join(CERT_FOLDER, domain, "crt.pem") if not os.path.isfile(cert_file): @@ -777,7 +767,6 @@ def _backup_current_cert(domain): def _check_domain_is_ready_for_ACME(domain): - from yunohost.domain import _get_parent_domain_of from yunohost.dns import _get_dns_zone_for_domain from yunohost.utils.dns import is_yunohost_dyndns_domain @@ -866,7 +855,6 @@ def _regen_dnsmasq_if_needed(): # For all domain files in DNSmasq conf... domainsconf = glob.glob("/etc/dnsmasq.d/*.*") for domainconf in domainsconf: - # Look for the IP, it's in the lines with this format : # host-record=the.domain.tld,11.22.33.44 for line in open(domainconf).readlines(): diff --git a/src/diagnosers/00-basesystem.py b/src/diagnosers/00-basesystem.py index 5793a00aae..8be3344061 100644 --- a/src/diagnosers/00-basesystem.py +++ b/src/diagnosers/00-basesystem.py @@ -35,13 +35,11 @@ class MyDiagnoser(Diagnoser): - id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1] cache_duration = 600 dependencies: List[str] = [] def run(self): - virt = system_virt() if virt.lower() == "none": virt = "bare-metal" @@ -193,7 +191,6 @@ def run(self): ) def bad_sury_packages(self): - packages_to_check = ["openssl", "libssl1.1", "libssl-dev"] for package in packages_to_check: cmd = "dpkg --list | grep '^ii' | grep gbp | grep -q -w %s" % package @@ -209,12 +206,10 @@ def bad_sury_packages(self): yield (package, version_to_downgrade_to) def backports_in_sources_list(self): - cmd = "grep -q -nr '^ *deb .*-backports' /etc/apt/sources.list*" return os.system(cmd) == 0 def number_of_recent_auth_failure(self): - # Those syslog facilities correspond to auth and authpriv # c.f. https://unix.stackexchange.com/a/401398 # and https://wiki.archlinux.org/title/Systemd/Journal#Facility diff --git a/src/diagnosers/10-ip.py b/src/diagnosers/10-ip.py index 255b1165fb..ea68fc7bbb 100644 --- a/src/diagnosers/10-ip.py +++ b/src/diagnosers/10-ip.py @@ -34,13 +34,11 @@ class MyDiagnoser(Diagnoser): - id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1] cache_duration = 600 dependencies: List[str] = [] def run(self): - # ############################################################ # # PING : Check that we can ping outside at least in ipv4 or v6 # # ############################################################ # @@ -155,7 +153,6 @@ def is_ipvx_important(x): # TODO / FIXME : add some attempt to detect ISP (using whois ?) ? def can_ping_outside(self, protocol=4): - assert protocol in [ 4, 6, @@ -234,7 +231,6 @@ def good_resolvconf(self): return len(content) == 1 and content[0].split() == ["nameserver", "127.0.0.1"] def get_public_ip(self, protocol=4): - # FIXME - TODO : here we assume that DNS resolution for ip.yunohost.org is working # but if we want to be able to diagnose DNS resolution issues independently from # internet connectivity, we gotta rely on fixed IPs first.... diff --git a/src/diagnosers/12-dnsrecords.py b/src/diagnosers/12-dnsrecords.py index 92d795ea94..58bd04d39a 100644 --- a/src/diagnosers/12-dnsrecords.py +++ b/src/diagnosers/12-dnsrecords.py @@ -43,13 +43,11 @@ class MyDiagnoser(Diagnoser): - id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1] cache_duration = 600 dependencies: List[str] = ["ip"] def run(self): - main_domain = _get_maindomain() major_domains = domain_list(exclude_subdomains=True)["domains"] @@ -77,7 +75,6 @@ def run(self): yield report def check_domain(self, domain, is_main_domain): - if is_special_use_tld(domain): yield dict( meta={"domain": domain}, @@ -97,13 +94,11 @@ def check_domain(self, domain, is_main_domain): categories = ["basic", "mail", "xmpp", "extra"] for category in categories: - records = expected_configuration[category] discrepancies = [] results = {} for r in records: - id_ = r["type"] + ":" + r["name"] fqdn = r["name"] + "." + base_dns_zone if r["name"] != "@" else domain @@ -182,7 +177,6 @@ def its_important(): yield output def get_current_record(self, fqdn, type_): - success, answers = dig(fqdn, type_, resolvers="force_external") if success != "ok": diff --git a/src/diagnosers/14-ports.py b/src/diagnosers/14-ports.py index b3ea3d48df..12f2481f7b 100644 --- a/src/diagnosers/14-ports.py +++ b/src/diagnosers/14-ports.py @@ -25,13 +25,11 @@ class MyDiagnoser(Diagnoser): - id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1] cache_duration = 600 dependencies: List[str] = ["ip"] def run(self): - # TODO: report a warning if port 53 or 5353 is exposed to the outside world... # This dict is something like : diff --git a/src/diagnosers/21-web.py b/src/diagnosers/21-web.py index 64775180c3..a12a83f94e 100644 --- a/src/diagnosers/21-web.py +++ b/src/diagnosers/21-web.py @@ -32,17 +32,14 @@ class MyDiagnoser(Diagnoser): - id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1] cache_duration = 600 dependencies: List[str] = ["ip"] def run(self): - all_domains = domain_list()["domains"] domains_to_check = [] for domain in all_domains: - # If the diagnosis location ain't defined, can't do diagnosis, # probably because nginx conf manually modified... nginx_conf = "/etc/nginx/conf.d/%s.conf" % domain @@ -119,7 +116,6 @@ def run(self): pass def test_http(self, domains, ipversions): - results = {} for ipversion in ipversions: try: @@ -144,7 +140,6 @@ def test_http(self, domains, ipversions): return for domain in domains: - # i18n: diagnosis_http_bad_status_code # i18n: diagnosis_http_connection_error # i18n: diagnosis_http_timeout diff --git a/src/diagnosers/24-mail.py b/src/diagnosers/24-mail.py index 785f337033..d48b1959ed 100644 --- a/src/diagnosers/24-mail.py +++ b/src/diagnosers/24-mail.py @@ -39,13 +39,11 @@ class MyDiagnoser(Diagnoser): - id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1] cache_duration = 600 dependencies: List[str] = ["ip"] def run(self): - self.ehlo_domain = _get_maindomain() self.mail_domains = domain_list()["domains"] self.ipversions, self.ips = self.get_ips_checked() diff --git a/src/diagnosers/30-services.py b/src/diagnosers/30-services.py index 7adfd7c011..44bbf17458 100644 --- a/src/diagnosers/30-services.py +++ b/src/diagnosers/30-services.py @@ -24,17 +24,14 @@ class MyDiagnoser(Diagnoser): - id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1] cache_duration = 300 dependencies: List[str] = [] def run(self): - all_result = service_status() for service, result in sorted(all_result.items()): - item = dict( meta={"service": service}, data={ diff --git a/src/diagnosers/50-systemresources.py b/src/diagnosers/50-systemresources.py index 50933b9f9e..10a153c618 100644 --- a/src/diagnosers/50-systemresources.py +++ b/src/diagnosers/50-systemresources.py @@ -28,13 +28,11 @@ class MyDiagnoser(Diagnoser): - id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1] cache_duration = 300 dependencies: List[str] = [] def run(self): - MB = 1024**2 GB = MB * 1024 @@ -189,7 +187,6 @@ def recent_kills_by_oom_reaper(self): return [] def analyzed_kern_log(): - cmd = 'tail -n 10000 /var/log/kern.log | grep "oom_reaper: reaped process" || true' out = check_output(cmd) lines = out.split("\n") if out else [] diff --git a/src/diagnosers/70-regenconf.py b/src/diagnosers/70-regenconf.py index 8c0bf74ccd..7d11b91744 100644 --- a/src/diagnosers/70-regenconf.py +++ b/src/diagnosers/70-regenconf.py @@ -27,13 +27,11 @@ class MyDiagnoser(Diagnoser): - id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1] cache_duration = 300 dependencies: List[str] = [] def run(self): - regenconf_modified_files = list(self.manually_modified_files()) if not regenconf_modified_files: @@ -82,7 +80,6 @@ def run(self): ) def manually_modified_files(self): - for category, infos in _get_regenconf_infos().items(): for path, hash_ in infos["conffiles"].items(): if hash_ != _calculate_hash(path): diff --git a/src/diagnosers/80-apps.py b/src/diagnosers/80-apps.py index faff925e67..ae89f26d3a 100644 --- a/src/diagnosers/80-apps.py +++ b/src/diagnosers/80-apps.py @@ -25,13 +25,11 @@ class MyDiagnoser(Diagnoser): - id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1] cache_duration = 300 dependencies: List[str] = [] def run(self): - apps = app_list(full=True)["apps"] for app in apps: app["issues"] = list(self.issues(app)) @@ -44,7 +42,6 @@ def run(self): ) else: for app in apps: - if not app["issues"]: continue @@ -62,7 +59,6 @@ def run(self): ) def issues(self, app): - # Check quality level in catalog if not app.get("from_catalog") or app["from_catalog"].get("state") != "working": diff --git a/src/diagnosis.py b/src/diagnosis.py index 2dff6a40d1..6b9f8fa929 100644 --- a/src/diagnosis.py +++ b/src/diagnosis.py @@ -45,7 +45,6 @@ def diagnosis_list(): def diagnosis_get(category, item): - # Get all the categories all_categories_names = _list_diagnosis_categories() @@ -69,7 +68,6 @@ def diagnosis_get(category, item): def diagnosis_show( categories=[], issues=False, full=False, share=False, human_readable=False ): - if not os.path.exists(DIAGNOSIS_CACHE): logger.warning(m18n.n("diagnosis_never_ran_yet")) return @@ -90,7 +88,6 @@ def diagnosis_show( # Fetch all reports all_reports = [] for category in categories: - try: report = Diagnoser.get_cached_report(category) except Exception as e: @@ -139,7 +136,6 @@ def diagnosis_show( def _dump_human_readable_reports(reports): - output = "" for report in reports: @@ -159,7 +155,6 @@ def _dump_human_readable_reports(reports): def diagnosis_run( categories=[], force=False, except_if_never_ran_yet=False, email=False ): - if (email or except_if_never_ran_yet) and not os.path.exists(DIAGNOSIS_CACHE): return @@ -263,7 +258,6 @@ def _diagnosis_ignore(add_filter=None, remove_filter=None, list=False): return {"ignore_filters": configuration.get("ignore_filters", {})} def validate_filter_criterias(filter_): - # Get all the categories all_categories_names = _list_diagnosis_categories() @@ -286,7 +280,6 @@ def validate_filter_criterias(filter_): return category, criterias if add_filter: - category, criterias = validate_filter_criterias(add_filter) # Fetch current issues for the requested category @@ -320,7 +313,6 @@ def validate_filter_criterias(filter_): return if remove_filter: - category, criterias = validate_filter_criterias(remove_filter) # Make sure the subdicts/lists exists @@ -394,12 +386,10 @@ def add_ignore_flag_to_issues(report): class Diagnoser: def __init__(self): - self.cache_file = Diagnoser.cache_file(self.id_) self.description = Diagnoser.get_description(self.id_) def cached_time_ago(self): - if not os.path.exists(self.cache_file): return 99999999 return time.time() - os.path.getmtime(self.cache_file) @@ -410,7 +400,6 @@ def write_cache(self, report): return write_to_json(self.cache_file, report) def diagnose(self, force=False): - if not force and self.cached_time_ago() < self.cache_duration: logger.debug(f"Cache still valid : {self.cache_file}") logger.info( @@ -548,7 +537,6 @@ def get_description(id_): @staticmethod def i18n(report, force_remove_html_tags=False): - # "Render" the strings with m18n.n # N.B. : we do those m18n.n right now instead of saving the already-translated report # because we can't be sure we'll redisplay the infos with the same locale as it @@ -558,7 +546,6 @@ def i18n(report, force_remove_html_tags=False): report["description"] = Diagnoser.get_description(report["id"]) for item in report["items"]: - # For the summary and each details, we want to call # m18n() on the string, with the appropriate data for string # formatting which can come from : @@ -597,7 +584,6 @@ def m18n_(info): @staticmethod def remote_diagnosis(uri, data, ipversion, timeout=30): - # Lazy loading for performance import requests import socket @@ -646,7 +632,6 @@ def getaddrinfo_ipv6_only(*args, **kwargs): def _list_diagnosis_categories(): - paths = glob.glob(os.path.dirname(__file__) + "/diagnosers/??-*.py") names = [ name.split("-")[-1] @@ -657,7 +642,6 @@ def _list_diagnosis_categories(): def _load_diagnoser(diagnoser_name): - logger.debug(f"Loading diagnoser {diagnoser_name}") paths = glob.glob(os.path.dirname(__file__) + f"/diagnosers/??-{diagnoser_name}.py") diff --git a/src/dns.py b/src/dns.py index d56e8e625d..e697e6324f 100644 --- a/src/dns.py +++ b/src/dns.py @@ -169,7 +169,6 @@ def _build_dns_conf(base_domain, include_empty_AAAA_if_no_ipv6=False): base_dns_zone = _get_dns_zone_for_domain(base_domain) for domain, settings in domains_settings.items(): - # Domain # Base DNS zone # Basename # Suffix # # ------------------ # ----------------- # --------- # -------- # # domain.tld # domain.tld # @ # # @@ -462,7 +461,6 @@ def _get_dns_zone_for_domain(domain): # We don't wan't to do A NS request on the tld for parent in parent_list[0:-1]: - # Check if there's a NS record for that domain answer = dig(parent, rdtype="NS", full_answers=True, resolvers="force_external") @@ -503,7 +501,6 @@ def _get_relative_name_for_dns_zone(domain, base_dns_zone): def _get_registrar_config_section(domain): - from lexicon.providers.auto import _relevant_provider_for_domain registrar_infos = { @@ -517,7 +514,6 @@ def _get_registrar_config_section(domain): # If parent domain exists in yunohost parent_domain = _get_parent_domain_of(domain, topest=True) if parent_domain: - # Dirty hack to have a link on the webadmin if Moulinette.interface.type == "api": parent_domain_link = f"[{parent_domain}](#/domains/{parent_domain}/dns)" @@ -572,7 +568,6 @@ def _get_registrar_config_section(domain): } ) else: - registrar_infos["registrar"] = OrderedDict( { "type": "alert", @@ -606,7 +601,6 @@ def _get_registrar_config_section(domain): def _get_registar_settings(domain): - _assert_domain_exists(domain) settings = domain_config_get(domain, key="dns.registrar", export=True) @@ -670,7 +664,6 @@ def domain_dns_push(operation_logger, domain, dry_run=False, force=False, purge= wanted_records = [] for records in _build_dns_conf(domain).values(): for record in records: - # Make sure the name is a FQDN name = ( f"{record['name']}.{base_dns_zone}" @@ -745,7 +738,6 @@ def domain_dns_push(operation_logger, domain, dry_run=False, force=False, purge= ] for record in current_records: - # Try to get rid of weird stuff like ".domain.tld" or "@.domain.tld" record["name"] = record["name"].strip("@").strip(".") @@ -795,7 +787,6 @@ def domain_dns_push(operation_logger, domain, dry_run=False, force=False, purge= comparison[(record["type"], record["name"])]["wanted"].append(record) for type_and_name, records in comparison.items(): - # # Step 1 : compute a first "diff" where we remove records which are the same on both sides # @@ -939,9 +930,7 @@ def progress(info=""): results = {"warnings": [], "errors": []} for action in ["delete", "create", "update"]: - for record in changes[action]: - relative_name = _get_relative_name_for_dns_zone( record["name"], base_dns_zone ) @@ -1026,7 +1015,6 @@ def _set_managed_dns_records_hashes(domain: str, hashes: list) -> None: def _hash_dns_record(record: dict) -> int: - fields = ["name", "type", "content"] record_ = {f: record.get(f) for f in fields} diff --git a/src/domain.py b/src/domain.py index fbe147fcea..5728c68844 100644 --- a/src/domain.py +++ b/src/domain.py @@ -187,7 +187,6 @@ def _assert_domain_exists(domain): def _list_subdomains_of(parent_domain): - _assert_domain_exists(parent_domain) out = [] @@ -199,7 +198,6 @@ def _list_subdomains_of(parent_domain): def _get_parent_domain_of(domain, return_self=False, topest=False): - domains = _get_domains(exclude_subdomains=topest) domain_ = domain @@ -248,7 +246,6 @@ def domain_add(operation_logger, domain, dyndns=False): # DynDNS domain if dyndns: - from yunohost.utils.dns import is_yunohost_dyndns_domain from yunohost.dyndns import _guess_current_dyndns_domain @@ -589,7 +586,6 @@ def _apply(self): regen_conf(names=stuff_to_regen_conf) def _get_toml(self): - toml = super()._get_toml() toml["feature"]["xmpp"]["xmpp"]["default"] = ( @@ -611,7 +607,6 @@ def _get_toml(self): # Cert stuff if not filter_key or filter_key[0] == "cert": - from yunohost.certificate import certificate_status status = certificate_status([self.entity], full=True)["certificates"][ @@ -638,7 +633,6 @@ def _get_toml(self): return toml def _load_current_values(self): - # TODO add mechanism to share some settings with other domains on the same zone super()._load_current_values() @@ -656,7 +650,6 @@ def _load_current_values(self): def domain_action_run(domain, action, args=None): - import urllib.parse if action == "cert.cert.cert_install": @@ -671,7 +664,6 @@ def domain_action_run(domain, action, args=None): def _get_domain_settings(domain: str) -> dict: - _assert_domain_exists(domain) if os.path.exists(f"{DOMAIN_SETTINGS_DIR}/{domain}.yml"): @@ -681,7 +673,6 @@ def _get_domain_settings(domain: str) -> dict: def _set_domain_settings(domain: str, settings: dict) -> None: - _assert_domain_exists(domain) write_to_yaml(f"{DOMAIN_SETTINGS_DIR}/{domain}.yml", settings) diff --git a/src/dyndns.py b/src/dyndns.py index 217cf2e158..9cba360ab2 100644 --- a/src/dyndns.py +++ b/src/dyndns.py @@ -227,7 +227,6 @@ def dyndns_update( for dns_auth in DYNDNS_DNS_AUTH: for type_ in ["A", "AAAA"]: - ok, result = dig(dns_auth, type_) if ok == "ok" and len(result) and result[0]: auth_resolvers.append(result[0]) @@ -238,7 +237,6 @@ def dyndns_update( ) def resolve_domain(domain, rdtype): - ok, result = dig(domain, rdtype, resolvers=auth_resolvers) if ok == "ok": return result[0] if len(result) else None diff --git a/src/firewall.py b/src/firewall.py index 6cf68f1f78..f4d7f77fe8 100644 --- a/src/firewall.py +++ b/src/firewall.py @@ -415,7 +415,6 @@ def firewall_upnp(action="status", no_refresh=False): for protocol in ["TCP", "UDP"]: if protocol + "_TO_CLOSE" in firewall["uPnP"]: for port in firewall["uPnP"][protocol + "_TO_CLOSE"]: - if not isinstance(port, int): # FIXME : how should we handle port ranges ? logger.warning("Can't use UPnP to close '%s'" % port) @@ -430,7 +429,6 @@ def firewall_upnp(action="status", no_refresh=False): firewall["uPnP"][protocol + "_TO_CLOSE"] = [] for port in firewall["uPnP"][protocol]: - if not isinstance(port, int): # FIXME : how should we handle port ranges ? logger.warning("Can't use UPnP to open '%s'" % port) diff --git a/src/hook.py b/src/hook.py index d985f51841..eb5a7c0354 100644 --- a/src/hook.py +++ b/src/hook.py @@ -339,7 +339,6 @@ def hook_exec( raise YunohostError("file_does_not_exist", path=path) def is_relevant_warning(msg): - # Ignore empty warning messages... if not msg: return False @@ -389,7 +388,6 @@ def is_relevant_warning(msg): def _hook_exec_bash(path, args, chdir, env, user, return_format, loggers): - from moulinette.utils.process import call_async_output # Construct command variables @@ -477,7 +475,6 @@ def _hook_exec_bash(path, args, chdir, env, user, return_format, loggers): def _hook_exec_python(path, args, env, loggers): - dir_ = os.path.dirname(path) name = os.path.splitext(os.path.basename(path))[0] @@ -497,7 +494,6 @@ def _hook_exec_python(path, args, env, loggers): def hook_exec_with_script_debug_if_failure(*args, **kwargs): - operation_logger = kwargs.pop("operation_logger") error_message_if_failed = kwargs.pop("error_message_if_failed") error_message_if_script_failed = kwargs.pop("error_message_if_script_failed") diff --git a/src/log.py b/src/log.py index 6525b904d5..f8eb65f8f7 100644 --- a/src/log.py +++ b/src/log.py @@ -95,7 +95,6 @@ def log_list(limit=None, with_details=False, with_suboperations=False): logs = logs[: limit * 5] for log in logs: - base_filename = log[: -len(METADATA_FILE_EXT)] md_path = os.path.join(OPERATIONS_PATH, log) @@ -264,7 +263,6 @@ def suboperations(): return for filename in os.listdir(OPERATIONS_PATH): - if not filename.endswith(METADATA_FILE_EXT): continue @@ -438,7 +436,6 @@ def format(self, record): return msg def identify_data_to_redact(self, record): - # Wrapping this in a try/except because we don't want this to # break everything in case it fails miserably for some reason :s try: @@ -497,7 +494,6 @@ def __init__(self, operation, related_to=None, **kwargs): os.makedirs(self.path) def parent_logger(self): - # If there are other operation logger instances for instance in reversed(self._instances): # Is one of these operation logger started but not yet done ? @@ -732,7 +728,6 @@ def __del__(self): self.error(m18n.n("log_operation_unit_unclosed_properly")) def dump_script_log_extract_for_debugging(self): - with open(self.log_path, "r") as f: lines = f.readlines() @@ -774,7 +769,6 @@ def dump_script_log_extract_for_debugging(self): def _get_datetime_from_name(name): - # Filenames are expected to follow the format: # 20200831-170740-short_description-and-stuff diff --git a/src/migrations/0021_migrate_to_bullseye.py b/src/migrations/0021_migrate_to_bullseye.py index 54917cf95f..f320577e12 100644 --- a/src/migrations/0021_migrate_to_bullseye.py +++ b/src/migrations/0021_migrate_to_bullseye.py @@ -72,13 +72,11 @@ def _backup_pip_freeze_for_python_app_venvs(): class MyMigration(Migration): - "Upgrade the system to Debian Bullseye and Yunohost 11.x" mode = "manual" def run(self): - self.check_assertions() logger.info(m18n.n("migration_0021_start")) @@ -389,7 +387,6 @@ def yunohost_major_version(self): return int(get_ynh_package_version("yunohost")["version"].split(".")[0]) def check_assertions(self): - # Be on buster (10.x) and yunohost 4.x # NB : we do both check to cover situations where the upgrade crashed # in the middle and debian version could be > 9.x but yunohost package @@ -453,7 +450,6 @@ def check_assertions(self): @property def disclaimer(self): - # Avoid having a super long disclaimer + uncessary check if we ain't # on buster / yunohost 4.x anymore # NB : we do both check to cover situations where the upgrade crashed @@ -494,7 +490,6 @@ def disclaimer(self): return message def patch_apt_sources_list(self): - sources_list = glob.glob("/etc/apt/sources.list.d/*.list") if os.path.exists("/etc/apt/sources.list"): sources_list.append("/etc/apt/sources.list") @@ -516,7 +511,6 @@ def patch_apt_sources_list(self): os.system(command) def get_apps_equivs_packages(self): - command = ( "dpkg --get-selections" " | grep -v deinstall" diff --git a/src/migrations/0022_php73_to_php74_pools.py b/src/migrations/0022_php73_to_php74_pools.py index a2e5eae54f..dc428e5042 100644 --- a/src/migrations/0022_php73_to_php74_pools.py +++ b/src/migrations/0022_php73_to_php74_pools.py @@ -27,7 +27,6 @@ class MyMigration(Migration): - "Migrate php7.3-fpm 'pool' conf files to php7.4" dependencies = ["migrate_to_bullseye"] @@ -43,7 +42,6 @@ def run(self): oldphp_pool_files = [f for f in oldphp_pool_files if f != "www.conf"] for pf in oldphp_pool_files: - # Copy the files to the php7.3 pool src = "{}/{}".format(OLDPHP_POOLS, pf) dest = "{}/{}".format(NEWPHP_POOLS, pf) diff --git a/src/migrations/0023_postgresql_11_to_13.py b/src/migrations/0023_postgresql_11_to_13.py index f0128da0b6..6d37ffa740 100644 --- a/src/migrations/0023_postgresql_11_to_13.py +++ b/src/migrations/0023_postgresql_11_to_13.py @@ -13,13 +13,11 @@ class MyMigration(Migration): - "Migrate DBs from Postgresql 11 to 13 after migrating to Bullseye" dependencies = ["migrate_to_bullseye"] def run(self): - if ( os.system( 'grep -A10 "ynh-deps" /var/lib/dpkg/status | grep -E "Package:|Depends:" | grep -B1 postgresql' @@ -63,7 +61,6 @@ def run(self): self.runcmd("systemctl start postgresql") def package_is_installed(self, package_name): - (returncode, out, err) = self.runcmd( "dpkg --list | grep '^ii ' | grep -q -w {}".format(package_name), raise_on_errors=False, @@ -71,7 +68,6 @@ def package_is_installed(self, package_name): return returncode == 0 def runcmd(self, cmd, raise_on_errors=True): - logger.debug("Running command: " + cmd) p = subprocess.Popen( diff --git a/src/migrations/0024_rebuild_python_venv.py b/src/migrations/0024_rebuild_python_venv.py index d5aa7fc103..01a229b878 100644 --- a/src/migrations/0024_rebuild_python_venv.py +++ b/src/migrations/0024_rebuild_python_venv.py @@ -14,7 +14,6 @@ def extract_app_from_venv_path(venv_path): - venv_path = venv_path.replace("/var/www/", "") venv_path = venv_path.replace("/opt/yunohost/", "") venv_path = venv_path.replace("/opt/", "") @@ -137,13 +136,11 @@ def disclaimer(self): return msg def run(self): - if self.mode == "auto": return venvs = _get_all_venvs("/opt/") + _get_all_venvs("/var/www/") for venv in venvs: - app_corresponding_to_venv = extract_app_from_venv_path(venv) # Search for ignore apps diff --git a/src/migrations/0025_global_settings_to_configpanel.py b/src/migrations/0025_global_settings_to_configpanel.py index 3a43ccb132..3a88184617 100644 --- a/src/migrations/0025_global_settings_to_configpanel.py +++ b/src/migrations/0025_global_settings_to_configpanel.py @@ -14,7 +14,6 @@ class MyMigration(Migration): - "Migrate old global settings to the new ConfigPanel global settings" dependencies = ["migrate_to_bullseye"] diff --git a/src/migrations/0026_new_admins_group.py b/src/migrations/0026_new_admins_group.py index 5d9167ae77..98f2a54bef 100644 --- a/src/migrations/0026_new_admins_group.py +++ b/src/migrations/0026_new_admins_group.py @@ -21,7 +21,6 @@ class MyMigration(Migration): @Migration.ldap_migration def run(self, *args): - from yunohost.user import ( user_list, user_info, diff --git a/src/permission.py b/src/permission.py index e451bb74c2..7f5a65f2e9 100644 --- a/src/permission.py +++ b/src/permission.py @@ -79,7 +79,6 @@ def user_permission_list( permissions = {} for infos in permissions_infos: - name = infos["cn"][0] app = name.split(".")[0] @@ -654,7 +653,6 @@ def permission_sync_to_user(): permissions = user_permission_list(full=True)["permissions"] for permission_name, permission_infos in permissions.items(): - # These are the users currently allowed because there's an 'inheritPermission' object corresponding to it currently_allowed_users = set(permission_infos["corresponding_users"]) @@ -740,7 +738,6 @@ def _update_ldap_group_permission( update["isProtected"] = [str(protected).upper()] if show_tile is not None: - if show_tile is True: if not existing_permission["url"]: logger.warning( @@ -876,7 +873,6 @@ def validate_regex(regex): raise YunohostValidationError("invalid_regex", regex=regex) if url.startswith("re:"): - # regex without domain # we check for the first char after 're:' if url[3] in ["/", "^", "\\"]: diff --git a/src/regenconf.py b/src/regenconf.py index f1163e66a6..7acc6f58f8 100644 --- a/src/regenconf.py +++ b/src/regenconf.py @@ -77,7 +77,6 @@ def regen_conf( for category, conf_files in pending_conf.items(): for system_path, pending_path in conf_files.items(): - pending_conf[category][system_path] = { "pending_conf": pending_path, "diff": _get_files_diff(system_path, pending_path, True), @@ -595,7 +594,6 @@ def _update_conf_hashes(category, hashes): def _force_clear_hashes(paths): - categories = _get_regenconf_infos() for path in paths: for category in categories.keys(): @@ -675,7 +673,6 @@ def _process_regen_conf(system_conf, new_conf=None, save=True): def manually_modified_files(): - output = [] regenconf_categories = _get_regenconf_infos() for category, infos in regenconf_categories.items(): @@ -690,7 +687,6 @@ def manually_modified_files(): def manually_modified_files_compared_to_debian_default( ignore_handled_by_regenconf=False, ): - # from https://serverfault.com/a/90401 files = check_output( "dpkg-query -W -f='${Conffiles}\n' '*' \ diff --git a/src/service.py b/src/service.py index e11c2b6090..935e87339d 100644 --- a/src/service.py +++ b/src/service.py @@ -249,12 +249,10 @@ def service_reload_or_restart(names, test_conf=True): services = _get_services() for name in names: - logger.debug(f"Reloading service {name}") test_conf_cmd = services.get(name, {}).get("test_conf") if test_conf and test_conf_cmd: - p = subprocess.Popen( test_conf_cmd, shell=True, @@ -393,7 +391,6 @@ def _get_service_information_from_systemd(service): def _get_and_format_service_status(service, infos): - systemd_service = infos.get("actual_systemd_service", service) raw_status, raw_service = _get_service_information_from_systemd(systemd_service) @@ -414,7 +411,6 @@ def _get_and_format_service_status(service, infos): # If no description was there, try to get it from the .json locales if not description: - translation_key = f"service_description_{service}" if m18n.key_exists(translation_key): description = m18n.n(translation_key) @@ -521,7 +517,6 @@ def service_log(name, number=50): result["journalctl"] = _get_journalctl_logs(name, number).splitlines() for log_path in log_list: - if not os.path.exists(log_path): continue @@ -620,7 +615,6 @@ def _run_service_command(action, service): def _give_lock(action, service, p): - # Depending of the action, systemctl calls the PID differently :/ if action == "start" or action == "restart": systemctl_PID_name = "MainPID" @@ -744,7 +738,6 @@ def _save_services(services): diff = {} for service_name, service_infos in services.items(): - # Ignore php-fpm services, they are to be added dynamically by the core, # but not actually saved if service_name.startswith("php") and service_name.endswith("-fpm"): diff --git a/src/settings.py b/src/settings.py index d9ea600a43..d1203930df 100644 --- a/src/settings.py +++ b/src/settings.py @@ -59,7 +59,6 @@ def settings_get(key="", full=False, export=False): def settings_list(full=False): - settings = settings_get(full=full) if full: @@ -126,7 +125,6 @@ def __init__(self, config_path=None, save_path=None, creation=False): super().__init__("settings") def _apply(self): - root_password = self.new_values.pop("root_password", None) root_password_confirm = self.new_values.pop("root_password_confirm", None) passwordless_sudo = self.new_values.pop("passwordless_sudo", None) @@ -141,7 +139,6 @@ def _apply(self): assert all(v not in self.future_values for v in self.virtual_settings) if root_password and root_password.strip(): - if root_password != root_password_confirm: raise YunohostValidationError("password_confirmation_not_the_same") @@ -173,7 +170,6 @@ def _apply(self): raise def _get_toml(self): - toml = super()._get_toml() # Dynamic choice list for portal themes @@ -187,7 +183,6 @@ def _get_toml(self): return toml def _load_current_values(self): - super()._load_current_values() # Specific logic for those settings who are "virtual" settings @@ -207,7 +202,6 @@ def _load_current_values(self): self.values["passwordless_sudo"] = False def get(self, key="", mode="classic"): - result = super().get(key=key, mode=mode) if mode == "full": diff --git a/src/tests/conftest.py b/src/tests/conftest.py index cd5cb307ed..393c335644 100644 --- a/src/tests/conftest.py +++ b/src/tests/conftest.py @@ -51,7 +51,6 @@ def pytest_addoption(parser): def new_translate(self, key, *args, **kwargs): - if key not in self._translations[self.default_locale].keys(): raise KeyError("Unable to retrieve key %s for default locale !" % key) @@ -67,7 +66,6 @@ def new_translate(self, key, *args, **kwargs): def pytest_cmdline_main(config): - import sys sys.path.insert(0, "/usr/lib/moulinette/") @@ -76,7 +74,6 @@ def pytest_cmdline_main(config): yunohost.init(debug=config.option.yunodebug) class DummyInterface: - type = "cli" def prompt(self, *args, **kwargs): diff --git a/src/tests/test_app_catalog.py b/src/tests/test_app_catalog.py index e9ecb1c12a..f7363dabef 100644 --- a/src/tests/test_app_catalog.py +++ b/src/tests/test_app_catalog.py @@ -44,7 +44,6 @@ def __eq__(self, other): def setup_function(function): - # Clear apps catalog cache shutil.rmtree(APPS_CATALOG_CACHE, ignore_errors=True) @@ -54,7 +53,6 @@ def setup_function(function): def teardown_function(function): - # Clear apps catalog cache # Otherwise when using apps stuff after running the test, # we'll still have the dummy unusable list @@ -67,7 +65,6 @@ def teardown_function(function): def test_apps_catalog_init(mocker): - # Cache is empty assert not glob.glob(APPS_CATALOG_CACHE + "/*") # Conf doesn't exist yet @@ -91,7 +88,6 @@ def test_apps_catalog_init(mocker): def test_apps_catalog_emptylist(): - # Initialize ... _initialize_apps_catalog_system() @@ -104,7 +100,6 @@ def test_apps_catalog_emptylist(): def test_apps_catalog_update_nominal(mocker): - # Initialize ... _initialize_apps_catalog_system() @@ -113,7 +108,6 @@ def test_apps_catalog_update_nominal(mocker): # Update with requests_mock.Mocker() as m: - _actual_apps_catalog_api_url, # Mock the server response with a dummy apps catalog m.register_uri("GET", APPS_CATALOG_DEFAULT_URL_FULL, text=DUMMY_APP_CATALOG) @@ -139,12 +133,10 @@ def test_apps_catalog_update_nominal(mocker): def test_apps_catalog_update_404(mocker): - # Initialize ... _initialize_apps_catalog_system() with requests_mock.Mocker() as m: - # 404 error m.register_uri("GET", APPS_CATALOG_DEFAULT_URL_FULL, status_code=404) @@ -155,12 +147,10 @@ def test_apps_catalog_update_404(mocker): def test_apps_catalog_update_timeout(mocker): - # Initialize ... _initialize_apps_catalog_system() with requests_mock.Mocker() as m: - # Timeout m.register_uri( "GET", APPS_CATALOG_DEFAULT_URL_FULL, exc=requests.exceptions.ConnectTimeout @@ -173,12 +163,10 @@ def test_apps_catalog_update_timeout(mocker): def test_apps_catalog_update_sslerror(mocker): - # Initialize ... _initialize_apps_catalog_system() with requests_mock.Mocker() as m: - # SSL error m.register_uri( "GET", APPS_CATALOG_DEFAULT_URL_FULL, exc=requests.exceptions.SSLError @@ -191,12 +179,10 @@ def test_apps_catalog_update_sslerror(mocker): def test_apps_catalog_update_corrupted(mocker): - # Initialize ... _initialize_apps_catalog_system() with requests_mock.Mocker() as m: - # Corrupted json m.register_uri( "GET", APPS_CATALOG_DEFAULT_URL_FULL, text=DUMMY_APP_CATALOG[:-2] @@ -209,7 +195,6 @@ def test_apps_catalog_update_corrupted(mocker): def test_apps_catalog_load_with_empty_cache(mocker): - # Initialize ... _initialize_apps_catalog_system() @@ -218,7 +203,6 @@ def test_apps_catalog_load_with_empty_cache(mocker): # Update with requests_mock.Mocker() as m: - # Mock the server response with a dummy apps catalog m.register_uri("GET", APPS_CATALOG_DEFAULT_URL_FULL, text=DUMMY_APP_CATALOG) @@ -237,7 +221,6 @@ def test_apps_catalog_load_with_empty_cache(mocker): def test_apps_catalog_load_with_conflicts_between_lists(mocker): - # Initialize ... _initialize_apps_catalog_system() @@ -253,7 +236,6 @@ def test_apps_catalog_load_with_conflicts_between_lists(mocker): # Update with requests_mock.Mocker() as m: - # Mock the server response with a dummy apps catalog # + the same apps catalog for the second list m.register_uri("GET", APPS_CATALOG_DEFAULT_URL_FULL, text=DUMMY_APP_CATALOG) @@ -277,13 +259,11 @@ def test_apps_catalog_load_with_conflicts_between_lists(mocker): def test_apps_catalog_load_with_oudated_api_version(mocker): - # Initialize ... _initialize_apps_catalog_system() # Update with requests_mock.Mocker() as m: - mocker.spy(m18n, "n") m.register_uri("GET", APPS_CATALOG_DEFAULT_URL_FULL, text=DUMMY_APP_CATALOG) _update_apps_catalog() @@ -300,7 +280,6 @@ def test_apps_catalog_load_with_oudated_api_version(mocker): # Update with requests_mock.Mocker() as m: - # Mock the server response with a dummy apps catalog m.register_uri("GET", APPS_CATALOG_DEFAULT_URL_FULL, text=DUMMY_APP_CATALOG) diff --git a/src/tests/test_app_config.py b/src/tests/test_app_config.py index b524a7a512..4a74cbc0de 100644 --- a/src/tests/test_app_config.py +++ b/src/tests/test_app_config.py @@ -25,17 +25,14 @@ def setup_function(function): - clean() def teardown_function(function): - clean() def clean(): - # Make sure we have a ssowat os.system("mkdir -p /etc/ssowat/") app_ssowatconf() @@ -43,7 +40,6 @@ def clean(): test_apps = ["config_app", "legacy_app"] for test_app in test_apps: - if _is_installed(test_app): app_remove(test_app) @@ -66,7 +62,6 @@ def clean(): @pytest.fixture() def legacy_app(request): - main_domain = _get_maindomain() app_install( @@ -85,7 +80,6 @@ def remove_app(): @pytest.fixture() def config_app(request): - app_install( os.path.join(get_test_apps_dir(), "config_app_ynh"), args="", @@ -101,7 +95,6 @@ def remove_app(): def test_app_config_get(config_app): - user_create("alice", _get_maindomain(), "test123Ynh", fullname="Alice White") assert isinstance(app_config_get(config_app), dict) @@ -115,13 +108,11 @@ def test_app_config_get(config_app): def test_app_config_nopanel(legacy_app): - with pytest.raises(YunohostValidationError): app_config_get(legacy_app) def test_app_config_get_nonexistentstuff(config_app): - with pytest.raises(YunohostValidationError): app_config_get("nonexistent") @@ -140,7 +131,6 @@ def test_app_config_get_nonexistentstuff(config_app): def test_app_config_regular_setting(config_app): - assert app_config_get(config_app, "main.components.boolean") == 0 app_config_set(config_app, "main.components.boolean", "no") @@ -160,7 +150,6 @@ def test_app_config_regular_setting(config_app): def test_app_config_bind_on_file(config_app): - # c.f. conf/test.php in the config app assert '$arg5= "Arg5 value";' in read_file("/var/www/config_app/test.php") assert app_config_get(config_app, "bind.variable.arg5") == "Arg5 value" @@ -184,7 +173,6 @@ def test_app_config_bind_on_file(config_app): def test_app_config_custom_validator(config_app): - # c.f. the config script # arg8 is a password that must be at least 8 chars assert not os.path.exists("/var/www/config_app/password") @@ -198,7 +186,6 @@ def test_app_config_custom_validator(config_app): def test_app_config_custom_set(config_app): - assert not os.path.exists("/var/www/config_app/password") assert app_setting(config_app, "arg8") is None diff --git a/src/tests/test_app_resources.py b/src/tests/test_app_resources.py index 879f6e29ac..d2df647a3d 100644 --- a/src/tests/test_app_resources.py +++ b/src/tests/test_app_resources.py @@ -17,7 +17,6 @@ class DummyAppResource(AppResource): - type = "dummy" default_properties = { @@ -26,14 +25,12 @@ class DummyAppResource(AppResource): } def provision_or_update(self, context): - open(self.file, "w").write(self.content) if self.content == "forbiddenvalue": raise Exception("Emeged you used the forbidden value!1!£&") def deprovision(self, context): - os.system(f"rm -f {self.file}") @@ -41,7 +38,6 @@ def deprovision(self, context): def setup_function(function): - clean() os.system("mkdir /etc/yunohost/apps/testapp") @@ -51,12 +47,10 @@ def setup_function(function): def teardown_function(function): - clean() def clean(): - os.system(f"rm -f {dummyfile}") os.system("rm -rf /etc/yunohost/apps/testapp") os.system("rm -rf /var/www/testapp") @@ -70,7 +64,6 @@ def clean(): def test_provision_dummy(): - current = {"resources": {}} wanted = {"resources": {"dummy": {}}} @@ -82,7 +75,6 @@ def test_provision_dummy(): def test_deprovision_dummy(): - current = {"resources": {"dummy": {}}} wanted = {"resources": {}} @@ -96,7 +88,6 @@ def test_deprovision_dummy(): def test_provision_dummy_nondefaultvalue(): - current = {"resources": {}} wanted = {"resources": {"dummy": {"content": "bar"}}} @@ -108,7 +99,6 @@ def test_provision_dummy_nondefaultvalue(): def test_update_dummy(): - current = {"resources": {"dummy": {}}} wanted = {"resources": {"dummy": {"content": "bar"}}} @@ -122,7 +112,6 @@ def test_update_dummy(): def test_update_dummy_failwithrollback(): - current = {"resources": {"dummy": {}}} wanted = {"resources": {"dummy": {"content": "forbiddenvalue"}}} @@ -137,7 +126,6 @@ def test_update_dummy_failwithrollback(): def test_resource_system_user(): - r = AppResourceClassesByType["system_user"] conf = {} @@ -161,7 +149,6 @@ def test_resource_system_user(): def test_resource_install_dir(): - r = AppResourceClassesByType["install_dir"] conf = {"owner": "nobody:rx", "group": "nogroup:rx"} @@ -196,7 +183,6 @@ def test_resource_install_dir(): def test_resource_data_dir(): - r = AppResourceClassesByType["data_dir"] conf = {"owner": "nobody:rx", "group": "nogroup:rx"} @@ -228,7 +214,6 @@ def test_resource_data_dir(): def test_resource_ports(): - r = AppResourceClassesByType["ports"] conf = {} @@ -244,7 +229,6 @@ def test_resource_ports(): def test_resource_ports_several(): - r = AppResourceClassesByType["ports"] conf = {"main": {"default": 12345}, "foobar": {"default": 23456}} @@ -263,7 +247,6 @@ def test_resource_ports_several(): def test_resource_ports_firewall(): - r = AppResourceClassesByType["ports"] conf = {"main": {"default": 12345}} @@ -283,7 +266,6 @@ def test_resource_ports_firewall(): def test_resource_database(): - r = AppResourceClassesByType["database"] conf = {"type": "mysql"} @@ -308,7 +290,6 @@ def test_resource_database(): def test_resource_apt(): - r = AppResourceClassesByType["apt"] conf = { "packages": "nyancat, sl", @@ -356,7 +337,6 @@ def test_resource_apt(): def test_resource_permissions(): - maindomain = _get_maindomain() os.system(f"echo 'domain: {maindomain}' >> /etc/yunohost/apps/testapp/settings.yml") os.system("echo 'path: /testapp' >> /etc/yunohost/apps/testapp/settings.yml") diff --git a/src/tests/test_apps.py b/src/tests/test_apps.py index 6efdaa0b03..965ce5892d 100644 --- a/src/tests/test_apps.py +++ b/src/tests/test_apps.py @@ -28,17 +28,14 @@ def setup_function(function): - clean() def teardown_function(function): - clean() def clean(): - # Make sure we have a ssowat os.system("mkdir -p /etc/ssowat/") app_ssowatconf() @@ -53,7 +50,6 @@ def clean(): ] for test_app in test_apps: - if _is_installed(test_app): app_remove(test_app) @@ -95,7 +91,6 @@ def check_permission_for_apps_call(): @pytest.fixture(scope="module") def secondary_domain(request): - if "example.test" not in domain_list()["domains"]: domain_add("example.test") @@ -113,7 +108,6 @@ def remove_example_domain(): def app_expected_files(domain, app): - yield "/etc/nginx/conf.d/{}.d/{}.conf".format(domain, app) if app.startswith("legacy_app"): yield "/var/www/%s/index.html" % app @@ -127,21 +121,18 @@ def app_expected_files(domain, app): def app_is_installed(domain, app): - return _is_installed(app) and all( os.path.exists(f) for f in app_expected_files(domain, app) ) def app_is_not_installed(domain, app): - return not _is_installed(app) and not all( os.path.exists(f) for f in app_expected_files(domain, app) ) def app_is_exposed_on_http(domain, path, message_in_page): - try: r = requests.get( "https://127.0.0.1" + path + "/", @@ -155,7 +146,6 @@ def app_is_exposed_on_http(domain, path, message_in_page): def install_legacy_app(domain, path, public=True): - app_install( os.path.join(get_test_apps_dir(), "legacy_app_ynh"), args="domain={}&path={}&is_public={}".format(domain, path, 1 if public else 0), @@ -164,7 +154,6 @@ def install_legacy_app(domain, path, public=True): def install_manifestv2_app(domain, path, public=True): - app_install( os.path.join(get_test_apps_dir(), "manifestv2_app_ynh"), args="domain={}&path={}&init_main_permission={}".format( @@ -175,7 +164,6 @@ def install_manifestv2_app(domain, path, public=True): def install_full_domain_app(domain): - app_install( os.path.join(get_test_apps_dir(), "full_domain_app_ynh"), args="domain=%s" % domain, @@ -184,7 +172,6 @@ def install_full_domain_app(domain): def install_break_yo_system(domain, breakwhat): - app_install( os.path.join(get_test_apps_dir(), "break_yo_system_ynh"), args="domain={}&breakwhat={}".format(domain, breakwhat), @@ -193,7 +180,6 @@ def install_break_yo_system(domain, breakwhat): def test_legacy_app_install_main_domain(): - main_domain = _get_maindomain() install_legacy_app(main_domain, "/legacy") @@ -213,7 +199,6 @@ def test_legacy_app_install_main_domain(): def test_legacy_app_manifest_preinstall(): - m = app_manifest(os.path.join(get_test_apps_dir(), "legacy_app_ynh")) # v1 manifesto are expected to have been autoconverted to v2 @@ -231,7 +216,6 @@ def test_legacy_app_manifest_preinstall(): def test_manifestv2_app_manifest_preinstall(): - m = app_manifest(os.path.join(get_test_apps_dir(), "manifestv2_app_ynh")) assert "id" in m @@ -258,7 +242,6 @@ def test_manifestv2_app_manifest_preinstall(): def test_manifestv2_app_install_main_domain(): - main_domain = _get_maindomain() install_manifestv2_app(main_domain, "/manifestv2") @@ -278,7 +261,6 @@ def test_manifestv2_app_install_main_domain(): def test_manifestv2_app_info_postinstall(): - main_domain = _get_maindomain() install_manifestv2_app(main_domain, "/manifestv2") m = app_info("manifestv2_app", full=True)["manifest"] @@ -308,13 +290,11 @@ def test_manifestv2_app_info_postinstall(): def test_manifestv2_app_info_preupgrade(monkeypatch): - manifest = app_manifest(os.path.join(get_test_apps_dir(), "manifestv2_app_ynh")) from yunohost.app_catalog import _load_apps_catalog as original_load_apps_catalog def custom_load_apps_catalog(*args, **kwargs): - res = original_load_apps_catalog(*args, **kwargs) res["apps"]["manifestv2_app"] = { "id": "manifestv2_app", @@ -372,7 +352,6 @@ def test_app_from_catalog(): def test_legacy_app_install_secondary_domain(secondary_domain): - install_legacy_app(secondary_domain, "/legacy") assert app_is_installed(secondary_domain, "legacy_app") @@ -384,7 +363,6 @@ def test_legacy_app_install_secondary_domain(secondary_domain): def test_legacy_app_install_secondary_domain_on_root(secondary_domain): - install_legacy_app(secondary_domain, "/") app_map_ = app_map(raw=True) @@ -402,7 +380,6 @@ def test_legacy_app_install_secondary_domain_on_root(secondary_domain): def test_legacy_app_install_private(secondary_domain): - install_legacy_app(secondary_domain, "/legacy", public=False) assert app_is_installed(secondary_domain, "legacy_app") @@ -416,7 +393,6 @@ def test_legacy_app_install_private(secondary_domain): def test_legacy_app_install_unknown_domain(mocker): - with pytest.raises(YunohostError): with message(mocker, "app_argument_invalid"): install_legacy_app("whatever.nope", "/legacy") @@ -425,7 +401,6 @@ def test_legacy_app_install_unknown_domain(mocker): def test_legacy_app_install_multiple_instances(secondary_domain): - install_legacy_app(secondary_domain, "/foo") install_legacy_app(secondary_domain, "/bar") @@ -447,7 +422,6 @@ def test_legacy_app_install_multiple_instances(secondary_domain): def test_legacy_app_install_path_unavailable(mocker, secondary_domain): - # These will be removed in teardown install_legacy_app(secondary_domain, "/legacy") @@ -460,7 +434,6 @@ def test_legacy_app_install_path_unavailable(mocker, secondary_domain): def test_legacy_app_install_with_nginx_down(mocker, secondary_domain): - os.system("systemctl stop nginx") with raiseYunohostError( @@ -470,7 +443,6 @@ def test_legacy_app_install_with_nginx_down(mocker, secondary_domain): def test_legacy_app_failed_install(mocker, secondary_domain): - # This will conflict with the folder that the app # attempts to create, making the install fail mkdir("/var/www/legacy_app/", 0o750) @@ -483,7 +455,6 @@ def test_legacy_app_failed_install(mocker, secondary_domain): def test_legacy_app_failed_remove(mocker, secondary_domain): - install_legacy_app(secondary_domain, "/legacy") # The remove script runs with set -eu and attempt to remove this @@ -503,14 +474,12 @@ def test_legacy_app_failed_remove(mocker, secondary_domain): def test_full_domain_app(secondary_domain): - install_full_domain_app(secondary_domain) assert app_is_exposed_on_http(secondary_domain, "/", "This is a dummy app") def test_full_domain_app_with_conflicts(mocker, secondary_domain): - install_legacy_app(secondary_domain, "/legacy") with raiseYunohostError(mocker, "app_full_domain_unavailable"): @@ -518,7 +487,6 @@ def test_full_domain_app_with_conflicts(mocker, secondary_domain): def test_systemfuckedup_during_app_install(mocker, secondary_domain): - with pytest.raises(YunohostError): with message(mocker, "app_install_failed"): with message(mocker, "app_action_broke_system"): @@ -528,7 +496,6 @@ def test_systemfuckedup_during_app_install(mocker, secondary_domain): def test_systemfuckedup_during_app_remove(mocker, secondary_domain): - install_break_yo_system(secondary_domain, breakwhat="remove") with pytest.raises(YunohostError): @@ -540,7 +507,6 @@ def test_systemfuckedup_during_app_remove(mocker, secondary_domain): def test_systemfuckedup_during_app_install_and_remove(mocker, secondary_domain): - with pytest.raises(YunohostError): with message(mocker, "app_install_failed"): with message(mocker, "app_action_broke_system"): @@ -550,7 +516,6 @@ def test_systemfuckedup_during_app_install_and_remove(mocker, secondary_domain): def test_systemfuckedup_during_app_upgrade(mocker, secondary_domain): - install_break_yo_system(secondary_domain, breakwhat="upgrade") with pytest.raises(YunohostError): @@ -562,7 +527,6 @@ def test_systemfuckedup_during_app_upgrade(mocker, secondary_domain): def test_failed_multiple_app_upgrade(mocker, secondary_domain): - install_legacy_app(secondary_domain, "/legacy") install_break_yo_system(secondary_domain, breakwhat="upgrade") diff --git a/src/tests/test_appurl.py b/src/tests/test_appurl.py index c036ae28a0..351bb4e833 100644 --- a/src/tests/test_appurl.py +++ b/src/tests/test_appurl.py @@ -18,7 +18,6 @@ def setup_function(function): - try: app_remove("register_url_app") except Exception: @@ -26,7 +25,6 @@ def setup_function(function): def teardown_function(function): - try: app_remove("register_url_app") except Exception: @@ -34,7 +32,6 @@ def teardown_function(function): def test_parse_app_instance_name(): - assert _parse_app_instance_name("yolo") == ("yolo", 1) assert _parse_app_instance_name("yolo1") == ("yolo1", 1) assert _parse_app_instance_name("yolo__0") == ("yolo__0", 1) @@ -86,7 +83,6 @@ def test_repo_url_definition(): def test_urlavailable(): - # Except the maindomain/macnuggets to be available assert domain_url_available(maindomain, "/macnuggets") @@ -96,7 +92,6 @@ def test_urlavailable(): def test_registerurl(): - app_install( os.path.join(get_test_apps_dir(), "register_url_app_ynh"), args="domain={}&path={}".format(maindomain, "/urlregisterapp"), @@ -115,7 +110,6 @@ def test_registerurl(): def test_registerurl_baddomain(): - with pytest.raises(YunohostError): app_install( os.path.join(get_test_apps_dir(), "register_url_app_ynh"), diff --git a/src/tests/test_backuprestore.py b/src/tests/test_backuprestore.py index dc37d3497b..28646960c1 100644 --- a/src/tests/test_backuprestore.py +++ b/src/tests/test_backuprestore.py @@ -30,7 +30,6 @@ def setup_function(function): - global maindomain maindomain = _get_maindomain() @@ -89,7 +88,6 @@ def setup_function(function): def teardown_function(function): - assert tmp_backup_directory_is_empty() reset_ssowat_conf() @@ -133,7 +131,6 @@ def check_permission_for_apps_call(): def app_is_installed(app): - if app == "permissions_app": return _is_installed(app) @@ -147,7 +144,6 @@ def app_is_installed(app): def backup_test_dependencies_are_met(): - # Dummy test apps (or backup archives) assert os.path.exists( os.path.join(get_test_apps_dir(), "backup_wordpress_from_4p2") @@ -161,7 +157,6 @@ def backup_test_dependencies_are_met(): def tmp_backup_directory_is_empty(): - if not os.path.exists("/home/yunohost.backup/tmp/"): return True else: @@ -169,7 +164,6 @@ def tmp_backup_directory_is_empty(): def clean_tmp_backup_directory(): - if tmp_backup_directory_is_empty(): return @@ -191,27 +185,23 @@ def clean_tmp_backup_directory(): def reset_ssowat_conf(): - # Make sure we have a ssowat os.system("mkdir -p /etc/ssowat/") app_ssowatconf() def delete_all_backups(): - for archive in backup_list()["archives"]: backup_delete(archive) def uninstall_test_apps_if_needed(): - for app in ["legacy_app", "backup_recommended_app", "wordpress", "permissions_app"]: if _is_installed(app): app_remove(app) def install_app(app, path, additionnal_args=""): - app_install( os.path.join(get_test_apps_dir(), app), args="domain={}&path={}{}".format(maindomain, path, additionnal_args), @@ -220,7 +210,6 @@ def install_app(app, path, additionnal_args=""): def add_archive_wordpress_from_4p2(): - os.system("mkdir -p /home/yunohost.backup/archives") os.system( @@ -231,7 +220,6 @@ def add_archive_wordpress_from_4p2(): def add_archive_system_from_4p2(): - os.system("mkdir -p /home/yunohost.backup/archives") os.system( @@ -247,7 +235,6 @@ def add_archive_system_from_4p2(): def test_backup_only_ldap(mocker): - # Create the backup with message(mocker, "backup_created"): backup_create(system=["conf_ldap"], apps=None) @@ -262,7 +249,6 @@ def test_backup_only_ldap(mocker): def test_backup_system_part_that_does_not_exists(mocker): - # Create the backup with message(mocker, "backup_hook_unknown", hook="doesnt_exist"): with raiseYunohostError(mocker, "backup_nothings_done"): @@ -275,7 +261,6 @@ def test_backup_system_part_that_does_not_exists(mocker): def test_backup_and_restore_all_sys(mocker): - # Create the backup with message(mocker, "backup_created"): backup_create(system=[], apps=None) @@ -309,7 +294,6 @@ def test_backup_and_restore_all_sys(mocker): @pytest.mark.with_system_archive_from_4p2 def test_restore_system_from_Ynh4p2(monkeypatch, mocker): - # Backup current system with message(mocker, "backup_created"): backup_create(system=[], apps=None) @@ -337,7 +321,6 @@ def test_restore_system_from_Ynh4p2(monkeypatch, mocker): @pytest.mark.with_backup_recommended_app_installed def test_backup_script_failure_handling(monkeypatch, mocker): def custom_hook_exec(name, *args, **kwargs): - if os.path.basename(name).startswith("backup_"): raise Exception else: @@ -373,7 +356,6 @@ def custom_free_space_in_directory(dirpath): def test_backup_app_not_installed(mocker): - assert not _is_installed("wordpress") with message(mocker, "unbackup_app", app="wordpress"): @@ -383,7 +365,6 @@ def test_backup_app_not_installed(mocker): @pytest.mark.with_backup_recommended_app_installed def test_backup_app_with_no_backup_script(mocker): - backup_script = "/etc/yunohost/apps/backup_recommended_app/scripts/backup" os.system("rm %s" % backup_script) assert not os.path.exists(backup_script) @@ -397,7 +378,6 @@ def test_backup_app_with_no_backup_script(mocker): @pytest.mark.with_backup_recommended_app_installed def test_backup_app_with_no_restore_script(mocker): - restore_script = "/etc/yunohost/apps/backup_recommended_app/scripts/restore" os.system("rm %s" % restore_script) assert not os.path.exists(restore_script) @@ -413,7 +393,6 @@ def test_backup_app_with_no_restore_script(mocker): @pytest.mark.clean_opt_dir def test_backup_with_different_output_directory(mocker): - # Create the backup with message(mocker, "backup_created"): backup_create( @@ -436,7 +415,6 @@ def test_backup_with_different_output_directory(mocker): @pytest.mark.clean_opt_dir def test_backup_using_copy_method(mocker): - # Create the backup with message(mocker, "backup_created"): backup_create( @@ -458,7 +436,6 @@ def test_backup_using_copy_method(mocker): @pytest.mark.with_wordpress_archive_from_4p2 @pytest.mark.with_custom_domain("yolo.test") def test_restore_app_wordpress_from_Ynh4p2(mocker): - with message(mocker, "restore_complete"): backup_restore( system=None, name=backup_list()["archives"][0], apps=["wordpress"] @@ -507,7 +484,6 @@ def custom_free_space_in_directory(dirpath): @pytest.mark.with_wordpress_archive_from_4p2 def test_restore_app_not_in_backup(mocker): - assert not _is_installed("wordpress") assert not _is_installed("yoloswag") @@ -524,7 +500,6 @@ def test_restore_app_not_in_backup(mocker): @pytest.mark.with_wordpress_archive_from_4p2 @pytest.mark.with_custom_domain("yolo.test") def test_restore_app_already_installed(mocker): - assert not _is_installed("wordpress") with message(mocker, "restore_complete"): @@ -544,25 +519,21 @@ def test_restore_app_already_installed(mocker): @pytest.mark.with_legacy_app_installed def test_backup_and_restore_legacy_app(mocker): - _test_backup_and_restore_app(mocker, "legacy_app") @pytest.mark.with_backup_recommended_app_installed def test_backup_and_restore_recommended_app(mocker): - _test_backup_and_restore_app(mocker, "backup_recommended_app") @pytest.mark.with_backup_recommended_app_installed_with_ynh_restore def test_backup_and_restore_with_ynh_restore(mocker): - _test_backup_and_restore_app(mocker, "backup_recommended_app") @pytest.mark.with_permission_app_installed def test_backup_and_restore_permission_app(mocker): - res = user_permission_list(full=True)["permissions"] assert "permissions_app.main" in res assert "permissions_app.admin" in res @@ -593,7 +564,6 @@ def test_backup_and_restore_permission_app(mocker): def _test_backup_and_restore_app(mocker, app): - # Create a backup of this app with message(mocker, "backup_created"): backup_create(system=None, apps=[app]) @@ -628,7 +598,6 @@ def _test_backup_and_restore_app(mocker, app): def test_restore_archive_with_no_json(mocker): - # Create a backup with no info.json associated os.system("touch /tmp/afile") os.system("tar -cvf /home/yunohost.backup/archives/badbackup.tar /tmp/afile") @@ -641,7 +610,6 @@ def test_restore_archive_with_no_json(mocker): @pytest.mark.with_wordpress_archive_from_4p2 def test_restore_archive_with_bad_archive(mocker): - # Break the archive os.system( "head -n 1000 /home/yunohost.backup/archives/backup_wordpress_from_4p2.tar > /home/yunohost.backup/archives/backup_wordpress_from_4p2_bad.tar" @@ -656,7 +624,6 @@ def test_restore_archive_with_bad_archive(mocker): def test_restore_archive_with_custom_hook(mocker): - custom_restore_hook_folder = os.path.join(CUSTOM_HOOK_FOLDER, "restore") os.system("touch %s/99-yolo" % custom_restore_hook_folder) diff --git a/src/tests/test_dns.py b/src/tests/test_dns.py index a23ac7982d..e896d9c9f7 100644 --- a/src/tests/test_dns.py +++ b/src/tests/test_dns.py @@ -12,12 +12,10 @@ def setup_function(function): - clean() def teardown_function(function): - clean() @@ -76,7 +74,6 @@ def example_domain(): def test_domain_dns_suggest(example_domain): - assert _build_dns_conf(example_domain) diff --git a/src/tests/test_domains.py b/src/tests/test_domains.py index 95a33e0ba6..b414c21d89 100644 --- a/src/tests/test_domains.py +++ b/src/tests/test_domains.py @@ -19,7 +19,6 @@ def setup_function(function): - # Save domain list in variable to avoid multiple calls to domain_list() domains = domain_list()["domains"] @@ -52,7 +51,6 @@ def setup_function(function): def teardown_function(function): - clean() @@ -102,7 +100,6 @@ def test_domain_config_get_default(): def test_domain_config_get_export(): - assert domain_config_get(TEST_DOMAINS[0], export=True)["xmpp"] == 1 assert domain_config_get(TEST_DOMAINS[1], export=True)["xmpp"] == 0 diff --git a/src/tests/test_ldapauth.py b/src/tests/test_ldapauth.py index e8a48aa6d2..9e3ae36cc3 100644 --- a/src/tests/test_ldapauth.py +++ b/src/tests/test_ldapauth.py @@ -10,7 +10,6 @@ def setup_function(function): - for u in user_list()["users"]: user_delete(u, purge=True) @@ -24,7 +23,6 @@ def setup_function(function): def teardown_function(): - os.system("systemctl is-active slapd >/dev/null || systemctl start slapd; sleep 5") for u in user_list()["users"]: @@ -36,7 +34,6 @@ def test_authenticate(): def test_authenticate_with_no_user(): - with pytest.raises(MoulinetteError): LDAPAuth().authenticate_credentials(credentials="Yunohost") @@ -45,7 +42,6 @@ def test_authenticate_with_no_user(): def test_authenticate_with_user_who_is_not_admin(): - with pytest.raises(MoulinetteError) as exception: LDAPAuth().authenticate_credentials(credentials="bob:test123Ynh") @@ -70,7 +66,6 @@ def test_authenticate_server_down(mocker): def test_authenticate_change_password(): - LDAPAuth().authenticate_credentials(credentials="alice:Yunohost") user_update("alice", change_password="plopette") diff --git a/src/tests/test_permission.py b/src/tests/test_permission.py index acb3419c9e..10bd018d23 100644 --- a/src/tests/test_permission.py +++ b/src/tests/test_permission.py @@ -354,7 +354,6 @@ def check_permission_for_apps(): def can_access_webpage(webpath, logged_as=None): - webpath = webpath.rstrip("/") sso_url = "https://" + maindomain + "/yunohost/sso/" @@ -1094,7 +1093,6 @@ def test_permission_protection_management_by_helper(): @pytest.mark.other_domains(number=1) def test_permission_app_propagation_on_ssowat(): - app_install( os.path.join(get_test_apps_dir(), "permissions_app_ynh"), args="domain=%s&domain_2=%s&path=%s&is_public=1&admin=%s" @@ -1131,7 +1129,6 @@ def test_permission_app_propagation_on_ssowat(): @pytest.mark.other_domains(number=1) def test_permission_legacy_app_propagation_on_ssowat(): - app_install( os.path.join(get_test_apps_dir(), "legacy_app_ynh"), args="domain=%s&domain_2=%s&path=%s&is_public=1" diff --git a/src/tests/test_questions.py b/src/tests/test_questions.py index e49047469a..cf7c3c6e65 100644 --- a/src/tests/test_questions.py +++ b/src/tests/test_questions.py @@ -49,7 +49,6 @@ def test_question_empty(): def test_question_string(): - questions = { "some_string": { "type": "string", @@ -65,7 +64,6 @@ def test_question_string(): def test_question_string_from_query_string(): - questions = { "some_string": { "type": "string", @@ -1539,7 +1537,6 @@ def test_question_user_two_users_default_input(): os, "isatty", return_value=True ): with patch.object(user, "user_info", return_value={}): - with patch.object(Moulinette, "prompt", return_value=username): out = ask_questions_and_parse_answers(questions, answers)[0] @@ -1843,7 +1840,6 @@ def test_question_display_text(): def test_question_file_from_cli(): - FileQuestion.clean_upload_dirs() filename = "/tmp/ynh_test_question_file" @@ -1874,7 +1870,6 @@ def test_question_file_from_cli(): def test_question_file_from_api(): - FileQuestion.clean_upload_dirs() from base64 import b64encode @@ -1907,7 +1902,6 @@ def test_question_file_from_api(): def test_normalize_boolean_nominal(): - assert BooleanQuestion.normalize("yes") == 1 assert BooleanQuestion.normalize("Yes") == 1 assert BooleanQuestion.normalize(" yes ") == 1 @@ -1937,7 +1931,6 @@ def test_normalize_boolean_nominal(): def test_normalize_boolean_humanize(): - assert BooleanQuestion.humanize("yes") == "yes" assert BooleanQuestion.humanize("true") == "yes" assert BooleanQuestion.humanize("on") == "yes" @@ -1948,7 +1941,6 @@ def test_normalize_boolean_humanize(): def test_normalize_boolean_invalid(): - with pytest.raises(YunohostValidationError): BooleanQuestion.normalize("yesno") with pytest.raises(YunohostValidationError): @@ -1958,7 +1950,6 @@ def test_normalize_boolean_invalid(): def test_normalize_boolean_special_yesno(): - customyesno = {"yes": "enabled", "no": "disabled"} assert BooleanQuestion.normalize("yes", customyesno) == "enabled" @@ -1977,14 +1968,12 @@ def test_normalize_boolean_special_yesno(): def test_normalize_domain(): - assert DomainQuestion.normalize("https://yolo.swag/") == "yolo.swag" assert DomainQuestion.normalize("http://yolo.swag") == "yolo.swag" assert DomainQuestion.normalize("yolo.swag/") == "yolo.swag" def test_normalize_path(): - assert PathQuestion.normalize("") == "/" assert PathQuestion.normalize("") == "/" assert PathQuestion.normalize("macnuggets") == "/macnuggets" diff --git a/src/tests/test_regenconf.py b/src/tests/test_regenconf.py index f454f33e3b..8dda1a7f25 100644 --- a/src/tests/test_regenconf.py +++ b/src/tests/test_regenconf.py @@ -16,19 +16,16 @@ def setup_function(function): - _force_clear_hashes([TEST_DOMAIN_NGINX_CONFIG]) clean() def teardown_function(function): - clean() _force_clear_hashes([TEST_DOMAIN_NGINX_CONFIG]) def clean(): - assert os.system("pgrep slapd >/dev/null") == 0 assert os.system("pgrep nginx >/dev/null") == 0 @@ -48,7 +45,6 @@ def clean(): def test_add_domain(): - domain_add(TEST_DOMAIN) assert TEST_DOMAIN in domain_list()["domains"] @@ -60,7 +56,6 @@ def test_add_domain(): def test_add_and_edit_domain_conf(): - domain_add(TEST_DOMAIN) assert os.path.exists(TEST_DOMAIN_NGINX_CONFIG) @@ -73,7 +68,6 @@ def test_add_and_edit_domain_conf(): def test_add_domain_conf_already_exists(): - os.system("echo ' ' >> %s" % TEST_DOMAIN_NGINX_CONFIG) domain_add(TEST_DOMAIN) @@ -84,7 +78,6 @@ def test_add_domain_conf_already_exists(): def test_ssh_conf_unmanaged(): - _force_clear_hashes([SSHD_CONFIG]) assert SSHD_CONFIG not in _get_conf_hashes("ssh") @@ -95,7 +88,6 @@ def test_ssh_conf_unmanaged(): def test_ssh_conf_unmanaged_and_manually_modified(mocker): - _force_clear_hashes([SSHD_CONFIG]) os.system("echo ' ' >> %s" % SSHD_CONFIG) diff --git a/src/tests/test_service.py b/src/tests/test_service.py index 88013a3fe4..84573fd899 100644 --- a/src/tests/test_service.py +++ b/src/tests/test_service.py @@ -14,17 +14,14 @@ def setup_function(function): - clean() def teardown_function(function): - clean() def clean(): - # To run these tests, we assume ssh(d) service exists and is running assert os.system("pgrep sshd >/dev/null") == 0 @@ -45,46 +42,39 @@ def clean(): def test_service_status_all(): - status = service_status() assert "ssh" in status.keys() assert status["ssh"]["status"] == "running" def test_service_status_single(): - status = service_status("ssh") assert "status" in status.keys() assert status["status"] == "running" def test_service_log(): - logs = service_log("ssh") assert "journalctl" in logs.keys() assert "/var/log/auth.log" in logs.keys() def test_service_status_unknown_service(mocker): - with raiseYunohostError(mocker, "service_unknown"): service_status(["ssh", "doesnotexists"]) def test_service_add(): - service_add("dummyservice", description="A dummy service to run tests") assert "dummyservice" in service_status().keys() def test_service_add_real_service(): - service_add("networking") assert "networking" in service_status().keys() def test_service_remove(): - service_add("dummyservice", description="A dummy service to run tests") assert "dummyservice" in service_status().keys() service_remove("dummyservice") @@ -92,7 +82,6 @@ def test_service_remove(): def test_service_remove_service_that_doesnt_exists(mocker): - assert "dummyservice" not in service_status().keys() with raiseYunohostError(mocker, "service_unknown"): @@ -102,7 +91,6 @@ def test_service_remove_service_that_doesnt_exists(mocker): def test_service_update_to_add_properties(): - service_add("dummyservice", description="dummy") assert not _get_services()["dummyservice"].get("test_status") service_add("dummyservice", description="dummy", test_status="true") @@ -110,7 +98,6 @@ def test_service_update_to_add_properties(): def test_service_update_to_change_properties(): - service_add("dummyservice", description="dummy", test_status="false") assert _get_services()["dummyservice"].get("test_status") == "false" service_add("dummyservice", description="dummy", test_status="true") @@ -118,7 +105,6 @@ def test_service_update_to_change_properties(): def test_service_update_to_remove_properties(): - service_add("dummyservice", description="dummy", test_status="false") assert _get_services()["dummyservice"].get("test_status") == "false" service_add("dummyservice", description="dummy", test_status="") @@ -126,7 +112,6 @@ def test_service_update_to_remove_properties(): def test_service_conf_broken(): - os.system("echo pwet > /etc/nginx/conf.d/broken.conf") status = service_status("nginx") diff --git a/src/tests/test_settings.py b/src/tests/test_settings.py index 2eaebba55c..20f959a800 100644 --- a/src/tests/test_settings.py +++ b/src/tests/test_settings.py @@ -65,7 +65,6 @@ def teardown_function(function): def _monkeypatch_translator(self, key, *args, **kwargs): - if key.startswith("global_settings_setting_"): return f"Dummy translation for {key}" @@ -175,7 +174,6 @@ def test_settings_set_doesexit(): def test_settings_set_bad_type_bool(): - with patch.object(os, "isatty", return_value=False): with pytest.raises(YunohostError): settings_set("example.example.boolean", 42) diff --git a/src/tests/test_user-group.py b/src/tests/test_user-group.py index 343431b696..eececb8279 100644 --- a/src/tests/test_user-group.py +++ b/src/tests/test_user-group.py @@ -92,7 +92,6 @@ def test_list_groups(): def test_create_user(mocker): - with message(mocker, "user_created"): user_create("albert", maindomain, "test123Ynh", fullname="Albert Good") @@ -104,7 +103,6 @@ def test_create_user(mocker): def test_del_user(mocker): - with message(mocker, "user_deleted"): user_delete("alice") @@ -185,7 +183,6 @@ def test_export_user(mocker): def test_create_group(mocker): - with message(mocker, "group_created", group="adminsys"): user_group_create("adminsys") @@ -196,7 +193,6 @@ def test_create_group(mocker): def test_del_group(mocker): - with message(mocker, "group_deleted", group="dev"): user_group_delete("dev") diff --git a/src/tools.py b/src/tools.py index eb385f4a85..777d8fc8f1 100644 --- a/src/tools.py +++ b/src/tools.py @@ -62,7 +62,6 @@ def tools_versions(): def tools_rootpw(new_password, check_strength=True): - from yunohost.user import _hash_user_password from yunohost.utils.password import ( assert_password_is_strong_enough, @@ -154,7 +153,6 @@ def tools_postinstall( ignore_dyndns=False, force_diskspace=False, ): - from yunohost.dyndns import _dyndns_available from yunohost.utils.dns import is_yunohost_dyndns_domain from yunohost.utils.password import ( @@ -193,7 +191,6 @@ def tools_postinstall( # If this is a nohost.me/noho.st, actually check for availability if not ignore_dyndns and is_yunohost_dyndns_domain(domain): - available = None # Check if the domain is available... @@ -281,7 +278,6 @@ def tools_postinstall( def tools_regen_conf( names=[], with_diff=False, force=False, dry_run=False, list_pending=False ): - # Make sure the settings are migrated before running the migration, # which may otherwise fuck things up such as the ssh config ... # We do this here because the regen-conf is called before the migration in debian/postinst @@ -312,7 +308,6 @@ def tools_update(target=None): upgradable_system_packages = [] if target in ["system", "all"]: - # Update APT cache # LC_ALL=C is here to make sure the results are in english command = ( @@ -426,7 +421,6 @@ def tools_upgrade(operation_logger, target=None): # if target == "apps": - # Make sure there's actually something to upgrade upgradable_apps = [app["id"] for app in app_list(upgradable=True)["apps"]] @@ -450,7 +444,6 @@ def tools_upgrade(operation_logger, target=None): # if target == "system": - # Check that there's indeed some packages to upgrade upgradables = list(_list_upgradable_apt_packages()) if not upgradables: @@ -498,7 +491,6 @@ def is_relevant(line): any(p["name"] == "yunohost" for p in upgradables) and Moulinette.interface.type == "api" ): - # Restart the API after 10 sec (at now doesn't support sub-minute times...) # We do this so that the API / webadmin still gets the proper HTTP response # It's then up to the webadmin to implement a proper UX process to wait 10 sec and then auto-fresh the webadmin @@ -722,7 +714,6 @@ def get_matching_migration(target): # Actually run selected migrations for migration in targets: - # If we are migrating in "automatic mode" (i.e. from debian configure # during an upgrade of the package) but we are asked for running # migrations to be ran manually by the user, stop there and ask the @@ -778,7 +769,6 @@ def get_matching_migration(target): _write_migration_state(migration.id, "skipped") operation_logger.success() else: - try: migration.operation_logger = operation_logger logger.info(m18n.n("migrations_running_forward", id=migration.id)) @@ -810,14 +800,12 @@ def tools_migrations_state(): def _write_migration_state(migration_id, state): - current_states = tools_migrations_state() current_states["migrations"][migration_id] = state write_to_yaml(MIGRATIONS_STATE_PATH, current_states) def _get_migrations_list(): - # states is a datastructure that represents the last run migration # it has this form: # { @@ -868,7 +856,6 @@ def _get_migration_by_name(migration_name): def _load_migration(migration_file): - migration_id = migration_file[: -len(".py")] logger.debug(m18n.n("migrations_loading_migration", id=migration_id)) @@ -903,7 +890,6 @@ def _skip_all_migrations(): def _tools_migrations_run_after_system_restore(backup_version): - all_migrations = _get_migrations_list() current_version = version.parse(ynh_packages_version()["yunohost"]["version"]) @@ -930,7 +916,6 @@ def _tools_migrations_run_after_system_restore(backup_version): def _tools_migrations_run_before_app_restore(backup_version, app_id): - all_migrations = _get_migrations_list() current_version = version.parse(ynh_packages_version()["yunohost"]["version"]) @@ -957,7 +942,6 @@ def _tools_migrations_run_before_app_restore(backup_version, app_id): class Migration: - # Those are to be implemented by daughter classes mode = "auto" @@ -985,7 +969,6 @@ def description(self): def ldap_migration(run): def func(self): - # Backup LDAP before the migration logger.info(m18n.n("migration_ldap_backup_before_migration")) try: diff --git a/src/user.py b/src/user.py index ee0aebae63..797c3252f5 100644 --- a/src/user.py +++ b/src/user.py @@ -53,7 +53,6 @@ def user_list(fields=None): - from yunohost.utils.ldap import _get_ldap_interface ldap_attrs = { @@ -149,7 +148,6 @@ def user_create( from_import=False, loginShell=None, ): - if firstname or lastname: logger.warning( "Options --firstname / --lastname of 'yunohost user create' are deprecated. We recommend using --fullname instead." @@ -319,7 +317,6 @@ def user_create( @is_unit_operation([("username", "user")]) def user_delete(operation_logger, username, purge=False, from_import=False): - from yunohost.hook import hook_callback from yunohost.utils.ldap import _get_ldap_interface @@ -380,7 +377,6 @@ def user_update( fullname=None, loginShell=None, ): - if firstname or lastname: logger.warning( "Options --firstname / --lastname of 'yunohost user create' are deprecated. We recommend using --fullname instead." @@ -735,7 +731,6 @@ def to_list(str_list): ) for user in reader: - # Validate column values against regexes format_errors = [ f"{key}: '{user[key]}' doesn't match the expected format" @@ -991,7 +986,6 @@ def user_group_list(short=False, full=False, include_primary_groups=True): users = user_list()["users"] groups = {} for infos in groups_infos: - name = infos["cn"][0] if not include_primary_groups and name in users: @@ -1141,7 +1135,6 @@ def user_group_update( sync_perm=True, from_import=False, ): - from yunohost.permission import permission_sync_to_user from yunohost.utils.ldap import _get_ldap_interface, _ldap_path_extract @@ -1184,7 +1177,6 @@ def user_group_update( new_attr_dict = {} if add: - users_to_add = [add] if not isinstance(add, list) else add for user in users_to_add: @@ -1225,7 +1217,6 @@ def user_group_update( # Check the whole alias situation if add_mailalias: - from yunohost.domain import domain_list domains = domain_list()["domains"] @@ -1269,7 +1260,6 @@ def user_group_update( raise YunohostValidationError("mail_alias_remove_failed", mail=mail) if set(new_group_mail) != set(current_group_mail): - logger.info(m18n.n("group_update_aliases", group=groupname)) new_attr_dict["mail"] = set(new_group_mail) @@ -1477,7 +1467,6 @@ def _hash_user_password(password): def _update_admins_group_aliases(old_main_domain, new_main_domain): - current_admin_aliases = user_group_info("admins")["mail-aliases"] aliases_to_remove = [ diff --git a/src/utils/config.py b/src/utils/config.py index bd3a6b6a91..5dce4070d7 100644 --- a/src/utils/config.py +++ b/src/utils/config.py @@ -264,7 +264,6 @@ def get(self, key="", mode="classic"): # In 'classic' mode, we display the current value if key refer to an option if self.filter_key.count(".") == 2 and mode == "classic": - option = self.filter_key.split(".")[-1] value = self.values.get(option, None) @@ -280,7 +279,6 @@ def get(self, key="", mode="classic"): logger.debug(f"Formating result in '{mode}' mode") result = {} for panel, section, option in self._iterate(): - if section["is_action_section"] and mode != "full": continue @@ -323,7 +321,6 @@ def get(self, key="", mode="classic"): return result def list_actions(self): - actions = {} # FIXME : meh, loading the entire config panel is again going to cause @@ -462,7 +459,6 @@ def _get_toml(self): return read_toml(self.config_path) def _get_config_panel(self): - # Split filter_key filter_key = self.filter_key.split(".") if self.filter_key != "" else [] if len(filter_key) > 3: @@ -639,7 +635,6 @@ def _hydrate(self): # Hydrating config panel with current value for _, section, option in self._iterate(): if option["id"] not in self.values: - allowed_empty_types = [ "alert", "display_text", @@ -701,7 +696,6 @@ def display_header(message): Moulinette.display(colorize(message, "purple")) for panel, section, obj in self._iterate(["panel", "section"]): - if ( section and section.get("visible") @@ -814,7 +808,6 @@ def _apply(self): write_to_yaml(self.save_path, values_to_save) def _reload_services(self): - from yunohost.service import service_reload_or_restart services_to_reload = set() @@ -905,7 +898,6 @@ def _prompt(self, text): ) def ask_if_needed(self): - if self.visible and not evaluate_simple_js_expression( self.visible, context=self.context ): @@ -980,7 +972,6 @@ def _prevalidate(self): ) def _format_text_for_user_input_in_cli(self): - text_for_user_input_in_cli = _value_for_locale(self.ask) if self.readonly: @@ -991,7 +982,6 @@ def _format_text_for_user_input_in_cli(self): ) return text_for_user_input_in_cli + f" {self.humanize(self.current_value)}" elif self.choices: - # Prevent displaying a shitload of choices # (e.g. 100+ available users when choosing an app admin...) choices = ( @@ -1160,7 +1150,6 @@ class PathQuestion(Question): @staticmethod def normalize(value, option={}): - option = option.__dict__ if isinstance(option, Question) else option if not value.strip(): @@ -1187,7 +1176,6 @@ class BooleanQuestion(Question): @staticmethod def humanize(value, option={}): - option = option.__dict__ if isinstance(option, Question) else option yes = option.get("yes", 1) @@ -1211,7 +1199,6 @@ def humanize(value, option={}): @staticmethod def normalize(value, option={}): - option = option.__dict__ if isinstance(option, Question) else option if isinstance(value, str): @@ -1368,7 +1355,6 @@ class GroupQuestion(Question): def __init__( self, question, context: Mapping[str, Any] = {}, hooks: Dict[str, Callable] = {} ): - from yunohost.user import user_group_list super().__init__(question, context) @@ -1401,7 +1387,6 @@ def __init__( @staticmethod def normalize(value, option={}): - if isinstance(value, int): return value diff --git a/src/utils/dns.py b/src/utils/dns.py index 091168615a..225a0e98fc 100644 --- a/src/utils/dns.py +++ b/src/utils/dns.py @@ -31,19 +31,16 @@ def is_yunohost_dyndns_domain(domain): - return any( domain.endswith(f".{dyndns_domain}") for dyndns_domain in YNH_DYNDNS_DOMAINS ) def is_special_use_tld(domain): - return any(domain.endswith(f".{tld}") for tld in SPECIAL_USE_TLDS) def external_resolvers(): - global external_resolvers_ if not external_resolvers_: diff --git a/src/utils/error.py b/src/utils/error.py index e7046540dc..cdf2a3d096 100644 --- a/src/utils/error.py +++ b/src/utils/error.py @@ -21,7 +21,6 @@ class YunohostError(MoulinetteError): - http_code = 500 """ @@ -43,7 +42,6 @@ def __init__(self, key, raw_msg=False, log_ref=None, *args, **kwargs): super(YunohostError, self).__init__(msg, raw_msg=True) def content(self): - if not self.log_ref: return super().content() else: @@ -51,14 +49,11 @@ def content(self): class YunohostValidationError(YunohostError): - http_code = 400 def content(self): - return {"error": self.strerror, "error_key": self.key, **self.kwargs} class YunohostAuthenticationError(MoulinetteAuthenticationError): - pass diff --git a/src/utils/ldap.py b/src/utils/ldap.py index ee50d0b983..5a0e3ba35f 100644 --- a/src/utils/ldap.py +++ b/src/utils/ldap.py @@ -36,7 +36,6 @@ def _get_ldap_interface(): - global _ldap_interface if _ldap_interface is None: diff --git a/src/utils/legacy.py b/src/utils/legacy.py index 3334632c29..fa0b681379 100644 --- a/src/utils/legacy.py +++ b/src/utils/legacy.py @@ -193,7 +193,6 @@ def translate_legacy_default_app_in_ssowant_conf_json_persistent(): def _patch_legacy_php_versions(app_folder): - files_to_patch = [] files_to_patch.extend(glob.glob("%s/conf/*" % app_folder)) files_to_patch.extend(glob.glob("%s/scripts/*" % app_folder)) @@ -203,7 +202,6 @@ def _patch_legacy_php_versions(app_folder): files_to_patch.append("%s/manifest.toml" % app_folder) for filename in files_to_patch: - # Ignore non-regular files if not os.path.isfile(filename): continue @@ -217,7 +215,6 @@ def _patch_legacy_php_versions(app_folder): def _patch_legacy_php_versions_in_settings(app_folder): - settings = read_yaml(os.path.join(app_folder, "settings.yml")) if settings.get("fpm_config_dir") in ["/etc/php/7.0/fpm", "/etc/php/7.3/fpm"]: @@ -243,7 +240,6 @@ def _patch_legacy_php_versions_in_settings(app_folder): def _patch_legacy_helpers(app_folder): - files_to_patch = [] files_to_patch.extend(glob.glob("%s/scripts/*" % app_folder)) files_to_patch.extend(glob.glob("%s/scripts/.*" % app_folder)) @@ -291,7 +287,6 @@ def _patch_legacy_helpers(app_folder): infos["replace"] = infos.get("replace") for filename in files_to_patch: - # Ignore non-regular files if not os.path.isfile(filename): continue @@ -305,7 +300,6 @@ def _patch_legacy_helpers(app_folder): show_warning = False for helper, infos in stuff_to_replace.items(): - # Ignore if not relevant for this file if infos.get("only_for") and not any( filename.endswith(f) for f in infos["only_for"] @@ -329,7 +323,6 @@ def _patch_legacy_helpers(app_folder): ) if replaced_stuff: - # Check the app do load the helper # If it doesn't, add the instruction ourselve (making sure it's after the #!/bin/bash if it's there... if filename.split("/")[-1] in [ diff --git a/src/utils/network.py b/src/utils/network.py index 06dd3493d7..e9892333ef 100644 --- a/src/utils/network.py +++ b/src/utils/network.py @@ -29,7 +29,6 @@ def get_public_ip(protocol=4): - assert protocol in [4, 6], ( "Invalid protocol version for get_public_ip: %s, expected 4 or 6" % protocol ) @@ -90,7 +89,6 @@ def is_default_route(r): def get_network_interfaces(): - # Get network devices and their addresses (raw infos from 'ip addr') devices_raw = {} output = check_output("ip addr show") @@ -111,7 +109,6 @@ def get_network_interfaces(): def get_gateway(): - output = check_output("ip route show") m = re.search(r"default via (.*) dev ([a-z]+[0-9]?)", output) if not m: diff --git a/src/utils/password.py b/src/utils/password.py index 3202e8055c..569833a7d2 100644 --- a/src/utils/password.py +++ b/src/utils/password.py @@ -58,7 +58,6 @@ def assert_password_is_compatible(password): """ if len(password) >= 127: - # Note that those imports are made here and can't be put # on top (at least not the moulinette ones) # because the moulinette needs to be correctly initialized @@ -69,7 +68,6 @@ def assert_password_is_compatible(password): def assert_password_is_strong_enough(profile, password): - PasswordValidator(profile).validate(password) @@ -197,7 +195,6 @@ def strength_level(self, password): return strength_level def is_in_most_used_list(self, password): - # Decompress file if compressed if os.path.exists("%s.gz" % MOST_USED_PASSWORDS): os.system("gzip -fd %s.gz" % MOST_USED_PASSWORDS) diff --git a/src/utils/resources.py b/src/utils/resources.py index 7b500ad3fe..5695120067 100644 --- a/src/utils/resources.py +++ b/src/utils/resources.py @@ -37,7 +37,6 @@ class AppResourceManager: def __init__(self, app: str, current: Dict, wanted: Dict): - self.app = app self.current = current self.wanted = wanted @@ -50,7 +49,6 @@ def __init__(self, app: str, current: Dict, wanted: Dict): def apply( self, rollback_and_raise_exception_if_failure, operation_logger=None, **context ): - todos = list(self.compute_todos()) completed = [] rollback = False @@ -121,7 +119,6 @@ def apply( logger.error(exception) def compute_todos(self): - for name, infos in reversed(self.current["resources"].items()): if name not in self.wanted["resources"].keys(): resource = AppResourceClassesByType[name](infos, self.app, self) @@ -140,12 +137,10 @@ def compute_todos(self): class AppResource: - type: str = "" default_properties: Dict[str, Any] = {} def __init__(self, properties: Dict[str, Any], app: str, manager=None): - self.app = app self.manager = manager @@ -175,7 +170,6 @@ def delete_setting(self, key): app_setting(self.app, key, delete=True) def _run_script(self, action, script, env={}, user="root"): - from yunohost.app import ( _make_tmp_workdir_for_app, _make_environment_for_app_script, @@ -295,7 +289,6 @@ class PermissionsResource(AppResource): permissions: Dict[str, Dict[str, Any]] = {} def __init__(self, properties: Dict[str, Any], *args, **kwargs): - # FIXME : if url != None, we should check that there's indeed a domain/path defined ? ie that app is a webapp for perm, infos in properties.items(): @@ -315,7 +308,6 @@ def __init__(self, properties: Dict[str, Any], *args, **kwargs): super().__init__({"permissions": properties}, *args, **kwargs) def provision_or_update(self, context: Dict = {}): - from yunohost.permission import ( permission_create, permission_url, @@ -375,7 +367,6 @@ def provision_or_update(self, context: Dict = {}): permission_sync_to_user() def deprovision(self, context: Dict = {}): - from yunohost.permission import ( permission_delete, user_permission_list, @@ -432,7 +423,6 @@ class SystemuserAppResource(AppResource): allow_sftp: bool = False def provision_or_update(self, context: Dict = {}): - # FIXME : validate that no yunohost user exists with that name? # and/or that no system user exists during install ? @@ -462,7 +452,6 @@ def provision_or_update(self, context: Dict = {}): os.system(f"usermod -G {','.join(groups)} {self.app}") def deprovision(self, context: Dict = {}): - if check_output(f"getent passwd {self.app} &>/dev/null || true").strip(): os.system(f"deluser {self.app} >/dev/null") if check_output(f"getent passwd {self.app} &>/dev/null || true").strip(): @@ -528,7 +517,6 @@ class InstalldirAppResource(AppResource): # FIXME: change default dir to /opt/stuff if app ain't a webapp ... def provision_or_update(self, context: Dict = {}): - assert self.dir.strip() # Be paranoid about self.dir being empty... assert self.owner.strip() assert self.group.strip() @@ -582,7 +570,6 @@ def provision_or_update(self, context: Dict = {}): self.delete_setting("final_path") # Legacy def deprovision(self, context: Dict = {}): - assert self.dir.strip() # Be paranoid about self.dir being empty... assert self.owner.strip() assert self.group.strip() @@ -643,7 +630,6 @@ class DatadirAppResource(AppResource): group: str = "" def provision_or_update(self, context: Dict = {}): - assert self.dir.strip() # Be paranoid about self.dir being empty... assert self.owner.strip() assert self.group.strip() @@ -686,7 +672,6 @@ def provision_or_update(self, context: Dict = {}): self.delete_setting("datadir") # Legacy def deprovision(self, context: Dict = {}): - assert self.dir.strip() # Be paranoid about self.dir being empty... assert self.owner.strip() assert self.group.strip() @@ -737,7 +722,6 @@ class AptDependenciesAppResource(AppResource): extras: Dict[str, Dict[str, str]] = {} def __init__(self, properties: Dict[str, Any], *args, **kwargs): - for key, values in properties.get("extras", {}).items(): if not all( isinstance(values.get(k), str) for k in ["repo", "key", "packages"] @@ -749,7 +733,6 @@ def __init__(self, properties: Dict[str, Any], *args, **kwargs): super().__init__(properties, *args, **kwargs) def provision_or_update(self, context: Dict = {}): - script = [f"ynh_install_app_dependencies {self.packages}"] for repo, values in self.extras.items(): script += [ @@ -760,7 +743,6 @@ def provision_or_update(self, context: Dict = {}): self._run_script("provision_or_update", "\n".join(script)) def deprovision(self, context: Dict = {}): - self._run_script("deprovision", "ynh_remove_app_dependencies") @@ -818,7 +800,6 @@ class PortsResource(AppResource): ports: Dict[str, Dict[str, Any]] def __init__(self, properties: Dict[str, Any], *args, **kwargs): - if "main" not in properties: properties["main"] = {} @@ -832,7 +813,6 @@ def __init__(self, properties: Dict[str, Any], *args, **kwargs): super().__init__({"ports": properties}, *args, **kwargs) def _port_is_used(self, port): - # FIXME : this could be less brutal than two os.system ... cmd1 = ( "ss --numeric --listening --tcp --udp | awk '{print$5}' | grep --quiet --extended-regexp ':%s$'" @@ -843,11 +823,9 @@ def _port_is_used(self, port): return os.system(cmd1) == 0 and os.system(cmd2) == 0 def provision_or_update(self, context: Dict = {}): - from yunohost.firewall import firewall_allow, firewall_disallow for name, infos in self.ports.items(): - setting_name = f"port_{name}" if name != "main" else "port" port_value = self.get_setting(setting_name) if not port_value and name != "main": @@ -881,7 +859,6 @@ def provision_or_update(self, context: Dict = {}): ) def deprovision(self, context: Dict = {}): - from yunohost.firewall import firewall_disallow for name, infos in self.ports.items(): @@ -938,7 +915,6 @@ class DatabaseAppResource(AppResource): } def __init__(self, properties: Dict[str, Any], *args, **kwargs): - if "type" not in properties or properties["type"] not in [ "mysql", "postgresql", @@ -956,7 +932,6 @@ def __init__(self, properties: Dict[str, Any], *args, **kwargs): super().__init__(properties, *args, **kwargs) def db_exists(self, db_name): - if self.dbtype == "mysql": return os.system(f"mysqlshow '{db_name}' >/dev/null 2>/dev/null") == 0 elif self.dbtype == "postgresql": @@ -970,7 +945,6 @@ def db_exists(self, db_name): return False def provision_or_update(self, context: Dict = {}): - # This is equivalent to ynh_sanitize_dbid db_name = self.app.replace("-", "_").replace(".", "_") db_user = db_name @@ -997,7 +971,6 @@ def provision_or_update(self, context: Dict = {}): self.set_setting("db_pwd", db_pwd) if not self.db_exists(db_name): - if self.dbtype == "mysql": self._run_script( "provision", @@ -1010,7 +983,6 @@ def provision_or_update(self, context: Dict = {}): ) def deprovision(self, context: Dict = {}): - db_name = self.app.replace("-", "_").replace(".", "_") db_user = db_name diff --git a/src/utils/system.py b/src/utils/system.py index 8b0ed70928..c55023e52a 100644 --- a/src/utils/system.py +++ b/src/utils/system.py @@ -49,7 +49,6 @@ def free_space_in_directory(dirpath): def space_used_by_directory(dirpath, follow_symlinks=True): - if not follow_symlinks: du_output = check_output(["du", "-sb", dirpath], shell=False) return int(du_output.split()[0]) @@ -61,7 +60,6 @@ def space_used_by_directory(dirpath, follow_symlinks=True): def human_to_binary(size: str) -> int: - symbols = ("K", "M", "G", "T", "P", "E", "Z", "Y") factor = {} for i, s in enumerate(symbols): @@ -99,14 +97,12 @@ def binary_to_human(n: int) -> str: def ram_available(): - import psutil return (psutil.virtual_memory().available, psutil.swap_memory().free) def get_ynh_package_version(package): - # Returns the installed version and release version ('stable' or 'testing' # or 'unstable') @@ -152,7 +148,6 @@ def dpkg_lock_available(): def _list_upgradable_apt_packages(): - # List upgradable packages # LC_ALL=C is here to make sure the results are in english upgradable_raw = check_output("LC_ALL=C apt list --upgradable") @@ -162,7 +157,6 @@ def _list_upgradable_apt_packages(): line.strip() for line in upgradable_raw.split("\n") if line.strip() ] for line in upgradable_raw: - # Remove stupid warning and verbose messages >.> if "apt does not have a stable CLI interface" in line or "Listing..." in line: continue @@ -182,7 +176,6 @@ def _list_upgradable_apt_packages(): def _dump_sources_list(): - from glob import glob filenames = glob("/etc/apt/sources.list") + glob("/etc/apt/sources.list.d/*") diff --git a/src/utils/yunopaste.py b/src/utils/yunopaste.py index 0edcc721b6..806f8a34f2 100644 --- a/src/utils/yunopaste.py +++ b/src/utils/yunopaste.py @@ -28,7 +28,6 @@ def yunopaste(data): - paste_server = "https://paste.yunohost.org" try: From 480f7a43ef1e571fe6800afd547da0c41cd3ec4e Mon Sep 17 00:00:00 2001 From: Axolotle Date: Wed, 1 Feb 2023 18:13:07 +0100 Subject: [PATCH 56/67] fix domain_config.toml typos in conditions --- share/config_domain.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/share/config_domain.toml b/share/config_domain.toml index b1ec436c5a..c67996d13a 100644 --- a/share/config_domain.toml +++ b/share/config_domain.toml @@ -64,24 +64,24 @@ name = "Certificate" [cert.cert.acme_eligible_explain] type = "alert" style = "warning" - visible = "acme_eligible == false || acme_elligible == null" + visible = "acme_eligible == false || acme_eligible == null" [cert.cert.cert_no_checks] ask = "Ignore diagnosis checks" type = "boolean" default = false - visible = "acme_eligible == false || acme_elligible == null" + visible = "acme_eligible == false || acme_eligible == null" [cert.cert.cert_install] type = "button" icon = "star" style = "success" - visible = "issuer != 'letsencrypt'" + visible = "cert_issuer != 'letsencrypt'" enabled = "acme_eligible || cert_no_checks" [cert.cert.cert_renew] type = "button" icon = "refresh" style = "warning" - visible = "issuer == 'letsencrypt'" + visible = "cert_issuer == 'letsencrypt'" enabled = "acme_eligible || cert_no_checks" From daa9eb1cab7eb6da81e808d19766e0ebeefa60a3 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 1 Feb 2023 18:30:51 +0100 Subject: [PATCH 57/67] Duplicate import --- src/diagnosers/24-mail.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/diagnosers/24-mail.py b/src/diagnosers/24-mail.py index d48b1959ed..9a4cd1fc3f 100644 --- a/src/diagnosers/24-mail.py +++ b/src/diagnosers/24-mail.py @@ -31,7 +31,6 @@ from yunohost.domain import _get_maindomain, domain_list from yunohost.settings import settings_get from yunohost.utils.dns import dig -from yunohost.settings import settings_get DEFAULT_DNS_BLACKLIST = "/usr/share/yunohost/dnsbl_list.yml" From 452ba8bb9a8da0ed32a0e5f57e74134c37893f0c Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 1 Feb 2023 18:39:05 +0100 Subject: [PATCH 58/67] Don't try restarting metronome if no domain configured for it --- src/certificate.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/certificate.py b/src/certificate.py index 0addca8582..c9165fa6dc 100644 --- a/src/certificate.py +++ b/src/certificate.py @@ -20,7 +20,7 @@ import sys import shutil import subprocess -import glob +from glob import glob from datetime import datetime @@ -734,10 +734,11 @@ def _enable_certificate(domain, new_cert_folder): logger.debug("Restarting services...") for service in ("dovecot", "metronome"): - # Ugly trick to not restart metronome if it's not installed + # Ugly trick to not restart metronome if it's not installed or no domain configured for XMPP if ( service == "metronome" - and os.system("dpkg --list | grep -q 'ii *metronome'") != 0 + and (os.system("dpkg --list | grep -q 'ii *metronome'") != 0 + or not glob("/etc/metronome/conf.d/*.cfg.lua")) ): continue _run_service_command("restart", service) @@ -853,7 +854,7 @@ def _regen_dnsmasq_if_needed(): do_regen = False # For all domain files in DNSmasq conf... - domainsconf = glob.glob("/etc/dnsmasq.d/*.*") + domainsconf = glob("/etc/dnsmasq.d/*.*") for domainconf in domainsconf: # Look for the IP, it's in the lines with this format : # host-record=the.domain.tld,11.22.33.44 From 314d27bec1fc96a63690309753b1b81e2872f028 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 1 Feb 2023 20:21:19 +0100 Subject: [PATCH 59/67] Fix flake8 complains --- doc/generate_api_doc.py | 13 +++++++------ src/settings.py | 2 +- tox.ini | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/doc/generate_api_doc.py b/doc/generate_api_doc.py index fc44ffbcd3..514415eef9 100644 --- a/doc/generate_api_doc.py +++ b/doc/generate_api_doc.py @@ -26,15 +26,16 @@ def main(): - """ """ + with open("../share/actionsmap.yml") as f: action_map = yaml.safe_load(f) - try: - with open("/etc/yunohost/current_host", "r") as f: - domain = f.readline().rstrip() - except IOError: - domain = requests.get("http://ip.yunohost.org").text + #try: + # with open("/etc/yunohost/current_host", "r") as f: + # domain = f.readline().rstrip() + #except IOError: + # domain = requests.get("http://ip.yunohost.org").text + with open("../debian/changelog") as f: top_changelog = f.readline() api_version = top_changelog[top_changelog.find("(") + 1 : top_changelog.find(")")] diff --git a/src/settings.py b/src/settings.py index d1203930df..a06377176d 100644 --- a/src/settings.py +++ b/src/settings.py @@ -198,7 +198,7 @@ def _load_current_values(self): self.values["passwordless_sudo"] = "!authenticate" in ldap.search( "ou=sudo", "cn=admins", ["sudoOption"] )[0].get("sudoOption", []) - except: + except Exception: self.values["passwordless_sudo"] = False def get(self, key="", mode="classic"): diff --git a/tox.ini b/tox.ini index dc2c52074b..49c78959d2 100644 --- a/tox.ini +++ b/tox.ini @@ -8,7 +8,7 @@ deps = py39-black-{run,check}: black py39-mypy: mypy >= 0.900 commands = - py39-lint: flake8 src doc maintenance tests --ignore E402,E501,E203,W503 --exclude src/vendor + py39-lint: flake8 src doc maintenance tests --ignore E402,E501,E203,W503,E741 --exclude src/vendor py39-invalidcode: flake8 src bin maintenance --exclude src/tests,src/vendor --select F,E722,W605 py39-black-check: black --check --diff bin src doc maintenance tests py39-black-run: black bin src doc maintenance tests From c2c0a66cdf43abccf83fc2bdea66f04eecd5c44e Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 1 Feb 2023 20:22:56 +0100 Subject: [PATCH 60/67] Upate changelog for 11.1.5 --- debian/changelog | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/debian/changelog b/debian/changelog index 637a74bfd9..0d13b3c920 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,15 @@ +yunohost (11.1.5) stable; urgency=low + + - Release as stable ! + + - diagnosis: we can't yield an ERROR if there's no IPv6, otherwise that blocks all subsequent network-related diagnoser because of the dependency system ... (ade92e43) + - domains: fix domain_config.toml typos in conditions (480f7a43) + - certs: Don't try restarting metronome if no domain configured for it (452ba8bb) + + Thanks to all contributors <3 ! (Axolotle) + + -- Alexandre Aubin Wed, 01 Feb 2023 20:21:56 +0100 + yunohost (11.1.4.1) testing; urgency=low - debian: don't dump upgradable apps during postinst's catalog update (82d30f02) From 0826a54189f6ac3424c3b59dace1f550a28acf8f Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 2 Feb 2023 14:14:35 +0100 Subject: [PATCH 61/67] debian: Bump moulinette/ssowat requirement to 11.1 --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index facedbff27..0258eaac77 100644 --- a/debian/control +++ b/debian/control @@ -10,7 +10,7 @@ Package: yunohost Essential: yes Architecture: all Depends: ${python3:Depends}, ${misc:Depends} - , moulinette (>= 11.0), ssowat (>= 11.0) + , moulinette (>= 11.1), ssowat (>= 11.1) , python3-psutil, python3-requests, python3-dnspython, python3-openssl , python3-miniupnpc, python3-dbus, python3-jinja2 , python3-toml, python3-packaging, python3-publicsuffix2 From 9004cc76152b23b577f09f44574d230466fe71dc Mon Sep 17 00:00:00 2001 From: ppr Date: Mon, 30 Jan 2023 17:21:33 +0000 Subject: [PATCH 62/67] Translated using Weblate (French) Currently translated at 99.6% (750 of 753 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/fr/ --- locales/fr.json | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/locales/fr.json b/locales/fr.json index 41e58a1c59..9e0a24578f 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -748,5 +748,8 @@ "app_not_enough_ram": "Cette application nécessite {required} de mémoire vive (RAM) pour être installée/mise à niveau mais seule {current} de mémoire est disponible actuellement.", "app_yunohost_version_not_supported": "Cette application nécessite une version de YunoHost >= {required}. La version installée est {current}", "confirm_notifications_read": "AVERTISSEMENT : Vous devriez vérifier les notifications de l'application susmentionnée avant de continuer, il pourrait y avoir des informations importantes à connaître. [{answers}]", - "invalid_shell": "Shell invalide : {shell}" -} \ No newline at end of file + "invalid_shell": "Shell invalide : {shell}", + "global_settings_setting_dns_exposure": "Versions/Suites d'IP à prendre en compte pour la configuration et le diagnostic du DNS", + "global_settings_setting_dns_exposure_help": "NB : Ceci n'affecte que la configuration DNS recommandée et les vérifications de diagnostic. Cela n'affecte pas les configurations du système.", + "diagnosis_ip_no_ipv6_tip_important": "IPv6 devrait généralement être configuré automatiquement par le système ou par votre fournisseur d'accès à internet (FAI) s'il est disponible. Sinon, vous devrez peut-être configurer quelques éléments manuellement, comme expliqué dans la documentation ici : https://yunohost.org/#/ipv6." +} From 7ac6471b00165440e4c824ffeb0c67751058698c Mon Sep 17 00:00:00 2001 From: ButterflyOfFire Date: Tue, 31 Jan 2023 09:53:24 +0000 Subject: [PATCH 63/67] Translated using Weblate (Arabic) Currently translated at 22.0% (166 of 753 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/ar/ --- locales/ar.json | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/locales/ar.json b/locales/ar.json index dd254096b9..c1d6cbcfbb 100644 --- a/locales/ar.json +++ b/locales/ar.json @@ -10,7 +10,7 @@ "app_not_installed": "إنّ التطبيق {app} غير مُنصَّب", "app_not_properly_removed": "لم يتم حذف تطبيق {app} بشكلٍ جيّد", "app_removed": "تمت إزالة تطبيق {app}", - "app_requirements_checking": "جار فحص الحزم اللازمة لـ {app}…", + "app_requirements_checking": "جار فحص متطلبات تطبيق {app}…", "app_sources_fetch_failed": "تعذر جلب ملفات المصدر ، هل عنوان URL صحيح؟", "app_unknown": "برنامج مجهول", "app_upgrade_app_name": "جارٍ تحديث {app}…", @@ -49,14 +49,14 @@ "pattern_domain": "يتوجب أن يكون إسم نطاق صالح (مثل my-domain.org)", "pattern_email": "يتوجب أن يكون عنوان بريد إلكتروني صالح (مثل someone@domain.org)", "pattern_password": "يتوجب أن تكون مكونة من 3 حروف على الأقل", - "restore_extracting": "جارٍ فك الضغط عن الملفات التي نحتاجها من النسخة الاحتياطية…", + "restore_extracting": "جارٍ فك الضغط عن الملفات اللازمة من النسخة الاحتياطية…", "server_shutdown": "سوف ينطفئ الخادوم", "server_shutdown_confirm": "سوف ينطفئ الخادوم حالا. متأكد ؟ [{answers}]", "server_reboot": "سيعاد تشغيل الخادوم", "server_reboot_confirm": "سيعاد تشغيل الخادوم في الحين. هل أنت متأكد ؟ [{answers}]", "service_add_failed": "تعذرت إضافة خدمة '{service}'", "service_already_stopped": "إنّ خدمة '{service}' متوقفة مِن قبلُ", - "service_disabled": "لن يتم إطلاق خدمة '{service}' أثناء بداية تشغيل النظام.", + "service_disabled": "لن يتم إطلاق خدمة '{service}' أثناء بداية تشغيل النظام بتاتا.", "service_enabled": "سيتم الآن بدء تشغيل الخدمة '{service}' تلقائيًا أثناء تمهيد النظام.", "service_removed": "تمت إزالة خدمة '{service}'", "service_started": "تم إطلاق تشغيل خدمة '{service}'", @@ -71,10 +71,10 @@ "user_deleted": "تم حذف المستخدم", "user_deletion_failed": "لا يمكن حذف المستخدم", "user_unknown": "المستخدم {user} مجهول", - "user_update_failed": "لا يمكن تحديث المستخدم", - "user_updated": "تم تحديث المستخدم", + "user_update_failed": "لا يمكن تحديث المستخدم {user}: {error}", + "user_updated": "تم تحديث معلومات المستخدم", "yunohost_installing": "عملية تنصيب واي يونوهوست جارية …", - "yunohost_not_installed": "إنَّ واي يونوهوست ليس مُنَصَّب أو هو مثبت حاليا بشكل خاطئ. قم بتنفيذ الأمر 'yunohost tools postinstall'", + "yunohost_not_installed": "إنَّ واي يونوهوست ليس مُنَصَّب بشكل جيد. فضلًا قم بتنفيذ الأمر 'yunohost tools postinstall'", "migrations_list_conflict_pending_done": "لا يمكنك استخدام --previous و --done معًا على نفس سطر الأوامر.", "service_description_metronome": "يُدير حسابات الدردشة الفورية XMPP", "service_description_nginx": "يقوم بتوفير النفاذ و السماح بالوصول إلى كافة مواقع الويب المستضافة على خادومك", @@ -199,10 +199,15 @@ "service_description_yunomdns": "يسمح لك بالوصول إلى خادمك الخاص باستخدام 'yunohost.local' في شبكتك المحلية", "good_practices_about_user_password": "أنت الآن على وشك تحديد كلمة مرور مستخدم جديدة. يجب أن تتكون كلمة المرور من 8 أحرف على الأقل - على الرغم من أنه من الممارسات الجيدة استخدام كلمة مرور أطول (أي عبارة مرور) و / أو مجموعة متنوعة من الأحرف (الأحرف الكبيرة والصغيرة والأرقام والأحرف الخاصة).", "root_password_changed": "تم تغيير كلمة مرور الجذر", - "root_password_desynchronized": "تم تغيير كلمة مرور المسؤول ، لكن لم يتمكن YunoHost من نشرها على كلمة مرور الجذر!", + "root_password_desynchronized": "تم تغيير كلمة مرور المدير ، لكن لم يتمكن YunoHost من نشرها على كلمة مرور الجذر!", "user_import_bad_line": "سطر غير صحيح {line}: {details}", "user_import_success": "تم استيراد المستخدمين بنجاح", "visitors": "الزوار", "password_too_simple_3": "يجب أن تتكون كلمة المرور من 8 أحرف على الأقل وأن تحتوي على أرقام وأرقام علوية وسفلية وأحرف خاصة", - "password_too_simple_4": "يجب أن تتكون كلمة المرور من 12 حرفًا على الأقل وأن تحتوي على أرقام وأرقام علوية وسفلية وأحرف خاصة" -} \ No newline at end of file + "password_too_simple_4": "يجب أن تتكون كلمة المرور من 12 حرفًا على الأقل وأن تحتوي على أرقام وأرقام علوية وسفلية وأحرف خاصة", + "service_unknown": "الخدمة '{service}' غير معروفة", + "unbackup_app": "لن يتم حفظ التطبيق '{app}'", + "unrestore_app": "لن يتم استعادة التطبيق '{app}'", + "yunohost_already_installed": "إنّ YunoHost مُنصّب مِن قَبل", + "hook_name_unknown": "إسم الإجراء '{name}' غير معروف" +} From dabf86be7767a1cedfb79aff0921868ffe19998f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Gaspar?= Date: Tue, 31 Jan 2023 11:31:41 +0000 Subject: [PATCH 64/67] Translated using Weblate (French) Currently translated at 100.0% (753 of 753 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/fr/ --- locales/fr.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/fr.json b/locales/fr.json index 9e0a24578f..c1647334a2 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -749,7 +749,7 @@ "app_yunohost_version_not_supported": "Cette application nécessite une version de YunoHost >= {required}. La version installée est {current}", "confirm_notifications_read": "AVERTISSEMENT : Vous devriez vérifier les notifications de l'application susmentionnée avant de continuer, il pourrait y avoir des informations importantes à connaître. [{answers}]", "invalid_shell": "Shell invalide : {shell}", - "global_settings_setting_dns_exposure": "Versions/Suites d'IP à prendre en compte pour la configuration et le diagnostic du DNS", + "global_settings_setting_dns_exposure": "Suites d'IP à prendre en compte pour la configuration et le diagnostic du DNS", "global_settings_setting_dns_exposure_help": "NB : Ceci n'affecte que la configuration DNS recommandée et les vérifications de diagnostic. Cela n'affecte pas les configurations du système.", "diagnosis_ip_no_ipv6_tip_important": "IPv6 devrait généralement être configuré automatiquement par le système ou par votre fournisseur d'accès à internet (FAI) s'il est disponible. Sinon, vous devrez peut-être configurer quelques éléments manuellement, comme expliqué dans la documentation ici : https://yunohost.org/#/ipv6." } From 7e9678622a0131e1586c367cc6984bc0dccdec87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20M?= Date: Thu, 2 Feb 2023 05:27:30 +0000 Subject: [PATCH 65/67] Translated using Weblate (Galician) Currently translated at 99.6% (750 of 753 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/gl/ --- locales/gl.json | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/locales/gl.json b/locales/gl.json index c592c650f8..7ba5c181f8 100644 --- a/locales/gl.json +++ b/locales/gl.json @@ -745,5 +745,8 @@ "app_yunohost_version_not_supported": "Esta app require YunoHost >= {required} pero a versión actual instalada é {current}", "confirm_app_insufficient_ram": "PERIGO! Esta app precisa {required} de RAM para instalar/actualizar pero só hai {current} dispoñibles. Incluso se a app funcionase, o seu proceso de instalación/actualización require gran cantidade de RAM e o teu servidor podería colgarse e fallar. Se queres asumir o risco, escribe '{answers}'", "confirm_notifications_read": "AVISO: Deberías comprobar as notificacións da app antes de continuar, poderías ter información importante que revisar. [{answers}]", - "app_not_enough_ram": "Esta app require {required} de RAM para instalar/actualizar pero só hai {current} dispoñible." -} \ No newline at end of file + "app_not_enough_ram": "Esta app require {required} de RAM para instalar/actualizar pero só hai {current} dispoñible.", + "global_settings_setting_dns_exposure": "Versións de IP a ter en conta para a configuración DNS e diagnóstico", + "global_settings_setting_dns_exposure_help": "Nota: Esto só lle afecta á configuración DNS recomendada e diagnóstico do sistema. Non lle afecta aos axustes do sistema.", + "diagnosis_ip_no_ipv6_tip_important": "Se está dispoñible, IPv6 debería estar automáticamente configurado polo sistema ou o teu provedor. Se non, pode que teñas que facer algúns axustes manualmente tal como se explica na documentación: https://yunohost.org/#/ipv6." +} From 3577956c06c6c52b3876d46462b84f0c97e831c1 Mon Sep 17 00:00:00 2001 From: yunohost-bot Date: Thu, 2 Feb 2023 13:35:03 +0000 Subject: [PATCH 66/67] [CI] Format code with Black --- doc/generate_api_doc.py | 5 ++--- src/certificate.py | 7 +++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/doc/generate_api_doc.py b/doc/generate_api_doc.py index 514415eef9..6b75f8a730 100644 --- a/doc/generate_api_doc.py +++ b/doc/generate_api_doc.py @@ -26,14 +26,13 @@ def main(): - with open("../share/actionsmap.yml") as f: action_map = yaml.safe_load(f) - #try: + # try: # with open("/etc/yunohost/current_host", "r") as f: # domain = f.readline().rstrip() - #except IOError: + # except IOError: # domain = requests.get("http://ip.yunohost.org").text with open("../debian/changelog") as f: diff --git a/src/certificate.py b/src/certificate.py index c9165fa6dc..a0eba212a7 100644 --- a/src/certificate.py +++ b/src/certificate.py @@ -735,10 +735,9 @@ def _enable_certificate(domain, new_cert_folder): for service in ("dovecot", "metronome"): # Ugly trick to not restart metronome if it's not installed or no domain configured for XMPP - if ( - service == "metronome" - and (os.system("dpkg --list | grep -q 'ii *metronome'") != 0 - or not glob("/etc/metronome/conf.d/*.cfg.lua")) + if service == "metronome" and ( + os.system("dpkg --list | grep -q 'ii *metronome'") != 0 + or not glob("/etc/metronome/conf.d/*.cfg.lua") ): continue _run_service_command("restart", service) From 7c4c3188e497900741a38772185045b6318589ef Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 2 Feb 2023 14:37:17 +0100 Subject: [PATCH 67/67] Unused import --- doc/generate_api_doc.py | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/generate_api_doc.py b/doc/generate_api_doc.py index 6b75f8a730..bb5f1df298 100644 --- a/doc/generate_api_doc.py +++ b/doc/generate_api_doc.py @@ -22,7 +22,6 @@ import sys import yaml import json -import requests def main():