Merge branch 'dev' into enh-csv

This commit is contained in:
Alexandre Aubin 2021-08-27 01:48:15 +02:00 committed by GitHub
commit c20ca3015e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
39 changed files with 423 additions and 162 deletions

173
bin/yunomdns Executable file
View file

@ -0,0 +1,173 @@
#!/usr/bin/env python3
"""
Pythonic declaration of mDNS .local domains for YunoHost
"""
import subprocess
import re
import sys
import yaml
import socket
from time import sleep
from typing import List, Dict
from zeroconf import Zeroconf, ServiceInfo
# Helper command taken from Moulinette
def check_output(args, stderr=subprocess.STDOUT, shell=True, **kwargs):
"""Run command with arguments and return its output as a byte string
Overwrite some of the arguments to capture standard error in the result
and use shell by default before calling subprocess.check_output.
"""
return (
subprocess.check_output(args, stderr=stderr, shell=shell, **kwargs)
.decode("utf-8")
.strip()
)
# Helper command taken from Moulinette
def _extract_inet(string, skip_netmask=False, skip_loopback=True):
"""
Extract IP addresses (v4 and/or v6) from a string limited to one
address by protocol
Keyword argument:
string -- String to search in
skip_netmask -- True to skip subnet mask extraction
skip_loopback -- False to include addresses reserved for the
loopback interface
Returns:
A dict of {protocol: address} with protocol one of 'ipv4' or 'ipv6'
"""
ip4_pattern = (
r"((25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}"
)
ip6_pattern = r"(((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)::?((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)"
ip4_pattern += r"/[0-9]{1,2})" if not skip_netmask else ")"
ip6_pattern += r"/[0-9]{1,3})" if not skip_netmask else ")"
result = {}
for m in re.finditer(ip4_pattern, string):
addr = m.group(1)
if skip_loopback and addr.startswith("127."):
continue
# Limit to only one result
result["ipv4"] = addr
break
for m in re.finditer(ip6_pattern, string):
addr = m.group(1)
if skip_loopback and addr == "::1":
continue
# Limit to only one result
result["ipv6"] = addr
break
return result
# Helper command taken from Moulinette
def get_network_interfaces():
# Get network devices and their addresses (raw infos from 'ip addr')
devices_raw = {}
output = check_output("ip --brief a").split("\n")
for line in output:
line = line.split()
iname = line[0]
ips = ' '.join(line[2:])
devices_raw[iname] = ips
# Parse relevant informations for each of them
devices = {
name: _extract_inet(addrs)
for name, addrs in devices_raw.items()
if name != "lo"
}
return devices
if __name__ == '__main__':
###
# CONFIG
###
with open('/etc/yunohost/mdns.yml', 'r') as f:
config = yaml.safe_load(f) or {}
updated = False
required_fields = ["interfaces", "domains"]
missing_fields = [field for field in required_fields if field not in config]
if missing_fields:
print("The fields %s are required" % ', '.join(missing_fields))
if config['interfaces'] is None:
print('No interface listed for broadcast.')
sys.exit(0)
if 'yunohost.local' not in config['domains']:
config['domains'].append('yunohost.local')
zcs = {}
interfaces = get_network_interfaces()
for interface in config['interfaces']:
infos = [] # List of ServiceInfo objects, to feed Zeroconf
ips = [] # Human-readable IPs
b_ips = [] # Binary-convered IPs
ipv4 = interfaces[interface]['ipv4'].split('/')[0]
if ipv4:
ips.append(ipv4)
b_ips.append(socket.inet_pton(socket.AF_INET, ipv4))
ipv6 = interfaces[interface]['ipv6'].split('/')[0]
if ipv6:
ips.append(ipv6)
b_ips.append(socket.inet_pton(socket.AF_INET6, ipv6))
# If at least one IP is listed
if ips:
# Create a Zeroconf object, and store the ServiceInfos
zc = Zeroconf(interfaces=ips)
zcs[zc]=[]
for d in config['domains']:
d_domain=d.replace('.local','')
if '.' in d_domain:
print(d_domain+'.local: subdomains are not supported.')
else:
# Create a ServiceInfo object for each .local domain
zcs[zc].append(ServiceInfo(
type_='_device-info._tcp.local.',
name=interface+': '+d_domain+'._device-info._tcp.local.',
addresses=b_ips,
port=80,
server=d+'.',
))
print('Adding '+d+' with addresses '+str(ips)+' on interface '+interface)
# Run registration
print("Registering...")
for zc, infos in zcs.items():
for info in infos:
zc.register_service(info)
try:
print("Registered. Press Ctrl+C or stop service to stop.")
while True:
sleep(1)
except KeyboardInterrupt:
pass
finally:
print("Unregistering...")
for zc, infos in zcs.items():
for info in infos:
zc.unregister_service(info)
zc.close()

View file

@ -695,7 +695,11 @@ app:
api: DELETE /apps/<app> api: DELETE /apps/<app>
arguments: arguments:
app: app:
help: App to delete help: App to remove
-p:
full: --purge
help: Also remove all application data
action: store_true
### app_upgrade() ### app_upgrade()
upgrade: upgrade:
@ -715,6 +719,10 @@ app:
full: --force full: --force
help: Force the update, even though the app is up to date help: Force the update, even though the app is up to date
action: store_true action: store_true
-b:
full: --no-safety-backup
help: Disable the safety backup during upgrade
action: store_true
### app_change_url() ### app_change_url()
change-url: change-url:

View file

