From 7026a8cfd5cbc413cea9805298fafebf828f1366 Mon Sep 17 00:00:00 2001 From: Krakinou Date: Sat, 12 Jun 2021 16:49:05 +0200 Subject: [PATCH 01/55] Check home folder before creating multimedia directory --- data/helpers.d/multimedia | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/data/helpers.d/multimedia b/data/helpers.d/multimedia index 2d43c2540..c86153e85 100644 --- a/data/helpers.d/multimedia +++ b/data/helpers.d/multimedia @@ -31,7 +31,10 @@ ynh_multimedia_build_main_dir() { mkdir -p "$MEDIA_DIRECTORY/$user/eBook" ln -sfn "$MEDIA_DIRECTORY/share" "$MEDIA_DIRECTORY/$user/Share" # 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 + if [[ -d "$(getent passwd $user | cut -d: -f6)" && "$(getent passwd $user | cut -d: -f6 | grep home)" ]]; then + ln -sfn "$MEDIA_DIRECTORY/$user" "/home/$user/Multimedia" + fi # Propriétaires des dossiers utilisateurs. chown -R $user "$MEDIA_DIRECTORY/$user" done From 9c23f4390550a1c0161880ee0d9bbad6d62a6e90 Mon Sep 17 00:00:00 2001 From: Krakinou Date: Mon, 14 Jun 2021 23:28:31 +0200 Subject: [PATCH 02/55] check if home exists --- data/helpers.d/multimedia | 5 +++-- data/hooks/post_user_create/ynh_multimedia | 6 +++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/data/helpers.d/multimedia b/data/helpers.d/multimedia index c86153e85..a07f5fdfd 100644 --- a/data/helpers.d/multimedia +++ b/data/helpers.d/multimedia @@ -32,8 +32,9 @@ ynh_multimedia_build_main_dir() { ln -sfn "$MEDIA_DIRECTORY/share" "$MEDIA_DIRECTORY/$user/Share" # Création du lien symbolique dans le home de l'utilisateur. #link will only be created if the home directory of the user exists and if it's located in '/home' folder - if [[ -d "$(getent passwd $user | cut -d: -f6)" && "$(getent passwd $user | cut -d: -f6 | grep home)" ]]; then - ln -sfn "$MEDIA_DIRECTORY/$user" "/home/$user/Multimedia" + home="$(getent passwd $user | cut -d: -f6)" + if [[ -d "$home" && "$(echo "$home" | grep home)" ]]; then + ln -sfn "$MEDIA_DIRECTORY/$user" "$home/Multimedia" fi # Propriétaires des dossiers utilisateurs. chown -R $user "$MEDIA_DIRECTORY/$user" diff --git a/data/hooks/post_user_create/ynh_multimedia b/data/hooks/post_user_create/ynh_multimedia index 441212bbc..aa5ab48d3 100644 --- a/data/hooks/post_user_create/ynh_multimedia +++ b/data/hooks/post_user_create/ynh_multimedia @@ -15,7 +15,11 @@ mkdir -p "$MEDIA_DIRECTORY/$user/Video" mkdir -p "$MEDIA_DIRECTORY/$user/eBook" ln -sfn "$MEDIA_DIRECTORY/share" "$MEDIA_DIRECTORY/$user/Share" # 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 +home="$(getent passwd $user | cut -d: -f6)" +if [[ -d "$home" && "$(echo "$home" | grep home)" ]]; then + ln -sfn "$MEDIA_DIRECTORY/$user" "$home/Multimedia" +fi # Propriétaires des dossiers utilisateurs. chown -R $user "$MEDIA_DIRECTORY/$user" From 29db3d51fff28e1c9bf1a2e129e1fcb1353d2c5b Mon Sep 17 00:00:00 2001 From: Krakinou Date: Mon, 14 Jun 2021 23:37:30 +0200 Subject: [PATCH 03/55] grep full /home/ --- data/helpers.d/multimedia | 2 +- data/hooks/post_user_create/ynh_multimedia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/data/helpers.d/multimedia b/data/helpers.d/multimedia index a07f5fdfd..4ec7611fc 100644 --- a/data/helpers.d/multimedia +++ b/data/helpers.d/multimedia @@ -33,7 +33,7 @@ ynh_multimedia_build_main_dir() { # Création du lien symbolique dans le home de l'utilisateur. #link will only be created if the home directory of the user exists and if it's located in '/home' folder home="$(getent passwd $user | cut -d: -f6)" - if [[ -d "$home" && "$(echo "$home" | grep home)" ]]; then + if [[ -d "$home" && "$(echo "$home" | grep /home/)" ]]; then ln -sfn "$MEDIA_DIRECTORY/$user" "$home/Multimedia" fi # Propriétaires des dossiers utilisateurs. diff --git a/data/hooks/post_user_create/ynh_multimedia b/data/hooks/post_user_create/ynh_multimedia index aa5ab48d3..2fa02505a 100644 --- a/data/hooks/post_user_create/ynh_multimedia +++ b/data/hooks/post_user_create/ynh_multimedia @@ -17,7 +17,7 @@ ln -sfn "$MEDIA_DIRECTORY/share" "$MEDIA_DIRECTORY/$user/Share" # Création du lien symbolique dans le home de l'utilisateur. #link will only be created if the home directory of the user exists and if it's located in '/home' folder home="$(getent passwd $user | cut -d: -f6)" -if [[ -d "$home" && "$(echo "$home" | grep home)" ]]; then +if [[ -d "$home" && "$(echo "$home" | grep /home/)" ]]; then ln -sfn "$MEDIA_DIRECTORY/$user" "$home/Multimedia" fi # Propriétaires des dossiers utilisateurs. From 7c92b44ddb19b3c712f78b898e11a5fadc9b7092 Mon Sep 17 00:00:00 2001 From: tituspijean Date: Mon, 5 Jul 2021 21:24:00 +0000 Subject: [PATCH 04/55] Add mdns.py for mDNS broadcast --- data/other/mdns.py | 94 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 data/other/mdns.py diff --git a/data/other/mdns.py b/data/other/mdns.py new file mode 100644 index 000000000..144742758 --- /dev/null +++ b/data/other/mdns.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python3 + +""" +WIP +Pythonic declaration of mDNS .local domains. +Heavily based off https://github.com/jstasiak/python-zeroconf/blob/master/tests/test_asyncio.py +""" + +import os +import sys +import argparse + +import asyncio +import logging +import socket +import time +from typing import List + +sys.path.insert(0, "/usr/lib/moulinette/") +from yunohost.domain import domain_list + +from zeroconf import IPVersion +from zeroconf.asyncio import AsyncServiceInfo, AsyncZeroconf + +# TODO: Remove traceback beautification +from rich.traceback import install +install(show_locals=True) + +async def register_services(infos: List[AsyncServiceInfo]) -> None: + tasks = [aiozc.async_register_service(info) for info in infos] + background_tasks = await asyncio.gather(*tasks) + await asyncio.gather(*background_tasks) + + +async def unregister_services(infos: List[AsyncServiceInfo]) -> None: + tasks = [aiozc.async_unregister_service(info) for info in infos] + background_tasks = await asyncio.gather(*tasks) + await asyncio.gather(*background_tasks) + + +async def close_aiozc(aiozc: AsyncZeroconf) -> None: + await aiozc.async_close() + + +if __name__ == '__main__': + logging.basicConfig(level=logging.DEBUG) + + local_domains = [ d for d in domain_list()['domains'] if d.endswith('.local') ] + + parser = argparse.ArgumentParser() + parser.add_argument('--debug', action='store_true') + version_group = parser.add_mutually_exclusive_group() + version_group.add_argument('--v6', action='store_true') + version_group.add_argument('--v6-only', action='store_true') + args = parser.parse_args() + + if args.debug: + logging.getLogger('zeroconf').setLevel(logging.DEBUG) + if args.v6: + ip_version = IPVersion.All + elif args.v6_only: + ip_version = IPVersion.V6Only + else: + ip_version = IPVersion.V4Only + + infos = [] + for d in local_domains: + d_domain=d.replace('.local','') + infos.append( + AsyncServiceInfo( + type_="_device-info._tcp.local.", + name=d_domain+f"._device-info._tcp.local.", + addresses=[socket.inet_aton("127.0.0.1")], + port=80, + server=d, + ) + ) + + print("Registration of .local domains, press Ctrl-C to exit...") + aiozc = AsyncZeroconf(ip_version=ip_version) + loop = asyncio.get_event_loop() + loop.run_until_complete(register_services(infos)) + print("Registration complete.") + try: + while True: + time.sleep(0.1) + except KeyboardInterrupt: + pass + finally: + print("Unregistering...") + loop.run_until_complete(unregister_services(infos)) + print("Unregistration complete.") + loop.run_until_complete(close_aiozc(aiozc)) + From 99390f23133f41b21a2665dbccbb417bbdc46413 Mon Sep 17 00:00:00 2001 From: tituspijean Date: Mon, 5 Jul 2021 23:01:19 +0000 Subject: [PATCH 05/55] PoC for mDNS broadcast --- data/other/mdns.py | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/data/other/mdns.py b/data/other/mdns.py index 144742758..2146caec0 100644 --- a/data/other/mdns.py +++ b/data/other/mdns.py @@ -2,8 +2,8 @@ """ WIP -Pythonic declaration of mDNS .local domains. -Heavily based off https://github.com/jstasiak/python-zeroconf/blob/master/tests/test_asyncio.py +Pythonic declaration of mDNS .local domains for YunoHost +Based off https://github.com/jstasiak/python-zeroconf/blob/master/tests/test_asyncio.py """ import os @@ -18,6 +18,7 @@ from typing import List sys.path.insert(0, "/usr/lib/moulinette/") from yunohost.domain import domain_list +from yunohost.utils.network import get_network_interfaces from zeroconf import IPVersion from zeroconf.asyncio import AsyncServiceInfo, AsyncZeroconf @@ -47,21 +48,26 @@ if __name__ == '__main__': local_domains = [ d for d in domain_list()['domains'] if d.endswith('.local') ] + # TODO: Create setting to list interfaces + wanted_interfaces = [ 'zt3jnskpna' ] + interfaces = get_network_interfaces() + ips = [] + for i in wanted_interfaces: + try: + ips.append(socket.inet_pton(socket.AF_INET, interfaces[i]['ipv4'].split('/')[0])) + except: + pass + try: + ips.append(socket.inet_pton(socket.AF_INET6, interfaces[i]['ipv6'].split('/')[0])) + except: + pass + parser = argparse.ArgumentParser() parser.add_argument('--debug', action='store_true') - version_group = parser.add_mutually_exclusive_group() - version_group.add_argument('--v6', action='store_true') - version_group.add_argument('--v6-only', action='store_true') args = parser.parse_args() if args.debug: logging.getLogger('zeroconf').setLevel(logging.DEBUG) - if args.v6: - ip_version = IPVersion.All - elif args.v6_only: - ip_version = IPVersion.V6Only - else: - ip_version = IPVersion.V4Only infos = [] for d in local_domains: @@ -70,14 +76,14 @@ if __name__ == '__main__': AsyncServiceInfo( type_="_device-info._tcp.local.", name=d_domain+f"._device-info._tcp.local.", - addresses=[socket.inet_aton("127.0.0.1")], + addresses=ips, port=80, - server=d, + server=d+'.', ) ) print("Registration of .local domains, press Ctrl-C to exit...") - aiozc = AsyncZeroconf(ip_version=ip_version) + aiozc = AsyncZeroconf() loop = asyncio.get_event_loop() loop.run_until_complete(register_services(infos)) print("Registration complete.") From 654690b42749ea0ee022136f601ccc8c171e13e6 Mon Sep 17 00:00:00 2001 From: tituspijean Date: Tue, 6 Jul 2021 10:48:39 +0000 Subject: [PATCH 06/55] Add interfaces selection for mDNS broadcast - System setting added - Loop through list of interfaces --- data/other/mdns.py | 106 +++++++++++++++++++++++---------------- locales/en.json | 1 + src/yunohost/settings.py | 1 + 3 files changed, 65 insertions(+), 43 deletions(-) diff --git a/data/other/mdns.py b/data/other/mdns.py index 2146caec0..0e249e7b8 100644 --- a/data/other/mdns.py +++ b/data/other/mdns.py @@ -19,26 +19,23 @@ from typing import List sys.path.insert(0, "/usr/lib/moulinette/") from yunohost.domain import domain_list from yunohost.utils.network import get_network_interfaces +from yunohost.settings import settings_get +from moulinette import m18n +from moulinette.interfaces.cli import get_locale -from zeroconf import IPVersion from zeroconf.asyncio import AsyncServiceInfo, AsyncZeroconf -# TODO: Remove traceback beautification -from rich.traceback import install -install(show_locals=True) -async def register_services(infos: List[AsyncServiceInfo]) -> None: +async def register_services(aiozc: AsyncZeroconf, infos: List[AsyncServiceInfo]) -> None: tasks = [aiozc.async_register_service(info) for info in infos] background_tasks = await asyncio.gather(*tasks) await asyncio.gather(*background_tasks) - -async def unregister_services(infos: List[AsyncServiceInfo]) -> None: +async def unregister_services(aiozc: AsyncZeroconf, infos: List[AsyncServiceInfo]) -> None: tasks = [aiozc.async_unregister_service(info) for info in infos] background_tasks = await asyncio.gather(*tasks) await asyncio.gather(*background_tasks) - async def close_aiozc(aiozc: AsyncZeroconf) -> None: await aiozc.async_close() @@ -46,22 +43,6 @@ async def close_aiozc(aiozc: AsyncZeroconf) -> None: if __name__ == '__main__': logging.basicConfig(level=logging.DEBUG) - local_domains = [ d for d in domain_list()['domains'] if d.endswith('.local') ] - - # TODO: Create setting to list interfaces - wanted_interfaces = [ 'zt3jnskpna' ] - interfaces = get_network_interfaces() - ips = [] - for i in wanted_interfaces: - try: - ips.append(socket.inet_pton(socket.AF_INET, interfaces[i]['ipv4'].split('/')[0])) - except: - pass - try: - ips.append(socket.inet_pton(socket.AF_INET6, interfaces[i]['ipv6'].split('/')[0])) - except: - pass - parser = argparse.ArgumentParser() parser.add_argument('--debug', action='store_true') args = parser.parse_args() @@ -69,24 +50,62 @@ if __name__ == '__main__': if args.debug: logging.getLogger('zeroconf').setLevel(logging.DEBUG) - infos = [] - for d in local_domains: - d_domain=d.replace('.local','') - infos.append( - AsyncServiceInfo( - type_="_device-info._tcp.local.", - name=d_domain+f"._device-info._tcp.local.", - addresses=ips, - port=80, - server=d+'.', - ) - ) - print("Registration of .local domains, press Ctrl-C to exit...") - aiozc = AsyncZeroconf() - loop = asyncio.get_event_loop() - loop.run_until_complete(register_services(infos)) - print("Registration complete.") + local_domains = [ d for d in domain_list()['domains'] if d.endswith('.local') ] + + m18n.load_namespace("yunohost") + m18n.set_locale(get_locale()) + + if settings_get('mdns.interfaces'): + wanted_interfaces = settings_get('mdns.interfaces').split() + else: + wanted_interfaces = [] + print('No interface listed for broadcast.') + + aiozcs = [] + interfaces = get_network_interfaces() + for interface in wanted_interfaces: + infos = [] + ips = [] # Human-readable IPs + b_ips = [] # Binary-convered IPs + + # Parse the IPs and prepare their binary version + try: + ip = interfaces[interface]['ipv4'].split('/')[0] + ips.append(ip) + b_ips.append(socket.inet_pton(socket.AF_INET, ip)) + except: + pass + try: + ip = interfaces[interface]['ipv6'].split('/')[0] + ips.append(ip) + b_ips.append(socket.inet_pton(socket.AF_INET6, ip)) + except: + pass + + # Create a ServiceInfo object for each .local domain + for d in local_domains: + d_domain=d.replace('.local','') + infos.append( + AsyncServiceInfo( + type_="_device-info._tcp.local.", + name=d_domain+f"._device-info._tcp.local.", + addresses=b_ips, + port=80, + server=d+'.', + ) + ) + print('Adding '+d+' with addresses '+str(ips)+' on interface '+interface) + + # Create an AsyncZeroconf object, store it, and start Service registration + aiozc = AsyncZeroconf(interfaces=ips) + aiozcs.append(aiozc) + print("Registration on interface "+interface+"...") + loop = asyncio.get_event_loop() + loop.run_until_complete(register_services(aiozc, infos)) + + # We are done looping among the interfaces + print("Registration complete. Press Ctrl-c to exit...") try: while True: time.sleep(0.1) @@ -94,7 +113,8 @@ if __name__ == '__main__': pass finally: print("Unregistering...") - loop.run_until_complete(unregister_services(infos)) + for aiozc in aiozcs: + loop.run_until_complete(unregister_services(aiozc, infos)) + loop.run_until_complete(close_aiozc(aiozc)) print("Unregistration complete.") - loop.run_until_complete(close_aiozc(aiozc)) diff --git a/locales/en.json b/locales/en.json index 84a01dfaa..70a0e9309 100644 --- a/locales/en.json +++ b/locales/en.json @@ -321,6 +321,7 @@ "global_settings_cant_write_settings": "Could not save settings file, reason: {reason:s}", "global_settings_key_doesnt_exists": "The key '{settings_key:s}' does not exist in the global settings, you can see all the available keys by running 'yunohost settings list'", "global_settings_reset_success": "Previous settings now backed up to {path:s}", + "global_settings_setting_mdns_interfaces": "Space-separated list of interfaces for mDNS broadcast. Leave empty to disable mDNS.", "global_settings_setting_pop3_enabled": "Enable the POP3 protocol for the mail server", "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", diff --git a/src/yunohost/settings.py b/src/yunohost/settings.py index 0466d8126..36904ee70 100644 --- a/src/yunohost/settings.py +++ b/src/yunohost/settings.py @@ -100,6 +100,7 @@ DEFAULTS = OrderedDict( ("smtp.relay.password", {"type": "string", "default": ""}), ("backup.compress_tar_archives", {"type": "bool", "default": False}), ("ssowat.panel_overlay.enabled", {"type": "bool", "default": True}), + ("mdns.interfaces", {"type": "string", "default": ""}), ] ) From 9e93efa895ae6c3a7013c47adeb2891bdf3c8a3f Mon Sep 17 00:00:00 2001 From: tituspijean Date: Tue, 6 Jul 2021 20:33:23 +0000 Subject: [PATCH 07/55] Move mDNS script to yunomdns --- data/other/mdns.py => bin/yunomdns | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename data/other/mdns.py => bin/yunomdns (100%) mode change 100644 => 100755 diff --git a/data/other/mdns.py b/bin/yunomdns old mode 100644 new mode 100755 similarity index 100% rename from data/other/mdns.py rename to bin/yunomdns From 99aacd8b51ade29f5f153cde3808f55706c15bf6 Mon Sep 17 00:00:00 2001 From: tituspijean Date: Sun, 11 Jul 2021 14:23:41 +0000 Subject: [PATCH 08/55] Do not rely on Moulinette, integration with Yunohost of mDNS broadcast --- bin/yunomdns | 269 +++++++++++++++++++++------ data/hooks/conf_regen/01-yunohost | 5 +- data/other/yunomdns.service | 13 ++ data/templates/yunohost/mdns.yml | 4 + data/templates/yunohost/services.yml | 2 + debian/install | 1 + debian/postinst | 4 + 7 files changed, 244 insertions(+), 54 deletions(-) create mode 100644 data/other/yunomdns.service create mode 100644 data/templates/yunohost/mdns.yml diff --git a/bin/yunomdns b/bin/yunomdns index 0e249e7b8..795481dfa 100755 --- a/bin/yunomdns +++ b/bin/yunomdns @@ -6,115 +6,278 @@ Pythonic declaration of mDNS .local domains for YunoHost Based off https://github.com/jstasiak/python-zeroconf/blob/master/tests/test_asyncio.py """ +import subprocess import os +import re import sys import argparse +import yaml import asyncio import logging import socket import time -from typing import List - -sys.path.insert(0, "/usr/lib/moulinette/") -from yunohost.domain import domain_list -from yunohost.utils.network import get_network_interfaces -from yunohost.settings import settings_get -from moulinette import m18n -from moulinette.interfaces.cli import get_locale +from typing import List, Dict +from zeroconf import DNSEntry, DNSRecord from zeroconf.asyncio import AsyncServiceInfo, AsyncZeroconf +# 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() + ) -async def register_services(aiozc: AsyncZeroconf, infos: List[AsyncServiceInfo]) -> None: - tasks = [aiozc.async_register_service(info) for info in infos] +# 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 addr show") + for d in re.split(r"^(?:[0-9]+: )", output, flags=re.MULTILINE): + # Extract device name (1) and its addresses (2) + m = re.match(r"([^\s@]+)(?:@[\S]+)?: (.*)", d, flags=re.DOTALL) + if m: + devices_raw[m.group(1)] = m.group(2) + + # Parse relevant informations for each of them + devices = { + name: _extract_inet(addrs) + for name, addrs in devices_raw.items() + if name != "lo" + } + + return devices + +# async commands +async def register_services(aiozcs: Dict[AsyncZeroconf, List[AsyncServiceInfo]]) -> None: + tasks = [] + for aiozc, infos in aiozcs.items(): + for info in infos: + tasks.append(aiozc.async_register_service(info)) background_tasks = await asyncio.gather(*tasks) await asyncio.gather(*background_tasks) -async def unregister_services(aiozc: AsyncZeroconf, infos: List[AsyncServiceInfo]) -> None: - tasks = [aiozc.async_unregister_service(info) for info in infos] +async def unregister_services(aiozcs: Dict[AsyncZeroconf, List[AsyncServiceInfo]]) -> None: + for aiozc, infos in aiozcs.items(): + for info in infos: + tasks.append(aiozc.async_unregister_service(info)) background_tasks = await asyncio.gather(*tasks) await asyncio.gather(*background_tasks) -async def close_aiozc(aiozc: AsyncZeroconf) -> None: - await aiozc.async_close() +async def close_aiozcs(aiozcs: Dict[AsyncZeroconf, List[AsyncServiceInfo]]) -> None: + tasks = [] + for aiozc in aiozcs: + tasks.append(aiozc.async_close()) + background_tasks = await asyncio.gather(*tasks) + await asyncio.gather(*background_tasks) if __name__ == '__main__': logging.basicConfig(level=logging.DEBUG) - parser = argparse.ArgumentParser() + + ### + # ARGUMENTS + ### + + parser = argparse.ArgumentParser(description=''' + mDNS broadcast for .local domains. + Configuration file: /etc/yunohost/mdns.yml + Subdomains are not supported. + ''') parser.add_argument('--debug', action='store_true') + parser.add_argument('--regen', nargs='?', const='as_stored', choices=['domains', 'interfaces', 'all', 'as_stored'], + help=''' + Regenerates selection into the configuration file then starts mDNS broadcasting. + ''') + parser.add_argument('--set-regen', choices=['domains', 'interfaces', 'all', 'none'], + help=''' + Set which part of the configuration to be regenerated. + Implies --regen as_stored, with newly stored parameter. + ''') + able = parser.add_mutually_exclusive_group() + able.add_argument('--enable', action='store_true', help='Enables mDNS broadcast, and regenerates the configuration') + able.add_argument('--disable', action='store_true') args = parser.parse_args() if args.debug: logging.getLogger('zeroconf').setLevel(logging.DEBUG) - - - local_domains = [ d for d in domain_list()['domains'] if d.endswith('.local') ] - - m18n.load_namespace("yunohost") - m18n.set_locale(get_locale()) - - if settings_get('mdns.interfaces'): - wanted_interfaces = settings_get('mdns.interfaces').split() + logging.getLogger('asyncio').setLevel(logging.DEBUG) else: - wanted_interfaces = [] - print('No interface listed for broadcast.') + logging.getLogger('zeroconf').setLevel(logging.WARNING) + logging.getLogger('asyncio').setLevel(logging.WARNING) - aiozcs = [] + ### + # CONFIG + ### + + with open('/etc/yunohost/mdns.yml', 'r') as f: + config = yaml.load(f) or {} + updated = False + + if args.enable: + config['enabled'] = True + args.regen = 'as_stored' + updated = True + + if args.disable: + config['enabled'] = False + updated = True + + if args.set_regen: + config['regen'] = args.set_regen + args.regen = 'as_stored' + updated = True + + if args.regen: + if args.regen == 'as_stored': + r = config['regen'] + else: + r = args.regen + if r == 'none': + print('Regeneration disabled.') + if r == 'interfaces' or r == 'all': + config['interfaces'] = [ i for i in get_network_interfaces() ] + print('Regenerated interfaces list: ' + str(config['interfaces'])) + if r == 'domains' or r == 'all': + import glob + config['domains'] = [ d.rsplit('/',1)[1][:-2] for d in glob.glob('/etc/nginx/conf.d/*.local.d') ] + print('Regenerated domains list: ' + str(config['domains'])) + updated = True + + if updated: + with open('/etc/yunohost/mdns.yml', 'w') as f: + yaml.safe_dump(config, f, default_flow_style=False) + print('Configuration file updated.') + + ### + # MAIN SCRIPT + ### + + if config['enabled'] is not True: + print('YunomDNS is disabled.') + sys.exit(0) + + if config['interfaces'] is None: + print('No interface listed for broadcast.') + sys.exit(0) + + aiozcs = {} + tasks = [] + loop = asyncio.get_event_loop() interfaces = get_network_interfaces() - for interface in wanted_interfaces: - infos = [] + for interface in config['interfaces']: + infos = [] # List of ServiceInfo objects, to feed Zeroconf ips = [] # Human-readable IPs b_ips = [] # Binary-convered IPs # Parse the IPs and prepare their binary version + addressed = False try: ip = interfaces[interface]['ipv4'].split('/')[0] + if len(ip)>0: addressed = True ips.append(ip) b_ips.append(socket.inet_pton(socket.AF_INET, ip)) except: pass try: ip = interfaces[interface]['ipv6'].split('/')[0] + if len(ip)>0: addressed = True ips.append(ip) b_ips.append(socket.inet_pton(socket.AF_INET6, ip)) except: pass - # Create a ServiceInfo object for each .local domain - for d in local_domains: - d_domain=d.replace('.local','') - infos.append( - AsyncServiceInfo( - type_="_device-info._tcp.local.", - name=d_domain+f"._device-info._tcp.local.", - addresses=b_ips, - port=80, - server=d+'.', + # If at least one IP is listed + if addressed: + # Create a ServiceInfo object for each .local domain + for d in config['domains']: + d_domain=d.replace('.local','') + infos.append( + AsyncServiceInfo( + type_='_device-info._tcp.local.', + name=d_domain+'._device-info._tcp.local.', + addresses=b_ips, + port=80, + server=d+'.', + ) ) - ) - print('Adding '+d+' with addresses '+str(ips)+' on interface '+interface) + infos.append( + AsyncServiceInfo( + type_='_http._tcp.local.', + name=d_domain+'._http._tcp.local.', + addresses=b_ips, + port=80, + server=d+'.', + ) + ) + print('Adding '+d+' with addresses '+str(ips)+' on interface '+interface) + # Create an AsyncZeroconf object, and store registration task + aiozc = AsyncZeroconf(interfaces=ips) + aiozcs[aiozc]=infos - # Create an AsyncZeroconf object, store it, and start Service registration - aiozc = AsyncZeroconf(interfaces=ips) - aiozcs.append(aiozc) - print("Registration on interface "+interface+"...") - loop = asyncio.get_event_loop() - loop.run_until_complete(register_services(aiozc, infos)) + # Run registration + loop.run_until_complete(register_services(aiozcs)) + print("Registration complete. Press Ctrl-c or stop service to exit...") - # We are done looping among the interfaces - print("Registration complete. Press Ctrl-c to exit...") try: while True: - time.sleep(0.1) + time.sleep(1) except KeyboardInterrupt: pass finally: print("Unregistering...") - for aiozc in aiozcs: - loop.run_until_complete(unregister_services(aiozc, infos)) - loop.run_until_complete(close_aiozc(aiozc)) + loop.run_until_complete(unregister_services(aiozcs)) print("Unregistration complete.") + loop.run_until_complete(close_aiozcs(aiozcs)) diff --git a/data/hooks/conf_regen/01-yunohost b/data/hooks/conf_regen/01-yunohost index 3d65d34cd..d160b9e66 100755 --- a/data/hooks/conf_regen/01-yunohost +++ b/data/hooks/conf_regen/01-yunohost @@ -3,6 +3,7 @@ set -e services_path="/etc/yunohost/services.yml" +mdns_path="/etc/yunohost/mdns.yml" do_init_regen() { if [[ $EUID -ne 0 ]]; then @@ -18,9 +19,11 @@ do_init_regen() { [[ -f /etc/yunohost/current_host ]] \ || echo "yunohost.org" > /etc/yunohost/current_host - # copy default services and firewall + # copy default services, mdns, and firewall [[ -f $services_path ]] \ || cp services.yml "$services_path" + [[ -f $mdns_path ]] \ + || cp mdns.yml "$mdns_path" [[ -f /etc/yunohost/firewall.yml ]] \ || cp firewall.yml /etc/yunohost/firewall.yml diff --git a/data/other/yunomdns.service b/data/other/yunomdns.service new file mode 100644 index 000000000..36d938035 --- /dev/null +++ b/data/other/yunomdns.service @@ -0,0 +1,13 @@ +[Unit] +Description=YunoHost mDNS service +After=network.target + +[Service] +User=avahi +Group=avahi +Type=simple +ExecStart=/usr/bin/yunomdns +StandardOutput=syslog + +[Install] +WantedBy=default.target diff --git a/data/templates/yunohost/mdns.yml b/data/templates/yunohost/mdns.yml new file mode 100644 index 000000000..3ed9e792b --- /dev/null +++ b/data/templates/yunohost/mdns.yml @@ -0,0 +1,4 @@ +enabled: True +regen: all +interfaces: +domains: diff --git a/data/templates/yunohost/services.yml b/data/templates/yunohost/services.yml index 7df563c67..b961d274e 100644 --- a/data/templates/yunohost/services.yml +++ b/data/templates/yunohost/services.yml @@ -52,6 +52,8 @@ yunohost-firewall: need_lock: true test_status: iptables -S | grep "^-A INPUT" | grep " --dport" | grep -q ACCEPT category: security +yunomdns: + needs_exposed_ports: [5353] glances: null nsswitch: null ssl: null diff --git a/debian/install b/debian/install index 1691a4849..e30a69a8b 100644 --- a/debian/install +++ b/debian/install @@ -5,6 +5,7 @@ doc/yunohost.8.gz /usr/share/man/man8/ data/actionsmap/* /usr/share/moulinette/actionsmap/ data/hooks/* /usr/share/yunohost/hooks/ data/other/yunoprompt.service /etc/systemd/system/ +data/other/yunomdns.service /etc/systemd/system/ data/other/password/* /usr/share/yunohost/other/password/ data/other/dpkg-origins/yunohost /etc/dpkg/origins data/other/dnsbl_list.yml /usr/share/yunohost/other/ diff --git a/debian/postinst b/debian/postinst index ecae9b258..7590197bd 100644 --- a/debian/postinst +++ b/debian/postinst @@ -38,6 +38,10 @@ do_configure() { # Yunoprompt systemctl enable yunoprompt.service + + # Yunomdns + chown avahi:avahi /etc/yunohost/mdns.yml + systemctl enable yunomdns.service } # summary of how this script can be called: From 842783f64c54bc0744d1692f5b1e4ea37e7c35ce Mon Sep 17 00:00:00 2001 From: tituspijean Date: Sun, 11 Jul 2021 15:20:14 +0000 Subject: [PATCH 09/55] Accomodate mDNS feature in diagnosis --- data/hooks/diagnosis/12-dnsrecords.py | 23 +++++++++++++++++++++-- data/hooks/diagnosis/21-web.py | 6 ++++++ data/templates/yunohost/services.yml | 1 + locales/en.json | 4 +++- 4 files changed, 31 insertions(+), 3 deletions(-) diff --git a/data/hooks/diagnosis/12-dnsrecords.py b/data/hooks/diagnosis/12-dnsrecords.py index 719ce4d6a..89816847d 100644 --- a/data/hooks/diagnosis/12-dnsrecords.py +++ b/data/hooks/diagnosis/12-dnsrecords.py @@ -29,8 +29,9 @@ class DNSRecordsDiagnoser(Diagnoser): for domain in all_domains: self.logger_debug("Diagnosing DNS conf for %s" % domain) is_subdomain = domain.split(".", 1)[1] in all_domains + is_localdomain = domain.endswith(".local") for report in self.check_domain( - domain, domain == main_domain, is_subdomain=is_subdomain + domain, domain == main_domain, is_subdomain=is_subdomain, is_localdomain=is_localdomain ): yield report @@ -48,7 +49,7 @@ class DNSRecordsDiagnoser(Diagnoser): for report in self.check_expiration_date(domains_from_registrar): yield report - def check_domain(self, domain, is_main_domain, is_subdomain): + def check_domain(self, domain, is_main_domain, is_subdomain, is_localdomain): expected_configuration = _build_dns_conf( domain, include_empty_AAAA_if_no_ipv6=True @@ -59,6 +60,24 @@ class DNSRecordsDiagnoser(Diagnoser): if is_subdomain: categories = ["basic"] + if is_localdomain: + categories = [] + if is_subdomain: + yield dict( + meta={"domain": domain, "category": "basic"}, + results={}, + status="WARNING", + summary="diagnosis_domain_subdomain_localdomain", + ) + else: + yield dict( + meta={"domain": domain, "category": "basic"}, + results={}, + status="INFO", + summary="diagnosis_domain_localdomain", + ) + + for category in categories: records = expected_configuration[category] diff --git a/data/hooks/diagnosis/21-web.py b/data/hooks/diagnosis/21-web.py index 81c4d6e48..04c36661e 100644 --- a/data/hooks/diagnosis/21-web.py +++ b/data/hooks/diagnosis/21-web.py @@ -34,6 +34,12 @@ class WebDiagnoser(Diagnoser): summary="diagnosis_http_nginx_conf_not_up_to_date", 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: domains_to_check.append(domain) diff --git a/data/templates/yunohost/services.yml b/data/templates/yunohost/services.yml index b961d274e..447829684 100644 --- a/data/templates/yunohost/services.yml +++ b/data/templates/yunohost/services.yml @@ -54,6 +54,7 @@ yunohost-firewall: category: security yunomdns: needs_exposed_ports: [5353] + category: mdns glances: null nsswitch: null ssl: null diff --git a/locales/en.json b/locales/en.json index 70a0e9309..3734b7cf3 100644 --- a/locales/en.json +++ b/locales/en.json @@ -190,6 +190,8 @@ "diagnosis_domain_expiration_warning": "Some domains will expire soon!", "diagnosis_domain_expiration_error": "Some domains will expire VERY SOON!", "diagnosis_domain_expires_in": "{domain} expires in {days} days.", + "diagnosis_domain_localdomain": "Domain {domain}, with a .local TLD, is not expected to have DNS records as it can be discovered through mDNS.", + "diagnosis_domain_subdomain_localdomain": "Domain {domain} is a subdomain of a .local domain. Zeroconf/mDNS discovery only works with first-level domains.", "diagnosis_services_running": "Service {service} is running!", "diagnosis_services_conf_broken": "Configuration is broken for service {service}!", "diagnosis_services_bad_status": "Service {service} is {status} :(", @@ -259,6 +261,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 https://yunohost.org/dns_local_network", "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_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_timeout": "Timed-out while trying to contact your server from outside. It appears to be unreachable.
1. The most common cause for this issue is that port 80 (and 443) are not correctly forwarded to your server.
2. You should also make sure that the service nginx is running
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.", @@ -321,7 +324,6 @@ "global_settings_cant_write_settings": "Could not save settings file, reason: {reason:s}", "global_settings_key_doesnt_exists": "The key '{settings_key:s}' does not exist in the global settings, you can see all the available keys by running 'yunohost settings list'", "global_settings_reset_success": "Previous settings now backed up to {path:s}", - "global_settings_setting_mdns_interfaces": "Space-separated list of interfaces for mDNS broadcast. Leave empty to disable mDNS.", "global_settings_setting_pop3_enabled": "Enable the POP3 protocol for the mail server", "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", From f14dcec711f1856373456033134ba4ffe019c13e Mon Sep 17 00:00:00 2001 From: tituspijean Date: Sun, 11 Jul 2021 15:20:35 +0000 Subject: [PATCH 10/55] Remove mDNS setting now we use our own setting file, not a system setting --- src/yunohost/settings.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/yunohost/settings.py b/src/yunohost/settings.py index 36904ee70..0466d8126 100644 --- a/src/yunohost/settings.py +++ b/src/yunohost/settings.py @@ -100,7 +100,6 @@ DEFAULTS = OrderedDict( ("smtp.relay.password", {"type": "string", "default": ""}), ("backup.compress_tar_archives", {"type": "bool", "default": False}), ("ssowat.panel_overlay.enabled", {"type": "bool", "default": True}), - ("mdns.interfaces", {"type": "string", "default": ""}), ] ) From 92a1a12226d6caa5becb502bc2c0c690da4c199c Mon Sep 17 00:00:00 2001 From: tituspijean Date: Sun, 11 Jul 2021 17:32:33 +0000 Subject: [PATCH 11/55] [mdns] Fix NonUniqueNameException Service names have to be unique even accross different interfaces --- bin/yunomdns | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/yunomdns b/bin/yunomdns index 795481dfa..ad1c1a012 100755 --- a/bin/yunomdns +++ b/bin/yunomdns @@ -246,7 +246,7 @@ if __name__ == '__main__': infos.append( AsyncServiceInfo( type_='_device-info._tcp.local.', - name=d_domain+'._device-info._tcp.local.', + name=interface+' '+d_domain+'._device-info._tcp.local.', addresses=b_ips, port=80, server=d+'.', @@ -255,7 +255,7 @@ if __name__ == '__main__': infos.append( AsyncServiceInfo( type_='_http._tcp.local.', - name=d_domain+'._http._tcp.local.', + name=interface+' '+d_domain+'._http._tcp.local.', addresses=b_ips, port=80, server=d+'.', From 7c58aa198c1096f4ce27993f7f6a05f628445dae Mon Sep 17 00:00:00 2001 From: tituspijean Date: Tue, 27 Jul 2021 20:38:02 +0000 Subject: [PATCH 12/55] Remove asyncio and do not support subdomains --- bin/yunomdns | 88 +++++++++++++++++----------------------------------- 1 file changed, 28 insertions(+), 60 deletions(-) diff --git a/bin/yunomdns b/bin/yunomdns index ad1c1a012..123935871 100755 --- a/bin/yunomdns +++ b/bin/yunomdns @@ -16,11 +16,10 @@ import yaml import asyncio import logging import socket -import time +from time import sleep from typing import List, Dict -from zeroconf import DNSEntry, DNSRecord -from zeroconf.asyncio import AsyncServiceInfo, AsyncZeroconf +from zeroconf import Zeroconf, ServiceInfo # Helper command taken from Moulinette def check_output(args, stderr=subprocess.STDOUT, shell=True, **kwargs): @@ -98,30 +97,6 @@ def get_network_interfaces(): return devices -# async commands -async def register_services(aiozcs: Dict[AsyncZeroconf, List[AsyncServiceInfo]]) -> None: - tasks = [] - for aiozc, infos in aiozcs.items(): - for info in infos: - tasks.append(aiozc.async_register_service(info)) - background_tasks = await asyncio.gather(*tasks) - await asyncio.gather(*background_tasks) - -async def unregister_services(aiozcs: Dict[AsyncZeroconf, List[AsyncServiceInfo]]) -> None: - for aiozc, infos in aiozcs.items(): - for info in infos: - tasks.append(aiozc.async_unregister_service(info)) - background_tasks = await asyncio.gather(*tasks) - await asyncio.gather(*background_tasks) - -async def close_aiozcs(aiozcs: Dict[AsyncZeroconf, List[AsyncServiceInfo]]) -> None: - tasks = [] - for aiozc in aiozcs: - tasks.append(aiozc.async_close()) - background_tasks = await asyncio.gather(*tasks) - await asyncio.gather(*background_tasks) - - if __name__ == '__main__': logging.basicConfig(level=logging.DEBUG) @@ -212,9 +187,7 @@ if __name__ == '__main__': print('No interface listed for broadcast.') sys.exit(0) - aiozcs = {} - tasks = [] - loop = asyncio.get_event_loop() + zcs = {} interfaces = get_network_interfaces() for interface in config['interfaces']: infos = [] # List of ServiceInfo objects, to feed Zeroconf @@ -240,44 +213,39 @@ if __name__ == '__main__': # If at least one IP is listed if addressed: - # Create a ServiceInfo object for each .local domain + # Create a Zeroconf object, and store the ServiceInfos + zc = Zeroconf(interfaces=ips) + zcs[zc]=[] for d in config['domains']: d_domain=d.replace('.local','') - infos.append( - AsyncServiceInfo( - type_='_device-info._tcp.local.', - name=interface+' '+d_domain+'._device-info._tcp.local.', - addresses=b_ips, - port=80, - server=d+'.', - ) - ) - infos.append( - AsyncServiceInfo( - type_='_http._tcp.local.', - name=interface+' '+d_domain+'._http._tcp.local.', - addresses=b_ips, - port=80, - server=d+'.', - ) - ) - print('Adding '+d+' with addresses '+str(ips)+' on interface '+interface) - # Create an AsyncZeroconf object, and store registration task - aiozc = AsyncZeroconf(interfaces=ips) - aiozcs[aiozc]=infos + 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 - loop.run_until_complete(register_services(aiozcs)) - print("Registration complete. Press Ctrl-c or stop service to exit...") + 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: - time.sleep(1) + sleep(1) except KeyboardInterrupt: pass finally: print("Unregistering...") - loop.run_until_complete(unregister_services(aiozcs)) - print("Unregistration complete.") - loop.run_until_complete(close_aiozcs(aiozcs)) - + for zc, infos in zcs.items(): + for info in infos: + zc.unregister_service(info) + zc.close() From c4762c05eb55e08f5f3cd19adc54bd1a7f91ab8b Mon Sep 17 00:00:00 2001 From: Luca Date: Sun, 8 Aug 2021 21:45:57 +0000 Subject: [PATCH 13/55] Translated using Weblate (German) Currently translated at 100.0% (637 of 637 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/de/ --- locales/de.json | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/locales/de.json b/locales/de.json index 1ef86980a..76de18746 100644 --- a/locales/de.json +++ b/locales/de.json @@ -124,7 +124,7 @@ "upnp_dev_not_found": "Es konnten keine UPnP Geräte gefunden werden", "upnp_disabled": "UPnP deaktiviert", "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_creation_failed": "Benutzer konnte nicht erstellt werden {user}: {error}", "user_deleted": "Benutzer gelöscht", @@ -528,7 +528,7 @@ "migrations_no_such_migration": "Es existiert keine Migration genannt '{id}'", "migrations_running_forward": "Durchführen der 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.", "operation_interrupted": "Wurde die Operation manuell unterbrochen?", "invalid_number": "Muss eine Zahl sein", @@ -539,8 +539,8 @@ "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_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_3": "Das Passwort muss mindestens 8 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 Grossbuchstaben, Kleinbuchstaben, Zahlen und Sonderzeichen enthalten", "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_kept_back": "Die Konfigurationsdatei '{conf}' sollte von \"regen-conf\" (Kategorie {category}) gelöscht werden, wurde aber beibehalten.", @@ -631,5 +631,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.", "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 ' 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", - "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" } From 3535b374aed13faf1e1ce72b1830fab12b09e920 Mon Sep 17 00:00:00 2001 From: tituspijean Date: Wed, 11 Aug 2021 16:19:51 +0000 Subject: [PATCH 14/55] [mdns] Always broadcast yunohost.local --- bin/yunomdns | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bin/yunomdns b/bin/yunomdns index 123935871..bc4e4c0e1 100755 --- a/bin/yunomdns +++ b/bin/yunomdns @@ -167,6 +167,8 @@ if __name__ == '__main__': if r == 'domains' or r == 'all': import glob config['domains'] = [ d.rsplit('/',1)[1][:-2] for d in glob.glob('/etc/nginx/conf.d/*.local.d') ] + if 'yunohost.local' not in config['domains']: + config['domains'].append('yunohost.local') print('Regenerated domains list: ' + str(config['domains'])) updated = True From cad5c39dae9b89c6f815250b6ed24351d7ae40fc Mon Sep 17 00:00:00 2001 From: tituspijean Date: Wed, 11 Aug 2021 16:21:32 +0000 Subject: [PATCH 15/55] [mdns] Remove logging and asyncio dependencies --- bin/yunomdns | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/bin/yunomdns b/bin/yunomdns index bc4e4c0e1..4f698a0ac 100755 --- a/bin/yunomdns +++ b/bin/yunomdns @@ -3,7 +3,6 @@ """ WIP Pythonic declaration of mDNS .local domains for YunoHost -Based off https://github.com/jstasiak/python-zeroconf/blob/master/tests/test_asyncio.py """ import subprocess @@ -13,8 +12,6 @@ import sys import argparse import yaml -import asyncio -import logging import socket from time import sleep from typing import List, Dict @@ -98,7 +95,6 @@ def get_network_interfaces(): return devices if __name__ == '__main__': - logging.basicConfig(level=logging.DEBUG) ### @@ -110,7 +106,6 @@ if __name__ == '__main__': Configuration file: /etc/yunohost/mdns.yml Subdomains are not supported. ''') - parser.add_argument('--debug', action='store_true') parser.add_argument('--regen', nargs='?', const='as_stored', choices=['domains', 'interfaces', 'all', 'as_stored'], help=''' Regenerates selection into the configuration file then starts mDNS broadcasting. @@ -125,13 +120,6 @@ if __name__ == '__main__': able.add_argument('--disable', action='store_true') args = parser.parse_args() - if args.debug: - logging.getLogger('zeroconf').setLevel(logging.DEBUG) - logging.getLogger('asyncio').setLevel(logging.DEBUG) - else: - logging.getLogger('zeroconf').setLevel(logging.WARNING) - logging.getLogger('asyncio').setLevel(logging.WARNING) - ### # CONFIG ### From f53f36e332fb40c89a9467b9e558dab828da2df9 Mon Sep 17 00:00:00 2001 From: tituspijean Date: Wed, 11 Aug 2021 17:58:50 +0000 Subject: [PATCH 16/55] [mdns] Fix yunohost.local broadcast --- bin/yunomdns | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bin/yunomdns b/bin/yunomdns index 4f698a0ac..7280aebc8 100755 --- a/bin/yunomdns +++ b/bin/yunomdns @@ -155,8 +155,6 @@ if __name__ == '__main__': if r == 'domains' or r == 'all': import glob config['domains'] = [ d.rsplit('/',1)[1][:-2] for d in glob.glob('/etc/nginx/conf.d/*.local.d') ] - if 'yunohost.local' not in config['domains']: - config['domains'].append('yunohost.local') print('Regenerated domains list: ' + str(config['domains'])) updated = True @@ -177,6 +175,9 @@ if __name__ == '__main__': 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']: From 9bef3105f1c2992bdac88c678ee30918a80024ed Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 11 Aug 2021 20:13:51 +0200 Subject: [PATCH 17/55] Add dependency to python3-zeroconf --- debian/control | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/debian/control b/debian/control index ef5061fe7..cabff028b 100644 --- a/debian/control +++ b/debian/control @@ -13,7 +13,8 @@ Depends: ${python3:Depends}, ${misc:Depends} , moulinette (>= 4.2), ssowat (>= 4.0) , python3-psutil, python3-requests, python3-dnspython, python3-openssl , 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 , php7.3-common, php7.3-fpm, php7.3-ldap, php7.3-intl , mariadb-server, php7.3-mysql From a2a50d0e453164510640508c02958f21bfd20b05 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 11 Aug 2021 20:29:29 +0200 Subject: [PATCH 18/55] mdns: Remove argument parsing because we won't really need this ? :Z --- bin/yunomdns | 71 +++------------------------------------------------- 1 file changed, 4 insertions(+), 67 deletions(-) diff --git a/bin/yunomdns b/bin/yunomdns index 7280aebc8..3e3eea72f 100755 --- a/bin/yunomdns +++ b/bin/yunomdns @@ -6,10 +6,8 @@ Pythonic declaration of mDNS .local domains for YunoHost """ import subprocess -import os import re import sys -import argparse import yaml import socket @@ -96,30 +94,6 @@ def get_network_interfaces(): if __name__ == '__main__': - - ### - # ARGUMENTS - ### - - parser = argparse.ArgumentParser(description=''' - mDNS broadcast for .local domains. - Configuration file: /etc/yunohost/mdns.yml - Subdomains are not supported. - ''') - parser.add_argument('--regen', nargs='?', const='as_stored', choices=['domains', 'interfaces', 'all', 'as_stored'], - help=''' - Regenerates selection into the configuration file then starts mDNS broadcasting. - ''') - parser.add_argument('--set-regen', choices=['domains', 'interfaces', 'all', 'none'], - help=''' - Set which part of the configuration to be regenerated. - Implies --regen as_stored, with newly stored parameter. - ''') - able = parser.add_mutually_exclusive_group() - able.add_argument('--enable', action='store_true', help='Enables mDNS broadcast, and regenerates the configuration') - able.add_argument('--disable', action='store_true') - args = parser.parse_args() - ### # CONFIG ### @@ -128,48 +102,11 @@ if __name__ == '__main__': config = yaml.load(f) or {} updated = False - if args.enable: - config['enabled'] = True - args.regen = 'as_stored' - updated = True + required_fields = ["interfaces", "domains"] + missing_fields = [field for field in required_fields if field not in config] - if args.disable: - config['enabled'] = False - updated = True - - if args.set_regen: - config['regen'] = args.set_regen - args.regen = 'as_stored' - updated = True - - if args.regen: - if args.regen == 'as_stored': - r = config['regen'] - else: - r = args.regen - if r == 'none': - print('Regeneration disabled.') - if r == 'interfaces' or r == 'all': - config['interfaces'] = [ i for i in get_network_interfaces() ] - print('Regenerated interfaces list: ' + str(config['interfaces'])) - if r == 'domains' or r == 'all': - import glob - config['domains'] = [ d.rsplit('/',1)[1][:-2] for d in glob.glob('/etc/nginx/conf.d/*.local.d') ] - print('Regenerated domains list: ' + str(config['domains'])) - updated = True - - if updated: - with open('/etc/yunohost/mdns.yml', 'w') as f: - yaml.safe_dump(config, f, default_flow_style=False) - print('Configuration file updated.') - - ### - # MAIN SCRIPT - ### - - if config['enabled'] is not True: - print('YunomDNS is disabled.') - sys.exit(0) + if missing_fields: + print("The fields %s are required" % ', '.join(missing_fields)) if config['interfaces'] is None: print('No interface listed for broadcast.') From 5bf687d619ae685b574c84822b0c59469d832394 Mon Sep 17 00:00:00 2001 From: ppr Date: Wed, 11 Aug 2021 16:22:47 +0000 Subject: [PATCH 19/55] Translated using Weblate (French) Currently translated at 99.6% (635 of 637 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/fr/ --- locales/fr.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/locales/fr.json b/locales/fr.json index 208492d20..dea492e60 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -633,5 +633,7 @@ "diagnosis_sshd_config_inconsistent_details": "Veuillez exécuter yunohost settings set security.ssh.port -v VOTRE_PORT_SSH pour définir le port SSH, et vérifiez yunohost tools regen-conf ssh --dry-run --with-diff et yunohost tools regen-conf ssh --force 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_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." -} \ No newline at end of file + "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)." +} From 98d295f5850ec99ccb83e94c70f3e100bbf159cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20M?= Date: Thu, 12 Aug 2021 05:49:08 +0000 Subject: [PATCH 20/55] Translated using Weblate (Galician) Currently translated at 56.2% (358 of 637 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/gl/ --- locales/gl.json | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/locales/gl.json b/locales/gl.json index 1caa2f3a6..6ef2c45c1 100644 --- a/locales/gl.json +++ b/locales/gl.json @@ -67,7 +67,7 @@ "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_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_installed": "Non se puido atopar {app} na lista de apps instaladas: {all_apps}", "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_user": "Conta de usuaria no 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." -} \ No newline at end of file + "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" +} From fe2e014b5667c48f9f983e0c17f7b1e1db884699 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 12 Aug 2021 15:26:39 +0200 Subject: [PATCH 21/55] mdns: Rework mdns's conf handling such that it's generated by the regen-conf. Also drop avahi-daemon because not needed anymore. --- data/hooks/conf_regen/01-yunohost | 5 +- data/hooks/conf_regen/37-avahi-daemon | 37 --------- data/hooks/conf_regen/37-mdns | 75 +++++++++++++++++++ data/templates/avahi-daemon/avahi-daemon.conf | 68 ----------------- .../mdns}/yunomdns.service | 0 data/templates/yunohost/mdns.yml | 4 - data/templates/yunohost/services.yml | 2 +- debian/control | 2 +- debian/install | 1 - debian/postinst | 4 - 10 files changed, 78 insertions(+), 120 deletions(-) delete mode 100755 data/hooks/conf_regen/37-avahi-daemon create mode 100755 data/hooks/conf_regen/37-mdns delete mode 100644 data/templates/avahi-daemon/avahi-daemon.conf rename data/{other => templates/mdns}/yunomdns.service (100%) delete mode 100644 data/templates/yunohost/mdns.yml diff --git a/data/hooks/conf_regen/01-yunohost b/data/hooks/conf_regen/01-yunohost index d160b9e66..3d65d34cd 100755 --- a/data/hooks/conf_regen/01-yunohost +++ b/data/hooks/conf_regen/01-yunohost @@ -3,7 +3,6 @@ set -e services_path="/etc/yunohost/services.yml" -mdns_path="/etc/yunohost/mdns.yml" do_init_regen() { if [[ $EUID -ne 0 ]]; then @@ -19,11 +18,9 @@ do_init_regen() { [[ -f /etc/yunohost/current_host ]] \ || echo "yunohost.org" > /etc/yunohost/current_host - # copy default services, mdns, and firewall + # copy default services and firewall [[ -f $services_path ]] \ || cp services.yml "$services_path" - [[ -f $mdns_path ]] \ - || cp mdns.yml "$mdns_path" [[ -f /etc/yunohost/firewall.yml ]] \ || cp firewall.yml /etc/yunohost/firewall.yml diff --git a/data/hooks/conf_regen/37-avahi-daemon b/data/hooks/conf_regen/37-avahi-daemon deleted file mode 100755 index 4127d66ca..000000000 --- a/data/hooks/conf_regen/37-avahi-daemon +++ /dev/null @@ -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 diff --git a/data/hooks/conf_regen/37-mdns b/data/hooks/conf_regen/37-mdns new file mode 100755 index 000000000..903b41a0f --- /dev/null +++ b/data/hooks/conf_regen/37-mdns @@ -0,0 +1,75 @@ +#!/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/dnsmasq + 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 + + _generate_config > ${pending_dir}/etc/yunohost/mdns.yml +} + +do_post_regen() { + regen_conf_files="$1" + + chown mdns:mdns ${pending_dir}/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 + + [[ -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 diff --git a/data/templates/avahi-daemon/avahi-daemon.conf b/data/templates/avahi-daemon/avahi-daemon.conf deleted file mode 100644 index d3542a411..000000000 --- a/data/templates/avahi-daemon/avahi-daemon.conf +++ /dev/null @@ -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 diff --git a/data/other/yunomdns.service b/data/templates/mdns/yunomdns.service similarity index 100% rename from data/other/yunomdns.service rename to data/templates/mdns/yunomdns.service diff --git a/data/templates/yunohost/mdns.yml b/data/templates/yunohost/mdns.yml deleted file mode 100644 index 3ed9e792b..000000000 --- a/data/templates/yunohost/mdns.yml +++ /dev/null @@ -1,4 +0,0 @@ -enabled: True -regen: all -interfaces: -domains: diff --git a/data/templates/yunohost/services.yml b/data/templates/yunohost/services.yml index 447829684..c7690fc9c 100644 --- a/data/templates/yunohost/services.yml +++ b/data/templates/yunohost/services.yml @@ -1,4 +1,3 @@ -avahi-daemon: {} dnsmasq: test_conf: dnsmasq --test dovecot: @@ -71,3 +70,4 @@ rmilter: null php5-fpm: null php7.0-fpm: null nslcd: null +avahi-daemon: null diff --git a/debian/control b/debian/control index cabff028b..c9306bef1 100644 --- a/debian/control +++ b/debian/control @@ -21,7 +21,7 @@ Depends: ${python3:Depends}, ${misc:Depends} , openssh-server, iptables, fail2ban, dnsutils, bind9utils , openssl, ca-certificates, netcat-openbsd, iproute2 , slapd, ldap-utils, sudo-ldap, libnss-ldapd, unscd, libpam-ldapd - , dnsmasq, avahi-daemon, libnss-mdns, resolvconf, libnss-myhostname + , dnsmasq, libnss-mdns, resolvconf, libnss-myhostname , postfix, postfix-ldap, postfix-policyd-spf-perl, postfix-pcre , dovecot-core, dovecot-ldap, dovecot-lmtpd, dovecot-managesieved, dovecot-antispam , rspamd, opendkim-tools, postsrsd, procmail, mailutils diff --git a/debian/install b/debian/install index e30a69a8b..1691a4849 100644 --- a/debian/install +++ b/debian/install @@ -5,7 +5,6 @@ doc/yunohost.8.gz /usr/share/man/man8/ data/actionsmap/* /usr/share/moulinette/actionsmap/ data/hooks/* /usr/share/yunohost/hooks/ data/other/yunoprompt.service /etc/systemd/system/ -data/other/yunomdns.service /etc/systemd/system/ data/other/password/* /usr/share/yunohost/other/password/ data/other/dpkg-origins/yunohost /etc/dpkg/origins data/other/dnsbl_list.yml /usr/share/yunohost/other/ diff --git a/debian/postinst b/debian/postinst index 7590197bd..ecae9b258 100644 --- a/debian/postinst +++ b/debian/postinst @@ -38,10 +38,6 @@ do_configure() { # Yunoprompt systemctl enable yunoprompt.service - - # Yunomdns - chown avahi:avahi /etc/yunohost/mdns.yml - systemctl enable yunomdns.service } # summary of how this script can be called: From 8dd65f78c8cc2e3631c2836b7596a238a8b654b4 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 12 Aug 2021 15:27:19 +0200 Subject: [PATCH 22/55] mdns: Propagate new service name to i18n strings --- locales/ar.json | 2 +- locales/ca.json | 2 +- locales/de.json | 2 +- locales/en.json | 2 +- locales/eo.json | 2 +- locales/es.json | 2 +- locales/fr.json | 2 +- locales/it.json | 2 +- locales/oc.json | 2 +- locales/zh_Hans.json | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/locales/ar.json b/locales/ar.json index 06e444f4a..6a057bdc8 100644 --- a/locales/ar.json +++ b/locales/ar.json @@ -83,7 +83,7 @@ "yunohost_installing": "عملية تنصيب يونوهوست جارية …", "yunohost_not_installed": "إنَّ واي يونوهوست ليس مُنَصَّب أو هو مثبت حاليا بشكل خاطئ. قم بتنفيذ الأمر 'yunohost tools postinstall'", "migrations_list_conflict_pending_done": "لا يمكنك استخدام --previous و --done معًا على نفس سطر الأوامر.", - "service_description_avahi-daemon": "يسمح لك بالنفاذ إلى خادومك عبر الشبكة المحلية باستخدام yunohost.local", + "service_description_mdns": "يسمح لك بالنفاذ إلى خادومك عبر الشبكة المحلية باستخدام yunohost.local", "service_description_metronome": "يُدير حسابات الدردشة الفورية XMPP", "service_description_nginx": "يقوم بتوفير النفاذ و السماح بالوصول إلى كافة مواقع الويب المستضافة على خادومك", "service_description_postfix": "يقوم بإرسال و تلقي الرسائل البريدية الإلكترونية", diff --git a/locales/ca.json b/locales/ca.json index 1e4c55f5d..c9f71c0ad 100644 --- a/locales/ca.json +++ b/locales/ca.json @@ -283,7 +283,7 @@ "service_already_started": "El servei «{service:s}» ja està funcionant", "service_already_stopped": "Ja s'ha aturat el servei «{service:s}»", "service_cmd_exec_failed": "No s'ha pogut executar l'ordre «{command:s}»", - "service_description_avahi-daemon": "Permet accedir al servidor via «yunohost.local» en la xarxa local", + "service_description_mdns": "Permet accedir al servidor via «yunohost.local» en la xarxa local", "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_fail2ban": "Protegeix contra els atacs de força bruta i a altres atacs provinents d'Internet", diff --git a/locales/de.json b/locales/de.json index 83647ec17..0760dc775 100644 --- a/locales/de.json +++ b/locales/de.json @@ -597,7 +597,7 @@ "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_dnsmasq": "Verarbeitet die Auflösung des Domainnamens (DNS)", - "service_description_avahi-daemon": "Erlaubt, den Server im lokalen Netz über 'yunohost.local' zu erreichen", + "service_description_mdns": "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.", "service_description_slapd": "Speichert Benutzer, Domains und verbundene Informationen", "service_description_rspamd": "Spamfilter und andere E-Mail-Merkmale", diff --git a/locales/en.json b/locales/en.json index 3734b7cf3..5c73cba8b 100644 --- a/locales/en.json +++ b/locales/en.json @@ -558,7 +558,7 @@ "service_already_started": "The service '{service:s}' is running already", "service_already_stopped": "The service '{service:s}' has already been stopped", "service_cmd_exec_failed": "Could not execute the command '{command:s}'", - "service_description_avahi-daemon": "Allows you to reach your server using 'yunohost.local' in your local network", + "service_description_mdns": "Allows you to reach your server using 'yunohost.local' in your local network", "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_fail2ban": "Protects against brute-force and other kinds of attacks from the Internet", diff --git a/locales/eo.json b/locales/eo.json index d273593a9..b4d53f0f1 100644 --- a/locales/eo.json +++ b/locales/eo.json @@ -332,7 +332,7 @@ "hook_exec_failed": "Ne povis funkcii skripto: {path:s}", "global_settings_cant_open_settings": "Ne eblis malfermi agordojn, tial: {reason:s}", "user_created": "Uzanto kreita", - "service_description_avahi-daemon": "Permesas al vi atingi vian servilon uzante 'yunohost.local' en via loka reto", + "service_description_mdns": "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:s}! (Uzu --forte pretervidi)", "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}", diff --git a/locales/es.json b/locales/es.json index f95451922..f2b8063cf 100644 --- a/locales/es.json +++ b/locales/es.json @@ -238,7 +238,7 @@ "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_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", + "service_description_mdns": "Permite acceder a su servidor usando «yunohost.local» en su red local", "server_reboot_confirm": "El servidor se reiniciará inmediatamente ¿está seguro? [{answers:s}]", "server_reboot": "El servidor se reiniciará", "server_shutdown_confirm": "El servidor se apagará inmediatamente ¿está seguro? [{answers:s}]", diff --git a/locales/fr.json b/locales/fr.json index f06acf2e5..565cc8032 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -232,7 +232,7 @@ "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 l’interface 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 l’option --accept-disclaimer.", - "service_description_avahi-daemon": "Vous permet d’atteindre votre serveur en utilisant « yunohost.local » sur votre réseau local", + "service_description_mdns": "Vous permet d’atteindre 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_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", diff --git a/locales/it.json b/locales/it.json index 707f3afc2..3444b846d 100644 --- a/locales/it.json +++ b/locales/it.json @@ -428,7 +428,7 @@ "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_dnsmasq": "Gestisce la risoluzione dei domini (DNS)", - "service_description_avahi-daemon": "Consente di raggiungere il tuo server eseguendo 'yunohost.local' sulla tua LAN", + "service_description_mdns": "Consente di raggiungere il tuo server eseguendo 'yunohost.local' sulla tua LAN", "server_reboot_confirm": "Il server si riavvierà immediatamente, sei sicuro? [{answers:s}]", "server_reboot": "Il server si riavvierà", "server_shutdown_confirm": "Il server si spegnerà immediatamente, sei sicuro? [{answers:s}]", diff --git a/locales/oc.json b/locales/oc.json index 991383bc3..b5bd9474c 100644 --- a/locales/oc.json +++ b/locales/oc.json @@ -193,7 +193,7 @@ "user_unknown": "Utilizaire « {user:s} » desconegut", "user_update_failed": "Modificacion impossibla de l’utilizaire", "user_updated": "L’utilizaire es estat modificat", - "service_description_avahi-daemon": "permet d’aténher vòstre servidor via yunohost.local sus vòstre ret local", + "service_description_mdns": "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…", "server_reboot_confirm": "Lo servidor es per reaviar sul pic, o volètz vertadièrament ? {answers:s}", diff --git a/locales/zh_Hans.json b/locales/zh_Hans.json index 78ba55133..0e971299f 100644 --- a/locales/zh_Hans.json +++ b/locales/zh_Hans.json @@ -226,7 +226,7 @@ "service_description_fail2ban": "防止来自互联网的暴力攻击和其他类型的攻击", "service_description_dovecot": "允许电子邮件客户端访问/获取电子邮件(通过IMAP和POP3)", "service_description_dnsmasq": "处理域名解析(DNS)", - "service_description_avahi-daemon": "允许您使用本地网络中的“ yunohost.local”访问服务器", + "service_description_mdns": "允许您使用本地网络中的“ yunohost.local”访问服务器", "service_started": "服务 '{service:s}' 已启动", "service_start_failed": "无法启动服务 '{service:s}'\n\n最近的服务日志:{logs:s}", "service_reloaded_or_restarted": "服务'{service:s}'已重新加载或重新启动", From ffc132f2c5192e393275250bb1073bd2ee499c7f Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 12 Aug 2021 16:59:54 +0200 Subject: [PATCH 23/55] Configure mdns during yunohost's debian postinst init --- debian/postinst | 1 + 1 file changed, 1 insertion(+) diff --git a/debian/postinst b/debian/postinst index ecae9b258..8fc00bbe2 100644 --- a/debian/postinst +++ b/debian/postinst @@ -18,6 +18,7 @@ do_configure() { 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/15-nginx init + bash /usr/share/yunohost/hooks/conf_regen/37-mdns init fi else echo "Regenerating configuration, this might take a while..." From 4d0581bef21865903202a8cd911fd7dec0db7285 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 12 Aug 2021 17:19:45 +0200 Subject: [PATCH 24/55] mdns: Misc fixes after tests on the battefield --- data/hooks/conf_regen/37-mdns | 6 ++++-- src/yunohost/domain.py | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/data/hooks/conf_regen/37-mdns b/data/hooks/conf_regen/37-mdns index 903b41a0f..c85e43a9a 100755 --- a/data/hooks/conf_regen/37-mdns +++ b/data/hooks/conf_regen/37-mdns @@ -30,18 +30,20 @@ do_init_regen() { do_pre_regen() { pending_dir="$1" - cd /usr/share/yunohost/templates/dnsmasq + 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 ${pending_dir}/etc/yunohost/mdns.yml + 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$" diff --git a/src/yunohost/domain.py b/src/yunohost/domain.py index aaac3a995..bca701dc6 100644 --- a/src/yunohost/domain.py +++ b/src/yunohost/domain.py @@ -163,7 +163,7 @@ def domain_add(operation_logger, domain, dyndns=False): # because it's one of the major service, but in the long term we # should identify the root of this bug... _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() except Exception as e: @@ -290,7 +290,7 @@ def domain_remove(operation_logger, domain, remove_apps=False, force=False): "/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() hook_callback("post_domain_remove", args=[domain]) From a343490f304d9a3a0a8cc1e64e73a7eb83064fbe Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 12 Aug 2021 17:22:20 +0200 Subject: [PATCH 25/55] We shall not expose port 5353 publicly --- data/templates/yunohost/services.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/data/templates/yunohost/services.yml b/data/templates/yunohost/services.yml index c7690fc9c..c781d54aa 100644 --- a/data/templates/yunohost/services.yml +++ b/data/templates/yunohost/services.yml @@ -52,7 +52,6 @@ yunohost-firewall: test_status: iptables -S | grep "^-A INPUT" | grep " --dport" | grep -q ACCEPT category: security yunomdns: - needs_exposed_ports: [5353] category: mdns glances: null nsswitch: null From 212ea635df64ca8a2d2a9167529c52204d89c5ea Mon Sep 17 00:00:00 2001 From: tituspijean Date: Thu, 12 Aug 2021 15:52:25 +0000 Subject: [PATCH 26/55] [mdns] Fix service user --- data/templates/mdns/yunomdns.service | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/templates/mdns/yunomdns.service b/data/templates/mdns/yunomdns.service index 36d938035..ce2641b5d 100644 --- a/data/templates/mdns/yunomdns.service +++ b/data/templates/mdns/yunomdns.service @@ -3,8 +3,8 @@ Description=YunoHost mDNS service After=network.target [Service] -User=avahi -Group=avahi +User=mdns +Group=mdns Type=simple ExecStart=/usr/bin/yunomdns StandardOutput=syslog From f1444bc36ffea201890e6e676ef71459e20c30ba Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 12 Aug 2021 18:40:43 +0200 Subject: [PATCH 27/55] mdns: misc fixes for ip parsing --- bin/yunomdns | 53 ++++++++++++++++++++++++---------------------------- 1 file changed, 24 insertions(+), 29 deletions(-) diff --git a/bin/yunomdns b/bin/yunomdns index 3e3eea72f..be5a87be0 100755 --- a/bin/yunomdns +++ b/bin/yunomdns @@ -47,7 +47,7 @@ def _extract_inet(string, skip_netmask=False, skip_loopback=True): 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})*)?)" + 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 = {} @@ -74,14 +74,16 @@ def _extract_inet(string, skip_netmask=False, skip_loopback=True): # 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 addr show") - for d in re.split(r"^(?:[0-9]+: )", output, flags=re.MULTILINE): - # Extract device name (1) and its addresses (2) - m = re.match(r"([^\s@]+)(?:@[\S]+)?: (.*)", d, flags=re.DOTALL) - if m: - devices_raw[m.group(1)] = m.group(2) + 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 = { @@ -122,25 +124,18 @@ if __name__ == '__main__': ips = [] # Human-readable IPs b_ips = [] # Binary-convered IPs - # Parse the IPs and prepare their binary version - addressed = False - try: - ip = interfaces[interface]['ipv4'].split('/')[0] - if len(ip)>0: addressed = True - ips.append(ip) - b_ips.append(socket.inet_pton(socket.AF_INET, ip)) - except: - pass - try: - ip = interfaces[interface]['ipv6'].split('/')[0] - if len(ip)>0: addressed = True - ips.append(ip) - b_ips.append(socket.inet_pton(socket.AF_INET6, ip)) - except: - pass + 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 addressed: + if ips: # Create a Zeroconf object, and store the ServiceInfos zc = Zeroconf(interfaces=ips) zcs[zc]=[] @@ -151,11 +146,11 @@ if __name__ == '__main__': 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+'.', + 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) From 7ca637d8f82f0a888d3d8af93950e0692b125821 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 12 Aug 2021 18:54:20 +0200 Subject: [PATCH 28/55] yaml.load -> yaml.safe_load --- bin/yunomdns | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bin/yunomdns b/bin/yunomdns index be5a87be0..862a1f477 100755 --- a/bin/yunomdns +++ b/bin/yunomdns @@ -1,7 +1,6 @@ #!/usr/bin/env python3 """ -WIP Pythonic declaration of mDNS .local domains for YunoHost """ @@ -101,7 +100,7 @@ if __name__ == '__main__': ### with open('/etc/yunohost/mdns.yml', 'r') as f: - config = yaml.load(f) or {} + config = yaml.safe_load(f) or {} updated = False required_fields = ["interfaces", "domains"] From 849ccb043a94bbc60c608cf12665e9453df03455 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 12 Aug 2021 19:13:26 +0200 Subject: [PATCH 29/55] mdns: diagnosis expects a 'data' key instead of 'results' --- data/hooks/diagnosis/12-dnsrecords.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/hooks/diagnosis/12-dnsrecords.py b/data/hooks/diagnosis/12-dnsrecords.py index 89816847d..49e39c775 100644 --- a/data/hooks/diagnosis/12-dnsrecords.py +++ b/data/hooks/diagnosis/12-dnsrecords.py @@ -65,14 +65,14 @@ class DNSRecordsDiagnoser(Diagnoser): if is_subdomain: yield dict( meta={"domain": domain, "category": "basic"}, - results={}, + data={}, status="WARNING", summary="diagnosis_domain_subdomain_localdomain", ) else: yield dict( meta={"domain": domain, "category": "basic"}, - results={}, + data={}, status="INFO", summary="diagnosis_domain_localdomain", ) From 7f3eeafbed74af010c31e46f8753c2a4bd165fdd Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 12 Aug 2021 19:40:36 +0200 Subject: [PATCH 30/55] mdns/diagnosis: following suggestion IRL: extend the no-check mecanism for .local to .onion and other special-use TLDs --- data/hooks/diagnosis/12-dnsrecords.py | 30 ++++++++++----------------- locales/en.json | 3 +-- 2 files changed, 12 insertions(+), 21 deletions(-) diff --git a/data/hooks/diagnosis/12-dnsrecords.py b/data/hooks/diagnosis/12-dnsrecords.py index 49e39c775..c29029de9 100644 --- a/data/hooks/diagnosis/12-dnsrecords.py +++ b/data/hooks/diagnosis/12-dnsrecords.py @@ -13,7 +13,7 @@ from yunohost.diagnosis import Diagnoser from yunohost.domain import domain_list, _build_dns_conf, _get_maindomain YNH_DYNDNS_DOMAINS = ["nohost.me", "noho.st", "ynh.fr"] - +SPECIAL_USE_TLDS = ["local", "localhost", "onion", "dev", "test"] class DNSRecordsDiagnoser(Diagnoser): @@ -29,9 +29,9 @@ class DNSRecordsDiagnoser(Diagnoser): for domain in all_domains: self.logger_debug("Diagnosing DNS conf for %s" % domain) is_subdomain = domain.split(".", 1)[1] in all_domains - is_localdomain = domain.endswith(".local") + is_specialusedomain = any(domain.endswith("." + tld) for tld in SPECIAL_USE_TLDS) for report in self.check_domain( - domain, domain == main_domain, is_subdomain=is_subdomain, is_localdomain=is_localdomain + domain, domain == main_domain, is_subdomain=is_subdomain, is_specialusedomain=is_specialusedomain ): yield report @@ -49,7 +49,7 @@ class DNSRecordsDiagnoser(Diagnoser): for report in self.check_expiration_date(domains_from_registrar): yield report - def check_domain(self, domain, is_main_domain, is_subdomain, is_localdomain): + def check_domain(self, domain, is_main_domain, is_subdomain, is_specialusedomain): expected_configuration = _build_dns_conf( domain, include_empty_AAAA_if_no_ipv6=True @@ -60,22 +60,14 @@ class DNSRecordsDiagnoser(Diagnoser): if is_subdomain: categories = ["basic"] - if is_localdomain: + if is_specialusedomain: categories = [] - if is_subdomain: - yield dict( - meta={"domain": domain, "category": "basic"}, - data={}, - status="WARNING", - summary="diagnosis_domain_subdomain_localdomain", - ) - else: - yield dict( - meta={"domain": domain, "category": "basic"}, - data={}, - status="INFO", - summary="diagnosis_domain_localdomain", - ) + yield dict( + meta={"domain": domain}, + data={}, + status="INFO", + summary="diagnosis_dns_specialusedomain", + ) for category in categories: diff --git a/locales/en.json b/locales/en.json index 2b8e8b32f..cad1c8dcb 100644 --- a/locales/en.json +++ b/locales/en.json @@ -183,6 +183,7 @@ "diagnosis_dns_discrepancy": "The following DNS record does not seem to follow the recommended configuration:
Type: {type}
Name: {name}
Current value: {current}
Expected value: {value}", "diagnosis_dns_point_to_doc": "Please check the documentation at https://yunohost.org/dns_config 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 yunohost dyndns update --force.", + "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_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?", @@ -190,8 +191,6 @@ "diagnosis_domain_expiration_warning": "Some domains will expire soon!", "diagnosis_domain_expiration_error": "Some domains will expire VERY SOON!", "diagnosis_domain_expires_in": "{domain} expires in {days} days.", - "diagnosis_domain_localdomain": "Domain {domain}, with a .local TLD, is not expected to have DNS records as it can be discovered through mDNS.", - "diagnosis_domain_subdomain_localdomain": "Domain {domain} is a subdomain of a .local domain. Zeroconf/mDNS discovery only works with first-level domains.", "diagnosis_services_running": "Service {service} is running!", "diagnosis_services_conf_broken": "Configuration is broken for service {service}!", "diagnosis_services_bad_status": "Service {service} is {status} :(", From e493b89d6a5eb2301e6663277aa03ac404329e87 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 12 Aug 2021 20:16:35 +0200 Subject: [PATCH 31/55] diagnosis: Zblerg, .dev is actually an actual TLD --- data/hooks/diagnosis/12-dnsrecords.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/data/hooks/diagnosis/12-dnsrecords.py b/data/hooks/diagnosis/12-dnsrecords.py index c29029de9..1db4af685 100644 --- a/data/hooks/diagnosis/12-dnsrecords.py +++ b/data/hooks/diagnosis/12-dnsrecords.py @@ -13,7 +13,8 @@ from yunohost.diagnosis import Diagnoser from yunohost.domain import domain_list, _build_dns_conf, _get_maindomain YNH_DYNDNS_DOMAINS = ["nohost.me", "noho.st", "ynh.fr"] -SPECIAL_USE_TLDS = ["local", "localhost", "onion", "dev", "test"] +SPECIAL_USE_TLDS = ["local", "localhost", "onion", "test"] + class DNSRecordsDiagnoser(Diagnoser): From f0590907c9e2eebe46d28146698387a33a8aea76 Mon Sep 17 00:00:00 2001 From: Kay0u Date: Sat, 14 Aug 2021 11:44:52 +0200 Subject: [PATCH 32/55] fix ynh_permission_has_user --- data/helpers.d/permission | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/data/helpers.d/permission b/data/helpers.d/permission index a5c09cded..c04b4145b 100644 --- a/data/helpers.d/permission +++ b/data/helpers.d/permission @@ -362,8 +362,17 @@ ynh_permission_has_user() { return 1 fi - yunohost user permission info "$app.$permission" --output-as json --quiet \ - | jq -e --arg user $user '.corresponding_users | index($user)' >/dev/null + # Check both allowed and corresponding_users sections in the json + 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 From c2460d7526069ed48ff2b0bd5a35c8c3f2086c76 Mon Sep 17 00:00:00 2001 From: sagessylu Date: Sun, 15 Aug 2021 21:41:32 +0200 Subject: [PATCH 33/55] Add purge option to yunohost app remove --- data/actionsmap/yunohost.yml | 6 +++++- src/yunohost/app.py | 6 ++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/data/actionsmap/yunohost.yml b/data/actionsmap/yunohost.yml index 5df1c0877..bd9207528 100644 --- a/data/actionsmap/yunohost.yml +++ b/data/actionsmap/yunohost.yml @@ -673,7 +673,11 @@ app: api: DELETE /apps/ arguments: app: - help: App to delete + help: App to remove + -p: + full: --purge + help: Remove with all app data + action: store_true ### app_upgrade() upgrade: diff --git a/src/yunohost/app.py b/src/yunohost/app.py index a48400a8e..d6b459264 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -1187,12 +1187,13 @@ def dump_app_log_extract_for_debugging(operation_logger): @is_unit_operation() -def app_remove(operation_logger, app): +def app_remove(operation_logger, app, purge=False): """ Remove app - Keyword argument: + Keyword arguments: app -- App(s) to delete + purge -- Remove with all app data """ from yunohost.hook import hook_exec, hook_remove, hook_callback @@ -1230,6 +1231,7 @@ def app_remove(operation_logger, app): env_dict["YNH_APP_INSTANCE_NAME"] = app env_dict["YNH_APP_INSTANCE_NUMBER"] = str(app_instance_nb) env_dict["YNH_APP_MANIFEST_VERSION"] = manifest.get("version", "?") + env_dict["YNH_APP_PURGE"] = purge operation_logger.extra.update({"env": env_dict}) operation_logger.flush() From cec4971cac0aa567149349e2c4f27efbd2f45387 Mon Sep 17 00:00:00 2001 From: sagessylu Date: Sun, 15 Aug 2021 22:02:13 +0200 Subject: [PATCH 34/55] Add no-safety-backup option to yunohost app upgrade --- data/actionsmap/yunohost.yml | 4 ++++ src/yunohost/app.py | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/data/actionsmap/yunohost.yml b/data/actionsmap/yunohost.yml index 5df1c0877..43955c017 100644 --- a/data/actionsmap/yunohost.yml +++ b/data/actionsmap/yunohost.yml @@ -693,6 +693,10 @@ app: full: --force help: Force the update, even though the app is up to date action: store_true + -b: + full: --no-safety-backup + help: Disable the safety backup during upgrade + action: store_true ### app_change_url() change-url: diff --git a/src/yunohost/app.py b/src/yunohost/app.py index a48400a8e..1841b2a07 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -502,7 +502,7 @@ def app_change_url(operation_logger, app, domain, path): 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 @@ -510,6 +510,7 @@ def app_upgrade(app=[], url=None, file=None, force=False): file -- Folder or tarball for upgrade app -- App(s) to upgrade (default all) url -- Git url to fetch for upgrade + no_safety_backup -- Disable the safety backup during upgrade """ 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_MANIFEST_VERSION"] = str(app_new_version) env_dict["YNH_APP_CURRENT_VERSION"] = str(app_current_version) + env_dict["YNH_APP_NO_BACKUP_UPGRADE"] = no_safety_backup # We'll check that the app didn't brutally edit some system configuration manually_modified_files_before_install = manually_modified_files() From b39201a1933e4f1cf06c0f668a581c032a39e993 Mon Sep 17 00:00:00 2001 From: mifegui Date: Sun, 15 Aug 2021 19:22:04 +0000 Subject: [PATCH 35/55] Translated using Weblate (Portuguese) Currently translated at 8.1% (52 of 637 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/pt/ --- locales/pt.json | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/locales/pt.json b/locales/pt.json index 72d983a39..82edbf349 100644 --- a/locales/pt.json +++ b/locales/pt.json @@ -1,7 +1,7 @@ { "action_invalid": "Acção Inválida '{action}'", "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", "app_already_installed": "{app} já está instalada", "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_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", - "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_argument_choice_invalid": "Escolha inválida para o argumento '{name}', deve ser um dos {choices}", - "app_argument_invalid": "Valor inválido de argumento '{name}': {error}", + "app_argument_choice_invalid": "Use uma das opções '{choices}' para o argumento '{name}'", + "app_argument_invalid": "Escolha um valor válido para o argumento '{name}': {error}", "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_upgrade_app_name": "Atualizando aplicação {app}…", "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.", "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", - "aborting": "Abortando." -} \ No newline at end of file + "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}'" +} From ccb6dc54b1091f51e4a3689faf82f686ba4d7d90 Mon Sep 17 00:00:00 2001 From: ljf Date: Tue, 17 Aug 2021 17:26:00 +0200 Subject: [PATCH 36/55] [fix] Avoid warning and use safeloader --- data/actionsmap/yunohost_completion.py | 2 +- data/helpers.d/setting | 4 ++-- data/hooks/conf_regen/01-yunohost | 4 ++-- doc/generate_manpages.py | 2 +- src/yunohost/app.py | 4 ++-- src/yunohost/firewall.py | 2 +- src/yunohost/regenconf.py | 2 +- src/yunohost/service.py | 2 +- tests/test_actionmap.py | 2 +- tests/test_i18n_keys.py | 2 +- 10 files changed, 13 insertions(+), 13 deletions(-) diff --git a/data/actionsmap/yunohost_completion.py b/data/actionsmap/yunohost_completion.py index bc32028d3..3891aee9c 100644 --- a/data/actionsmap/yunohost_completion.py +++ b/data/actionsmap/yunohost_completion.py @@ -32,7 +32,7 @@ def get_dict_actions(OPTION_SUBTREE, category): with open(ACTIONSMAP_FILE, "r") as stream: # Getting the dictionary containning what actions are possible per category - OPTION_TREE = yaml.load(stream) + OPTION_TREE = yaml.safe_load(stream) CATEGORY = [ category for category in OPTION_TREE.keys() if not category.startswith("_") diff --git a/data/helpers.d/setting b/data/helpers.d/setting index 2950b3829..66bce9717 100644 --- a/data/helpers.d/setting +++ b/data/helpers.d/setting @@ -86,7 +86,7 @@ key, value = os.environ['KEY'], os.environ.get('VALUE', None) setting_file = "/etc/yunohost/apps/%s/settings.yml" % app assert os.path.exists(setting_file), "Setting file %s does not exists ?" % setting_file with open(setting_file) as f: - settings = yaml.load(f) + settings = yaml.safe_load(f) if action == "get": if key in settings: print(settings[key]) @@ -96,7 +96,7 @@ else: del settings[key] elif action == "set": if key in ['redirected_urls', 'redirected_regex']: - value = yaml.load(value) + value = yaml.safe_load(value) settings[key] = value else: raise ValueError("action should either be get, set or delete") diff --git a/data/hooks/conf_regen/01-yunohost b/data/hooks/conf_regen/01-yunohost index 8ef398f1d..1a10a6954 100755 --- a/data/hooks/conf_regen/01-yunohost +++ b/data/hooks/conf_regen/01-yunohost @@ -212,10 +212,10 @@ import yaml 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: - services = yaml.load(f) or {} + services = yaml.safe_load(f) or {} updated = False diff --git a/doc/generate_manpages.py b/doc/generate_manpages.py index f681af7dd..8691bab37 100644 --- a/doc/generate_manpages.py +++ b/doc/generate_manpages.py @@ -33,7 +33,7 @@ def ordered_yaml_load(stream): yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG, lambda loader, node: OrderedDict(loader.construct_pairs(node)), ) - return yaml.load(stream, OrderedLoader) + return yaml.safe_load(stream, OrderedLoader) def main(): diff --git a/src/yunohost/app.py b/src/yunohost/app.py index a48400a8e..6a2640cee 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -1518,7 +1518,7 @@ def app_setting(app, key, value=None, delete=False): # SET else: if key in ["redirected_urls", "redirected_regex"]: - value = yaml.load(value) + value = yaml.safe_load(value) app_settings[key] = value _set_app_settings(app, app_settings) @@ -2175,7 +2175,7 @@ def _get_app_settings(app_id): ) try: 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... # 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()} diff --git a/src/yunohost/firewall.py b/src/yunohost/firewall.py index 9850defa5..4be6810ec 100644 --- a/src/yunohost/firewall.py +++ b/src/yunohost/firewall.py @@ -179,7 +179,7 @@ def firewall_list(raw=False, by_ip_version=False, list_forwarded=False): """ with open(FIREWALL_FILE) as f: - firewall = yaml.load(f) + firewall = yaml.safe_load(f) if raw: return firewall diff --git a/src/yunohost/regenconf.py b/src/yunohost/regenconf.py index 924818e44..0608bcf8c 100644 --- a/src/yunohost/regenconf.py +++ b/src/yunohost/regenconf.py @@ -444,7 +444,7 @@ def _get_regenconf_infos(): """ try: with open(REGEN_CONF_FILE, "r") as f: - return yaml.load(f) + return yaml.safe_load(f) except Exception: return {} diff --git a/src/yunohost/service.py b/src/yunohost/service.py index e6e960a57..912662600 100644 --- a/src/yunohost/service.py +++ b/src/yunohost/service.py @@ -670,7 +670,7 @@ def _get_services(): """ try: with open("/etc/yunohost/services.yml", "r") as f: - services = yaml.load(f) or {} + services = yaml.safe_load(f) or {} except Exception: return {} diff --git a/tests/test_actionmap.py b/tests/test_actionmap.py index bf6755979..0b8abb152 100644 --- a/tests/test_actionmap.py +++ b/tests/test_actionmap.py @@ -2,4 +2,4 @@ import yaml def test_yaml_syntax(): - yaml.load(open("data/actionsmap/yunohost.yml")) + yaml.safe_load(open("data/actionsmap/yunohost.yml")) diff --git a/tests/test_i18n_keys.py b/tests/test_i18n_keys.py index 2ad56a34e..7b5ad1956 100644 --- a/tests/test_i18n_keys.py +++ b/tests/test_i18n_keys.py @@ -108,7 +108,7 @@ def find_expected_string_keys(): yield m # 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(): continue for action in category["actions"].values(): From 5518931c029f60aaaffc9e38e89b20b7574f8b3b Mon Sep 17 00:00:00 2001 From: ljf Date: Tue, 17 Aug 2021 17:33:23 +0200 Subject: [PATCH 37/55] [fix] OrderedLoader from SafeLoader --- doc/generate_manpages.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/generate_manpages.py b/doc/generate_manpages.py index 8691bab37..fa042fb17 100644 --- a/doc/generate_manpages.py +++ b/doc/generate_manpages.py @@ -26,14 +26,14 @@ ACTIONSMAP_FILE = os.path.join(THIS_SCRIPT_DIR, "../data/actionsmap/yunohost.yml def ordered_yaml_load(stream): - class OrderedLoader(yaml.Loader): + class OrderedLoader(yaml.SafeLoader): pass OrderedLoader.add_constructor( yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG, lambda loader, node: OrderedDict(loader.construct_pairs(node)), ) - return yaml.safe_load(stream, OrderedLoader) + return yaml.load(stream, OrderedLoader) def main(): From 69a5ae5736f3e89b0a7d5cfec7a6106a71187b40 Mon Sep 17 00:00:00 2001 From: sagessylu <49091098+sagessylu@users.noreply.github.com> Date: Tue, 17 Aug 2021 20:27:33 +0200 Subject: [PATCH 38/55] Update src/yunohost/app.py Co-authored-by: ljf (zamentur) --- 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 1841b2a07..a69229ad4 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -619,7 +619,7 @@ def app_upgrade(app=[], url=None, file=None, force=False, no_safety_backup=False env_dict["YNH_APP_UPGRADE_TYPE"] = upgrade_type env_dict["YNH_APP_MANIFEST_VERSION"] = str(app_new_version) env_dict["YNH_APP_CURRENT_VERSION"] = str(app_current_version) - env_dict["YNH_APP_NO_BACKUP_UPGRADE"] = no_safety_backup + env_dict["NO_BACKUP_UPGRADE"] = no_safety_backup # We'll check that the app didn't brutally edit some system configuration manually_modified_files_before_install = manually_modified_files() From 09efb86ff10ab4786cdf6a0350435832120ea9e4 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 18 Aug 2021 19:40:10 +0200 Subject: [PATCH 39/55] Improve help text for app remove --purge --- data/actionsmap/yunohost.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/actionsmap/yunohost.yml b/data/actionsmap/yunohost.yml index bd9207528..bcd6a61c3 100644 --- a/data/actionsmap/yunohost.yml +++ b/data/actionsmap/yunohost.yml @@ -676,7 +676,7 @@ app: help: App to remove -p: full: --purge - help: Remove with all app data + help: Also remove all application data action: store_true ### app_upgrade() From 4b84922315e9e89e4d92420d6c8bb95d20b4749c Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 18 Aug 2021 19:47:46 +0200 Subject: [PATCH 40/55] Apply suggestions from code review --- data/helpers.d/multimedia | 6 +++--- data/hooks/post_user_create/ynh_multimedia | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/data/helpers.d/multimedia b/data/helpers.d/multimedia index 4ec7611fc..552b8c984 100644 --- a/data/helpers.d/multimedia +++ b/data/helpers.d/multimedia @@ -32,9 +32,9 @@ ynh_multimedia_build_main_dir() { ln -sfn "$MEDIA_DIRECTORY/share" "$MEDIA_DIRECTORY/$user/Share" # Création du lien symbolique dans le home de l'utilisateur. #link will only be created if the home directory of the user exists and if it's located in '/home' folder - home="$(getent passwd $user | cut -d: -f6)" - if [[ -d "$home" && "$(echo "$home" | grep /home/)" ]]; then - ln -sfn "$MEDIA_DIRECTORY/$user" "$home/Multimedia" + 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. chown -R $user "$MEDIA_DIRECTORY/$user" diff --git a/data/hooks/post_user_create/ynh_multimedia b/data/hooks/post_user_create/ynh_multimedia index 2fa02505a..2be3f42d4 100644 --- a/data/hooks/post_user_create/ynh_multimedia +++ b/data/hooks/post_user_create/ynh_multimedia @@ -16,9 +16,9 @@ mkdir -p "$MEDIA_DIRECTORY/$user/eBook" ln -sfn "$MEDIA_DIRECTORY/share" "$MEDIA_DIRECTORY/$user/Share" # Création du lien symbolique dans le home de l'utilisateur. #link will only be created if the home directory of the user exists and if it's located in '/home' folder -home="$(getent passwd $user | cut -d: -f6)" -if [[ -d "$home" && "$(echo "$home" | grep /home/)" ]]; then - ln -sfn "$MEDIA_DIRECTORY/$user" "$home/Multimedia" +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. chown -R $user "$MEDIA_DIRECTORY/$user" From 3c07e55017d2d2c42a45c9aea027396f1121913f Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 19 Aug 2021 18:14:15 +0200 Subject: [PATCH 41/55] [fix] hook_exec / subprocess.Popen explodes if you feed non-string values in env variables --- 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 ef753d4d6..fad2033a6 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -1233,7 +1233,7 @@ def app_remove(operation_logger, app, purge=False): env_dict["YNH_APP_INSTANCE_NAME"] = app env_dict["YNH_APP_INSTANCE_NUMBER"] = str(app_instance_nb) env_dict["YNH_APP_MANIFEST_VERSION"] = manifest.get("version", "?") - env_dict["YNH_APP_PURGE"] = purge + env_dict["YNH_APP_PURGE"] = str(purge) operation_logger.extra.update({"env": env_dict}) operation_logger.flush() From e3f11bec0982e3ba9e3b9800a4acc1d104c56107 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 19 Aug 2021 18:41:47 +0200 Subject: [PATCH 42/55] NO_BACKUP_UPGRADE: helpers expect 0 or 1 --- 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 fad2033a6..57498c644 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -619,7 +619,7 @@ def app_upgrade(app=[], url=None, file=None, force=False, no_safety_backup=False env_dict["YNH_APP_UPGRADE_TYPE"] = upgrade_type env_dict["YNH_APP_MANIFEST_VERSION"] = str(app_new_version) env_dict["YNH_APP_CURRENT_VERSION"] = str(app_current_version) - env_dict["NO_BACKUP_UPGRADE"] = no_safety_backup + 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 manually_modified_files_before_install = manually_modified_files() From b452838a1797641f82778e60f4e50e1722837eba Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 19 Aug 2021 19:16:29 +0200 Subject: [PATCH 43/55] Update changelog for 4.2.8 --- debian/changelog | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/debian/changelog b/debian/changelog index 57da44532..b1894758a 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,16 @@ +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 Thu, 19 Aug 2021 19:11:19 +0200 + yunohost (4.2.7) stable; urgency=low Notable changes: From ecf136d5db27caae21656091b948eb825369b248 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 19 Aug 2021 20:28:20 +0200 Subject: [PATCH 44/55] Auto-enable yunomdns on legacy systems --- data/hooks/conf_regen/37-mdns | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/data/hooks/conf_regen/37-mdns b/data/hooks/conf_regen/37-mdns index c85e43a9a..1d7381e26 100755 --- a/data/hooks/conf_regen/37-mdns +++ b/data/hooks/conf_regen/37-mdns @@ -51,6 +51,12 @@ do_post_regen() { 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 } From b8c8ac0b2de6e2a5c91f2c50dab54209ec619faa Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 19 Aug 2021 20:29:28 +0200 Subject: [PATCH 45/55] Gotta also remove libnss-mdns if we want to get rid of avahi-daemon --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index c9306bef1..37eccb5dd 100644 --- a/debian/control +++ b/debian/control @@ -21,7 +21,7 @@ Depends: ${python3:Depends}, ${misc:Depends} , openssh-server, iptables, fail2ban, dnsutils, bind9utils , openssl, ca-certificates, netcat-openbsd, iproute2 , slapd, ldap-utils, sudo-ldap, libnss-ldapd, unscd, libpam-ldapd - , dnsmasq, libnss-mdns, resolvconf, libnss-myhostname + , dnsmasq, resolvconf, libnss-myhostname , postfix, postfix-ldap, postfix-policyd-spf-perl, postfix-pcre , dovecot-core, dovecot-ldap, dovecot-lmtpd, dovecot-managesieved, dovecot-antispam , rspamd, opendkim-tools, postsrsd, procmail, mailutils From cd917a9123de55245f5bc39612c82430fd4e123a Mon Sep 17 00:00:00 2001 From: "ljf (zamentur)" Date: Sun, 22 Aug 2021 21:57:50 +0200 Subject: [PATCH 46/55] [fix] Wording in path question --- locales/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/en.json b/locales/en.json index 693e9d24d..2cb3fc329 100644 --- a/locales/en.json +++ b/locales/en.json @@ -32,7 +32,7 @@ "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_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 web 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_admin": "Choose an administrator user for this app", "app_manifest_install_ask_is_public": "Should this app be exposed to anonymous visitors?", From c9d73af4013816ccb5ba2eba47a3cb804b44d2ee Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Mon, 23 Aug 2021 15:31:43 +0200 Subject: [PATCH 47/55] i18n: mdns -> yunomdns --- locales/en.json | 2 +- locales/fr.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/locales/en.json b/locales/en.json index cad1c8dcb..f2658c412 100644 --- a/locales/en.json +++ b/locales/en.json @@ -561,7 +561,7 @@ "service_already_started": "The service '{service}' is running already", "service_already_stopped": "The service '{service}' has already been stopped", "service_cmd_exec_failed": "Could not execute the command '{command}'", - "service_description_mdns": "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_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", diff --git a/locales/fr.json b/locales/fr.json index 72afe80dd..d40b39c62 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -234,7 +234,7 @@ "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 l’interface 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 l’option --accept-disclaimer.", - "service_description_mdns": "Vous permet d’atteindre votre serveur en utilisant « yunohost.local » sur votre réseau local", + "service_description_yunomdns": "Vous permet d’atteindre 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_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", From f4d0106c367902cad01e49808b570816f12fda12 Mon Sep 17 00:00:00 2001 From: yunohost-bot Date: Mon, 23 Aug 2021 14:36:55 +0000 Subject: [PATCH 48/55] [CI] Remove stale translated strings --- locales/ar.json | 1 - locales/ca.json | 1 - locales/de.json | 3 +-- locales/eo.json | 1 - locales/es.json | 1 - locales/fr.json | 2 +- locales/gl.json | 2 +- locales/it.json | 1 - locales/oc.json | 1 - locales/pt.json | 2 +- locales/zh_Hans.json | 1 - 11 files changed, 4 insertions(+), 12 deletions(-) diff --git a/locales/ar.json b/locales/ar.json index 1d3dbd49d..3e5248917 100644 --- a/locales/ar.json +++ b/locales/ar.json @@ -83,7 +83,6 @@ "yunohost_installing": "عملية تنصيب يونوهوست جارية …", "yunohost_not_installed": "إنَّ واي يونوهوست ليس مُنَصَّب أو هو مثبت حاليا بشكل خاطئ. قم بتنفيذ الأمر 'yunohost tools postinstall'", "migrations_list_conflict_pending_done": "لا يمكنك استخدام --previous و --done معًا على نفس سطر الأوامر.", - "service_description_mdns": "يسمح لك بالنفاذ إلى خادومك عبر الشبكة المحلية باستخدام yunohost.local", "service_description_metronome": "يُدير حسابات الدردشة الفورية XMPP", "service_description_nginx": "يقوم بتوفير النفاذ و السماح بالوصول إلى كافة مواقع الويب المستضافة على خادومك", "service_description_postfix": "يقوم بإرسال و تلقي الرسائل البريدية الإلكترونية", diff --git a/locales/ca.json b/locales/ca.json index bfdb57c9e..d01c0da0b 100644 --- a/locales/ca.json +++ b/locales/ca.json @@ -283,7 +283,6 @@ "service_already_started": "El servei «{service}» ja està funcionant", "service_already_stopped": "Ja s'ha aturat el servei «{service}»", "service_cmd_exec_failed": "No s'ha pogut executar l'ordre «{command}»", - "service_description_mdns": "Permet accedir al servidor via «yunohost.local» en la xarxa local", "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_fail2ban": "Protegeix contra els atacs de força bruta i a altres atacs provinents d'Internet", diff --git a/locales/de.json b/locales/de.json index ef8593bd6..ea20c7d7f 100644 --- a/locales/de.json +++ b/locales/de.json @@ -597,7 +597,6 @@ "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_dnsmasq": "Verarbeitet die Auflösung des Domainnamens (DNS)", - "service_description_mdns": "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.", "service_description_slapd": "Speichert Benutzer, Domains und verbundene Informationen", "service_description_rspamd": "Spamfilter und andere E-Mail-Merkmale", @@ -636,4 +635,4 @@ "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" -} +} \ No newline at end of file diff --git a/locales/eo.json b/locales/eo.json index 8fac2e50e..76cec1264 100644 --- a/locales/eo.json +++ b/locales/eo.json @@ -332,7 +332,6 @@ "hook_exec_failed": "Ne povis funkcii skripto: {path}", "global_settings_cant_open_settings": "Ne eblis malfermi agordojn, tial: {reason}", "user_created": "Uzanto kreita", - "service_description_mdns": "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)", "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}", diff --git a/locales/es.json b/locales/es.json index 44d637796..560bfe240 100644 --- a/locales/es.json +++ b/locales/es.json @@ -238,7 +238,6 @@ "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_dnsmasq": "Maneja la resolución de nombres de dominio (DNS)", - "service_description_mdns": "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": "El servidor se reiniciará", "server_shutdown_confirm": "El servidor se apagará inmediatamente ¿está seguro? [{answers}]", diff --git a/locales/fr.json b/locales/fr.json index d40b39c62..f1ccde84d 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -636,4 +636,4 @@ "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)." -} +} \ No newline at end of file diff --git a/locales/gl.json b/locales/gl.json index 6ef2c45c1..a9d901275 100644 --- a/locales/gl.json +++ b/locales/gl.json @@ -358,4 +358,4 @@ "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" -} +} \ No newline at end of file diff --git a/locales/it.json b/locales/it.json index c818dd14c..543ab99bd 100644 --- a/locales/it.json +++ b/locales/it.json @@ -428,7 +428,6 @@ "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_dnsmasq": "Gestisce la risoluzione dei domini (DNS)", - "service_description_mdns": "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": "Il server si riavvierà", "server_shutdown_confirm": "Il server si spegnerà immediatamente, sei sicuro? [{answers}]", diff --git a/locales/oc.json b/locales/oc.json index fb0a7006d..906f67106 100644 --- a/locales/oc.json +++ b/locales/oc.json @@ -193,7 +193,6 @@ "user_unknown": "Utilizaire « {user} » desconegut", "user_update_failed": "Modificacion impossibla de l’utilizaire", "user_updated": "L’utilizaire es estat modificat", - "service_description_mdns": "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…", "server_reboot_confirm": "Lo servidor es per reaviar sul pic, o volètz vertadièrament ? {answers}", diff --git a/locales/pt.json b/locales/pt.json index 82edbf349..353d48744 100644 --- a/locales/pt.json +++ b/locales/pt.json @@ -137,4 +137,4 @@ "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}'" -} +} \ No newline at end of file diff --git a/locales/zh_Hans.json b/locales/zh_Hans.json index 7951961b6..5f076fa2e 100644 --- a/locales/zh_Hans.json +++ b/locales/zh_Hans.json @@ -226,7 +226,6 @@ "service_description_fail2ban": "防止来自互联网的暴力攻击和其他类型的攻击", "service_description_dovecot": "允许电子邮件客户端访问/获取电子邮件(通过IMAP和POP3)", "service_description_dnsmasq": "处理域名解析(DNS)", - "service_description_mdns": "允许您使用本地网络中的“ yunohost.local”访问服务器", "service_started": "服务 '{service}' 已启动", "service_start_failed": "无法启动服务 '{service}'\n\n最近的服务日志:{logs}", "service_reloaded_or_restarted": "服务'{service}'已重新加载或重新启动", From 07cd1428d24fec44f3c6ca0d516f19d28d107f97 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 26 Aug 2021 20:06:39 +0200 Subject: [PATCH 49/55] Update locales/en.json --- locales/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/en.json b/locales/en.json index 2cb3fc329..109c4b16b 100644 --- a/locales/en.json +++ b/locales/en.json @@ -32,7 +32,7 @@ "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_install_ask_domain": "Choose the domain where this app should be installed", - "app_manifest_install_ask_path": "Choose the web path after the domain 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_admin": "Choose an administrator user for this app", "app_manifest_install_ask_is_public": "Should this app be exposed to anonymous visitors?", From aac0146aef754315764705a8f45084ff0f9209e1 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 26 Aug 2021 20:14:23 +0200 Subject: [PATCH 50/55] Forbid installing apps with a dot in app id --- 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 57498c644..490368a15 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -887,7 +887,7 @@ def app_install( raise YunohostValidationError("disk_space_not_sufficient_install") # 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") app_id = manifest["id"] From 4f0494d66bb78974b3f8e25522f8ad74475b95d8 Mon Sep 17 00:00:00 2001 From: ericgaspar Date: Thu, 26 Aug 2021 20:57:23 +0200 Subject: [PATCH 51/55] Update en.json --- locales/en.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/locales/en.json b/locales/en.json index 27bdd63ab..83c270b58 100644 --- a/locales/en.json +++ b/locales/en.json @@ -32,7 +32,7 @@ "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_install_ask_domain": "Choose the domain 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_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_admin": "Choose an administrator user for this app", "app_manifest_install_ask_is_public": "Should this app be exposed to anonymous visitors?", @@ -399,7 +399,7 @@ "log_letsencrypt_cert_install": "Install a Let's Encrypt certificate on '{}' domain", "log_permission_create": "Create 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_letsencrypt_cert_renew": "Renew '{}' Let's Encrypt certificate", "log_regen_conf": "Regenerate system configurations '{}'", From aac8b8d4608db5ab57a89beed6118996c7b27b63 Mon Sep 17 00:00:00 2001 From: yunohost-bot Date: Thu, 26 Aug 2021 20:09:57 +0000 Subject: [PATCH 52/55] [CI] Format code --- data/hooks/diagnosis/12-dnsrecords.py | 10 +++++++--- data/hooks/diagnosis/21-web.py | 2 +- src/yunohost/domain.py | 4 +++- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/data/hooks/diagnosis/12-dnsrecords.py b/data/hooks/diagnosis/12-dnsrecords.py index 1db4af685..6110024f4 100644 --- a/data/hooks/diagnosis/12-dnsrecords.py +++ b/data/hooks/diagnosis/12-dnsrecords.py @@ -30,9 +30,14 @@ class DNSRecordsDiagnoser(Diagnoser): for domain in all_domains: self.logger_debug("Diagnosing DNS conf for %s" % domain) is_subdomain = domain.split(".", 1)[1] in all_domains - is_specialusedomain = any(domain.endswith("." + tld) for tld in SPECIAL_USE_TLDS) + is_specialusedomain = any( + domain.endswith("." + tld) for tld in SPECIAL_USE_TLDS + ) for report in self.check_domain( - domain, domain == main_domain, is_subdomain=is_subdomain, is_specialusedomain=is_specialusedomain + domain, + domain == main_domain, + is_subdomain=is_subdomain, + is_specialusedomain=is_specialusedomain, ): yield report @@ -70,7 +75,6 @@ class DNSRecordsDiagnoser(Diagnoser): summary="diagnosis_dns_specialusedomain", ) - for category in categories: records = expected_configuration[category] diff --git a/data/hooks/diagnosis/21-web.py b/data/hooks/diagnosis/21-web.py index 04c36661e..40a6c26b4 100644 --- a/data/hooks/diagnosis/21-web.py +++ b/data/hooks/diagnosis/21-web.py @@ -34,7 +34,7 @@ class WebDiagnoser(Diagnoser): summary="diagnosis_http_nginx_conf_not_up_to_date", details=["diagnosis_http_nginx_conf_not_up_to_date_details"], ) - elif domain.endswith('.local'): + elif domain.endswith(".local"): yield dict( meta={"domain": domain}, status="INFO", diff --git a/src/yunohost/domain.py b/src/yunohost/domain.py index 3c9192b8f..09d419c71 100644 --- a/src/yunohost/domain.py +++ b/src/yunohost/domain.py @@ -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 # should identify the root of this bug... _force_clear_hashes(["/etc/nginx/conf.d/%s.conf" % domain]) - regen_conf(names=["nginx", "metronome", "dnsmasq", "postfix", "rspamd", "mdns"]) + regen_conf( + names=["nginx", "metronome", "dnsmasq", "postfix", "rspamd", "mdns"] + ) app_ssowatconf() except Exception as e: From f7258dd3a6cf91cc07da2d06a960ae2af1fc9ee8 Mon Sep 17 00:00:00 2001 From: "ljf (zamentur)" Date: Fri, 27 Aug 2021 01:17:11 +0200 Subject: [PATCH 53/55] [fix] Another tmp nightmare original idea from Aleks --- data/hooks/conf_regen/06-slapd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/hooks/conf_regen/06-slapd b/data/hooks/conf_regen/06-slapd index 3fa3a0fd2..b2439dcf9 100755 --- a/data/hooks/conf_regen/06-slapd +++ b/data/hooks/conf_regen/06-slapd @@ -2,7 +2,7 @@ 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" db_init="/usr/share/yunohost/templates/slapd/db_init.ldif" From 3c646b3d6a647bcd33cad8d929eda9300124f97b Mon Sep 17 00:00:00 2001 From: "ljf (zamentur)" Date: Fri, 27 Aug 2021 01:17:11 +0200 Subject: [PATCH 54/55] [fix] Another tmp nightmare original idea from Aleks --- data/hooks/conf_regen/06-slapd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/hooks/conf_regen/06-slapd b/data/hooks/conf_regen/06-slapd index 3fa3a0fd2..b2439dcf9 100755 --- a/data/hooks/conf_regen/06-slapd +++ b/data/hooks/conf_regen/06-slapd @@ -2,7 +2,7 @@ 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" db_init="/usr/share/yunohost/templates/slapd/db_init.ldif" From eef5cd4da913705035767fa62d497096890f6c74 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Fri, 27 Aug 2021 01:34:10 +0200 Subject: [PATCH 55/55] Update changelog for 4.2.8.1 --- debian/changelog | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/debian/changelog b/debian/changelog index b1894758a..48f3bbdca 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +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 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)