From 439a999c02c172fe1d0299bc3a7f779d719e8a5f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Josu=C3=A9=20Tille?=
Date: Sun, 26 Aug 2018 12:47:15 +0200
Subject: [PATCH 001/180] Add hook support in domain_dns_conf
---
src/yunohost/domain.py | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/yunohost/domain.py b/src/yunohost/domain.py
index 560a6fda5..644b233d2 100644
--- a/src/yunohost/domain.py
+++ b/src/yunohost/domain.py
@@ -188,6 +188,7 @@ def domain_dns_conf(domain, ttl=None):
ttl -- Time to live
"""
+ from yunohost.hook import hook_callback
ttl = 3600 if ttl is None else ttl
@@ -209,6 +210,11 @@ def domain_dns_conf(domain, ttl=None):
for record in dns_conf["mail"]:
result += "\n{name} {ttl} IN {type} {value}".format(**record)
+ result += "\n\n"
+ result += "; Custom\n"
+
+ result += ''.join(hook_callback('custom_dns_rules', args=[])['stdreturn'])
+
is_cli = True if msettings.get('interface') == 'cli' else False
if is_cli:
logger.info(m18n.n("domain_dns_conf_is_just_a_recommendation"))
From 5a27e314ff78fbc29b8c9849a555732977e9b223 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Josu=C3=A9=20Tille?=
Date: Sun, 26 Aug 2018 14:59:52 +0200
Subject: [PATCH 002/180] Get custom dns conf in _build_dns_conf
---
src/yunohost/domain.py | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)
diff --git a/src/yunohost/domain.py b/src/yunohost/domain.py
index 644b233d2..475b23223 100644
--- a/src/yunohost/domain.py
+++ b/src/yunohost/domain.py
@@ -38,6 +38,7 @@ import yunohost.certificate
from yunohost.service import service_regen_conf
from yunohost.utils.network import get_public_ip
from yunohost.log import is_unit_operation
+from yunohost.hook import hook_callback
logger = getActionLogger('yunohost.domain')
@@ -188,7 +189,6 @@ def domain_dns_conf(domain, ttl=None):
ttl -- Time to live
"""
- from yunohost.hook import hook_callback
ttl = 3600 if ttl is None else ttl
@@ -212,8 +212,8 @@ def domain_dns_conf(domain, ttl=None):
result += "\n\n"
result += "; Custom\n"
-
- result += ''.join(hook_callback('custom_dns_rules', args=[])['stdreturn'])
+ for record in dns_conf["custom"]:
+ result += "\n{name} {ttl} IN {type} {value}".format(**record)
is_cli = True if msettings.get('interface') == 'cli' else False
if is_cli:
@@ -393,12 +393,22 @@ def _build_dns_conf(domain, ttl=3600):
["_dmarc", ttl, "TXT", '"v=DMARC1; p=none"'],
]
- return {
+ # Custom
+ hookres = hook_callback('custom_dns_rules', args=[domain])
+ print(hookres)
+ custom = []
+ for h in hookres.values() :
+ custom.extend(h['stdreturn'])
+
+ res = {
"basic": [{"name": name, "ttl": ttl, "type": type_, "value": value} for name, ttl, type_, value in basic],
"xmpp": [{"name": name, "ttl": ttl, "type": type_, "value": value} for name, ttl, type_, value in xmpp],
"mail": [{"name": name, "ttl": ttl, "type": type_, "value": value} for name, ttl, type_, value in mail],
+ "custom": custom,
}
+ return res
+
def _get_DKIM(domain):
DKIM_file = '/etc/dkim/{domain}.mail.txt'.format(domain=domain)
From f83e9cae7d24ec8e3ca6c80ce71e7e5503444093 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Josu=C3=A9=20Tille?=
Date: Wed, 29 Aug 2018 21:49:35 +0200
Subject: [PATCH 003/180] Dns hook : add specific comment for each hook
---
src/yunohost/domain.py | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/src/yunohost/domain.py b/src/yunohost/domain.py
index 475b23223..6c094e80b 100644
--- a/src/yunohost/domain.py
+++ b/src/yunohost/domain.py
@@ -210,10 +210,12 @@ def domain_dns_conf(domain, ttl=None):
for record in dns_conf["mail"]:
result += "\n{name} {ttl} IN {type} {value}".format(**record)
- result += "\n\n"
- result += "; Custom\n"
- for record in dns_conf["custom"]:
- result += "\n{name} {ttl} IN {type} {value}".format(**record)
+ for name, record_list in dns_conf.items():
+ if name not in ("basic", "xmpp", "mail"):
+ result += "\n\n"
+ result += "; " + name + "\n"
+ for record in record_list:
+ result += "\n{name} {ttl} IN {type} {value}".format(**record)
is_cli = True if msettings.get('interface') == 'cli' else False
if is_cli:
@@ -393,20 +395,18 @@ def _build_dns_conf(domain, ttl=3600):
["_dmarc", ttl, "TXT", '"v=DMARC1; p=none"'],
]
- # Custom
- hookres = hook_callback('custom_dns_rules', args=[domain])
- print(hookres)
- custom = []
- for h in hookres.values() :
- custom.extend(h['stdreturn'])
-
+ # Official record
res = {
"basic": [{"name": name, "ttl": ttl, "type": type_, "value": value} for name, ttl, type_, value in basic],
"xmpp": [{"name": name, "ttl": ttl, "type": type_, "value": value} for name, ttl, type_, value in xmpp],
"mail": [{"name": name, "ttl": ttl, "type": type_, "value": value} for name, ttl, type_, value in mail],
- "custom": custom,
}
+ # Custom record
+ hookres = hook_callback('custom_dns_rules', args=[domain])
+ for n,v in hookres.items() :
+ res[n] = v['stdreturn']
+
return res
From a20b72c2dd26db2721a6d9d9b61fcc3ea116abb8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Josu=C3=A9=20Tille?=
Date: Tue, 4 Sep 2018 22:50:45 +0200
Subject: [PATCH 004/180] Add comment about DNS datastructure returned
---
src/yunohost/domain.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/yunohost/domain.py b/src/yunohost/domain.py
index 6c094e80b..a9df20026 100644
--- a/src/yunohost/domain.py
+++ b/src/yunohost/domain.py
@@ -342,6 +342,9 @@ def _build_dns_conf(domain, ttl=3600):
{"type": "TXT", "name": "mail._domainkey", "value": "\"v=DKIM1; k=rsa; p=some-super-long-key\"", "ttl": 3600},
{"type": "TXT", "name": "_dmarc", "value": "\"v=DMARC1; p=none\"", "ttl": 3600}
],
+ "example_of_a_custom_rule": [
+ {"type": "SRV", "name": "_matrix", "value": "domain.tld.", "ttl": 3600}
+ ],
}
"""
From f266cceb265559e8bf3d272b1b4837bb2206c08e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Josu=C3=A9=20Tille?=
Date: Mon, 7 Jan 2019 20:23:41 +0100
Subject: [PATCH 005/180] Fix typo
---
src/yunohost/domain.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/yunohost/domain.py b/src/yunohost/domain.py
index 280f8a9c3..088f7724f 100644
--- a/src/yunohost/domain.py
+++ b/src/yunohost/domain.py
@@ -4,8 +4,7 @@
Copyright (C) 2013 YunoHost
- This progra
- m is free software; you can redistribute it and/or modify
+ This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
From 8e1034771af5ecc9acce6e9966ac077ec2ea36c7 Mon Sep 17 00:00:00 2001
From: Romuald du Song
Date: Mon, 4 Feb 2019 23:01:16 +0100
Subject: [PATCH 006/180] use setting security_ciphers_compatibility to define
security configurations
---
data/hooks/conf_regen/03-ssh | 8 +++++++-
data/hooks/conf_regen/15-nginx | 6 ++++++
data/templates/nginx/server.tpl.conf | 20 ++++++++++++--------
data/templates/ssh/sshd_config | 15 +++++++++++----
4 files changed, 36 insertions(+), 13 deletions(-)
diff --git a/data/hooks/conf_regen/03-ssh b/data/hooks/conf_regen/03-ssh
index 9de527518..330166f08 100755
--- a/data/hooks/conf_regen/03-ssh
+++ b/data/hooks/conf_regen/03-ssh
@@ -12,7 +12,7 @@ do_pre_regen() {
[[ ! -f /etc/yunohost/from_script ]] || return 0
cd /usr/share/yunohost/templates/ssh
-
+
# do not listen to IPv6 if unavailable
[[ -f /proc/net/if_inet6 ]] && ipv6_enabled=true || ipv6_enabled=false
@@ -23,8 +23,14 @@ do_pre_regen() {
ssh_keys="$ssh_keys $(ls /etc/ssh/ssh_host_dsa_key 2>/dev/null || true)"
fi
+ # Support different strategy for security configurations
+ if [[ -n "$(yunohost settings get 'security.ciphers.compatibility')" ]]; then
+ security_ciphers_compatibility="$(yunohost settings get 'security.ciphers.compatibility')"
+ fi
+
export ssh_keys
export ipv6_enabled
+ export security_ciphers_compatibility
ynh_render_template "sshd_config" "${pending_dir}/etc/ssh/sshd_config"
}
diff --git a/data/hooks/conf_regen/15-nginx b/data/hooks/conf_regen/15-nginx
index 461c10c0c..97543dcfa 100755
--- a/data/hooks/conf_regen/15-nginx
+++ b/data/hooks/conf_regen/15-nginx
@@ -36,6 +36,11 @@ do_pre_regen() {
main_domain=$(cat /etc/yunohost/current_host)
domain_list=$(sudo yunohost domain list --output-as plain --quiet)
+ # Support different strategy for security configurations
+ if [[ -n "$(yunohost settings get 'security.ciphers.compatibility')" ]]; then
+ security_ciphers_compatibility="$(yunohost settings get 'security.ciphers.compatibility')"
+ fi
+
# add domain conf files
for domain in $domain_list; do
domain_conf_dir="${nginx_conf_dir}/${domain}.d"
@@ -44,6 +49,7 @@ do_pre_regen() {
mkdir -p "$mail_autoconfig_dir"
# NGINX server configuration
+ export security_ciphers_compatibility
export domain
export domain_cert_ca=$(yunohost domain cert-status $domain --json \
| jq ".certificates.\"$domain\".CA_type" \
diff --git a/data/templates/nginx/server.tpl.conf b/data/templates/nginx/server.tpl.conf
index 0c221f188..50ee1b9b8 100644
--- a/data/templates/nginx/server.tpl.conf
+++ b/data/templates/nginx/server.tpl.conf
@@ -29,6 +29,15 @@ server {
ssl_session_timeout 5m;
ssl_session_cache shared:SSL:50m;
+ {%- if security_ciphers_compatibility == "modern" -%}
+ # Ciphers with modern compatibility
+ # https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=nginx-1.6.2&openssl=1.0.1t&hsts=yes&profile=modern
+ # Uncomment the following to use modern ciphers, but remove compatibility with some old clients (android < 5.0, Internet Explorer < 10, ...)
+ ssl_protocols TLSv1.2;
+ ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
+ ssl_prefer_server_ciphers on;
+
+ {%- else -%}
# As suggested by Mozilla : https://wiki.mozilla.org/Security/Server_Side_TLS and https://en.wikipedia.org/wiki/Curve25519
ssl_ecdh_curve secp521r1:secp384r1:prime256v1;
ssl_prefer_server_ciphers on;
@@ -38,20 +47,15 @@ server {
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
- # Ciphers with modern compatibility
- # https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=nginx-1.6.2&openssl=1.0.1t&hsts=yes&profile=modern
- # Uncomment the following to use modern ciphers, but remove compatibility with some old clients (android < 5.0, Internet Explorer < 10, ...)
- #ssl_protocols TLSv1.2;
- #ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
-
# Uncomment the following directive after DH generation
# > openssl dhparam -out /etc/ssl/private/dh2048.pem -outform PEM -2 2048
#ssl_dhparam /etc/ssl/private/dh2048.pem;
+ {%- endif -%}
# Follows the Web Security Directives from the Mozilla Dev Lab and the Mozilla Obervatory + Partners
# https://wiki.mozilla.org/Security/Guidelines/Web_Security
- # https://observatory.mozilla.org/
- more_set_headers "Strict-Transport-Security : max-age=63072000; includeSubDomains; preload";
+ # https://observatory.mozilla.org/
+ more_set_headers "Strict-Transport-Security : max-age=63072000; includeSubDomains; preload";
more_set_headers "Content-Security-Policy : upgrade-insecure-requests";
more_set_headers "Content-Security-Policy-Report-Only : default-src https: data: 'unsafe-inline' 'unsafe-eval'";
more_set_headers "X-Content-Type-Options : nosniff";
diff --git a/data/templates/ssh/sshd_config b/data/templates/ssh/sshd_config
index ed870e5dc..7194a309d 100644
--- a/data/templates/ssh/sshd_config
+++ b/data/templates/ssh/sshd_config
@@ -15,10 +15,17 @@ HostKey {{ key }}{% endfor %}
# https://infosec.mozilla.org/guidelines/openssh
# ##############################################
-# Keys, ciphers and MACS
-KexAlgorithms curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256
-Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
-MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com
+{%- if security_ciphers_compatibility == "intermediate" -%}
+ KexAlgorithms diffie-hellman-group-exchange-sha256
+ Ciphers aes256-ctr,aes192-ctr,aes128-ctr
+ MACs hmac-sha2-512,hmac-sha2-256
+{%- else -%}
+ # By default use "modern" Mozilla configuration
+ # Keys, ciphers and MACS
+ KexAlgorithms curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256
+ Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
+ MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com
+{%- endif -%}
# Use kernel sandbox mechanisms where possible in unprivileged processes
UsePrivilegeSeparation sandbox
From e0aaf6f8a160f7b2028635e9e1b7235eca6bc4c7 Mon Sep 17 00:00:00 2001
From: Romuald du Song
Date: Sat, 9 Feb 2019 11:56:33 +0100
Subject: [PATCH 007/180] add trace for process check
---
data/hooks/conf_regen/15-nginx | 1 +
1 file changed, 1 insertion(+)
diff --git a/data/hooks/conf_regen/15-nginx b/data/hooks/conf_regen/15-nginx
index 97543dcfa..f0ca11797 100755
--- a/data/hooks/conf_regen/15-nginx
+++ b/data/hooks/conf_regen/15-nginx
@@ -49,6 +49,7 @@ do_pre_regen() {
mkdir -p "$mail_autoconfig_dir"
# NGINX server configuration
+ echo "RDS Using security_ciphers_compatibility=$security_ciphers_compatibility"
export security_ciphers_compatibility
export domain
export domain_cert_ca=$(yunohost domain cert-status $domain --json \
From f084de5a69e7edd353ab90b7bf999775bbd234e0 Mon Sep 17 00:00:00 2001
From: Romuald du Song
Date: Sat, 9 Feb 2019 23:30:40 +0100
Subject: [PATCH 008/180] declare setting security.ciphers.compatibility
---
locales/en.json | 1 +
locales/fr.json | 1 +
src/yunohost/settings.py | 1 +
3 files changed, 3 insertions(+)
diff --git a/locales/en.json b/locales/en.json
index 8528c2576..72a34fb57 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -202,6 +202,7 @@
"global_settings_setting_example_enum": "Example enum option",
"global_settings_setting_example_int": "Example int option",
"global_settings_setting_example_string": "Example string option",
+ "global_settings_setting_security_ciphers_compatibility": "Admin ciphers compatibility strategy",
"global_settings_setting_security_password_admin_strength": "Admin password strength",
"global_settings_setting_security_password_user_strength": "User password strength",
"global_settings_unknown_setting_from_settings_file": "Unknown key in settings: '{setting_key:s}', discarding it and save it in /etc/yunohost/unkown_settings.json",
diff --git a/locales/fr.json b/locales/fr.json
index 7119039db..0c73cebcd 100644
--- a/locales/fr.json
+++ b/locales/fr.json
@@ -308,6 +308,7 @@
"global_settings_setting_example_int": "Exemple d’option de type entier",
"global_settings_setting_example_string": "Exemple d’option de type chaîne",
"global_settings_setting_example_enum": "Exemple d’option de type énumération",
+ "global_settings_setting_security_ciphers_compatibility": "Stratégie de compatibilité des ciphers",
"global_settings_unknown_type": "Situation inattendue, la configuration {setting:s} semble avoir le type {unknown_type:s} mais ce n’est pas un type pris en charge par le système.",
"global_settings_unknown_setting_from_settings_file": "Clef inconnue dans les configurations : {setting_key:s}, rejet de cette clef et sauvegarde de celle-ci dans /etc/yunohost/unkown_settings.json",
"service_conf_new_managed_file": "Le fichier de configuration « {conf} » est désormais géré par le service {service}.",
diff --git a/src/yunohost/settings.py b/src/yunohost/settings.py
index bbfb3ca56..7826b620f 100644
--- a/src/yunohost/settings.py
+++ b/src/yunohost/settings.py
@@ -39,6 +39,7 @@ DEFAULTS = OrderedDict([
("security.password.admin.strength", {"type": "int", "default": 1}),
("security.password.user.strength", {"type": "int", "default": 1}),
("service.ssh.allow_deprecated_dsa_hostkey", {"type": "bool", "default": False}),
+ ("security.ciphers.compatibility", {"type": "string", "default": "intermediate"}),
])
From d15092a7401001ffbe8fcceec168bab0657ea439 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Josu=C3=A9=20Tille?=
Date: Mon, 11 Feb 2019 20:22:42 +0100
Subject: [PATCH 009/180] Fix result from hook_callback
---
src/yunohost/domain.py | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/src/yunohost/domain.py b/src/yunohost/domain.py
index 088f7724f..66f17c491 100644
--- a/src/yunohost/domain.py
+++ b/src/yunohost/domain.py
@@ -206,16 +206,16 @@ def domain_dns_conf(domain, ttl=None):
result += "; Mail"
for record in dns_conf["mail"]:
result += "\n{name} {ttl} IN {type} {value}".format(**record)
- result += "\n\n
+ result += "\n\n"
result += "; Extra"
for record in dns_conf["extra"]:
result += "\n{name} {ttl} IN {type} {value}".format(**record)
for name, record_list in dns_conf.items():
- if name not in ("basic", "xmpp", "mail"):
+ if name not in ("basic", "xmpp", "mail", "extra") and record_list:
result += "\n\n"
- result += "; " + name + "\n"
+ result += "; " + name
for record in record_list:
result += "\n{name} {ttl} IN {type} {value}".format(**record)
@@ -418,8 +418,10 @@ def _build_dns_conf(domain, ttl=3600):
# Custom record
hookres = hook_callback('custom_dns_rules', args=[domain])
- for n,v in hookres.items() :
- res[n] = v['stdreturn']
+ for n, val in hookres.items() :
+ res[n] = []
+ for v in [v['stdreturn'] for p, v in val.items() if v and v['stdreturn']]:
+ res[n].extend(v)
return res
From e776c777e602f76f614659353d9e0f8d84acb387 Mon Sep 17 00:00:00 2001
From: Romuald du Song
Date: Thu, 14 Feb 2019 21:17:13 +0100
Subject: [PATCH 010/180] remove strip whitespace syntax
---
data/templates/nginx/server.tpl.conf | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/data/templates/nginx/server.tpl.conf b/data/templates/nginx/server.tpl.conf
index 50ee1b9b8..2d161d79c 100644
--- a/data/templates/nginx/server.tpl.conf
+++ b/data/templates/nginx/server.tpl.conf
@@ -29,7 +29,7 @@ server {
ssl_session_timeout 5m;
ssl_session_cache shared:SSL:50m;
- {%- if security_ciphers_compatibility == "modern" -%}
+ {% if security_ciphers_compatibility == "modern" %}
# Ciphers with modern compatibility
# https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=nginx-1.6.2&openssl=1.0.1t&hsts=yes&profile=modern
# Uncomment the following to use modern ciphers, but remove compatibility with some old clients (android < 5.0, Internet Explorer < 10, ...)
@@ -37,7 +37,7 @@ server {
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
ssl_prefer_server_ciphers on;
- {%- else -%}
+ {% else %}
# As suggested by Mozilla : https://wiki.mozilla.org/Security/Server_Side_TLS and https://en.wikipedia.org/wiki/Curve25519
ssl_ecdh_curve secp521r1:secp384r1:prime256v1;
ssl_prefer_server_ciphers on;
@@ -50,7 +50,7 @@ server {
# Uncomment the following directive after DH generation
# > openssl dhparam -out /etc/ssl/private/dh2048.pem -outform PEM -2 2048
#ssl_dhparam /etc/ssl/private/dh2048.pem;
- {%- endif -%}
+ {% endif %}
# Follows the Web Security Directives from the Mozilla Dev Lab and the Mozilla Obervatory + Partners
# https://wiki.mozilla.org/Security/Guidelines/Web_Security
From 3251189ab8529e34c455f38b2b88d60fe47b8208 Mon Sep 17 00:00:00 2001
From: Romuald du Song
Date: Thu, 14 Feb 2019 21:26:25 +0100
Subject: [PATCH 011/180] what a cumbersome whitespace control
---
data/templates/nginx/server.tpl.conf | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/data/templates/nginx/server.tpl.conf b/data/templates/nginx/server.tpl.conf
index 2d161d79c..5f22c8df5 100644
--- a/data/templates/nginx/server.tpl.conf
+++ b/data/templates/nginx/server.tpl.conf
@@ -29,14 +29,13 @@ server {
ssl_session_timeout 5m;
ssl_session_cache shared:SSL:50m;
- {% if security_ciphers_compatibility == "modern" %}
+ {% if security_ciphers_compatibility == "modern" -%}
# Ciphers with modern compatibility
# https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=nginx-1.6.2&openssl=1.0.1t&hsts=yes&profile=modern
# Uncomment the following to use modern ciphers, but remove compatibility with some old clients (android < 5.0, Internet Explorer < 10, ...)
ssl_protocols TLSv1.2;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
ssl_prefer_server_ciphers on;
-
{% else %}
# As suggested by Mozilla : https://wiki.mozilla.org/Security/Server_Side_TLS and https://en.wikipedia.org/wiki/Curve25519
ssl_ecdh_curve secp521r1:secp384r1:prime256v1;
@@ -64,7 +63,7 @@ server {
more_set_headers "X-Permitted-Cross-Domain-Policies : none";
more_set_headers "X-Frame-Options : SAMEORIGIN";
- {% if domain_cert_ca == "Let's Encrypt" %}
+ {% if domain_cert_ca == "Let's Encrypt" -%}
# OCSP settings
ssl_stapling on;
ssl_stapling_verify on;
From a267e1bc74167f07bb521162f4e92b225336e89d Mon Sep 17 00:00:00 2001
From: Romuald du Song
Date: Thu, 14 Feb 2019 21:28:56 +0100
Subject: [PATCH 012/180] what a cumbersome whitespace control
---
data/templates/nginx/server.tpl.conf | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/data/templates/nginx/server.tpl.conf b/data/templates/nginx/server.tpl.conf
index 5f22c8df5..9d662b904 100644
--- a/data/templates/nginx/server.tpl.conf
+++ b/data/templates/nginx/server.tpl.conf
@@ -70,7 +70,7 @@ server {
ssl_trusted_certificate /etc/yunohost/certs/{{ domain }}/crt.pem;
resolver 127.0.0.1 127.0.1.1 valid=300s;
resolver_timeout 5s;
- {% endif %}
+ {%- endif %}
access_by_lua_file /usr/share/ssowat/access.lua;
From 7b01ccfefbc534c34b31dcb3367ebf629b01353c Mon Sep 17 00:00:00 2001
From: Romuald du Song
Date: Thu, 14 Feb 2019 21:33:36 +0100
Subject: [PATCH 013/180] remove whitespace control attempt
---
data/templates/nginx/server.tpl.conf | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/data/templates/nginx/server.tpl.conf b/data/templates/nginx/server.tpl.conf
index 9d662b904..e19bab970 100644
--- a/data/templates/nginx/server.tpl.conf
+++ b/data/templates/nginx/server.tpl.conf
@@ -29,7 +29,7 @@ server {
ssl_session_timeout 5m;
ssl_session_cache shared:SSL:50m;
- {% if security_ciphers_compatibility == "modern" -%}
+ {% if security_ciphers_compatibility == "modern" %}
# Ciphers with modern compatibility
# https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=nginx-1.6.2&openssl=1.0.1t&hsts=yes&profile=modern
# Uncomment the following to use modern ciphers, but remove compatibility with some old clients (android < 5.0, Internet Explorer < 10, ...)
@@ -63,14 +63,14 @@ server {
more_set_headers "X-Permitted-Cross-Domain-Policies : none";
more_set_headers "X-Frame-Options : SAMEORIGIN";
- {% if domain_cert_ca == "Let's Encrypt" -%}
+ {% if domain_cert_ca == "Let's Encrypt" %}
# OCSP settings
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/yunohost/certs/{{ domain }}/crt.pem;
resolver 127.0.0.1 127.0.1.1 valid=300s;
resolver_timeout 5s;
- {%- endif %}
+ {% endif %}
access_by_lua_file /usr/share/ssowat/access.lua;
From e9274ee44376cbdcb617f7aa9622d93f6672145a Mon Sep 17 00:00:00 2001
From: Romuald du Song
Date: Thu, 14 Feb 2019 22:27:49 +0100
Subject: [PATCH 014/180] Handle yunohost admin nginx config
---
.../templates/nginx/plain/yunohost_admin.conf | 21 +++++++++++--------
1 file changed, 12 insertions(+), 9 deletions(-)
diff --git a/data/templates/nginx/plain/yunohost_admin.conf b/data/templates/nginx/plain/yunohost_admin.conf
index b6fabf8e3..7992b2de9 100644
--- a/data/templates/nginx/plain/yunohost_admin.conf
+++ b/data/templates/nginx/plain/yunohost_admin.conf
@@ -20,6 +20,14 @@ server {
ssl_session_timeout 5m;
ssl_session_cache shared:SSL:50m;
+ {% if security_ciphers_compatibility == "modern" %}
+ # Ciphers with modern compatibility
+ # https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=nginx-1.6.2&openssl=1.0.1t&hsts=yes&profile=modern
+ # Uncomment the following to use modern ciphers, but remove compatibility with some old clients (android < 5.0, Internet Explorer < 10, ...)
+ ssl_protocols TLSv1.2;
+ ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
+ ssl_prefer_server_ciphers on;
+ {% else %}
# As suggested by Mozilla : https://wiki.mozilla.org/Security/Server_Side_TLS and https://en.wikipedia.org/wiki/Curve25519
ssl_ecdh_curve secp521r1:secp384r1:prime256v1;
ssl_prefer_server_ciphers on;
@@ -29,20 +37,15 @@ server {
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
- # Ciphers with modern compatibility
- # https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=nginx-1.6.2&openssl=1.0.1t&hsts=yes&profile=modern
- # Uncomment the following to use modern ciphers, but remove compatibility with some old clients (android < 5.0, Internet Explorer < 10, ...)
- #ssl_protocols TLSv1.2;
- #ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
-
# Uncomment the following directive after DH generation
# > openssl dhparam -out /etc/ssl/private/dh2048.pem -outform PEM -2 2048
#ssl_dhparam /etc/ssl/private/dh2048.pem;
-
+ {% endif %}
+
# Follows the Web Security Directives from the Mozilla Dev Lab and the Mozilla Obervatory + Partners
# https://wiki.mozilla.org/Security/Guidelines/Web_Security
- # https://observatory.mozilla.org/
- more_set_headers "Strict-Transport-Security : max-age=63072000; includeSubDomains; preload";
+ # https://observatory.mozilla.org/
+ more_set_headers "Strict-Transport-Security : max-age=63072000; includeSubDomains; preload";
more_set_headers "Referrer-Policy : 'same-origin'";
more_set_headers "Content-Security-Policy : upgrade-insecure-requests; object-src 'none'; script-src https: 'unsafe-eval'";
more_set_headers "X-Content-Type-Options : nosniff";
From 12d0e0e1de00463fb13c468ef1403e6761a3cda7 Mon Sep 17 00:00:00 2001
From: Romuald du Song
Date: Thu, 14 Feb 2019 22:34:35 +0100
Subject: [PATCH 015/180] add instruction to rebuild yunohost-admin conf
---
data/hooks/conf_regen/15-nginx | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/data/hooks/conf_regen/15-nginx b/data/hooks/conf_regen/15-nginx
index f0ca11797..4c5bac331 100755
--- a/data/hooks/conf_regen/15-nginx
+++ b/data/hooks/conf_regen/15-nginx
@@ -41,6 +41,8 @@ do_pre_regen() {
security_ciphers_compatibility="$(yunohost settings get 'security.ciphers.compatibility')"
fi
+ export security_ciphers_compatibility
+
# add domain conf files
for domain in $domain_list; do
domain_conf_dir="${nginx_conf_dir}/${domain}.d"
@@ -49,8 +51,6 @@ do_pre_regen() {
mkdir -p "$mail_autoconfig_dir"
# NGINX server configuration
- echo "RDS Using security_ciphers_compatibility=$security_ciphers_compatibility"
- export security_ciphers_compatibility
export domain
export domain_cert_ca=$(yunohost domain cert-status $domain --json \
| jq ".certificates.\"$domain\".CA_type" \
@@ -64,6 +64,7 @@ do_pre_regen() {
|| cp yunohost_local.conf "${domain_conf_dir}/yunohost_local.conf"
done
+ ynh_render_template "plain/yunohost_admin.conf" "${nginx_conf_dir}/yunohost-admin.conf"
# remove old domain conf files
conf_files=$(ls -1 /etc/nginx/conf.d \
From ec52ded7776cc481c7563edce790a1c20d5ee09e Mon Sep 17 00:00:00 2001
From: Romuald du Song
Date: Thu, 14 Feb 2019 22:38:28 +0100
Subject: [PATCH 016/180] don't conflict translation tool
---
locales/fr.json | 1 -
1 file changed, 1 deletion(-)
diff --git a/locales/fr.json b/locales/fr.json
index 0c73cebcd..7119039db 100644
--- a/locales/fr.json
+++ b/locales/fr.json
@@ -308,7 +308,6 @@
"global_settings_setting_example_int": "Exemple d’option de type entier",
"global_settings_setting_example_string": "Exemple d’option de type chaîne",
"global_settings_setting_example_enum": "Exemple d’option de type énumération",
- "global_settings_setting_security_ciphers_compatibility": "Stratégie de compatibilité des ciphers",
"global_settings_unknown_type": "Situation inattendue, la configuration {setting:s} semble avoir le type {unknown_type:s} mais ce n’est pas un type pris en charge par le système.",
"global_settings_unknown_setting_from_settings_file": "Clef inconnue dans les configurations : {setting_key:s}, rejet de cette clef et sauvegarde de celle-ci dans /etc/yunohost/unkown_settings.json",
"service_conf_new_managed_file": "Le fichier de configuration « {conf} » est désormais géré par le service {service}.",
From e8eff8729792d9ef27cf8b829687206c941cd987 Mon Sep 17 00:00:00 2001
From: Romuald du Song
Date: Thu, 14 Feb 2019 22:49:13 +0100
Subject: [PATCH 017/180] switch to enum type to store cipher policy setting
---
src/yunohost/settings.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/yunohost/settings.py b/src/yunohost/settings.py
index 7826b620f..9b12647a6 100644
--- a/src/yunohost/settings.py
+++ b/src/yunohost/settings.py
@@ -39,7 +39,7 @@ DEFAULTS = OrderedDict([
("security.password.admin.strength", {"type": "int", "default": 1}),
("security.password.user.strength", {"type": "int", "default": 1}),
("service.ssh.allow_deprecated_dsa_hostkey", {"type": "bool", "default": False}),
- ("security.ciphers.compatibility", {"type": "string", "default": "intermediate"}),
+ ("security.ciphers.compatibility", {"type": "enum", "choices": "intermediate", "modern"}),
])
From a899102efc8a13fcf4c16bf31bb7769f4d820b23 Mon Sep 17 00:00:00 2001
From: Romuald du Song
Date: Thu, 14 Feb 2019 22:57:24 +0100
Subject: [PATCH 018/180] don't share setting for nginx and ssh
---
data/hooks/conf_regen/03-ssh | 6 +++---
data/templates/ssh/sshd_config | 6 +++---
locales/en.json | 3 ++-
src/yunohost/settings.py | 1 +
4 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/data/hooks/conf_regen/03-ssh b/data/hooks/conf_regen/03-ssh
index 330166f08..3a79de456 100755
--- a/data/hooks/conf_regen/03-ssh
+++ b/data/hooks/conf_regen/03-ssh
@@ -24,13 +24,13 @@ do_pre_regen() {
fi
# Support different strategy for security configurations
- if [[ -n "$(yunohost settings get 'security.ciphers.compatibility')" ]]; then
- security_ciphers_compatibility="$(yunohost settings get 'security.ciphers.compatibility')"
+ if [[ -n "$(yunohost settings get 'service.ssh.ciphers.compatibility')" ]]; then
+ ssh_ciphers_compatibility="$(yunohost settings get 'service.ssh.ciphers.compatibility')"
fi
export ssh_keys
export ipv6_enabled
- export security_ciphers_compatibility
+ export ssh_ciphers_compatibility
ynh_render_template "sshd_config" "${pending_dir}/etc/ssh/sshd_config"
}
diff --git a/data/templates/ssh/sshd_config b/data/templates/ssh/sshd_config
index 7194a309d..f27ca3ebe 100644
--- a/data/templates/ssh/sshd_config
+++ b/data/templates/ssh/sshd_config
@@ -15,17 +15,17 @@ HostKey {{ key }}{% endfor %}
# https://infosec.mozilla.org/guidelines/openssh
# ##############################################
-{%- if security_ciphers_compatibility == "intermediate" -%}
+{% if ssh_ciphers_compatibility == "intermediate" %}
KexAlgorithms diffie-hellman-group-exchange-sha256
Ciphers aes256-ctr,aes192-ctr,aes128-ctr
MACs hmac-sha2-512,hmac-sha2-256
-{%- else -%}
+{% else %}
# By default use "modern" Mozilla configuration
# Keys, ciphers and MACS
KexAlgorithms curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com
-{%- endif -%}
+{% endif %}
# Use kernel sandbox mechanisms where possible in unprivileged processes
UsePrivilegeSeparation sandbox
diff --git a/locales/en.json b/locales/en.json
index 72a34fb57..3f01cb08e 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -202,11 +202,12 @@
"global_settings_setting_example_enum": "Example enum option",
"global_settings_setting_example_int": "Example int option",
"global_settings_setting_example_string": "Example string option",
- "global_settings_setting_security_ciphers_compatibility": "Admin ciphers compatibility strategy",
+ "global_settings_setting_security_ciphers_compatibility": "Admin ciphers compatibility strategy for the web",
"global_settings_setting_security_password_admin_strength": "Admin password strength",
"global_settings_setting_security_password_user_strength": "User password strength",
"global_settings_unknown_setting_from_settings_file": "Unknown key in settings: '{setting_key:s}', discarding it and save it in /etc/yunohost/unkown_settings.json",
"global_settings_setting_service_ssh_allow_deprecated_dsa_hostkey": "Allow the use of (deprecated) DSA hostkey for the SSH daemon configuration",
+ "global_settings_setting_service_ssh_ciphers_compatibility": "Admin ciphers compatibility strategy for SSH",
"global_settings_unknown_type": "Unexpected situation, the setting {setting:s} appears to have the type {unknown_type:s} but it's not a type supported by the system.",
"good_practices_about_admin_password": "You are now about to define a new administration password. The password should be at least 8 characters - though it is good practice to use longer password (i.e. a passphrase) and/or to use various kind of characters (uppercase, lowercase, digits and special characters).",
"good_practices_about_user_password": "You are now about to define a new user password. The password should be at least 8 characters - though it is good practice to use longer password (i.e. a passphrase) and/or to use various kind of characters (uppercase, lowercase, digits and special characters).",
diff --git a/src/yunohost/settings.py b/src/yunohost/settings.py
index 9b12647a6..c3d4591b0 100644
--- a/src/yunohost/settings.py
+++ b/src/yunohost/settings.py
@@ -39,6 +39,7 @@ DEFAULTS = OrderedDict([
("security.password.admin.strength", {"type": "int", "default": 1}),
("security.password.user.strength", {"type": "int", "default": 1}),
("service.ssh.allow_deprecated_dsa_hostkey", {"type": "bool", "default": False}),
+ ("service.ssh.ciphers.compatibility", {"type": "enum", "choices": "intermediate", "modern"}),
("security.ciphers.compatibility", {"type": "enum", "choices": "intermediate", "modern"}),
])
From 375b7d53b1fca626abdba882799692aa247ab1e8 Mon Sep 17 00:00:00 2001
From: Romuald du Song
Date: Thu, 14 Feb 2019 23:00:52 +0100
Subject: [PATCH 019/180] fix enum syntax
---
src/yunohost/settings.py | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/yunohost/settings.py b/src/yunohost/settings.py
index c3d4591b0..1d60c3a6a 100644
--- a/src/yunohost/settings.py
+++ b/src/yunohost/settings.py
@@ -39,8 +39,10 @@ DEFAULTS = OrderedDict([
("security.password.admin.strength", {"type": "int", "default": 1}),
("security.password.user.strength", {"type": "int", "default": 1}),
("service.ssh.allow_deprecated_dsa_hostkey", {"type": "bool", "default": False}),
- ("service.ssh.ciphers.compatibility", {"type": "enum", "choices": "intermediate", "modern"}),
- ("security.ciphers.compatibility", {"type": "enum", "choices": "intermediate", "modern"}),
+ ("service.ssh.ciphers.compatibility", {"type": "enum", "default": "modern",
+ "choices": ["intermediate", "modern"]}),
+ ("security.ciphers.compatibility", {"type": "enum", "default": "intermediate",
+ "choices": ["intermediate", "modern"]}),
])
From aaf6dba8d7c28ca43dedc88b0eec907b22ed2629 Mon Sep 17 00:00:00 2001
From: Romuald du Song
Date: Thu, 14 Feb 2019 23:03:27 +0100
Subject: [PATCH 020/180] fix yunhost admin config filename
---
data/hooks/conf_regen/15-nginx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/data/hooks/conf_regen/15-nginx b/data/hooks/conf_regen/15-nginx
index 4c5bac331..c33f16cba 100755
--- a/data/hooks/conf_regen/15-nginx
+++ b/data/hooks/conf_regen/15-nginx
@@ -64,7 +64,7 @@ do_pre_regen() {
|| cp yunohost_local.conf "${domain_conf_dir}/yunohost_local.conf"
done
- ynh_render_template "plain/yunohost_admin.conf" "${nginx_conf_dir}/yunohost-admin.conf"
+ ynh_render_template "plain/yunohost_admin.conf" "${nginx_conf_dir}/yunohost_admin.conf"
# remove old domain conf files
conf_files=$(ls -1 /etc/nginx/conf.d \
From 5d48640f3c993d5a3d7c80a411531d4efc07892b Mon Sep 17 00:00:00 2001
From: Romuald du Song
Date: Thu, 14 Feb 2019 23:12:59 +0100
Subject: [PATCH 021/180] Adapt comment to new context
---
data/templates/nginx/server.tpl.conf | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/data/templates/nginx/server.tpl.conf b/data/templates/nginx/server.tpl.conf
index e19bab970..84c884055 100644
--- a/data/templates/nginx/server.tpl.conf
+++ b/data/templates/nginx/server.tpl.conf
@@ -32,7 +32,7 @@ server {
{% if security_ciphers_compatibility == "modern" %}
# Ciphers with modern compatibility
# https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=nginx-1.6.2&openssl=1.0.1t&hsts=yes&profile=modern
- # Uncomment the following to use modern ciphers, but remove compatibility with some old clients (android < 5.0, Internet Explorer < 10, ...)
+ # The following configuration use modern ciphers, but remove compatibility with some old clients (android < 5.0, Internet Explorer < 10, ...)
ssl_protocols TLSv1.2;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
ssl_prefer_server_ciphers on;
From 42b41aa934c8ca88c21795d4976d690c463cf9a1 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Thu, 7 Feb 2019 17:00:46 +0100
Subject: [PATCH 022/180] Add new regen-conf API in tools category
---
data/actionsmap/yunohost.yml | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/data/actionsmap/yunohost.yml b/data/actionsmap/yunohost.yml
index cbe959b55..fabdcb923 100644
--- a/data/actionsmap/yunohost.yml
+++ b/data/actionsmap/yunohost.yml
@@ -1623,6 +1623,32 @@ tools:
full: --force
action: store_true
+ ### tools_regen_conf()
+ regen-conf:
+ action_help: Regenerate the configuration file(s)
+ api: PUT /tools/regenconf
+ arguments:
+ names:
+ help: Categories to regenerate configuration of (all by default)
+ nargs: "*"
+ metavar: NAME
+ -d:
+ full: --with-diff
+ help: Show differences in case of configuration changes
+ action: store_true
+ -f:
+ full: --force
+ help: Override all manual modifications in configuration files
+ action: store_true
+ -n:
+ full: --dry-run
+ help: Show what would have been regenerated
+ action: store_true
+ -p:
+ full: --list-pending
+ help: List pending configuration files and exit
+ action: store_true
+
subcategories:
migrations:
From 739bf8e559af5e52cc0c55bf614d649b8737c7ee Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Thu, 7 Feb 2019 17:23:44 +0100
Subject: [PATCH 023/180] Brutally move regenconf stuff to a new regenconf.py
file
---
src/yunohost/regenconf.py | 546 ++++++++++++++++++++++++++++++++++++++
src/yunohost/service.py | 475 ---------------------------------
2 files changed, 546 insertions(+), 475 deletions(-)
create mode 100644 src/yunohost/regenconf.py
diff --git a/src/yunohost/regenconf.py b/src/yunohost/regenconf.py
new file mode 100644
index 000000000..0330db508
--- /dev/null
+++ b/src/yunohost/regenconf.py
@@ -0,0 +1,546 @@
+# -*- coding: utf-8 -*-
+
+""" License
+
+ Copyright (C) 2019 YunoHost
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program; if not, see http://www.gnu.org/licenses
+
+"""
+
+import os
+import yaml
+import json
+import subprocess
+import shutil
+import hashlib
+
+from difflib import unified_diff
+from datetime import datetime
+
+from moulinette import m18n
+from moulinette.utils import log, filesystem
+
+from yunohost.utils.error import YunohostError
+from yunohost.log import is_unit_operation
+from yunohost.hook import hook_callback, hook_list
+
+BASE_CONF_PATH = '/home/yunohost.conf'
+BACKUP_CONF_DIR = os.path.join(BASE_CONF_PATH, 'backup')
+PENDING_CONF_DIR = os.path.join(BASE_CONF_PATH, 'pending')
+
+logger = log.getActionLogger('yunohost.regenconf')
+
+
+@is_unit_operation([('names', 'service')])
+def regen_conf(operation_logger, names=[], with_diff=False, force=False, dry_run=False,
+ list_pending=False):
+ """
+ Regenerate the configuration file(s) for a service
+
+ Keyword argument:
+ names -- Services name to regenerate configuration of
+ with_diff -- Show differences in case of configuration changes
+ force -- Override all manual modifications in configuration files
+ dry_run -- Show what would have been regenerated
+ list_pending -- List pending configuration files and exit
+
+ """
+ result = {}
+
+ # Return the list of pending conf
+ if list_pending:
+ pending_conf = _get_pending_conf(names)
+
+ if not with_diff:
+ return pending_conf
+
+ for service, conf_files in pending_conf.items():
+ for system_path, pending_path in conf_files.items():
+
+ pending_conf[service][system_path] = {
+ 'pending_conf': pending_path,
+ 'diff': _get_files_diff(
+ system_path, pending_path, True),
+ }
+
+ return pending_conf
+
+ if not dry_run:
+ operation_logger.related_to = [('service', x) for x in names]
+ if not names:
+ operation_logger.name_parameter_override = 'all'
+ elif len(names) != 1:
+ operation_logger.name_parameter_override = str(len(operation_logger.related_to)) + '_services'
+ operation_logger.start()
+
+ # Clean pending conf directory
+ if os.path.isdir(PENDING_CONF_DIR):
+ if not names:
+ shutil.rmtree(PENDING_CONF_DIR, ignore_errors=True)
+ else:
+ for name in names:
+ shutil.rmtree(os.path.join(PENDING_CONF_DIR, name),
+ ignore_errors=True)
+ else:
+ filesystem.mkdir(PENDING_CONF_DIR, 0o755, True)
+
+ # Format common hooks arguments
+ common_args = [1 if force else 0, 1 if dry_run else 0]
+
+ # Execute hooks for pre-regen
+ pre_args = ['pre', ] + common_args
+
+ def _pre_call(name, priority, path, args):
+ # create the pending conf directory for the service
+ service_pending_path = os.path.join(PENDING_CONF_DIR, name)
+ filesystem.mkdir(service_pending_path, 0o755, True, uid='root')
+
+ # return the arguments to pass to the script
+ return pre_args + [service_pending_path, ]
+
+ # Don't regen SSH if not specifically specified
+ if not names:
+ names = hook_list('conf_regen', list_by='name',
+ show_info=False)['hooks']
+ names.remove('ssh')
+
+ pre_result = hook_callback('conf_regen', names, pre_callback=_pre_call)
+
+ # Update the services name
+ names = pre_result['succeed'].keys()
+
+ if not names:
+ raise YunohostError('service_regenconf_failed',
+ services=', '.join(pre_result['failed']))
+
+ # Set the processing method
+ _regen = _process_regen_conf if not dry_run else lambda *a, **k: True
+
+ operation_logger.related_to = []
+
+ # Iterate over services and process pending conf
+ for service, conf_files in _get_pending_conf(names).items():
+ if not dry_run:
+ operation_logger.related_to.append(('service', service))
+
+ logger.debug(m18n.n(
+ 'service_regenconf_pending_applying' if not dry_run else
+ 'service_regenconf_dry_pending_applying',
+ service=service))
+
+ conf_hashes = _get_conf_hashes(service)
+ succeed_regen = {}
+ failed_regen = {}
+
+ for system_path, pending_path in conf_files.items():
+ logger.debug("processing pending conf '%s' to system conf '%s'",
+ pending_path, system_path)
+ conf_status = None
+ regenerated = False
+
+ # Get the diff between files
+ conf_diff = _get_files_diff(
+ system_path, pending_path, True) if with_diff else None
+
+ # Check if the conf must be removed
+ to_remove = True if os.path.getsize(pending_path) == 0 else False
+
+ # Retrieve and calculate hashes
+ system_hash = _calculate_hash(system_path)
+ saved_hash = conf_hashes.get(system_path, None)
+ new_hash = None if to_remove else _calculate_hash(pending_path)
+
+ # -> system conf does not exists
+ if not system_hash:
+ if to_remove:
+ logger.debug("> system conf is already removed")
+ os.remove(pending_path)
+ continue
+ if not saved_hash or force:
+ if force:
+ logger.debug("> system conf has been manually removed")
+ conf_status = 'force-created'
+ else:
+ logger.debug("> system conf does not exist yet")
+ conf_status = 'created'
+ regenerated = _regen(
+ system_path, pending_path, save=False)
+ else:
+ logger.info(m18n.n(
+ 'service_conf_file_manually_removed',
+ conf=system_path))
+ conf_status = 'removed'
+
+ # -> system conf is not managed yet
+ elif not saved_hash:
+ logger.debug("> system conf is not managed yet")
+ if system_hash == new_hash:
+ logger.debug("> no changes to system conf has been made")
+ conf_status = 'managed'
+ regenerated = True
+ elif not to_remove:
+ # If the conf exist but is not managed yet, and is not to be removed,
+ # we assume that it is safe to regen it, since the file is backuped
+ # anyway (by default in _regen), as long as we warn the user
+ # appropriately.
+ logger.info(m18n.n('service_conf_now_managed_by_yunohost',
+ conf=system_path))
+ regenerated = _regen(system_path, pending_path)
+ conf_status = 'new'
+ elif force:
+ regenerated = _regen(system_path)
+ conf_status = 'force-removed'
+ else:
+ logger.info(m18n.n('service_conf_file_kept_back',
+ conf=system_path, service=service))
+ conf_status = 'unmanaged'
+
+ # -> system conf has not been manually modified
+ elif system_hash == saved_hash:
+ if to_remove:
+ regenerated = _regen(system_path)
+ conf_status = 'removed'
+ elif system_hash != new_hash:
+ regenerated = _regen(system_path, pending_path)
+ conf_status = 'updated'
+ else:
+ logger.debug("> system conf is already up-to-date")
+ os.remove(pending_path)
+ continue
+
+ else:
+ logger.debug("> system conf has been manually modified")
+ if system_hash == new_hash:
+ logger.debug("> new conf is as current system conf")
+ conf_status = 'managed'
+ regenerated = True
+ elif force:
+ regenerated = _regen(system_path, pending_path)
+ conf_status = 'force-updated'
+ else:
+ logger.warning(m18n.n(
+ 'service_conf_file_manually_modified',
+ conf=system_path))
+ conf_status = 'modified'
+
+ # Store the result
+ conf_result = {'status': conf_status}
+ if conf_diff is not None:
+ conf_result['diff'] = conf_diff
+ if regenerated:
+ succeed_regen[system_path] = conf_result
+ conf_hashes[system_path] = new_hash
+ if os.path.isfile(pending_path):
+ os.remove(pending_path)
+ else:
+ failed_regen[system_path] = conf_result
+
+ # Check for service conf changes
+ if not succeed_regen and not failed_regen:
+ logger.debug(m18n.n('service_conf_up_to_date', service=service))
+ continue
+ elif not failed_regen:
+ logger.success(m18n.n(
+ 'service_conf_updated' if not dry_run else
+ 'service_conf_would_be_updated',
+ service=service))
+
+ if succeed_regen and not dry_run:
+ _update_conf_hashes(service, conf_hashes)
+
+ # Append the service results
+ result[service] = {
+ 'applied': succeed_regen,
+ 'pending': failed_regen
+ }
+
+ # Return in case of dry run
+ if dry_run:
+ return result
+
+ # Execute hooks for post-regen
+ post_args = ['post', ] + common_args
+
+ def _pre_call(name, priority, path, args):
+ # append coma-separated applied changes for the service
+ if name in result and result[name]['applied']:
+ regen_conf_files = ','.join(result[name]['applied'].keys())
+ else:
+ regen_conf_files = ''
+ return post_args + [regen_conf_files, ]
+
+ hook_callback('conf_regen', names, pre_callback=_pre_call)
+
+ operation_logger.success()
+
+ return result
+
+
+def _get_services():
+ """
+ Get a dict of managed services with their parameters
+
+ """
+ try:
+ with open('/etc/yunohost/services.yml', 'r') as f:
+ services = yaml.load(f)
+ except:
+ return {}
+ else:
+ # some services are marked as None to remove them from YunoHost
+ # filter this
+ for key, value in services.items():
+ if value is None:
+ del services[key]
+
+ return services
+
+
+def _save_services(services):
+ """
+ Save managed services to files
+
+ Keyword argument:
+ services -- A dict of managed services with their parameters
+
+ """
+ try:
+ with open('/etc/yunohost/services.yml', 'w') as f:
+ yaml.safe_dump(services, f, default_flow_style=False)
+ except Exception as e:
+ logger.warning('Error while saving services, exception: %s', e, exc_info=1)
+ raise
+
+
+def _get_files_diff(orig_file, new_file, as_string=False, skip_header=True):
+ """Compare two files and return the differences
+
+ Read and compare two files. The differences are returned either as a delta
+ in unified diff format or a formatted string if as_string is True. The
+ header can also be removed if skip_header is True.
+
+ """
+
+ if os.path.exists(orig_file):
+ with open(orig_file, 'r') as orig_file:
+ orig_file = orig_file.readlines()
+ else:
+ orig_file = []
+
+ if os.path.exists(new_file):
+ with open(new_file, 'r') as new_file:
+ new_file = new_file.readlines()
+ else:
+ new_file = []
+
+ # Compare files and format output
+ diff = unified_diff(orig_file, new_file)
+
+ if skip_header:
+ try:
+ next(diff)
+ next(diff)
+ except:
+ pass
+
+ if as_string:
+ return ''.join(diff).rstrip()
+
+ return diff
+
+
+def _calculate_hash(path):
+ """Calculate the MD5 hash of a file"""
+
+ if not os.path.exists(path):
+ return None
+
+ hasher = hashlib.md5()
+
+ try:
+ with open(path, 'rb') as f:
+ hasher.update(f.read())
+ return hasher.hexdigest()
+
+ except IOError as e:
+ logger.warning("Error while calculating file '%s' hash: %s", path, e, exc_info=1)
+ return None
+
+
+def _get_pending_conf(services=[]):
+ """Get pending configuration for service(s)
+
+ Iterate over the pending configuration directory for given service(s) - or
+ all if empty - and look for files inside. Each file is considered as a
+ pending configuration file and therefore must be in the same directory
+ tree than the system file that it replaces.
+ The result is returned as a dict of services with pending configuration as
+ key and a dict of `system_conf_path` => `pending_conf_path` as value.
+
+ """
+ result = {}
+
+ if not os.path.isdir(PENDING_CONF_DIR):
+ return result
+
+ if not services:
+ services = os.listdir(PENDING_CONF_DIR)
+
+ for name in services:
+ service_pending_path = os.path.join(PENDING_CONF_DIR, name)
+
+ if not os.path.isdir(service_pending_path):
+ continue
+
+ path_index = len(service_pending_path)
+ service_conf = {}
+
+ for root, dirs, files in os.walk(service_pending_path):
+ for filename in files:
+ pending_path = os.path.join(root, filename)
+ service_conf[pending_path[path_index:]] = pending_path
+
+ if service_conf:
+ result[name] = service_conf
+ else:
+ # remove empty directory
+ shutil.rmtree(service_pending_path, ignore_errors=True)
+
+ return result
+
+
+def _get_conf_hashes(service):
+ """Get the registered conf hashes for a service"""
+
+ services = _get_services()
+
+ if service not in services:
+ logger.debug("Service %s is not in services.yml yet.", service)
+ return {}
+
+ elif services[service] is None or 'conffiles' not in services[service]:
+ logger.debug("No configuration files for service %s.", service)
+ return {}
+
+ else:
+ return services[service]['conffiles']
+
+
+def _update_conf_hashes(service, hashes):
+ """Update the registered conf hashes for a service"""
+ logger.debug("updating conf hashes for '%s' with: %s",
+ service, hashes)
+ services = _get_services()
+ service_conf = services.get(service, {})
+
+ # Handle the case where services[service] is set to null in the yaml
+ if service_conf is None:
+ service_conf = {}
+
+ service_conf['conffiles'] = hashes
+ services[service] = service_conf
+ _save_services(services)
+
+
+def _process_regen_conf(system_conf, new_conf=None, save=True):
+ """Regenerate a given system configuration file
+
+ Replace a given system configuration file by a new one or delete it if
+ new_conf is None. A backup of the file - keeping its directory tree - will
+ be done in the backup conf directory before any operation if save is True.
+
+ """
+ if save:
+ backup_path = os.path.join(BACKUP_CONF_DIR, '{0}-{1}'.format(
+ system_conf.lstrip('/'), datetime.utcnow().strftime("%Y%m%d.%H%M%S")))
+ backup_dir = os.path.dirname(backup_path)
+
+ if not os.path.isdir(backup_dir):
+ filesystem.mkdir(backup_dir, 0o755, True)
+
+ shutil.copy2(system_conf, backup_path)
+ logger.debug(m18n.n('service_conf_file_backed_up',
+ conf=system_conf, backup=backup_path))
+
+ try:
+ if not new_conf:
+ os.remove(system_conf)
+ logger.debug(m18n.n('service_conf_file_removed',
+ conf=system_conf))
+ else:
+ system_dir = os.path.dirname(system_conf)
+
+ if not os.path.isdir(system_dir):
+ filesystem.mkdir(system_dir, 0o755, True)
+
+ shutil.copyfile(new_conf, system_conf)
+ logger.debug(m18n.n('service_conf_file_updated',
+ conf=system_conf))
+ except Exception as e:
+ logger.warning("Exception while trying to regenerate conf '%s': %s", system_conf, e, exc_info=1)
+ if not new_conf and os.path.exists(system_conf):
+ logger.warning(m18n.n('service_conf_file_remove_failed',
+ conf=system_conf),
+ exc_info=1)
+ return False
+
+ elif new_conf:
+ try:
+ # From documentation:
+ # Raise an exception if an os.stat() call on either pathname fails.
+ # (os.stats returns a series of information from a file like type, size...)
+ copy_succeed = os.path.samefile(system_conf, new_conf)
+ except:
+ copy_succeed = False
+ finally:
+ if not copy_succeed:
+ logger.warning(m18n.n('service_conf_file_copy_failed',
+ conf=system_conf, new=new_conf),
+ exc_info=1)
+ return False
+
+ return True
+
+
+def manually_modified_files():
+
+ # We do this to have --quiet, i.e. don't throw a whole bunch of logs
+ # just to fetch this...
+ # Might be able to optimize this by looking at what service_regenconf does
+ # and only do the part that checks file hashes...
+ cmd = "yunohost service regen-conf --dry-run --output-as json --quiet"
+ j = json.loads(subprocess.check_output(cmd.split()))
+
+ # j is something like :
+ # {"postfix": {"applied": {}, "pending": {"/etc/postfix/main.cf": {"status": "modified"}}}
+
+ output = []
+ for app, actions in j.items():
+ for action, files in actions.items():
+ for filename, infos in files.items():
+ if infos["status"] == "modified":
+ output.append(filename)
+
+ return output
+
+
+def manually_modified_files_compared_to_debian_default():
+
+ # from https://serverfault.com/a/90401
+ r = subprocess.check_output("dpkg-query -W -f='${Conffiles}\n' '*' \
+ | awk 'OFS=\" \"{print $2,$1}' \
+ | md5sum -c 2>/dev/null \
+ | awk -F': ' '$2 !~ /OK/{print $1}'", shell=True)
+ return r.strip().split("\n")
diff --git a/src/yunohost/service.py b/src/yunohost/service.py
index 60729053b..ab0e791d8 100644
--- a/src/yunohost/service.py
+++ b/src/yunohost/service.py
@@ -26,12 +26,8 @@
import os
import time
import yaml
-import json
import subprocess
-import shutil
-import hashlib
-from difflib import unified_diff
from datetime import datetime
from moulinette import m18n
@@ -39,11 +35,7 @@ from yunohost.utils.error import YunohostError
from moulinette.utils import log, filesystem
from yunohost.log import is_unit_operation
-from yunohost.hook import hook_callback, hook_list
-BASE_CONF_PATH = '/home/yunohost.conf'
-BACKUP_CONF_DIR = os.path.join(BASE_CONF_PATH, 'backup')
-PENDING_CONF_DIR = os.path.join(BASE_CONF_PATH, 'pending')
MOULINETTE_LOCK = "/var/run/moulinette_yunohost.lock"
logger = log.getActionLogger('yunohost.service')
@@ -418,251 +410,6 @@ def service_log(name, number=50):
return result
-@is_unit_operation([('names', 'service')])
-def service_regen_conf(operation_logger, names=[], with_diff=False, force=False, dry_run=False,
- list_pending=False):
- """
- Regenerate the configuration file(s) for a service
-
- Keyword argument:
- names -- Services name to regenerate configuration of
- with_diff -- Show differences in case of configuration changes
- force -- Override all manual modifications in configuration files
- dry_run -- Show what would have been regenerated
- list_pending -- List pending configuration files and exit
-
- """
- result = {}
-
- # Return the list of pending conf
- if list_pending:
- pending_conf = _get_pending_conf(names)
-
- if not with_diff:
- return pending_conf
-
- for service, conf_files in pending_conf.items():
- for system_path, pending_path in conf_files.items():
-
- pending_conf[service][system_path] = {
- 'pending_conf': pending_path,
- 'diff': _get_files_diff(
- system_path, pending_path, True),
- }
-
- return pending_conf
-
- if not dry_run:
- operation_logger.related_to = [('service', x) for x in names]
- if not names:
- operation_logger.name_parameter_override = 'all'
- elif len(names) != 1:
- operation_logger.name_parameter_override = str(len(operation_logger.related_to)) + '_services'
- operation_logger.start()
-
- # Clean pending conf directory
- if os.path.isdir(PENDING_CONF_DIR):
- if not names:
- shutil.rmtree(PENDING_CONF_DIR, ignore_errors=True)
- else:
- for name in names:
- shutil.rmtree(os.path.join(PENDING_CONF_DIR, name),
- ignore_errors=True)
- else:
- filesystem.mkdir(PENDING_CONF_DIR, 0o755, True)
-
- # Format common hooks arguments
- common_args = [1 if force else 0, 1 if dry_run else 0]
-
- # Execute hooks for pre-regen
- pre_args = ['pre', ] + common_args
-
- def _pre_call(name, priority, path, args):
- # create the pending conf directory for the service
- service_pending_path = os.path.join(PENDING_CONF_DIR, name)
- filesystem.mkdir(service_pending_path, 0o755, True, uid='root')
-
- # return the arguments to pass to the script
- return pre_args + [service_pending_path, ]
-
- # Don't regen SSH if not specifically specified
- if not names:
- names = hook_list('conf_regen', list_by='name',
- show_info=False)['hooks']
- names.remove('ssh')
-
- pre_result = hook_callback('conf_regen', names, pre_callback=_pre_call)
-
- # Update the services name
- names = pre_result['succeed'].keys()
-
- if not names:
- raise YunohostError('service_regenconf_failed',
- services=', '.join(pre_result['failed']))
-
- # Set the processing method
- _regen = _process_regen_conf if not dry_run else lambda *a, **k: True
-
- operation_logger.related_to = []
-
- # Iterate over services and process pending conf
- for service, conf_files in _get_pending_conf(names).items():
- if not dry_run:
- operation_logger.related_to.append(('service', service))
-
- logger.debug(m18n.n(
- 'service_regenconf_pending_applying' if not dry_run else
- 'service_regenconf_dry_pending_applying',
- service=service))
-
- conf_hashes = _get_conf_hashes(service)
- succeed_regen = {}
- failed_regen = {}
-
- for system_path, pending_path in conf_files.items():
- logger.debug("processing pending conf '%s' to system conf '%s'",
- pending_path, system_path)
- conf_status = None
- regenerated = False
-
- # Get the diff between files
- conf_diff = _get_files_diff(
- system_path, pending_path, True) if with_diff else None
-
- # Check if the conf must be removed
- to_remove = True if os.path.getsize(pending_path) == 0 else False
-
- # Retrieve and calculate hashes
- system_hash = _calculate_hash(system_path)
- saved_hash = conf_hashes.get(system_path, None)
- new_hash = None if to_remove else _calculate_hash(pending_path)
-
- # -> system conf does not exists
- if not system_hash:
- if to_remove:
- logger.debug("> system conf is already removed")
- os.remove(pending_path)
- continue
- if not saved_hash or force:
- if force:
- logger.debug("> system conf has been manually removed")
- conf_status = 'force-created'
- else:
- logger.debug("> system conf does not exist yet")
- conf_status = 'created'
- regenerated = _regen(
- system_path, pending_path, save=False)
- else:
- logger.info(m18n.n(
- 'service_conf_file_manually_removed',
- conf=system_path))
- conf_status = 'removed'
-
- # -> system conf is not managed yet
- elif not saved_hash:
- logger.debug("> system conf is not managed yet")
- if system_hash == new_hash:
- logger.debug("> no changes to system conf has been made")
- conf_status = 'managed'
- regenerated = True
- elif not to_remove:
- # If the conf exist but is not managed yet, and is not to be removed,
- # we assume that it is safe to regen it, since the file is backuped
- # anyway (by default in _regen), as long as we warn the user
- # appropriately.
- logger.info(m18n.n('service_conf_now_managed_by_yunohost',
- conf=system_path))
- regenerated = _regen(system_path, pending_path)
- conf_status = 'new'
- elif force:
- regenerated = _regen(system_path)
- conf_status = 'force-removed'
- else:
- logger.info(m18n.n('service_conf_file_kept_back',
- conf=system_path, service=service))
- conf_status = 'unmanaged'
-
- # -> system conf has not been manually modified
- elif system_hash == saved_hash:
- if to_remove:
- regenerated = _regen(system_path)
- conf_status = 'removed'
- elif system_hash != new_hash:
- regenerated = _regen(system_path, pending_path)
- conf_status = 'updated'
- else:
- logger.debug("> system conf is already up-to-date")
- os.remove(pending_path)
- continue
-
- else:
- logger.debug("> system conf has been manually modified")
- if system_hash == new_hash:
- logger.debug("> new conf is as current system conf")
- conf_status = 'managed'
- regenerated = True
- elif force:
- regenerated = _regen(system_path, pending_path)
- conf_status = 'force-updated'
- else:
- logger.warning(m18n.n(
- 'service_conf_file_manually_modified',
- conf=system_path))
- conf_status = 'modified'
-
- # Store the result
- conf_result = {'status': conf_status}
- if conf_diff is not None:
- conf_result['diff'] = conf_diff
- if regenerated:
- succeed_regen[system_path] = conf_result
- conf_hashes[system_path] = new_hash
- if os.path.isfile(pending_path):
- os.remove(pending_path)
- else:
- failed_regen[system_path] = conf_result
-
- # Check for service conf changes
- if not succeed_regen and not failed_regen:
- logger.debug(m18n.n('service_conf_up_to_date', service=service))
- continue
- elif not failed_regen:
- logger.success(m18n.n(
- 'service_conf_updated' if not dry_run else
- 'service_conf_would_be_updated',
- service=service))
-
- if succeed_regen and not dry_run:
- _update_conf_hashes(service, conf_hashes)
-
- # Append the service results
- result[service] = {
- 'applied': succeed_regen,
- 'pending': failed_regen
- }
-
- # Return in case of dry run
- if dry_run:
- return result
-
- # Execute hooks for post-regen
- post_args = ['post', ] + common_args
-
- def _pre_call(name, priority, path, args):
- # append coma-separated applied changes for the service
- if name in result and result[name]['applied']:
- regen_conf_files = ','.join(result[name]['applied'].keys())
- else:
- regen_conf_files = ''
- return post_args + [regen_conf_files, ]
-
- hook_callback('conf_regen', names, pre_callback=_pre_call)
-
- operation_logger.success()
-
- return result
-
-
def _run_service_command(action, service):
"""
Run services management command (start, stop, enable, disable, restart, reload)
@@ -860,231 +607,9 @@ def _find_previous_log_file(file):
return None
-def _get_files_diff(orig_file, new_file, as_string=False, skip_header=True):
- """Compare two files and return the differences
-
- Read and compare two files. The differences are returned either as a delta
- in unified diff format or a formatted string if as_string is True. The
- header can also be removed if skip_header is True.
-
- """
-
- if os.path.exists(orig_file):
- with open(orig_file, 'r') as orig_file:
- orig_file = orig_file.readlines()
- else:
- orig_file = []
-
- if os.path.exists(new_file):
- with open(new_file, 'r') as new_file:
- new_file = new_file.readlines()
- else:
- new_file = []
-
- # Compare files and format output
- diff = unified_diff(orig_file, new_file)
-
- if skip_header:
- try:
- next(diff)
- next(diff)
- except:
- pass
-
- if as_string:
- return ''.join(diff).rstrip()
-
- return diff
-
-
-def _calculate_hash(path):
- """Calculate the MD5 hash of a file"""
-
- if not os.path.exists(path):
- return None
-
- hasher = hashlib.md5()
-
- try:
- with open(path, 'rb') as f:
- hasher.update(f.read())
- return hasher.hexdigest()
-
- except IOError as e:
- logger.warning("Error while calculating file '%s' hash: %s", path, e, exc_info=1)
- return None
-
-
-def _get_pending_conf(services=[]):
- """Get pending configuration for service(s)
-
- Iterate over the pending configuration directory for given service(s) - or
- all if empty - and look for files inside. Each file is considered as a
- pending configuration file and therefore must be in the same directory
- tree than the system file that it replaces.
- The result is returned as a dict of services with pending configuration as
- key and a dict of `system_conf_path` => `pending_conf_path` as value.
-
- """
- result = {}
-
- if not os.path.isdir(PENDING_CONF_DIR):
- return result
-
- if not services:
- services = os.listdir(PENDING_CONF_DIR)
-
- for name in services:
- service_pending_path = os.path.join(PENDING_CONF_DIR, name)
-
- if not os.path.isdir(service_pending_path):
- continue
-
- path_index = len(service_pending_path)
- service_conf = {}
-
- for root, dirs, files in os.walk(service_pending_path):
- for filename in files:
- pending_path = os.path.join(root, filename)
- service_conf[pending_path[path_index:]] = pending_path
-
- if service_conf:
- result[name] = service_conf
- else:
- # remove empty directory
- shutil.rmtree(service_pending_path, ignore_errors=True)
-
- return result
-
-
-def _get_conf_hashes(service):
- """Get the registered conf hashes for a service"""
-
- services = _get_services()
-
- if service not in services:
- logger.debug("Service %s is not in services.yml yet.", service)
- return {}
-
- elif services[service] is None or 'conffiles' not in services[service]:
- logger.debug("No configuration files for service %s.", service)
- return {}
-
- else:
- return services[service]['conffiles']
-
-
-def _update_conf_hashes(service, hashes):
- """Update the registered conf hashes for a service"""
- logger.debug("updating conf hashes for '%s' with: %s",
- service, hashes)
- services = _get_services()
- service_conf = services.get(service, {})
-
- # Handle the case where services[service] is set to null in the yaml
- if service_conf is None:
- service_conf = {}
-
- service_conf['conffiles'] = hashes
- services[service] = service_conf
- _save_services(services)
-
-
-def _process_regen_conf(system_conf, new_conf=None, save=True):
- """Regenerate a given system configuration file
-
- Replace a given system configuration file by a new one or delete it if
- new_conf is None. A backup of the file - keeping its directory tree - will
- be done in the backup conf directory before any operation if save is True.
-
- """
- if save:
- backup_path = os.path.join(BACKUP_CONF_DIR, '{0}-{1}'.format(
- system_conf.lstrip('/'), datetime.utcnow().strftime("%Y%m%d.%H%M%S")))
- backup_dir = os.path.dirname(backup_path)
-
- if not os.path.isdir(backup_dir):
- filesystem.mkdir(backup_dir, 0o755, True)
-
- shutil.copy2(system_conf, backup_path)
- logger.debug(m18n.n('service_conf_file_backed_up',
- conf=system_conf, backup=backup_path))
-
- try:
- if not new_conf:
- os.remove(system_conf)
- logger.debug(m18n.n('service_conf_file_removed',
- conf=system_conf))
- else:
- system_dir = os.path.dirname(system_conf)
-
- if not os.path.isdir(system_dir):
- filesystem.mkdir(system_dir, 0o755, True)
-
- shutil.copyfile(new_conf, system_conf)
- logger.debug(m18n.n('service_conf_file_updated',
- conf=system_conf))
- except Exception as e:
- logger.warning("Exception while trying to regenerate conf '%s': %s", system_conf, e, exc_info=1)
- if not new_conf and os.path.exists(system_conf):
- logger.warning(m18n.n('service_conf_file_remove_failed',
- conf=system_conf),
- exc_info=1)
- return False
-
- elif new_conf:
- try:
- # From documentation:
- # Raise an exception if an os.stat() call on either pathname fails.
- # (os.stats returns a series of information from a file like type, size...)
- copy_succeed = os.path.samefile(system_conf, new_conf)
- except:
- copy_succeed = False
- finally:
- if not copy_succeed:
- logger.warning(m18n.n('service_conf_file_copy_failed',
- conf=system_conf, new=new_conf),
- exc_info=1)
- return False
-
- return True
-
-
-def manually_modified_files():
-
- # We do this to have --quiet, i.e. don't throw a whole bunch of logs
- # just to fetch this...
- # Might be able to optimize this by looking at what service_regenconf does
- # and only do the part that checks file hashes...
- cmd = "yunohost service regen-conf --dry-run --output-as json --quiet"
- j = json.loads(subprocess.check_output(cmd.split()))
-
- # j is something like :
- # {"postfix": {"applied": {}, "pending": {"/etc/postfix/main.cf": {"status": "modified"}}}
-
- output = []
- for app, actions in j.items():
- for action, files in actions.items():
- for filename, infos in files.items():
- if infos["status"] == "modified":
- output.append(filename)
-
- return output
-
-
def _get_journalctl_logs(service, number="all"):
try:
return subprocess.check_output("journalctl -xn -u {0} -n{1}".format(service, number), shell=True)
except:
import traceback
return "error while get services logs from journalctl:\n%s" % traceback.format_exc()
-
-
-def manually_modified_files_compared_to_debian_default():
-
- # from https://serverfault.com/a/90401
- r = subprocess.check_output("dpkg-query -W -f='${Conffiles}\n' '*' \
- | awk 'OFS=\" \"{print $2,$1}' \
- | md5sum -c 2>/dev/null \
- | awk -F': ' '$2 !~ /OK/{print $1}'", shell=True)
- return r.strip().split("\n")
From 3067e8e8975e77a3309a3038e0ba614647a381b6 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Fri, 8 Feb 2019 12:03:17 +0100
Subject: [PATCH 024/180] Misc renaming for consistency, basically
service->category
---
locales/en.json | 30 ++++----
src/yunohost/regenconf.py | 152 +++++++++++++++++++-------------------
2 files changed, 92 insertions(+), 90 deletions(-)
diff --git a/locales/en.json b/locales/en.json
index 8528c2576..34517a036 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -377,6 +377,21 @@
"port_available": "Port {port:d} is available",
"port_unavailable": "Port {port:d} is not available",
"recommend_to_add_first_user": "The post-install is finished but YunoHost needs at least one user to work correctly, you should add one using 'yunohost user create' or the admin interface.",
+ "regenconf_file_backed_up": "The configuration file '{conf}' has been backed up to '{backup}'",
+ "regenconf_file_copy_failed": "Unable to copy the new configuration file '{new}' to '{conf}'",
+ "regenconf_file_kept_back": "The configuration file '{conf}' is expected to be deleted by regen-conf (category {category}) but has been kept back.",
+ "regenconf_file_manually_modified": "The configuration file '{conf}' has been manually modified and will not be updated",
+ "regenconf_file_manually_removed": "The configuration file '{conf}' has been manually removed and will not be created",
+ "regenconf_file_remove_failed": "Unable to remove the configuration file '{conf}'",
+ "regenconf_file_removed": "The configuration file '{conf}' has been removed",
+ "regenconf_file_updated": "The configuration file '{conf}' has been updated",
+ "regenconf_now_managed_by_yunohost": "The configuration file '{conf}' is now managed by YunoHost (category {category}).",
+ "regenconf_up_to_date": "The configuration is already up-to-date for category '{category}'",
+ "regenconf_updated": "The configuration has been updated for category '{category}'",
+ "regenconf_would_be_updated": "The configuration would have been updated for category '{category}'",
+ "regenconf_dry_pending_applying": "Checking pending configuration which would have been applied for category '{category}'…",
+ "regenconf_failed": "Unable to regenerate the configuration for category(s): {categories}",
+ "regenconf_pending_applying": "Applying pending configuration for category '{category}'…",
"restore_action_required": "You must specify something to restore",
"restore_already_installed_app": "An app is already installed with the id '{app:s}'",
"restore_app_failed": "Unable to restore the app '{app:s}'",
@@ -405,18 +420,6 @@
"service_already_started": "Service '{service:s}' has already been started",
"service_already_stopped": "Service '{service:s}' has already been stopped",
"service_cmd_exec_failed": "Unable to execute command '{command:s}'",
- "service_conf_file_backed_up": "The configuration file '{conf}' has been backed up to '{backup}'",
- "service_conf_file_copy_failed": "Unable to copy the new configuration file '{new}' to '{conf}'",
- "service_conf_file_kept_back": "The configuration file '{conf}' is expected to be deleted by service {service} but has been kept back.",
- "service_conf_file_manually_modified": "The configuration file '{conf}' has been manually modified and will not be updated",
- "service_conf_file_manually_removed": "The configuration file '{conf}' has been manually removed and will not be created",
- "service_conf_file_remove_failed": "Unable to remove the configuration file '{conf}'",
- "service_conf_file_removed": "The configuration file '{conf}' has been removed",
- "service_conf_file_updated": "The configuration file '{conf}' has been updated",
- "service_conf_now_managed_by_yunohost": "The configuration file '{conf}' is now managed by YunoHost.",
- "service_conf_up_to_date": "The configuration is already up-to-date for service '{service}'",
- "service_conf_updated": "The configuration has been updated for service '{service}'",
- "service_conf_would_be_updated": "The configuration would have been updated for service '{service}'",
"service_description_avahi-daemon": "allows to reach your server using yunohost.local on your local network",
"service_description_dnsmasq": "handles domain name resolution (DNS)",
"service_description_dovecot": "allows e-mail client to access/fetch email (via IMAP and POP3)",
@@ -440,9 +443,6 @@
"service_enable_failed": "Unable to enable service '{service:s}'\n\nRecent service logs:{logs:s}",
"service_enabled": "The service '{service:s}' has been enabled",
"service_no_log": "No log to display for service '{service:s}'",
- "service_regenconf_dry_pending_applying": "Checking pending configuration which would have been applied for service '{service}'…",
- "service_regenconf_failed": "Unable to regenerate the configuration for service(s): {services}",
- "service_regenconf_pending_applying": "Applying pending configuration for service '{service}'…",
"service_remove_failed": "Unable to remove service '{service:s}'",
"service_removed": "The service '{service:s}' has been removed",
"service_reload_failed": "Unable to reload service '{service:s}'\n\nRecent service logs:{logs:s}",
diff --git a/src/yunohost/regenconf.py b/src/yunohost/regenconf.py
index 0330db508..4104e2491 100644
--- a/src/yunohost/regenconf.py
+++ b/src/yunohost/regenconf.py
@@ -43,14 +43,16 @@ PENDING_CONF_DIR = os.path.join(BASE_CONF_PATH, 'pending')
logger = log.getActionLogger('yunohost.regenconf')
+# FIXME : those ain't just services anymore ... what are we supposed to do with this ...
+# FIXME : check for all reference of 'service' close to operation_logger stuff
@is_unit_operation([('names', 'service')])
def regen_conf(operation_logger, names=[], with_diff=False, force=False, dry_run=False,
list_pending=False):
"""
- Regenerate the configuration file(s) for a service
+ Regenerate the configuration file(s)
Keyword argument:
- names -- Services name to regenerate configuration of
+ names -- Categories to regenerate configuration of
with_diff -- Show differences in case of configuration changes
force -- Override all manual modifications in configuration files
dry_run -- Show what would have been regenerated
@@ -66,10 +68,10 @@ def regen_conf(operation_logger, names=[], with_diff=False, force=False, dry_run
if not with_diff:
return pending_conf
- for service, conf_files in pending_conf.items():
+ for category, conf_files in pending_conf.items():
for system_path, pending_path in conf_files.items():
- pending_conf[service][system_path] = {
+ pending_conf[category][system_path] = {
'pending_conf': pending_path,
'diff': _get_files_diff(
system_path, pending_path, True),
@@ -103,12 +105,12 @@ def regen_conf(operation_logger, names=[], with_diff=False, force=False, dry_run
pre_args = ['pre', ] + common_args
def _pre_call(name, priority, path, args):
- # create the pending conf directory for the service
- service_pending_path = os.path.join(PENDING_CONF_DIR, name)
- filesystem.mkdir(service_pending_path, 0o755, True, uid='root')
+ # create the pending conf directory for the category
+ category_pending_path = os.path.join(PENDING_CONF_DIR, name)
+ filesystem.mkdir(category_pending_path, 0o755, True, uid='root')
# return the arguments to pass to the script
- return pre_args + [service_pending_path, ]
+ return pre_args + [category_pending_path, ]
# Don't regen SSH if not specifically specified
if not names:
@@ -118,29 +120,29 @@ def regen_conf(operation_logger, names=[], with_diff=False, force=False, dry_run
pre_result = hook_callback('conf_regen', names, pre_callback=_pre_call)
- # Update the services name
+ # Update the categorys name
names = pre_result['succeed'].keys()
if not names:
- raise YunohostError('service_regenconf_failed',
- services=', '.join(pre_result['failed']))
+ raise YunohostError('regenconf_failed',
+ categories=', '.join(pre_result['failed']))
# Set the processing method
_regen = _process_regen_conf if not dry_run else lambda *a, **k: True
operation_logger.related_to = []
- # Iterate over services and process pending conf
- for service, conf_files in _get_pending_conf(names).items():
+ # Iterate over categorys and process pending conf
+ for category, conf_files in _get_pending_conf(names).items():
if not dry_run:
- operation_logger.related_to.append(('service', service))
+ operation_logger.related_to.append(('service', category))
logger.debug(m18n.n(
- 'service_regenconf_pending_applying' if not dry_run else
- 'service_regenconf_dry_pending_applying',
- service=service))
+ 'regenconf_pending_applying' if not dry_run else
+ 'regenconf_dry_pending_applying',
+ category=category))
- conf_hashes = _get_conf_hashes(service)
+ conf_hashes = _get_conf_hashes(category)
succeed_regen = {}
failed_regen = {}
@@ -179,7 +181,7 @@ def regen_conf(operation_logger, names=[], with_diff=False, force=False, dry_run
system_path, pending_path, save=False)
else:
logger.info(m18n.n(
- 'service_conf_file_manually_removed',
+ 'regenconf_file_manually_removed',
conf=system_path))
conf_status = 'removed'
@@ -195,16 +197,16 @@ def regen_conf(operation_logger, names=[], with_diff=False, force=False, dry_run
# we assume that it is safe to regen it, since the file is backuped
# anyway (by default in _regen), as long as we warn the user
# appropriately.
- logger.info(m18n.n('service_conf_now_managed_by_yunohost',
- conf=system_path))
+ logger.info(m18n.n('regenconf_now_managed_by_yunohost',
+ conf=system_path, category=category))
regenerated = _regen(system_path, pending_path)
conf_status = 'new'
elif force:
regenerated = _regen(system_path)
conf_status = 'force-removed'
else:
- logger.info(m18n.n('service_conf_file_kept_back',
- conf=system_path, service=service))
+ logger.info(m18n.n('regenconf_file_kept_back',
+ conf=system_path, category=category))
conf_status = 'unmanaged'
# -> system conf has not been manually modified
@@ -231,7 +233,7 @@ def regen_conf(operation_logger, names=[], with_diff=False, force=False, dry_run
conf_status = 'force-updated'
else:
logger.warning(m18n.n(
- 'service_conf_file_manually_modified',
+ 'regenconf_file_manually_modified',
conf=system_path))
conf_status = 'modified'
@@ -247,21 +249,21 @@ def regen_conf(operation_logger, names=[], with_diff=False, force=False, dry_run
else:
failed_regen[system_path] = conf_result
- # Check for service conf changes
+ # Check for category conf changes
if not succeed_regen and not failed_regen:
- logger.debug(m18n.n('service_conf_up_to_date', service=service))
+ logger.debug(m18n.n('regenconf_up_to_date', category=category))
continue
elif not failed_regen:
logger.success(m18n.n(
- 'service_conf_updated' if not dry_run else
- 'service_conf_would_be_updated',
- service=service))
+ 'regenconf_updated' if not dry_run else
+ 'regenconf_would_be_updated',
+ category=category))
if succeed_regen and not dry_run:
- _update_conf_hashes(service, conf_hashes)
+ _update_conf_hashes(category, conf_hashes)
- # Append the service results
- result[service] = {
+ # Append the category results
+ result[category] = {
'applied': succeed_regen,
'pending': failed_regen
}
@@ -274,7 +276,7 @@ def regen_conf(operation_logger, names=[], with_diff=False, force=False, dry_run
post_args = ['post', ] + common_args
def _pre_call(name, priority, path, args):
- # append coma-separated applied changes for the service
+ # append coma-separated applied changes for the category
if name in result and result[name]['applied']:
regen_conf_files = ','.join(result[name]['applied'].keys())
else:
@@ -379,14 +381,14 @@ def _calculate_hash(path):
return None
-def _get_pending_conf(services=[]):
- """Get pending configuration for service(s)
+def _get_pending_conf(categories=[]):
+ """Get pending configuration for categories
- Iterate over the pending configuration directory for given service(s) - or
+ Iterate over the pending configuration directory for given categories - or
all if empty - and look for files inside. Each file is considered as a
pending configuration file and therefore must be in the same directory
tree than the system file that it replaces.
- The result is returned as a dict of services with pending configuration as
+ The result is returned as a dict of categories with pending configuration as
key and a dict of `system_conf_path` => `pending_conf_path` as value.
"""
@@ -395,63 +397,63 @@ def _get_pending_conf(services=[]):
if not os.path.isdir(PENDING_CONF_DIR):
return result
- if not services:
- services = os.listdir(PENDING_CONF_DIR)
+ if not categories:
+ categories = os.listdir(PENDING_CONF_DIR)
- for name in services:
- service_pending_path = os.path.join(PENDING_CONF_DIR, name)
+ for name in categories:
+ category_pending_path = os.path.join(PENDING_CONF_DIR, name)
- if not os.path.isdir(service_pending_path):
+ if not os.path.isdir(category_pending_path):
continue
- path_index = len(service_pending_path)
- service_conf = {}
+ path_index = len(category_pending_path)
+ category_conf = {}
- for root, dirs, files in os.walk(service_pending_path):
+ for root, dirs, files in os.walk(category_pending_path):
for filename in files:
pending_path = os.path.join(root, filename)
- service_conf[pending_path[path_index:]] = pending_path
+ category_conf[pending_path[path_index:]] = pending_path
- if service_conf:
- result[name] = service_conf
+ if category_conf:
+ result[name] = category_conf
else:
# remove empty directory
- shutil.rmtree(service_pending_path, ignore_errors=True)
+ shutil.rmtree(category_pending_path, ignore_errors=True)
return result
-def _get_conf_hashes(service):
- """Get the registered conf hashes for a service"""
+def _get_conf_hashes(category):
+ """Get the registered conf hashes for a category"""
- services = _get_services()
+ categories = _get_categories()
- if service not in services:
- logger.debug("Service %s is not in services.yml yet.", service)
+ if category not in categories:
+ logger.debug("category %s is not in categories.yml yet.", category)
return {}
- elif services[service] is None or 'conffiles' not in services[service]:
- logger.debug("No configuration files for service %s.", service)
+ elif categories[category] is None or 'conffiles' not in categories[category]:
+ logger.debug("No configuration files for category %s.", category)
return {}
else:
- return services[service]['conffiles']
+ return categories[category]['conffiles']
-def _update_conf_hashes(service, hashes):
- """Update the registered conf hashes for a service"""
+def _update_conf_hashes(category, hashes):
+ """Update the registered conf hashes for a category"""
logger.debug("updating conf hashes for '%s' with: %s",
- service, hashes)
- services = _get_services()
- service_conf = services.get(service, {})
+ category, hashes)
+ categories = _get_categories()
+ category_conf = categories.get(category, {})
- # Handle the case where services[service] is set to null in the yaml
- if service_conf is None:
- service_conf = {}
+ # Handle the case where categories[category] is set to null in the yaml
+ if category_conf is None:
+ category_conf = {}
- service_conf['conffiles'] = hashes
- services[service] = service_conf
- _save_services(services)
+ category_conf['conffiles'] = hashes
+ categories[category] = category_conf
+ _save_categories(categories)
def _process_regen_conf(system_conf, new_conf=None, save=True):
@@ -471,13 +473,13 @@ def _process_regen_conf(system_conf, new_conf=None, save=True):
filesystem.mkdir(backup_dir, 0o755, True)
shutil.copy2(system_conf, backup_path)
- logger.debug(m18n.n('service_conf_file_backed_up',
+ logger.debug(m18n.n('regenconf_file_backed_up',
conf=system_conf, backup=backup_path))
try:
if not new_conf:
os.remove(system_conf)
- logger.debug(m18n.n('service_conf_file_removed',
+ logger.debug(m18n.n('regenconf_file_removed',
conf=system_conf))
else:
system_dir = os.path.dirname(system_conf)
@@ -486,12 +488,12 @@ def _process_regen_conf(system_conf, new_conf=None, save=True):
filesystem.mkdir(system_dir, 0o755, True)
shutil.copyfile(new_conf, system_conf)
- logger.debug(m18n.n('service_conf_file_updated',
+ logger.debug(m18n.n('regenconf_file_updated',
conf=system_conf))
except Exception as e:
logger.warning("Exception while trying to regenerate conf '%s': %s", system_conf, e, exc_info=1)
if not new_conf and os.path.exists(system_conf):
- logger.warning(m18n.n('service_conf_file_remove_failed',
+ logger.warning(m18n.n('regenconf_file_remove_failed',
conf=system_conf),
exc_info=1)
return False
@@ -506,7 +508,7 @@ def _process_regen_conf(system_conf, new_conf=None, save=True):
copy_succeed = False
finally:
if not copy_succeed:
- logger.warning(m18n.n('service_conf_file_copy_failed',
+ logger.warning(m18n.n('regenconf_file_copy_failed',
conf=system_conf, new=new_conf),
exc_info=1)
return False
@@ -518,9 +520,9 @@ def manually_modified_files():
# We do this to have --quiet, i.e. don't throw a whole bunch of logs
# just to fetch this...
- # Might be able to optimize this by looking at what service_regenconf does
+ # Might be able to optimize this by looking at what the regen conf does
# and only do the part that checks file hashes...
- cmd = "yunohost service regen-conf --dry-run --output-as json --quiet"
+ cmd = "yunohost tools regen-conf --dry-run --output-as json --quiet"
j = json.loads(subprocess.check_output(cmd.split()))
# j is something like :
From e6f3a99269927a17829977dfa9682eb22827eae6 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Mon, 18 Feb 2019 17:44:09 +0100
Subject: [PATCH 025/180] Change binding from service_regen_conf to
tools_regen_conf
---
debian/postinst | 2 +-
locales/en.json | 1 +
src/yunohost/backup.py | 4 ++--
src/yunohost/certificate.py | 7 +++---
...0007_ssh_conf_managed_by_yunohost_step1.py | 6 ++---
...0008_ssh_conf_managed_by_yunohost_step2.py | 6 ++---
src/yunohost/domain.py | 6 ++---
src/yunohost/service.py | 13 +++++++++++
src/yunohost/tools.py | 22 ++++++++++++-------
9 files changed, 44 insertions(+), 23 deletions(-)
diff --git a/debian/postinst b/debian/postinst
index df7112b9d..83220ae0b 100644
--- a/debian/postinst
+++ b/debian/postinst
@@ -12,7 +12,7 @@ do_configure() {
bash /usr/share/yunohost/hooks/conf_regen/15-nginx init
else
echo "Regenerating configuration, this might take a while..."
- yunohost service regen-conf --output-as none
+ yunohost tools regen-conf --output-as none
echo "Launching migrations.."
yunohost tools migrations migrate --auto
diff --git a/locales/en.json b/locales/en.json
index 34517a036..5ab2a749b 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -443,6 +443,7 @@
"service_enable_failed": "Unable to enable service '{service:s}'\n\nRecent service logs:{logs:s}",
"service_enabled": "The service '{service:s}' has been enabled",
"service_no_log": "No log to display for service '{service:s}'",
+ "service_regen_conf_is_deprecated": "'yunohost service regen-conf' is depracted! Please use 'yunohost tools regen-conf' instead.",
"service_remove_failed": "Unable to remove service '{service:s}'",
"service_removed": "The service '{service:s}' has been removed",
"service_reload_failed": "Unable to reload service '{service:s}'\n\nRecent service logs:{logs:s}",
diff --git a/src/yunohost/backup.py b/src/yunohost/backup.py
index ed7799fc1..9f48700a2 100644
--- a/src/yunohost/backup.py
+++ b/src/yunohost/backup.py
@@ -50,7 +50,7 @@ from yunohost.hook import (
)
from yunohost.monitor import binary_to_human
from yunohost.tools import tools_postinstall
-from yunohost.service import service_regen_conf
+from yunohost.regenconf import regen_conf
from yunohost.log import OperationLogger
from functools import reduce
@@ -1191,7 +1191,7 @@ class RestoreManager():
else:
operation_logger.success()
- service_regen_conf()
+ regen_conf()
def _restore_apps(self):
"""Restore all apps targeted"""
diff --git a/src/yunohost/certificate.py b/src/yunohost/certificate.py
index 855910b8a..d7e8c0157 100644
--- a/src/yunohost/certificate.py
+++ b/src/yunohost/certificate.py
@@ -43,7 +43,8 @@ from yunohost.utils.network import get_public_ip
from moulinette import m18n
from yunohost.app import app_ssowatconf
-from yunohost.service import _run_service_command, service_regen_conf
+from yunohost.service import _run_service_command
+from yunohost.regenconf import regen_conf
from yunohost.log import OperationLogger
logger = getActionLogger('yunohost.certmanager')
@@ -806,7 +807,7 @@ def _enable_certificate(domain, new_cert_folder):
if os.path.isfile('/etc/yunohost/installed'):
# regen nginx conf to be sure it integrates OCSP Stapling
# (We don't do this yet if postinstall is not finished yet)
- service_regen_conf(names=['nginx'])
+ regen_conf(names=['nginx'])
_run_service_command("reload", "nginx")
@@ -924,7 +925,7 @@ def _regen_dnsmasq_if_needed():
break
if do_regen:
- service_regen_conf(["dnsmasq"])
+ regen_conf(["dnsmasq"])
def _name_self_CA():
diff --git a/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step1.py b/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step1.py
index 080cc0163..39a7d34e3 100644
--- a/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step1.py
+++ b/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step1.py
@@ -8,10 +8,10 @@ from moulinette.utils.log import getActionLogger
from moulinette.utils.filesystem import mkdir, rm
from yunohost.tools import Migration
-from yunohost.service import service_regen_conf, \
- _get_conf_hashes, \
+from yunohost.service import _get_conf_hashes, \
_calculate_hash, \
_run_service_command
+from yunohost.regen_conf import regen_conf
from yunohost.settings import settings_set
from yunohost.utils.error import YunohostError
@@ -64,7 +64,7 @@ class MyMigration(Migration):
if os.path.exists('/etc/yunohost/from_script'):
rm('/etc/yunohost/from_script')
copyfile(SSHD_CONF, '/etc/ssh/sshd_config.bkp')
- service_regen_conf(names=['ssh'], force=True)
+ regen_conf(names=['ssh'], force=True)
copyfile('/etc/ssh/sshd_config.bkp', SSHD_CONF)
# Restart ssh and backward if it fail
diff --git a/src/yunohost/data_migrations/0008_ssh_conf_managed_by_yunohost_step2.py b/src/yunohost/data_migrations/0008_ssh_conf_managed_by_yunohost_step2.py
index 0976f1354..fce44298d 100644
--- a/src/yunohost/data_migrations/0008_ssh_conf_managed_by_yunohost_step2.py
+++ b/src/yunohost/data_migrations/0008_ssh_conf_managed_by_yunohost_step2.py
@@ -6,9 +6,9 @@ from moulinette.utils.log import getActionLogger
from moulinette.utils.filesystem import chown
from yunohost.tools import Migration
-from yunohost.service import service_regen_conf, \
- _get_conf_hashes, \
+from yunohost.service import _get_conf_hashes, \
_calculate_hash
+from yunohost.regenconf import regen_conf
from yunohost.settings import settings_set, settings_get
from yunohost.utils.error import YunohostError
from yunohost.backup import ARCHIVES_PATH
@@ -36,7 +36,7 @@ class MyMigration(Migration):
def migrate(self):
settings_set("service.ssh.allow_deprecated_dsa_hostkey", False)
- service_regen_conf(names=['ssh'], force=True)
+ regen_conf(names=['ssh'], force=True)
# Update local archives folder permissions, so that
# admin can scp archives out of the server
diff --git a/src/yunohost/domain.py b/src/yunohost/domain.py
index 3d46691f8..54ed81dfb 100644
--- a/src/yunohost/domain.py
+++ b/src/yunohost/domain.py
@@ -34,7 +34,7 @@ from moulinette.utils.log import getActionLogger
import yunohost.certificate
-from yunohost.service import service_regen_conf
+from yunohost.regenconf import regen_conf
from yunohost.utils.network import get_public_ip
from yunohost.log import is_unit_operation
@@ -111,7 +111,7 @@ def domain_add(operation_logger, auth, domain, dyndns=False):
# Don't regen these conf if we're still in postinstall
if os.path.exists('/etc/yunohost/installed'):
- service_regen_conf(names=['nginx', 'metronome', 'dnsmasq', 'postfix', 'rspamd'])
+ regen_conf(names=['nginx', 'metronome', 'dnsmasq', 'postfix', 'rspamd'])
app_ssowatconf(auth)
except Exception:
@@ -164,7 +164,7 @@ def domain_remove(operation_logger, auth, domain, force=False):
else:
raise YunohostError('domain_deletion_failed')
- service_regen_conf(names=['nginx', 'metronome', 'dnsmasq', 'postfix'])
+ regen_conf(names=['nginx', 'metronome', 'dnsmasq', 'postfix'])
app_ssowatconf(auth)
hook_callback('post_domain_remove', args=[domain])
diff --git a/src/yunohost/service.py b/src/yunohost/service.py
index ab0e791d8..d088f0029 100644
--- a/src/yunohost/service.py
+++ b/src/yunohost/service.py
@@ -410,6 +410,19 @@ def service_log(name, number=50):
return result
+def service_regen_conf(names=[], with_diff=False, force=False, dry_run=False,
+ list_pending=False):
+
+ services = _get_services()
+ for name in names:
+ if name not in services:
+ raise YunohostError('service_unknown', service=service)
+
+ logger.warning(m18n.n("service_regen_conf_is_deprecated"))
+
+ return regen_conf(names, with_diff, force, dry_run, list_pending)
+
+
def _run_service_command(action, service):
"""
Run services management command (start, stop, enable, disable, restart, reload)
diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py
index b2fbf380c..deec0746f 100644
--- a/src/yunohost/tools.py
+++ b/src/yunohost/tools.py
@@ -47,7 +47,8 @@ from yunohost.app import app_fetchlist, app_info, app_upgrade, app_ssowatconf, a
from yunohost.domain import domain_add, domain_list, _get_maindomain, _set_maindomain
from yunohost.dyndns import _dyndns_available, _dyndns_provides
from yunohost.firewall import firewall_upnp
-from yunohost.service import service_status, service_regen_conf, service_log, service_start, service_enable
+from yunohost.service import service_status, service_log, service_start, service_enable
+from yunohost.regenconf import regen_conf
from yunohost.monitor import monitor_disk, monitor_system
from yunohost.utils.packages import ynh_packages_version
from yunohost.utils.network import get_public_ip
@@ -207,7 +208,7 @@ def tools_maindomain(operation_logger, auth, new_domain=None):
# Regen configurations
try:
with open('/etc/yunohost/installed', 'r'):
- service_regen_conf()
+ regen_conf()
except IOError:
pass
@@ -325,7 +326,7 @@ def tools_postinstall(operation_logger, domain, password, ignore_dyndns=False,
operation_logger.start()
logger.info(m18n.n('yunohost_installing'))
- service_regen_conf(['nslcd', 'nsswitch'], force=True)
+ regen_conf(['nslcd', 'nsswitch'], force=True)
# Initialize LDAP for YunoHost
# TODO: Improve this part by integrate ldapinit into conf_regen hook
@@ -376,7 +377,7 @@ def tools_postinstall(operation_logger, domain, password, ignore_dyndns=False,
os.system('chmod 644 /etc/ssowat/conf.json.persistent')
# Create SSL CA
- service_regen_conf(['ssl'], force=True)
+ regen_conf(['ssl'], force=True)
ssl_dir = '/usr/share/yunohost/yunohost-config/ssl/yunoCA'
# (Update the serial so that it's specific to this very instance)
os.system("openssl rand -hex 19 > %s/serial" % ssl_dir)
@@ -405,7 +406,7 @@ def tools_postinstall(operation_logger, domain, password, ignore_dyndns=False,
logger.success(m18n.n('yunohost_ca_creation_success'))
# New domain config
- service_regen_conf(['nsswitch'], force=True)
+ regen_conf(['nsswitch'], force=True)
domain_add(auth, domain, dyndns)
tools_maindomain(auth, domain)
@@ -433,7 +434,7 @@ def tools_postinstall(operation_logger, domain, password, ignore_dyndns=False,
service_enable("yunohost-firewall")
service_start("yunohost-firewall")
- service_regen_conf(force=True)
+ regen_conf(force=True)
# Restore original ssh conf, as chosen by the
# admin during the initial install
@@ -450,13 +451,18 @@ def tools_postinstall(operation_logger, domain, password, ignore_dyndns=False,
else:
# We need to explicitly ask the regen conf to regen ssh
# (by default, i.e. first argument = None, it won't because it's too touchy)
- service_regen_conf(names=["ssh"], force=True)
+ regen_conf(names=["ssh"], force=True)
logger.success(m18n.n('yunohost_configured'))
logger.warning(m18n.n('recommend_to_add_first_user'))
+def tools_regen_conf(names=[], with_diff=False, force=False, dry_run=False,
+ list_pending=False):
+ return regen_conf(names, with_diff, force, dry_run, list_pending)
+
+
def tools_update(ignore_apps=False, ignore_packages=False):
"""
Update apps & package cache, then display changelog
@@ -693,7 +699,7 @@ def tools_diagnosis(auth, private=False):
# Domains
diagnosis['private']['domains'] = domain_list(auth)['domains']
- diagnosis['private']['regen_conf'] = service_regen_conf(with_diff=True, dry_run=True)
+ diagnosis['private']['regen_conf'] = regen_conf(with_diff=True, dry_run=True)
try:
diagnosis['security'] = {
From 39891b228c393986101cdbf5093eaa9f1f2227c4 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Mon, 18 Feb 2019 17:54:24 +0100
Subject: [PATCH 026/180] Inteface with regenconf.yml instead of services.yml
---
src/yunohost/regenconf.py | 39 +++++++++++++++------------------------
1 file changed, 15 insertions(+), 24 deletions(-)
diff --git a/src/yunohost/regenconf.py b/src/yunohost/regenconf.py
index 4104e2491..783b50c4a 100644
--- a/src/yunohost/regenconf.py
+++ b/src/yunohost/regenconf.py
@@ -39,6 +39,7 @@ from yunohost.hook import hook_callback, hook_list
BASE_CONF_PATH = '/home/yunohost.conf'
BACKUP_CONF_DIR = os.path.join(BASE_CONF_PATH, 'backup')
PENDING_CONF_DIR = os.path.join(BASE_CONF_PATH, 'pending')
+REGEN_CONF_FILE = '/etc/yunohost/regenconf.yml'
logger = log.getActionLogger('yunohost.regenconf')
@@ -290,39 +291,28 @@ def regen_conf(operation_logger, names=[], with_diff=False, force=False, dry_run
return result
-def _get_services():
+def _get_regenconf_infos():
"""
- Get a dict of managed services with their parameters
-
+ Get a dict of regen conf informations
"""
try:
- with open('/etc/yunohost/services.yml', 'r') as f:
- services = yaml.load(f)
+ with open(REGEN_CONF_FILE, 'r') as f:
+ return yaml.load(f)
except:
return {}
- else:
- # some services are marked as None to remove them from YunoHost
- # filter this
- for key, value in services.items():
- if value is None:
- del services[key]
-
- return services
-def _save_services(services):
+def _save_regenconf_infos(infos):
"""
- Save managed services to files
-
+ Save the regen conf informations
Keyword argument:
- services -- A dict of managed services with their parameters
-
+ categories -- A dict containing the regenconf infos
"""
try:
- with open('/etc/yunohost/services.yml', 'w') as f:
- yaml.safe_dump(services, f, default_flow_style=False)
+ with open(REGEN_CONF_FILE, 'w') as f:
+ yaml.safe_dump(infos, f, default_flow_style=False)
except Exception as e:
- logger.warning('Error while saving services, exception: %s', e, exc_info=1)
+ logger.warning('Error while saving regenconf infos, exception: %s', e, exc_info=1)
raise
@@ -426,7 +416,7 @@ def _get_pending_conf(categories=[]):
def _get_conf_hashes(category):
"""Get the registered conf hashes for a category"""
- categories = _get_categories()
+ categories = _get_regenconf_infos()
if category not in categories:
logger.debug("category %s is not in categories.yml yet.", category)
@@ -444,7 +434,8 @@ def _update_conf_hashes(category, hashes):
"""Update the registered conf hashes for a category"""
logger.debug("updating conf hashes for '%s' with: %s",
category, hashes)
- categories = _get_categories()
+
+ categories = _get_regenconf_infos()
category_conf = categories.get(category, {})
# Handle the case where categories[category] is set to null in the yaml
@@ -453,7 +444,7 @@ def _update_conf_hashes(category, hashes):
category_conf['conffiles'] = hashes
categories[category] = category_conf
- _save_categories(categories)
+ _save_regenconf_infos(categories)
def _process_regen_conf(system_conf, new_conf=None, save=True):
From 96bd6f8deb5683475bb5daa23ad2489419e909cc Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Mon, 18 Feb 2019 18:50:46 +0100
Subject: [PATCH 027/180] Fix a few things for service_regen_conf backward
compatibility
---
src/yunohost/service.py | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/src/yunohost/service.py b/src/yunohost/service.py
index d088f0029..56cac7a55 100644
--- a/src/yunohost/service.py
+++ b/src/yunohost/service.py
@@ -414,12 +414,20 @@ def service_regen_conf(names=[], with_diff=False, force=False, dry_run=False,
list_pending=False):
services = _get_services()
+
+ if isinstance(names, str):
+ names = [names]
+
for name in names:
- if name not in services:
- raise YunohostError('service_unknown', service=service)
+ if name not in services.keys():
+ raise YunohostError('service_unknown', service=name)
+
+ if names is []:
+ names = services.keys()
logger.warning(m18n.n("service_regen_conf_is_deprecated"))
+ from yunohost.regenconf import regen_conf
return regen_conf(names, with_diff, force, dry_run, list_pending)
From 0ebbb83191273ca716ecaf1c128ece0705b84c82 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Mon, 18 Feb 2019 19:03:43 +0100
Subject: [PATCH 028/180] Add migration for services.yml on existing instance
---
data/templates/yunohost/services.yml | 9 ++--
.../0009_decouple_regenconf_from_services.py | 42 +++++++++++++++++++
src/yunohost/regenconf.py | 12 ++++++
3 files changed, 57 insertions(+), 6 deletions(-)
create mode 100644 src/yunohost/data_migrations/0009_decouple_regenconf_from_services.py
diff --git a/data/templates/yunohost/services.yml b/data/templates/yunohost/services.yml
index 62509e1e9..0d79b182f 100644
--- a/data/templates/yunohost/services.yml
+++ b/data/templates/yunohost/services.yml
@@ -20,8 +20,6 @@ mysql:
glances: {}
ssh:
log: /var/log/auth.log
-ssl:
- status: null
metronome:
log: [/var/log/metronome/metronome.log,/var/log/metronome/metronome.err]
slapd:
@@ -34,10 +32,9 @@ yunohost-firewall:
need_lock: true
nslcd:
log: /var/log/syslog
-nsswitch:
- status: null
-yunohost:
- status: null
+nsswitch: null
+ssl: null
+yunohost: null
bind9: null
tahoe-lafs: null
memcached: null
diff --git a/src/yunohost/data_migrations/0009_decouple_regenconf_from_services.py b/src/yunohost/data_migrations/0009_decouple_regenconf_from_services.py
new file mode 100644
index 000000000..e65aadfdf
--- /dev/null
+++ b/src/yunohost/data_migrations/0009_decouple_regenconf_from_services.py
@@ -0,0 +1,42 @@
+import os
+
+from moulinette import m18n
+from moulinette.utils.log import getActionLogger
+
+from moulinette.utils.filesystem import read_file
+from yunohost.service import _get_services, _save_services
+from yunohost.regenconf import _update_conf_hashes
+
+from yunohost.tools import Migration
+
+logger = getActionLogger('yunohost.migration')
+
+
+class MyMigration(Migration):
+ """
+ Decouple the regen conf mechanism from the concept of services
+ """
+
+ def migrate(self):
+
+ if "conffiles" not in read_file("/etc/yunohost/services.yml") \
+ or os.path.exists("/etc/yunohost/regenconf.yml"):
+ logger.warning(m18n.n("migration_0009_not_needed"))
+ return
+
+ # For all services
+ services = _get_services()
+ for service, infos in services.items():
+ # If there are some conffiles (file hashes)
+ if "conffiles" in infos.keys():
+ # Save them using the new regen conf thingy
+ _update_conf_hashes(service, infos["conffiles"])
+ # And delete the old conffile key from the service infos
+ del services[service]["conffiles"]
+
+ # (Actually save the modification of services)
+ _save_services(services)
+
+ def backward(self):
+
+ pass
diff --git a/src/yunohost/regenconf.py b/src/yunohost/regenconf.py
index 783b50c4a..3ea8ccb6d 100644
--- a/src/yunohost/regenconf.py
+++ b/src/yunohost/regenconf.py
@@ -31,6 +31,7 @@ from datetime import datetime
from moulinette import m18n
from moulinette.utils import log, filesystem
+from moulinette.utils.filesystem import read_file
from yunohost.utils.error import YunohostError
from yunohost.log import is_unit_operation
@@ -60,6 +61,17 @@ def regen_conf(operation_logger, names=[], with_diff=False, force=False, dry_run
list_pending -- List pending configuration files and exit
"""
+
+ # Legacy code to automatically run the migration
+ # This is required because regen_conf is called before the migration call
+ # in debian's postinst script
+ if os.path.exists("/etc/yunohost/installed") \
+ and ("conffiles" in read_file("/etc/yunohost/services.yml") \
+ or not os.path.exists("/etc/yunohost/regenconf.yml")):
+ from yunohost.tools import _get_migration_by_name
+ migration = _get_migration_by_name("decouple_regenconf_from_services")
+ migration.migrate()
+
result = {}
# Return the list of pending conf
From d7d224286237f7bb8733bdccb19ad348674f1331 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Mon, 18 Feb 2019 19:10:01 +0100
Subject: [PATCH 029/180] Fix imports in some migrations
---
src/yunohost/data_migrations/0003_migrate_to_stretch.py | 6 +++---
.../0007_ssh_conf_managed_by_yunohost_step1.py | 7 ++-----
.../0008_ssh_conf_managed_by_yunohost_step2.py | 3 +--
3 files changed, 6 insertions(+), 10 deletions(-)
diff --git a/src/yunohost/data_migrations/0003_migrate_to_stretch.py b/src/yunohost/data_migrations/0003_migrate_to_stretch.py
index 438393216..0db719e15 100644
--- a/src/yunohost/data_migrations/0003_migrate_to_stretch.py
+++ b/src/yunohost/data_migrations/0003_migrate_to_stretch.py
@@ -10,9 +10,9 @@ from moulinette.utils.filesystem import read_file
from yunohost.tools import Migration
from yunohost.app import unstable_apps
-from yunohost.service import (_run_service_command,
- manually_modified_files,
- manually_modified_files_compared_to_debian_default)
+from yunohost.service import _run_service_command
+from yunohost.regenconf import (manually_modified_files,
+ manually_modified_files_compared_to_debian_default)
from yunohost.utils.filesystem import free_space_in_directory
from yunohost.utils.packages import get_installed_version
from yunohost.utils.network import get_network_interfaces
diff --git a/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step1.py b/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step1.py
index 39a7d34e3..959b17fb5 100644
--- a/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step1.py
+++ b/src/yunohost/data_migrations/0007_ssh_conf_managed_by_yunohost_step1.py
@@ -3,15 +3,12 @@ import re
from shutil import copyfile
-from moulinette import m18n
from moulinette.utils.log import getActionLogger
from moulinette.utils.filesystem import mkdir, rm
from yunohost.tools import Migration
-from yunohost.service import _get_conf_hashes, \
- _calculate_hash, \
- _run_service_command
-from yunohost.regen_conf import regen_conf
+from yunohost.service import _run_service_command
+from yunohost.regenconf import regen_conf
from yunohost.settings import settings_set
from yunohost.utils.error import YunohostError
diff --git a/src/yunohost/data_migrations/0008_ssh_conf_managed_by_yunohost_step2.py b/src/yunohost/data_migrations/0008_ssh_conf_managed_by_yunohost_step2.py
index fce44298d..8984440bd 100644
--- a/src/yunohost/data_migrations/0008_ssh_conf_managed_by_yunohost_step2.py
+++ b/src/yunohost/data_migrations/0008_ssh_conf_managed_by_yunohost_step2.py
@@ -6,8 +6,7 @@ from moulinette.utils.log import getActionLogger
from moulinette.utils.filesystem import chown
from yunohost.tools import Migration
-from yunohost.service import _get_conf_hashes, \
- _calculate_hash
+from yunohost.regenconf import _get_conf_hashes, _calculate_hash
from yunohost.regenconf import regen_conf
from yunohost.settings import settings_set, settings_get
from yunohost.utils.error import YunohostError
From 984646bb3cd6866ce36e146620ad62fe3361e048 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Mon, 18 Feb 2019 19:22:19 +0100
Subject: [PATCH 030/180] Implement strings for migration
---
locales/en.json | 2 ++
1 file changed, 2 insertions(+)
diff --git a/locales/en.json b/locales/en.json
index 5ab2a749b..a606a13dc 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -286,6 +286,7 @@
"migration_description_0006_sync_admin_and_root_passwords": "Synchronize admin and root passwords",
"migration_description_0007_ssh_conf_managed_by_yunohost_step1": "Let the SSH configuration be managed by YunoHost (step 1, automatic)",
"migration_description_0008_ssh_conf_managed_by_yunohost_step2": "Let the SSH configuration be managed by YunoHost (step 2, manual)",
+ "migration_description_0009_decouple_regenconf_from_services": "Decouple the regen-conf mechanism from services",
"migration_0003_backward_impossible": "The stretch migration cannot be reverted.",
"migration_0003_start": "Starting migration to Stretch. The logs will be available in {logfile}.",
"migration_0003_patching_sources_list": "Patching the sources.lists…",
@@ -311,6 +312,7 @@
"migration_0008_dsa": " - the DSA key will be disabled. Hence, you might need to invalidate a spooky warning from your SSH client, and recheck the fingerprint of your server;",
"migration_0008_warning": "If you understand those warnings and agree to let YunoHost override your current configuration, run the migration. Otherwise, you can also skip the migration - though it is not recommended.",
"migration_0008_no_warning": "No major risk has been indentified about overriding your SSH configuration - but we can't be absolutely sure ;)! If you agree to let YunoHost override your current configuration, run the migration. Otherwise, you can also skip the migration - though it is not recommended.",
+ "migration_0009_not_needed": "This migration already happened somehow ? Skipping.",
"migrations_backward": "Migrating backward.",
"migrations_bad_value_for_target": "Invalid number for target argument, available migrations numbers are 0 or {}",
"migrations_cant_reach_migration_file": "Can't access migrations files at path %s",
From 69b8f7294b91360f3e937a2b3ab5cf7bd9515331 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Mon, 18 Feb 2019 19:36:06 +0100
Subject: [PATCH 031/180] Fix log handling
---
locales/en.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/locales/en.json b/locales/en.json
index a606a13dc..c10e8c393 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -249,7 +249,7 @@
"log_selfsigned_cert_install": "Install self signed certificate on '{}' domain",
"log_letsencrypt_cert_renew": "Renew '{}' Let's encrypt certificate",
"log_service_enable": "Enable '{}' service",
- "log_service_regen_conf": "Regenerate system configurations '{}'",
+ "log_regen_conf": "Regenerate system configurations '{}'",
"log_user_create": "Add '{}' user",
"log_user_delete": "Delete '{}' user",
"log_user_update": "Update information of '{}' user",
From 9aa6cb6ac5c23f1a5385d0bda513629a445bf8ee Mon Sep 17 00:00:00 2001
From: Romuald du Song
Date: Thu, 21 Feb 2019 20:46:18 +0100
Subject: [PATCH 032/180] add hook to reconfigure nginx or ssh on settings
change
---
src/yunohost/settings.py | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/src/yunohost/settings.py b/src/yunohost/settings.py
index 1d60c3a6a..96c73a79d 100644
--- a/src/yunohost/settings.py
+++ b/src/yunohost/settings.py
@@ -239,3 +239,14 @@ def _save_settings(settings, location=SETTINGS_PATH):
settings_fd.write(result)
except Exception as e:
raise YunohostError('global_settings_cant_write_settings', reason=e)
+
+@post_change_hook("security.ciphers.compatibility")
+def reconfigure_nginx(setting_name, old_value, new_value):
+ if old_value != new_value:
+ service_regen_conf("nginx")
+
+@post_change_hook("service.ssh.ciphers.compatibility")
+def reconfigure_ssh(setting_name, old_value, new_value):
+ if old_value != new_value:
+ service_regen_conf("ssh")
+
From ac250e2549974adc2a610756f9bea2f8404b27d5 Mon Sep 17 00:00:00 2001
From: Romuald du Song
Date: Thu, 21 Feb 2019 21:15:25 +0100
Subject: [PATCH 033/180] fix service_regen_conf syntax
---
src/yunohost/settings.py | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/yunohost/settings.py b/src/yunohost/settings.py
index 96c73a79d..d19b0cba3 100644
--- a/src/yunohost/settings.py
+++ b/src/yunohost/settings.py
@@ -7,6 +7,7 @@ from collections import OrderedDict
from moulinette import m18n
from yunohost.utils.error import YunohostError
from moulinette.utils.log import getActionLogger
+from yunohost.service import service_regen_conf
logger = getActionLogger('yunohost.settings')
@@ -243,10 +244,10 @@ def _save_settings(settings, location=SETTINGS_PATH):
@post_change_hook("security.ciphers.compatibility")
def reconfigure_nginx(setting_name, old_value, new_value):
if old_value != new_value:
- service_regen_conf("nginx")
+ service_regen_conf(names=['nginx'], force=True)
@post_change_hook("service.ssh.ciphers.compatibility")
def reconfigure_ssh(setting_name, old_value, new_value):
if old_value != new_value:
- service_regen_conf("ssh")
+ service_regen_conf(names=['ssh'], force=True)
From e7d322b68ccf6bb13e103ace8b1ed81543984f91 Mon Sep 17 00:00:00 2001
From: Romuald du Song
Date: Mon, 25 Feb 2019 18:29:46 +0100
Subject: [PATCH 034/180] don't enforce services reconfiguration generation
unless you don't want to keep user meodifications
---
src/yunohost/settings.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/yunohost/settings.py b/src/yunohost/settings.py
index cb87f67ac..916e8b8c3 100644
--- a/src/yunohost/settings.py
+++ b/src/yunohost/settings.py
@@ -286,9 +286,9 @@ def trigger_post_change_hook(setting_name, old_value, new_value):
@post_change_hook("security.ciphers.compatibility")
def reconfigure_nginx(setting_name, old_value, new_value):
if old_value != new_value:
- service_regen_conf(names=['nginx'], force=True)
+ service_regen_conf(names=['nginx'])
@post_change_hook("service.ssh.ciphers.compatibility")
def reconfigure_ssh(setting_name, old_value, new_value):
if old_value != new_value:
- service_regen_conf(names=['ssh'], force=True)
+ service_regen_conf(names=['ssh'])
From 873bf4ae370cf785c66db0028ca1ab5bc06340c0 Mon Sep 17 00:00:00 2001
From: Maniack Crudelis
Date: Mon, 25 Feb 2019 18:44:21 +0100
Subject: [PATCH 035/180] Add min version for all helpers
---
data/helpers.d/backend | 16 ++++++++++++++++
data/helpers.d/debug | 4 ++++
data/helpers.d/filesystem | 11 +++++++++++
data/helpers.d/getopts | 2 ++
data/helpers.d/ip | 3 +++
data/helpers.d/mysql | 24 ++++++++++++++++++++++++
data/helpers.d/network | 8 ++++++++
data/helpers.d/nodejs | 10 ++++++++++
data/helpers.d/package | 24 ++++++++++++++++++++++++
data/helpers.d/print | 27 +++++++++++++++++++++++++++
data/helpers.d/psql | 20 ++++++++++++++++++++
data/helpers.d/setting | 6 ++++++
data/helpers.d/string | 6 ++++++
data/helpers.d/system | 12 ++++++++++++
data/helpers.d/user | 12 ++++++++++++
data/helpers.d/utils | 8 ++++++++
16 files changed, 193 insertions(+)
diff --git a/data/helpers.d/backend b/data/helpers.d/backend
index e710da9c7..ac6f3e5de 100644
--- a/data/helpers.d/backend
+++ b/data/helpers.d/backend
@@ -14,6 +14,8 @@
#
# It's possible to use this helper several times, each config will be added to the same logrotate config file.
# Unless you use the option --non-append
+#
+# Requires YunoHost version 2.6.4 or higher.
ynh_use_logrotate () {
# Declare an array to define the options of this helper.
local legacy_args=lnuya
@@ -92,6 +94,8 @@ EOF
# Remove the app's logrotate config.
#
# usage: ynh_remove_logrotate
+#
+# Requires YunoHost version 2.6.4 or higher.
ynh_remove_logrotate () {
if [ -e "/etc/logrotate.d/$app" ]; then
sudo rm "/etc/logrotate.d/$app"
@@ -112,6 +116,7 @@ ynh_remove_logrotate () {
# __APP__ by $app
# __FINALPATH__ by $final_path
#
+# Requires YunoHost version 2.7.2 or higher.
ynh_add_systemd_config () {
# Declare an array to define the options of this helper.
local legacy_args=st
@@ -147,6 +152,7 @@ ynh_add_systemd_config () {
# usage: ynh_remove_systemd_config [--service=service]
# | arg: -s, --service - Service name (optionnal, $app by default)
#
+# Requires YunoHost version 2.7.2 or higher.
ynh_remove_systemd_config () {
# Declare an array to define the options of this helper.
local legacy_args=s
@@ -183,6 +189,7 @@ ynh_remove_systemd_config () {
# __PATH_2__ by $path_2
# __PORT_2__ by $port_2
#
+# Requires YunoHost version 2.7.2 or higher.
ynh_add_nginx_config () {
finalnginxconf="/etc/nginx/conf.d/$domain.d/$app.conf"
local others_var=${1:-}
@@ -233,6 +240,8 @@ ynh_add_nginx_config () {
# Remove the dedicated nginx config
#
# usage: ynh_remove_nginx_config
+#
+# Requires YunoHost version 2.7.2 or higher.
ynh_remove_nginx_config () {
ynh_secure_remove --file="/etc/nginx/conf.d/$domain.d/$app.conf"
sudo systemctl reload nginx
@@ -241,6 +250,8 @@ ynh_remove_nginx_config () {
# Create a dedicated php-fpm config
#
# usage: ynh_add_fpm_config
+#
+# Requires YunoHost version 2.7.2 or higher.
ynh_add_fpm_config () {
# Configure PHP-FPM 7.0 by default
local fpm_config_dir="/etc/php/7.0/fpm"
@@ -276,6 +287,8 @@ ynh_add_fpm_config () {
# Remove the dedicated php-fpm config
#
# usage: ynh_remove_fpm_config
+#
+# Requires YunoHost version 2.7.2 or higher.
ynh_remove_fpm_config () {
local fpm_config_dir=$(ynh_app_setting_get --app=$app --key=fpm_config_dir)
local fpm_service=$(ynh_app_setting_get --app=$app --key=fpm_service)
@@ -350,6 +363,7 @@ ynh_remove_fpm_config () {
# To validate your regex you can test with this command:
# fail2ban-regex /var/log/YOUR_LOG_FILE_PATH /etc/fail2ban/filter.d/YOUR_APP.conf
#
+# Requires YunoHost version 3.?.? or higher.
ynh_add_fail2ban_config () {
# Declare an array to define the options of this helper.
declare -Ar args_array=( [l]=logpath= [r]=failregex= [m]=max_retry= [p]=ports= [t]=use_template [v]=others_var=)
@@ -429,6 +443,8 @@ EOF
# Remove the dedicated fail2ban config (jail and filter conf files)
#
# usage: ynh_remove_fail2ban_config
+#
+# Requires YunoHost version 3.?.? or higher.
ynh_remove_fail2ban_config () {
ynh_secure_remove "/etc/fail2ban/jail.d/$app.conf"
ynh_secure_remove "/etc/fail2ban/filter.d/$app.conf"
diff --git a/data/helpers.d/debug b/data/helpers.d/debug
index a8b7c8d69..ea20ffc1a 100644
--- a/data/helpers.d/debug
+++ b/data/helpers.d/debug
@@ -5,6 +5,8 @@
# usage: ynh_debug [--message=message] [--trace=1/0]
# | arg: -m, --message= - The text to print
# | arg: -t, --trace= - Turn on or off the trace of the script. Usefull to trace nonly a small part of a script.
+#
+# Requires YunoHost version 3.?.? or higher.
ynh_debug () {
# Disable set xtrace for the helper itself, to not pollute the debug log
set +x
@@ -54,6 +56,8 @@ ynh_debug () {
# In case of use of pipes, you have to use double quotes. Otherwise, this helper will be executed with the first command, then be sent to the next pipe.
#
# | arg: command - command to execute
+#
+# Requires YunoHost version 3.?.? or higher.
ynh_debug_exec () {
ynh_debug --message="$(eval $@)"
}
diff --git a/data/helpers.d/filesystem b/data/helpers.d/filesystem
index 10123dea4..6fb6347a6 100644
--- a/data/helpers.d/filesystem
+++ b/data/helpers.d/filesystem
@@ -46,6 +46,7 @@ CAN_BIND=${CAN_BIND:-1}
# ynh_backup "/etc/nginx/conf.d/$domain.d/$app.conf" "/conf/"
# # => "/etc/nginx/conf.d/$domain.d/$app.conf","apps/wordpress/conf/$app.conf"
#
+# Requires YunoHost version 2.4.0 or higher.
ynh_backup() {
# TODO find a way to avoid injection by file strange naming !
@@ -158,6 +159,7 @@ ynh_backup() {
#
# usage: ynh_restore
#
+# Requires YunoHost version 2.6.4 or higher.
ynh_restore () {
# Deduce the relative path of $YNH_CWD
local REL_DIR="${YNH_CWD#$YNH_BACKUP_DIR/}"
@@ -219,6 +221,7 @@ with open(sys.argv[1], 'r') as backup_file:
# # DON'T GIVE THE ARCHIVE PATH:
# ynh_restore_file "conf/nginx.conf"
#
+# Requires YunoHost version 2.6.4 or higher.
ynh_restore_file () {
# Declare an array to define the options of this helper.
local legacy_args=odm
@@ -313,6 +316,8 @@ properly with chmod/chown." >&2
#
# usage: ynh_store_file_checksum --file=file
# | arg: -f, --file - The file on which the checksum will performed, then stored.
+#
+# Requires YunoHost version 2.6.4 or higher.
ynh_store_file_checksum () {
# Declare an array to define the options of this helper.
local legacy_args=f
@@ -345,6 +350,8 @@ ynh_store_file_checksum () {
# | arg: -f, --file - The file on which the checksum test will be perfomed.
#
# | ret: Return the name a the backup file, or nothing
+#
+# Requires YunoHost version 2.6.4 or higher.
ynh_backup_if_checksum_is_different () {
# Declare an array to define the options of this helper.
local legacy_args=f
@@ -376,6 +383,8 @@ ynh_backup_if_checksum_is_different () {
#
# usage: ynh_remove_file_checksum file
# | arg: -f, --file= - The file for which the checksum will be deleted
+#
+# Requires YunoHost version 3.3.1 or higher.
ynh_delete_file_checksum () {
# Declare an array to define the options of this helper.
local legacy_args=f
@@ -392,6 +401,8 @@ ynh_delete_file_checksum () {
#
# usage: ynh_secure_remove --file=path_to_remove
# | arg: -f, --file - File or directory to remove
+#
+# Requires YunoHost version 2.6.4 or higher.
ynh_secure_remove () {
# Declare an array to define the options of this helper.
local legacy_args=f
diff --git a/data/helpers.d/getopts b/data/helpers.d/getopts
index 7055325f1..f89784578 100644
--- a/data/helpers.d/getopts
+++ b/data/helpers.d/getopts
@@ -43,6 +43,8 @@
# To keep a retrocompatibility, a package can still call a helper, using getopts, with positional arguments.
# The "legacy mode" will manage the positional arguments and fill the variable in the same order than they are given in $args_array.
# e.g. for `my_helper "val1" val2`, arg1 will be filled with val1, and arg2 with val2.
+#
+# Requires YunoHost version 3.2.2 or higher.
ynh_handle_getopts_args () {
# Manage arguments only if there's some provided
set +x
diff --git a/data/helpers.d/ip b/data/helpers.d/ip
index c50d8be73..2ca4053d9 100644
--- a/data/helpers.d/ip
+++ b/data/helpers.d/ip
@@ -7,6 +7,7 @@
#
# example: ynh_validate_ip 4 111.222.333.444
#
+# Requires YunoHost version 2.2.4 or higher.
ynh_validate_ip()
{
# http://stackoverflow.com/questions/319279/how-to-validate-ip-address-in-python#319298
@@ -40,6 +41,7 @@ EOF
# usage: ynh_validate_ip4 --ip_address=ip_address
# | ret: 0 for valid ipv4 addresses, 1 otherwise
#
+# Requires YunoHost version 2.2.4 or higher.
ynh_validate_ip4()
{
# Declare an array to define the options of this helper.
@@ -60,6 +62,7 @@ ynh_validate_ip4()
# usage: ynh_validate_ip6 --ip_address=ip_address
# | ret: 0 for valid ipv6 addresses, 1 otherwise
#
+# Requires YunoHost version 2.2.4 or higher.
ynh_validate_ip6()
{
# Declare an array to define the options of this helper.
diff --git a/data/helpers.d/mysql b/data/helpers.d/mysql
index fa1a61dab..313b7a245 100644
--- a/data/helpers.d/mysql
+++ b/data/helpers.d/mysql
@@ -11,6 +11,8 @@ MYSQL_ROOT_PWD_FILE=/etc/yunohost/mysql
# | arg: -u, --user - the user name to connect as
# | arg: -p, --password - the user password
# | arg: -d, --database - the database to connect to
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_mysql_connect_as() {
# Declare an array to define the options of this helper.
local legacy_args=upd
@@ -30,6 +32,8 @@ ynh_mysql_connect_as() {
# usage: ynh_mysql_execute_as_root --sql=sql [--database=database]
# | arg: -s, --sql - the SQL command to execute
# | arg: -d, --database - the database to connect to
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_mysql_execute_as_root() {
# Declare an array to define the options of this helper.
local legacy_args=sd
@@ -49,6 +53,8 @@ ynh_mysql_execute_as_root() {
# usage: ynh_mysql_execute_file_as_root --file=file [--database=database]
# | arg: -f, --file - the file containing SQL commands
# | arg: -d, --database - the database to connect to
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_mysql_execute_file_as_root() {
# Declare an array to define the options of this helper.
local legacy_args=fd
@@ -71,6 +77,8 @@ ynh_mysql_execute_file_as_root() {
# | arg: db - the database name to create
# | arg: user - the user to grant privilegies
# | arg: pwd - the password to identify user by
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_mysql_create_db() {
local db=$1
@@ -95,6 +103,8 @@ ynh_mysql_create_db() {
#
# usage: ynh_mysql_drop_db db
# | arg: db - the database name to drop
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_mysql_drop_db() {
ynh_mysql_execute_as_root --sql="DROP DATABASE ${1};"
}
@@ -106,6 +116,8 @@ ynh_mysql_drop_db() {
# usage: ynh_mysql_dump_db --database=database
# | arg: -d, --database - the database name to dump
# | ret: the mysqldump output
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_mysql_dump_db() {
# Declare an array to define the options of this helper.
local legacy_args=d
@@ -124,6 +136,8 @@ ynh_mysql_dump_db() {
# usage: ynh_mysql_create_user user pwd [host]
# | arg: user - the user name to create
# | arg: pwd - the password to identify user by
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_mysql_create_user() {
ynh_mysql_execute_as_root \
--sql="CREATE USER '${1}'@'localhost' IDENTIFIED BY '${2}';"
@@ -133,6 +147,8 @@ ynh_mysql_create_user() {
#
# usage: ynh_mysql_user_exists --user=user
# | arg: -u, --user - the user for which to check existence
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_mysql_user_exists()
{
# Declare an array to define the options of this helper.
@@ -156,6 +172,8 @@ ynh_mysql_user_exists()
#
# usage: ynh_mysql_drop_user user
# | arg: user - the user name to drop
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_mysql_drop_user() {
ynh_mysql_execute_as_root --sql="DROP USER '${1}'@'localhost';"
}
@@ -169,6 +187,8 @@ ynh_mysql_drop_user() {
# | arg: -u, --db_user - Owner of the database
# | arg: -n, --db_name - Name of the database
# | arg: -p, --db_pwd - Password of the database. If not given, a password will be generated
+#
+# Requires YunoHost version 2.6.4 or higher.
ynh_mysql_setup_db () {
# Declare an array to define the options of this helper.
local legacy_args=unp
@@ -192,6 +212,8 @@ ynh_mysql_setup_db () {
# usage: ynh_mysql_remove_db --db_user=user --db_name=name
# | arg: -u, --db_user - Owner of the database
# | arg: -n, --db_name - Name of the database
+#
+# Requires YunoHost version 2.6.4 or higher.
ynh_mysql_remove_db () {
# Declare an array to define the options of this helper.
local legacy_args=un
@@ -223,6 +245,8 @@ ynh_mysql_remove_db () {
# usage: ynh_sanitize_dbid --db_name=name
# | arg: -n, --db_name - name to correct/sanitize
# | ret: the corrected name
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_sanitize_dbid () {
# Declare an array to define the options of this helper.
local legacy_args=n
diff --git a/data/helpers.d/network b/data/helpers.d/network
index a765d6346..8812f8f39 100644
--- a/data/helpers.d/network
+++ b/data/helpers.d/network
@@ -12,6 +12,8 @@
#
# usage: ynh_normalize_url_path --path_url=path_to_normalize
# | arg: -p, --path_url - URL path to normalize before using it
+#
+# Requires YunoHost version 2.6.4 or higher.
ynh_normalize_url_path () {
# Declare an array to define the options of this helper.
local legacy_args=p
@@ -36,6 +38,8 @@ ynh_normalize_url_path () {
#
# usage: ynh_find_port --port=begin_port
# | arg: -p, --port - port to start to search
+#
+# Requires YunoHost version 2.6.4 or higher.
ynh_find_port () {
# Declare an array to define the options of this helper.
local legacy_args=p
@@ -59,6 +63,8 @@ ynh_find_port () {
# usage: ynh_webpath_available --domain=domain --path_url=path
# | arg: -d, --domain - the domain/host of the url
# | arg: -p, --path_url - the web path to check the availability of
+#
+# Requires YunoHost version 2.6.4 or higher.
ynh_webpath_available () {
# Declare an array to define the options of this helper.
local legacy_args=dp
@@ -79,6 +85,8 @@ ynh_webpath_available () {
# | arg: -a, --app - the app for which the domain should be registered
# | arg: -d, --domain - the domain/host of the web path
# | arg: -p, --path_url - the web path to be registered
+#
+# Requires YunoHost version 2.6.4 or higher.
ynh_webpath_register () {
# Declare an array to define the options of this helper.
local legacy_args=adp
diff --git a/data/helpers.d/nodejs b/data/helpers.d/nodejs
index 61a1414ef..34583328d 100644
--- a/data/helpers.d/nodejs
+++ b/data/helpers.d/nodejs
@@ -10,6 +10,8 @@ export N_PREFIX="$n_install_dir"
# [internal]
#
# usage: ynh_install_n
+#
+# Requires YunoHost version 2.7.12 or higher.
ynh_install_n () {
echo "Installation of N - Node.js version management" >&2
# Build an app.src for n
@@ -36,6 +38,8 @@ SOURCE_SUM=2ba3c9d4dd3c7e38885b37e02337906a1ee91febe6d5c9159d89a9050f2eea8f" > "
# That's means it has to be added to any systemd script.
#
# usage: ynh_use_nodejs
+#
+# Requires YunoHost version 2.7.12 or higher.
ynh_use_nodejs () {
nodejs_version=$(ynh_app_setting_get --app=$app --key=nodejs_version)
@@ -59,6 +63,8 @@ ynh_use_nodejs () {
# | arg: -n, --nodejs_version - Version of node to install.
# If possible, prefer to use major version number (e.g. 8 instead of 8.10.0).
# The crontab will handle the update of minor versions when needed.
+#
+# Requires YunoHost version 2.7.12 or higher.
ynh_install_nodejs () {
# Use n, https://github.com/tj/n to manage the nodejs versions
@@ -135,6 +141,8 @@ ynh_install_nodejs () {
# If no other app uses node, n will be also removed.
#
# usage: ynh_remove_nodejs
+#
+# Requires YunoHost version 2.7.12 or higher.
ynh_remove_nodejs () {
nodejs_version=$(ynh_app_setting_get --app=$app --key=nodejs_version)
@@ -164,6 +172,8 @@ ynh_remove_nodejs () {
# This cron will check and update all minor node versions used by your apps.
#
# usage: ynh_cron_upgrade_node
+#
+# Requires YunoHost version 2.7.12 or higher.
ynh_cron_upgrade_node () {
# Build the update script
cat > "$n_install_dir/node_update.sh" << EOF
diff --git a/data/helpers.d/package b/data/helpers.d/package
index 3924fc14e..75323521d 100644
--- a/data/helpers.d/package
+++ b/data/helpers.d/package
@@ -5,6 +5,8 @@
# [internal]
#
# usage: ynh_wait_dpkg_free
+#
+# Requires YunoHost version 3.3.1 or higher.
ynh_wait_dpkg_free() {
local try
# With seq 1 17, timeout will be almost 30 minutes
@@ -44,6 +46,8 @@ ynh_wait_dpkg_free() {
#
# usage: ynh_package_is_installed --package=name
# | arg: -p, --package - the package name to check
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_package_is_installed() {
# Declare an array to define the options of this helper.
local legacy_args=p
@@ -64,6 +68,8 @@ ynh_package_is_installed() {
# usage: ynh_package_version --package=name
# | arg: -p, --package - the package name to get version
# | ret: the version or an empty string
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_package_version() {
# Declare an array to define the options of this helper.
local legacy_args=p
@@ -84,6 +90,8 @@ ynh_package_version() {
# [internal]
#
# usage: ynh_apt update
+#
+# Requires YunoHost version 2.4.0.3 or higher.
ynh_apt() {
ynh_wait_dpkg_free
DEBIAN_FRONTEND=noninteractive apt-get -y $@
@@ -92,6 +100,8 @@ ynh_apt() {
# Update package index files
#
# usage: ynh_package_update
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_package_update() {
ynh_apt update
}
@@ -100,6 +110,8 @@ ynh_package_update() {
#
# usage: ynh_package_install name [name [...]]
# | arg: name - the package name to install
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_package_install() {
ynh_apt --no-remove -o Dpkg::Options::=--force-confdef \
-o Dpkg::Options::=--force-confold install $@
@@ -109,6 +121,8 @@ ynh_package_install() {
#
# usage: ynh_package_remove name [name [...]]
# | arg: name - the package name to remove
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_package_remove() {
ynh_apt remove $@
}
@@ -117,6 +131,8 @@ ynh_package_remove() {
#
# usage: ynh_package_autoremove name [name [...]]
# | arg: name - the package name to remove
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_package_autoremove() {
ynh_apt autoremove $@
}
@@ -125,6 +141,8 @@ ynh_package_autoremove() {
#
# usage: ynh_package_autopurge name [name [...]]
# | arg: name - the package name to autoremove and purge
+#
+# Requires YunoHost version 2.7.2 or higher.
ynh_package_autopurge() {
ynh_apt autoremove --purge $@
}
@@ -139,6 +157,8 @@ ynh_package_autopurge() {
#
# usage: ynh_package_install_from_equivs controlfile
# | arg: controlfile - path of the equivs control file
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_package_install_from_equivs () {
local controlfile=$1
@@ -181,6 +201,8 @@ ynh_package_install_from_equivs () {
# You can give a choice between some package with this syntax : "dep1|dep2"
# Example : ynh_install_app_dependencies dep1 dep2 "dep3|dep4|dep5"
# This mean in the dependence tree : dep1 & dep2 & (dep3 | dep4 | dep5)
+#
+# Requires YunoHost version 2.6.4 or higher.
ynh_install_app_dependencies () {
local dependencies=$@
local dependencies=${dependencies// /, }
@@ -217,6 +239,8 @@ EOF
# Dependencies will removed only if no other package need them.
#
# usage: ynh_remove_app_dependencies
+#
+# Requires YunoHost version 2.6.4 or higher.
ynh_remove_app_dependencies () {
local dep_app=${app//_/-} # Replace all '_' by '-'
ynh_package_autopurge ${dep_app}-ynh-deps # Remove the fake package and its dependencies if they not still used.
diff --git a/data/helpers.d/print b/data/helpers.d/print
index 7f37021ae..6e7b2b1d7 100644
--- a/data/helpers.d/print
+++ b/data/helpers.d/print
@@ -2,6 +2,8 @@
# Print a message to stderr and exit
# usage: ynh_die --message=MSG [--ret_code=RETCODE]
+#
+# Requires YunoHost version 2.4.0 or higher.
ynh_die() {
# Declare an array to define the options of this helper.
local legacy_args=mc
@@ -18,6 +20,8 @@ ynh_die() {
# Display a message in the 'INFO' logging category
#
# usage: ynh_print_info --message="Some message"
+#
+# Requires YunoHost version 3.2.0 or higher.
ynh_print_info() {
# Declare an array to define the options of this helper.
local legacy_args=m
@@ -37,6 +41,8 @@ ynh_print_info() {
#
# Simply duplicate the log, execute the yunohost command and replace the log without the result of this command
# It's a very badly hack...
+#
+# Requires YunoHost version 2.6.4 or higher.
ynh_no_log() {
local ynh_cli_log=/var/log/yunohost/yunohost-cli.log
sudo cp -a ${ynh_cli_log} ${ynh_cli_log}-move
@@ -50,6 +56,7 @@ ynh_no_log() {
#
# [internal]
#
+# Requires YunoHost version 3.2.0 or higher.
ynh_print_log () {
echo -e "${1}"
}
@@ -58,6 +65,8 @@ ynh_print_log () {
#
# usage: ynh_print_warn --message="Text to print"
# | arg: -m, --message - The text to print
+#
+# Requires YunoHost version 3.2.0 or higher.
ynh_print_warn () {
# Declare an array to define the options of this helper.
local legacy_args=m
@@ -73,6 +82,8 @@ ynh_print_warn () {
#
# usage: ynh_print_err --message="Text to print"
# | arg: -m, --message - The text to print
+#
+# Requires YunoHost version 3.2.0 or higher.
ynh_print_err () {
# Declare an array to define the options of this helper.
local legacy_args=m
@@ -91,6 +102,8 @@ ynh_print_err () {
# In case of use of pipes, you have to use double quotes. Otherwise, this helper will be executed with the first command, then be sent to the next pipe.
#
# | arg: command - command to execute
+#
+# Requires YunoHost version 3.2.0 or higher.
ynh_exec_err () {
ynh_print_err "$(eval $@)"
}
@@ -102,6 +115,8 @@ ynh_exec_err () {
# In case of use of pipes, you have to use double quotes. Otherwise, this helper will be executed with the first command, then be sent to the next pipe.
#
# | arg: command - command to execute
+#
+# Requires YunoHost version 3.2.0 or higher.
ynh_exec_warn () {
ynh_print_warn "$(eval $@)"
}
@@ -113,6 +128,8 @@ ynh_exec_warn () {
# In case of use of pipes, you have to use double quotes. Otherwise, this helper will be executed with the first command, then be sent to the next pipe.
#
# | arg: command - command to execute
+#
+# Requires YunoHost version 3.2.0 or higher.
ynh_exec_warn_less () {
eval $@ 2>&1
}
@@ -124,6 +141,8 @@ ynh_exec_warn_less () {
# In case of use of pipes, you have to use double quotes. Otherwise, this helper will be executed with the first command, then be sent to the next pipe.
#
# | arg: command - command to execute
+#
+# Requires YunoHost version 3.2.0 or higher.
ynh_exec_quiet () {
eval $@ > /dev/null
}
@@ -135,6 +154,8 @@ ynh_exec_quiet () {
# In case of use of pipes, you have to use double quotes. Otherwise, this helper will be executed with the first command, then be sent to the next pipe.
#
# | arg: command - command to execute
+#
+# Requires YunoHost version 3.2.0 or higher.
ynh_exec_fully_quiet () {
eval $@ > /dev/null 2>&1
}
@@ -143,6 +164,8 @@ ynh_exec_fully_quiet () {
#
# usage: ynh_print_OFF
# WARNING: You should be careful with this helper, and never forget to use ynh_print_ON as soon as possible to restore the logging.
+#
+# Requires YunoHost version 3.2.0 or higher.
ynh_print_OFF () {
set +x
}
@@ -150,6 +173,8 @@ ynh_print_OFF () {
# Restore the logging after ynh_print_OFF
#
# usage: ynh_print_ON
+#
+# Requires YunoHost version 3.2.0 or higher.
ynh_print_ON () {
set -x
# Print an echo only for the log, to be able to know that ynh_print_ON has been called.
@@ -163,6 +188,8 @@ ynh_print_ON () {
# | arg: -w, --weight= - The weight for this progression. This value is 1 by default. Use a bigger value for a longer part of the script.
# | arg: -t, --time= - Print the execution time since the last call to this helper. Especially usefull to define weights.
# | arg: -l, --last= - Use for the last call of the helper, to fill te progression bar.
+#
+# Requires YunoHost version 3.?.? or higher.
increment_progression=0
previous_weight=0
# Define base_time when the file is sourced
diff --git a/data/helpers.d/psql b/data/helpers.d/psql
index 2ef13482a..70ea58af4 100644
--- a/data/helpers.d/psql
+++ b/data/helpers.d/psql
@@ -2,6 +2,8 @@
# Please always call this script in install and restore scripts
#
# usage: ynh_psql_test_if_first_run
+#
+# Requires YunoHost version 3.?.? or higher.
ynh_psql_test_if_first_run() {
if [ -f /etc/yunohost/psql ];
then
@@ -43,6 +45,8 @@ ynh_psql_test_if_first_run() {
# | arg: user - the user name to connect as
# | arg: pwd - the user password
# | arg: db - the database to connect to
+#
+# Requires YunoHost version 3.?.? or higher.
ynh_psql_connect_as() {
local user="$1"
local pwd="$2"
@@ -54,6 +58,8 @@ ynh_psql_connect_as() {
#
# usage: ynh_psql_execute_as_root sql [db]
# | arg: sql - the SQL command to execute
+#
+# Requires YunoHost version 3.?.? or higher.
ynh_psql_execute_as_root () {
local sql="$1"
sudo --login --user=postgres psql <<< "$sql"
@@ -64,6 +70,8 @@ ynh_psql_execute_as_root () {
# usage: ynh_psql_execute_file_as_root file [db]
# | arg: file - the file containing SQL commands
# | arg: db - the database to connect to
+#
+# Requires YunoHost version 3.?.? or higher.
ynh_psql_execute_file_as_root() {
local file="$1"
local db="$2"
@@ -79,6 +87,8 @@ ynh_psql_execute_file_as_root() {
# | arg: user - Owner of the database
# | arg: name - Name of the database
# | arg: pwd - Password of the database. If not given, a password will be generated
+#
+# Requires YunoHost version 3.?.? or higher.
ynh_psql_setup_db () {
local db_user="$1"
local db_name="$2"
@@ -95,6 +105,8 @@ ynh_psql_setup_db () {
# | arg: db - the database name to create
# | arg: user - the user to grant privilegies
# | arg: pwd - the user password
+#
+# Requires YunoHost version 3.?.? or higher.
ynh_psql_create_db() {
local db="$1"
local user="$2"
@@ -108,6 +120,8 @@ ynh_psql_create_db() {
# usage: ynh_psql_drop_db db
# | arg: db - the database name to drop
# | arg: user - the user to drop
+#
+# Requires YunoHost version 3.?.? or higher.
ynh_psql_remove_db() {
local db="$1"
local user="$2"
@@ -122,6 +136,8 @@ ynh_psql_remove_db() {
# usage: ynh_psql_dump_db db
# | arg: db - the database name to dump
# | ret: the psqldump output
+#
+# Requires YunoHost version 3.?.? or higher.
ynh_psql_dump_db() {
local db="$1"
sudo --login --user=postgres pg_dump "$db"
@@ -132,6 +148,8 @@ ynh_psql_dump_db() {
#
# usage: ynh_psql_create_user user pwd [host]
# | arg: user - the user name to create
+#
+# Requires YunoHost version 3.?.? or higher.
ynh_psql_create_user() {
local user="$1"
local pwd="$2"
@@ -142,6 +160,8 @@ ynh_psql_create_user() {
#
# usage: ynh_psql_drop_user user
# | arg: user - the user name to drop
+#
+# Requires YunoHost version 3.?.? or higher.
ynh_psql_drop_user() {
local user="$1"
sudo --login --user=postgres dropuser "$user"
diff --git a/data/helpers.d/setting b/data/helpers.d/setting
index 6f75f6c80..0c3698061 100644
--- a/data/helpers.d/setting
+++ b/data/helpers.d/setting
@@ -5,6 +5,8 @@
# usage: ynh_app_setting_get --app=app --key=key
# | arg: -a, --app - the application id
# | arg: -k, --key - the setting to get
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_app_setting_get() {
# Declare an array to define the options of this helper.
local legacy_args=ak
@@ -23,6 +25,8 @@ ynh_app_setting_get() {
# | arg: -a, --app - the application id
# | arg: -k, --key - the setting name to set
# | arg: -v, --value - the setting value to set
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_app_setting_set() {
# Declare an array to define the options of this helper.
local legacy_args=akv
@@ -41,6 +45,8 @@ ynh_app_setting_set() {
# usage: ynh_app_setting_delete --app=app --key=key
# | arg: -a, --app - the application id
# | arg: -k, --key - the setting to delete
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_app_setting_delete() {
# Declare an array to define the options of this helper.
local legacy_args=ak
diff --git a/data/helpers.d/string b/data/helpers.d/string
index 739757d43..52eede872 100644
--- a/data/helpers.d/string
+++ b/data/helpers.d/string
@@ -6,6 +6,8 @@
#
# usage: ynh_string_random [--length=string_length]
# | arg: -l, --length - the string length to generate (default: 24)
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_string_random() {
# Declare an array to define the options of this helper.
local legacy_args=l
@@ -30,6 +32,8 @@ ynh_string_random() {
# As this helper is based on sed command, regular expressions and
# references to sub-expressions can be used
# (see sed manual page for more information)
+#
+# Requires YunoHost version 2.6.4 or higher.
ynh_replace_string () {
# Declare an array to define the options of this helper.
local legacy_args=mrf
@@ -57,6 +61,8 @@ ynh_replace_string () {
#
# This helper will use ynh_replace_string, but as you can use special
# characters, you can't use some regular expressions and sub-expressions.
+#
+# Requires YunoHost version 2.7.7 or higher.
ynh_replace_special_string () {
# Declare an array to define the options of this helper.
local legacy_args=mrf
diff --git a/data/helpers.d/system b/data/helpers.d/system
index 9a4219e11..fd5b21435 100644
--- a/data/helpers.d/system
+++ b/data/helpers.d/system
@@ -16,6 +16,7 @@
#
# It prints a warning to inform that the script was failed, and execute the ynh_clean_setup function if used in the app script
#
+# Requires YunoHost version 2.6.4 or higher.
ynh_exit_properly () {
local exit_code=$?
if [ "$exit_code" -eq 0 ]; then
@@ -43,6 +44,7 @@ ynh_exit_properly () {
# immediately and a call to `ynh_clean_setup` is triggered if it has been
# defined by your script.
#
+# Requires YunoHost version 2.6.4 or higher.
ynh_abort_if_errors () {
set -eu # Exit if a command fail, and if a variable is used unset.
trap ynh_exit_properly EXIT # Capturing exit signals on shell script
@@ -52,6 +54,8 @@ ynh_abort_if_errors () {
#
# usage: ynh_get_debian_release
# | ret: The Debian release codename (i.e. jessie, stretch, ...)
+#
+# Requires YunoHost version 2.7.12 or higher.
ynh_get_debian_release () {
echo $(lsb_release --codename --short)
}
@@ -61,6 +65,8 @@ ynh_get_debian_release () {
# usage: ynh_read_manifest manifest key
# | arg: -m, --manifest= - Path of the manifest to read
# | arg: -k, --key= - Name of the key to find
+#
+# Requires YunoHost version 3.?.? or higher.
ynh_read_manifest () {
# Declare an array to define the options of this helper.
declare -Ar args_array=( [m]=manifest= [k]=manifest_key= )
@@ -85,6 +91,8 @@ ynh_read_manifest () {
#
# usage: ynh_app_upstream_version [-m manifest]
# | arg: -m, --manifest= - Path of the manifest to read
+#
+# Requires YunoHost version 3.?.? or higher.
ynh_app_upstream_version () {
declare -Ar args_array=( [m]=manifest= )
local manifest
@@ -104,6 +112,8 @@ ynh_app_upstream_version () {
#
# usage: ynh_app_package_version [-m manifest]
# | arg: -m, --manifest= - Path of the manifest to read
+#
+# Requires YunoHost version 3.?.? or higher.
ynh_app_package_version () {
declare -Ar args_array=( [m]=manifest= )
local manifest
@@ -129,6 +139,8 @@ ynh_app_package_version () {
# example: sudo YNH_FORCE_UPGRADE=1 yunohost app upgrade MyApp
#
# usage: ynh_check_app_version_changed
+#
+# Requires YunoHost version 3.?.? or higher.
ynh_check_app_version_changed () {
local force_upgrade=${YNH_FORCE_UPGRADE:-0}
local package_check=${PACKAGE_CHECK_EXEC:-0}
diff --git a/data/helpers.d/user b/data/helpers.d/user
index d716bf03b..f19739993 100644
--- a/data/helpers.d/user
+++ b/data/helpers.d/user
@@ -6,6 +6,8 @@
#
# usage: ynh_user_exists --username=username
# | arg: -u, --username - the username to check
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_user_exists() {
# Declare an array to define the options of this helper.
local legacy_args=u
@@ -25,6 +27,8 @@ ynh_user_exists() {
# | arg: -u, --username - the username to retrieve info from
# | arg: -k, --key - the key to retrieve
# | ret: string - the key's value
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_user_get_info() {
# Declare an array to define the options of this helper.
local legacy_args=uk
@@ -43,6 +47,8 @@ ynh_user_get_info() {
#
# usage: ynh_user_list
# | ret: string - one username per line
+#
+# Requires YunoHost version 2.4.0 or higher.
ynh_user_list() {
sudo yunohost user list --output-as plain --quiet \
| awk '/^##username$/{getline; print}'
@@ -52,6 +58,8 @@ ynh_user_list() {
#
# usage: ynh_system_user_exists --username=username
# | arg: -u, --username - the username to check
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_system_user_exists() {
# Declare an array to define the options of this helper.
local legacy_args=u
@@ -76,6 +84,8 @@ ynh_system_user_exists() {
# | arg: -h, --home_dir - Path of the home dir for the user. Usually the final path of the app. If this argument is omitted, the user will be created without home
# | arg: -s, --use_shell - Create a user using the default login shell if present.
# If this argument is omitted, the user will be created with /usr/sbin/nologin shell
+#
+# Requires YunoHost version 2.6.4 or higher.
ynh_system_user_create () {
# Declare an array to define the options of this helper.
local legacy_args=uhs
@@ -108,6 +118,8 @@ ynh_system_user_create () {
#
# usage: ynh_system_user_delete --username=user_name
# | arg: -u, --username - Name of the system user that will be create
+#
+# Requires YunoHost version 2.6.4 or higher.
ynh_system_user_delete () {
# Declare an array to define the options of this helper.
local legacy_args=u
diff --git a/data/helpers.d/utils b/data/helpers.d/utils
index 5ba2946a2..5f5e61015 100644
--- a/data/helpers.d/utils
+++ b/data/helpers.d/utils
@@ -6,6 +6,8 @@
#
# usage: ynh_get_plain_key key [subkey [subsubkey ...]]
# | ret: string - the key's value
+#
+# Requires YunoHost version 2.2.4 or higher.
ynh_get_plain_key() {
local prefix="#"
local founded=0
@@ -36,6 +38,7 @@ ynh_get_plain_key() {
# }
# ynh_abort_if_errors
#
+# Requires YunoHost version 2.7.2 or higher.
ynh_restore_upgradebackup () {
echo "Upgrade failed." >&2
local app_bck=${app//_/-} # Replace all '_' by '-'
@@ -67,6 +70,7 @@ ynh_restore_upgradebackup () {
# }
# ynh_abort_if_errors
#
+# Requires YunoHost version 2.7.2 or higher.
ynh_backup_before_upgrade () {
if [ ! -e "/etc/yunohost/apps/$app/scripts/backup" ]
then
@@ -150,6 +154,8 @@ ynh_backup_before_upgrade () {
# usage: ynh_setup_source --dest_dir=dest_dir [--source_id=source_id]
# | arg: -d, --dest_dir - Directory where to setup sources
# | arg: -s, --source_id - Name of the app, if the package contains more than one app
+#
+# Requires YunoHost version 2.6.4 or higher.
ynh_setup_source () {
# Declare an array to define the options of this helper.
local legacy_args=ds
@@ -255,6 +261,8 @@ ynh_setup_source () {
# | arg: key1=value1 - (Optionnal) POST key and corresponding value
# | arg: key2=value2 - (Optionnal) Another POST key and corresponding value
# | arg: ... - (Optionnal) More POST keys and values
+#
+# Requires YunoHost version 2.6.4 or higher.
ynh_local_curl () {
# Define url of page to curl
local local_page=$(ynh_normalize_url_path $1)
From 2703d5aa66d020460a187985be146f2484fb25e9 Mon Sep 17 00:00:00 2001
From: Maniack Crudelis
Date: Tue, 26 Feb 2019 00:07:53 +0100
Subject: [PATCH 036/180] Use apps.json as default list
---
src/yunohost/tools.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py
index a011b1546..11d90dd09 100644
--- a/src/yunohost/tools.py
+++ b/src/yunohost/tools.py
@@ -415,10 +415,10 @@ def tools_postinstall(operation_logger, domain, password, ignore_dyndns=False,
# Enable UPnP silently and reload firewall
firewall_upnp('enable', no_refresh=True)
- # Setup the default official app list with cron job
+ # Setup the default apps list with cron job
try:
app_fetchlist(name="yunohost",
- url="https://app.yunohost.org/official.json")
+ url="https://app.yunohost.org/apps.json")
except Exception as e:
logger.warning(str(e))
From 5d9a62192f02cd27ac3dc0ed93fbd8edcfaced63 Mon Sep 17 00:00:00 2001
From: Maniack Crudelis
Date: Tue, 26 Feb 2019 01:32:52 +0100
Subject: [PATCH 037/180] Migrate to apps.json
---
.../0009_migrate_to_apps_json.py | 27 +++++++++++++++++++
1 file changed, 27 insertions(+)
create mode 100644 src/yunohost/data_migrations/0009_migrate_to_apps_json.py
diff --git a/src/yunohost/data_migrations/0009_migrate_to_apps_json.py b/src/yunohost/data_migrations/0009_migrate_to_apps_json.py
new file mode 100644
index 000000000..364497b46
--- /dev/null
+++ b/src/yunohost/data_migrations/0009_migrate_to_apps_json.py
@@ -0,0 +1,27 @@
+from moulinette.utils.log import getActionLogger
+from yunohost.app import app_fetchlist, app_removelist
+from yunohost.tools import Migration
+
+logger = getActionLogger('yunohost.migration')
+
+class MyMigration(Migration):
+
+ "Migrate from official.json to apps.json"
+
+ def migrate(self):
+
+ # Remove official.json list
+ app_removelist(name="yunohost")
+
+ # Replace by apps.json list
+ app_fetchlist(name="yunohost",
+ url="https://app.yunohost.org/apps.json")
+
+ def backward(self):
+
+ # Remove apps.json list
+ app_removelist(name="yunohost")
+
+ # Replace by official.json list
+ app_fetchlist(name="yunohost",
+ url="https://app.yunohost.org/official.json")
From e81e232fb216fb2f88cb381b42166bacea245b6e Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Mon, 4 Mar 2019 03:09:23 +0100
Subject: [PATCH 038/180] Add a check that some required services are up before
running install and upgrade
---
locales/en.json | 1 +
src/yunohost/app.py | 29 ++++++++++++++++++++++++++++-
2 files changed, 29 insertions(+), 1 deletion(-)
diff --git a/locales/en.json b/locales/en.json
index 1157e0a54..f10542951 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -4,6 +4,7 @@
"admin_password": "Administration password",
"admin_password_change_failed": "Unable to change password",
"admin_password_changed": "The administration password has been changed",
+ "app_action_cannot_be_ran_because_required_services_down": "This app requires some services which are currently down. Before continuing, you should try to restart the following services (and possibly investigate why they are down) : {services}",
"app_already_installed": "{app:s} is already installed",
"app_already_installed_cant_change_url": "This app is already installed. The url cannot be changed just by this function. Look into `app changeurl` if it's available.",
"app_already_up_to_date": "{app:s} is already up to date",
diff --git a/src/yunohost/app.py b/src/yunohost/app.py
index be0bb5a55..4997727e3 100644
--- a/src/yunohost/app.py
+++ b/src/yunohost/app.py
@@ -42,7 +42,7 @@ from yunohost.utils.error import YunohostError
from moulinette.utils.log import getActionLogger
from moulinette.utils.filesystem import read_json
-from yunohost.service import service_log, _run_service_command
+from yunohost.service import service_log, service_status, _run_service_command
from yunohost.utils import packages
from yunohost.log import is_unit_operation, OperationLogger
@@ -623,6 +623,7 @@ def app_upgrade(auth, app=[], url=None, file=None):
# Check requirements
_check_manifest_requirements(manifest, app_instance_name=app_instance_name)
+ _check_services_status_for_app(manifest.get("services", []))
app_setting_path = APPS_SETTING_PATH + '/' + app_instance_name
@@ -778,6 +779,7 @@ def app_install(operation_logger, auth, app, label=None, args=None, no_remove_on
# Check requirements
_check_manifest_requirements(manifest, app_id)
+ _check_services_status_for_app(manifest.get("services", []))
# Check if app can be forked
instance_number = _installed_instance_number(app_id, last=True) + 1
@@ -2574,6 +2576,31 @@ def unstable_apps():
return output
+def _check_services_status_for_app(services):
+
+ logger.debug("Checking that required services are up and running...")
+
+ # Some apps use php-fpm or php5-fpm which is now php7.0-fpm
+ def replace_alias(service):
+ if service in ["php-fpm", "php5-fpm"]:
+ return "php7.0-fpm"
+ else:
+ return service
+ services = [replace_alias(s) for s in services]
+
+ # We only check those, mostly to ignore "custom" services
+ # (added by apps) and because those are the most popular
+ # services
+ service_filter = ["nginx", "php7.0-fpm", "mysql", "postfix"]
+ services = [s for s in services if s in service_filter]
+
+ # List services currently down and raise an exception if any are found
+ faulty_services = [s for s, infos in service_status(services).items() if infos["active"] != "active"]
+ if faulty_services:
+ raise YunohostError('app_action_cannot_be_ran_because_required_services_down',
+ services=', '.join(faulty_services))
+
+
def _patch_php5(app_folder):
files_to_patch = []
From ea8605db5ccab33c7ce64cb7ec92a4283471b46a Mon Sep 17 00:00:00 2001
From: Maniack Crudelis
Date: Fri, 8 Mar 2019 23:32:23 +0100
Subject: [PATCH 039/180] [enh] Support php versions in ynh_add_fpm_config
---
data/helpers.d/backend | 17 ++++++++++++++---
1 file changed, 14 insertions(+), 3 deletions(-)
diff --git a/data/helpers.d/backend b/data/helpers.d/backend
index 1532601a8..fbebf278a 100644
--- a/data/helpers.d/backend
+++ b/data/helpers.d/backend
@@ -240,11 +240,21 @@ ynh_remove_nginx_config () {
# Create a dedicated php-fpm config
#
-# usage: ynh_add_fpm_config
+# usage: ynh_add_fpm_config [--phpversion=7.X]
+# | arg: -v, --phpversion - Version of php to use.
ynh_add_fpm_config () {
+ # Declare an array to define the options of this helper.
+ local legacy_args=v
+ declare -Ar args_array=( [v]=phpversion= )
+ local phpversion
+ # Manage arguments with getopts
+ ynh_handle_getopts_args "$@"
+
# Configure PHP-FPM 7.0 by default
- local fpm_config_dir="/etc/php/7.0/fpm"
- local fpm_service="php7.0-fpm"
+ phpversion="${phpversion:-7.0}"
+
+ local fpm_config_dir="/etc/php/$phpversion/fpm"
+ local fpm_service="php${phpversion}-fpm"
# Configure PHP-FPM 5 on Debian Jessie
if [ "$(ynh_get_debian_release)" == "jessie" ]; then
fpm_config_dir="/etc/php5/fpm"
@@ -258,6 +268,7 @@ ynh_add_fpm_config () {
ynh_replace_string --match_string="__NAMETOCHANGE__" --replace_string="$app" --target_file="$finalphpconf"
ynh_replace_string --match_string="__FINALPATH__" --replace_string="$final_path" --target_file="$finalphpconf"
ynh_replace_string --match_string="__USER__" --replace_string="$app" --target_file="$finalphpconf"
+ ynh_replace_string --match_string="__PHPVERSION__" --replace_string="$phpversion" --target_file="$finalphpconf"
sudo chown root: "$finalphpconf"
ynh_store_file_checksum --file="$finalphpconf"
From 3550be63f2e5cb556a0c080ca58b62836f052d84 Mon Sep 17 00:00:00 2001
From: Christophe Vuillot
Date: Mon, 11 Mar 2019 14:53:40 +0100
Subject: [PATCH 040/180] Added a python script (yunohost_completion.py) which
generates a bash completion file for the yunohost command based on
yunohost.yml, in data/actionsmap
Added the output of the script in data/bash-completion.d/yunohost_completion
This is probably not the correct place for the script and the generation should
be done at some other time and place also.
---
data/actionsmap/yunohost_completion.py | 84 ++++++++++++++++++++++
data/bash-completion.d/yunohost_completion | 77 ++++++++++++++++++++
2 files changed, 161 insertions(+)
create mode 100644 data/actionsmap/yunohost_completion.py
create mode 100644 data/bash-completion.d/yunohost_completion
diff --git a/data/actionsmap/yunohost_completion.py b/data/actionsmap/yunohost_completion.py
new file mode 100644
index 000000000..9b5472837
--- /dev/null
+++ b/data/actionsmap/yunohost_completion.py
@@ -0,0 +1,84 @@
+"""
+Simple automated generation of a bash_completion file
+for yunohost command from the actionsmap.
+
+Generates a bash completion file assuming the structure
+`yunohost domain action`
+adds `--help` at the end if one presses [tab] again.
+
+author: Christophe Vuillot
+"""
+import yaml
+
+ACTIONSMAP_FILE = 'yunohost.yml'
+BASH_COMPLETION_FILE = '../bash-completion.d/yunohost_completion'
+
+with open(ACTIONSMAP_FILE, 'r') as stream:
+
+ # Getting the dictionary containning what actions are possible per domain
+ OPTION_TREE = yaml.load(stream)
+ DOMAINS = [str for str in OPTION_TREE.keys() if not str.startswith('_')]
+ DOMAINS_STR = '"{}"'.format(' '.join(DOMAINS))
+ ACTIONS_DICT = {}
+ for domain in DOMAINS:
+ ACTIONS = [str for str in OPTION_TREE[domain]['actions'].keys()
+ if not str.startswith('_')]
+ ACTIONS_STR = '"{}"'.format(' '.join(ACTIONS))
+ ACTIONS_DICT[domain] = ACTIONS_STR
+
+ with open(BASH_COMPLETION_FILE, 'w') as generated_file:
+
+ # header of the file
+ generated_file.write('#\n')
+ generated_file.write('# completion for yunohost\n')
+ generated_file.write('# automatically generated from the actionsmap\n')
+ generated_file.write('#\n\n')
+
+ # Start of the completion function
+ generated_file.write('_yunohost_completion()\n')
+ generated_file.write('{\n')
+
+ # Defining local variable for previously and currently typed words
+ generated_file.write('\tlocal cur prev opts narg\n')
+ generated_file.write('\tCOMPREPLY=()\n\n')
+ generated_file.write('\t# the number of words already typed\n')
+ generated_file.write('\tnarg=${#COMP_WORDS[@]}\n\n')
+ generated_file.write('\t# the current word being typed\n')
+ generated_file.write('\tcur="${COMP_WORDS[COMP_CWORD]}"\n\n')
+ generated_file.write('\t# the last typed word\n')
+ generated_file.write('\tprev="${COMP_WORDS[COMP_CWORD-1]}"\n\n')
+
+ # If one is currently typing a domain then match with the domain list
+ generated_file.write('\t# If one is currently typing a domain,\n')
+ generated_file.write('\t# match with domains\n')
+ generated_file.write('\tif [[ $narg == 2 ]]; then\n')
+ generated_file.write('\t\topts={}\n'.format(DOMAINS_STR))
+ generated_file.write('\tfi\n\n')
+
+ # If one is currently typing an action then match with the action list
+ # of the previously typed domain
+ generated_file.write('\t# If one already typed a domain,\n')
+ generated_file.write('\t# match the actions of that domain\n')
+ generated_file.write('\tif [[ $narg == 3 ]]; then\n')
+ for domain in DOMAINS:
+ generated_file.write('\t\tif [[ $prev == "{}" ]]; then\n'.format(domain))
+ generated_file.write('\t\t\topts={}\n'.format(ACTIONS_DICT[domain]))
+ generated_file.write('\t\tfi\n')
+ generated_file.write('\tfi\n\n')
+
+ # If both domain and action have been typed or the domain
+ # was not recognized propose --help (only once)
+ generated_file.write('\t# If no options were found propose --help\n')
+ generated_file.write('\tif [ -z "$opts" ]; then\n')
+ generated_file.write('\t\tif [[ $prev != "--help" ]]; then\n')
+ generated_file.write('\t\t\topts=( --help )\n')
+ generated_file.write('\t\tfi\n')
+ generated_file.write('\tfi\n')
+
+ # generate the completion list from the possible options
+ generated_file.write('\tCOMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )\n')
+ generated_file.write('\treturn 0\n')
+ generated_file.write('}\n\n')
+
+ # Add the function to bash completion
+ generated_file.write('complete -F _yunohost_completion yunohost')
diff --git a/data/bash-completion.d/yunohost_completion b/data/bash-completion.d/yunohost_completion
new file mode 100644
index 000000000..715073475
--- /dev/null
+++ b/data/bash-completion.d/yunohost_completion
@@ -0,0 +1,77 @@
+#
+# completion for yunohost
+# automatically generated from the actionsmap
+#
+
+_yunohost_completion()
+{
+ local cur prev opts narg
+ COMPREPLY=()
+
+ # the number of words already typed
+ narg=${#COMP_WORDS[@]}
+
+ # the current word being typed
+ cur="${COMP_WORDS[COMP_CWORD]}"
+
+ # the last typed word
+ prev="${COMP_WORDS[COMP_CWORD-1]}"
+
+ # If one is currently typing a domain,
+ # match with domains
+ if [[ $narg == 2 ]]; then
+ opts="user domain log service settings firewall backup app hook dyndns tools monitor"
+ fi
+
+ # If one already typed a domain,
+ # match the actions of that domain
+ if [[ $narg == 3 ]]; then
+ if [[ $prev == "user" ]]; then
+ opts="info create list update delete"
+ fi
+ if [[ $prev == "domain" ]]; then
+ opts="cert-install cert-status list remove url-available add dns-conf cert-renew"
+ fi
+ if [[ $prev == "log" ]]; then
+ opts="list display"
+ fi
+ if [[ $prev == "service" ]]; then
+ opts="status enable reload_or_restart log start stop remove reload add disable regen-conf restart"
+ fi
+ if [[ $prev == "settings" ]]; then
+ opts="reset set list reset-all get"
+ fi
+ if [[ $prev == "firewall" ]]; then
+ opts="reload allow stop list upnp disallow"
+ fi
+ if [[ $prev == "backup" ]]; then
+ opts="info restore create list delete"
+ fi
+ if [[ $prev == "app" ]]; then
+ opts="map checkurl install makedefault checkport listlists change-url removelist info change-label upgrade fetchlist clearaccess ssowatconf list remove register-url removeaccess setting initdb debug addaccess"
+ fi
+ if [[ $prev == "hook" ]]; then
+ opts="info callback add exec list remove"
+ fi
+ if [[ $prev == "dyndns" ]]; then
+ opts="subscribe update installcron removecron"
+ fi
+ if [[ $prev == "tools" ]]; then
+ opts="upgrade ldapinit postinstall maindomain update reboot shell adminpw shutdown diagnosis port-available"
+ fi
+ if [[ $prev == "monitor" ]]; then
+ opts="enable network show-stats update-stats disk system disable"
+ fi
+ fi
+
+ # If no options were found propose --help
+ if [ -z "$opts" ]; then
+ if [[ $prev != "--help" ]]; then
+ opts=( --help )
+ fi
+ fi
+ COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
+ return 0
+}
+
+complete -F _yunohost_completion yunohost
\ No newline at end of file
From 23d7a0005d6f7c17825473b50bd04bf89181aaa1 Mon Sep 17 00:00:00 2001
From: Maniack Crudelis
Date: Sat, 16 Mar 2019 16:05:32 +0100
Subject: [PATCH 041/180] Escape $ in getopts
---
data/helpers.d/getopts | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/data/helpers.d/getopts b/data/helpers.d/getopts
index 7055325f1..891fdaaeb 100644
--- a/data/helpers.d/getopts
+++ b/data/helpers.d/getopts
@@ -152,6 +152,8 @@ ynh_handle_getopts_args () {
fi
# Escape double quote to prevent any interpretation during the eval
all_args[$i]="${all_args[$i]//\"/\\\"}"
+ # Escape $ as well to prevent the string following it to be seen as a variable.
+ all_args[$i]="${all_args[$i]//$/\\\$}"
eval ${option_var}+=\"${all_args[$i]}\"
shift_value=$(( shift_value + 1 ))
@@ -193,6 +195,8 @@ ynh_handle_getopts_args () {
# Escape double quote to prevent any interpretation during the eval
arguments[$i]="${arguments[$i]//\"/\\\"}"
+ # Escape $ as well to prevent the string following it to be seen as a variable.
+ all_args[$i]="${all_args[$i]//$/\\\$}"
# Store each value given as argument in the corresponding variable
# The values will be stored in the same order than $args_array
From ad748a75f62490386c7ca97b92191d3ee2d3fa0d Mon Sep 17 00:00:00 2001
From: Maniack Crudelis
Date: Sat, 16 Mar 2019 16:15:54 +0100
Subject: [PATCH 042/180] eval is useful and working before being evil...
---
data/helpers.d/getopts | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/data/helpers.d/getopts b/data/helpers.d/getopts
index 891fdaaeb..90db671c4 100644
--- a/data/helpers.d/getopts
+++ b/data/helpers.d/getopts
@@ -155,6 +155,13 @@ ynh_handle_getopts_args () {
# Escape $ as well to prevent the string following it to be seen as a variable.
all_args[$i]="${all_args[$i]//$/\\\$}"
+ # For the record.
+ # We're using eval here to get the content of the variable stored itself as simple text in $option_var...
+ # Other ways to get that content would be to use either ${!option_var} or declare -g ${option_var}
+ # But... ${!option_var} can't be used as left part of an assignation.
+ # declare -g ${option_var} will create a local variable (despite -g !) and will not be available for the helper itself.
+ # So... Stop fucking arguing each time that eval is evil... Go find an other working solution if you can find one!
+
eval ${option_var}+=\"${all_args[$i]}\"
shift_value=$(( shift_value + 1 ))
fi
From 652edc204cbf9fbcd7fc9d273d429dc05a0eef7f Mon Sep 17 00:00:00 2001
From: Maniack Crudelis
Date: Sat, 16 Mar 2019 16:53:07 +0100
Subject: [PATCH 043/180] Syntax fix
---
data/helpers.d/getopts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/data/helpers.d/getopts b/data/helpers.d/getopts
index 90db671c4..70d4a13d3 100644
--- a/data/helpers.d/getopts
+++ b/data/helpers.d/getopts
@@ -203,7 +203,7 @@ ynh_handle_getopts_args () {
# Escape double quote to prevent any interpretation during the eval
arguments[$i]="${arguments[$i]//\"/\\\"}"
# Escape $ as well to prevent the string following it to be seen as a variable.
- all_args[$i]="${all_args[$i]//$/\\\$}"
+ arguments[$i]="${arguments[$i]//$/\\\$}"
# Store each value given as argument in the corresponding variable
# The values will be stored in the same order than $args_array
From 18e7be1bc1459cbc6a5f3e234c56214005fee6d4 Mon Sep 17 00:00:00 2001
From: Maniack Crudelis
Date: Mon, 18 Mar 2019 07:57:28 +0100
Subject: [PATCH 044/180] Update psql
---
data/helpers.d/psql | 1 +
1 file changed, 1 insertion(+)
diff --git a/data/helpers.d/psql b/data/helpers.d/psql
index a9ea5dadc..2212d692a 100644
--- a/data/helpers.d/psql
+++ b/data/helpers.d/psql
@@ -134,6 +134,7 @@ ynh_psql_dump_db() {
#
# usage: ynh_psql_create_user user pwd
# | arg: user - the user name to create
+# | arg: pwd - the password to identify user by
#
# Requires YunoHost version 3.?.? or higher.
ynh_psql_create_user() {
From 3af3c2b77950b4a93c7c806d061372859674657b Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Mon, 18 Mar 2019 19:37:52 +0100
Subject: [PATCH 045/180] Directly inject standard css + custom css and js
---
data/templates/nginx/plain/yunohost_panel.conf.inc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/data/templates/nginx/plain/yunohost_panel.conf.inc b/data/templates/nginx/plain/yunohost_panel.conf.inc
index 34afe136d..61f0af613 100644
--- a/data/templates/nginx/plain/yunohost_panel.conf.inc
+++ b/data/templates/nginx/plain/yunohost_panel.conf.inc
@@ -1,5 +1,5 @@
# Insert YunoHost panel
-sub_filter '';
+sub_filter '';
sub_filter_once on;
# Apply to other mime types than text/html
sub_filter_types application/xhtml+xml;
From b99b22bb03bc9b1cd1e53e4491af592bcf31573a Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Tue, 19 Mar 2019 01:17:45 +0100
Subject: [PATCH 046/180] Propagate file renaming for semantic
---
data/templates/nginx/plain/yunohost_panel.conf.inc | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/data/templates/nginx/plain/yunohost_panel.conf.inc b/data/templates/nginx/plain/yunohost_panel.conf.inc
index 61f0af613..d159c29f9 100644
--- a/data/templates/nginx/plain/yunohost_panel.conf.inc
+++ b/data/templates/nginx/plain/yunohost_panel.conf.inc
@@ -1,8 +1,8 @@
-# Insert YunoHost panel
-sub_filter '';
+# Insert YunoHost button + portal overlay
+sub_filter '';
sub_filter_once on;
# Apply to other mime types than text/html
sub_filter_types application/xhtml+xml;
# Prevent YunoHost panel files from being blocked by specific app rules
-location ~ ynhpanel\.(js|json|css) {
+location ~ (ynh_portal.js|ynh_overlay.css) {
}
From de7a66ff0e76f21463f22ee151530dbb4f0d7bcb Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Fri, 22 Mar 2019 01:14:45 +0100
Subject: [PATCH 047/180] Rework system-part of tools_update...
---
src/yunohost/tools.py | 51 ++++++++++++++++++++++++++++++++++---------
1 file changed, 41 insertions(+), 10 deletions(-)
diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py
index a011b1546..482d9305b 100644
--- a/src/yunohost/tools.py
+++ b/src/yunohost/tools.py
@@ -41,7 +41,7 @@ from moulinette import msettings, msignals, m18n
from moulinette.core import init_authenticator
from yunohost.utils.error import YunohostError
from moulinette.utils.log import getActionLogger
-from moulinette.utils.process import check_output
+from moulinette.utils.process import check_output, call_async_output
from moulinette.utils.filesystem import read_json, write_to_json
from yunohost.app import app_fetchlist, app_info, app_upgrade, app_ssowatconf, app_list, _install_appslist_fetch_cron
from yunohost.domain import domain_add, domain_list, _get_maindomain, _set_maindomain
@@ -469,23 +469,54 @@ def tools_update(ignore_apps=False, ignore_packages=False):
# "packages" will list upgradable packages
packages = []
if not ignore_packages:
- cache = apt.Cache()
# Update APT cache
+ # LC_ALL=C is here to make sure the results are in english
+ command = "LC_ALL=C apt update"
+ # TODO : add @is_unit_operation to tools_update so that the
+ # debug output can be fetched when there's an issue...
+ callbacks = (
+ # stdout goes to debug
+ lambda l: logger.debug(l.rstrip()),
+ # stderr goes to warning
+ # FIXME : filter the damn "CLI interface not stable" from apt >.>
+ lambda l: logger.warning(l.rstrip()),
+ )
+
logger.info(m18n.n('updating_apt_cache'))
- if not cache.update():
+
+ returncode = call_async_output(command, callbacks, shell=True)
+
+ if returncode != 0:
+
+ # TODO : here, we should run something like a
+ # `cat /etc/apt/sources.list /etc/apt/sources.list.d/*`
+ # and append it to the error message to improve debugging
+
raise YunohostError('update_cache_failed')
- cache.open(None)
- cache.upgrade(True)
+ # 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")
- # Add changelogs to the result
- for pkg in cache.get_changes():
+ # Dirty parsing of the output
+ upgradable_raw = [l.strip() for l in upgradable_raw.split("\n") if l.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
+ # line should look like :
+ # yunohost/stable 3.5.0.2+201903211853 all [upgradable from: 3.4.2.4+201903080053]
+ line = line.split()
+ if len(line) != 6:
+ logger.warning("Failed to parse this line : %s" % ' '.join(line))
+ continue
packages.append({
- 'name': pkg.name,
- 'fullname': pkg.fullname,
- 'changelog': pkg.get_changelog()
+ "name": line[0].split("/")[0],
+ "new_version": line[1],
+ "current_version": line[5].strip("]"),
})
+
logger.debug(m18n.n('done'))
# "apps" will list upgradable packages
From 51fe6fea277e337732e47239158e68d01a1617b9 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Fri, 22 Mar 2019 04:01:08 +0100
Subject: [PATCH 048/180] Factorize function to list upgradable packages
---
src/yunohost/tools.py | 50 ++++++++++++++++++++++++-------------------
1 file changed, 28 insertions(+), 22 deletions(-)
diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py
index 482d9305b..93e3dd177 100644
--- a/src/yunohost/tools.py
+++ b/src/yunohost/tools.py
@@ -495,28 +495,7 @@ def tools_update(ignore_apps=False, ignore_packages=False):
raise YunohostError('update_cache_failed')
- # 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")
-
- # Dirty parsing of the output
- upgradable_raw = [l.strip() for l in upgradable_raw.split("\n") if l.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
- # line should look like :
- # yunohost/stable 3.5.0.2+201903211853 all [upgradable from: 3.4.2.4+201903080053]
- line = line.split()
- if len(line) != 6:
- logger.warning("Failed to parse this line : %s" % ' '.join(line))
- continue
- packages.append({
- "name": line[0].split("/")[0],
- "new_version": line[1],
- "current_version": line[5].strip("]"),
- })
-
+ packages = list(_list_upgradable_apt_packages())
logger.debug(m18n.n('done'))
# "apps" will list upgradable packages
@@ -545,6 +524,33 @@ def tools_update(ignore_apps=False, ignore_packages=False):
return {'packages': packages, 'apps': apps}
+# TODO : move this to utils/packages.py ?
+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")
+
+ # Dirty parsing of the output
+ upgradable_raw = [l.strip() for l in upgradable_raw.split("\n") if l.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
+ # line should look like :
+ # yunohost/stable 3.5.0.2+201903211853 all [upgradable from: 3.4.2.4+201903080053]
+ line = line.split()
+ if len(line) != 6:
+ logger.warning("Failed to parse this line : %s" % ' '.join(line))
+ continue
+
+ yield {
+ "name": line[0].split("/")[0],
+ "new_version": line[1],
+ "current_version": line[5].strip("]"),
+ }
+
+
@is_unit_operation()
def tools_upgrade(operation_logger, auth, ignore_apps=False, ignore_packages=False):
"""
From 096c2a7d7bfa6030206078bc9c19ec2e9305b9c7 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Fri, 22 Mar 2019 04:02:38 +0100
Subject: [PATCH 049/180] Rework system-part of tools_upgrade...
---
src/yunohost/tools.py | 170 +++++++++++++++++++++++++++++-------------
1 file changed, 119 insertions(+), 51 deletions(-)
diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py
index 93e3dd177..589e49a3f 100644
--- a/src/yunohost/tools.py
+++ b/src/yunohost/tools.py
@@ -33,6 +33,7 @@ import socket
from xmlrpclib import Fault
from importlib import import_module
from collections import OrderedDict
+from datetime import datetime
import apt
import apt.progress
@@ -567,61 +568,127 @@ def tools_upgrade(operation_logger, auth, ignore_apps=False, ignore_packages=Fal
failure = False
- # Retrieve interface
- is_api = True if msettings.get('interface') == 'api' else False
-
if not ignore_packages:
- apt.apt_pkg.init()
- apt.apt_pkg.config.set("DPkg::Options::", "--force-confdef")
- apt.apt_pkg.config.set("DPkg::Options::", "--force-confold")
-
- cache = apt.Cache()
- cache.open(None)
- cache.upgrade(True)
-
- # If API call
- if is_api:
- critical_packages = ("moulinette", "yunohost",
- "yunohost-admin", "ssowat", "python")
- critical_upgrades = set()
-
- for pkg in cache.get_changes():
- if pkg.name in critical_packages:
- critical_upgrades.add(pkg.name)
- # Temporarily keep package ...
- pkg.mark_keep()
-
- # ... and set a hourly cron up to upgrade critical packages
- if critical_upgrades:
- logger.info(m18n.n('packages_upgrade_critical_later',
- packages=', '.join(critical_upgrades)))
- with open('/etc/cron.d/yunohost-upgrade', 'w+') as f:
- f.write('00 * * * * root PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin apt-get install %s -y && rm -f /etc/cron.d/yunohost-upgrade\n' % ' '.join(critical_upgrades))
-
- if cache.get_changes():
- logger.info(m18n.n('upgrading_packages'))
-
- operation_logger.start()
- try:
- os.environ["DEBIAN_FRONTEND"] = "noninteractive"
- # Apply APT changes
- # TODO: Logs output for the API
- cache.commit(apt.progress.text.AcquireProgress(),
- apt.progress.base.InstallProgress())
- except Exception as e:
- failure = True
- logger.warning('unable to upgrade packages: %s' % str(e))
- logger.error(m18n.n('packages_upgrade_failed'))
- operation_logger.error(m18n.n('packages_upgrade_failed'))
- else:
- logger.info(m18n.n('done'))
- operation_logger.success()
- finally:
- del os.environ["DEBIAN_FRONTEND"]
- else:
+ # Check that there's indeed some packages to upgrade
+ upgradables = list(_list_upgradable_apt_packages())
+ if not upgradables:
logger.info(m18n.n('packages_no_upgrade'))
+ logger.info(m18n.n('upgrading_packages'))
+ operation_logger.start()
+
+ # Critical packages are packages that we can't just upgrade
+ # randomly from yunohost itself... upgrading them is likely to
+ critical_packages = ("moulinette", "yunohost", "yunohost-admin", "ssowat", "python")
+
+ critical_packages_upgradable = [p for p in upgradables if p["name"] in critical_packages]
+ noncritical_packages_upgradable = [p for p in upgradables if p["name"] not in critical_packages]
+
+ # Prepare dist-upgrade command
+ dist_upgrade = "DEBIAN_FRONTEND=noninteractive"
+ dist_upgrade += " APT_LISTCHANGES_FRONTEND=none"
+ dist_upgrade += " apt-get"
+ dist_upgrade += " --fix-broken --show-upgraded --assume-yes"
+ for conf_flag in ["old", "miss", "def"]:
+ dist_upgrade += ' -o Dpkg::Options::="--force-conf{}"'.format(conf_flag)
+ dist_upgrade += " dist-upgrade"
+
+ #
+ # "Regular" packages upgrade
+ #
+ if not failure and noncritical_packages_upgradable:
+
+ # TODO : i18n
+ logger.info("Upgrading 'regular' (non-yunohost-related) packages ...")
+
+ # TODO : factorize this in utils/packages.py ?
+ # Mark all critical packages as held
+ for package in critical_packages:
+ check_output("apt-mark hold %s" % package)
+ # Doublecheck with apt-mark showhold that packages are indeed held ...
+ held_packages = check_output("apt-mark showhold").split("\n")
+ if any(p not in held_packages for p in critical_packages):
+ failure = True
+ logger.warning('Unable to hold critical packages ...')
+ logger.error(m18n.n('packages_upgrade_failed'))
+ # FIXME : watdo here, should this be an exception or just an
+ # error
+ operation_logger.error(m18n.n('packages_upgrade_failed'))
+
+ if not failure:
+ logger.debug("Running apt command :\n{}".format(dist_upgrade))
+
+ callbacks = (
+ lambda l: logger.info(l.rstrip()),
+ lambda l: logger.warning(l.rstrip()),
+ )
+ returncode = call_async_output(dist_upgrade, callbacks, shell=True)
+ if returncode != 0:
+ failure = True
+ logger.warning('unable to upgrade packages: %s' % ', '.join(noncritical_packages_upgradable))
+ logger.error(m18n.n('packages_upgrade_failed'))
+ operation_logger.error(m18n.n('packages_upgrade_failed'))
+
+ #
+ # Critical packages upgrade
+ #
+ if not failure and critical_packages_upgradable:
+
+ # TODO : i18n
+ logger.info("Upgrading 'special' (yunohost-related) packages ...")
+
+ # TODO : factorize this in utils/packages.py ?
+ # Mark all critical packages as unheld
+ for package in critical_packages:
+ check_output("apt-mark unhold %s" % package)
+ # Doublecheck with apt-mark showhold that packages are indeed unheld ...
+ unheld_packages = check_output("apt-mark showhold").split("\n")
+ if any(p in unheld_packages for p in critical_packages):
+ failure = True
+ logger.warning('Unable to unhold critical packages ...')
+ logger.error(m18n.n('packages_upgrade_failed'))
+ # FIXME : watdo here, should this be an exception or just an
+ # error
+ operation_logger.error(m18n.n('packages_upgrade_failed'))
+
+ #
+ # Here we use a dirty hack to run a command after the current
+ # "yunohost tools upgrade", because the upgrade of yunohost
+ # will also trigger other yunohost commands (e.g. "yunohost tools migrations migrate")
+ # (also the upgrade of the package, if executed from the webadmin, is
+ # likely to kill/restart the api which is in turn likely to kill this
+ # command before it ends...)
+ #
+
+ logfile = "/var/log/yunohost/special_upgrade_%s.log" % datetime.utcnow().strftime("%Y%m%d_%H%M%S")
+ command = dist_upgrade + " 2>&1 | tee -a {}".format(logfile)
+
+ MOULINETTE_LOCK = "/var/run/moulinette_yunohost.lock"
+ wait_until_end_of_yunohost_command = "(while [ -f {} ]; do sleep 2; done)".format(MOULINETTE_LOCK)
+
+ # TODO : i18n
+ upgrade_completed = "YunoHost package upgrade completed ! Press [enter] to get the command line back"
+ command = "({} && {}; echo '{}') &".format(wait_until_end_of_yunohost_command,
+ command,
+ upgrade_completed)
+
+ logger.debug("Running command :\n{}".format(command))
+ os.system(command)
+
+ # TODO / FIXME : return from this function immediately,
+ # otherwise the apps upgrade might happen and it's gonna be a mess
+
+ # FIXME / open question : what about "permanently" mark yunohost
+ # as "hold" to avoid accidental deletion of it...
+ # (so, only unhold it during the upgrade)
+
+ if not failure:
+
+ logger.info(m18n.n('done'))
+ operation_logger.success()
+
+
if not ignore_apps:
try:
app_upgrade(auth)
@@ -634,6 +701,7 @@ def tools_upgrade(operation_logger, auth, ignore_apps=False, ignore_packages=Fal
logger.success(m18n.n('system_upgraded'))
# Return API logs if it is an API call
+ is_api = True if msettings.get('interface') == 'api' else False
if is_api:
return {"log": service_log('yunohost-api', number="100").values()[0]}
From ad0f65aad713e3f582f437af4d3bc63dc02044ca Mon Sep 17 00:00:00 2001
From: ljf
Date: Fri, 22 Mar 2019 15:17:39 +0100
Subject: [PATCH 050/180] [enh] Log special upgrade into operation_logger
---
src/yunohost/log.py | 20 ++++++++++++++++----
src/yunohost/tools.py | 12 +++++++-----
2 files changed, 23 insertions(+), 9 deletions(-)
diff --git a/src/yunohost/log.py b/src/yunohost/log.py
index 857cc3658..7b0401e5b 100644
--- a/src/yunohost/log.py
+++ b/src/yunohost/log.py
@@ -318,14 +318,27 @@ class OperationLogger(object):
self.flush()
self._register_log()
+ @property
+ def md_path(self):
+ """
+ Metadata path file
+ """
+ return os.path.join(self.path, self.name + METADATA_FILE_EXT)
+
+ @property
+ def log_path(self):
+ """
+ Log path file
+ """
+ return os.path.join(self.path, self.name + LOG_FILE_EXT)
+
def _register_log(self):
"""
Register log with a handler connected on log system
"""
# TODO add a way to not save password on app installation
- filename = os.path.join(self.path, self.name + LOG_FILE_EXT)
- self.file_handler = FileHandler(filename)
+ self.file_handler = FileHandler(self.log_path)
self.file_handler.formatter = Formatter('%(asctime)s: %(levelname)s - %(message)s')
# Listen to the root logger
@@ -337,8 +350,7 @@ class OperationLogger(object):
Write or rewrite the metadata file with all metadata known
"""
- filename = os.path.join(self.path, self.name + METADATA_FILE_EXT)
- with open(filename, 'w') as outfile:
+ with open(self.md_path, 'w') as outfile:
yaml.safe_dump(self.metadata, outfile, default_flow_style=False)
@property
diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py
index 589e49a3f..6120ed3a1 100644
--- a/src/yunohost/tools.py
+++ b/src/yunohost/tools.py
@@ -660,18 +660,20 @@ def tools_upgrade(operation_logger, auth, ignore_apps=False, ignore_packages=Fal
# likely to kill/restart the api which is in turn likely to kill this
# command before it ends...)
#
-
- logfile = "/var/log/yunohost/special_upgrade_%s.log" % datetime.utcnow().strftime("%Y%m%d_%H%M%S")
+ logfile = operation_logger.log_path
command = dist_upgrade + " 2>&1 | tee -a {}".format(logfile)
MOULINETTE_LOCK = "/var/run/moulinette_yunohost.lock"
wait_until_end_of_yunohost_command = "(while [ -f {} ]; do sleep 2; done)".format(MOULINETTE_LOCK)
+ update_log_metadata = "sed -i \"s/ended_at: .*$/ended_at: $(date -u +'%Y-%m-%d %H:%M:%S.%N')/\" {}"
+ update_log_metadata = update_log_metadata.format(operation_logger.md_path)
# TODO : i18n
upgrade_completed = "YunoHost package upgrade completed ! Press [enter] to get the command line back"
- command = "({} && {}; echo '{}') &".format(wait_until_end_of_yunohost_command,
- command,
- upgrade_completed)
+ command = "({} && {} && {}; echo '{}') &".format(wait_until_end_of_yunohost_command,
+ command,
+ update_log_metadata,
+ upgrade_completed)
logger.debug("Running command :\n{}".format(command))
os.system(command)
From ac05ae655721469255a25885c8a451ede31ce6ca Mon Sep 17 00:00:00 2001
From: ljf
Date: Fri, 22 Mar 2019 15:32:51 +0100
Subject: [PATCH 051/180] [enh] Support success info with criticla upgrades
---
src/yunohost/tools.py | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py
index 6120ed3a1..9b27b340a 100644
--- a/src/yunohost/tools.py
+++ b/src/yunohost/tools.py
@@ -665,15 +665,17 @@ def tools_upgrade(operation_logger, auth, ignore_apps=False, ignore_packages=Fal
MOULINETTE_LOCK = "/var/run/moulinette_yunohost.lock"
wait_until_end_of_yunohost_command = "(while [ -f {} ]; do sleep 2; done)".format(MOULINETTE_LOCK)
+ mark_success = "(echo 'success: true' | tee -a {})".format(operation_logger.md_path)
update_log_metadata = "sed -i \"s/ended_at: .*$/ended_at: $(date -u +'%Y-%m-%d %H:%M:%S.%N')/\" {}"
update_log_metadata = update_log_metadata.format(operation_logger.md_path)
# TODO : i18n
upgrade_completed = "YunoHost package upgrade completed ! Press [enter] to get the command line back"
- command = "({} && {} && {}; echo '{}') &".format(wait_until_end_of_yunohost_command,
- command,
- update_log_metadata,
- upgrade_completed)
+ command = "({} && {} && {}; {}; echo '{}') &".format(wait_until_end_of_yunohost_command,
+ command,
+ mark_success,
+ update_log_metadata,
+ upgrade_completed)
logger.debug("Running command :\n{}".format(command))
os.system(command)
@@ -685,7 +687,7 @@ def tools_upgrade(operation_logger, auth, ignore_apps=False, ignore_packages=Fal
# as "hold" to avoid accidental deletion of it...
# (so, only unhold it during the upgrade)
- if not failure:
+ elif not failure:
logger.info(m18n.n('done'))
operation_logger.success()
From 847cecaf7fe77413af4e675a4631f1db861ceaa9 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Fri, 22 Mar 2019 16:12:06 +0100
Subject: [PATCH 052/180] [fix] Fix error message for bad choice for setting
enums
---
locales/en.json | 2 +-
src/yunohost/settings.py | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/locales/en.json b/locales/en.json
index 00fe6aa66..940201ef4 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -199,7 +199,7 @@
"firewall_reloaded": "The firewall has been reloaded",
"firewall_rules_cmd_failed": "Some firewall rules commands have failed. For more information, see the log.",
"format_datetime_short": "%m/%d/%Y %I:%M %p",
- "global_settings_bad_choice_for_enum": "Bad value for setting {setting:s}, received {received_type:s}, except {expected_type:s}",
+ "global_settings_bad_choice_for_enum": "Bad choice for setting {setting:s}, received '{choice:s}' but available choices are : {available_choices:s}",
"global_settings_bad_type_for_setting": "Bad type for setting {setting:s}, received {received_type:s}, except {expected_type:s}",
"global_settings_cant_open_settings": "Failed to open settings file, reason: {reason:s}",
"global_settings_cant_serialize_settings": "Failed to serialize settings data, reason: {reason:s}",
diff --git a/src/yunohost/settings.py b/src/yunohost/settings.py
index 81ea46114..5d2d55ede 100644
--- a/src/yunohost/settings.py
+++ b/src/yunohost/settings.py
@@ -109,8 +109,8 @@ def settings_set(key, value):
elif key_type == "enum":
if value not in settings[key]["choices"]:
raise YunohostError('global_settings_bad_choice_for_enum', setting=key,
- received_type=type(value).__name__,
- expected_type=", ".join(settings[key]["choices"]))
+ choice=value,
+ available_choices=", ".join(settings[key]["choices"]))
else:
raise YunohostError('global_settings_unknown_type', setting=key,
unknown_type=key_type)
From fee79820e097ebefb342bd53a16098661359b196 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Fri, 22 Mar 2019 16:15:11 +0100
Subject: [PATCH 053/180] Rename nginx and ssh compatibility setting for
consistency
---
data/hooks/conf_regen/03-ssh | 4 ++--
data/hooks/conf_regen/15-nginx | 4 ++--
src/yunohost/settings.py | 8 ++++----
3 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/data/hooks/conf_regen/03-ssh b/data/hooks/conf_regen/03-ssh
index dbf9d69e3..0b58a461c 100755
--- a/data/hooks/conf_regen/03-ssh
+++ b/data/hooks/conf_regen/03-ssh
@@ -24,8 +24,8 @@ do_pre_regen() {
fi
# Support different strategy for security configurations
- if [[ -n "$(yunohost settings get 'service.ssh.ciphers.compatibility')" ]]; then
- ssh_ciphers_compatibility="$(yunohost settings get 'service.ssh.ciphers.compatibility')"
+ if [[ -n "$(yunohost settings get 'service.ssh.compatibility')" ]]; then
+ ssh_ciphers_compatibility="$(yunohost settings get 'service.ssh.compatibility')"
fi
export ssh_keys
diff --git a/data/hooks/conf_regen/15-nginx b/data/hooks/conf_regen/15-nginx
index 9a7579eeb..57446c081 100755
--- a/data/hooks/conf_regen/15-nginx
+++ b/data/hooks/conf_regen/15-nginx
@@ -37,8 +37,8 @@ do_pre_regen() {
domain_list=$(sudo yunohost domain list --output-as plain --quiet)
# Support different strategy for security configurations
- if [[ -n "$(yunohost settings get 'security.ciphers.compatibility')" ]]; then
- security_ciphers_compatibility="$(yunohost settings get 'security.ciphers.compatibility')"
+ if [[ -n "$(yunohost settings get 'security.nginx.compatibility')" ]]; then
+ security_ciphers_compatibility="$(yunohost settings get 'security.nginx.compatibility')"
fi
export security_ciphers_compatibility
diff --git a/src/yunohost/settings.py b/src/yunohost/settings.py
index 916e8b8c3..6277c8283 100644
--- a/src/yunohost/settings.py
+++ b/src/yunohost/settings.py
@@ -40,9 +40,9 @@ DEFAULTS = OrderedDict([
("security.password.admin.strength", {"type": "int", "default": 1}),
("security.password.user.strength", {"type": "int", "default": 1}),
("service.ssh.allow_deprecated_dsa_hostkey", {"type": "bool", "default": False}),
- ("service.ssh.ciphers.compatibility", {"type": "enum", "default": "modern",
+ ("security.ssh.compatibility", {"type": "enum", "default": "modern",
"choices": ["intermediate", "modern"]}),
- ("security.ciphers.compatibility", {"type": "enum", "default": "intermediate",
+ ("security.nginx.compatibility", {"type": "enum", "default": "intermediate",
"choices": ["intermediate", "modern"]}),
])
@@ -283,12 +283,12 @@ def trigger_post_change_hook(setting_name, old_value, new_value):
#
# ===========================================
-@post_change_hook("security.ciphers.compatibility")
+@post_change_hook("security.nginx.compatibility")
def reconfigure_nginx(setting_name, old_value, new_value):
if old_value != new_value:
service_regen_conf(names=['nginx'])
-@post_change_hook("service.ssh.ciphers.compatibility")
+@post_change_hook("security.ssh.compatibility")
def reconfigure_ssh(setting_name, old_value, new_value):
if old_value != new_value:
service_regen_conf(names=['ssh'])
From 2defd6ffa82368a6714b8850a1a1a960d345ac1e Mon Sep 17 00:00:00 2001
From: "ljf (zamentur)"
Date: Fri, 22 Mar 2019 16:20:35 +0100
Subject: [PATCH 054/180] [fix] Keep user info in json format
Previously it was ynhpanel.json
---
data/templates/nginx/plain/yunohost_panel.conf.inc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/data/templates/nginx/plain/yunohost_panel.conf.inc b/data/templates/nginx/plain/yunohost_panel.conf.inc
index d159c29f9..b36d79119 100644
--- a/data/templates/nginx/plain/yunohost_panel.conf.inc
+++ b/data/templates/nginx/plain/yunohost_panel.conf.inc
@@ -4,5 +4,5 @@ sub_filter_once on;
# Apply to other mime types than text/html
sub_filter_types application/xhtml+xml;
# Prevent YunoHost panel files from being blocked by specific app rules
-location ~ (ynh_portal.js|ynh_overlay.css) {
+location ~ (ynh_portal.js|ynh_overlay.css|userinfo.json) {
}
From c8d8e0e272b89e660f8f6ad860bb748642c4709a Mon Sep 17 00:00:00 2001
From: "ljf (zamentur)"
Date: Fri, 22 Mar 2019 16:30:02 +0100
Subject: [PATCH 055/180] [fix] Avoid potential conflict with some apps
---
data/templates/nginx/plain/yunohost_panel.conf.inc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/data/templates/nginx/plain/yunohost_panel.conf.inc b/data/templates/nginx/plain/yunohost_panel.conf.inc
index b36d79119..1c5a2d656 100644
--- a/data/templates/nginx/plain/yunohost_panel.conf.inc
+++ b/data/templates/nginx/plain/yunohost_panel.conf.inc
@@ -4,5 +4,5 @@ sub_filter_once on;
# Apply to other mime types than text/html
sub_filter_types application/xhtml+xml;
# Prevent YunoHost panel files from being blocked by specific app rules
-location ~ (ynh_portal.js|ynh_overlay.css|userinfo.json) {
+location ~ (ynh_portal.js|ynh_overlay.css|ynh_userinfo.json) {
}
From dcff10f6f84d03c5f15cfa29cd4698cdcb365bd3 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Fri, 22 Mar 2019 16:31:45 +0100
Subject: [PATCH 056/180] Simplify setting usage in regenconf hooks
---
data/hooks/conf_regen/03-ssh | 5 +----
data/hooks/conf_regen/15-nginx | 6 +-----
data/templates/nginx/plain/yunohost_admin.conf | 2 +-
data/templates/nginx/server.tpl.conf | 2 +-
data/templates/ssh/sshd_config | 2 +-
5 files changed, 5 insertions(+), 12 deletions(-)
diff --git a/data/hooks/conf_regen/03-ssh b/data/hooks/conf_regen/03-ssh
index 0b58a461c..265c2f746 100755
--- a/data/hooks/conf_regen/03-ssh
+++ b/data/hooks/conf_regen/03-ssh
@@ -24,13 +24,10 @@ do_pre_regen() {
fi
# Support different strategy for security configurations
- if [[ -n "$(yunohost settings get 'service.ssh.compatibility')" ]]; then
- ssh_ciphers_compatibility="$(yunohost settings get 'service.ssh.compatibility')"
- fi
+ export compatibility="$(yunohost settings get 'service.ssh.compatibility')"
export ssh_keys
export ipv6_enabled
- export ssh_ciphers_compatibility
ynh_render_template "sshd_config" "${pending_dir}/etc/ssh/sshd_config"
}
diff --git a/data/hooks/conf_regen/15-nginx b/data/hooks/conf_regen/15-nginx
index 57446c081..60e719743 100755
--- a/data/hooks/conf_regen/15-nginx
+++ b/data/hooks/conf_regen/15-nginx
@@ -37,11 +37,7 @@ do_pre_regen() {
domain_list=$(sudo yunohost domain list --output-as plain --quiet)
# Support different strategy for security configurations
- if [[ -n "$(yunohost settings get 'security.nginx.compatibility')" ]]; then
- security_ciphers_compatibility="$(yunohost settings get 'security.nginx.compatibility')"
- fi
-
- export security_ciphers_compatibility
+ export compatibility="$(yunohost settings get 'security.nginx.compatibility')"
# add domain conf files
for domain in $domain_list; do
diff --git a/data/templates/nginx/plain/yunohost_admin.conf b/data/templates/nginx/plain/yunohost_admin.conf
index 71ad22545..c785a63c4 100644
--- a/data/templates/nginx/plain/yunohost_admin.conf
+++ b/data/templates/nginx/plain/yunohost_admin.conf
@@ -20,7 +20,7 @@ server {
ssl_session_timeout 5m;
ssl_session_cache shared:SSL:50m;
- {% if security_ciphers_compatibility == "modern" %}
+ {% if compatibility == "modern" %}
# Ciphers with modern compatibility
# https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=nginx-1.6.2&openssl=1.0.1t&hsts=yes&profile=modern
# Uncomment the following to use modern ciphers, but remove compatibility with some old clients (android < 5.0, Internet Explorer < 10, ...)
diff --git a/data/templates/nginx/server.tpl.conf b/data/templates/nginx/server.tpl.conf
index b25e38faa..26bc78b39 100644
--- a/data/templates/nginx/server.tpl.conf
+++ b/data/templates/nginx/server.tpl.conf
@@ -29,7 +29,7 @@ server {
ssl_session_timeout 5m;
ssl_session_cache shared:SSL:50m;
- {% if security_ciphers_compatibility == "modern" %}
+ {% if compatibility == "modern" %}
# Ciphers with modern compatibility
# https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=nginx-1.6.2&openssl=1.0.1t&hsts=yes&profile=modern
# The following configuration use modern ciphers, but remove compatibility with some old clients (android < 5.0, Internet Explorer < 10, ...)
diff --git a/data/templates/ssh/sshd_config b/data/templates/ssh/sshd_config
index f27ca3ebe..8dc0e8dfc 100644
--- a/data/templates/ssh/sshd_config
+++ b/data/templates/ssh/sshd_config
@@ -15,7 +15,7 @@ HostKey {{ key }}{% endfor %}
# https://infosec.mozilla.org/guidelines/openssh
# ##############################################
-{% if ssh_ciphers_compatibility == "intermediate" %}
+{% if compatibility == "intermediate" %}
KexAlgorithms diffie-hellman-group-exchange-sha256
Ciphers aes256-ctr,aes192-ctr,aes128-ctr
MACs hmac-sha2-512,hmac-sha2-256
From 219dd2590c7ae876ec194fb4522e86d48a618b0a Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Fri, 22 Mar 2019 17:12:38 +0100
Subject: [PATCH 057/180] Update settings descriptions
---
locales/en.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/locales/en.json b/locales/en.json
index e56b8e304..af3360b8a 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -210,12 +210,12 @@
"global_settings_setting_example_enum": "Example enum option",
"global_settings_setting_example_int": "Example int option",
"global_settings_setting_example_string": "Example string option",
- "global_settings_setting_security_ciphers_compatibility": "Admin ciphers compatibility strategy for the web",
+ "global_settings_setting_security_nginx_compatibility": "Compatibility vs. security tradeoff for the web server nginx. Affects the ciphers (and other security-related aspects)",
"global_settings_setting_security_password_admin_strength": "Admin password strength",
"global_settings_setting_security_password_user_strength": "User password strength",
+ "global_settings_setting_security_ssh_compatibility": "Compatibility vs. security tradeoff for the SSH server. Affects the ciphers (and other security-related aspects)",
"global_settings_unknown_setting_from_settings_file": "Unknown key in settings: '{setting_key:s}', discarding it and save it in /etc/yunohost/unkown_settings.json",
"global_settings_setting_service_ssh_allow_deprecated_dsa_hostkey": "Allow the use of (deprecated) DSA hostkey for the SSH daemon configuration",
- "global_settings_setting_service_ssh_ciphers_compatibility": "Admin ciphers compatibility strategy for SSH",
"global_settings_unknown_type": "Unexpected situation, the setting {setting:s} appears to have the type {unknown_type:s} but it's not a type supported by the system.",
"good_practices_about_admin_password": "You are now about to define a new administration password. The password should be at least 8 characters - though it is good practice to use longer password (i.e. a passphrase) and/or to use various kind of characters (uppercase, lowercase, digits and special characters).",
"good_practices_about_user_password": "You are now about to define a new user password. The password should be at least 8 characters - though it is good practice to use longer password (i.e. a passphrase) and/or to use various kind of characters (uppercase, lowercase, digits and special characters).",
From fefa44e0621fa6ee28515079df0755dc9e7d7e09 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Fri, 22 Mar 2019 17:14:48 +0100
Subject: [PATCH 058/180] Typo in previous commits
---
data/hooks/conf_regen/03-ssh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/data/hooks/conf_regen/03-ssh b/data/hooks/conf_regen/03-ssh
index 265c2f746..54b7c55b7 100755
--- a/data/hooks/conf_regen/03-ssh
+++ b/data/hooks/conf_regen/03-ssh
@@ -24,7 +24,7 @@ do_pre_regen() {
fi
# Support different strategy for security configurations
- export compatibility="$(yunohost settings get 'service.ssh.compatibility')"
+ export compatibility="$(yunohost settings get 'security.ssh.compatibility')"
export ssh_keys
export ipv6_enabled
From e2e9a7a0339ae269a239156972595d6ff590cebe Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Fri, 22 Mar 2019 17:47:32 +0100
Subject: [PATCH 059/180] Remove all deprecated lists, not just 'yunohost'
---
.../0009_migrate_to_apps_json.py | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/src/yunohost/data_migrations/0009_migrate_to_apps_json.py b/src/yunohost/data_migrations/0009_migrate_to_apps_json.py
index 364497b46..b5ae1130b 100644
--- a/src/yunohost/data_migrations/0009_migrate_to_apps_json.py
+++ b/src/yunohost/data_migrations/0009_migrate_to_apps_json.py
@@ -1,5 +1,5 @@
from moulinette.utils.log import getActionLogger
-from yunohost.app import app_fetchlist, app_removelist
+from yunohost.app import app_fetchlist, app_removelist, _read_appslist_list
from yunohost.tools import Migration
logger = getActionLogger('yunohost.migration')
@@ -10,12 +10,21 @@ class MyMigration(Migration):
def migrate(self):
- # Remove official.json list
- app_removelist(name="yunohost")
+ # Remove all the deprecated lists
+ lists_to_remove = [
+ "https://app.yunohost.org/official.json",
+ "https://app.yunohost.org/community.json",
+ "https://labriqueinter.net/apps/labriqueinternet.json"
+ ]
+
+ appslists = _read_appslist_list()
+ for appslist, infos in appslists.items():
+ if infos["url"] in lists_to_remove:
+ app_removelist(name=appslist)
# Replace by apps.json list
app_fetchlist(name="yunohost",
- url="https://app.yunohost.org/apps.json")
+ url="https://app.yunohost.org/apps.json")
def backward(self):
From 93c978ba422b26971180a4277a0b69e82848ee78 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Fri, 22 Mar 2019 17:58:46 +0100
Subject: [PATCH 060/180] Backup / restore original appslist to handle backward
case properly
---
.../0009_migrate_to_apps_json.py | 20 ++++++++++++-------
1 file changed, 13 insertions(+), 7 deletions(-)
diff --git a/src/yunohost/data_migrations/0009_migrate_to_apps_json.py b/src/yunohost/data_migrations/0009_migrate_to_apps_json.py
index b5ae1130b..8c81746d9 100644
--- a/src/yunohost/data_migrations/0009_migrate_to_apps_json.py
+++ b/src/yunohost/data_migrations/0009_migrate_to_apps_json.py
@@ -1,15 +1,25 @@
+import os
+
from moulinette.utils.log import getActionLogger
-from yunohost.app import app_fetchlist, app_removelist, _read_appslist_list
+from yunohost.app import app_fetchlist, app_removelist, _read_appslist_list, APPSLISTS_JSON
from yunohost.tools import Migration
logger = getActionLogger('yunohost.migration')
+BASE_CONF_PATH = '/home/yunohost.conf'
+BACKUP_CONF_DIR = os.path.join(BASE_CONF_PATH, 'backup')
+APPSLISTS_BACKUP = os.path.join(BACKUP_CONF_DIR, "appslist_before_migration_0009.json")
+
+
class MyMigration(Migration):
"Migrate from official.json to apps.json"
def migrate(self):
+ # Backup current app list json
+ os.system("cp %s %s") % (APPSLISTS_JSON, APPSLISTS_BACKUP)
+
# Remove all the deprecated lists
lists_to_remove = [
"https://app.yunohost.org/official.json",
@@ -28,9 +38,5 @@ class MyMigration(Migration):
def backward(self):
- # Remove apps.json list
- app_removelist(name="yunohost")
-
- # Replace by official.json list
- app_fetchlist(name="yunohost",
- url="https://app.yunohost.org/official.json")
+ if os.path.exists(APPSLISTS_BACKUP):
+ os.system("cp %s %s") % (APPSLISTS_BACKUP, APPSLISTS_JSON)
From d6b6fff7064c06ec505de5c5aaf572b776223ce9 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Fri, 22 Mar 2019 18:00:46 +0100
Subject: [PATCH 061/180] Add description for migration 0009
---
locales/en.json | 1 +
1 file changed, 1 insertion(+)
diff --git a/locales/en.json b/locales/en.json
index 1157e0a54..2a2db5340 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -294,6 +294,7 @@
"migration_description_0006_sync_admin_and_root_passwords": "Synchronize admin and root passwords",
"migration_description_0007_ssh_conf_managed_by_yunohost_step1": "Let the SSH configuration be managed by YunoHost (step 1, automatic)",
"migration_description_0008_ssh_conf_managed_by_yunohost_step2": "Let the SSH configuration be managed by YunoHost (step 2, manual)",
+ "migration_description_0009_migrate_to_apps_json": "Remove deprecated appslists and use the new unified 'apps.json' list instead.",
"migration_0003_backward_impossible": "The stretch migration cannot be reverted.",
"migration_0003_start": "Starting migration to Stretch. The logs will be available in {logfile}.",
"migration_0003_patching_sources_list": "Patching the sources.lists…",
From d0df02837347def4b8e9b66c92a2a74937083ff3 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Fri, 22 Mar 2019 18:06:39 +0100
Subject: [PATCH 062/180] Woopsi typo
---
src/yunohost/data_migrations/0009_migrate_to_apps_json.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/yunohost/data_migrations/0009_migrate_to_apps_json.py b/src/yunohost/data_migrations/0009_migrate_to_apps_json.py
index 8c81746d9..4f4baa5bd 100644
--- a/src/yunohost/data_migrations/0009_migrate_to_apps_json.py
+++ b/src/yunohost/data_migrations/0009_migrate_to_apps_json.py
@@ -18,7 +18,7 @@ class MyMigration(Migration):
def migrate(self):
# Backup current app list json
- os.system("cp %s %s") % (APPSLISTS_JSON, APPSLISTS_BACKUP)
+ os.system("cp %s %s" % (APPSLISTS_JSON, APPSLISTS_BACKUP))
# Remove all the deprecated lists
lists_to_remove = [
@@ -39,4 +39,4 @@ class MyMigration(Migration):
def backward(self):
if os.path.exists(APPSLISTS_BACKUP):
- os.system("cp %s %s") % (APPSLISTS_BACKUP, APPSLISTS_JSON)
+ os.system("cp %s %s" % (APPSLISTS_BACKUP, APPSLISTS_JSON))
From 1268872ecfec60f2688f9eba2bc92a7f4d632646 Mon Sep 17 00:00:00 2001
From: Romuald
Date: Sat, 23 Mar 2019 11:58:07 +0100
Subject: [PATCH 063/180] Fix filename in error message
---
locales/en.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/locales/en.json b/locales/en.json
index 940201ef4..41c68fd16 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -212,7 +212,7 @@
"global_settings_setting_example_string": "Example string option",
"global_settings_setting_security_password_admin_strength": "Admin password strength",
"global_settings_setting_security_password_user_strength": "User password strength",
- "global_settings_unknown_setting_from_settings_file": "Unknown key in settings: '{setting_key:s}', discarding it and save it in /etc/yunohost/unkown_settings.json",
+ "global_settings_unknown_setting_from_settings_file": "Unknown key in settings: '{setting_key:s}', discarding it and save it in /etc/yunohost/settings-unknown.json",
"global_settings_setting_service_ssh_allow_deprecated_dsa_hostkey": "Allow the use of (deprecated) DSA hostkey for the SSH daemon configuration",
"global_settings_unknown_type": "Unexpected situation, the setting {setting:s} appears to have the type {unknown_type:s} but it's not a type supported by the system.",
"good_practices_about_admin_password": "You are now about to define a new administration password. The password should be at least 8 characters - though it is good practice to use longer password (i.e. a passphrase) and/or to use various kind of characters (uppercase, lowercase, digits and special characters).",
From a86c379233e4305cda886d89b9aa254876a44c25 Mon Sep 17 00:00:00 2001
From: Romuald du Song
Date: Sat, 23 Mar 2019 16:46:40 +0100
Subject: [PATCH 064/180] fix syntax in nodejs helper
---
data/helpers.d/nodejs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/data/helpers.d/nodejs b/data/helpers.d/nodejs
index 61a1414ef..1730990e7 100644
--- a/data/helpers.d/nodejs
+++ b/data/helpers.d/nodejs
@@ -99,7 +99,7 @@ ynh_install_nodejs () {
# Install the requested version of nodejs
uname=$(uname -m)
- if [[ $uname =~ aarch64 || $uname =~ arm64]]
+ if [[ $uname =~ aarch64 || $uname =~ arm64 ]]
then
n $nodejs_version --arch=arm64
else
From dd87b9192aefde56175f54aa5aa20cdf98baa9b8 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Sat, 23 Mar 2019 16:50:44 +0100
Subject: [PATCH 065/180] Improve naming / semantic / add comments
---
src/yunohost/domain.py | 33 +++++++++++++++++++++++++--------
1 file changed, 25 insertions(+), 8 deletions(-)
diff --git a/src/yunohost/domain.py b/src/yunohost/domain.py
index e604b54f0..a7141e0b8 100644
--- a/src/yunohost/domain.py
+++ b/src/yunohost/domain.py
@@ -408,21 +408,38 @@ def _build_dns_conf(domain, ttl=3600):
]
# Official record
- res = {
+ records = {
"basic": [{"name": name, "ttl": ttl, "type": type_, "value": value} for name, ttl, type_, value in basic],
"xmpp": [{"name": name, "ttl": ttl, "type": type_, "value": value} for name, ttl, type_, value in xmpp],
"mail": [{"name": name, "ttl": ttl, "type": type_, "value": value} for name, ttl, type_, value in mail],
"extra": [{"name": name, "ttl": ttl, "type": type_, "value": value} for name, ttl, type_, value in extra],
}
- # Custom record
- hookres = hook_callback('custom_dns_rules', args=[domain])
- for n, val in hookres.items() :
- res[n] = []
- for v in [v['stdreturn'] for p, v in val.items() if v and v['stdreturn']]:
- res[n].extend(v)
+ # Custom records
+ hook_results = hook_callback('custom_dns_rules', args=[domain])
+ for hook_name, results in hook_results.items():
+ #
+ # There can be multiple results per hook name, so results look like
+ # {'/some/path/to/hook1':
+ # { 'state': 'succeed',
+ # 'stdreturn': [{'type': 'SRV',
+ # 'name': 'stuff.foo.bar.',
+ # 'value': 'yoloswag',
+ # 'ttl': 3600}]
+ # },
+ # '/some/path/to/hook2':
+ # { ... },
+ # [...]
+ #
+ # Loop over the sub-results
+ custom_records = [v['stdreturn'] for v in results.values()
+ if v and v['stdreturn']]
- return res
+ records[hook_name] = []
+ for record_list in custom_records:
+ records[hook_name].extend(record_list)
+
+ return records
def _get_DKIM(domain):
From cd9fcd265d99e52d4da02f5546483d802c074c98 Mon Sep 17 00:00:00 2001
From: Romuald du Song
Date: Sat, 23 Mar 2019 16:54:47 +0100
Subject: [PATCH 066/180] fix conflict
---
data/helpers.d/nodejs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/data/helpers.d/nodejs b/data/helpers.d/nodejs
index 1730990e7..098ed4410 100644
--- a/data/helpers.d/nodejs
+++ b/data/helpers.d/nodejs
@@ -99,7 +99,7 @@ ynh_install_nodejs () {
# Install the requested version of nodejs
uname=$(uname -m)
- if [[ $uname =~ aarch64 || $uname =~ arm64 ]]
+ if [[ $uname =~ aarch64 || $uname =~ arm64 ]]
then
n $nodejs_version --arch=arm64
else
From 5ac5cc93107efea4a5855afb686d4f4640d244bf Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Sat, 23 Mar 2019 17:31:56 +0100
Subject: [PATCH 067/180] Check format of data retrieved from hook stdreturn
---
src/yunohost/domain.py | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/src/yunohost/domain.py b/src/yunohost/domain.py
index a7141e0b8..70a4ef5c9 100644
--- a/src/yunohost/domain.py
+++ b/src/yunohost/domain.py
@@ -437,6 +437,15 @@ def _build_dns_conf(domain, ttl=3600):
records[hook_name] = []
for record_list in custom_records:
+ # Check that record_list is indeed a list of dict
+ # with the required keys
+ if not isinstance(record_list, list) \
+ or any(not isinstance(record, dict) for record in record_list) \
+ or any(key not in record for record in record_list for key in ["name", "ttl", "type", "value"]):
+ # Display an error, mainly for app packagers trying to implement a hook
+ logger.warning("Ignored custom record from hook '%s' because the data is not a *list* of dict with keys name, ttl, type and value. Raw data : %s" % (hook_name, record_list))
+ continue
+
records[hook_name].extend(record_list)
return records
From fad3edf66a21ef56b43b5e314745b167bb683175 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Mon, 25 Mar 2019 16:50:49 +0100
Subject: [PATCH 068/180] [fix] SSH login breaks if password is longer than 127
chars...
---
locales/en.json | 1 +
src/yunohost/tools.py | 5 +++++
2 files changed, 6 insertions(+)
diff --git a/locales/en.json b/locales/en.json
index 18ab84be1..694df0707 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -4,6 +4,7 @@
"admin_password": "Administration password",
"admin_password_change_failed": "Unable to change password",
"admin_password_changed": "The administration password has been changed",
+ "admin_password_too_long": "Please choose a password shorter than 127 characters",
"app_already_installed": "{app:s} is already installed",
"app_already_installed_cant_change_url": "This app is already installed. The url cannot be changed just by this function. Look into `app changeurl` if it's available.",
"app_already_up_to_date": "{app:s} is already up to date",
diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py
index a011b1546..42114c7e9 100644
--- a/src/yunohost/tools.py
+++ b/src/yunohost/tools.py
@@ -132,6 +132,11 @@ def tools_adminpw(auth, new_password, check_strength=True):
if check_strength:
assert_password_is_strong_enough("admin", new_password)
+ # UNIX seems to not like password longer than 127 chars ...
+ # e.g. SSH login gets broken (or even 'su admin' when entering the password)
+ if len(new_password) >= 127:
+ raise YunohostError('admin_password_too_long')
+
new_hash = _hash_user_password(new_password)
try:
From 84c66990c34d3bb28c3eef819fbfcd2bd470e44c Mon Sep 17 00:00:00 2001
From: Gabriel Corona
Date: Sat, 16 Mar 2019 23:04:33 +0100
Subject: [PATCH 069/180] Avoid having to shell-escape arguments in
ynh_handle_getopts_args
Fixes $ ` and \ injections.
---
data/helpers.d/getopts | 22 ++--------------------
1 file changed, 2 insertions(+), 20 deletions(-)
diff --git a/data/helpers.d/getopts b/data/helpers.d/getopts
index 694543e1d..894c9395f 100644
--- a/data/helpers.d/getopts
+++ b/data/helpers.d/getopts
@@ -152,19 +152,8 @@ ynh_handle_getopts_args () {
# If there's already another value for this option, add a ; before adding the new value
eval ${option_var}+="\;"
fi
- # Escape double quote to prevent any interpretation during the eval
- all_args[$i]="${all_args[$i]//\"/\\\"}"
- # Escape $ as well to prevent the string following it to be seen as a variable.
- all_args[$i]="${all_args[$i]//$/\\\$}"
- # For the record.
- # We're using eval here to get the content of the variable stored itself as simple text in $option_var...
- # Other ways to get that content would be to use either ${!option_var} or declare -g ${option_var}
- # But... ${!option_var} can't be used as left part of an assignation.
- # declare -g ${option_var} will create a local variable (despite -g !) and will not be available for the helper itself.
- # So... Stop fucking arguing each time that eval is evil... Go find an other working solution if you can find one!
-
- eval ${option_var}+=\"${all_args[$i]}\"
+ eval ${option_var}+='"${all_args[$i]}"'
shift_value=$(( shift_value + 1 ))
fi
done
@@ -202,14 +191,7 @@ ynh_handle_getopts_args () {
# The variable name will be stored in 'option_var'
local option_var="${args_array[$option_flag]%=}"
- # Escape double quote to prevent any interpretation during the eval
- arguments[$i]="${arguments[$i]//\"/\\\"}"
- # Escape $ as well to prevent the string following it to be seen as a variable.
- arguments[$i]="${arguments[$i]//$/\\\$}"
-
- # Store each value given as argument in the corresponding variable
- # The values will be stored in the same order than $args_array
- eval ${option_var}+=\"${arguments[$i]}\"
+ eval ${option_var}+='"${arguments[$i]}"'
done
unset legacy_args
else
From 2f0dd973b8686de62f92b1aefa91a6d68ebb6100 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Fri, 22 Mar 2019 01:14:45 +0100
Subject: [PATCH 070/180] Rework system-part of tools_update...
---
src/yunohost/tools.py | 51 ++++++++++++++++++++++++++++++++++---------
1 file changed, 41 insertions(+), 10 deletions(-)
diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py
index 42114c7e9..92c68eca9 100644
--- a/src/yunohost/tools.py
+++ b/src/yunohost/tools.py
@@ -41,7 +41,7 @@ from moulinette import msettings, msignals, m18n
from moulinette.core import init_authenticator
from yunohost.utils.error import YunohostError
from moulinette.utils.log import getActionLogger
-from moulinette.utils.process import check_output
+from moulinette.utils.process import check_output, call_async_output
from moulinette.utils.filesystem import read_json, write_to_json
from yunohost.app import app_fetchlist, app_info, app_upgrade, app_ssowatconf, app_list, _install_appslist_fetch_cron
from yunohost.domain import domain_add, domain_list, _get_maindomain, _set_maindomain
@@ -474,23 +474,54 @@ def tools_update(ignore_apps=False, ignore_packages=False):
# "packages" will list upgradable packages
packages = []
if not ignore_packages:
- cache = apt.Cache()
# Update APT cache
+ # LC_ALL=C is here to make sure the results are in english
+ command = "LC_ALL=C apt update"
+ # TODO : add @is_unit_operation to tools_update so that the
+ # debug output can be fetched when there's an issue...
+ callbacks = (
+ # stdout goes to debug
+ lambda l: logger.debug(l.rstrip()),
+ # stderr goes to warning
+ # FIXME : filter the damn "CLI interface not stable" from apt >.>
+ lambda l: logger.warning(l.rstrip()),
+ )
+
logger.info(m18n.n('updating_apt_cache'))
- if not cache.update():
+
+ returncode = call_async_output(command, callbacks, shell=True)
+
+ if returncode != 0:
+
+ # TODO : here, we should run something like a
+ # `cat /etc/apt/sources.list /etc/apt/sources.list.d/*`
+ # and append it to the error message to improve debugging
+
raise YunohostError('update_cache_failed')
- cache.open(None)
- cache.upgrade(True)
+ # 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")
- # Add changelogs to the result
- for pkg in cache.get_changes():
+ # Dirty parsing of the output
+ upgradable_raw = [l.strip() for l in upgradable_raw.split("\n") if l.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
+ # line should look like :
+ # yunohost/stable 3.5.0.2+201903211853 all [upgradable from: 3.4.2.4+201903080053]
+ line = line.split()
+ if len(line) != 6:
+ logger.warning("Failed to parse this line : %s" % ' '.join(line))
+ continue
packages.append({
- 'name': pkg.name,
- 'fullname': pkg.fullname,
- 'changelog': pkg.get_changelog()
+ "name": line[0].split("/")[0],
+ "new_version": line[1],
+ "current_version": line[5].strip("]"),
})
+
logger.debug(m18n.n('done'))
# "apps" will list upgradable packages
From 2f034bb7c9b6d62943a9ea1897b3000b5c33f193 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Fri, 22 Mar 2019 04:01:08 +0100
Subject: [PATCH 071/180] Factorize function to list upgradable packages
---
src/yunohost/tools.py | 50 ++++++++++++++++++++++++-------------------
1 file changed, 28 insertions(+), 22 deletions(-)
diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py
index 92c68eca9..154ad086a 100644
--- a/src/yunohost/tools.py
+++ b/src/yunohost/tools.py
@@ -500,28 +500,7 @@ def tools_update(ignore_apps=False, ignore_packages=False):
raise YunohostError('update_cache_failed')
- # 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")
-
- # Dirty parsing of the output
- upgradable_raw = [l.strip() for l in upgradable_raw.split("\n") if l.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
- # line should look like :
- # yunohost/stable 3.5.0.2+201903211853 all [upgradable from: 3.4.2.4+201903080053]
- line = line.split()
- if len(line) != 6:
- logger.warning("Failed to parse this line : %s" % ' '.join(line))
- continue
- packages.append({
- "name": line[0].split("/")[0],
- "new_version": line[1],
- "current_version": line[5].strip("]"),
- })
-
+ packages = list(_list_upgradable_apt_packages())
logger.debug(m18n.n('done'))
# "apps" will list upgradable packages
@@ -550,6 +529,33 @@ def tools_update(ignore_apps=False, ignore_packages=False):
return {'packages': packages, 'apps': apps}
+# TODO : move this to utils/packages.py ?
+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")
+
+ # Dirty parsing of the output
+ upgradable_raw = [l.strip() for l in upgradable_raw.split("\n") if l.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
+ # line should look like :
+ # yunohost/stable 3.5.0.2+201903211853 all [upgradable from: 3.4.2.4+201903080053]
+ line = line.split()
+ if len(line) != 6:
+ logger.warning("Failed to parse this line : %s" % ' '.join(line))
+ continue
+
+ yield {
+ "name": line[0].split("/")[0],
+ "new_version": line[1],
+ "current_version": line[5].strip("]"),
+ }
+
+
@is_unit_operation()
def tools_upgrade(operation_logger, auth, ignore_apps=False, ignore_packages=False):
"""
From f35eb1785437d9f7b1fd3c66edeb83868dc26418 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Tue, 26 Mar 2019 18:49:32 +0100
Subject: [PATCH 072/180] Mark YunoHost as essential to avoid removing it
inadvertenly
---
debian/control | 1 +
1 file changed, 1 insertion(+)
diff --git a/debian/control b/debian/control
index 685c194ba..a6fd95154 100644
--- a/debian/control
+++ b/debian/control
@@ -1,6 +1,7 @@
Source: yunohost
Section: utils
Priority: extra
+Essential: yes
Maintainer: YunoHost Contributors
Build-Depends: debhelper (>=9), dh-systemd, dh-python, python-all (>= 2.7)
Standards-Version: 3.9.6
From e298838949ce3b2ab924a303dff3cbeffc9b39f3 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Tue, 26 Mar 2019 19:45:16 +0100
Subject: [PATCH 073/180] Filter boring apt warnings + report an error if there
was real warnings
---
locales/en.json | 1 +
src/yunohost/tools.py | 17 ++++++++++++++---
2 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/locales/en.json b/locales/en.json
index 694df0707..da27c7cb0 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -483,6 +483,7 @@
"unlimit": "No quota",
"unrestore_app": "App '{app:s}' will not be restored",
"update_cache_failed": "Unable to update APT cache",
+ "update_cache_warning": "Some errors happened while updating APT cache",
"updating_apt_cache": "Fetching available upgrades for system packages…",
"upgrade_complete": "Upgrade complete",
"upgrading_packages": "Upgrading packages…",
diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py
index 154ad086a..f9d86ad09 100644
--- a/src/yunohost/tools.py
+++ b/src/yunohost/tools.py
@@ -480,12 +480,21 @@ def tools_update(ignore_apps=False, ignore_packages=False):
command = "LC_ALL=C apt update"
# TODO : add @is_unit_operation to tools_update so that the
# debug output can be fetched when there's an issue...
+
+ # Filter boring message about "apt not having a stable CLI interface"
+ # Also keep track of wether or not we encountered a warning...
+ warnings = []
+ def is_legit_warning(m):
+ legit_warning = m.rstrip() and "apt does not have a stable CLI interface" not in m.rstrip()
+ if legit_warning:
+ warnings.append(m)
+ return legit_warning
+
callbacks = (
# stdout goes to debug
lambda l: logger.debug(l.rstrip()),
- # stderr goes to warning
- # FIXME : filter the damn "CLI interface not stable" from apt >.>
- lambda l: logger.warning(l.rstrip()),
+ # stderr goes to warning except for the boring apt messages
+ lambda l: logger.warning(l.rstrip()) if is_legit_warning(l) else logger.debug(l.rstrip())
)
logger.info(m18n.n('updating_apt_cache'))
@@ -499,6 +508,8 @@ def tools_update(ignore_apps=False, ignore_packages=False):
# and append it to the error message to improve debugging
raise YunohostError('update_cache_failed')
+ elif warnings:
+ logger.error(m18n.n('update_cache_warning'))
packages = list(_list_upgradable_apt_packages())
logger.debug(m18n.n('done'))
From 0bd781be4735169685473f7e3969c6a45f6c0b3e Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Wed, 27 Mar 2019 15:11:11 +0100
Subject: [PATCH 074/180] [fix] Small issue with optional arguments... c.f.
issue 1261
---
src/yunohost/app.py | 18 +++++++++++-------
1 file changed, 11 insertions(+), 7 deletions(-)
diff --git a/src/yunohost/app.py b/src/yunohost/app.py
index f21352fc2..8f2de0caa 100644
--- a/src/yunohost/app.py
+++ b/src/yunohost/app.py
@@ -2257,13 +2257,17 @@ def _parse_action_args_in_yunohost_format(args, action_args, auth=None):
elif arg_default is not None:
arg_value = arg_default
- # Validate argument value
- if (arg_value is None or arg_value == '') \
- and not arg.get('optional', False):
- raise YunohostError('app_argument_required', name=arg_name)
- elif arg_value is None:
- args_dict[arg_name] = ''
- continue
+ # If the value is empty (none or '')
+ # then check if arg is optional or not
+ if arg_value is None or arg_value == '':
+ if arg.get("optional", False):
+ # Argument is optional, keep an empty value
+ # and that's all for this arg !
+ args_dict[arg_name] = ''
+ continue
+ else:
+ # The argument is required !
+ raise YunohostError('app_argument_required', name=arg_name)
# Validate argument choice
if arg_choices and arg_value not in arg_choices:
From 162eeb7e06e04ec32ed66331a184c9527fa68e82 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Wed, 27 Mar 2019 18:08:46 +0100
Subject: [PATCH 075/180] Dump sources list in error message to help debugging
---
locales/en.json | 4 ++--
src/yunohost/tools.py | 21 ++++++++++++++-------
2 files changed, 16 insertions(+), 9 deletions(-)
diff --git a/locales/en.json b/locales/en.json
index da27c7cb0..64f2e6766 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -482,8 +482,8 @@
"unit_unknown": "Unknown unit '{unit:s}'",
"unlimit": "No quota",
"unrestore_app": "App '{app:s}' will not be restored",
- "update_cache_failed": "Unable to update APT cache",
- "update_cache_warning": "Some errors happened while updating APT cache",
+ "update_apt_cache_failed": "Unable to update the cache of APT (Debian's package manager). Here is a dump of the sources.list lines which might help to identify problematic lines : \n{sourceslist}",
+ "update_apt_cache_warning": "Some errors happened while updating the cache of APT (Debian's package manager). Here is a dump of the sources.list lines which might help to identify problematic lines : \n{sourceslist}",
"updating_apt_cache": "Fetching available upgrades for system packages…",
"upgrade_complete": "Upgrade complete",
"upgrading_packages": "Upgrading packages…",
diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py
index f9d86ad09..635399801 100644
--- a/src/yunohost/tools.py
+++ b/src/yunohost/tools.py
@@ -30,6 +30,7 @@ import json
import subprocess
import pwd
import socket
+from glob import glob
from xmlrpclib import Fault
from importlib import import_module
from collections import OrderedDict
@@ -502,14 +503,9 @@ def tools_update(ignore_apps=False, ignore_packages=False):
returncode = call_async_output(command, callbacks, shell=True)
if returncode != 0:
-
- # TODO : here, we should run something like a
- # `cat /etc/apt/sources.list /etc/apt/sources.list.d/*`
- # and append it to the error message to improve debugging
-
- raise YunohostError('update_cache_failed')
+ raise YunohostError('update_apt_cache_failed', sourceslist='\n'.join(_dump_sources_list()))
elif warnings:
- logger.error(m18n.n('update_cache_warning'))
+ logger.error(m18n.n('update_apt_cache_warning', sourceslist='\n'.join(_dump_sources_list())))
packages = list(_list_upgradable_apt_packages())
logger.debug(m18n.n('done'))
@@ -567,6 +563,17 @@ def _list_upgradable_apt_packages():
}
+def _dump_sources_list():
+
+ filenames = glob("/etc/apt/sources.list") + glob("/etc/apt/sources.list.d/*")
+ for filename in filenames:
+ with open(filename, "r") as f:
+ for line in f.readlines():
+ if line.startswith("#") or not line.strip():
+ continue
+ yield filename.replace("/etc/apt/", "") + ":" + line.strip()
+
+
@is_unit_operation()
def tools_upgrade(operation_logger, auth, ignore_apps=False, ignore_packages=False):
"""
From ccdd7e645d7a745d5293a188820e6e75492330c5 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Thu, 28 Mar 2019 16:47:54 +0100
Subject: [PATCH 076/180] Be able to run the script from a distant folder
---
data/actionsmap/yunohost_completion.py | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/data/actionsmap/yunohost_completion.py b/data/actionsmap/yunohost_completion.py
index 9b5472837..915c6ac89 100644
--- a/data/actionsmap/yunohost_completion.py
+++ b/data/actionsmap/yunohost_completion.py
@@ -8,10 +8,12 @@ adds `--help` at the end if one presses [tab] again.
author: Christophe Vuillot
"""
+import os
import yaml
-ACTIONSMAP_FILE = 'yunohost.yml'
-BASH_COMPLETION_FILE = '../bash-completion.d/yunohost_completion'
+THIS_SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
+ACTIONSMAP_FILE = THIS_SCRIPT_DIR + '/yunohost.yml'
+BASH_COMPLETION_FILE = THIS_SCRIPT_DIR + '/../bash-completion.d/yunohost_completion'
with open(ACTIONSMAP_FILE, 'r') as stream:
From 8b8df94befe8906e0a05b6fc3afb23ac796b90c2 Mon Sep 17 00:00:00 2001
From: Maniack Crudelis
Date: Thu, 28 Mar 2019 19:37:23 +0100
Subject: [PATCH 077/180] Keep useful comments...
We still use eval, comment about its usage is still relevant...
---
data/helpers.d/getopts | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/data/helpers.d/getopts b/data/helpers.d/getopts
index 894c9395f..b6cd95f3c 100644
--- a/data/helpers.d/getopts
+++ b/data/helpers.d/getopts
@@ -153,6 +153,13 @@ ynh_handle_getopts_args () {
eval ${option_var}+="\;"
fi
+ # For the record.
+ # We're using eval here to get the content of the variable stored itself as simple text in $option_var...
+ # Other ways to get that content would be to use either ${!option_var} or declare -g ${option_var}
+ # But... ${!option_var} can't be used as left part of an assignation.
+ # declare -g ${option_var} will create a local variable (despite -g !) and will not be available for the helper itself.
+ # So... Stop fucking arguing each time that eval is evil... Go find an other working solution if you can find one!
+
eval ${option_var}+='"${all_args[$i]}"'
shift_value=$(( shift_value + 1 ))
fi
@@ -191,6 +198,8 @@ ynh_handle_getopts_args () {
# The variable name will be stored in 'option_var'
local option_var="${args_array[$option_flag]%=}"
+ # Store each value given as argument in the corresponding variable
+ # The values will be stored in the same order than $args_array
eval ${option_var}+='"${arguments[$i]}"'
done
unset legacy_args
From 15ac51098d9d2ae52eaa50929f843551310a4cd9 Mon Sep 17 00:00:00 2001
From: Romuald du Song
Date: Thu, 28 Mar 2019 22:03:25 +0100
Subject: [PATCH 078/180] propose a setting to remove support for TLSv1 and
TLSv1.1
---
data/hooks/conf_regen/19-postfix | 11 ++-
data/templates/postfix/main.cf | 116 ++++++++++++++++---------------
locales/en.json | 1 +
src/yunohost/settings.py | 7 ++
4 files changed, 76 insertions(+), 59 deletions(-)
diff --git a/data/hooks/conf_regen/19-postfix b/data/hooks/conf_regen/19-postfix
index a3ad70327..b37425984 100755
--- a/data/hooks/conf_regen/19-postfix
+++ b/data/hooks/conf_regen/19-postfix
@@ -2,6 +2,8 @@
set -e
+. /usr/share/yunohost/helpers
+
do_pre_regen() {
pending_dir=$1
@@ -20,9 +22,12 @@ do_pre_regen() {
main_domain=$(cat /etc/yunohost/current_host)
domain_list=$(sudo yunohost domain list --output-as plain --quiet | tr '\n' ' ')
- cat main.cf \
- | sed "s/{{ main_domain }}/${main_domain}/g" \
- > "${postfix_dir}/main.cf"
+ # Support different strategy for security configurations
+ export compatibility="$(yunohost settings get 'security.postfix.compatibility')"
+
+ export main_domain
+ export domain_list
+ ynh_render_template "main.cf" "${postfix_dir}/main.cf"
cat postsrsd \
| sed "s/{{ main_domain }}/${main_domain}/g" \
diff --git a/data/templates/postfix/main.cf b/data/templates/postfix/main.cf
index c38896a3f..e5a3875d4 100644
--- a/data/templates/postfix/main.cf
+++ b/data/templates/postfix/main.cf
@@ -33,7 +33,11 @@ smtpd_tls_key_file = /etc/yunohost/certs/{{ main_domain }}/key.pem
smtpd_tls_exclude_ciphers = aNULL, MD5, DES, ADH, RC4, 3DES
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtpd_tls_loglevel=1
+{% if compatibility == "intermediate" %}
smtpd_tls_mandatory_protocols=!SSLv2,!SSLv3
+{% else %}
+smtpd_tls_mandatory_protocols=!SSLv2,!SSLv3,!TLSv1,!TLSv1.1
+{% endif %}
smtpd_tls_mandatory_ciphers=high
smtpd_tls_eecdh_grade = ultra
@@ -58,7 +62,7 @@ alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
mydomain = {{ main_domain }}
mydestination = localhost
-relayhost =
+relayhost =
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
mailbox_command = procmail -a "$EXTENSION"
mailbox_size_limit = 0
@@ -68,71 +72,71 @@ inet_interfaces = all
#### Fit to the maximum message size to 30mb, more than allowed by GMail or Yahoo ####
message_size_limit = 31457280
-# Virtual Domains Control
-virtual_mailbox_domains = ldap:/etc/postfix/ldap-domains.cf
-virtual_mailbox_maps = ldap:/etc/postfix/ldap-accounts.cf
-virtual_mailbox_base =
-virtual_alias_maps = ldap:/etc/postfix/ldap-aliases.cf
-virtual_alias_domains =
-virtual_minimum_uid = 100
-virtual_uid_maps = static:vmail
+# Virtual Domains Control
+virtual_mailbox_domains = ldap:/etc/postfix/ldap-domains.cf
+virtual_mailbox_maps = ldap:/etc/postfix/ldap-accounts.cf
+virtual_mailbox_base =
+virtual_alias_maps = ldap:/etc/postfix/ldap-aliases.cf
+virtual_alias_domains =
+virtual_minimum_uid = 100
+virtual_uid_maps = static:vmail
virtual_gid_maps = static:mail
smtpd_sender_login_maps= ldap:/etc/postfix/ldap-accounts.cf
-# Dovecot LDA
-virtual_transport = dovecot
+# Dovecot LDA
+virtual_transport = dovecot
dovecot_destination_recipient_limit = 1
-# Enable SASL authentication for the smtpd daemon
-smtpd_sasl_auth_enable = yes
-smtpd_sasl_type = dovecot
-smtpd_sasl_path = private/auth
-# Fix some outlook's bugs
-broken_sasl_auth_clients = yes
-# Reject anonymous connections
-smtpd_sasl_security_options = noanonymous
+# Enable SASL authentication for the smtpd daemon
+smtpd_sasl_auth_enable = yes
+smtpd_sasl_type = dovecot
+smtpd_sasl_path = private/auth
+# Fix some outlook's bugs
+broken_sasl_auth_clients = yes
+# Reject anonymous connections
+smtpd_sasl_security_options = noanonymous
smtpd_sasl_local_domain =
-# Wait until the RCPT TO command before evaluating restrictions
-smtpd_delay_reject = yes
-
-# Basics Restrictions
-smtpd_helo_required = yes
-strict_rfc821_envelopes = yes
-
-# Requirements for the connecting server
-smtpd_client_restrictions =
- permit_mynetworks,
- permit_sasl_authenticated,
- reject_rbl_client bl.spamcop.net,
- reject_rbl_client cbl.abuseat.org,
- reject_rbl_client zen.spamhaus.org,
- permit
-
-# Requirements for the HELO statement
-smtpd_helo_restrictions =
- permit_mynetworks,
- permit_sasl_authenticated,
- reject_non_fqdn_hostname,
- reject_invalid_hostname,
- permit
-
-# Requirements for the sender address
+# Wait until the RCPT TO command before evaluating restrictions
+smtpd_delay_reject = yes
+
+# Basics Restrictions
+smtpd_helo_required = yes
+strict_rfc821_envelopes = yes
+
+# Requirements for the connecting server
+smtpd_client_restrictions =
+ permit_mynetworks,
+ permit_sasl_authenticated,
+ reject_rbl_client bl.spamcop.net,
+ reject_rbl_client cbl.abuseat.org,
+ reject_rbl_client zen.spamhaus.org,
+ permit
+
+# Requirements for the HELO statement
+smtpd_helo_restrictions =
+ permit_mynetworks,
+ permit_sasl_authenticated,
+ reject_non_fqdn_hostname,
+ reject_invalid_hostname,
+ permit
+
+# Requirements for the sender address
smtpd_sender_restrictions =
- reject_sender_login_mismatch,
- permit_mynetworks,
- permit_sasl_authenticated,
- reject_non_fqdn_sender,
+ reject_sender_login_mismatch,
+ permit_mynetworks,
+ permit_sasl_authenticated,
+ reject_non_fqdn_sender,
reject_unknown_sender_domain,
- permit
-
-# Requirement for the recipient address
-smtpd_recipient_restrictions =
- permit_mynetworks,
- permit_sasl_authenticated,
- reject_non_fqdn_recipient,
- reject_unknown_recipient_domain,
+ permit
+
+# Requirement for the recipient address
+smtpd_recipient_restrictions =
+ permit_mynetworks,
+ permit_sasl_authenticated,
+ reject_non_fqdn_recipient,
+ reject_unknown_recipient_domain,
reject_unauth_destination,
permit
diff --git a/locales/en.json b/locales/en.json
index 694df0707..6ab91fd2e 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -215,6 +215,7 @@
"global_settings_setting_security_password_admin_strength": "Admin password strength",
"global_settings_setting_security_password_user_strength": "User password strength",
"global_settings_setting_security_ssh_compatibility": "Compatibility vs. security tradeoff for the SSH server. Affects the ciphers (and other security-related aspects)",
+ "global_settings_setting_security_postfix_compatibility": "Compatibility vs. security tradeoff for the Postfix server. Affects the ciphers (and other security-related aspects)",
"global_settings_unknown_setting_from_settings_file": "Unknown key in settings: '{setting_key:s}', discarding it and save it in /etc/yunohost/settings-unknown.json",
"global_settings_setting_service_ssh_allow_deprecated_dsa_hostkey": "Allow the use of (deprecated) DSA hostkey for the SSH daemon configuration",
"global_settings_unknown_type": "Unexpected situation, the setting {setting:s} appears to have the type {unknown_type:s} but it's not a type supported by the system.",
diff --git a/src/yunohost/settings.py b/src/yunohost/settings.py
index 671ad70e9..01f27ba83 100644
--- a/src/yunohost/settings.py
+++ b/src/yunohost/settings.py
@@ -44,6 +44,8 @@ DEFAULTS = OrderedDict([
"choices": ["intermediate", "modern"]}),
("security.nginx.compatibility", {"type": "enum", "default": "intermediate",
"choices": ["intermediate", "modern"]}),
+ ("security.postfix.compatibility", {"type": "enum", "default": "intermediate",
+ "choices": ["intermediate", "modern"]}),
])
@@ -292,3 +294,8 @@ def reconfigure_nginx(setting_name, old_value, new_value):
def reconfigure_ssh(setting_name, old_value, new_value):
if old_value != new_value:
service_regen_conf(names=['ssh'])
+
+@post_change_hook("security.postfix.compatibility")
+def reconfigure_ssh(setting_name, old_value, new_value):
+ if old_value != new_value:
+ service_regen_conf(names=['postfix'])
From 0a3f12ed58d37e5722311041d8e696ebd6f52150 Mon Sep 17 00:00:00 2001
From: Laurent Peuch
Date: Sun, 31 Mar 2019 04:10:23 +0200
Subject: [PATCH 079/180] [mod] use ask key for display_text instead and
support i18n
---
src/yunohost/app.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/yunohost/app.py b/src/yunohost/app.py
index 8561e2667..70d21afb1 100644
--- a/src/yunohost/app.py
+++ b/src/yunohost/app.py
@@ -2204,7 +2204,7 @@ def _parse_action_args_in_yunohost_format(args, action_args, auth=None):
# do not print for webadmin
if arg_type == 'display_text' and msettings.get('interface') != 'api':
- print(arg["text"])
+ print(_value_for_locale(arg['ask']))
continue
# Attempt to retrieve argument value
From 26e77b77ffe08f1c5a03eb22e9ad2f3ca0167cee Mon Sep 17 00:00:00 2001
From: Maniack Crudelis
Date: Mon, 1 Apr 2019 21:24:15 +0200
Subject: [PATCH 080/180] Force stdout to stderr in ynh_debug
Merge as a micro decision.
---
data/helpers.d/debug | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/data/helpers.d/debug b/data/helpers.d/debug
index ea20ffc1a..7ad097dbd 100644
--- a/data/helpers.d/debug
+++ b/data/helpers.d/debug
@@ -37,6 +37,8 @@ ynh_debug () {
PS4='$(basename ${BASH_SOURCE[0]})-L${LINENO}: '
# Force xtrace to stderr
BASH_XTRACEFD=2
+ # Force stdout to stderr
+ exec 1>&2
fi
if [ "$trace" == "0" ]
then
@@ -44,6 +46,8 @@ ynh_debug () {
set +x
# Put xtrace back to its original fild descriptor
BASH_XTRACEFD=$old_bash_xtracefd
+ # Restore stdout
+ exec 1>&1
fi
# Renable set xtrace
set -x
From b3d8167548803364b62ecb8cafafe0f78802497c Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Tue, 2 Apr 2019 01:53:10 +0200
Subject: [PATCH 081/180] Generate yunohost_completion.py during debian builds
---
data/bash-completion.d/yunohost | 15 +----
data/bash-completion.d/yunohost_completion | 77 ----------------------
debian/rules | 4 ++
3 files changed, 7 insertions(+), 89 deletions(-)
delete mode 100644 data/bash-completion.d/yunohost_completion
diff --git a/data/bash-completion.d/yunohost b/data/bash-completion.d/yunohost
index 106f8fbdf..2572a391d 100644
--- a/data/bash-completion.d/yunohost
+++ b/data/bash-completion.d/yunohost
@@ -1,12 +1,3 @@
-#
-# Bash completion for yunohost
-#
-
-_python_argcomplete() {
- local IFS=''
- COMPREPLY=( $(IFS="$IFS" COMP_LINE="$COMP_LINE" COMP_POINT="$COMP_POINT" _ARGCOMPLETE_COMP_WORDBREAKS="$COMP_WORDBREAKS" _ARGCOMPLETE=1 "$1" 8>&1 9>&2 1>/dev/null 2>/dev/null) )
- if [[ $? != 0 ]]; then
- unset COMPREPLY
- fi
-}
-complete -o nospace -o default -F _python_argcomplete "yunohost"
+# This file is automatically generated
+# during Debian's package build by the script
+# data/actionsmap/yunohost_completion.py
diff --git a/data/bash-completion.d/yunohost_completion b/data/bash-completion.d/yunohost_completion
deleted file mode 100644
index 715073475..000000000
--- a/data/bash-completion.d/yunohost_completion
+++ /dev/null
@@ -1,77 +0,0 @@
-#
-# completion for yunohost
-# automatically generated from the actionsmap
-#
-
-_yunohost_completion()
-{
- local cur prev opts narg
- COMPREPLY=()
-
- # the number of words already typed
- narg=${#COMP_WORDS[@]}
-
- # the current word being typed
- cur="${COMP_WORDS[COMP_CWORD]}"
-
- # the last typed word
- prev="${COMP_WORDS[COMP_CWORD-1]}"
-
- # If one is currently typing a domain,
- # match with domains
- if [[ $narg == 2 ]]; then
- opts="user domain log service settings firewall backup app hook dyndns tools monitor"
- fi
-
- # If one already typed a domain,
- # match the actions of that domain
- if [[ $narg == 3 ]]; then
- if [[ $prev == "user" ]]; then
- opts="info create list update delete"
- fi
- if [[ $prev == "domain" ]]; then
- opts="cert-install cert-status list remove url-available add dns-conf cert-renew"
- fi
- if [[ $prev == "log" ]]; then
- opts="list display"
- fi
- if [[ $prev == "service" ]]; then
- opts="status enable reload_or_restart log start stop remove reload add disable regen-conf restart"
- fi
- if [[ $prev == "settings" ]]; then
- opts="reset set list reset-all get"
- fi
- if [[ $prev == "firewall" ]]; then
- opts="reload allow stop list upnp disallow"
- fi
- if [[ $prev == "backup" ]]; then
- opts="info restore create list delete"
- fi
- if [[ $prev == "app" ]]; then
- opts="map checkurl install makedefault checkport listlists change-url removelist info change-label upgrade fetchlist clearaccess ssowatconf list remove register-url removeaccess setting initdb debug addaccess"
- fi
- if [[ $prev == "hook" ]]; then
- opts="info callback add exec list remove"
- fi
- if [[ $prev == "dyndns" ]]; then
- opts="subscribe update installcron removecron"
- fi
- if [[ $prev == "tools" ]]; then
- opts="upgrade ldapinit postinstall maindomain update reboot shell adminpw shutdown diagnosis port-available"
- fi
- if [[ $prev == "monitor" ]]; then
- opts="enable network show-stats update-stats disk system disable"
- fi
- fi
-
- # If no options were found propose --help
- if [ -z "$opts" ]; then
- if [[ $prev != "--help" ]]; then
- opts=( --help )
- fi
- fi
- COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
- return 0
-}
-
-complete -F _yunohost_completion yunohost
\ No newline at end of file
diff --git a/debian/rules b/debian/rules
index ce03d0e31..d012c73f3 100755
--- a/debian/rules
+++ b/debian/rules
@@ -7,6 +7,10 @@
%:
dh ${@} --with=python2,systemd
+override_dh_auto_build:
+ # Generate bash completion file
+ python data/actionsmap/yunohost_completion.py
+
override_dh_installinit:
dh_installinit -pyunohost --name=yunohost-api --restart-after-upgrade
dh_installinit -pyunohost --name=yunohost-firewall --noscripts
From 0c67559c43ba50a5d069888b1a5ea00fd3f7f21c Mon Sep 17 00:00:00 2001
From: Maniack Crudelis
Date: Tue, 2 Apr 2019 12:33:49 +0200
Subject: [PATCH 082/180] Fix missing legacy_args
Merged as a micro decision
---
data/helpers.d/print | 1 +
1 file changed, 1 insertion(+)
diff --git a/data/helpers.d/print b/data/helpers.d/print
index 95d2af139..f1120367a 100644
--- a/data/helpers.d/print
+++ b/data/helpers.d/print
@@ -201,6 +201,7 @@ previous_weight=0
base_time=$(date +%s)
ynh_script_progression () {
# Declare an array to define the options of this helper.
+ local legacy_args=mwtl
declare -Ar args_array=( [m]=message= [w]=weight= [t]=time [l]=last )
local message
local weight
From 92b5777aff64c8e7c914dea4bd050bceb6aeb32a Mon Sep 17 00:00:00 2001
From: Maniack Crudelis
Date: Tue, 2 Apr 2019 12:36:17 +0200
Subject: [PATCH 083/180] Fix missing legacy_args
Merged as a micro decision
---
data/helpers.d/system | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/data/helpers.d/system b/data/helpers.d/system
index c4c049c31..a491b19b5 100644
--- a/data/helpers.d/system
+++ b/data/helpers.d/system
@@ -75,6 +75,7 @@ ynh_get_debian_release () {
# | arg: -e, --length= - Length of the error log : Default : 20
ynh_systemd_action() {
# Declare an array to define the options of this helper.
+ local legacy_args=nalpte
declare -Ar args_array=( [n]=service_name= [a]=action= [l]=line_match= [p]=log_path= [t]=timeout= [e]=length= )
local service_name
local action
@@ -175,6 +176,7 @@ ynh_clean_check_starting () {
# Requires YunoHost version 3.?.? or higher.
ynh_read_manifest () {
# Declare an array to define the options of this helper.
+ local legacy_args=mk
declare -Ar args_array=( [m]=manifest= [k]=manifest_key= )
local manifest
local manifest_key
@@ -200,6 +202,8 @@ ynh_read_manifest () {
#
# Requires YunoHost version 3.?.? or higher.
ynh_app_upstream_version () {
+ # Declare an array to define the options of this helper.
+ local legacy_args=m
declare -Ar args_array=( [m]=manifest= )
local manifest
# Manage arguments with getopts
@@ -221,6 +225,8 @@ ynh_app_upstream_version () {
#
# Requires YunoHost version 3.?.? or higher.
ynh_app_package_version () {
+ # Declare an array to define the options of this helper.
+ local legacy_args=m
declare -Ar args_array=( [m]=manifest= )
local manifest
# Manage arguments with getopts
From 9766a73e0d0fb39172984419f516bca417cb2d7d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?M=C3=A9lanie=20Chauvel?=
Date: Mon, 18 Mar 2019 18:24:46 +0000
Subject: [PATCH 084/180] Translated using Weblate (French)
Currently translated at 99.4% (501 of 504 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 b864c5ac7..6a41ff45b 100644
--- a/locales/fr.json
+++ b/locales/fr.json
@@ -471,7 +471,7 @@
"service_description_php7.0-fpm": "exécute des applications écrites en PHP avec nginx",
"users_available": "Liste des utilisateurs disponibles :",
"good_practices_about_admin_password": "Vous êtes maintenant sur le point de définir un nouveau mot de passe d’administration. Le mot de passe doit comporter au moins 8 caractères – bien qu’il soit recommandé d’utiliser un mot de passe plus long (c’est-à-dire une phrase de chiffrement) et/ou d’utiliser différents types de caractères (majuscules, minuscules, chiffres et caractères spéciaux).",
- "good_practices_about_user_password": "Vous êtes maintenant sur le point de définir un nouveau mot de passe utilisateur. Le mot de passe doit comporter au moins 8 caractères - bien qu'il soit recommandé d'utiliser un mot de passe plus long (c'est-à-dire une phrase secrète) et/ou d'utiliser différents types de caractères (majuscules, minuscules, chiffres et caractères spéciaux).",
+ "good_practices_about_user_password": "Vous êtes maintenant sur le point de définir un nouveau mot de passe utilisateur. Le mot de passe doit comporter au moins 8 caractères — bien qu'il soit recommandé d'utiliser un mot de passe plus long (c'est-à-dire une phrase secrète) et/ou d'utiliser différents types de caractères (majuscules, minuscules, chiffres et caractères spéciaux).",
"migration_description_0006_sync_admin_and_root_passwords": "Synchroniser les mots de passe admin et root",
"migration_0006_disclaimer": "Yunohost s’attend maintenant à ce que les mots de passe admin et root soient synchronisés. En exécutant cette migration, votre mot de passe root sera remplacé par le mot de passe administrateur.",
"migration_0006_done": "Votre mot de passe root a été remplacé par celui de votre adminitrateur.",
From 92a097ea50209b0af41fb39bb03f655d57784d4b Mon Sep 17 00:00:00 2001
From: ppr
Date: Tue, 19 Mar 2019 07:52:39 +0000
Subject: [PATCH 085/180] Translated using Weblate (French)
Currently translated at 99.4% (501 of 504 strings)
Translation: YunoHost/core
Translate-URL: https://translate.yunohost.org/projects/yunohost/core/fr/
---
locales/fr.json | 58 ++++++++++++++++++++++++-------------------------
1 file changed, 29 insertions(+), 29 deletions(-)
diff --git a/locales/fr.json b/locales/fr.json
index 6a41ff45b..bea929837 100644
--- a/locales/fr.json
+++ b/locales/fr.json
@@ -1,13 +1,13 @@
{
- "action_invalid": "Action « {action:s} » incorrecte",
+ "action_invalid": "Action '{action:s}' incorrecte",
"admin_password": "Mot de passe d’administration",
"admin_password_change_failed": "Impossible de changer le mot de passe",
"admin_password_changed": "Le mot de passe d’administration a été modifié",
"app_already_installed": "{app:s} est déjà installé",
- "app_argument_choice_invalid": "Choix invalide pour le paramètre « {name:s} », il doit être l’un de {choices:s}",
- "app_argument_invalid": "Valeur invalide pour le paramètre `{name:s}` : {error:s}",
+ "app_argument_choice_invalid": "Choix invalide pour le paramètre '{name:s}', il doit être l’un de {choices:s}",
+ "app_argument_invalid": "Valeur invalide pour le paramètre '{name:s}' : {error:s}",
"app_argument_missing": "Paramètre manquant « {:s} »",
- "app_argument_required": "Le paramètre `{name:s}` est requis",
+ "app_argument_required": "Le paramètre '{name:s}' est requis",
"app_extraction_failed": "Impossible d’extraire les fichiers d’installation",
"app_id_invalid": "Identifiant d’application invalide",
"app_incompatible": "L’application {app} est incompatible avec votre version de YunoHost",
@@ -35,7 +35,7 @@
"appslist_retrieve_error": "Impossible de récupérer la liste d’applications distante {appslist:s} : {error:s}",
"appslist_unknown": "La liste d’applications {appslist:s} est inconnue.",
"ask_current_admin_password": "Mot de passe d’administration actuel",
- "ask_email": "Adresse courriel",
+ "ask_email": "Adresse de courriel",
"ask_firstname": "Prénom",
"ask_lastname": "Nom",
"ask_list_to_remove": "Liste à supprimer",
@@ -43,7 +43,7 @@
"ask_new_admin_password": "Nouveau mot de passe d’administration",
"ask_password": "Mot de passe",
"backup_action_required": "Vous devez préciser ce qui est à sauvegarder",
- "backup_app_failed": "Impossible de sauvegarder l’application « {app:s} »",
+ "backup_app_failed": "Impossible de sauvegarder l’application '{app:s}'",
"backup_archive_app_not_found": "L’application '{app:s}' n’a pas été trouvée dans l’archive de la sauvegarde",
"backup_archive_hook_not_exec": "Le script « {hook:s} » n'a pas été exécuté dans cette sauvegarde",
"backup_archive_name_exists": "Une archive de sauvegarde avec ce nom existe déjà",
@@ -60,8 +60,8 @@
"backup_invalid_archive": "Archive de sauvegarde invalide",
"backup_nothings_done": "Il n’y a rien à sauvegarder",
"backup_output_directory_forbidden": "Dossier de destination interdit. Les sauvegardes ne peuvent être créées dans les sous-dossiers /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var ou /home/yunohost.backup/archives",
- "backup_output_directory_not_empty": "Le dossier de sortie n’est pas vide",
- "backup_output_directory_required": "Vous devez spécifier un dossier de sortie pour la sauvegarde",
+ "backup_output_directory_not_empty": "Le répertoire de destination n'est pas vide",
+ "backup_output_directory_required": "Vous devez spécifier un dossier de destination pour la sauvegarde",
"backup_running_app_script": "Lancement du script de sauvegarde de l’application « {app:s} »...",
"backup_running_hooks": "Exécution des scripts de sauvegarde …",
"custom_app_url_required": "Vous devez spécifier une URL pour mettre à jour votre application personnalisée {app:s}",
@@ -255,7 +255,7 @@
"certmanager_certificate_fetching_or_enabling_failed": "Il semble que l’activation du nouveau certificat pour {domain:s} a échoué …",
"certmanager_attempt_to_renew_nonLE_cert": "Le certificat pour le domaine {domain:s} n’est pas émis par Let’s Encrypt. Impossible de le renouveler automatiquement !",
"certmanager_attempt_to_renew_valid_cert": "Le certificat pour le domaine {domain:s} est sur le point d’expirer ! Utilisez --force pour contourner cela",
- "certmanager_domain_http_not_working": "Il semble que le domaine {domain:s} n’est pas accessible via HTTP. Veuillez vérifier que vos configuration DNS et Nginx sont correctes",
+ "certmanager_domain_http_not_working": "Il semble que le domaine {domain:s} ne soit pas accessible via HTTP. Veuillez vérifier que vos configuration DNS et Nginx sont correctes",
"certmanager_error_no_A_record": "Aucun enregistrement DNS 'A' n’a été trouvé pour {domain:s}. Vous devez faire pointer votre nom de domaine vers votre machine pour être en mesure d’installer un certificat Let’s Encrypt ! (Si vous savez ce que vous faites, utilisez --no-checks pour désactiver ces contrôles)",
"certmanager_domain_dns_ip_differs_from_public_ip": "L’enregistrement DNS 'A' du domaine {domain:s} est différent de l’adresse IP de ce serveur. Si vous avez récemment modifié votre enregistrement 'A', veuillez attendre sa propagation (quelques vérificateur de propagation DNS sont disponibles en ligne). (Si vous savez ce que vous faites, utilisez --no-checks pour désactiver ces contrôles)",
"certmanager_cannot_read_cert": "Quelque chose s’est mal passé lors de la tentative d’ouverture du certificat actuel pour le domaine {domain:s} (fichier : {file:s}), la cause est : {reason:s}",
@@ -264,13 +264,13 @@
"certmanager_cert_renew_success": "Renouvellement avec succès d’un certificat Let’s Encrypt pour le domaine {domain:s} !",
"certmanager_old_letsencrypt_app_detected": "\nYunoHost a détecté que l’application « letsencrypt » est installé, ce qui est en conflit avec les nouvelles fonctionnalités de gestion intégrée de certificats dans YunoHost. Si vous souhaitez utiliser ces nouvelles fonctionnalités intégrées, veuillez lancer les commandes suivantes pour migrer votre installation :\n\n yunohost app remove letsencrypt\n yunohost domain cert-install\n\nN.B. : cela tentera de réinstaller les certificats de tous les domaines avec un certificat Let's Encrypt ou ceux auto-signés",
"certmanager_cert_signing_failed": "La signature du nouveau certificat a échoué",
- "certmanager_no_cert_file": "Impossible de lire le fichier de certificat pour le domaine {domain:s} (fichier : {file:s})",
+ "certmanager_no_cert_file": "Impossible de lire le fichier de/du certificat pour le domaine {domain:s} (fichier : {file:s})",
"certmanager_conflicting_nginx_file": "Impossible de préparer le domaine pour le défi ACME : le fichier de configuration Nginx {filepath:s} est en conflit et doit être préalablement retiré",
"certmanager_hit_rate_limit": "Trop de certificats ont déjà été émis récemment pour ce même ensemble de domaines {domain:s}. Veuillez réessayer plus tard. Lisez https://letsencrypt.org/docs/rate-limits/ pour obtenir plus de détails sur les ratios et limitations",
"ldap_init_failed_to_create_admin": "L’initialisation de LDAP n’a pas réussi à créer l’utilisateur admin",
"ssowat_persistent_conf_read_error": "Erreur lors de la lecture de la configuration persistante de SSOwat : {error:s}. Modifiez le fichier /etc/ssowat/conf.json.persistent pour réparer la syntaxe JSON",
"ssowat_persistent_conf_write_error": "Erreur lors de la sauvegarde de la configuration persistante de SSOwat : {error:s}. Modifiez le fichier /etc/ssowat/conf.json.persistent pour réparer la syntaxe JSON",
- "domain_cannot_remove_main": "Impossible de supprimer le domaine principal. Commencez par définir un nouveau domaine principal",
+ "domain_cannot_remove_main": "Impossible de supprimer le domaine principal. Définissez d'abord un nouveau domaine principal",
"certmanager_self_ca_conf_file_not_found": "Le fichier de configuration pour l’autorité du certificat auto-signé est introuvable (fichier : {file:s})",
"certmanager_unable_to_parse_self_CA_name": "Impossible d’analyser le nom de l’autorité du certificat auto-signé (fichier : {file:s})",
"mailbox_used_space_dovecot_down": "Le service mail Dovecot doit être démarré, si vous souhaitez voir l’espace disque occupé par la messagerie",
@@ -279,7 +279,7 @@
"certmanager_acme_not_configured_for_domain": "Le certificat du domaine {domain:s} ne semble pas être correctement installé. Veuillez d'abord exécuter cert-install.",
"certmanager_domain_not_resolved_locally": "Le domaine {domain:s} ne peut être résolu depuis votre serveur YunoHost. Cela peut se produire si vous avez récemment modifié votre enregistrement DNS. Si c'est le cas, merci d’attendre quelques heures qu’il se propage. Si le problème persiste, envisager d’ajouter {domain:s} au fichier /etc/hosts. (Si vous savez ce que vous faites, utilisez --no-checks pour désactiver ces vérifications.)",
"certmanager_http_check_timeout": "Expiration du délai lorsque le serveur a essayé de se contacter lui-même via HTTP en utilisant l'adresse IP public {ip:s} du domaine {domain:s}. Vous rencontrez peut-être un problème d’hairpinning ou alors le pare-feu/routeur en amont de votre serveur est mal configuré.",
- "certmanager_couldnt_fetch_intermediate_cert": "Expiration du délai lors de la tentative de récupération du certificat intermédiaire depuis Let’s Encrypt. L’installation ou le renouvellement du certificat a été annulé - veuillez réessayer plus tard.",
+ "certmanager_couldnt_fetch_intermediate_cert": "Expiration du délai lors de la tentative de récupération du certificat intermédiaire depuis Let’s Encrypt. L’installation ou le renouvellement du certificat a été annulé. Veuillez réessayer plus tard.",
"appslist_retrieve_bad_format": "Le fichier récupéré pour la liste d’applications {appslist:s} n’est pas valide",
"domain_hostname_failed": "Échec de la création d’un nouveau nom d’hôte",
"yunohost_ca_creation_success": "L’autorité de certification locale a été créée.",
@@ -288,39 +288,39 @@
"appslist_migrating": "Migration de la liste d’applications {appslist:s} …",
"appslist_could_not_migrate": "Impossible de migrer la liste {appslist:s} ! Impossible d’exploiter l’URL. L’ancienne tâche programmée a été conservée dans {bkp_file:s}.",
"appslist_corrupted_json": "Impossible de charger la liste d’applications. Il semble que {filename:s} soit corrompu.",
- "app_already_installed_cant_change_url": "Cette application est déjà installée. L’URL ne peut pas être changé simplement par cette fonction. Regardez avec `app changeurl` si c’est disponible.",
+ "app_already_installed_cant_change_url": "Cette application est déjà installée. L’URL ne peut pas être changé simplement par cette fonction. Regardez si cela est disponible avec `app changeurl`.",
"app_change_no_change_url_script": "L’application {app_name:s} ne prend pas encore en charge le changement d’URL, vous pourriez avoir besoin de la mettre à jour.",
- "app_change_url_failed_nginx_reload": "Le redémarrage de nginx a échoué. Voici la sortie de `nginx -t` :\n{nginx_errors:s}",
- "app_change_url_identical_domains": "L’ancien et le nouveau couple domaine/chemin_de_l'URL sont identiques pour (`{domain:s}{path:s}`), rien à faire.",
- "app_change_url_no_script": "L’application `{app_name:s}` ne prend pas encore en charge le changement d’URL. Vous devriez peut-être la mettre à jour.",
+ "app_change_url_failed_nginx_reload": "Le redémarrage de Nginx a échoué. Voici la sortie de 'nginx -t' :\n{nginx_errors:s}",
+ "app_change_url_identical_domains": "L’ancien et le nouveau couple domaine/chemin_de_l'URL sont identiques pour ('{domain:s}{path:s}'), rien à faire.",
+ "app_change_url_no_script": "L’application '{app_name:s}' ne prend pas encore en charge le changement d’URL. Vous devriez peut-être la mettre à jour.",
"app_change_url_success": "L’URL de l’application {app:s} a été changée en {domain:s}{path:s}",
- "app_location_unavailable": "Cette URL n’est pas disponible ou est en conflit avec une application existante\n{apps:s}",
+ "app_location_unavailable": "Cette URL n’est pas disponible ou est en conflit avec une application existante :\n{apps:s}",
"app_already_up_to_date": "{app:s} est déjà à jour",
"invalid_url_format": "Format d’URL non valide",
- "global_settings_bad_choice_for_enum": "La valeur du paramètre {setting:s} est incorrecte. Reçu : {received_type:s} mais attendu : {expected_type:s}",
- "global_settings_bad_type_for_setting": "Le type du paramètre {setting:s} est incorrect. Reçu : {received_type:s} mais attendu : {expected_type:s}",
+ "global_settings_bad_choice_for_enum": "La valeur du paramètre {setting:s} est incorrecte. Reçu {received_type:s} alors que {expected_type:s} était attendu",
+ "global_settings_bad_type_for_setting": "Le type du paramètre {setting:s} est incorrect. Reçu {received_type:s} alors que {expected_type:s} était attendu",
"global_settings_cant_open_settings": "Échec de l’ouverture du ficher de configurations car : {reason:s}",
"global_settings_cant_serialize_setings": "Échec de sérialisation des données de configurations, cause : {reason:s}",
"global_settings_cant_write_settings": "Échec d’écriture du fichier de configurations car : {reason:s}",
"global_settings_key_doesnt_exists": "La clef '{settings_key:s}' n’existe pas dans les configurations générales, vous pouvez voir toutes les clefs disponibles en saisissant 'yunohost settings list'",
- "global_settings_reset_success": "Réussite ! Vos configurations précédentes ont été sauvegardées dans {path:s}",
+ "global_settings_reset_success": "Super ! Vos configurations précédentes ont été sauvegardées dans {path:s}",
"global_settings_setting_example_bool": "Exemple d’option booléenne",
"global_settings_setting_example_int": "Exemple d’option de type entier",
"global_settings_setting_example_string": "Exemple d’option de type chaîne",
"global_settings_setting_example_enum": "Exemple d’option de type énumération",
- "global_settings_unknown_type": "Situation inattendue, la configuration {setting:s} semble avoir le type {unknown_type:s} mais celui-ci n'est pas pris en charge par le système.",
+ "global_settings_unknown_type": "Situation inattendue : la configuration {setting:s} semble avoir le type {unknown_type:s} mais celui-ci n'est pas pris en charge par le système.",
"global_settings_unknown_setting_from_settings_file": "Clef inconnue dans les paramètres : '{setting_key:s}', rejet de cette clef et sauvegarde de celle-ci dans /etc/yunohost/unkown_settings.json",
"service_conf_new_managed_file": "Le fichier de configuration « {conf} » est désormais géré par le service {service}.",
"service_conf_file_kept_back": "Le fichier de configuration « {conf} » devrait être supprimé par le service {service} mais a été conservé.",
"backup_abstract_method": "Cette méthode de sauvegarde n’a pas encore été implémentée",
"backup_applying_method_tar": "Création de l’archive tar de la sauvegarde …",
"backup_applying_method_copy": "Copie de tous les fichiers à sauvegarder …",
- "backup_applying_method_borg": "Envoi de tous les fichiers à sauvegarder dans de référentiel borg-backup …",
+ "backup_applying_method_borg": "Envoi de tous les fichiers à sauvegarder dans le référentiel/répertoire borg-backup …",
"backup_applying_method_custom": "Appel de la méthode de sauvegarde personnalisée '{method:s}' …",
"backup_archive_system_part_not_available": "La partie '{part:s}' du système n’est pas disponible dans cette sauvegarde",
"backup_archive_mount_failed": "Le montage de l’archive de sauvegarde a échoué",
"backup_archive_writing_error": "Impossible d'ajouter des fichiers '{source:s}' (nommés dans l'archive : '{dest:s}') à sauvegarder dans l'archive compressée '{archive:s}'",
- "backup_ask_for_copying_if_needed": "Certains fichiers n’ont pas pu être préparés pour être sauvegardés en utilisant la méthode qui évite temporairement de gaspiller de l’espace sur le système. Pour mener la sauvegarde, {size:s} Mo doivent être temporairement utilisés. Acceptez-vous ?",
+ "backup_ask_for_copying_if_needed": "Certains fichiers n’ont pas pu être préparés pour être sauvegardés en utilisant la méthode qui évite temporairement de gaspiller de l’espace sur le système. Pour réaliser la sauvegarde, {size:s} Mo doivent être temporairement utilisés. Acceptez-vous ?",
"backup_borg_not_implemented": "La méthode de sauvegarde Borg n’est pas encore implémentée",
"backup_cant_mount_uncompress_archive": "Impossible de monter en lecture seule le dossier de l’archive décompressée",
"backup_copying_to_organize_the_archive": "Copie de {size:s} Mo pour organiser l’archive",
@@ -346,8 +346,8 @@
"restore_not_enough_disk_space": "Espace disponible insuffisant (libre : {free_space:d} octets, nécessaire : {needed_space:d} octets, marge de sécurité : {margin:d} octets)",
"restore_system_part_failed": "Impossible de restaurer la partie « {part:s} » du système",
"backup_couldnt_bind": "Impossible de lier {src:s} avec {dest:s}.",
- "domain_dns_conf_is_just_a_recommendation": "Cette page montre la configuration *recommandée*. Elle ne configure *pas* le DNS pour vous. Il est de votre responsabilité que de configurer votre zone DNS chez votre registrar DNS avec cette recommandation.",
- "domain_dyndns_dynette_is_unreachable": "Impossible de contacter la dynette YunoHost, soit YunoHost n’est pas correctement connecté à internet ou alors le serveur de dynette est arrêté. Erreur : {error}",
+ "domain_dns_conf_is_just_a_recommendation": "Cette page montre la configuration *recommandée*. Elle ne configure *pas* le DNS pour vous. Il est de votre responsabilité que de configurer votre zone DNS chez votre fournisseur/registrar DNS avec cette recommandation.",
+ "domain_dyndns_dynette_is_unreachable": "Impossible de contacter la dynette YunoHost. Soit YunoHost n’est pas correctement connecté à internet, soit le serveur de dynette est en panne ou ne répond pas. Erreur : {error}",
"migrations_backward": "Migration en arrière.",
"migrations_bad_value_for_target": "Nombre invalide pour le paramètre « target », les numéros de migration sont ou {}",
"migrations_cant_reach_migration_file": "Impossible d’accéder aux fichiers de migrations avec le chemin %s",
@@ -368,7 +368,7 @@
"ask_path": "Chemin",
"dyndns_could_not_check_provide": "Impossible de vérifier si {provider:s} peut fournir {domain:s}.",
"dyndns_domain_not_provided": "Le fournisseur DynDNS {provider:s} ne peut pas fournir le domaine {domain:s}.",
- "app_make_default_location_already_used": "Impossible de configurer l’application '{app}' par défaut pour le domaine {domain} car déjà utilisé par l'application '{other_app}'",
+ "app_make_default_location_already_used": "Impossible de configurer l’application '{app}' par défaut pour le domaine {domain} car il est déjà utilisé par l'application '{other_app}'",
"app_upgrade_app_name": "Mise à jour de l’application {app} …",
"backup_output_symlink_dir_broken": "Vous avez un lien symbolique cassé à la place de votre dossier d’archives '{path:s}'. Vous pourriez avoir une configuration personnalisée pour sauvegarder vos données sur un autre système de fichiers, dans ce cas, vous avez probablement oublié de monter ou de connecter votre disque dur ou votre clef USB.",
"migrate_tsig_end": "La migration à hmac-sha512 est terminée",
@@ -470,7 +470,7 @@
"recommend_to_add_first_user": "La post-installation est terminée, mais YunoHost a besoin d’au moins un utilisateur pour fonctionner correctement. Vous devez en ajouter un en utilisant « yunohost user create » ou l’interface d’administration.",
"service_description_php7.0-fpm": "exécute des applications écrites en PHP avec nginx",
"users_available": "Liste des utilisateurs disponibles :",
- "good_practices_about_admin_password": "Vous êtes maintenant sur le point de définir un nouveau mot de passe d’administration. Le mot de passe doit comporter au moins 8 caractères – bien qu’il soit recommandé d’utiliser un mot de passe plus long (c’est-à-dire une phrase de chiffrement) et/ou d’utiliser différents types de caractères (majuscules, minuscules, chiffres et caractères spéciaux).",
+ "good_practices_about_admin_password": "Vous êtes maintenant sur le point de définir un nouveau mot de passe d’administration. Le mot de passe doit comporter au moins 8 caractères – bien qu’il soit recommandé d’utiliser un mot de passe plus long (c’est-à-dire une phrase secrète) et/ou d’utiliser différents types de caractères (majuscules, minuscules, chiffres et caractères spéciaux).",
"good_practices_about_user_password": "Vous êtes maintenant sur le point de définir un nouveau mot de passe utilisateur. Le mot de passe doit comporter au moins 8 caractères — bien qu'il soit recommandé d'utiliser un mot de passe plus long (c'est-à-dire une phrase secrète) et/ou d'utiliser différents types de caractères (majuscules, minuscules, chiffres et caractères spéciaux).",
"migration_description_0006_sync_admin_and_root_passwords": "Synchroniser les mots de passe admin et root",
"migration_0006_disclaimer": "Yunohost s’attend maintenant à ce que les mots de passe admin et root soient synchronisés. En exécutant cette migration, votre mot de passe root sera remplacé par le mot de passe administrateur.",
@@ -492,9 +492,9 @@
"ask_new_path": "Nouveau chemin",
"backup_actually_backuping": "Création d'une archive de sauvegarde à partir des fichiers collectés …",
"backup_mount_archive_for_restore": "Préparation de l'archive pour restauration …",
- "confirm_app_install_warning": "Avertissement : cette application peut fonctionner mais n'est pas bien intégrée dans YunoHost. Certaines fonctionnalités telles que l'authentification unique et la sauvegarde/restauration peuvent ne pas être disponibles. L'installer quand même ? [{réponses:s}] ",
+ "confirm_app_install_warning": "Avertissement : cette application peut fonctionner mais n'est pas bien intégrée dans YunoHost. Certaines fonctionnalités telles que l'authentification unique et la sauvegarde/restauration peuvent ne pas être disponibles. L'installer quand même ? [{answers:s}] ",
"confirm_app_install_danger": "AVERTISSEMENT ! Cette application est encore expérimentale (explicitement, elle ne fonctionne pas) et risque de casser votre système ! Vous ne devriez probablement PAS l'installer sans savoir ce que vous faites. Êtes-vous prêt à prendre ce risque ? [{answers:s}] ",
- "confirm_app_install_thirdparty": "AVERTISSEMENT ! L'installation d'applications tierces peut compromettre l'intégrité et la sécurité de votre système. Vous ne devriez probablement PAS l'installer si vous ne savez pas ce que vous faites. Êtes-vous prêt à prendre ce risque ? [{réponses:s}] ",
+ "confirm_app_install_thirdparty": "AVERTISSEMENT ! L'installation d'applications tierces peut compromettre l'intégrité et la sécurité de votre système. Vous ne devriez probablement PAS l'installer si vous ne savez pas ce que vous faites. Êtes-vous prêt à prendre ce risque ? [{answers:s}] ",
"dpkg_is_broken": "Vous ne pouvez pas faire ça maintenant car dpkg/apt (le gestionnaire de paquets du système) semble avoir laissé des choses non configurées. Vous pouvez essayer de résoudre ce problème en vous connectant via SSH et en exécutant `sudo dpkg --configure -a'.",
"dyndns_could_not_check_available": "Impossible de vérifier si {domain:s} est disponible chez {provider:s}.",
"file_does_not_exist": "Le fichier dont le chemin est {path:s} n'existe pas.",
From 63912c25f4ef986a8cb634cc050f7774fac93e31 Mon Sep 17 00:00:00 2001
From: xaloc33
Date: Sun, 17 Mar 2019 16:20:39 +0000
Subject: [PATCH 086/180] Translated using Weblate (Catalan)
Currently translated at 22.6% (114 of 504 strings)
Translation: YunoHost/core
Translate-URL: https://translate.yunohost.org/projects/yunohost/core/ca/
---
locales/ca.json | 48 ++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 40 insertions(+), 8 deletions(-)
diff --git a/locales/ca.json b/locales/ca.json
index bfad4d2bd..44d473d91 100644
--- a/locales/ca.json
+++ b/locales/ca.json
@@ -29,20 +29,20 @@
"app_not_properly_removed": "{app:s} no s'ha pogut suprimir correctament",
"app_package_need_update": "El paquet de l'aplicació {app} ha de ser actualitzat per poder seguir els canvis de YunoHost",
"app_removed": "{app:s} ha estat suprimida",
- "app_requirements_checking": "Verificació dels paquets requerits per {app}",
+ "app_requirements_checking": "Verificació dels paquets requerits per {app}…",
"app_requirements_failed": "No es poden satisfer els requeriments per {app}: {error}",
"app_requirements_unmeet": "No es compleixen els requeriments per {app}, el paquet {pkgname} ({version}) ha de ser {spec}",
"app_sources_fetch_failed": "No s'han pogut carregar els fitxers font",
"app_unknown": "Aplicació desconeguda",
"app_unsupported_remote_type": "El tipus remot utilitzat per l'aplicació no està suportat",
- "app_upgrade_app_name": "Actualitzant l'aplicació {app}...",
+ "app_upgrade_app_name": "Actualitzant l'aplicació {app}…",
"app_upgrade_failed": "No s'ha pogut actualitzar {app:s}",
"app_upgrade_some_app_failed": "No s'han pogut actualitzar algunes aplicacions",
"app_upgraded": "{app:s} ha estat actualitzada",
"appslist_corrupted_json": "No s'han pogut carregar les llistes d'aplicacions. Sembla que {filename:s} està danyat.",
"appslist_could_not_migrate": "No s'ha pogut migrar la llista d'aplicacions {appslist:s}! No s'ha pogut analitzar la URL... L'antic cronjob s'ha guardat a {bkp_file:s}.",
"appslist_fetched": "S'ha descarregat la llista d'aplicacions {appslist:s} correctament",
- "appslist_migrating": "Migrant la llista d'aplicacions {appslist:s} ...",
+ "appslist_migrating": "Migrant la llista d'aplicacions {appslist:s}…",
"appslist_name_already_tracked": "Ja hi ha una llista d'aplicacions registrada amb el nom {name:s}.",
"appslist_removed": "S'ha eliminat la llista d'aplicacions {appslist:s}",
"appslist_retrieve_bad_format": "L'arxiu obtingut per la llista d'aplicacions {appslist:s} no és vàlid",
@@ -61,10 +61,10 @@
"backup_abstract_method": "Encara no s'ha implementat aquest mètode de copia de seguretat",
"backup_action_required": "S'ha d'especificar què s'ha de guardar",
"backup_app_failed": "No s'ha pogut fer la còpia de seguretat de l'aplicació \"{app:s}\"",
- "backup_applying_method_borg": "Enviant tots els fitxers de la còpia de seguretat al repositori borg-backup...",
- "backup_applying_method_copy": "Còpia de tots els fitxers a la còpia de seguretat...",
- "backup_applying_method_custom": "Crida del mètode de còpia de seguretat personalitzat \"{method:s}\"...",
- "backup_applying_method_tar": "Creació de l'arxiu tar de la còpia de seguretat...",
+ "backup_applying_method_borg": "Enviant tots els fitxers de la còpia de seguretat al repositori borg-backup…",
+ "backup_applying_method_copy": "Còpia de tots els fitxers a la còpia de seguretat…",
+ "backup_applying_method_custom": "Crida del mètode de còpia de seguretat personalitzat \"{method:s}\"…",
+ "backup_applying_method_tar": "Creació de l'arxiu tar de la còpia de seguretat…",
"backup_archive_app_not_found": "L'aplicació \"{app:s}\" no es troba dins l'arxiu de la còpia de seguretat",
"backup_archive_broken_link": "No s'ha pogut accedir a l'arxiu de la còpia de seguretat (enllaç invàlid cap a {path:s})",
"backup_archive_mount_failed": "No s'ha pogut carregar l'arxiu de la còpia de seguretat",
@@ -80,5 +80,37 @@
"backup_copying_to_organize_the_archive": "Copiant {size:s}MB per organitzar l'arxiu",
"backup_couldnt_bind": "No es pot lligar {src:s} amb {dest:s}.",
"backup_created": "S'ha creat la còpia de seguretat",
- "backup_creating_archive": "Creant l'arxiu de la còpia de seguretat"
+ "backup_creating_archive": "Creant l'arxiu de la còpia de seguretat…",
+ "aborting": "Avortant.",
+ "app_not_upgraded": "Les següents aplicacions no s'han actualitzat: {apps}",
+ "app_start_install": "instal·lant l'aplicació {app}…",
+ "app_start_remove": "Eliminant l'aplicació {app}…",
+ "app_start_backup": "Recuperant els fitxers pels que s'ha de fer una còpia de seguretat per {app}…",
+ "app_start_restore": "Recuperant l'aplicació {app}…",
+ "app_upgrade_several_apps": "S'actualitzaran les següents aplicacions: {apps}",
+ "ask_new_domain": "Nou domini",
+ "ask_new_path": "Nou camí",
+ "backup_actually_backuping": "S'està creant un arxiu de còpia de seguretat a partir dels fitxers recuperats…",
+ "backup_creation_failed": "Ha fallat la creació de la còpia de seguretat",
+ "backup_csv_addition_failed": "No s'han pogut afegir fitxers per a fer-ne la còpia de seguretat al fitxer CSV",
+ "backup_csv_creation_failed": "No s'ha pogut crear el fitxer CSV necessari per a futures operacions de recuperació",
+ "backup_custom_backup_error": "El mètode de còpia de seguretat personalitzat ha fallat a l'etapa \"backup\"",
+ "backup_custom_mount_error": "El mètode de còpia de seguretat personalitzat ha fallat a l'etapa \"mount\"",
+ "backup_custom_need_mount_error": "El mètode de còpia de seguretat personalitzat ha fallat a l'etapa \"need_mount\"",
+ "backup_delete_error": "No s'ha pogut suprimir \"{path:s}\"",
+ "backup_deleted": "S'ha suprimit la còpia de seguretat",
+ "backup_extracting_archive": "Extraient l'arxiu de la còpia de seguretat…",
+ "backup_hook_unknown": "Script de còpia de seguretat \"{hook:s}\" desconegut",
+ "backup_invalid_archive": "Arxiu de còpia de seguretat no vàlid",
+ "backup_method_borg_finished": "La còpia de seguretat a borg ha acabat",
+ "backup_method_copy_finished": "La còpia de la còpia de seguretat ha acabat",
+ "backup_method_custom_finished": "El mètode de còpia de seguretat personalitzat \"{method:s}\" ha acabat",
+ "backup_method_tar_finished": "S'ha creat l'arxiu de còpia de seguretat tar",
+ "backup_mount_archive_for_restore": "Preparant l'arxiu per la restauració…",
+ "good_practices_about_user_password": "Esteu a punt de definir una nova contrasenya d'usuari. La contrasenya ha de tenir un mínim de 8 caràcters ; tot i que és de bona pràctica utilitzar una contrasenya més llarga (és a dir una frase de contrasenya) i/o utilitzar diferents tipus de caràcters (majúscules, minúscules, dígits i caràcters especials).",
+ "password_listed": "Aquesta contrasenya és una de les més utilitzades en el món. Si us plau utilitzeu-ne una més única.",
+ "password_too_simple_1": "La contrasenya ha de tenir un mínim de 8 caràcters",
+ "password_too_simple_2": "La contrasenya ha de tenir un mínim de 8 caràcters i ha de contenir dígits, majúscules i minúscules",
+ "password_too_simple_3": "La contrasenya ha de tenir un mínim de 8 caràcters i tenir dígits, majúscules, minúscules i caràcters especials",
+ "password_too_simple_4": "La contrasenya ha de tenir un mínim de 12 caràcters i tenir dígits, majúscules, minúscules i caràcters especials"
}
From 6523caffcbd473350c133d2e115adadf70920055 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?M=C3=A9lanie=20Chauvel?=
Date: Mon, 18 Mar 2019 20:09:52 +0000
Subject: [PATCH 087/180] Translated using Weblate (Esperanto)
Currently translated at 6.7% (34 of 504 strings)
Translation: YunoHost/core
Translate-URL: https://translate.yunohost.org/projects/yunohost/core/eo/
---
locales/eo.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/locales/eo.json b/locales/eo.json
index 6a7a82784..b9d973557 100644
--- a/locales/eo.json
+++ b/locales/eo.json
@@ -16,7 +16,7 @@
"yunohost_already_installed": "YunoHost estas jam instalita",
"yunohost_ca_creation_failed": "Ne eblas krei atestan aŭtoritaton",
"yunohost_ca_creation_success": "Loka atesta aŭtoritato estas kreita.",
- "yunohost_installing": "Instalata YunoHost...",
+ "yunohost_installing": "Instalante YunoHost…",
"service_description_glances": "monitoras sisteminformojn de via servilo",
"service_description_metronome": "mastrumas XMPP tujmesaĝilon kontojn",
"service_description_mysql": "stokas aplikaĵojn datojn (SQL datumbazo)",
From a4f00f2eff9de781d64e496d748d26dfbf67af3f Mon Sep 17 00:00:00 2001
From: ppr
Date: Tue, 19 Mar 2019 09:06:19 +0000
Subject: [PATCH 088/180] Translated using Weblate (French)
Currently translated at 97.4% (491 of 504 strings)
Translation: YunoHost/core
Translate-URL: https://translate.yunohost.org/projects/yunohost/core/fr/
---
locales/fr.json | 234 ++++++++++++++++++++++++------------------------
1 file changed, 117 insertions(+), 117 deletions(-)
diff --git a/locales/fr.json b/locales/fr.json
index bea929837..58c25d3ad 100644
--- a/locales/fr.json
+++ b/locales/fr.json
@@ -111,7 +111,7 @@
"hook_choice_invalid": "Choix incorrect : '{:s}'",
"hook_exec_failed": "Échec de l’exécution du script : {path:s}",
"hook_exec_not_terminated": "L’exécution du script {path:s} ne s’est pas terminée correctement",
- "hook_list_by_invalid": "La propriété de tri des actions est invalide",
+ "hook_list_by_invalid": "Propriété invalide pour lister les actions par",
"hook_name_unknown": "Nom de l'action '{name:s}' inconnu",
"installation_complete": "Installation terminée",
"installation_failed": "Échec de l’installation",
@@ -119,8 +119,8 @@
"iptables_unavailable": "Vous ne pouvez pas jouer avec iptables ici. Vous êtes soit dans un conteneur, soit votre noyau ne le prend pas en charge",
"ldap_initialized": "L’annuaire LDAP a été initialisé",
"license_undefined": "indéfinie",
- "mail_alias_remove_failed": "Impossible de supprimer l’alias courriel '{mail:s}'",
- "mail_domain_unknown": "Le domaine '{domain:s}' du courriel est inconnu",
+ "mail_alias_remove_failed": "Impossible de supprimer l’alias de courriel '{mail:s}'",
+ "mail_domain_unknown": "Le domaine '{domain:s}' est inconnu pour cette adresse de courriel",
"mail_forward_remove_failed": "Impossible de supprimer le courriel de transfert '{mail:s}'",
"maindomain_change_failed": "Impossible de modifier le domaine principal",
"maindomain_changed": "Le domaine principal a été modifié",
@@ -136,119 +136,119 @@
"mysql_db_creation_failed": "Impossible de créer la base de données MySQL",
"mysql_db_init_failed": "Impossible d’initialiser la base de données MySQL",
"mysql_db_initialized": "La base de données MySQL a été initialisée",
- "network_check_mx_ko": "L’enregistrement DNS MX n’est pas précisé",
+ "network_check_mx_ko": "L’enregistrement DNS MX n’est pas défini",
"network_check_smtp_ko": "Le trafic courriel sortant (port 25 SMTP) semble bloqué par votre réseau",
"network_check_smtp_ok": "Le trafic courriel sortant (port 25 SMTP) n’est pas bloqué",
"new_domain_required": "Vous devez spécifier le nouveau domaine principal",
"no_appslist_found": "Aucune liste d’applications n’a été trouvée",
"no_internet_connection": "Le serveur n’est pas connecté à Internet",
"no_ipv6_connectivity": "La connectivité IPv6 n’est pas disponible",
- "no_restore_script": "Le script de sauvegarde n’a pas été trouvé pour l’application « {app:s} »",
+ "no_restore_script": "Le script de sauvegarde n’a pas été trouvé pour l’application '{app:s}'",
"no_such_conf_file": "Le fichier {file:s} n’existe pas, il ne peut pas être copié",
- "not_enough_disk_space": "L’espace disque est insuffisant sur « {path:s} »",
- "package_not_installed": "Le paquet « {pkgname} » n’est pas installé",
- "package_unexpected_error": "Une erreur inattendue est survenue avec le paquet « {pkgname} »",
- "package_unknown": "Paquet « {pkgname} » inconnu",
+ "not_enough_disk_space": "L’espace disque est insuffisant sur '{path:s}'",
+ "package_not_installed": "Le paquet '{pkgname}' n’est pas installé",
+ "package_unexpected_error": "Une erreur inattendue s'est produite lors du traitement du paquet '{pkgname}'",
+ "package_unknown": "Le paquet '{pkgname}' est inconnu",
"packages_no_upgrade": "Il n’y a aucun paquet à mettre à jour",
"packages_upgrade_critical_later": "Les paquets critiques ({packages:s}) seront mis à jour ultérieurement",
"packages_upgrade_failed": "Impossible de mettre à jour tous les paquets",
"path_removal_failed": "Impossible de supprimer le chemin {:s}",
- "pattern_backup_archive_name": "Doit être un nom de fichier valide avec un maximum de 30 caractères, et composé uniquement de caractères alphanumériques et de tirets tels que - et _",
- "pattern_domain": "Doit être un nom de domaine valide (ex : mon-domaine.org)",
- "pattern_email": "Doit être une adresse courriel valide (ex. : pseudo@domain.org)",
+ "pattern_backup_archive_name": "Doit être un nom de fichier valide avec un maximum de 30 caractères, et composé uniquement de caractères alphanumériques et de tirets tels que -_.",
+ "pattern_domain": "Doit être un nom de domaine valide (ex : mon-domaine.fr)",
+ "pattern_email": "Doit être une adresse de courriel valide (ex. : pseudo@domaine.fr)",
"pattern_firstname": "Doit être un prénom valide",
"pattern_lastname": "Doit être un nom valide",
- "pattern_listname": "Doit être composé uniquement de caractères alphanumériques et de tirets bas",
- "pattern_mailbox_quota": "Doit être une taille avec le suffixe b/k/M/G/T ou 0 pour désactiver le quota",
+ "pattern_listname": "Doit être composé uniquement de caractères alphanumériques et de tirets bas (aussi appelé tiret du 8 ou underscore)",
+ "pattern_mailbox_quota": "Doit avoir une taille suffixée avec b/k/M/G/T ou 0 pour désactiver le quota",
"pattern_password": "Doit être composé d’au moins 3 caractères",
- "pattern_port": "Doit être un numéro de port valide (ex. : 0-65535)",
- "pattern_port_or_range": "Doit être un numéro de port valide (ex. : 0-65535) ou une gamme de ports (ex. : 100:200)",
+ "pattern_port": "Doit être un numéro de port valide compris entre 0 et 65535",
+ "pattern_port_or_range": "Doit être un numéro de port valide compris entre 0 et 65535, ou une gamme de ports (exemple : 100:200)",
"pattern_positive_number": "Doit être un nombre positif",
- "pattern_username": "Doit être composé uniquement de caractères alphanumériques minuscules et de tirets bas",
+ "pattern_username": "Doit être composé uniquement de caractères alphanumériques minuscules et de tirets bas (aussi appelé tiret du 8 ou underscore)",
"port_already_closed": "Le port {port:d} est déjà fermé pour les connexions {ip_version:s}",
"port_already_opened": "Le port {port:d} est déjà ouvert pour les connexions {ip_version:s}",
"port_available": "Le port {port:d} est disponible",
"port_unavailable": "Le port {port:d} n’est pas disponible",
"restore_action_required": "Vous devez préciser ce qui est à restaurer",
- "restore_already_installed_app": "Une application est déjà installée avec l’id « {app:s} »",
- "restore_app_failed": "Impossible de restaurer l’application « {app:s} »",
+ "restore_already_installed_app": "Une application est déjà installée avec l’identifiant '{app:s}'",
+ "restore_app_failed": "Impossible de restaurer l’application '{app:s}'",
"restore_cleaning_failed": "Impossible de nettoyer le dossier temporaire de restauration",
"restore_complete": "Restauration terminée",
"restore_confirm_yunohost_installed": "Voulez-vous vraiment restaurer un système déjà installé ? [{answers:s}]",
"restore_failed": "Impossible de restaurer le système",
- "restore_hook_unavailable": "Le script de restauration « {part:s} » n’est pas disponible sur votre système, et n’est pas non plus dans l’archive",
+ "restore_hook_unavailable": "Le script de restauration '{part:s}' n’est pas disponible sur votre système, et ne l'est pas non plus dans l’archive",
"restore_nothings_done": "Rien n’a été restauré",
"restore_running_app_script": "Exécution du script de restauration de l'application '{app:s}' .…",
"restore_running_hooks": "Exécution des scripts de restauration …",
"service_add_configuration": "Ajout du fichier de configuration {file:s}",
- "service_add_failed": "Impossible d’ajouter le service « {service:s} »",
- "service_added": "Le service « {service:s} » a été ajouté",
- "service_already_started": "Le service « {service:s} » est déjà démarré",
- "service_already_stopped": "Le service « {service:s} » est déjà arrêté",
- "service_cmd_exec_failed": "Impossible d’exécuter la commande « {command:s} »",
- "service_conf_file_backed_up": "Le fichier de configuration « {conf} » a été sauvegardé dans « {backup} »",
- "service_conf_file_copy_failed": "Impossible de copier le nouveau fichier de configuration « {new} » vers « {conf} »",
- "service_conf_file_manually_modified": "Le fichier de configuration « {conf} » a été modifié manuellement et ne sera pas mis à jour",
- "service_conf_file_manually_removed": "Le fichier de configuration « {conf} » a été supprimé manuellement et ne sera pas créé",
+ "service_add_failed": "Impossible d’ajouter le service '{service:s}'",
+ "service_added": "Le service '{service:s}' a été ajouté",
+ "service_already_started": "Le service '{service:s}' est déjà démarré",
+ "service_already_stopped": "Le service '{service:s}' est déjà arrêté",
+ "service_cmd_exec_failed": "Impossible d’exécuter la commande '{command:s}'",
+ "service_conf_file_backed_up": "Le fichier de configuration '{conf}' a été sauvegardé dans '{backup}'",
+ "service_conf_file_copy_failed": "Impossible de copier le nouveau fichier de configuration '{new}' vers '{conf}'",
+ "service_conf_file_manually_modified": "Le fichier de configuration '{conf}' a été modifié manuellement et ne sera pas mis à jour",
+ "service_conf_file_manually_removed": "Le fichier de configuration '{conf}' a été supprimé manuellement et ne sera pas créé",
"service_conf_file_not_managed": "Le fichier de configuration « {conf} » n'est pas géré pour l'instant et ne sera pas mis à jour",
- "service_conf_file_remove_failed": "Impossible de supprimer le fichier de configuration « {conf} »",
- "service_conf_file_removed": "Le fichier de configuration « {conf} » a été supprimé",
- "service_conf_file_updated": "Le fichier de configuration « {conf} » a été mis à jour",
- "service_conf_up_to_date": "La configuration du service « {service} » est déjà à jour",
- "service_conf_updated": "La configuration a été mise à jour pour le service « {service} »",
- "service_conf_would_be_updated": "La configuration du service « {service} » aurait été mise à jour",
+ "service_conf_file_remove_failed": "Impossible de supprimer le fichier de configuration '{conf}'",
+ "service_conf_file_removed": "Le fichier de configuration '{conf}' a été supprimé",
+ "service_conf_file_updated": "Le fichier de configuration '{conf}' a été mis à jour",
+ "service_conf_up_to_date": "La configuration du service '{service}' est déjà à jour",
+ "service_conf_updated": "La configuration a été mise à jour pour le service '{service}'",
+ "service_conf_would_be_updated": "La configuration du service '{service}' aurait été mise à jour",
"service_configuration_conflict": "Le fichier {file:s} a été modifié depuis sa dernière génération. Veuillez y appliquer les modifications manuellement ou utiliser l’option --force (ce qui écrasera toutes les modifications effectuées sur le fichier).",
"service_configured": "La configuration du service « {service:s} » a été générée avec succès",
"service_configured_all": "La configuration de tous les services a été générée avec succès",
- "service_disable_failed": "Impossible de désactiver le service « {service:s} »\n\nJournaux récents : {logs:s}",
- "service_disabled": "Le service « {service:s} » a été désactivé",
- "service_enable_failed": "Impossible d’activer le service « {service:s} »\n\nJournaux récents : {logs:s}",
- "service_enabled": "Le service « {service:s} » a été activé",
- "service_no_log": "Aucun journal à afficher pour le service « {service:s} »",
- "service_regenconf_dry_pending_applying": "Vérification des configurations en attentes qui pourraient être appliquées pour le service « {service} »…",
+ "service_disable_failed": "Impossible de désactiver le service '{service:s}'\n\nJournaux historisés récents : {logs:s}",
+ "service_disabled": "Le service '{service:s}' a été désactivé",
+ "service_enable_failed": "Impossible d’activer le service '{service:s}'\n\nJournaux historisés récents : {logs:s}",
+ "service_enabled": "Le service '{service:s}' a été activé",
+ "service_no_log": "Aucun journal historisé à afficher pour le service '{service:s}'",
+ "service_regenconf_dry_pending_applying": "Vérification des configurations en attentes qui pourraient être appliquées au le service '{service}' …",
"service_regenconf_failed": "Impossible de régénérer la configuration pour les services : {services}",
- "service_regenconf_pending_applying": "Application des configurations en attentes pour le service « {service} »…",
- "service_remove_failed": "Impossible d’enlever le service « {service:s} »",
- "service_removed": "Le service « {service:s} » a été enlevé",
- "service_start_failed": "Impossible de démarrer le service « {service:s} »\n\nJournaux récents : {logs:s}",
- "service_started": "Le service « {service:s} » a été démarré",
- "service_status_failed": "Impossible de déterminer le statut du service « {service:s} »",
- "service_stop_failed": "Impossible d’arrêter le service « {service:s} »\n\nJournaux récents : {logs:s}",
- "service_stopped": "Le service « {service:s} » a été arrêté",
- "service_unknown": "Service « {service:s} » inconnu",
+ "service_regenconf_pending_applying": "Application des configurations en attentes pour le service '{service}' …",
+ "service_remove_failed": "Impossible de supprimer le service '{service:s}'",
+ "service_removed": "Le service '{service:s}' a été supprimé",
+ "service_start_failed": "Impossible de démarrer le service '{service:s}'\n\nJournaux historisés récents : {logs:s}",
+ "service_started": "Le service '{service:s}' a été démarré",
+ "service_status_failed": "Impossible de déterminer le statut du service '{service:s}'",
+ "service_stop_failed": "Impossible d’arrêter le service '{service:s}'\n\nJournaux historisés récents : {logs:s}",
+ "service_stopped": "Le service '{service:s}' a été arrêté",
+ "service_unknown": "Le service '{service:s}' est inconnu",
"services_configured": "La configuration a été générée avec succès",
"show_diff": "Voici les différences :\n{diff:s}",
"ssowat_conf_generated": "La configuration de SSOwat a été générée",
"ssowat_conf_updated": "La configuration de SSOwat a été mise à jour",
"system_upgraded": "Le système a été mis à jour",
- "system_username_exists": "Le nom d’utilisateur existe déjà dans les utilisateurs système",
- "unbackup_app": "L’application « {app:s} » ne sera pas sauvegardée",
- "unexpected_error": "Une erreur inattendue est survenue",
- "unit_unknown": "Unité « {unit:s} » inconnue",
+ "system_username_exists": "Ce nom d’utilisateur existe déjà dans les utilisateurs système",
+ "unbackup_app": "L’application '{app:s}' ne sera pas sauvegardée",
+ "unexpected_error": "Une erreur inattendue est survenue : {error}",
+ "unit_unknown": "L'unité '{unit:s}' est inconnue",
"unlimit": "Pas de quota",
- "unrestore_app": "L’application « {app:s} » ne sera pas restaurée",
- "update_cache_failed": "Impossible de mettre à jour le cache de l’APT",
- "updating_apt_cache": "Récupération des mises à jour disponibles pour les paquets du système .…",
+ "unrestore_app": "L’application '{app:s}' ne sera pas restaurée",
+ "update_cache_failed": "Impossible de mettre à jour le cache de l'outil de gestion avancée des paquets (APT)",
+ "updating_apt_cache": "Récupération des mises à jour disponibles pour les paquets du système …",
"upgrade_complete": "Mise à jour terminée",
"upgrading_packages": "Mise à jour des paquets en cours …",
"upnp_dev_not_found": "Aucun périphérique compatible UPnP n’a été trouvé",
"upnp_disabled": "UPnP a été désactivé",
"upnp_enabled": "UPnP a été activé",
- "upnp_port_open_failed": "Impossible d’ouvrir les ports avec UPnP",
+ "upnp_port_open_failed": "Impossible d’ouvrir les ports UPnP",
"user_created": "L’utilisateur a été créé",
"user_creation_failed": "Impossible de créer l’utilisateur",
"user_deleted": "L’utilisateur a été supprimé",
"user_deletion_failed": "Impossible de supprimer l’utilisateur",
"user_home_creation_failed": "Impossible de créer le dossier personnel de l’utilisateur",
"user_info_failed": "Impossible de récupérer les informations de l’utilisateur",
- "user_unknown": "Utilisateur « {user:s} » inconnu",
+ "user_unknown": "L'utilisateur {user:s} est inconnu",
"user_update_failed": "Impossible de modifier l’utilisateur",
"user_updated": "L’utilisateur a été modifié",
"yunohost_already_installed": "YunoHost est déjà installé",
"yunohost_ca_creation_failed": "Impossible de créer l’autorité de certification",
"yunohost_configured": "YunoHost a été configuré",
- "yunohost_installing": "Installation de YunoHost en cours …",
- "yunohost_not_installed": "YunoHost n’est pas ou pas correctement installé. Veuillez exécuter « yunohost tools postinstall »",
+ "yunohost_installing": "L'installation de YunoHost est en cours …",
+ "yunohost_not_installed": "YunoHost n’est pas ou pas correctement installé. Veuillez exécuter 'yunohost tools postinstall'",
"certmanager_attempt_to_replace_valid_cert": "Vous êtes en train de vouloir remplacer un certificat correct et valide pour le domaine {domain:s} ! (Utilisez --force pour contourner cela)",
"certmanager_domain_unknown": "Domaine {domain:s} inconnu",
"certmanager_domain_cert_not_selfsigned": "Le certificat du domaine {domain:s} n’est pas auto-signé. Voulez-vous vraiment le remplacer ? (Utilisez --force pour cela)",
@@ -267,13 +267,13 @@
"certmanager_no_cert_file": "Impossible de lire le fichier de/du certificat pour le domaine {domain:s} (fichier : {file:s})",
"certmanager_conflicting_nginx_file": "Impossible de préparer le domaine pour le défi ACME : le fichier de configuration Nginx {filepath:s} est en conflit et doit être préalablement retiré",
"certmanager_hit_rate_limit": "Trop de certificats ont déjà été émis récemment pour ce même ensemble de domaines {domain:s}. Veuillez réessayer plus tard. Lisez https://letsencrypt.org/docs/rate-limits/ pour obtenir plus de détails sur les ratios et limitations",
- "ldap_init_failed_to_create_admin": "L’initialisation de LDAP n’a pas réussi à créer l’utilisateur admin",
+ "ldap_init_failed_to_create_admin": "L’initialisation de l'annuaire LDAP n’a pas réussi à créer l’utilisateur admin",
"ssowat_persistent_conf_read_error": "Erreur lors de la lecture de la configuration persistante de SSOwat : {error:s}. Modifiez le fichier /etc/ssowat/conf.json.persistent pour réparer la syntaxe JSON",
"ssowat_persistent_conf_write_error": "Erreur lors de la sauvegarde de la configuration persistante de SSOwat : {error:s}. Modifiez le fichier /etc/ssowat/conf.json.persistent pour réparer la syntaxe JSON",
"domain_cannot_remove_main": "Impossible de supprimer le domaine principal. Définissez d'abord un nouveau domaine principal",
"certmanager_self_ca_conf_file_not_found": "Le fichier de configuration pour l’autorité du certificat auto-signé est introuvable (fichier : {file:s})",
"certmanager_unable_to_parse_self_CA_name": "Impossible d’analyser le nom de l’autorité du certificat auto-signé (fichier : {file:s})",
- "mailbox_used_space_dovecot_down": "Le service mail Dovecot doit être démarré, si vous souhaitez voir l’espace disque occupé par la messagerie",
+ "mailbox_used_space_dovecot_down": "Le service de courriel Dovecot doit être démarré, si vous souhaitez voir l’espace disque occupé par la messagerie",
"domains_available": "Domaines disponibles :",
"backup_archive_broken_link": "Impossible d’accéder à l’archive de sauvegarde (lien invalide vers {path:s})",
"certmanager_acme_not_configured_for_domain": "Le certificat du domaine {domain:s} ne semble pas être correctement installé. Veuillez d'abord exécuter cert-install.",
@@ -311,7 +311,7 @@
"global_settings_unknown_type": "Situation inattendue : la configuration {setting:s} semble avoir le type {unknown_type:s} mais celui-ci n'est pas pris en charge par le système.",
"global_settings_unknown_setting_from_settings_file": "Clef inconnue dans les paramètres : '{setting_key:s}', rejet de cette clef et sauvegarde de celle-ci dans /etc/yunohost/unkown_settings.json",
"service_conf_new_managed_file": "Le fichier de configuration « {conf} » est désormais géré par le service {service}.",
- "service_conf_file_kept_back": "Le fichier de configuration « {conf} » devrait être supprimé par le service {service} mais a été conservé.",
+ "service_conf_file_kept_back": "Le fichier de configuration '{conf}' devait être supprimé par le service {service} mais a été conservé.",
"backup_abstract_method": "Cette méthode de sauvegarde n’a pas encore été implémentée",
"backup_applying_method_tar": "Création de l’archive tar de la sauvegarde …",
"backup_applying_method_copy": "Copie de tous les fichiers à sauvegarder …",
@@ -340,28 +340,28 @@
"backup_with_no_restore_script_for_app": "L’application {app:s} n’a pas de script de restauration, vous ne pourrez pas restaurer automatiquement la sauvegarde de cette application.",
"global_settings_cant_serialize_settings": "Échec de la sérialisation des données de paramétrage car : {reason:s}",
"restore_removing_tmp_dir_failed": "Impossible de sauvegarder un ancien dossier temporaire",
- "restore_extracting": "Extraction des fichiers nécessaires depuis l’archive…",
- "restore_mounting_archive": "Montage de l’archive dans « {path:s} »",
- "restore_may_be_not_enough_disk_space": "Votre système semble ne pas avoir suffisamment d’espace disponible (libre : {free_space:d} octets, nécessaire : {needed_space:d} octets, marge de sécurité : {margin:d} octets)",
- "restore_not_enough_disk_space": "Espace disponible insuffisant (libre : {free_space:d} octets, nécessaire : {needed_space:d} octets, marge de sécurité : {margin:d} octets)",
- "restore_system_part_failed": "Impossible de restaurer la partie « {part:s} » du système",
+ "restore_extracting": "Extraction des fichiers nécessaires depuis l’archive …",
+ "restore_mounting_archive": "Montage de l’archive dans '{path:s}'",
+ "restore_may_be_not_enough_disk_space": "Votre système semble ne pas avoir suffisamment d’espace disponible (L'espace libre est de {free_space:d} octets. Le besoin d'espace nécessaire est de {needed_space:d} octets. En appliquant une marge de sécurité, la quantité d'espace nécessaire est de {margin:d} octets)",
+ "restore_not_enough_disk_space": "Espace disponible insuffisant (L'espace libre est de {free_space:d} octets. Le besoin d'espace nécessaire est de {needed_space:d} octets. En appliquant une marge de sécurité, la quantité d'espace nécessaire est de {margin:d} octets)",
+ "restore_system_part_failed": "Impossible de restaurer la partie '{part:s}' du système",
"backup_couldnt_bind": "Impossible de lier {src:s} avec {dest:s}.",
"domain_dns_conf_is_just_a_recommendation": "Cette page montre la configuration *recommandée*. Elle ne configure *pas* le DNS pour vous. Il est de votre responsabilité que de configurer votre zone DNS chez votre fournisseur/registrar DNS avec cette recommandation.",
"domain_dyndns_dynette_is_unreachable": "Impossible de contacter la dynette YunoHost. Soit YunoHost n’est pas correctement connecté à internet, soit le serveur de dynette est en panne ou ne répond pas. Erreur : {error}",
"migrations_backward": "Migration en arrière.",
- "migrations_bad_value_for_target": "Nombre invalide pour le paramètre « target », les numéros de migration sont ou {}",
+ "migrations_bad_value_for_target": "Nombre invalide pour le paramètre target, les numéros de migration sont 0 ou {}",
"migrations_cant_reach_migration_file": "Impossible d’accéder aux fichiers de migrations avec le chemin %s",
"migrations_current_target": "La cible de migration est {}",
"migrations_error_failed_to_load_migration": "ERREUR : échec du chargement de migration {number} {name}",
"migrations_forward": "Migration en avant",
- "migrations_loading_migration": "Chargement de la migration {number} {name}…",
- "migrations_migration_has_failed": "La migration {number} {name} a échoué avec l’exception {exception}, annulation",
+ "migrations_loading_migration": "Chargement de la migration {number} {name} …",
+ "migrations_migration_has_failed": "La migration {number} {name} a échoué avec l’exception {exception} : annulation",
"migrations_no_migrations_to_run": "Aucune migration à lancer",
- "migrations_show_currently_running_migration": "Application de la migration {number} {name}…",
+ "migrations_show_currently_running_migration": "Application de la migration {number} {name} …",
"migrations_show_last_migration": "La dernière migration appliquée est {}",
- "migrations_skip_migration": "Omission de la migration {number} {name}…",
- "server_shutdown": "Le serveur sera éteint",
- "server_shutdown_confirm": "Le serveur immédiatement être éteint, le voulez-vous vraiment ? [{answers:s}]",
+ "migrations_skip_migration": "Ignorer et passer la migration {number} {name} …",
+ "server_shutdown": "Le serveur va éteindre",
+ "server_shutdown_confirm": "Le serveur va être éteint immédiatement, le voulez-vous vraiment ? [{answers:s}]",
"server_reboot": "Le serveur va redémarrer",
"server_reboot_confirm": "Le serveur va redémarrer immédiatement, le voulez-vous vraiment ? [{answers:s}]",
"app_upgrade_some_app_failed": "Impossible de mettre à jour certaines applications",
@@ -372,35 +372,35 @@
"app_upgrade_app_name": "Mise à jour de l’application {app} …",
"backup_output_symlink_dir_broken": "Vous avez un lien symbolique cassé à la place de votre dossier d’archives '{path:s}'. Vous pourriez avoir une configuration personnalisée pour sauvegarder vos données sur un autre système de fichiers, dans ce cas, vous avez probablement oublié de monter ou de connecter votre disque dur ou votre clef USB.",
"migrate_tsig_end": "La migration à hmac-sha512 est terminée",
- "migrate_tsig_failed": "La migration du domaine DynDNS {domain} à hmac-sha512 a échoué, annulation des modifications. Erreur : {error_code} - {error}",
- "migrate_tsig_start": "L’algorithme de génération des clefs n’est pas suffisamment sécurisé pour la signature TSIG du domaine « {domain} », lancement de la migration vers hmac-sha512 qui est plus sécurisé",
+ "migrate_tsig_failed": "La migration du domaine DynDNS {domain} à hmac-sha512 a échoué. Annulation des modifications. Erreur : {error_code} - {error}",
+ "migrate_tsig_start": "L’algorithme de génération des clefs n’est pas suffisamment sécurisé pour la signature TSIG du domaine '{domain}', lancement de la migration vers hmac-sha512 qui est plus sécurisé",
"migrate_tsig_wait": "Attendre 3 minutes pour que le serveur DynDNS prenne en compte la nouvelle clef …",
"migrate_tsig_wait_2": "2 minutes …",
"migrate_tsig_wait_3": "1 minute …",
"migrate_tsig_wait_4": "30 secondes …",
"migrate_tsig_not_needed": "Il ne semble pas que vous utilisez un domaine DynDNS, donc aucune migration n’est nécessaire !",
"app_checkurl_is_deprecated": "Packagers /!\\ 'app checkurl' est obsolète ! Utilisez 'app register-url' en remplacement !",
- "migration_description_0001_change_cert_group_to_sslcert": "Change les permissions de groupe des certificats de 'metronome' à 'ssl-cert'",
- "migration_description_0002_migrate_to_tsig_sha256": "Améliore la sécurité de DynDNS TSIG en utilisant SHA512 au lieu de MD5",
+ "migration_description_0001_change_cert_group_to_sslcert": "Changement des permissions de groupe des certificats de 'metronome' à 'ssl-cert'",
+ "migration_description_0002_migrate_to_tsig_sha256": "Amélioration de la sécurité de DynDNS TSIG en utilisant SHA512 au lieu de MD5",
"migration_description_0003_migrate_to_stretch": "Mise à niveau du système vers Debian Stretch et YunoHost 3.0",
"migration_0003_backward_impossible": "La migration Stretch n’est pas réversible.",
"migration_0003_start": "Démarrage de la migration vers Stretch. Les journaux seront disponibles dans {logfile}.",
- "migration_0003_patching_sources_list": "Modification de sources.lists …",
+ "migration_0003_patching_sources_list": "Modification du fichier sources.lists …",
"migration_0003_main_upgrade": "Démarrage de la mise à niveau principale …",
"migration_0003_fail2ban_upgrade": "Démarrage de la mise à niveau de fail2ban …",
"migration_0003_restoring_origin_nginx_conf": "Votre fichier /etc/nginx/nginx.conf a été modifié d’une manière ou d’une autre. La migration va d’abords le réinitialiser à son état initial. Le fichier précédent sera disponible en tant que {backup_dest}.",
- "migration_0003_yunohost_upgrade": "Démarrage de la mise à niveau du paquet YunoHost. La migration se terminera, mais la mise à jour réelle aura lieu immédiatement après. Après cette opération terminée, vous pourriez avoir à vous reconnecter à l’administration via le panel web.",
+ "migration_0003_yunohost_upgrade": "Démarrage de la mise à niveau du paquet YunoHost. La migration se terminera, mais la mise à jour réelle aura lieu immédiatement après. Une fois cette opération terminée, vous pourriez avoir à vous reconnecter à l’administration via le panel web.",
"migration_0003_not_jessie": "La distribution Debian actuelle n’est pas Jessie !",
"migration_0003_system_not_fully_up_to_date": "Votre système n’est pas complètement à jour. Veuillez mener une mise à jour classique avant de lancer à migration à Stretch.",
- "migration_0003_still_on_jessie_after_main_upgrade": "Quelque chose s’est ma passé pendant la mise à niveau principale : le système est toujours sur Jessie ?!? Pour investiguer le problème, veuillez regarder les journaux {log} 🙁…",
- "migration_0003_general_warning": "Veuillez noter que cette migration est une opération délicate. Si l’équipe YunoHost a fait de son mieux pour la relire et la tester, la migration pourrait tout de même casser des parties de votre système ou de vos applications.\n\nEn conséquence, nous vous recommandons :\n - de lancer une sauvegarde de vos données ou applications critiques. Plus d’informations sur https://yunohost.org/backup ;\n - d’être patient après avoir lancé la migration : selon votre connexion internet et matériel, cela pourrait prendre jusqu’à quelques heures pour que tout soit à niveau.\n\nDe plus, le port SMTP utilisé par les clients de messagerie externes comme (Thunderbird ou K9-Mail) a été changé de 465 (SSL/TLS) à 587 (STARTTLS). L’ancien port 465 sera automatiquement fermé et le nouveau port 587 sera ouvert dans le pare-feu. Vous et vos utilisateurs *devront* adapter la configuration de vos clients de messagerie en conséquence !",
- "migration_0003_problematic_apps_warning": "Veuillez noter que les applications suivantes, éventuellement problématiques, ont été détectées. Il semble qu’elles n’aient pas été installées depuis une liste d’application ou qu’elles ne soit pas marquées «working ». En conséquence, nous ne pouvons pas garantir qu’elles fonctionneront après la mise à niveau : {problematic_apps}",
+ "migration_0003_still_on_jessie_after_main_upgrade": "Quelque chose s’est mal passé pendant la mise à niveau principale : le système est toujours sur Jessie !? Pour en savoir plus et investiguer sur ce problème, veuillez regarder les journaux {log}:s .",
+ "migration_0003_general_warning": "Veuillez noter que cette migration est une opération délicate. Si l’équipe YunoHost a fait de son mieux pour la relire et la tester, la migration pourrait tout de même casser des parties de votre système ou de vos applications.\n\nEn conséquence, nous vous recommandons :\n - de lancer une sauvegarde de vos données ou applications critiques. Plus d’informations sur https://yunohost.org/backup ;\n - d’être patient après avoir lancé la migration : selon votre connexion internet et matériel, cela pourrait prendre jusqu’à quelques heures pour que tout soit à niveau.\n\nEn outre, le port SMTP utilisé par les clients de messagerie externes comme (Thunderbird ou K9-Mail) a été changé de 465 (SSL/TLS) à 587 (STARTTLS). L’ancien port 465 sera automatiquement fermé et le nouveau port 587 sera ouvert dans le pare-feu. Vous et vos utilisateurs *devront* adapter la configuration de vos clients de messagerie en conséquence !",
+ "migration_0003_problematic_apps_warning": "Veuillez noter que des applications possiblement problématiques ont été détectées. Il semble qu’elles n’aient pas été installées depuis une liste d’application ou qu’elles ne soit pas marquées comme 'fonctionnelles'/'working'. En conséquence, nous ne pouvons pas garantir qu’elles fonctionneront après la mise à niveau : {problematic_apps}",
"migration_0003_modified_files": "Veuillez noter que les fichiers suivants ont été détectés comme modifiés manuellement et pourraient être écrasés à la fin de la mise à niveau : {manually_modified_files}",
"migrations_list_conflict_pending_done": "Vous ne pouvez pas utiliser --previous et --done simultanément.",
- "migrations_to_be_ran_manually": "La migration {number} {name} doit être lancée manuellement. Veuillez aller dans Outils > Migration dans l’interface admin, ou lancer `yunohost tools migrations migrate`.",
+ "migrations_to_be_ran_manually": "La migration {number} {name} doit être lancée manuellement. Veuillez aller dans Outils > Migrations dans l’interface admin, ou lancer `yunohost tools migrations migrate`.",
"migrations_need_to_accept_disclaimer": "Pour lancer la migration {number} {name}, vous devez accepter cette clause de non-responsabilité :\n---\n{disclaimer}\n---\nSi vous acceptez de lancer la migration, veuillez relancer la commande avec l’option --accept-disclaimer.",
"service_description_avahi-daemon": "permet d’atteindre votre serveur via yunohost.local sur votre réseau local",
- "service_description_dnsmasq": "assure la résolution des noms de domaine (DNS)",
+ "service_description_dnsmasq": "gère la résolution des noms de domaine (DNS)",
"service_description_dovecot": "permet aux clients de messagerie d’accéder/récupérer les courriels (via IMAP et POP3)",
"service_description_fail2ban": "protège contre les attaques brute-force et autres types d’attaques venant d’Internet",
"service_description_glances": "surveille les informations système de votre serveur",
@@ -410,43 +410,43 @@
"service_description_nslcd": "gère la connexion en ligne de commande des utilisateurs YunoHost",
"service_description_php5-fpm": "exécute des applications écrites en PHP avec nginx",
"service_description_postfix": "utilisé pour envoyer et recevoir des courriels",
- "service_description_redis-server": "une base de donnée spécialisée utilisée pour l’accès rapide aux données, les files d’attentes et la communication inter-programmes",
+ "service_description_redis-server": "une base de données spécialisée utilisée pour l’accès rapide aux données, les files d’attentes et la communication entre les programmes",
"service_description_rmilter": "vérifie divers paramètres dans les courriels",
"service_description_rspamd": "filtre le pourriel, et d’autres fonctionnalités liées au courriel",
"service_description_slapd": "stocke les utilisateurs, domaines et leurs informations liées",
"service_description_ssh": "vous permet de vous connecter à distance à votre serveur via un terminal (protocole SSH)",
"service_description_yunohost-api": "permet les interactions entre l’interface web de YunoHost et le système",
- "service_description_yunohost-firewall": "gère les ports de connexion ouverts et fermés aux services",
+ "service_description_yunohost-firewall": "gère l'ouverture et la fermeture des ports de connexion aux services",
"experimental_feature": "Attention : cette fonctionnalité est expérimentale et ne doit pas être considérée comme stable, vous ne devriez pas l’utiliser à moins que vous ne sachiez ce que vous faites.",
- "log_corrupted_md_file": "Le fichier yaml de metadata associé aux logs est corrompu : {md_file}",
+ "log_corrupted_md_file": "Le fichier yaml de metadata associé aux logs est corrompu : '{md_file}'",
"log_category_404": "Le journal de la catégorie '{category}' n’existe pas",
- "log_link_to_log": "Log complet de cette opération : ' {desc} '",
- "log_help_to_get_log": "Pour voir le log de cette opération '{desc}', utiliser la commande 'yunohost log display {name}'",
- "log_link_to_failed_log": "L’opération '{desc}' a échouée ! Pour avoir de l’aide, merci de fournir le log complet de l’opération en cliquant ici",
+ "log_link_to_log": "Journal historisé complet de cette opération : ' {desc} '",
+ "log_help_to_get_log": "Pour voir le journal historisé de cette opération '{desc}', utilisez la commande 'yunohost log display {name}'",
+ "log_link_to_failed_log": "L’opération '{desc}' a échouée ! Pour avoir de l’aide, merci de fournir le journal historisé complet de l’opération en cliquant ici",
"backup_php5_to_php7_migration_may_fail": "Impossible de convertir votre archive pour prendre en charge php7, vos applications php pourraient ne pas être restaurées (reason: {error:s})",
- "log_help_to_get_failed_log": "L’opération '{desc}' a échouée ! Pour avoir de l’aide, merci de partager le log de cette opération en utilisant la commande 'yunohost log display {name} --share'",
- "log_does_exists": "Il n’existe pas de log de l’opération ayant pour nom '{log}', utiliser 'yunohost log list pour voir tous les fichiers de logs disponibles'",
- "log_operation_unit_unclosed_properly": "L’opération ne s’est pas terminée correctement",
- "log_app_addaccess": "Ajouter l’accès à '{}'",
- "log_app_removeaccess": "Enlever l’accès à '{}'",
+ "log_help_to_get_failed_log": "L’opération '{desc}' a échouée ! Pour avoir de l’aide, merci de partager le journal historisé de cette opération en utilisant la commande 'yunohost log display {name} --share'",
+ "log_does_exists": "Il n’existe pas de journal historisé de l’opération ayant pour nom '{log}', utiliser 'yunohost log list pour voir tous les fichiers de journaux historisés disponibles'",
+ "log_operation_unit_unclosed_properly": "L’opération ne s’est pas fermée/terminée correctement",
+ "log_app_addaccess": "Ajouter l’accès à '{}'",
+ "log_app_removeaccess": "Enlever l’accès à '{}'",
"log_app_clearaccess": "Retirer tous les accès à '{}'",
"log_app_fetchlist": "Ajouter une liste d’application",
"log_app_removelist": "Enlever une liste d’application",
- "log_app_change_url": "Changer l’url de l’application '{}'",
+ "log_app_change_url": "Changer l’URL de l’application '{}'",
"log_app_install": "Installer l’application '{}'",
"log_app_remove": "Enlever l’application '{}'",
"log_app_upgrade": "Mettre à jour l’application '{}'",
- "log_app_makedefault": "Faire de '{}' l’application par défaut",
- "log_available_on_yunopaste": "Le log est désormais disponible via {url}",
+ "log_app_makedefault": "Faire de '{}' l’application par défaut",
+ "log_available_on_yunopaste": "Le journal historisé est désormais disponible via {url}",
"log_backup_restore_system": "Restaurer le système depuis une archive de sauvegarde",
"log_backup_restore_app": "Restaurer '{}' depuis une sauvegarde",
- "log_remove_on_failed_restore": "Retirer '{}' après la restauration depuis une sauvegarde qui a échouée",
+ "log_remove_on_failed_restore": "Retirer '{}' après un échec de restauration depuis une archive de sauvegarde",
"log_remove_on_failed_install": "Enlever '{}' après une installation échouée",
"log_domain_add": "Ajouter le domaine '{}' dans la configuration du système",
"log_domain_remove": "Enlever le domaine '{}' de la configuration du système",
"log_dyndns_subscribe": "Souscrire au sous-domaine YunoHost '{}'",
"log_dyndns_update": "Mettre à jour l’adresse IP associée à votre sous-domaine YunoHost '{}'",
- "log_letsencrypt_cert_install": "Installer le certificat Let’s Encrypt sur le domaine '{}'",
+ "log_letsencrypt_cert_install": "Installer le certificat Let’s Encrypt sur le domaine '{}'",
"log_selfsigned_cert_install": "Installer le certificat auto-signé sur le domaine '{}'",
"log_letsencrypt_cert_renew": "Renouveler le certificat Let’s Encrypt de '{}'",
"log_service_enable": "Activer le service '{}'",
@@ -461,26 +461,26 @@
"log_tools_upgrade": "Mise à jour des paquets Debian",
"log_tools_shutdown": "Éteindre votre serveur",
"log_tools_reboot": "Redémarrer votre serveur",
- "mail_unavailable": "Cette adresse mail est réservée et doit être automatiquement attribuée au tout premier utilisateur",
- "migration_description_0004_php5_to_php7_pools": "Reconfigurez le pool PHP pour utiliser PHP 7 au lieu de 5",
- "migration_description_0005_postgresql_9p4_to_9p6": "Migration des bases de données de postgresql 9.4 vers 9.6",
- "migration_0005_postgresql_94_not_installed": "Postgresql n’a pas été installé sur votre système. Rien à faire !",
- "migration_0005_postgresql_96_not_installed": "Postgresql 9.4 a été trouvé et installé, mais pas Postgresql 9.6 !? Quelque chose d’étrange a dû arriver à votre système :( …",
+ "mail_unavailable": "Cette adresse de courriel est réservée et doit être automatiquement attribuée au tout premier utilisateur",
+ "migration_description_0004_php5_to_php7_pools": "Reconfigurez le pool PHP pour utiliser PHP 7 au lieu de PHP 5",
+ "migration_description_0005_postgresql_9p4_to_9p6": "Migration des bases de données de PostgreSQL 9.4 vers PostgreSQL 9.6",
+ "migration_0005_postgresql_94_not_installed": "PostgreSQL n’a pas été installé sur votre système. Rien à faire !",
+ "migration_0005_postgresql_96_not_installed": "PostgreSQL 9.4 a été trouvé et installé, mais pas PostgreSQL 9.6 !? Quelque chose d’étrange a dû arriver à votre système :( …",
"migration_0005_not_enough_space": "Il n’y a pas assez d’espace libre de disponible sur {path} pour lancer maintenant la migration :(.",
- "recommend_to_add_first_user": "La post-installation est terminée, mais YunoHost a besoin d’au moins un utilisateur pour fonctionner correctement. Vous devez en ajouter un en utilisant « yunohost user create » ou l’interface d’administration.",
- "service_description_php7.0-fpm": "exécute des applications écrites en PHP avec nginx",
+ "recommend_to_add_first_user": "La post-installation est terminée. YunoHost a besoin d’au moins un utilisateur pour fonctionner correctement. Vous devez en ajouter un en utilisant 'yunohost user create' ou bien via l’interface d’administration web.",
+ "service_description_php7.0-fpm": "exécute des applications écrites en PHP avec Nginx",
"users_available": "Liste des utilisateurs disponibles :",
"good_practices_about_admin_password": "Vous êtes maintenant sur le point de définir un nouveau mot de passe d’administration. Le mot de passe doit comporter au moins 8 caractères – bien qu’il soit recommandé d’utiliser un mot de passe plus long (c’est-à-dire une phrase secrète) et/ou d’utiliser différents types de caractères (majuscules, minuscules, chiffres et caractères spéciaux).",
"good_practices_about_user_password": "Vous êtes maintenant sur le point de définir un nouveau mot de passe utilisateur. Le mot de passe doit comporter au moins 8 caractères — bien qu'il soit recommandé d'utiliser un mot de passe plus long (c'est-à-dire une phrase secrète) et/ou d'utiliser différents types de caractères (majuscules, minuscules, chiffres et caractères spéciaux).",
"migration_description_0006_sync_admin_and_root_passwords": "Synchroniser les mots de passe admin et root",
- "migration_0006_disclaimer": "Yunohost s’attend maintenant à ce que les mots de passe admin et root soient synchronisés. En exécutant cette migration, votre mot de passe root sera remplacé par le mot de passe administrateur.",
+ "migration_0006_disclaimer": "YunoHost s’attendra à ce que les mots de passe admin et root soient synchronisés. En exécutant cette migration, votre mot de passe root sera remplacé par le mot de passe administrateur.",
"migration_0006_done": "Votre mot de passe root a été remplacé par celui de votre adminitrateur.",
- "password_listed": "Ce mot de passe est l'un des mots de passe les plus utilisés dans le monde. Veuillez choisir quelque chose d'un peu plus unique.",
+ "password_listed": "Ce mot de passe est l'un des mots de passe les plus utilisés dans le monde. Veuillez choisir quelque chose d'un peu plus singulier.",
"password_too_simple_1": "Le mot de passe doit comporter au moins 8 caractères",
"password_too_simple_2": "Le mot de passe doit comporter au moins 8 caractères et contenir des chiffres, des majuscules et des minuscules",
"password_too_simple_3": "Le mot de passe doit comporter au moins 8 caractères et contenir des chiffres, des majuscules, des minuscules et des caractères spéciaux",
"password_too_simple_4": "Le mot de passe doit comporter au moins 12 caractères et contenir des chiffres, des majuscules, des minuscules et des caractères spéciaux",
- "root_password_desynchronized": "Le mot de passe administrateur a été changé, mais YunoHost n’a pas pu le propager sur le mot de passe root !",
+ "root_password_desynchronized": "Le mot de passe administrateur a été changé, mais YunoHost n’a pas pu le propager au mot de passe root !",
"aborting": "Interruption de la procédure.",
"app_not_upgraded": "Les applications suivantes n'ont pas été mises à jour : {apps}",
"app_start_install": "Installation de l'application {app} …",
@@ -516,11 +516,11 @@
"pattern_password_app": "Désolé, les mots de passe ne doivent pas contenir les caractères suivants : {forbidden_chars}",
"root_password_replaced_by_admin_password": "Votre mot de passe root a été remplacé par votre mot de passe administrateur.",
"service_conf_now_managed_by_yunohost": "Le fichier de configuration '{conf}' est maintenant géré par YunoHost.",
- "service_reload_failed": "Impossible de recharger le service '{service:s}'.\n\nJournaux récents de ce service : {logs:s}",
+ "service_reload_failed": "Impossible de recharger le service '{service:s}'.\n\nJournaux historisés récents de ce service : {logs:s}",
"service_reloaded": "Le service '{service:s}' a été rechargé",
- "service_restart_failed": "Impossible de redémarrer le service '{service:s}'\n\nJournaux récents de ce service : {logs:s}",
+ "service_restart_failed": "Impossible de redémarrer le service '{service:s}'\n\nJournaux historisés récents de ce service : {logs:s}",
"service_restarted": "Le service '{service:s}' a été redémarré",
- "service_reload_or_restart_failed": "Impossible de recharger ou de redémarrer le service '{service:s}'\n\nJournaux récents de ce service : {logs:s}",
+ "service_reload_or_restart_failed": "Impossible de recharger ou de redémarrer le service '{service:s}'\n\nJournaux historisés récents de ce service : {logs:s}",
"service_reloaded_or_restarted": "Le service '{service:s}' a été rechargé ou redémarré",
- "this_action_broke_dpkg": "Cette action a laissé des paquets non configurés par dpkg/apt (les gestionnaires de paquets système). Vous pouvez essayer de résoudre ce problème en vous connectant via SSH et en exécutant `sudo dpkg --configure -a'."
+ "this_action_broke_dpkg": "Cette action a laissé des paquets non configurés par dpkg/apt (les gestionnaires de paquets système). Vous pouvez essayer de résoudre ce problème en vous connectant via SSH et en exécutant `sudo dpkg --configure -a`."
}
From 8954caa39d22cf59f07f90aa6d7ede925a2b60a8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Quent=C3=AD?=
Date: Sun, 17 Mar 2019 18:44:20 +0000
Subject: [PATCH 089/180] Translated using Weblate (Occitan)
Currently translated at 95.6% (482 of 504 strings)
Translation: YunoHost/core
Translate-URL: https://translate.yunohost.org/projects/yunohost/core/oc/
---
locales/oc.json | 48 ++++++++++++++++++++++++++++++++++--------------
1 file changed, 34 insertions(+), 14 deletions(-)
diff --git a/locales/oc.json b/locales/oc.json
index 91b455210..433da4478 100644
--- a/locales/oc.json
+++ b/locales/oc.json
@@ -13,7 +13,7 @@
"app_not_properly_removed": "{app:s} es pas estat corrèctament suprimit",
"app_removed": "{app:s} es estat suprimit",
"app_unknown": "Aplicacion desconeguda",
- "app_upgrade_app_name": "Mesa a jorn de l’aplicacion {app}...",
+ "app_upgrade_app_name": "Mesa a jorn de l’aplicacion {app}…",
"app_upgrade_failed": "Impossible de metre a jorn {app:s}",
"app_upgrade_some_app_failed": "D’aplicacions se pòdon pas metre a jorn",
"app_upgraded": "{app:s} es estat mes a jorn",
@@ -52,7 +52,7 @@
"app_location_already_used": "L’aplicacion « {app} » es ja installada a aqueste emplaçament ({path})",
"app_manifest_invalid": "Manifest d’aplicacion incorrècte : {error}",
"app_package_need_update": "Lo paquet de l’aplicacion {app} deu èsser mes a jorn per seguir los cambiaments de YunoHost",
- "app_requirements_checking": "Verificacion dels paquets requesida per {app}...",
+ "app_requirements_checking": "Verificacion dels paquets requesits per {app}…",
"app_sources_fetch_failed": "Recuperacion dels fichièrs fonts impossibla",
"app_unsupported_remote_type": "Lo tipe alonhat utilizat per l’aplicacion es pas suportat",
"appslist_retrieve_error": "Impossible de recuperar la lista d’aplicacions alonhadas {appslist:s} : {error:s}",
@@ -64,7 +64,7 @@
"backup_cleaning_failed": "Impossible de netejar lo repertòri temporari de salvagarda",
"backup_copying_to_organize_the_archive": "Còpia de {size:s} Mio per organizar l’archiu",
"backup_created": "Salvagarda acabada",
- "backup_creating_archive": "Creacion de l’archiu de salvagarda...",
+ "backup_creating_archive": "Creacion de l’archiu de salvagarda…",
"backup_creation_failed": "Impossible de crear la salvagarda",
"app_already_installed_cant_change_url": "Aquesta aplicacion es ja installada. Aquesta foncion pòt pas simplament cambiar l’URL. Agachatz « app changeurl » s’es disponible.",
"app_change_no_change_url_script": "L’aplicacion {app_name:s} pren pas en compte lo cambiament d’URL, poiretz aver de la metre a jorn.",
@@ -83,7 +83,7 @@
"backup_output_directory_not_empty": "Lo dorsièr de sortida es pas void",
"backup_output_directory_required": "Vos cal especificar un dorsièr de sortida per la salvagarda",
"backup_running_app_script": "Lançament de l’escript de salvagarda de l’aplicacion « {app:s} »...",
- "backup_running_hooks": "Execucion dels scripts de salvagarda...",
+ "backup_running_hooks": "Execucion dels scripts de salvagarda…",
"backup_system_part_failed": "Impossible de salvagardar la part « {part:s} » del sistèma",
"app_requirements_failed": "Impossible de complir las condicions requesidas per {app} : {error}",
"app_requirements_unmeet": "Las condicions requesidas per {app} son pas complidas, lo paquet {pkgname} ({version}) deu èsser {spec}",
@@ -112,7 +112,7 @@
"upnp_port_open_failed": "Impossible de dobrir los pòrts amb UPnP",
"yunohost_already_installed": "YunoHost es ja installat",
"yunohost_configured": "YunoHost es estat configurat",
- "yunohost_installing": "Installacion de YunoHost...",
+ "yunohost_installing": "Installacion de YunoHost…",
"backup_applying_method_borg": "Mandadís de totes los fichièrs a la salvagarda dins lo repertòri borg-backup…",
"backup_csv_creation_failed": "Creacion impossibla del fichièr CSV necessari a las operacions futuras de restauracion",
"backup_extracting_archive": "Extraccion de l’archiu de salvagarda…",
@@ -161,7 +161,7 @@
"dyndns_cron_removed": "La tasca cron pel domeni DynDNS es levada",
"dyndns_ip_update_failed": "Impossible d’actualizar l’adreça IP sul domeni DynDNS",
"dyndns_ip_updated": "Vòstra adreça IP es estada actualizada pel domeni DynDNS",
- "dyndns_key_generating": "La clau DNS es a se generar, pòt trigar una estona...",
+ "dyndns_key_generating": "La clau DNS es a se generar, pòt trigar una estona…",
"dyndns_key_not_found": "Clau DNS introbabla pel domeni",
"dyndns_no_domain_registered": "Cap de domeni pas enregistrat amb DynDNS",
"dyndns_registered": "Lo domeni DynDNS es enregistrat",
@@ -313,7 +313,7 @@
"service_conf_would_be_updated": "La configuracion del servici « {service} » seriá estada actualizada",
"service_description_avahi-daemon": "permet d’aténher vòstre servidor via yunohost.local sus vòstre ret local",
"service_description_dnsmasq": "gerís la resolucion dels noms de domeni (DNS)",
- "updating_apt_cache": "Actualizacion de la lista dels paquets disponibles...",
+ "updating_apt_cache": "Actualizacion de la lista dels paquets disponibles…",
"service_conf_file_backed_up": "Lo fichièr de configuracion « {conf} » es salvagardat dins « {backup} »",
"service_conf_file_copy_failed": "Còpia impossibla del nòu fichièr de configuracion « {new} » cap a « {conf} »",
"server_reboot_confirm": "Lo servidor es per reaviar sul pic, o volètz vertadièrament ? {answers:s}",
@@ -372,7 +372,7 @@
"migrate_tsig_start": "L’algorisme de generacion de claus es pas pro securizat per la signatura TSIG del domeni « {domain} », lançament de la migracion cap a hmac-sha512 que’s mai securizat",
"migration_description_0001_change_cert_group_to_sslcert": "Càmbia las permissions de grop dels certificats de « metronome » per « ssl-cert »",
"migration_0003_restoring_origin_nginx_conf": "Vòstre fichièr /etc/nginx/nginx.conf es estat modificat manualament. La migracion reïnicializarà d’en primièr son estat origina… Lo fichièr precedent serà disponible coma {backup_dest}.",
- "migration_0003_still_on_jessie_after_main_upgrade": "Quicòm a trucat pendent la mesa a nivèl màger : lo sistèma es encara jos Jessie ?!? Per trobar lo problèma, agachatz {log} …",
+ "migration_0003_still_on_jessie_after_main_upgrade": "Quicòm a trucat pendent la mesa a nivèl màger : lo sistèma es encara jos Jessie ?!? Per trobar lo problèma, agachatz {log}…",
"migration_0003_general_warning": "Notatz qu’aquesta migracion es una operacion delicata. Encara que la còla YunoHost aguèsse fach çò melhor per la tornar legir e provar, la migracion poiriá copar de parts del sistèma o de las aplicacions.\n\nEn consequéncia, vos recomandam :\n· · · · - de lançar una salvagarda de vòstras donadas o aplicacions criticas. Mai d’informacions a https://yunohost.org/backup ;\n· · · · - d’èsser pacient aprèp aver lançat la migracion : segon vòstra connexion Internet e material, pòt trigar qualques oras per que tot siá mes al nivèl.\n\nEn mai, lo pòrt per SMTP, utilizat pels clients de corrièls extèrns (coma Thunderbird o K9-Mail per exemple) foguèt cambiat de 465 (SSL/TLS) per 587 (STARTTLS). L’ancian pòrt 465 serà automaticament tampat e lo nòu pòrt 587 serà dobèrt dins lo parafuòc. Vosautres e vòstres utilizaires *auretz* d’adaptar la configuracion de vòstre client de corrièl segon aqueles cambiaments !",
"migration_0003_problematic_apps_warning": "Notatz que las aplicacions seguentas, saique problematicas, son estadas desactivadas. Semblan d’aver estadas installadas d’una lista d’aplicacions o que son pas marcadas coma «working ». En consequéncia, podèm pas assegurar que tendràn de foncionar aprèp la mesa a nivèl : {problematic_apps}",
"migrations_bad_value_for_target": "Nombre invalid pel paramètre « target », los numèros de migracion son 0 o {}",
@@ -457,14 +457,34 @@
"service_description_php7.0-fpm": "executa d’aplicacions escrichas en PHP amb nginx",
"users_available": "Lista dels utilizaires disponibles :",
"good_practices_about_admin_password": "Sètz per definir un nòu senhal per l’administracion. Lo senhal deu almens conténer 8 caractèrs - encara que siá de bon far d’utilizar un senhal mai long qu’aquò (ex. una passafrasa) e/o d’utilizar mantun tipes de caractèrs (majuscula, minuscula, nombre e caractèrs especials).",
- "good_practices_about_user_password": "Sètz per definir un nòu senhal d’utilizaire. Lo senhal deu almens conténer 8 caractèrs - encara que siá de bon far d’utilizar un senhal mai long qu’aquò (ex. una passafrasa) e/o d’utilizar mantun tipes de caractèrs (majuscula, minuscula, nombre e caractèrs especials).",
+ "good_practices_about_user_password": "Sètz a mand de definir un nòu senhal d’utilizaire. Lo nòu senhal deu conténer almens 8 caractèrs, es de bon far d’utilizar un senhal mai long (es a dire una frasa de senhal) e/o utilizar mantuns tipes de caractèrs (majusculas, minusculas, nombres e caractèrs especials).",
"migration_description_0006_sync_admin_and_root_passwords": "Sincronizar los senhals admin e root",
"migration_0006_disclaimer": "Ara YunoHost s’espèra que los senhals admin e root sián sincronizats. En lançant aquesta migracion, vòstre senhal root serà remplaçat pel senhal admin.",
"migration_0006_done": "Lo senhal root es estat remplaçat pel senhal admin.",
- "password_listed": "Aqueste senhal fa part dels senhals mai utilizats del monde. Volgatz ben ne causir un mai unic.",
+ "password_listed": "Aqueste senhal es un dels mai utilizats al monde. Se vos plai utilizatz-ne un mai unic.",
"password_too_simple_1": "Lo senhal deu conténer almens 8 caractèrs",
- "password_too_simple_2": "Lo senhal deu conténer almens 8 caractèrs amb de nombres, de majusculas e de minusculas",
- "password_too_simple_3": "Lo senhal deu conténer almens 8 caractèrs amb de nombres, de majusculas, de minusculas e de caractèrs especials",
- "password_too_simple_4": "Lo senhal deu conténer almens 12 caractèrs amb de nombres, de majusculas, de minusculas e de caractèrs especials",
- "root_password_desynchronized": "Lo senhal de l’administrator es estat cambiat, mas YunoHost a pas pogut l’espandir al senhal root !"
+ "password_too_simple_2": "Lo senhal deu conténer almens 8 caractèrs e numbres, majusculas e minusculas",
+ "password_too_simple_3": "Lo senhal deu conténer almens 8 caractèrs e nombres, majusculas e minusculas e caractèrs especials",
+ "password_too_simple_4": "Lo senhal deu conténer almens 12 caractèrs, de nombre, majusculas, minisculas e caractèrs specials",
+ "root_password_desynchronized": "Lo senhal de l’administrator es estat cambiat, mas YunoHost a pas pogut l’espandir al senhal root !",
+ "aborting": "Interrupcion.",
+ "app_not_upgraded": "Las aplicacions seguentas son pas estadas actualizadas : {apps}",
+ "app_start_install": "Installacion de l’aplicacion {app}…",
+ "app_start_remove": "Supression de l’aplicacion {app}…",
+ "app_start_backup": "Recuperacion dels fichièrs de salvagardar per {app}…",
+ "app_start_restore": "Restauracion de l’aplicacion {app}…",
+ "app_upgrade_several_apps": "Las aplicacions seguentas seràn mesas a jorn : {apps}",
+ "ask_new_domain": "Nòu domeni",
+ "ask_new_path": "Nòu camin",
+ "backup_actually_backuping": "Creacion d’un archiu de seguretat a partir dels fichièrs recuperats…",
+ "backup_mount_archive_for_restore": "Preparacion de l’archiu per restauracion…",
+ "dyndns_could_not_check_available": "Verificacion impossibla de la disponibilitat de {domain:s} sus {provider:s}.",
+ "file_does_not_exist": "Lo camin {path:s} existís pas.",
+ "global_settings_setting_security_password_admin_strength": "Fòrça del senhal administrator",
+ "global_settings_setting_security_password_user_strength": "Fòrça del senhal utilizaire",
+ "migration_description_0007_ssh_conf_managed_by_yunohost_step1": "La configuracion SSH serà gerada per YunoHost (etapa 1, automatica)",
+ "migration_description_0008_ssh_conf_managed_by_yunohost_step2": "Daissar YunoHost gerir la configuracion SSH (etapa 2, manuala)",
+ "migration_0007_cancelled": "YunoHost a pas reüssit a melhorar lo biais de gerir la configuracion SSH.",
+ "root_password_replaced_by_admin_password": "Lo senhal root es estat remplaçat pel senhal administrator.",
+ "service_restarted": "Lo servici '{service:s}' es estat reaviat"
}
From 70ebf9b121778bda831cbb586cfe569394ae6ea2 Mon Sep 17 00:00:00 2001
From: xaloc33
Date: Thu, 21 Mar 2019 10:07:28 +0000
Subject: [PATCH 090/180] Translated using Weblate (Catalan)
Currently translated at 31.7% (160 of 504 strings)
Translation: YunoHost/core
Translate-URL: https://translate.yunohost.org/projects/yunohost/core/ca/
---
locales/ca.json | 48 +++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 47 insertions(+), 1 deletion(-)
diff --git a/locales/ca.json b/locales/ca.json
index 44d473d91..dd01ddebb 100644
--- a/locales/ca.json
+++ b/locales/ca.json
@@ -112,5 +112,51 @@
"password_too_simple_1": "La contrasenya ha de tenir un mínim de 8 caràcters",
"password_too_simple_2": "La contrasenya ha de tenir un mínim de 8 caràcters i ha de contenir dígits, majúscules i minúscules",
"password_too_simple_3": "La contrasenya ha de tenir un mínim de 8 caràcters i tenir dígits, majúscules, minúscules i caràcters especials",
- "password_too_simple_4": "La contrasenya ha de tenir un mínim de 12 caràcters i tenir dígits, majúscules, minúscules i caràcters especials"
+ "password_too_simple_4": "La contrasenya ha de tenir un mínim de 12 caràcters i tenir dígits, majúscules, minúscules i caràcters especials",
+ "backup_no_uncompress_archive_dir": "El directori de l'arxiu descomprimit no existeix",
+ "backup_nothings_done": "No hi ha res a guardar",
+ "backup_output_directory_forbidden": "Directori de sortida no permès. Les còpies de seguretat no es poden crear ni dins els directoris /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var ni dins els subdirectoris /home/yunohost.backup/archives",
+ "backup_output_directory_not_empty": "El directori de sortida no està buit",
+ "backup_output_directory_required": "Heu d'especificar un directori de sortida per la còpia de seguretat",
+ "backup_output_symlink_dir_broken": "Teniu un enllaç simbòlic trencat en lloc del directori dels arxius '{path:s}'. Pot ser teniu una configuració per la còpia de seguretat específica en un altre sistema de fitxers, si és el cas segurament heu oblidat muntar o connectar el disc dur o la clau USB.",
+ "backup_php5_to_php7_migration_may_fail": "No s'ha pogut convertir l'arxiu per suportar php7, la restauració de les vostres aplicacions pot fallar (raó: {error:s})",
+ "backup_running_hooks": "Executant els scripts de la còpia de seguretat…",
+ "backup_system_part_failed": "No s'ha pogut fer la còpia de seguretat de la part \"{part:s}\" del sistema",
+ "backup_unable_to_organize_files": "No s'han pogut organitzar els fitxers dins de l'arxiu amb el mètode ràpid",
+ "backup_with_no_backup_script_for_app": "L'aplicació {app:s} no té un script de còpia de seguretat. Serà ignorat.",
+ "backup_with_no_restore_script_for_app": "L'aplicació {app:s} no té un script de restauració, no podreu restaurar automàticament la còpia de seguretat d'aquesta aplicació.",
+ "certmanager_acme_not_configured_for_domain": "El certificat pel domini {domain:s} sembla que no està instal·lat correctament. Si us plau executeu primer cert-install per aquest domini.",
+ "certmanager_attempt_to_renew_nonLE_cert": "El certificat pel domini {domain:s} no ha estat emès per Let's Encrypt. No es pot renovar automàticament!",
+ "certmanager_attempt_to_renew_valid_cert": "El certificat pel domini {domain:s} està a punt de caducar! Utilitzeu --force per ometre",
+ "certmanager_attempt_to_replace_valid_cert": "Esteu intentant sobreescriure un certificat correcte i vàlid pel domini {domain:s}! (Utilitzeu --force per ometre)",
+ "certmanager_cannot_read_cert": "S'ha produït un error al intentar obrir el certificat actual pel domini {domain:s} (arxiu: {file:s}), raó: {reason:s}",
+ "certmanager_cert_install_success": "S'ha instal·lat correctament un certificat Let's Encrypt pel domini {domain:s}!",
+ "certmanager_cert_install_success_selfsigned": "S'ha instal·lat correctament un certificat auto-signat pel domini {domain:s}!",
+ "certmanager_cert_renew_success": "S'ha renovat correctament el certificat Let's Encrypt pel domini {domain:s}!",
+ "certmanager_cert_signing_failed": "No s'ha pogut firmar el nou certificat",
+ "certmanager_certificate_fetching_or_enabling_failed": "Sembla que l'activació del nou certificat per {domain:s} ha fallat…",
+ "certmanager_conflicting_nginx_file": "No s'ha pogut preparar el domini per al desafiament ACME: l'arxiu de configuració nginx {filepath:s} entra en conflicte i s'ha d'eliminar primer",
+ "certmanager_couldnt_fetch_intermediate_cert": "S'ha exhaurit el temps d'esperar al intentar recollir el certificat intermedi des de Let's Encrypt. La instal·lació/renovació del certificat s'ha cancel·lat - torneu a intentar-ho més tard.",
+ "certmanager_domain_cert_not_selfsigned": "El certificat pel domini {domain:s} no és auto-signat Esteu segur de voler canviar-lo? (Utilitzeu --force per fer-ho)",
+ "certmanager_domain_dns_ip_differs_from_public_ip": "El registre DNS \"A\" pel domini {domain:s} és diferent a l'adreça IP d'aquest servidor. Si heu modificat recentment el registre A, si us plau espereu a que es propagui (hi ha eines per verificar la propagació disponibles a internet). (Si sabeu el que esteu fent, podeu utilitzar --no-checks per desactivar aquestes comprovacions.)",
+ "certmanager_domain_http_not_working": "Sembla que el domini {domain:s} no és accessible via HTTP. Si us plau verifiqueu que les configuracions DNS i nginx siguin correctes",
+ "certmanager_domain_not_resolved_locally": "El domini {domain:s} no es pot resoldre dins del vostre servidor YunoHost. Això pot passar si heu modificat recentment el registre DNS. Si és així, si us plau espereu unes hores per a que es propagui. Si el problema continua, considereu afegir {domain:s} a /etc/hosts. (Si sabeu el que esteu fent, podeu utilitzar --no-checks per desactivar aquestes comprovacions.)",
+ "certmanager_domain_unknown": "Domini desconegut {domain:s}",
+ "certmanager_error_no_A_record": "No s'ha trobat cap registre DNS \"A\" per {domain:s}. Heu de fer que el vostre nom de domini apunti cap a la vostra màquina per tal de poder instal·lar un certificat Let's Encrypt! (Si sabeu el que esteu fent, podeu utilitzar --no-checks per desactivar aquestes comprovacions.)",
+ "certmanager_hit_rate_limit": "S'han emès massa certificats recentment per aquest mateix conjunt de dominis {domain:s}. Si us plau torneu-ho a intentar més tard. Consulteu https://letsencrypt.org/docs/rate-limits/ per obtenir més detalls",
+ "certmanager_http_check_timeout": "S'ha exhaurit el temps d'espera quan el servidor ha intentat contactar amb ell mateix via HTTP utilitzant la seva adreça IP pública (domini domain:s} amb IP {ip:s}). Pot ser degut a hairpinning o a que el talla focs/router al que està connectat el servidor estan mal configurats.",
+ "certmanager_no_cert_file": "No s'ha pogut llegir l'arxiu del certificat pel domini {domain:s} (fitxer: {file:s})",
+ "certmanager_self_ca_conf_file_not_found": "No s'ha trobat el fitxer de configuració per l'autoritat del certificat auto-signat (fitxer: {file:s})",
+ "certmanager_unable_to_parse_self_CA_name": "No s'ha pogut analitzar el nom de l'autoritat del certificat auto-signat (fitxer: {file:s})",
+ "confirm_app_install_warning": "Atenció: aquesta aplicació funciona però no està ben integrada amb YunoHost. Algunes característiques com la autenticació única i la còpia de seguretat/restauració poden no estar disponibles. Voleu instal·lar-la de totes maneres? [{answers:s}] ",
+ "confirm_app_install_danger": "ATENCIÓ! Aquesta aplicació encara és experimental (si no és que no funciona directament) i és probable que trenqui el sistema! No hauríeu d'instal·lar-la a no ser que sapigueu el que feu. Esteu segurs de voler córrer aquest risc? [{answers:s}] ",
+ "confirm_app_install_thirdparty": "ATENCIÓ! La instal·lació d'aplicacions de terceres parts pot comprometre la integritat i seguretat del seu sistema. Faci-ho sota la seva responsabilitat.No hauríeu d'instal·lar-ne a no ser que sapigueu el que feu. Esteu segurs de voler córrer aquest risc? [{answers:s}] ",
+ "custom_app_url_required": "Heu de especificar una URL per actualitzar la vostra aplicació personalitzada {app:s}",
+ "custom_appslist_name_required": "Heu d'especificar un nom per la vostra llista d'aplicacions personalitzada",
+ "diagnosis_debian_version_error": "No s'ha pogut obtenir la versió Debian: {error}",
+ "diagnosis_kernel_version_error": "No s'ha pogut obtenir la versió del nucli: {error}",
+ "diagnosis_monitor_disk_error": "No es poden monitorar els discs: {error}",
+ "diagnosis_monitor_network_error": "No es pot monitorar la xarxa: {error}",
+ "diagnosis_monitor_system_error": "No es pot monitorar el sistema: {error}",
+ "diagnosis_no_apps": "No hi ha cap aplicació instal·lada"
}
From ce596a401aebe364e98e97543b240280b450a537 Mon Sep 17 00:00:00 2001
From: Jean-Baptiste Holcroft
Date: Fri, 22 Mar 2019 05:48:11 +0000
Subject: [PATCH 091/180] Translated using Weblate (French)
Currently translated at 97.0% (489 of 504 strings)
Translation: YunoHost/core
Translate-URL: https://translate.yunohost.org/projects/yunohost/core/fr/
---
locales/fr.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/locales/fr.json b/locales/fr.json
index 58c25d3ad..1948751da 100644
--- a/locales/fr.json
+++ b/locales/fr.json
@@ -471,7 +471,7 @@
"service_description_php7.0-fpm": "exécute des applications écrites en PHP avec Nginx",
"users_available": "Liste des utilisateurs disponibles :",
"good_practices_about_admin_password": "Vous êtes maintenant sur le point de définir un nouveau mot de passe d’administration. Le mot de passe doit comporter au moins 8 caractères – bien qu’il soit recommandé d’utiliser un mot de passe plus long (c’est-à-dire une phrase secrète) et/ou d’utiliser différents types de caractères (majuscules, minuscules, chiffres et caractères spéciaux).",
- "good_practices_about_user_password": "Vous êtes maintenant sur le point de définir un nouveau mot de passe utilisateur. Le mot de passe doit comporter au moins 8 caractères — bien qu'il soit recommandé d'utiliser un mot de passe plus long (c'est-à-dire une phrase secrète) et/ou d'utiliser différents types de caractères (majuscules, minuscules, chiffres et caractères spéciaux).",
+ "good_practices_about_user_password": "Vous êtes maintenant sur le point de définir un nouveau mot de passe utilisateur. Le mot de passe doit comporter au moins 8 caractères — bien qu’il soit recommandé d’utiliser un mot de passe plus long (c’est-à-dire une phrase secrète) et/ou d’utiliser différents types de caractères (majuscules, minuscules, chiffres et caractères spéciaux).",
"migration_description_0006_sync_admin_and_root_passwords": "Synchroniser les mots de passe admin et root",
"migration_0006_disclaimer": "YunoHost s’attendra à ce que les mots de passe admin et root soient synchronisés. En exécutant cette migration, votre mot de passe root sera remplacé par le mot de passe administrateur.",
"migration_0006_done": "Votre mot de passe root a été remplacé par celui de votre adminitrateur.",
@@ -481,7 +481,7 @@
"password_too_simple_3": "Le mot de passe doit comporter au moins 8 caractères et contenir des chiffres, des majuscules, des minuscules et des caractères spéciaux",
"password_too_simple_4": "Le mot de passe doit comporter au moins 12 caractères et contenir des chiffres, des majuscules, des minuscules et des caractères spéciaux",
"root_password_desynchronized": "Le mot de passe administrateur a été changé, mais YunoHost n’a pas pu le propager au mot de passe root !",
- "aborting": "Interruption de la procédure.",
+ "aborting": "Interruption.",
"app_not_upgraded": "Les applications suivantes n'ont pas été mises à jour : {apps}",
"app_start_install": "Installation de l'application {app} …",
"app_start_remove": "Suppression de l'application {app} …",
From fc43640ae2fa660b2663870741926f6a47e80b94 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?M=C3=A9lanie=20Chauvel?=
Date: Fri, 22 Mar 2019 20:37:49 +0000
Subject: [PATCH 092/180] Translated using Weblate (French)
Currently translated at 98.8% (498 of 504 strings)
Translation: YunoHost/core
Translate-URL: https://translate.yunohost.org/projects/yunohost/core/fr/
---
locales/fr.json | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/locales/fr.json b/locales/fr.json
index 1948751da..d8d3edbb1 100644
--- a/locales/fr.json
+++ b/locales/fr.json
@@ -120,7 +120,7 @@
"ldap_initialized": "L’annuaire LDAP a été initialisé",
"license_undefined": "indéfinie",
"mail_alias_remove_failed": "Impossible de supprimer l’alias de courriel '{mail:s}'",
- "mail_domain_unknown": "Le domaine '{domain:s}' est inconnu pour cette adresse de courriel",
+ "mail_domain_unknown": "Le domaine « {domain:s} » du courriel est inconnu",
"mail_forward_remove_failed": "Impossible de supprimer le courriel de transfert '{mail:s}'",
"maindomain_change_failed": "Impossible de modifier le domaine principal",
"maindomain_changed": "Le domaine principal a été modifié",
@@ -153,7 +153,7 @@
"packages_upgrade_critical_later": "Les paquets critiques ({packages:s}) seront mis à jour ultérieurement",
"packages_upgrade_failed": "Impossible de mettre à jour tous les paquets",
"path_removal_failed": "Impossible de supprimer le chemin {:s}",
- "pattern_backup_archive_name": "Doit être un nom de fichier valide avec un maximum de 30 caractères, et composé uniquement de caractères alphanumériques et de tirets tels que -_.",
+ "pattern_backup_archive_name": "Doit être un nom de fichier valide avec un maximum de 30 caractères, et composé de caractères alphanumériques et -_. uniquement",
"pattern_domain": "Doit être un nom de domaine valide (ex : mon-domaine.fr)",
"pattern_email": "Doit être une adresse de courriel valide (ex. : pseudo@domaine.fr)",
"pattern_firstname": "Doit être un prénom valide",
@@ -264,7 +264,7 @@
"certmanager_cert_renew_success": "Renouvellement avec succès d’un certificat Let’s Encrypt pour le domaine {domain:s} !",
"certmanager_old_letsencrypt_app_detected": "\nYunoHost a détecté que l’application « letsencrypt » est installé, ce qui est en conflit avec les nouvelles fonctionnalités de gestion intégrée de certificats dans YunoHost. Si vous souhaitez utiliser ces nouvelles fonctionnalités intégrées, veuillez lancer les commandes suivantes pour migrer votre installation :\n\n yunohost app remove letsencrypt\n yunohost domain cert-install\n\nN.B. : cela tentera de réinstaller les certificats de tous les domaines avec un certificat Let's Encrypt ou ceux auto-signés",
"certmanager_cert_signing_failed": "La signature du nouveau certificat a échoué",
- "certmanager_no_cert_file": "Impossible de lire le fichier de/du certificat pour le domaine {domain:s} (fichier : {file:s})",
+ "certmanager_no_cert_file": "Impossible de lire le fichier du certificat pour le domaine {domain:s} (fichier : {file:s})",
"certmanager_conflicting_nginx_file": "Impossible de préparer le domaine pour le défi ACME : le fichier de configuration Nginx {filepath:s} est en conflit et doit être préalablement retiré",
"certmanager_hit_rate_limit": "Trop de certificats ont déjà été émis récemment pour ce même ensemble de domaines {domain:s}. Veuillez réessayer plus tard. Lisez https://letsencrypt.org/docs/rate-limits/ pour obtenir plus de détails sur les ratios et limitations",
"ldap_init_failed_to_create_admin": "L’initialisation de l'annuaire LDAP n’a pas réussi à créer l’utilisateur admin",
@@ -297,7 +297,7 @@
"app_location_unavailable": "Cette URL n’est pas disponible ou est en conflit avec une application existante :\n{apps:s}",
"app_already_up_to_date": "{app:s} est déjà à jour",
"invalid_url_format": "Format d’URL non valide",
- "global_settings_bad_choice_for_enum": "La valeur du paramètre {setting:s} est incorrecte. Reçu {received_type:s} alors que {expected_type:s} était attendu",
+ "global_settings_bad_choice_for_enum": "Valeur du paramètre {setting:s} incorrecte. Reçu : {received_type:s}, mais les valeurs possibles sont : {expected_type:s}",
"global_settings_bad_type_for_setting": "Le type du paramètre {setting:s} est incorrect. Reçu {received_type:s} alors que {expected_type:s} était attendu",
"global_settings_cant_open_settings": "Échec de l’ouverture du ficher de configurations car : {reason:s}",
"global_settings_cant_serialize_setings": "Échec de sérialisation des données de configurations, cause : {reason:s}",
@@ -315,7 +315,7 @@
"backup_abstract_method": "Cette méthode de sauvegarde n’a pas encore été implémentée",
"backup_applying_method_tar": "Création de l’archive tar de la sauvegarde …",
"backup_applying_method_copy": "Copie de tous les fichiers à sauvegarder …",
- "backup_applying_method_borg": "Envoi de tous les fichiers à sauvegarder dans le référentiel/répertoire borg-backup …",
+ "backup_applying_method_borg": "Envoi de tous les fichiers à sauvegarder dans le répertoire borg-backup…",
"backup_applying_method_custom": "Appel de la méthode de sauvegarde personnalisée '{method:s}' …",
"backup_archive_system_part_not_available": "La partie '{part:s}' du système n’est pas disponible dans cette sauvegarde",
"backup_archive_mount_failed": "Le montage de l’archive de sauvegarde a échoué",
@@ -347,7 +347,7 @@
"restore_system_part_failed": "Impossible de restaurer la partie '{part:s}' du système",
"backup_couldnt_bind": "Impossible de lier {src:s} avec {dest:s}.",
"domain_dns_conf_is_just_a_recommendation": "Cette page montre la configuration *recommandée*. Elle ne configure *pas* le DNS pour vous. Il est de votre responsabilité que de configurer votre zone DNS chez votre fournisseur/registrar DNS avec cette recommandation.",
- "domain_dyndns_dynette_is_unreachable": "Impossible de contacter la dynette YunoHost. Soit YunoHost n’est pas correctement connecté à internet, soit le serveur de dynette est en panne ou ne répond pas. Erreur : {error}",
+ "domain_dyndns_dynette_is_unreachable": "Impossible de contacter la dynette YunoHost. Soit YunoHost n’est pas correctement connecté à internet, soit le serveur de dynette est en panne. Erreur : {error}",
"migrations_backward": "Migration en arrière.",
"migrations_bad_value_for_target": "Nombre invalide pour le paramètre target, les numéros de migration sont 0 ou {}",
"migrations_cant_reach_migration_file": "Impossible d’accéder aux fichiers de migrations avec le chemin %s",
@@ -370,7 +370,7 @@
"dyndns_domain_not_provided": "Le fournisseur DynDNS {provider:s} ne peut pas fournir le domaine {domain:s}.",
"app_make_default_location_already_used": "Impossible de configurer l’application '{app}' par défaut pour le domaine {domain} car il est déjà utilisé par l'application '{other_app}'",
"app_upgrade_app_name": "Mise à jour de l’application {app} …",
- "backup_output_symlink_dir_broken": "Vous avez un lien symbolique cassé à la place de votre dossier d’archives '{path:s}'. Vous pourriez avoir une configuration personnalisée pour sauvegarder vos données sur un autre système de fichiers, dans ce cas, vous avez probablement oublié de monter ou de connecter votre disque dur ou votre clef USB.",
+ "backup_output_symlink_dir_broken": "Vous avez un lien symbolique cassé à la place de votre dossier d’archives « {path:s} ». Vous pourriez avoir une configuration personnalisée pour sauvegarder vos données sur un autre système de fichiers, dans ce cas, vous avez probablement oublié de monter ou de connecter votre disque dur ou votre clé USB.",
"migrate_tsig_end": "La migration à hmac-sha512 est terminée",
"migrate_tsig_failed": "La migration du domaine DynDNS {domain} à hmac-sha512 a échoué. Annulation des modifications. Erreur : {error_code} - {error}",
"migrate_tsig_start": "L’algorithme de génération des clefs n’est pas suffisamment sécurisé pour la signature TSIG du domaine '{domain}', lancement de la migration vers hmac-sha512 qui est plus sécurisé",
@@ -380,7 +380,7 @@
"migrate_tsig_wait_4": "30 secondes …",
"migrate_tsig_not_needed": "Il ne semble pas que vous utilisez un domaine DynDNS, donc aucune migration n’est nécessaire !",
"app_checkurl_is_deprecated": "Packagers /!\\ 'app checkurl' est obsolète ! Utilisez 'app register-url' en remplacement !",
- "migration_description_0001_change_cert_group_to_sslcert": "Changement des permissions de groupe des certificats de 'metronome' à 'ssl-cert'",
+ "migration_description_0001_change_cert_group_to_sslcert": "Changement des permissions de groupe des certificats de « metronome » à « ssl-cert »",
"migration_description_0002_migrate_to_tsig_sha256": "Amélioration de la sécurité de DynDNS TSIG en utilisant SHA512 au lieu de MD5",
"migration_description_0003_migrate_to_stretch": "Mise à niveau du système vers Debian Stretch et YunoHost 3.0",
"migration_0003_backward_impossible": "La migration Stretch n’est pas réversible.",
@@ -392,7 +392,7 @@
"migration_0003_yunohost_upgrade": "Démarrage de la mise à niveau du paquet YunoHost. La migration se terminera, mais la mise à jour réelle aura lieu immédiatement après. Une fois cette opération terminée, vous pourriez avoir à vous reconnecter à l’administration via le panel web.",
"migration_0003_not_jessie": "La distribution Debian actuelle n’est pas Jessie !",
"migration_0003_system_not_fully_up_to_date": "Votre système n’est pas complètement à jour. Veuillez mener une mise à jour classique avant de lancer à migration à Stretch.",
- "migration_0003_still_on_jessie_after_main_upgrade": "Quelque chose s’est mal passé pendant la mise à niveau principale : le système est toujours sur Jessie !? Pour en savoir plus et investiguer sur ce problème, veuillez regarder les journaux {log}:s .",
+ "migration_0003_still_on_jessie_after_main_upgrade": "Quelque chose s’est mal passé pendant la mise à niveau principale : le système est toujours sur Jessie !? Pour investiguer sur problème, veuillez regarder les journaux {log}:s…",
"migration_0003_general_warning": "Veuillez noter que cette migration est une opération délicate. Si l’équipe YunoHost a fait de son mieux pour la relire et la tester, la migration pourrait tout de même casser des parties de votre système ou de vos applications.\n\nEn conséquence, nous vous recommandons :\n - de lancer une sauvegarde de vos données ou applications critiques. Plus d’informations sur https://yunohost.org/backup ;\n - d’être patient après avoir lancé la migration : selon votre connexion internet et matériel, cela pourrait prendre jusqu’à quelques heures pour que tout soit à niveau.\n\nEn outre, le port SMTP utilisé par les clients de messagerie externes comme (Thunderbird ou K9-Mail) a été changé de 465 (SSL/TLS) à 587 (STARTTLS). L’ancien port 465 sera automatiquement fermé et le nouveau port 587 sera ouvert dans le pare-feu. Vous et vos utilisateurs *devront* adapter la configuration de vos clients de messagerie en conséquence !",
"migration_0003_problematic_apps_warning": "Veuillez noter que des applications possiblement problématiques ont été détectées. Il semble qu’elles n’aient pas été installées depuis une liste d’application ou qu’elles ne soit pas marquées comme 'fonctionnelles'/'working'. En conséquence, nous ne pouvons pas garantir qu’elles fonctionneront après la mise à niveau : {problematic_apps}",
"migration_0003_modified_files": "Veuillez noter que les fichiers suivants ont été détectés comme modifiés manuellement et pourraient être écrasés à la fin de la mise à niveau : {manually_modified_files}",
@@ -426,7 +426,7 @@
"backup_php5_to_php7_migration_may_fail": "Impossible de convertir votre archive pour prendre en charge php7, vos applications php pourraient ne pas être restaurées (reason: {error:s})",
"log_help_to_get_failed_log": "L’opération '{desc}' a échouée ! Pour avoir de l’aide, merci de partager le journal historisé de cette opération en utilisant la commande 'yunohost log display {name} --share'",
"log_does_exists": "Il n’existe pas de journal historisé de l’opération ayant pour nom '{log}', utiliser 'yunohost log list pour voir tous les fichiers de journaux historisés disponibles'",
- "log_operation_unit_unclosed_properly": "L’opération ne s’est pas fermée/terminée correctement",
+ "log_operation_unit_unclosed_properly": "L’opération ne s’est pas terminée correctement",
"log_app_addaccess": "Ajouter l’accès à '{}'",
"log_app_removeaccess": "Enlever l’accès à '{}'",
"log_app_clearaccess": "Retirer tous les accès à '{}'",
@@ -462,7 +462,7 @@
"log_tools_shutdown": "Éteindre votre serveur",
"log_tools_reboot": "Redémarrer votre serveur",
"mail_unavailable": "Cette adresse de courriel est réservée et doit être automatiquement attribuée au tout premier utilisateur",
- "migration_description_0004_php5_to_php7_pools": "Reconfigurez le pool PHP pour utiliser PHP 7 au lieu de PHP 5",
+ "migration_description_0004_php5_to_php7_pools": "Reconfiguration des pools PHP pour utiliser PHP 7 au lieu de PHP 5",
"migration_description_0005_postgresql_9p4_to_9p6": "Migration des bases de données de PostgreSQL 9.4 vers PostgreSQL 9.6",
"migration_0005_postgresql_94_not_installed": "PostgreSQL n’a pas été installé sur votre système. Rien à faire !",
"migration_0005_postgresql_96_not_installed": "PostgreSQL 9.4 a été trouvé et installé, mais pas PostgreSQL 9.6 !? Quelque chose d’étrange a dû arriver à votre système :( …",
From 2d4785ec59099e56c566c70a6bed453d4028fda7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?M=C3=A9lanie=20Chauvel?=
Date: Sat, 23 Mar 2019 13:25:50 +0000
Subject: [PATCH 093/180] Translated using Weblate (French)
Currently translated at 99.8% (503 of 504 strings)
Translation: YunoHost/core
Translate-URL: https://translate.yunohost.org/projects/yunohost/core/fr/
---
locales/fr.json | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/locales/fr.json b/locales/fr.json
index d8d3edbb1..1a8399454 100644
--- a/locales/fr.json
+++ b/locales/fr.json
@@ -309,7 +309,7 @@
"global_settings_setting_example_string": "Exemple d’option de type chaîne",
"global_settings_setting_example_enum": "Exemple d’option de type énumération",
"global_settings_unknown_type": "Situation inattendue : la configuration {setting:s} semble avoir le type {unknown_type:s} mais celui-ci n'est pas pris en charge par le système.",
- "global_settings_unknown_setting_from_settings_file": "Clef inconnue dans les paramètres : '{setting_key:s}', rejet de cette clef et sauvegarde de celle-ci dans /etc/yunohost/unkown_settings.json",
+ "global_settings_unknown_setting_from_settings_file": "Clé inconnue dans les paramètres : '{setting_key:s}', rejet de cette clé et sauvegarde de celle-ci dans /etc/yunohost/unkown_settings.json",
"service_conf_new_managed_file": "Le fichier de configuration « {conf} » est désormais géré par le service {service}.",
"service_conf_file_kept_back": "Le fichier de configuration '{conf}' devait être supprimé par le service {service} mais a été conservé.",
"backup_abstract_method": "Cette méthode de sauvegarde n’a pas encore été implémentée",
@@ -359,7 +359,7 @@
"migrations_no_migrations_to_run": "Aucune migration à lancer",
"migrations_show_currently_running_migration": "Application de la migration {number} {name} …",
"migrations_show_last_migration": "La dernière migration appliquée est {}",
- "migrations_skip_migration": "Ignorer et passer la migration {number} {name} …",
+ "migrations_skip_migration": "Ignorer et passer la migration {number} {name}…",
"server_shutdown": "Le serveur va éteindre",
"server_shutdown_confirm": "Le serveur va être éteint immédiatement, le voulez-vous vraiment ? [{answers:s}]",
"server_reboot": "Le serveur va redémarrer",
@@ -394,7 +394,7 @@
"migration_0003_system_not_fully_up_to_date": "Votre système n’est pas complètement à jour. Veuillez mener une mise à jour classique avant de lancer à migration à Stretch.",
"migration_0003_still_on_jessie_after_main_upgrade": "Quelque chose s’est mal passé pendant la mise à niveau principale : le système est toujours sur Jessie !? Pour investiguer sur problème, veuillez regarder les journaux {log}:s…",
"migration_0003_general_warning": "Veuillez noter que cette migration est une opération délicate. Si l’équipe YunoHost a fait de son mieux pour la relire et la tester, la migration pourrait tout de même casser des parties de votre système ou de vos applications.\n\nEn conséquence, nous vous recommandons :\n - de lancer une sauvegarde de vos données ou applications critiques. Plus d’informations sur https://yunohost.org/backup ;\n - d’être patient après avoir lancé la migration : selon votre connexion internet et matériel, cela pourrait prendre jusqu’à quelques heures pour que tout soit à niveau.\n\nEn outre, le port SMTP utilisé par les clients de messagerie externes comme (Thunderbird ou K9-Mail) a été changé de 465 (SSL/TLS) à 587 (STARTTLS). L’ancien port 465 sera automatiquement fermé et le nouveau port 587 sera ouvert dans le pare-feu. Vous et vos utilisateurs *devront* adapter la configuration de vos clients de messagerie en conséquence !",
- "migration_0003_problematic_apps_warning": "Veuillez noter que des applications possiblement problématiques ont été détectées. Il semble qu’elles n’aient pas été installées depuis une liste d’application ou qu’elles ne soit pas marquées comme 'fonctionnelles'/'working'. En conséquence, nous ne pouvons pas garantir qu’elles fonctionneront après la mise à niveau : {problematic_apps}",
+ "migration_0003_problematic_apps_warning": "Veuillez noter que des applications possiblement problématiques ont été détectées. Il semble qu’elles n’aient pas été installées depuis une liste d’application ou qu’elles ne soit pas marquées comme « fonctionnelles ». En conséquence, nous ne pouvons pas garantir qu’elles fonctionneront après la mise à niveau : {problematic_apps}",
"migration_0003_modified_files": "Veuillez noter que les fichiers suivants ont été détectés comme modifiés manuellement et pourraient être écrasés à la fin de la mise à niveau : {manually_modified_files}",
"migrations_list_conflict_pending_done": "Vous ne pouvez pas utiliser --previous et --done simultanément.",
"migrations_to_be_ran_manually": "La migration {number} {name} doit être lancée manuellement. Veuillez aller dans Outils > Migrations dans l’interface admin, ou lancer `yunohost tools migrations migrate`.",
@@ -473,7 +473,7 @@
"good_practices_about_admin_password": "Vous êtes maintenant sur le point de définir un nouveau mot de passe d’administration. Le mot de passe doit comporter au moins 8 caractères – bien qu’il soit recommandé d’utiliser un mot de passe plus long (c’est-à-dire une phrase secrète) et/ou d’utiliser différents types de caractères (majuscules, minuscules, chiffres et caractères spéciaux).",
"good_practices_about_user_password": "Vous êtes maintenant sur le point de définir un nouveau mot de passe utilisateur. Le mot de passe doit comporter au moins 8 caractères — bien qu’il soit recommandé d’utiliser un mot de passe plus long (c’est-à-dire une phrase secrète) et/ou d’utiliser différents types de caractères (majuscules, minuscules, chiffres et caractères spéciaux).",
"migration_description_0006_sync_admin_and_root_passwords": "Synchroniser les mots de passe admin et root",
- "migration_0006_disclaimer": "YunoHost s’attendra à ce que les mots de passe admin et root soient synchronisés. En exécutant cette migration, votre mot de passe root sera remplacé par le mot de passe administrateur.",
+ "migration_0006_disclaimer": "YunoHost s’attendra désormais à ce que les mots de passe admin et root soient synchronisés. En exécutant cette migration, votre mot de passe root sera remplacé par le mot de passe administrateur.",
"migration_0006_done": "Votre mot de passe root a été remplacé par celui de votre adminitrateur.",
"password_listed": "Ce mot de passe est l'un des mots de passe les plus utilisés dans le monde. Veuillez choisir quelque chose d'un peu plus singulier.",
"password_too_simple_1": "Le mot de passe doit comporter au moins 8 caractères",
From 992e8e91b63daf30bc0b288e89c5542169f9b758 Mon Sep 17 00:00:00 2001
From: xaloc33
Date: Thu, 28 Mar 2019 23:25:26 +0000
Subject: [PATCH 094/180] Translated using Weblate (Catalan)
Currently translated at 33.5% (170 of 507 strings)
Translation: YunoHost/core
Translate-URL: https://translate.yunohost.org/projects/yunohost/core/ca/
---
locales/ca.json | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/locales/ca.json b/locales/ca.json
index dd01ddebb..9023b8c75 100644
--- a/locales/ca.json
+++ b/locales/ca.json
@@ -158,5 +158,15 @@
"diagnosis_monitor_disk_error": "No es poden monitorar els discs: {error}",
"diagnosis_monitor_network_error": "No es pot monitorar la xarxa: {error}",
"diagnosis_monitor_system_error": "No es pot monitorar el sistema: {error}",
- "diagnosis_no_apps": "No hi ha cap aplicació instal·lada"
+ "diagnosis_no_apps": "No hi ha cap aplicació instal·lada",
+ "admin_password_too_long": "Trieu una contrasenya de menys de 127 caràcters",
+ "dpkg_is_broken": "No es pot fer això en aquest instant perquè dpkg/apt (els gestors de paquets del sistema) sembla estar mal configurat... Podeu intentar solucionar-ho connectant-vos per ssh i executant \"sudo dpkg --configure -a\".",
+ "dnsmasq_isnt_installed": "sembla que dnsmasq no està instal·lat, executeu \"apt-get remove bind9 && apt-get install dnsmasq\"",
+ "domain_cannot_remove_main": "No es pot eliminar el domini principal. S'ha d'establir un nou domini primer",
+ "domain_cert_gen_failed": "No s'ha pogut generar el certificat",
+ "domain_created": "S'ha creat el domini",
+ "domain_creation_failed": "No s'ha pogut crear el domini",
+ "domain_deleted": "S'ha eliminat el domini",
+ "domain_deletion_failed": "No s'ha pogut eliminar el domini",
+ "domain_exists": "El domini ja existeix"
}
From b6cff68d73eafffbf985cd213cd2318b720823d2 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Tue, 2 Apr 2019 18:15:16 +0200
Subject: [PATCH 095/180] [fix] Do not miserably crash if status.json can't be
decoded
---
src/yunohost/app.py | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/yunohost/app.py b/src/yunohost/app.py
index 3d33ab8ae..38df51ea0 100644
--- a/src/yunohost/app.py
+++ b/src/yunohost/app.py
@@ -1773,12 +1773,18 @@ def _get_app_status(app_id, format_date=False):
raise YunohostError('app_unknown')
status = {}
+ regen_status = True
try:
with open(app_setting_path + '/status.json') as f:
status = json.loads(str(f.read()))
+ regen_status = False
except IOError:
logger.debug("status file not found for '%s'", app_id,
exc_info=1)
+ except Exception as e:
+ logger.warning("could not open or decode %s : %s ... regenerating.", app_setting_path + '/status.json', str(e))
+
+ if regen_status:
# Create app status
status = {
'installed_at': app_setting(app_id, 'install_time'),
From 889eb0caa158b9c951fd34909091f37d1ce06f55 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Tue, 2 Apr 2019 20:47:03 +0200
Subject: [PATCH 096/180] [fix] Fix the dbus interface to get info for
services, because this was not working when service is disabled
---
src/yunohost/service.py | 25 ++++++++++++-------------
1 file changed, 12 insertions(+), 13 deletions(-)
diff --git a/src/yunohost/service.py b/src/yunohost/service.py
index 61274aaac..896090228 100644
--- a/src/yunohost/service.py
+++ b/src/yunohost/service.py
@@ -325,7 +325,7 @@ def service_status(names=[]):
result[name] = {
'status': str(status.get("SubState", "unknown")),
- 'loaded': "enabled" if str(status.get("LoadState", "unknown")) == "loaded" else str(status.get("LoadState", "unknown")),
+ 'loaded': str(status.get("UnitFileState", "unknown")),
'active': str(status.get("ActiveState", "unknown")),
'description': description,
'service_file_path': str(status.get("FragmentPath", "unknown")),
@@ -343,26 +343,25 @@ def service_status(names=[]):
def _get_service_information_from_systemd(service):
"this is the equivalent of 'systemctl status $service'"
import dbus
- from dbus.exceptions import DBusException
d = dbus.SystemBus()
systemd = d.get_object('org.freedesktop.systemd1', '/org/freedesktop/systemd1')
manager = dbus.Interface(systemd, 'org.freedesktop.systemd1.Manager')
- try:
- service_path = manager.GetUnit(service + ".service")
- except DBusException as exception:
- if exception.get_dbus_name() == 'org.freedesktop.systemd1.NoSuchUnit':
- return None
- raise
-
- service_proxy = d.get_object('org.freedesktop.systemd1', service_path)
-
- # unit_proxy = dbus.Interface(service_proxy, 'org.freedesktop.systemd1.Unit',)
+ # c.f. https://zignar.net/2014/09/08/getting-started-with-dbus-python-systemd/
+ # Very interface, much intuitive, wow
+ service_unit = manager.LoadUnit(service + '.service')
+ service_proxy = d.get_object('org.freedesktop.systemd1', str(service_unit))
properties_interface = dbus.Interface(service_proxy, 'org.freedesktop.DBus.Properties')
- return properties_interface.GetAll('org.freedesktop.systemd1.Unit')
+ properties = properties_interface.GetAll('org.freedesktop.systemd1.Unit')
+
+ if properties.get("LoadState", "not-found") == "not-found":
+ # Service doesn't really exist
+ return None
+ else:
+ return properties
def service_log(name, number=50):
From 15cfe22b3c835e313a44ea44d07105ba9e3a0b2d Mon Sep 17 00:00:00 2001
From: Kayou
Date: Wed, 3 Apr 2019 00:25:50 +0200
Subject: [PATCH 097/180] Add size of apps in backup_info result
---
src/yunohost/backup.py | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/src/yunohost/backup.py b/src/yunohost/backup.py
index 6f969327b..f10b112ac 100644
--- a/src/yunohost/backup.py
+++ b/src/yunohost/backup.py
@@ -2272,6 +2272,14 @@ def backup_info(name, with_details=False, human_readable=False):
if "hooks" in info.keys():
system_key = "hooks"
+
+ if "size_details" in info.keys():
+ for name, key_info in info["apps"].items():
+ if name in info["size_details"]["apps"].keys():
+ key_info["size"] = info["size_details"]["apps"][name]
+ else:
+ key_info["size"] = 0
+
result["apps"] = info["apps"]
result["system"] = info[system_key]
return result
From e7ec6d968078207755572bbcb80df59e8454e90c Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Wed, 3 Apr 2019 02:21:31 +0200
Subject: [PATCH 098/180] Update changelog for 3.5.1
---
debian/changelog | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/debian/changelog b/debian/changelog
index 444d797e1..831b21ef5 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,22 @@
+yunohost (3.5.1) testing; urgency=low
+
+ - [fix] Fix the dbus interface to get info for services (#698)
+ - [mod] Use ask key for display_text instead and support i18n (#697)
+ - [fix] Rework tools update (#695)
+ - [enh] Nginx conf tweaks for theme (#689)
+ - [fix] Fix argument escaping in getopts (#685, #683)
+ - [enh] Support php versions in ynh_add_fpm_config (#674)
+ - [enh] Check that required services are up before running app install and upgrade (#670)
+ - [doc] Add min version for all helpers (#664)
+ - [enh] Add a setting to control compatibility/security tradeoff for nginx and ssh configurations (#640)
+ - [enh] Hooks to allow apps to extend the recommended DNS configuration (#517)
+ - Misc technical fixes / improvements (0bd781b, fad3edf, 1268872, 847ceca, 26e77b7, b6cff68)
+ - [i18n] Update translation for French, Catalan, Esperanto, Occitan
+
+ Thanks to all contributors: Aleks, Bram, Gabriel Corona, Jibec, Josue, Maniack C, Mélanie C., Quentí, Romuald du Song, ljf, ppr, Xaloc ! <3
+
+ -- Alexandre Aubin Wed, 03 Apr 2019 02:13:00 +0000
+
yunohost (3.5.0.2) testing; urgency=low
- [fix] Make sure that `ynh_system_user_delete` also deletes the group (#680)
From bf3ffc3e7d8d84c8e35a54fcdfb78b45c553dd8d Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Wed, 3 Apr 2019 12:22:47 +0200
Subject: [PATCH 099/180] [fix] service_status returns different type of data
if you one or multiple services
---
src/yunohost/app.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/yunohost/app.py b/src/yunohost/app.py
index 38df51ea0..97210d60c 100644
--- a/src/yunohost/app.py
+++ b/src/yunohost/app.py
@@ -2610,10 +2610,10 @@ def _check_services_status_for_app(services):
# (added by apps) and because those are the most popular
# services
service_filter = ["nginx", "php7.0-fpm", "mysql", "postfix"]
- services = [s for s in services if s in service_filter]
+ services = [str(s) for s in services if s in service_filter]
# List services currently down and raise an exception if any are found
- faulty_services = [s for s, infos in service_status(services).items() if infos["active"] != "active"]
+ faulty_services = [s for s in services if service_status(s)["active"] != "active"]
if faulty_services:
raise YunohostError('app_action_cannot_be_ran_because_required_services_down',
services=', '.join(faulty_services))
From 5c4bf1ed2905e0a69ca11ba0b13407e8493815b2 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Wed, 3 Apr 2019 13:02:15 +0200
Subject: [PATCH 100/180] [fix] nginx diagnosis when there's an error throwing
a huge useless traceback. Use Popen instead to display the real error
---
src/yunohost/tools.py | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py
index 635399801..0fb097805 100644
--- a/src/yunohost/tools.py
+++ b/src/yunohost/tools.py
@@ -720,12 +720,13 @@ def tools_diagnosis(auth, private=False):
}
# nginx -t
- try:
- diagnosis['nginx'] = check_output("nginx -t").strip().split("\n")
- except Exception as e:
- import traceback
- traceback.print_exc()
- logger.warning("Unable to check 'nginx -t', exception: %s" % e)
+ p = subprocess.Popen("nginx -t".split(),
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+ out, _ = p.communicate()
+ diagnosis["nginx"] = out.strip().split("\n")
+ if p.returncode != 0:
+ logger.error(out)
# Services status
services = service_status()
From 1f1173ad0c699904e79903362f0ca51978ba80f0 Mon Sep 17 00:00:00 2001
From: yalh76
Date: Wed, 3 Apr 2019 13:46:37 +0200
Subject: [PATCH 101/180] Use YNH_APP_INSTANCE_NAME instead of YNH_APP_ID
when using YNH_APP_ID, if you install two time the same application, when removing one of them, nodejs is uninstalled
---
data/helpers.d/nodejs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/data/helpers.d/nodejs b/data/helpers.d/nodejs
index b51bcd7c3..6833b7593 100644
--- a/data/helpers.d/nodejs
+++ b/data/helpers.d/nodejs
@@ -123,7 +123,7 @@ ynh_install_nodejs () {
fi
# Store the ID of this app and the version of node requested for it
- echo "$YNH_APP_ID:$nodejs_version" | tee --append "$n_install_dir/ynh_app_version"
+ echo "$YNH_APP_INSTANCE_NAME:$nodejs_version" | tee --append "$n_install_dir/ynh_app_version"
# Store nodejs_version into the config of this app
ynh_app_setting_set --app=$app --key=nodejs_version --value=$nodejs_version
@@ -147,7 +147,7 @@ ynh_remove_nodejs () {
nodejs_version=$(ynh_app_setting_get --app=$app --key=nodejs_version)
# Remove the line for this app
- sed --in-place "/$YNH_APP_ID:$nodejs_version/d" "$n_install_dir/ynh_app_version"
+ sed --in-place "/$YNH_APP_INSTANCE_NAME:$nodejs_version/d" "$n_install_dir/ynh_app_version"
# If no other app uses this version of nodejs, remove it.
if ! grep --quiet "$nodejs_version" "$n_install_dir/ynh_app_version"
From 69d2ad9a8ad8c9fbd95b7a0bb87b19656b12793d Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Wed, 3 Apr 2019 16:56:29 +0200
Subject: [PATCH 102/180] Fix loaded status for sysv services
---
src/yunohost/service.py | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/src/yunohost/service.py b/src/yunohost/service.py
index 896090228..b139c0b6d 100644
--- a/src/yunohost/service.py
+++ b/src/yunohost/service.py
@@ -31,6 +31,7 @@ import subprocess
import shutil
import hashlib
+from glob import glob
from difflib import unified_diff
from datetime import datetime
@@ -330,6 +331,12 @@ def service_status(names=[]):
'description': description,
'service_file_path': str(status.get("FragmentPath", "unknown")),
}
+
+ # Fun stuff™ : to obtain the enabled/disabled status for sysv services,
+ # gotta do this ... cf code of /lib/systemd/systemd-sysv-install
+ if result[name]["loaded"] == "generated":
+ result[name]["loaded"] = "enabled" if glob("/etc/rc[S5].d/S??"+name) else "disabled"
+
if "ActiveEnterTimestamp" in status:
result[name]['active_at'] = datetime.utcfromtimestamp(status["ActiveEnterTimestamp"] / 1000000)
else:
From c262313477aa0a7494f7b2bdcdeeef69ab85f807 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Wed, 3 Apr 2019 17:28:20 +0200
Subject: [PATCH 103/180] Update changelog for 3.5.1.1
---
debian/changelog | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/debian/changelog b/debian/changelog
index 831b21ef5..2d42719f6 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,12 @@
+yunohost (3.5.1.1) testing; urgency=low
+
+ - [fix] enabled/disabled status for sysv services
+ - [fix] Nodejs helpers : use YNH_APP_INSTANCE_NAME instead of YNH_APP_ID (#700)
+ - [fix] nginx diagnosis when there's an error throwing a huge useless traceback. Use Popen instead to display the real error
+ - [fix] service_status returns different type of data if you ask for one or multiple services
+
+ -- Alexandre Aubin Wed, 03 Apr 2019 17:28:00 +0000
+
yunohost (3.5.1) testing; urgency=low
- [fix] Fix the dbus interface to get info for services (#698)
From 1a1fc0bdff52fbc9d77ed01c8148e818d358749b Mon Sep 17 00:00:00 2001
From: Kayou
Date: Thu, 4 Apr 2019 12:28:00 +0200
Subject: [PATCH 104/180] Add connection_upgrade
---
data/templates/nginx/server.tpl.conf | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/data/templates/nginx/server.tpl.conf b/data/templates/nginx/server.tpl.conf
index fa8b6586b..14cb52abc 100644
--- a/data/templates/nginx/server.tpl.conf
+++ b/data/templates/nginx/server.tpl.conf
@@ -1,3 +1,8 @@
+map $http_upgrade $connection_upgrade {
+ default upgrade;
+ '' close;
+}
+
server {
listen 80;
listen [::]:80;
From e9d399f7cd92ba50ea19b7da1fcc25997ecb650b Mon Sep 17 00:00:00 2001
From: Kayou
Date: Thu, 4 Apr 2019 12:29:23 +0200
Subject: [PATCH 105/180] Format
---
data/templates/nginx/server.tpl.conf | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/data/templates/nginx/server.tpl.conf b/data/templates/nginx/server.tpl.conf
index 14cb52abc..4a5e91557 100644
--- a/data/templates/nginx/server.tpl.conf
+++ b/data/templates/nginx/server.tpl.conf
@@ -1,6 +1,6 @@
map $http_upgrade $connection_upgrade {
- default upgrade;
- '' close;
+ default upgrade;
+ '' close;
}
server {
From 214d1ce8fc14b2c1afb7a7852574d6853e9c5be0 Mon Sep 17 00:00:00 2001
From: Josue-T
Date: Sun, 7 Apr 2019 11:27:38 +0200
Subject: [PATCH 106/180] Add support in restore script of ynh_setup_source
Actually the path to the app.src file in the helper ynh_setup_source work only in install and upgrade script.
Add the support for restore script.
---
data/helpers.d/utils | 21 ++++++++++++++-------
1 file changed, 14 insertions(+), 7 deletions(-)
diff --git a/data/helpers.d/utils b/data/helpers.d/utils
index 5f5e61015..40e6fe045 100644
--- a/data/helpers.d/utils
+++ b/data/helpers.d/utils
@@ -166,15 +166,22 @@ ynh_setup_source () {
ynh_handle_getopts_args "$@"
source_id="${source_id:-app}" # If the argument is not given, source_id equals "app"
+ local src_file_path="$YNH_CWD/../conf/${src_id}.src"
+ # In case of restore script the src file is in an other path.
+ # So try to use the restore path if the general path point to no file.
+ if [[ ! -e "$src_file_path" ]]; then
+ src_file_path="$YNH_CWD/../settings/conf/${src_id}.src"
+ fi
+
# Load value from configuration file (see above for a small doc about this file
# format)
- local src_url=$(grep 'SOURCE_URL=' "$YNH_CWD/../conf/${source_id}.src" | cut -d= -f2-)
- local src_sum=$(grep 'SOURCE_SUM=' "$YNH_CWD/../conf/${source_id}.src" | cut -d= -f2-)
- local src_sumprg=$(grep 'SOURCE_SUM_PRG=' "$YNH_CWD/../conf/${source_id}.src" | cut -d= -f2-)
- local src_format=$(grep 'SOURCE_FORMAT=' "$YNH_CWD/../conf/${source_id}.src" | cut -d= -f2-)
- local src_extract=$(grep 'SOURCE_EXTRACT=' "$YNH_CWD/../conf/${source_id}.src" | cut -d= -f2-)
- local src_in_subdir=$(grep 'SOURCE_IN_SUBDIR=' "$YNH_CWD/../conf/${source_id}.src" | cut -d= -f2-)
- local src_filename=$(grep 'SOURCE_FILENAME=' "$YNH_CWD/../conf/${source_id}.src" | cut -d= -f2-)
+ local src_url=$(grep 'SOURCE_URL=' "$src_file_path" | cut -d= -f2-)
+ local src_sum=$(grep 'SOURCE_SUM=' "$src_file_path" | cut -d= -f2-)
+ local src_sumprg=$(grep 'SOURCE_SUM_PRG=' "$src_file_path" | cut -d= -f2-)
+ local src_format=$(grep 'SOURCE_FORMAT=' "$src_file_path" | cut -d= -f2-)
+ local src_extract=$(grep 'SOURCE_EXTRACT=' "$src_file_path" | cut -d= -f2-)
+ local src_in_subdir=$(grep 'SOURCE_IN_SUBDIR=' "$src_file_path" | cut -d= -f2-)
+ local src_filename=$(grep 'SOURCE_FILENAME=' "$src_file_path" | cut -d= -f2-)
# Default value
src_sumprg=${src_sumprg:-sha256sum}
From a9761d356b8c787cbef6f0fb38025e75cb5e1ef0 Mon Sep 17 00:00:00 2001
From: Alexandre Aubin
Date: Mon, 8 Apr 2019 18:59:04 +0200
Subject: [PATCH 107/180] Update script to automatically generate helper
documentation
---
data/helpers.d/backend | 15 ++++++------
data/helpers.d/filesystem | 39 +++++++++++++-------------------
data/helpers.d/mysql | 4 ++--
data/helpers.d/network | 12 ++++++----
data/helpers.d/system | 2 +-
data/helpers.d/user | 11 ++++-----
doc/generate_helper_doc.py | 44 ++++++++++++++++++++++++++++--------
doc/helper_doc_template.html | 28 +++++++++++++++++++----
8 files changed, 96 insertions(+), 59 deletions(-)
diff --git a/data/helpers.d/backend b/data/helpers.d/backend
index 28c91e4f6..710e6299b 100644
--- a/data/helpers.d/backend
+++ b/data/helpers.d/backend
@@ -3,17 +3,17 @@
# Use logrotate to manage the logfile
#
# usage: ynh_use_logrotate [--logfile=/log/file] [--nonappend] [--specific_user=user/group]
-# | arg: -l, --logfile= - absolute path of logfile
-# | arg: -n, --nonappend - (Option) Replace the config file instead of appending this new config.
+# | arg: -l, --logfile - absolute path of logfile
+# | arg: -n, --nonappend - (optional) Replace the config file instead of appending this new config.
# | arg: -u, --specific_user : run logrotate as the specified user and group. If not specified logrotate is runned as root.
#
-# If no argument provided, a standard directory will be use. /var/log/${app}
-# You can provide a path with the directory only or with the logfile.
+# If no --logfile is provided, /var/log/${app} will be used as default.
+# logfile can be just a directory, or a full path to a logfile :
# /parentdir/logdir
# /parentdir/logdir/logfile.log
#
-# It's possible to use this helper several times, each config will be added to the same logrotate config file.
-# Unless you use the option --non-append
+# It's possible to use this helper multiple times, each config will be added to
+# the same logrotate config file. Unless you use the option --non-append
#
# Requires YunoHost version 2.6.4 or higher.
ynh_use_logrotate () {
@@ -175,8 +175,7 @@ ynh_remove_systemd_config () {
#
# usage: ynh_add_nginx_config "list of others variables to replace"
#
-# | arg: list of others variables to replace separeted by a space
-# | for example : 'path_2 port_2 ...'
+# | arg: list - (Optional) list of others variables to replace separated by spaces. For example : 'path_2 port_2 ...'
#
# This will use a template in ../conf/nginx.conf
# __PATH__ by $path_url
diff --git a/data/helpers.d/filesystem b/data/helpers.d/filesystem
index 6fb6347a6..07614d179 100644
--- a/data/helpers.d/filesystem
+++ b/data/helpers.d/filesystem
@@ -15,16 +15,13 @@ CAN_BIND=${CAN_BIND:-1}
# If DEST is ended by a slash it complete this path with the basename of SRC.
#
# usage: ynh_backup --src_path=src_path [--dest_path=dest_path] [--is_big] [--not_mandatory]
-# | arg: -s, --src_path - file or directory to bind or symlink or copy. it shouldn't be in
-# the backup dir.
-# | arg: -d, --dest_path - destination file or directory inside the
-# backup dir
+# | arg: -s, --src_path - file or directory to bind or symlink or copy. it shouldn't be in the backup dir.
+# | arg: -d, --dest_path - destination file or directory inside the backup dir
# | arg: -b, --is_big - Indicate data are big (mail, video, image ...)
# | arg: -m, --not_mandatory - Indicate that if the file is missing, the backup can ignore it.
# | arg: arg - Deprecated arg
#
-# example:
-# # Wordpress app context
+# Example in the context of a wordpress app
#
# ynh_backup "/etc/nginx/conf.d/$domain.d/$app.conf"
# # => This line will be added into CSV file
@@ -198,28 +195,25 @@ with open(sys.argv[1], 'r') as backup_file:
# Restore a file or a directory
#
# Use the registered path in backup_list by ynh_backup to restore the file at
-# the good place.
+# the right place.
#
# usage: ynh_restore_file --origin_path=origin_path [--dest_path=dest_path] [--not_mandatory]
-# | arg: -o, --origin_path - Path where was located the file or the directory before
-# to be backuped or relative path to $YNH_CWD where it is located in the backup archive
-# | arg: -d, --dest_path - Path where restore the file or the dir, if unspecified,
-# the destination will be ORIGIN_PATH or if the ORIGIN_PATH doesn't exist in
-# the archive, the destination will be searched into backup.csv
+# | arg: -o, --origin_path - Path where was located the file or the directory before to be backuped or relative path to $YNH_CWD where it is located in the backup archive
+# | arg: -d, --dest_path - Path where restore the file or the dir, if unspecified, the destination will be ORIGIN_PATH or if the ORIGIN_PATH doesn't exist in the archive, the destination will be searched into backup.csv
# | arg: -m, --not_mandatory - Indicate that if the file is missing, the restore process can ignore it.
#
+# examples:
+# ynh_restore_file "/etc/nginx/conf.d/$domain.d/$app.conf"
+# # You can also use relative paths:
+# ynh_restore_file "conf/nginx.conf"
+#
# If DEST_PATH already exists and is lighter than 500 Mo, a backup will be made in
# /home/yunohost.conf/backup/. Otherwise, the existing file is removed.
#
-# examples:
-# ynh_restore_file "/etc/nginx/conf.d/$domain.d/$app.conf"
-# # if apps/wordpress/etc/nginx/conf.d/$domain.d/$app.conf exists, restore it into
-# # /etc/nginx/conf.d/$domain.d/$app.conf
-# # if no, search a correspondance in the csv (eg: conf/nginx.conf) and restore it into
-# # /etc/nginx/conf.d/$domain.d/$app.conf
-#
-# # DON'T GIVE THE ARCHIVE PATH:
-# ynh_restore_file "conf/nginx.conf"
+# if apps/wordpress/etc/nginx/conf.d/$domain.d/$app.conf exists, restore it into
+# /etc/nginx/conf.d/$domain.d/$app.conf
+# if no, search for a match in the csv (eg: conf/nginx.conf) and restore it into
+# /etc/nginx/conf.d/$domain.d/$app.conf
#
# Requires YunoHost version 2.6.4 or higher.
ynh_restore_file () {
@@ -348,8 +342,7 @@ ynh_store_file_checksum () {
#
# usage: ynh_backup_if_checksum_is_different --file=file
# | arg: -f, --file - The file on which the checksum test will be perfomed.
-#
-# | ret: Return the name a the backup file, or nothing
+# | ret: the name of a backup file, or nothing
#
# Requires YunoHost version 2.6.4 or higher.
ynh_backup_if_checksum_is_different () {
diff --git a/data/helpers.d/mysql b/data/helpers.d/mysql
index 313b7a245..d7400db2d 100644
--- a/data/helpers.d/mysql
+++ b/data/helpers.d/mysql
@@ -186,7 +186,7 @@ ynh_mysql_drop_user() {
# usage: ynh_mysql_setup_db --db_user=user --db_name=name [--db_pwd=pwd]
# | arg: -u, --db_user - Owner of the database
# | arg: -n, --db_name - Name of the database
-# | arg: -p, --db_pwd - Password of the database. If not given, a password will be generated
+# | arg: -p, --db_pwd - Password of the database. If not provided, a password will be generated
#
# Requires YunoHost version 2.6.4 or higher.
ynh_mysql_setup_db () {
@@ -200,7 +200,7 @@ ynh_mysql_setup_db () {
ynh_handle_getopts_args "$@"
local new_db_pwd=$(ynh_string_random) # Generate a random password
- # If $db_pwd is not given, use new_db_pwd instead for db_pwd
+ # If $db_pwd is not provided, use new_db_pwd instead for db_pwd
db_pwd="${db_pwd:-$new_db_pwd}"
ynh_mysql_create_db "$db_name" "$db_user" "$db_pwd" # Create the database
diff --git a/data/helpers.d/network b/data/helpers.d/network
index 8812f8f39..4dc080203 100644
--- a/data/helpers.d/network
+++ b/data/helpers.d/network
@@ -1,14 +1,16 @@
#!/bin/bash
# Normalize the url path syntax
+#
# Handle the slash at the beginning of path and its absence at ending
# Return a normalized url path
#
-# example: url_path=$(ynh_normalize_url_path $url_path)
-# ynh_normalize_url_path example -> /example
-# ynh_normalize_url_path /example -> /example
-# ynh_normalize_url_path /example/ -> /example
-# ynh_normalize_url_path / -> /
+# examples:
+# url_path=$(ynh_normalize_url_path $url_path)
+# ynh_normalize_url_path example # -> /example
+# ynh_normalize_url_path /example # -> /example
+# ynh_normalize_url_path /example/ # -> /example
+# ynh_normalize_url_path / # -> /
#
# usage: ynh_normalize_url_path --path_url=path_to_normalize
# | arg: -p, --path_url - URL path to normalize before using it
diff --git a/data/helpers.d/system b/data/helpers.d/system
index a491b19b5..757fdf93c 100644
--- a/data/helpers.d/system
+++ b/data/helpers.d/system
@@ -241,7 +241,7 @@ ynh_app_package_version () {
# - UPGRADE_APP if the upstream app version has changed
# - UPGRADE_PACKAGE if only the YunoHost package has changed
#
-## It stops the current script without error if the package is up-to-date
+# It stops the current script without error if the package is up-to-date
#
# This helper should be used to avoid an upgrade of an app, or the upstream part
# of it, when it's not needed
diff --git a/data/helpers.d/user b/data/helpers.d/user
index 83fa47aa8..9ee44515d 100644
--- a/data/helpers.d/user
+++ b/data/helpers.d/user
@@ -89,16 +89,15 @@ ynh_system_group_exists() {
# Create a system user
#
# examples:
-# - ynh_system_user_create --username=nextcloud -> creates a nextcloud user with
-# no home directory and /usr/sbin/nologin login shell (hence no login capability)
-# - ynh_system_user_create --username=discourse --home_dir=/var/www/discourse --use_shell --> creates a
-# discourse user using /var/www/discourse as home directory and the default login shell
+# # Create a nextcloud user with no home directory and /usr/sbin/nologin login shell (hence no login capability)
+# ynh_system_user_create --username=nextcloud
+# # Create a discourse user using /var/www/discourse as home directory and the default login shell
+# ynh_system_user_create --username=discourse --home_dir=/var/www/discourse --use_shell
#
# usage: ynh_system_user_create --username=user_name [--home_dir=home_dir] [--use_shell]
# | arg: -u, --username - Name of the system user that will be create
# | arg: -h, --home_dir - Path of the home dir for the user. Usually the final path of the app. If this argument is omitted, the user will be created without home
-# | arg: -s, --use_shell - Create a user using the default login shell if present.
-# If this argument is omitted, the user will be created with /usr/sbin/nologin shell
+# | arg: -s, --use_shell - Create a user using the default login shell if present. If this argument is omitted, the user will be created with /usr/sbin/nologin shell
#
# Requires YunoHost version 2.6.4 or higher.
ynh_system_user_create () {
diff --git a/doc/generate_helper_doc.py b/doc/generate_helper_doc.py
index 7d8c489b7..5b51dda02 100644
--- a/doc/generate_helper_doc.py
+++ b/doc/generate_helper_doc.py
@@ -4,7 +4,12 @@ import os
import glob
import datetime
-def render(data):
+def render(helpers):
+
+ data = { "helpers": helpers,
+ "date": datetime.datetime.now().strftime("%m/%d/%Y"),
+ "version": open("../debian/changelog").readlines()[0].split()[1].strip("()")
+ }
from jinja2 import Template
from ansi2html import Ansi2HTMLConverter
@@ -43,7 +48,7 @@ class Parser():
"code": [] }
for i, line in enumerate(self.file):
-
+
if line.startswith("#!/bin/bash"):
continue
@@ -103,7 +108,6 @@ class Parser():
b["usage"] = ""
b["args"] = []
b["ret"] = ""
- b["example"] = ""
subblocks = '\n'.join(b["comments"]).split("\n\n")
@@ -114,17 +118,29 @@ class Parser():
b["brief"] = subblock
continue
- elif subblock.startswith("example"):
+ elif subblock.startswith("example:"):
b["example"] = " ".join(subblock.split()[1:])
continue
+ elif subblock.startswith("examples:"):
+ b["examples"] = subblock.split("\n")[1:]
+ continue
+
elif subblock.startswith("usage"):
for line in subblock.split("\n"):
if line.startswith("| arg"):
- argname = line.split()[2]
- argdescr = " ".join(line.split()[4:])
- b["args"].append((argname, argdescr))
+ linesplit = line.split()
+ argname = linesplit[2]
+ # Detect that there's a long argument version (-f, --foo - Some description)
+ if argname.endswith(",") and linesplit[3].startswith("--"):
+ argname = argname.strip(",")
+ arglongname = linesplit[3]
+ argdescr = " ".join(linesplit[5:])
+ b["args"].append((argname, arglongname, argdescr))
+ else:
+ argdescr = " ".join(linesplit[4:])
+ b["args"].append((argname, argdescr))
elif line.startswith("| ret"):
b["ret"] = " ".join(line.split()[2:])
else:
@@ -136,9 +152,17 @@ class Parser():
elif subblock.startswith("| arg"):
for line in subblock.split("\n"):
if line.startswith("| arg"):
- argname = line.split()[2]
- argdescr = line.split()[4:]
- b["args"].append((argname, argdescr))
+ linesplit = line.split()
+ argname = linesplit[2]
+ # Detect that there's a long argument version (-f, --foo - Some description)
+ if argname.endswith(",") and linesplit[3].startswith("--"):
+ argname = argname.strip(",")
+ arglongname = linesplit[3]
+ argdescr = " ".join(linesplit[5:])
+ b["args"].append((argname, arglongname, argdescr))
+ else:
+ argdescr = " ".join(linesplit[4:])
+ b["args"].append((argname, argdescr))
continue
else:
diff --git a/doc/helper_doc_template.html b/doc/helper_doc_template.html
index 1fa1f68ad..92611c737 100644
--- a/doc/helper_doc_template.html
+++ b/doc/helper_doc_template.html
@@ -2,7 +2,7 @@
App helpers
-{% for category, helpers in data %}
+{% for category, helpers in data.helpers %}
{{ category }}
@@ -27,8 +27,12 @@
Arguments:
- {% for name, descr in h.args %}
-
{{ name }} : {{ descr }}
+ {% for infos in h.args %}
+ {% if infos|length == 2 %}
+
{{ infos[0] }} : {{ infos[1] }}
+ {% else %}
+
{{ infos[0] }}, {{ infos[1] }} : {{ infos[2] }}
+ {% endif %}
{% endfor %}
@@ -38,11 +42,25 @@
Returns: {{ h.ret }}
{% endif %}
- {% if h.example %}
+ {% if "example" in h.keys() %}
Example: {{ h.example }}
{% endif %}
+ {% if "examples" in h.keys() %}
+
+ Examples:
+ {% for example in h.examples %}
+ {% if not example.strip().startswith("# ") %}
+ {{ example }}
+ {% else %}
+ {{ example.strip("# ") }}
+ {% endif %}
+
+ {% endfor %}
+