@ -32,7 +32,7 @@ def get_dict_actions(OPTION_SUBTREE, category):
with open(ACTIONSMAP_FILE, "r") as stream: with open(ACTIONSMAP_FILE, "r") as stream:
# Getting the dictionary containning what actions are possible per category # Getting the dictionary containning what actions are possible per category
OPTION_TREE = yaml.load(stream) OPTION_TREE = yaml.safe_load(stream)
CATEGORY = [ CATEGORY = [
category for category in OPTION_TREE.keys() if not category.startswith("_") category for category in OPTION_TREE.keys() if not category.startswith("_")

View file

@ -31,7 +31,11 @@ ynh_multimedia_build_main_dir() {
mkdir -p "$MEDIA_DIRECTORY/$user/eBook" mkdir -p "$MEDIA_DIRECTORY/$user/eBook"
ln -sfn "$MEDIA_DIRECTORY/share" "$MEDIA_DIRECTORY/$user/Share" ln -sfn "$MEDIA_DIRECTORY/share" "$MEDIA_DIRECTORY/$user/Share"
# Création du lien symbolique dans le home de l'utilisateur. # Création du lien symbolique dans le home de l'utilisateur.
ln -sfn "$MEDIA_DIRECTORY/$user" "/home/$user/Multimedia" #link will only be created if the home directory of the user exists and if it's located in '/home' folder
local user_home="$(getent passwd $user | cut -d: -f6 | grep '^/home/')"
if [[ -d "$user_home" ]]; then
ln -sfn "$MEDIA_DIRECTORY/$user" "$user_home/Multimedia"
fi
# Propriétaires des dossiers utilisateurs. # Propriétaires des dossiers utilisateurs.
chown -R $user "$MEDIA_DIRECTORY/$user" chown -R $user "$MEDIA_DIRECTORY/$user"
done done

View file

@ -362,8 +362,17 @@ ynh_permission_has_user() {
return 1 return 1
fi fi
yunohost user permission info "$app.$permission" --output-as json --quiet \ # Check both allowed and corresponding_users sections in the json
| jq -e --arg user $user '.corresponding_users | index($user)' >/dev/null for section in "allowed" "corresponding_users"
do
if yunohost user permission info "$app.$permission" --output-as json --quiet \
| jq -e --arg user $user --arg section $section '.[$section] | index($user)' >/dev/null
then
return 0
fi
done
return 1
} }
# Check if a legacy permissions exist # Check if a legacy permissions exist

View file

@ -86,7 +86,7 @@ key, value = os.environ['KEY'], os.environ.get('VALUE', None)
setting_file = "/etc/yunohost/apps/%s/settings.yml" % app setting_file = "/etc/yunohost/apps/%s/settings.yml" % app
assert os.path.exists(setting_file), "Setting file %s does not exists ?" % setting_file assert os.path.exists(setting_file), "Setting file %s does not exists ?" % setting_file
with open(setting_file) as f: with open(setting_file) as f:
settings = yaml.load(f) settings = yaml.safe_load(f)
if action == "get": if action == "get":
if key in settings: if key in settings:
print(settings[key]) print(settings[key])
@ -96,7 +96,7 @@ else:
del settings[key] del settings[key]
elif action == "set": elif action == "set":
if key in ['redirected_urls', 'redirected_regex']: if key in ['redirected_urls', 'redirected_regex']:
value = yaml.load(value) value = yaml.safe_load(value)
settings[key] = value settings[key] = value
else: else:
raise ValueError("action should either be get, set or delete") raise ValueError("action should either be get, set or delete")

View file

@ -212,10 +212,10 @@ import yaml
with open('services.yml') as f: with open('services.yml') as f:
new_services = yaml.load(f) new_services = yaml.safe_load(f)
with open('/etc/yunohost/services.yml') as f: with open('/etc/yunohost/services.yml') as f:
services = yaml.load(f) or {} services = yaml.safe_load(f) or {}
updated = False updated = False

View file

@ -2,7 +2,7 @@
set -e set -e
tmp_backup_dir_file="/tmp/slapd-backup-dir.txt" tmp_backup_dir_file="/root/slapd-backup-dir.txt"
config="/usr/share/yunohost/templates/slapd/config.ldif" config="/usr/share/yunohost/templates/slapd/config.ldif"
db_init="/usr/share/yunohost/templates/slapd/db_init.ldif" db_init="/usr/share/yunohost/templates/slapd/db_init.ldif"

View file

@ -1,37 +0,0 @@
#!/bin/bash
set -e
do_pre_regen() {
pending_dir=$1
cd /usr/share/yunohost/templates/avahi-daemon
install -D -m 644 avahi-daemon.conf \
"${pending_dir}/etc/avahi/avahi-daemon.conf"
}
do_post_regen() {
regen_conf_files=$1
[[ -z "$regen_conf_files" ]] \
|| systemctl restart avahi-daemon
}
FORCE=${2:-0}
DRY_RUN=${3:-0}
case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

83
data/hooks/conf_regen/37-mdns Executable file
View file

@ -0,0 +1,83 @@
#!/bin/bash
set -e
_generate_config() {
echo "domains:"
echo " - yunohost.local"
for domain in $YNH_DOMAINS
do
# Only keep .local domains (don't keep
[[ "$domain" =~ [^.]+\.[^.]+\.local$ ]] && echo "Subdomain $domain cannot be handled by Bonjour/Zeroconf/mDNS" >&2
[[ "$domain" =~ ^[^.]+\.local$ ]] || continue
echo " - $domain"
done
echo "interfaces:"
local_network_interfaces="$(ip --brief a | grep ' 10\.\| 192\.168\.' | awk '{print $1}')"
for interface in $local_network_interfaces
do
echo " - $interface"
done
}
do_init_regen() {
do_pre_regen
do_post_regen /etc/systemd/system/yunomdns.service
systemctl enable yunomdns
}
do_pre_regen() {
pending_dir="$1"
cd /usr/share/yunohost/templates/mdns
mkdir -p ${pending_dir}/etc/systemd/system/
cp yunomdns.service ${pending_dir}/etc/systemd/system/
getent passwd mdns &>/dev/null || useradd --no-create-home --shell /usr/sbin/nologin --system --user-group mdns
mkdir -p ${pending_dir}/etc/yunohost
_generate_config > ${pending_dir}/etc/yunohost/mdns.yml
}
do_post_regen() {
regen_conf_files="$1"
chown mdns:mdns /etc/yunohost/mdns.yml
# If we changed the systemd ynh-override conf
if echo "$regen_conf_files" | sed 's/,/\n/g' | grep -q "^/etc/systemd/system/yunomdns.service$"
then
systemctl daemon-reload
fi
# Legacy stuff to enable the new yunomdns service on legacy systems
if [[ -e /etc/avahi/avahi-daemon.conf ]] && grep -q 'yunohost' /etc/avahi/avahi-daemon.conf
then
systemctl enable yunomdns
fi
[[ -z "$regen_conf_files" ]] \
|| systemctl restart yunomdns
}
FORCE=${2:-0}
DRY_RUN=${3:-0}
case "$1" in
pre)
do_pre_regen $4
;;
post)
do_post_regen $4
;;
init)
do_init_regen
;;
*)
echo "hook called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

View file

@ -13,6 +13,7 @@ from yunohost.diagnosis import Diagnoser
from yunohost.domain import domain_list, _build_dns_conf, _get_maindomain from yunohost.domain import domain_list, _build_dns_conf, _get_maindomain
YNH_DYNDNS_DOMAINS = ["nohost.me", "noho.st", "ynh.fr"] YNH_DYNDNS_DOMAINS = ["nohost.me", "noho.st", "ynh.fr"]
SPECIAL_USE_TLDS = ["local", "localhost", "onion", "test"]
class DNSRecordsDiagnoser(Diagnoser): class DNSRecordsDiagnoser(Diagnoser):
@ -29,8 +30,14 @@ class DNSRecordsDiagnoser(Diagnoser):
for domain in all_domains: for domain in all_domains:
self.logger_debug("Diagnosing DNS conf for %s" % domain) self.logger_debug("Diagnosing DNS conf for %s" % domain)
is_subdomain = domain.split(".", 1)[1] in all_domains is_subdomain = domain.split(".", 1)[1] in all_domains
is_specialusedomain = any(
domain.endswith("." + tld) for tld in SPECIAL_USE_TLDS
)
for report in self.check_domain( for report in self.check_domain(
domain, domain == main_domain, is_subdomain=is_subdomain domain,
domain == main_domain,
is_subdomain=is_subdomain,
is_specialusedomain=is_specialusedomain,
): ):
yield report yield report
@ -48,7 +55,7 @@ class DNSRecordsDiagnoser(Diagnoser):
for report in self.check_expiration_date(domains_from_registrar): for report in self.check_expiration_date(domains_from_registrar):
yield report yield report
def check_domain(self, domain, is_main_domain, is_subdomain): def check_domain(self, domain, is_main_domain, is_subdomain, is_specialusedomain):
expected_configuration = _build_dns_conf( expected_configuration = _build_dns_conf(
domain, include_empty_AAAA_if_no_ipv6=True domain, include_empty_AAAA_if_no_ipv6=True
@ -59,6 +66,15 @@ class DNSRecordsDiagnoser(Diagnoser):
if is_subdomain: if is_subdomain:
categories = ["basic"] categories = ["basic"]
if is_specialusedomain:
categories = []
yield dict(
meta={"domain": domain},
data={},
status="INFO",
summary="diagnosis_dns_specialusedomain",
)
for category in categories: for category in categories:
records = expected_configuration[category] records = expected_configuration[category]

View file

@ -34,6 +34,12 @@ class WebDiagnoser(Diagnoser):
summary="diagnosis_http_nginx_conf_not_up_to_date", summary="diagnosis_http_nginx_conf_not_up_to_date",
details=["diagnosis_http_nginx_conf_not_up_to_date_details"], details=["diagnosis_http_nginx_conf_not_up_to_date_details"],
) )
elif domain.endswith(".local"):
yield dict(
meta={"domain": domain},
status="INFO",
summary="diagnosis_http_localdomain",
)
else: else:
domains_to_check.append(domain) domains_to_check.append(domain)

View file

@ -15,7 +15,11 @@ mkdir -p "$MEDIA_DIRECTORY/$user/Video"
mkdir -p "$MEDIA_DIRECTORY/$user/eBook" mkdir -p "$MEDIA_DIRECTORY/$user/eBook"
ln -sfn "$MEDIA_DIRECTORY/share" "$MEDIA_DIRECTORY/$user/Share" ln -sfn "$MEDIA_DIRECTORY/share" "$MEDIA_DIRECTORY/$user/Share"
# Création du lien symbolique dans le home de l'utilisateur. # Création du lien symbolique dans le home de l'utilisateur.
ln -sfn "$MEDIA_DIRECTORY/$user" "/home/$user/Multimedia" #link will only be created if the home directory of the user exists and if it's located in '/home' folder
local user_home="$(getent passwd $user | cut -d: -f6 | grep '^/home/')"
if [[ -d "$user_home" ]]; then
ln -sfn "$MEDIA_DIRECTORY/$user" "$user_home/Multimedia"
fi
# Propriétaires des dossiers utilisateurs. # Propriétaires des dossiers utilisateurs.
chown -R $user "$MEDIA_DIRECTORY/$user" chown -R $user "$MEDIA_DIRECTORY/$user"

View file

@ -1,68 +0,0 @@
# This file is part of avahi.
#
# avahi is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation; either version 2 of the
# License, or (at your option) any later version.
#
# avahi 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 General Public
# License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with avahi; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
# USA.
# See avahi-daemon.conf(5) for more information on this configuration
# file!
[server]
host-name=yunohost
domain-name=local
#browse-domains=0pointer.de, zeroconf.org
use-ipv4=yes
use-ipv6=yes
#allow-interfaces=eth0
#deny-interfaces=eth1
#check-response-ttl=no
#use-iff-running=no
#enable-dbus=yes
#disallow-other-stacks=no
#allow-point-to-point=no
#cache-entries-max=4096
#clients-max=4096
#objects-per-client-max=1024
#entries-per-entry-group-max=32
ratelimit-interval-usec=1000000
ratelimit-burst=1000
[wide-area]
enable-wide-area=yes
[publish]
#disable-publishing=no
#disable-user-service-publishing=no
#add-service-cookie=no
#publish-addresses=yes
#publish-hinfo=yes
#publish-workstation=yes
#publish-domain=yes
#publish-dns-servers=192.168.50.1, 192.168.50.2
#publish-resolv-conf-dns-servers=yes
#publish-aaaa-on-ipv4=yes
#publish-a-on-ipv6=no
[reflector]
#enable-reflector=no
#reflect-ipv=no
[rlimits]
#rlimit-as=
rlimit-core=0
rlimit-data=4194304
rlimit-fsize=0
rlimit-nofile=768
rlimit-stack=4194304
rlimit-nproc=3

View file

@ -0,0 +1,13 @@
[Unit]
Description=YunoHost mDNS service
After=network.target
[Service]
User=mdns
Group=mdns
Type=simple
ExecStart=/usr/bin/yunomdns
StandardOutput=syslog
[Install]
WantedBy=default.target

View file

@ -1,4 +1,3 @@
avahi-daemon: {}
dnsmasq: dnsmasq:
test_conf: dnsmasq --test test_conf: dnsmasq --test
dovecot: dovecot:
@ -52,6 +51,8 @@ yunohost-firewall:
need_lock: true need_lock: true
test_status: iptables -S | grep "^-A INPUT" | grep " --dport" | grep -q ACCEPT test_status: iptables -S | grep "^-A INPUT" | grep " --dport" | grep -q ACCEPT
category: security category: security
yunomdns:
category: mdns
glances: null glances: null
nsswitch: null nsswitch: null
ssl: null ssl: null
@ -68,3 +69,4 @@ rmilter: null
php5-fpm: null php5-fpm: null
php7.0-fpm: null php7.0-fpm: null
nslcd: null nslcd: null
avahi-daemon: null

21
debian/changelog vendored
View file

@ -1,3 +1,24 @@
yunohost (4.2.8.1) stable; urgency=low
- [fix] Safer location for slapd backup during hdb/mdb migration (3c646b3d)
Thanks to all contributors <3 ! (ljf)
-- Alexandre Aubin <alex.aubin@mailoo.org> Fri, 27 Aug 2021 01:32:16 +0200
yunohost (4.2.8) stable; urgency=low
- [fix] ynh_permission_has_user not behaving properly when checking if a group is allowed (f0590907)
- [enh] use yaml safeloader everywhere ([#1287](https://github.com/YunoHost/yunohost/pull/1287))
- [enh] Add --no-safety-backup option to "yunohost app upgrade" ([#1286](https://github.com/YunoHost/yunohost/pull/1286))
- [enh] Add --purge option to "yunohost app remove" ([#1285](https://github.com/YunoHost/yunohost/pull/1285))
- [enh] Multimedia helper: check that home folder exists ([#1255](https://github.com/YunoHost/yunohost/pull/1255))
- [i18n] Translations updated for French, Galician, German, Portuguese
Thanks to all contributors <3 ! (José M, Kay0u, Krakinou, ljf, Luca, mifegui, ppr, sagessylu)
-- Alexandre Aubin <alex.aubin@mailoo.org> Thu, 19 Aug 2021 19:11:19 +0200
yunohost (4.2.7) stable; urgency=low yunohost (4.2.7) stable; urgency=low
Notable changes: Notable changes:

5
debian/control vendored
View file

@ -13,14 +13,15 @@ Depends: ${python3:Depends}, ${misc:Depends}
, moulinette (>= 4.2), ssowat (>= 4.0) , moulinette (>= 4.2), ssowat (>= 4.0)
, python3-psutil, python3-requests, python3-dnspython, python3-openssl , python3-psutil, python3-requests, python3-dnspython, python3-openssl
, python3-miniupnpc, python3-dbus, python3-jinja2 , python3-miniupnpc, python3-dbus, python3-jinja2
, python3-toml, python3-packaging, python3-publicsuffix , python3-toml, python3-packaging, python3-publicsuffix,
, python3-zeroconf,
, apt, apt-transport-https, apt-utils, dirmngr , apt, apt-transport-https, apt-utils, dirmngr
, php7.3-common, php7.3-fpm, php7.3-ldap, php7.3-intl , php7.3-common, php7.3-fpm, php7.3-ldap, php7.3-intl
, mariadb-server, php7.3-mysql , mariadb-server, php7.3-mysql
, openssh-server, iptables, fail2ban, dnsutils, bind9utils , openssh-server, iptables, fail2ban, dnsutils, bind9utils
, openssl, ca-certificates, netcat-openbsd, iproute2 , openssl, ca-certificates, netcat-openbsd, iproute2
, slapd, ldap-utils, sudo-ldap, libnss-ldapd, unscd, libpam-ldapd , slapd, ldap-utils, sudo-ldap, libnss-ldapd, unscd, libpam-ldapd
, dnsmasq, avahi-daemon, libnss-mdns, resolvconf, libnss-myhostname , dnsmasq, resolvconf, libnss-myhostname
, postfix, postfix-ldap, postfix-policyd-spf-perl, postfix-pcre , postfix, postfix-ldap, postfix-policyd-spf-perl, postfix-pcre
, dovecot-core, dovecot-ldap, dovecot-lmtpd, dovecot-managesieved, dovecot-antispam , dovecot-core, dovecot-ldap, dovecot-lmtpd, dovecot-managesieved, dovecot-antispam
, rspamd, opendkim-tools, postsrsd, procmail, mailutils , rspamd, opendkim-tools, postsrsd, procmail, mailutils

1
debian/postinst vendored
View file

@ -18,6 +18,7 @@ do_configure() {
bash /usr/share/yunohost/hooks/conf_regen/46-nsswitch init bash /usr/share/yunohost/hooks/conf_regen/46-nsswitch init
bash /usr/share/yunohost/hooks/conf_regen/06-slapd init bash /usr/share/yunohost/hooks/conf_regen/06-slapd init
bash /usr/share/yunohost/hooks/conf_regen/15-nginx init bash /usr/share/yunohost/hooks/conf_regen/15-nginx init
bash /usr/share/yunohost/hooks/conf_regen/37-mdns init
fi fi
else else
echo "Regenerating configuration, this might take a while..." echo "Regenerating configuration, this might take a while..."

View file

@ -26,7 +26,7 @@ ACTIONSMAP_FILE = os.path.join(THIS_SCRIPT_DIR, "../data/actionsmap/yunohost.yml
def ordered_yaml_load(stream): def ordered_yaml_load(stream):
class OrderedLoader(yaml.Loader): class OrderedLoader(yaml.SafeLoader):
pass pass
OrderedLoader.add_constructor( OrderedLoader.add_constructor(

View file

@ -83,7 +83,6 @@
"yunohost_installing": "عملية تنصيب يونوهوست جارية …", "yunohost_installing": "عملية تنصيب يونوهوست جارية …",
"yunohost_not_installed": "إنَّ واي يونوهوست ليس مُنَصَّب أو هو مثبت حاليا بشكل خاطئ. قم بتنفيذ الأمر 'yunohost tools postinstall'", "yunohost_not_installed": "إنَّ واي يونوهوست ليس مُنَصَّب أو هو مثبت حاليا بشكل خاطئ. قم بتنفيذ الأمر 'yunohost tools postinstall'",
"migrations_list_conflict_pending_done": "لا يمكنك استخدام --previous و --done معًا على نفس سطر الأوامر.", "migrations_list_conflict_pending_done": "لا يمكنك استخدام --previous و --done معًا على نفس سطر الأوامر.",
"service_description_avahi-daemon": "يسمح لك بالنفاذ إلى خادومك عبر الشبكة المحلية باستخدام yunohost.local",
"service_description_metronome": "يُدير حسابات الدردشة الفورية XMPP", "service_description_metronome": "يُدير حسابات الدردشة الفورية XMPP",
"service_description_nginx": "يقوم بتوفير النفاذ و السماح بالوصول إلى كافة مواقع الويب المستضافة على خادومك", "service_description_nginx": "يقوم بتوفير النفاذ و السماح بالوصول إلى كافة مواقع الويب المستضافة على خادومك",
"service_description_postfix": "يقوم بإرسال و تلقي الرسائل البريدية الإلكترونية", "service_description_postfix": "يقوم بإرسال و تلقي الرسائل البريدية الإلكترونية",

View file

@ -283,7 +283,6 @@
"service_already_started": "El servei «{service}» ja està funcionant", "service_already_started": "El servei «{service}» ja està funcionant",
"service_already_stopped": "Ja s'ha aturat el servei «{service}»", "service_already_stopped": "Ja s'ha aturat el servei «{service}»",
"service_cmd_exec_failed": "No s'ha pogut executar l'ordre «{command}»", "service_cmd_exec_failed": "No s'ha pogut executar l'ordre «{command}»",
"service_description_avahi-daemon": "Permet accedir al servidor via «yunohost.local» en la xarxa local",
"service_description_dnsmasq": "Gestiona la resolució del nom de domini (DNS)", "service_description_dnsmasq": "Gestiona la resolució del nom de domini (DNS)",
"service_description_dovecot": "Permet als clients de correu accedir/recuperar correus (via IMAP i POP3)", "service_description_dovecot": "Permet als clients de correu accedir/recuperar correus (via IMAP i POP3)",
"service_description_fail2ban": "Protegeix contra els atacs de força bruta i a altres atacs provinents d'Internet", "service_description_fail2ban": "Protegeix contra els atacs de força bruta i a altres atacs provinents d'Internet",

View file

@ -124,7 +124,7 @@
"upnp_dev_not_found": "Es konnten keine UPnP Geräte gefunden werden", "upnp_dev_not_found": "Es konnten keine UPnP Geräte gefunden werden",
"upnp_disabled": "UPnP deaktiviert", "upnp_disabled": "UPnP deaktiviert",
"upnp_enabled": "UPnP aktiviert", "upnp_enabled": "UPnP aktiviert",
"upnp_port_open_failed": "UPnP Port konnte nicht geöffnet werden.", "upnp_port_open_failed": "Port konnte nicht via UPnP geöffnet werden",
"user_created": "Benutzer erstellt", "user_created": "Benutzer erstellt",
"user_creation_failed": "Benutzer konnte nicht erstellt werden {user}: {error}", "user_creation_failed": "Benutzer konnte nicht erstellt werden {user}: {error}",
"user_deleted": "Benutzer gelöscht", "user_deleted": "Benutzer gelöscht",
@ -528,7 +528,7 @@
"migrations_no_such_migration": "Es existiert keine Migration genannt '{id}'", "migrations_no_such_migration": "Es existiert keine Migration genannt '{id}'",
"migrations_running_forward": "Durchführen der Migrationen {id}...", "migrations_running_forward": "Durchführen der Migrationen {id}...",
"migrations_skip_migration": "Überspringe Migrationen {id}...", "migrations_skip_migration": "Überspringe Migrationen {id}...",
"password_too_simple_2": "Dieses Passwort gehört zu den meistverwendeten der Welt. Bitte nehmen Sie etwas einzigartigeres", "password_too_simple_2": "Das Passwort muss mindestens 8 Zeichen lang sein und Gross- sowie Kleinbuchstaben enthalten",
"password_listed": "Dieses Passwort zählt zu den meistgenutzten Passwörtern der Welt. Bitte wähle ein anderes, einzigartigeres Passwort.", "password_listed": "Dieses Passwort zählt zu den meistgenutzten Passwörtern der Welt. Bitte wähle ein anderes, einzigartigeres Passwort.",
"operation_interrupted": "Wurde die Operation manuell unterbrochen?", "operation_interrupted": "Wurde die Operation manuell unterbrochen?",
"invalid_number": "Muss eine Zahl sein", "invalid_number": "Muss eine Zahl sein",
@ -539,8 +539,8 @@
"permission_already_allowed": "Die Gruppe '{group}' hat die Berechtigung '{permission}' bereits erhalten", "permission_already_allowed": "Die Gruppe '{group}' hat die Berechtigung '{permission}' bereits erhalten",
"pattern_password_app": "Entschuldigen Sie bitte! Passwörter dürfen folgende Zeichen nicht enthalten: {forbidden_chars}", "pattern_password_app": "Entschuldigen Sie bitte! Passwörter dürfen folgende Zeichen nicht enthalten: {forbidden_chars}",
"pattern_email_forward": "Es muss sich um eine gültige E-Mail-Adresse handeln. Das Symbol '+' wird akzeptiert (zum Beispiel : maxmuster@beispiel.com oder maxmuster+yunohost@beispiel.com)", "pattern_email_forward": "Es muss sich um eine gültige E-Mail-Adresse handeln. Das Symbol '+' wird akzeptiert (zum Beispiel : maxmuster@beispiel.com oder maxmuster+yunohost@beispiel.com)",
"password_too_simple_4": "Dass Passwort muss mindestens 12 Zeichen lang sein und Zahlen, Klein- und Grossbuchstaben und Sonderzeichen enthalten", "password_too_simple_4": "Das Passwort muss mindestens 12 Zeichen lang sein und Grossbuchstaben, Kleinbuchstaben, Zahlen und Sonderzeichen enthalten",
"password_too_simple_3": "Das Passwort muss mindestens 8 Zeichen lang sein und Zahlen, Klein- und Grossbuchstaben und Sonderzeichen enthalten", "password_too_simple_3": "Das Passwort muss mindestens 8 Zeichen lang sein und Grossbuchstaben, Kleinbuchstaben, Zahlen und Sonderzeichen enthalten",
"regenconf_file_manually_removed": "Die Konfigurationsdatei '{conf}' wurde manuell gelöscht und wird nicht erstellt", "regenconf_file_manually_removed": "Die Konfigurationsdatei '{conf}' wurde manuell gelöscht und wird nicht erstellt",
"regenconf_file_manually_modified": "Die Konfigurationsdatei '{conf}' wurde manuell bearbeitet und wird nicht aktualisiert", "regenconf_file_manually_modified": "Die Konfigurationsdatei '{conf}' wurde manuell bearbeitet und wird nicht aktualisiert",
"regenconf_file_kept_back": "Die Konfigurationsdatei '{conf}' sollte von \"regen-conf\" (Kategorie {category}) gelöscht werden, wurde aber beibehalten.", "regenconf_file_kept_back": "Die Konfigurationsdatei '{conf}' sollte von \"regen-conf\" (Kategorie {category}) gelöscht werden, wurde aber beibehalten.",
@ -597,7 +597,6 @@
"service_description_fail2ban": "Schützt gegen Brute-Force-Angriffe und andere Angriffe aus dem Internet", "service_description_fail2ban": "Schützt gegen Brute-Force-Angriffe und andere Angriffe aus dem Internet",
"service_description_dovecot": "Ermöglicht es E-Mail-Clients auf Konten zuzugreifen (IMAP und POP3)", "service_description_dovecot": "Ermöglicht es E-Mail-Clients auf Konten zuzugreifen (IMAP und POP3)",
"service_description_dnsmasq": "Verarbeitet die Auflösung des Domainnamens (DNS)", "service_description_dnsmasq": "Verarbeitet die Auflösung des Domainnamens (DNS)",
"service_description_avahi-daemon": "Erlaubt, den Server im lokalen Netz über 'yunohost.local' zu erreichen",
"restore_backup_too_old": "Dieses Backup kann nicht wieder hergestellt werden, weil es von einer zu alten YunoHost Version stammt.", "restore_backup_too_old": "Dieses Backup kann nicht wieder hergestellt werden, weil es von einer zu alten YunoHost Version stammt.",
"service_description_slapd": "Speichert Benutzer, Domains und verbundene Informationen", "service_description_slapd": "Speichert Benutzer, Domains und verbundene Informationen",
"service_description_rspamd": "Spamfilter und andere E-Mail-Merkmale", "service_description_rspamd": "Spamfilter und andere E-Mail-Merkmale",
@ -631,5 +630,9 @@
"unknown_main_domain_path": "Unbekannte:r Domain oder Pfad für '{app}'. Du musst eine Domain und einen Pfad setzen, um die URL für Berechtigungen zu setzen.", "unknown_main_domain_path": "Unbekannte:r Domain oder Pfad für '{app}'. Du musst eine Domain und einen Pfad setzen, um die URL für Berechtigungen zu setzen.",
"yunohost_postinstall_end_tip": "Post-install ist fertig! Um das Setup abzuschliessen, wird empfohlen:\n - einen ersten Benutzer über den Bereich 'Benutzer*in' im Adminbereich hinzuzufügen (oder mit 'yunohost user create <username>' in der Kommandezeile);\n - mögliche Fehler zu diagnostizieren über den Bereich 'Diagnose' im Adminbereich (oder mit 'yunohost diagnosis run' in der Kommandozeile;\n - Die Abschnitte 'Install YunoHost' und 'Geführte Tour' im Administratorenhandbuch zu lesen: https://yunohost.org/admindoc.", "yunohost_postinstall_end_tip": "Post-install ist fertig! Um das Setup abzuschliessen, wird empfohlen:\n - einen ersten Benutzer über den Bereich 'Benutzer*in' im Adminbereich hinzuzufügen (oder mit 'yunohost user create <username>' in der Kommandezeile);\n - mögliche Fehler zu diagnostizieren über den Bereich 'Diagnose' im Adminbereich (oder mit 'yunohost diagnosis run' in der Kommandozeile;\n - Die Abschnitte 'Install YunoHost' und 'Geführte Tour' im Administratorenhandbuch zu lesen: https://yunohost.org/admindoc.",
"user_already_exists": "Der Benutzer '{user}' ist bereits vorhanden", "user_already_exists": "Der Benutzer '{user}' ist bereits vorhanden",
"update_apt_cache_warning": "Beim Versuch den Cache für APT (Debians Paketmanager) zu aktualisieren, ist etwas schief gelaufen. Hier ist ein Dump der Zeilen aus sources.list, die Ihnen vielleicht dabei helfen, das Problem zu identifizieren:\n{sourceslist}" "update_apt_cache_warning": "Beim Versuch den Cache für APT (Debians Paketmanager) zu aktualisieren, ist etwas schief gelaufen. Hier ist ein Dump der Zeilen aus sources.list, die Ihnen vielleicht dabei helfen, das Problem zu identifizieren:\n{sourceslist}",
"global_settings_setting_security_webadmin_allowlist": "IP-Adressen, die auf die Verwaltungsseite zugreifen dürfen. Kommasepariert.",
"global_settings_setting_security_webadmin_allowlist_enabled": "Erlaube nur bestimmten IP-Adressen den Zugriff auf die Verwaltungsseite.",
"disk_space_not_sufficient_update": "Es ist nicht genügend Speicherplatz frei, um diese Applikation zu aktuallisieren",
"disk_space_not_sufficient_install": "Es ist nicht genügend Speicherplatz frei, um diese Applikation zu installieren"
} }

View file

@ -32,7 +32,7 @@
"app_location_unavailable": "This URL is either unavailable, or conflicts with the already installed app(s):\n{apps}", "app_location_unavailable": "This URL is either unavailable, or conflicts with the already installed app(s):\n{apps}",
"app_manifest_invalid": "Something is wrong with the app manifest: {error}", "app_manifest_invalid": "Something is wrong with the app manifest: {error}",
"app_manifest_install_ask_domain": "Choose the domain where this app should be installed", "app_manifest_install_ask_domain": "Choose the domain where this app should be installed",
"app_manifest_install_ask_path": "Choose the path where this app should be installed", "app_manifest_install_ask_path": "Choose the URL path (after the domain) where this app should be installed",
"app_manifest_install_ask_password": "Choose an administration password for this app", "app_manifest_install_ask_password": "Choose an administration password for this app",
"app_manifest_install_ask_admin": "Choose an administrator user for this app", "app_manifest_install_ask_admin": "Choose an administrator user for this app",
"app_manifest_install_ask_is_public": "Should this app be exposed to anonymous visitors?", "app_manifest_install_ask_is_public": "Should this app be exposed to anonymous visitors?",
@ -183,6 +183,7 @@
"diagnosis_dns_discrepancy": "The following DNS record does not seem to follow the recommended configuration:<br>Type: <code>{type}</code><br>Name: <code>{name}</code><br>Current value: <code>{current}</code><br>Expected value: <code>{value}</code>", "diagnosis_dns_discrepancy": "The following DNS record does not seem to follow the recommended configuration:<br>Type: <code>{type}</code><br>Name: <code>{name}</code><br>Current value: <code>{current}</code><br>Expected value: <code>{value}</code>",
"diagnosis_dns_point_to_doc": "Please check the documentation at <a href='https://yunohost.org/dns_config'>https://yunohost.org/dns_config</a> if you need help about configuring DNS records.", "diagnosis_dns_point_to_doc": "Please check the documentation at <a href='https://yunohost.org/dns_config'>https://yunohost.org/dns_config</a> if you need help about configuring DNS records.",
"diagnosis_dns_try_dyndns_update_force": "This domain's DNS configuration should automatically be managed by YunoHost. If that's not the case, you can try to force an update using <cmd>yunohost dyndns update --force</cmd>.", "diagnosis_dns_try_dyndns_update_force": "This domain's DNS configuration should automatically be managed by YunoHost. If that's not the case, you can try to force an update using <cmd>yunohost dyndns update --force</cmd>.",
"diagnosis_dns_specialusedomain": "Domain {domain} is based on a special-use top-level domain (TLD) and is therefore not expected to have actual DNS records.",
"diagnosis_domain_expiration_not_found": "Unable to check the expiration date for some domains", "diagnosis_domain_expiration_not_found": "Unable to check the expiration date for some domains",
"diagnosis_domain_not_found_details": "The domain {domain} doesn't exist in WHOIS database or is expired!", "diagnosis_domain_not_found_details": "The domain {domain} doesn't exist in WHOIS database or is expired!",
"diagnosis_domain_expiration_not_found_details": "The WHOIS information for domain {domain} doesn't seem to contain the information about the expiration date?", "diagnosis_domain_expiration_not_found_details": "The WHOIS information for domain {domain} doesn't seem to contain the information about the expiration date?",
@ -259,6 +260,7 @@
"diagnosis_http_hairpinning_issue_details": "This is probably because of your ISP box / router. As a result, people from outside your local network will be able to access your server as expected, but not people from inside the local network (like you, probably?) when using the domain name or global IP. You may be able to improve the situation by having a look at <a href='https://yunohost.org/dns_local_network'>https://yunohost.org/dns_local_network</a>", "diagnosis_http_hairpinning_issue_details": "This is probably because of your ISP box / router. As a result, people from outside your local network will be able to access your server as expected, but not people from inside the local network (like you, probably?) when using the domain name or global IP. You may be able to improve the situation by having a look at <a href='https://yunohost.org/dns_local_network'>https://yunohost.org/dns_local_network</a>",
"diagnosis_http_could_not_diagnose": "Could not diagnose if domains are reachable from outside in IPv{ipversion}.", "diagnosis_http_could_not_diagnose": "Could not diagnose if domains are reachable from outside in IPv{ipversion}.",
"diagnosis_http_could_not_diagnose_details": "Error: {error}", "diagnosis_http_could_not_diagnose_details": "Error: {error}",
"diagnosis_http_localdomain": "Domain {domain}, with a .local TLD, is not expected to be reached from outside the local network.",
"diagnosis_http_ok": "Domain {domain} is reachable through HTTP from outside the local network.", "diagnosis_http_ok": "Domain {domain} is reachable through HTTP from outside the local network.",
"diagnosis_http_timeout": "Timed-out while trying to contact your server from outside. It appears to be unreachable.<br>1. The most common cause for this issue is that port 80 (and 443) <a href='https://yunohost.org/isp_box_config'>are not correctly forwarded to your server</a>.<br>2. You should also make sure that the service nginx is running<br>3. On more complex setups: make sure that no firewall or reverse-proxy is interfering.", "diagnosis_http_timeout": "Timed-out while trying to contact your server from outside. It appears to be unreachable.<br>1. The most common cause for this issue is that port 80 (and 443) <a href='https://yunohost.org/isp_box_config'>are not correctly forwarded to your server</a>.<br>2. You should also make sure that the service nginx is running<br>3. On more complex setups: make sure that no firewall or reverse-proxy is interfering.",
"diagnosis_http_connection_error": "Connection error: could not connect to the requested domain, it's very likely unreachable.", "diagnosis_http_connection_error": "Connection error: could not connect to the requested domain, it's very likely unreachable.",
@ -397,7 +399,7 @@
"log_letsencrypt_cert_install": "Install a Let's Encrypt certificate on '{}' domain", "log_letsencrypt_cert_install": "Install a Let's Encrypt certificate on '{}' domain",
"log_permission_create": "Create permission '{}'", "log_permission_create": "Create permission '{}'",
"log_permission_delete": "Delete permission '{}'", "log_permission_delete": "Delete permission '{}'",
"log_permission_url": "Update url related to permission '{}'", "log_permission_url": "Update URL related to permission '{}'",
"log_selfsigned_cert_install": "Install self-signed certificate on '{}' domain", "log_selfsigned_cert_install": "Install self-signed certificate on '{}' domain",
"log_letsencrypt_cert_renew": "Renew '{}' Let's Encrypt certificate", "log_letsencrypt_cert_renew": "Renew '{}' Let's Encrypt certificate",
"log_regen_conf": "Regenerate system configurations '{}'", "log_regen_conf": "Regenerate system configurations '{}'",
@ -560,7 +562,7 @@
"service_already_started": "The service '{service}' is running already", "service_already_started": "The service '{service}' is running already",
"service_already_stopped": "The service '{service}' has already been stopped", "service_already_stopped": "The service '{service}' has already been stopped",
"service_cmd_exec_failed": "Could not execute the command '{command}'", "service_cmd_exec_failed": "Could not execute the command '{command}'",
"service_description_avahi-daemon": "Allows you to reach your server using 'yunohost.local' in your local network", "service_description_yunomdns": "Allows you to reach your server using 'yunohost.local' in your local network",
"service_description_dnsmasq": "Handles domain name resolution (DNS)", "service_description_dnsmasq": "Handles domain name resolution (DNS)",
"service_description_dovecot": "Allows e-mail clients to access/fetch email (via IMAP and POP3)", "service_description_dovecot": "Allows e-mail clients to access/fetch email (via IMAP and POP3)",
"service_description_fail2ban": "Protects against brute-force and other kinds of attacks from the Internet", "service_description_fail2ban": "Protects against brute-force and other kinds of attacks from the Internet",

View file

@ -332,7 +332,6 @@
"hook_exec_failed": "Ne povis funkcii skripto: {path}", "hook_exec_failed": "Ne povis funkcii skripto: {path}",
"global_settings_cant_open_settings": "Ne eblis malfermi agordojn, tial: {reason}", "global_settings_cant_open_settings": "Ne eblis malfermi agordojn, tial: {reason}",
"user_created": "Uzanto kreita", "user_created": "Uzanto kreita",
"service_description_avahi-daemon": "Permesas al vi atingi vian servilon uzante 'yunohost.local' en via loka reto",
"certmanager_attempt_to_replace_valid_cert": "Vi provas anstataŭigi bonan kaj validan atestilon por domajno {domain}! (Uzu --forte pretervidi)", "certmanager_attempt_to_replace_valid_cert": "Vi provas anstataŭigi bonan kaj validan atestilon por domajno {domain}! (Uzu --forte pretervidi)",
"regenconf_updated": "Agordo ĝisdatigita por '{category}'", "regenconf_updated": "Agordo ĝisdatigita por '{category}'",
"update_apt_cache_warning": "Io iris malbone dum la ĝisdatigo de la kaŝmemoro de APT (paka administranto de Debian). Jen rubujo de la sources.list-linioj, kiuj povus helpi identigi problemajn liniojn:\n{sourceslist}", "update_apt_cache_warning": "Io iris malbone dum la ĝisdatigo de la kaŝmemoro de APT (paka administranto de Debian). Jen rubujo de la sources.list-linioj, kiuj povus helpi identigi problemajn liniojn:\n{sourceslist}",

View file

@ -238,7 +238,6 @@
"service_description_fail2ban": "Protege contra ataques de fuerza bruta y otras clases de ataques desde Internet", "service_description_fail2ban": "Protege contra ataques de fuerza bruta y otras clases de ataques desde Internet",
"service_description_dovecot": "Permite a los clientes de correo acceder/obtener correo (vía IMAP y POP3)", "service_description_dovecot": "Permite a los clientes de correo acceder/obtener correo (vía IMAP y POP3)",
"service_description_dnsmasq": "Maneja la resolución de nombres de dominio (DNS)", "service_description_dnsmasq": "Maneja la resolución de nombres de dominio (DNS)",
"service_description_avahi-daemon": "Permite acceder a su servidor usando «yunohost.local» en su red local",
"server_reboot_confirm": "El servidor se reiniciará inmediatamente ¿está seguro? [{answers}]", "server_reboot_confirm": "El servidor se reiniciará inmediatamente ¿está seguro? [{answers}]",
"server_reboot": "El servidor se reiniciará", "server_reboot": "El servidor se reiniciará",
"server_shutdown_confirm": "El servidor se apagará inmediatamente ¿está seguro? [{answers}]", "server_shutdown_confirm": "El servidor se apagará inmediatamente ¿está seguro? [{answers}]",

View file

@ -234,7 +234,7 @@
"migrations_list_conflict_pending_done": "Vous ne pouvez pas utiliser --previous et --done simultanément.", "migrations_list_conflict_pending_done": "Vous ne pouvez pas utiliser --previous et --done simultanément.",
"migrations_to_be_ran_manually": "La migration {id} doit être lancée manuellement. Veuillez aller dans Outils > Migrations dans linterface admin, ou lancer `yunohost tools migrations run`.", "migrations_to_be_ran_manually": "La migration {id} doit être lancée manuellement. Veuillez aller dans Outils > Migrations dans linterface admin, ou lancer `yunohost tools migrations run`.",
"migrations_need_to_accept_disclaimer": "Pour lancer la migration {id}, vous devez accepter cet avertissement :\n---\n{disclaimer}\n---\nSi vous acceptez de lancer la migration, veuillez relancer la commande avec loption --accept-disclaimer.", "migrations_need_to_accept_disclaimer": "Pour lancer la migration {id}, vous devez accepter cet avertissement :\n---\n{disclaimer}\n---\nSi vous acceptez de lancer la migration, veuillez relancer la commande avec loption --accept-disclaimer.",
"service_description_avahi-daemon": "Vous permet datteindre votre serveur en utilisant « yunohost.local » sur votre réseau local", "service_description_yunomdns": "Vous permet datteindre votre serveur en utilisant « yunohost.local » sur votre réseau local",
"service_description_dnsmasq": "Gère 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 daccéder/récupérer les courriels (via IMAP et POP3)", "service_description_dovecot": "Permet aux clients de messagerie daccéder/récupérer les courriels (via IMAP et POP3)",
"service_description_fail2ban": "Protège contre les attaques brute-force et autres types dattaques venant dInternet", "service_description_fail2ban": "Protège contre les attaques brute-force et autres types dattaques venant dInternet",
@ -633,5 +633,7 @@
"diagnosis_sshd_config_inconsistent_details": "Veuillez exécuter <cmd>yunohost settings set security.ssh.port -v VOTRE_PORT_SSH</cmd> pour définir le port SSH, et vérifiez <cmd>yunohost tools regen-conf ssh --dry-run --with-diff</cmd> et <cmd>yunohost tools regen-conf ssh --force</cmd> pour réinitialiser votre configuration aux recommandations YunoHost.", "diagnosis_sshd_config_inconsistent_details": "Veuillez exécuter <cmd>yunohost settings set security.ssh.port -v VOTRE_PORT_SSH</cmd> pour définir le port SSH, et vérifiez <cmd>yunohost tools regen-conf ssh --dry-run --with-diff</cmd> et <cmd>yunohost tools regen-conf ssh --force</cmd> pour réinitialiser votre configuration aux recommandations YunoHost.",
"diagnosis_sshd_config_inconsistent": "Il semble que le port SSH a été modifié manuellement dans /etc/ssh/sshd_config. Depuis YunoHost 4.2, un nouveau paramètre global 'security.ssh.port' est disponible pour éviter de modifier manuellement la configuration.", "diagnosis_sshd_config_inconsistent": "Il semble que le port SSH a été modifié manuellement dans /etc/ssh/sshd_config. Depuis YunoHost 4.2, un nouveau paramètre global 'security.ssh.port' est disponible pour éviter de modifier manuellement la configuration.",
"diagnosis_sshd_config_insecure": "La configuration SSH semble avoir été modifiée manuellement et n'est pas sécurisée car elle ne contient aucune directive 'AllowGroups' ou 'AllowUsers' pour limiter l'accès aux utilisateurs autorisés.", "diagnosis_sshd_config_insecure": "La configuration SSH semble avoir été modifiée manuellement et n'est pas sécurisée car elle ne contient aucune directive 'AllowGroups' ou 'AllowUsers' pour limiter l'accès aux utilisateurs autorisés.",
"backup_create_size_estimation": "L'archive contiendra environ {size} de données." "backup_create_size_estimation": "L'archive contiendra environ {size} de données.",
"global_settings_setting_security_webadmin_allowlist": "Adresses IP autorisées à accéder à la page web du portail d'administration (webadmin). Elles doivent être séparées par une virgule.",
"global_settings_setting_security_webadmin_allowlist_enabled": "Autorisez seulement certaines IP à accéder à la page web du portail d'administration (webadmin)."
} }

View file

@ -67,7 +67,7 @@
"app_remove_after_failed_install": "Eliminando a app debido ao fallo na instalación...", "app_remove_after_failed_install": "Eliminando a app debido ao fallo na instalación...",
"app_requirements_unmeet": "Non se cumpren os requerimentos de {app}, o paquete {pkgname} ({version}) debe ser {spec}", "app_requirements_unmeet": "Non se cumpren os requerimentos de {app}, o paquete {pkgname} ({version}) debe ser {spec}",
"app_requirements_checking": "Comprobando os paquetes requeridos por {app}...", "app_requirements_checking": "Comprobando os paquetes requeridos por {app}...",
"app_removed": "{app} eliminada", "app_removed": "{app} desinstalada",
"app_not_properly_removed": "{app} non se eliminou de xeito correcto", "app_not_properly_removed": "{app} non se eliminou de xeito correcto",
"app_not_installed": "Non se puido atopar {app} na lista de apps instaladas: {all_apps}", "app_not_installed": "Non se puido atopar {app} na lista de apps instaladas: {all_apps}",
"app_not_correctly_installed": "{app} semella que non está instalada correctamente", "app_not_correctly_installed": "{app} semella que non está instalada correctamente",
@ -345,5 +345,17 @@
"global_settings_setting_smtp_relay_password": "Contrasinal no repetidor SMTP", "global_settings_setting_smtp_relay_password": "Contrasinal no repetidor SMTP",
"global_settings_setting_smtp_relay_user": "Conta de usuaria no repetidor SMTP", "global_settings_setting_smtp_relay_user": "Conta de usuaria no repetidor SMTP",
"global_settings_setting_smtp_relay_port": "Porto do repetidor SMTP", "global_settings_setting_smtp_relay_port": "Porto do repetidor SMTP",
"global_settings_setting_smtp_relay_host": "Servidor repetidor SMTP para enviar emails no lugar da túa instancia yunohost. É útil se estás nunha destas situacións: o teu porto 25 está bloqueado polo teu provedor ISP u VPN, se tes unha IP residencial nunha lista DUHL, se non podes configurar DNS inversa ou se este servidor non ten conexión directa a internet e queres utilizar outro para enviar os emails." "global_settings_setting_smtp_relay_host": "Servidor repetidor SMTP para enviar emails no lugar da túa instancia yunohost. É útil se estás nunha destas situacións: o teu porto 25 está bloqueado polo teu provedor ISP u VPN, se tes unha IP residencial nunha lista DUHL, se non podes configurar DNS inversa ou se este servidor non ten conexión directa a internet e queres utilizar outro para enviar os emails.",
"group_updated": "Grupo '{group}' actualizado",
"group_unknown": "Grupo descoñecido '{group}'",
"group_deletion_failed": "Non se eliminou o grupo '{group}': {error}",
"group_deleted": "Grupo '{group}' eliminado",
"group_cannot_be_deleted": "O grupo {group} non se pode eliminar manualmente.",
"group_cannot_edit_primary_group": "O grupo '{group}' non se pode editar manualmente. É o grupo primario que contén só a unha usuaria concreta.",
"group_cannot_edit_visitors": "O grupo 'visitors' non se pode editar manualmente. É un grupo especial que representa a tódas visitantes anónimas",
"group_cannot_edit_all_users": "O grupo 'all_users' non se pode editar manualmente. É un grupo especial que contén tódalas usuarias rexistradas en YunoHost",
"global_settings_setting_security_webadmin_allowlist": "Enderezos IP con permiso para acceder á webadmin. Separados por vírgulas.",
"global_settings_setting_security_webadmin_allowlist_enabled": "Permitir que só algúns IPs accedan á webadmin.",
"disk_space_not_sufficient_update": "Non hai espazo suficiente no disco para actualizar esta aplicación",
"disk_space_not_sufficient_install": "Non queda espazo suficiente no disco para instalar esta aplicación"
} }

View file

@ -428,7 +428,6 @@
"service_description_fail2ban": "Ti protegge dal brute-force e altri tipi di attacchi da Internet", "service_description_fail2ban": "Ti protegge dal brute-force e altri tipi di attacchi da Internet",
"service_description_dovecot": "Consente ai client mail di accedere/recuperare le email (via IMAP e POP3)", "service_description_dovecot": "Consente ai client mail di accedere/recuperare le email (via IMAP e POP3)",
"service_description_dnsmasq": "Gestisce la risoluzione dei domini (DNS)", "service_description_dnsmasq": "Gestisce la risoluzione dei domini (DNS)",
"service_description_avahi-daemon": "Consente di raggiungere il tuo server eseguendo 'yunohost.local' sulla tua LAN",
"server_reboot_confirm": "Il server si riavvierà immediatamente, sei sicuro? [{answers}]", "server_reboot_confirm": "Il server si riavvierà immediatamente, sei sicuro? [{answers}]",
"server_reboot": "Il server si riavvierà", "server_reboot": "Il server si riavvierà",
"server_shutdown_confirm": "Il server si spegnerà immediatamente, sei sicuro? [{answers}]", "server_shutdown_confirm": "Il server si spegnerà immediatamente, sei sicuro? [{answers}]",

View file

@ -193,7 +193,6 @@
"user_unknown": "Utilizaire « {user} »desconegut", "user_unknown": "Utilizaire « {user} »desconegut",
"user_update_failed": "Modificacion impossibla de lutilizaire", "user_update_failed": "Modificacion impossibla de lutilizaire",
"user_updated": "Lutilizaire es estat modificat", "user_updated": "Lutilizaire es estat modificat",
"service_description_avahi-daemon": "permet daténher vòstre servidor via yunohost.local sus vòstre ret local",
"service_description_dnsmasq": "gerís la resolucion dels noms de domeni (DNS)", "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…",
"server_reboot_confirm": "Lo servidor es per reaviar sul pic, o volètz vertadièrament? {answers}", "server_reboot_confirm": "Lo servidor es per reaviar sul pic, o volètz vertadièrament? {answers}",

View file

@ -1,7 +1,7 @@
{ {
"action_invalid": "Acção Inválida '{action}'", "action_invalid": "Acção Inválida '{action}'",
"admin_password": "Senha de administração", "admin_password": "Senha de administração",
"admin_password_change_failed": "Não é possível alterar a senha", "admin_password_change_failed": "Não foi possível alterar a senha",
"admin_password_changed": "A senha da administração foi alterada", "admin_password_changed": "A senha da administração foi alterada",
"app_already_installed": "{app} já está instalada", "app_already_installed": "{app} já está instalada",
"app_extraction_failed": "Não foi possível extrair os ficheiros para instalação", "app_extraction_failed": "Não foi possível extrair os ficheiros para instalação",
@ -108,12 +108,12 @@
"backup_hook_unknown": "Gancho de backup '{hook}' desconhecido", "backup_hook_unknown": "Gancho de backup '{hook}' desconhecido",
"backup_nothings_done": "Não há nada para guardar", "backup_nothings_done": "Não há nada para guardar",
"backup_output_directory_forbidden": "Diretório de saída proibido. Os backups não podem ser criados em /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var ou /home/yunohost.backup/archives subpastas", "backup_output_directory_forbidden": "Diretório de saída proibido. Os backups não podem ser criados em /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var ou /home/yunohost.backup/archives subpastas",
"app_already_installed_cant_change_url": "Este aplicativo já está instalado. A URL não pode ser alterada apenas por esta função. Olhe para o `app changeurl` se estiver disponível.", "app_already_installed_cant_change_url": "Este aplicativo já está instalado. A URL não pode ser alterada apenas por esta função. Confira em `app changeurl` se está disponível.",
"app_already_up_to_date": "{app} já está atualizado", "app_already_up_to_date": "{app} já está atualizado",
"app_argument_choice_invalid": "Escolha inválida para o argumento '{name}', deve ser um dos {choices}", "app_argument_choice_invalid": "Use uma das opções '{choices}' para o argumento '{name}'",
"app_argument_invalid": "Valor inválido de argumento '{name}': {error}", "app_argument_invalid": "Escolha um valor válido para o argumento '{name}': {error}",
"app_argument_required": "O argumento '{name}' é obrigatório", "app_argument_required": "O argumento '{name}' é obrigatório",
"app_change_url_failed_nginx_reload": "Falha ao reiniciar o nginx. Aqui está o retorno de 'nginx -t':\n{nginx_errors}", "app_change_url_failed_nginx_reload": "Não foi possível reiniciar o nginx. Aqui está o retorno de 'nginx -t':\n{nginx_errors}",
"app_location_unavailable": "Esta url não está disponível ou está em conflito com outra aplicação já instalada", "app_location_unavailable": "Esta url não está disponível ou está em conflito com outra aplicação já instalada",
"app_upgrade_app_name": "Atualizando aplicação {app}…", "app_upgrade_app_name": "Atualizando aplicação {app}…",
"app_upgrade_some_app_failed": "Não foi possível atualizar algumas aplicações", "app_upgrade_some_app_failed": "Não foi possível atualizar algumas aplicações",
@ -129,5 +129,12 @@
"app_change_url_identical_domains": "O antigo e o novo domínio / url_path são idênticos ('{domain}{path}'), nada para fazer.", "app_change_url_identical_domains": "O antigo e o novo domínio / url_path são idênticos ('{domain}{path}'), nada para fazer.",
"password_too_simple_1": "A senha precisa ter pelo menos 8 caracteres", "password_too_simple_1": "A senha precisa ter pelo menos 8 caracteres",
"admin_password_too_long": "Escolha uma senha que contenha menos de 127 caracteres", "admin_password_too_long": "Escolha uma senha que contenha menos de 127 caracteres",
"aborting": "Abortando." "aborting": "Abortando.",
"app_change_url_no_script": "A aplicação '{app_name}' ainda não permite modificar a URL. Talvez devesse atualizá-la.",
"app_argument_password_no_default": "Erro ao interpretar argumento da senha '{name}': O argumento da senha não pode ter um valor padrão por segurança",
"app_action_cannot_be_ran_because_required_services_down": "Estes serviços devem estar funcionado para executar esta ação: {services}. Tente reiniciá-los para continuar (e possivelmente investigar o porquê de não estarem funcionado).",
"app_action_broke_system": "Esta ação parece ter quebrado estes serviços importantes: {services}",
"already_up_to_date": "Nada a ser feito. Tudo já está atualizado.",
"additional_urls_already_removed": "A URL adicional '{url}'já está removida para a permissão '{permission}'",
"additional_urls_already_added": "A URL adicional '{url}' já está adicionada para a permissão '{permission}'"
} }

View file

@ -226,7 +226,6 @@
"service_description_fail2ban": "防止来自互联网的暴力攻击和其他类型的攻击", "service_description_fail2ban": "防止来自互联网的暴力攻击和其他类型的攻击",
"service_description_dovecot": "允许电子邮件客户端访问/获取电子邮件通过IMAP和POP3", "service_description_dovecot": "允许电子邮件客户端访问/获取电子邮件通过IMAP和POP3",
"service_description_dnsmasq": "处理域名解析DNS", "service_description_dnsmasq": "处理域名解析DNS",
"service_description_avahi-daemon": "允许您使用本地网络中的“ yunohost.local”访问服务器",
"service_started": "服务 '{service}' 已启动", "service_started": "服务 '{service}' 已启动",
"service_start_failed": "无法启动服务 '{service}'\n\n最近的服务日志:{logs}", "service_start_failed": "无法启动服务 '{service}'\n\n最近的服务日志:{logs}",
"service_reloaded_or_restarted": "服务'{service}'已重新加载或重新启动", "service_reloaded_or_restarted": "服务'{service}'已重新加载或重新启动",

View file

@ -502,7 +502,7 @@ def app_change_url(operation_logger, app, domain, path):
hook_callback("post_app_change_url", env=env_dict) hook_callback("post_app_change_url", env=env_dict)
def app_upgrade(app=[], url=None, file=None, force=False): def app_upgrade(app=[], url=None, file=None, force=False, no_safety_backup=False):
""" """
Upgrade app Upgrade app
@ -510,6 +510,7 @@ def app_upgrade(app=[], url=None, file=None, force=False):
file -- Folder or tarball for upgrade file -- Folder or tarball for upgrade
app -- App(s) to upgrade (default all) app -- App(s) to upgrade (default all)
url -- Git url to fetch for upgrade url -- Git url to fetch for upgrade
no_safety_backup -- Disable the safety backup during upgrade
""" """
from packaging import version from packaging import version
@ -618,6 +619,7 @@ def app_upgrade(app=[], url=None, file=None, force=False):
env_dict["YNH_APP_UPGRADE_TYPE"] = upgrade_type env_dict["YNH_APP_UPGRADE_TYPE"] = upgrade_type
env_dict["YNH_APP_MANIFEST_VERSION"] = str(app_new_version) env_dict["YNH_APP_MANIFEST_VERSION"] = str(app_new_version)
env_dict["YNH_APP_CURRENT_VERSION"] = str(app_current_version) env_dict["YNH_APP_CURRENT_VERSION"] = str(app_current_version)
env_dict["NO_BACKUP_UPGRADE"] = "1" if no_safety_backup else "0"
# We'll check that the app didn't brutally edit some system configuration # We'll check that the app didn't brutally edit some system configuration
manually_modified_files_before_install = manually_modified_files() manually_modified_files_before_install = manually_modified_files()
@ -885,7 +887,7 @@ def app_install(
raise YunohostValidationError("disk_space_not_sufficient_install") raise YunohostValidationError("disk_space_not_sufficient_install")
# Check ID # Check ID
if "id" not in manifest or "__" in manifest["id"]: if "id" not in manifest or "__" in manifest["id"] or "." in manifest["id"]:
raise YunohostValidationError("app_id_invalid") raise YunohostValidationError("app_id_invalid")
app_id = manifest["id"] app_id = manifest["id"]
@ -1187,12 +1189,13 @@ def dump_app_log_extract_for_debugging(operation_logger):
@is_unit_operation() @is_unit_operation()
def app_remove(operation_logger, app): def app_remove(operation_logger, app, purge=False):
""" """
Remove app Remove app
Keyword argument: Keyword arguments:
app -- App(s) to delete app -- App(s) to delete
purge -- Remove with all app data
""" """
from yunohost.hook import hook_exec, hook_remove, hook_callback from yunohost.hook import hook_exec, hook_remove, hook_callback
@ -1230,6 +1233,7 @@ def app_remove(operation_logger, app):
env_dict["YNH_APP_INSTANCE_NAME"] = app env_dict["YNH_APP_INSTANCE_NAME"] = app
env_dict["YNH_APP_INSTANCE_NUMBER"] = str(app_instance_nb) env_dict["YNH_APP_INSTANCE_NUMBER"] = str(app_instance_nb)
env_dict["YNH_APP_MANIFEST_VERSION"] = manifest.get("version", "?") env_dict["YNH_APP_MANIFEST_VERSION"] = manifest.get("version", "?")
env_dict["YNH_APP_PURGE"] = str(purge)
operation_logger.extra.update({"env": env_dict}) operation_logger.extra.update({"env": env_dict})
operation_logger.flush() operation_logger.flush()
@ -1518,7 +1522,7 @@ def app_setting(app, key, value=None, delete=False):
# SET # SET
else: else:
if key in ["redirected_urls", "redirected_regex"]: if key in ["redirected_urls", "redirected_regex"]:
value = yaml.load(value) value = yaml.safe_load(value)
app_settings[key] = value app_settings[key] = value
_set_app_settings(app, app_settings) _set_app_settings(app, app_settings)
@ -2175,7 +2179,7 @@ def _get_app_settings(app_id):
) )
try: try:
with open(os.path.join(APPS_SETTING_PATH, app_id, "settings.yml")) as f: with open(os.path.join(APPS_SETTING_PATH, app_id, "settings.yml")) as f:
settings = yaml.load(f) settings = yaml.safe_load(f)
# If label contains unicode char, this may later trigger issues when building strings... # If label contains unicode char, this may later trigger issues when building strings...
# FIXME: this should be propagated to read_yaml so that this fix applies everywhere I think... # FIXME: this should be propagated to read_yaml so that this fix applies everywhere I think...
settings = {k: v for k, v in settings.items()} settings = {k: v for k, v in settings.items()}

View file

@ -166,7 +166,9 @@ def domain_add(operation_logger, domain, dyndns=False):
# because it's one of the major service, but in the long term we # because it's one of the major service, but in the long term we
# should identify the root of this bug... # should identify the root of this bug...
_force_clear_hashes(["/etc/nginx/conf.d/%s.conf" % domain]) _force_clear_hashes(["/etc/nginx/conf.d/%s.conf" % domain])
regen_conf(names=["nginx", "metronome", "dnsmasq", "postfix", "rspamd"]) regen_conf(
names=["nginx", "metronome", "dnsmasq", "postfix", "rspamd", "mdns"]
)
app_ssowatconf() app_ssowatconf()
except Exception as e: except Exception as e:
@ -293,7 +295,7 @@ def domain_remove(operation_logger, domain, remove_apps=False, force=False):
"/etc/nginx/conf.d/%s.conf" % domain, new_conf=None, save=True "/etc/nginx/conf.d/%s.conf" % domain, new_conf=None, save=True
) )
regen_conf(names=["nginx", "metronome", "dnsmasq", "postfix"]) regen_conf(names=["nginx", "metronome", "dnsmasq", "postfix", "rspamd", "mdns"])
app_ssowatconf() app_ssowatconf()
hook_callback("post_domain_remove", args=[domain]) hook_callback("post_domain_remove", args=[domain])

View file

@ -179,7 +179,7 @@ def firewall_list(raw=False, by_ip_version=False, list_forwarded=False):
""" """
with open(FIREWALL_FILE) as f: with open(FIREWALL_FILE) as f:
firewall = yaml.load(f) firewall = yaml.safe_load(f)
if raw: if raw:
return firewall return firewall

View file

@ -444,7 +444,7 @@ def _get_regenconf_infos():
""" """
try: try:
with open(REGEN_CONF_FILE, "r") as f: with open(REGEN_CONF_FILE, "r") as f:
return yaml.load(f) return yaml.safe_load(f)
except Exception: except Exception:
return {} return {}

View file

@ -670,7 +670,7 @@ def _get_services():
""" """
try: try:
with open("/etc/yunohost/services.yml", "r") as f: with open("/etc/yunohost/services.yml", "r") as f:
services = yaml.load(f) or {} services = yaml.safe_load(f) or {}
except Exception: except Exception:
return {} return {}

View file

@ -2,4 +2,4 @@ import yaml
def test_yaml_syntax(): def test_yaml_syntax():
yaml.load(open("data/actionsmap/yunohost.yml")) yaml.safe_load(open("data/actionsmap/yunohost.yml"))

View file

@ -108,7 +108,7 @@ def find_expected_string_keys():
yield m yield m
# Keys for the actionmap ... # Keys for the actionmap ...
for category in yaml.load(open("data/actionsmap/yunohost.yml")).values(): for category in yaml.safe_load(open("data/actionsmap/yunohost.yml")).values():
if "actions" not in category.keys(): if "actions" not in category.keys():
continue continue
for action in category["actions"].values(): for action in category["actions"].values():