From 64066f85b0ba6da48945a6c842a1c49f84fdd6d3 Mon Sep 17 00:00:00 2001 From: ljf Date: Tue, 13 Aug 2019 22:49:01 +0200 Subject: [PATCH 01/71] [enh] Allow admin to specify an smtp relay --- data/hooks/conf_regen/19-postfix | 12 +++++++++++- data/templates/postfix/main.cf | 20 ++++++++++++++++++++ src/yunohost/settings.py | 4 ++++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/data/hooks/conf_regen/19-postfix b/data/hooks/conf_regen/19-postfix index 68afe4bc9..235923b3d 100755 --- a/data/hooks/conf_regen/19-postfix +++ b/data/hooks/conf_regen/19-postfix @@ -23,7 +23,17 @@ do_pre_regen() { # Support different strategy for security configurations export compatibility="$(yunohost settings get 'security.postfix.compatibility')" - + + # Add possibility to specify a relay + # Could be useful with some isp with no 25 port open or more complex setup + export relay_host="$(yunohost settings get 'smtp.relay.host')" + if [ ! -z "${relay_host}" ]; then + export relay_port="$(yunohost settings get 'smtp.relay.port')" + export relay_user="$(yunohost settings get 'smtp.relay.user')" + relay_password="$(yunohost settings get 'smtp.relay.password')" + echo "[${relay_host}]:${relay_port} ${relay_user}:${relay_password}" > /etc/postfix/sasl_passwd + postmap /etc/postfix/sasl_passwd + fi export main_domain export domain_list="$YNH_DOMAINS" ynh_render_template "main.cf" "${postfix_dir}/main.cf" diff --git a/data/templates/postfix/main.cf b/data/templates/postfix/main.cf index 61cbfa2e6..8121ad3d9 100644 --- a/data/templates/postfix/main.cf +++ b/data/templates/postfix/main.cf @@ -72,7 +72,11 @@ alias_maps = hash:/etc/aliases alias_database = hash:/etc/aliases mydomain = {{ main_domain }} mydestination = localhost +{% if relay_host == "" %} relayhost = +{% else %} +relayhost = [{{ relay_host }}]:{{ relay_port }} +{% endif %} mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 mailbox_command = procmail -a "$EXTENSION" mailbox_size_limit = 0 @@ -178,3 +182,19 @@ default_destination_rate_delay = 5s # So it's easly possible to scan a server to know which email adress is valid # and after to send spam disable_vrfy_command = yes + +{% if relay_user != "" %} +# Relay email through an other smtp account +# enable SASL authentication +smtp_sasl_auth_enable = yes +# disallow methods that allow anonymous authentication. +smtp_sasl_security_options = noanonymous +# where to find sasl_passwd +smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd +{% if relay_port == "587" %} +# Enable STARTTLS encryption +smtp_use_tls = yes +{% endif %} +# where to find CA certificates +smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt +{% endif %} diff --git a/src/yunohost/settings.py b/src/yunohost/settings.py index c1edadb93..f40bb61af 100644 --- a/src/yunohost/settings.py +++ b/src/yunohost/settings.py @@ -71,6 +71,10 @@ DEFAULTS = OrderedDict([ "choices": ["intermediate", "modern"]}), ("pop3.enabled", {"type": "bool", "default": False}), ("smtp.allow_ipv6", {"type": "bool", "default": True}), + ("smtp.relay.host", {"type": "string", "default": ""}), + ("smtp.relay.port", {"type": "int", "default": 587}), + ("smtp.relay.user", {"type": "string", "default": ""}), + ("smtp.relay.password", {"type": "string", "default": ""}), ]) From 3a0104861ed04c554abfc57c4e52c9b7f020fe51 Mon Sep 17 00:00:00 2001 From: ljf Date: Wed, 29 Apr 2020 00:42:57 +0200 Subject: [PATCH 02/71] [fix] Don't modify directly files in regen conf --- data/hooks/conf_regen/19-postfix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/hooks/conf_regen/19-postfix b/data/hooks/conf_regen/19-postfix index 235923b3d..69790fd39 100755 --- a/data/hooks/conf_regen/19-postfix +++ b/data/hooks/conf_regen/19-postfix @@ -31,8 +31,8 @@ do_pre_regen() { export relay_port="$(yunohost settings get 'smtp.relay.port')" export relay_user="$(yunohost settings get 'smtp.relay.user')" relay_password="$(yunohost settings get 'smtp.relay.password')" - echo "[${relay_host}]:${relay_port} ${relay_user}:${relay_password}" > /etc/postfix/sasl_passwd - postmap /etc/postfix/sasl_passwd + echo "[${relay_host}]:${relay_port} ${relay_user}:${relay_password}" > ${postfix_dir}/sasl_passwd + postmap ${postfix_dir}/sasl_passwd fi export main_domain export domain_list="$YNH_DOMAINS" From fae6b3f3f474c7ba13d9e6f38ea8bb7270ec6ee6 Mon Sep 17 00:00:00 2001 From: ljf Date: Wed, 29 Apr 2020 00:53:52 +0200 Subject: [PATCH 03/71] [fix] Unrelevant obsolete config params --- data/templates/postfix/main.cf | 6 ------ 1 file changed, 6 deletions(-) diff --git a/data/templates/postfix/main.cf b/data/templates/postfix/main.cf index 8121ad3d9..b15964241 100644 --- a/data/templates/postfix/main.cf +++ b/data/templates/postfix/main.cf @@ -191,10 +191,4 @@ smtp_sasl_auth_enable = yes smtp_sasl_security_options = noanonymous # where to find sasl_passwd smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd -{% if relay_port == "587" %} -# Enable STARTTLS encryption -smtp_use_tls = yes -{% endif %} -# where to find CA certificates -smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt {% endif %} From c1fddb312dec74c1d471279819a5bdc297bc8ea0 Mon Sep 17 00:00:00 2001 From: ljf Date: Wed, 29 Apr 2020 01:11:25 +0200 Subject: [PATCH 04/71] [enh] Add settings description --- locales/en.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/locales/en.json b/locales/en.json index 25712e8cd..e81505efd 100644 --- a/locales/en.json +++ b/locales/en.json @@ -322,6 +322,10 @@ "global_settings_unknown_setting_from_settings_file": "Unknown key in settings: '{setting_key:s}', discard it and save it in /etc/yunohost/settings-unknown.json", "global_settings_setting_service_ssh_allow_deprecated_dsa_hostkey": "Allow the use of (deprecated) DSA hostkey for the SSH daemon configuration", "global_settings_setting_smtp_allow_ipv6": "Allow the use of IPv6 to receive and send mail", + "global_settings_setting_smtp_relay_host": "SMTP relay host to use in order to send mail instead of this yunohost instance. Useful if you are in one of this situation: your 25 port is blocked by your ISP or VPS provider, you have a residential IP listed on DUHL, you are not able to configure reverse DNS or this server is not directly exposed on the internet and you want use an other one to send mails.", + "global_settings_setting_smtp_relay_port": "SMTP relay port", + "global_settings_setting_smtp_relay_user": "SMTP relay user account", + "global_settings_setting_smtp_relay_password": "SMTP relay host password", "global_settings_unknown_type": "Unexpected situation, the setting {setting:s} appears to have the type {unknown_type:s} but it is not a type supported by the system.", "good_practices_about_admin_password": "You are now about to define a new administration password. The password should be at least 8 characters long—though it is good practice to use a longer password (i.e. a passphrase) and/or to use a variation of characters (uppercase, lowercase, digits and special characters).", "good_practices_about_user_password": "You are now about to define a new user password. The password should be at least 8 characters long—though it is good practice to use a longer password (i.e. a passphrase) and/or to a variation of characters (uppercase, lowercase, digits and special characters).", From 94eb9246bbed517d003c410aa4253da8b1e8ce64 Mon Sep 17 00:00:00 2001 From: ljf Date: Wed, 29 Apr 2020 03:12:52 +0200 Subject: [PATCH 05/71] [fix] Avoid sasl account reachable from other users --- data/hooks/conf_regen/19-postfix | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/data/hooks/conf_regen/19-postfix b/data/hooks/conf_regen/19-postfix index 69790fd39..3a8117a61 100755 --- a/data/hooks/conf_regen/19-postfix +++ b/data/hooks/conf_regen/19-postfix @@ -31,8 +31,21 @@ do_pre_regen() { export relay_port="$(yunohost settings get 'smtp.relay.port')" export relay_user="$(yunohost settings get 'smtp.relay.user')" relay_password="$(yunohost settings get 'smtp.relay.password')" - echo "[${relay_host}]:${relay_port} ${relay_user}:${relay_password}" > ${postfix_dir}/sasl_passwd + + # Avoid to display "Relay account paswword" to other users + touch ${postfix_dir}/sasl_passwd + chmod o=--- ${postfix_dir}/sasl_passwd + touch ${postfix_dir}/sasl_passwd.db + chmod o=--- ${postfix_dir}/sasl_passwd.db + # Avoid "postmap: warning: removing zero-length database file" + chown postfix ${pending_dir}/etc/postfix + chown postfix ${pending_dir}/etc/postfix/sasl_passwd + chown postfix ${pending_dir}/etc/postfix/sasl_passwd.db + + cat <<< "[${relay_host}]:${relay_port} ${relay_user}:${relay_password}" > ${postfix_dir}/sasl_passwd postmap ${postfix_dir}/sasl_passwd + + fi export main_domain export domain_list="$YNH_DOMAINS" @@ -57,6 +70,8 @@ do_pre_regen() { do_post_regen() { regen_conf_files=$1 + chmod o=--- /etc/postfix/sasl_passwd + chmod o=--- /etc/postfix/sasl_passwd.db [[ -z "$regen_conf_files" ]] \ || { service postfix restart && service postsrsd restart; } From ff0a2192b9d29b072e00582dcf31062af3a0da70 Mon Sep 17 00:00:00 2001 From: ljf Date: Wed, 29 Apr 2020 03:13:30 +0200 Subject: [PATCH 06/71] [enh] Automatic regenconf after editing smtp settings --- src/yunohost/settings.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/yunohost/settings.py b/src/yunohost/settings.py index f40bb61af..3dea458f1 100644 --- a/src/yunohost/settings.py +++ b/src/yunohost/settings.py @@ -326,6 +326,10 @@ def reconfigure_ssh(setting_name, old_value, new_value): service_regen_conf(names=['ssh']) @post_change_hook("smtp.allow_ipv6") +@post_change_hook("smtp.relay.host") +@post_change_hook("smtp.relay.port") +@post_change_hook("smtp.relay.user") +@post_change_hook("smtp.relay.password") @post_change_hook("security.postfix.compatibility") def reconfigure_postfix(setting_name, old_value, new_value): if old_value != new_value: From d51b126df85e7a74884a5dc4ebd9a4d7f9ca8001 Mon Sep 17 00:00:00 2001 From: ljf Date: Wed, 29 Apr 2020 03:23:30 +0200 Subject: [PATCH 07/71] [fix] postmap: warning: removing zero-length database file --- data/hooks/conf_regen/19-postfix | 3 --- 1 file changed, 3 deletions(-) diff --git a/data/hooks/conf_regen/19-postfix b/data/hooks/conf_regen/19-postfix index 3a8117a61..1a1b88a25 100755 --- a/data/hooks/conf_regen/19-postfix +++ b/data/hooks/conf_regen/19-postfix @@ -35,12 +35,9 @@ do_pre_regen() { # Avoid to display "Relay account paswword" to other users touch ${postfix_dir}/sasl_passwd chmod o=--- ${postfix_dir}/sasl_passwd - touch ${postfix_dir}/sasl_passwd.db - chmod o=--- ${postfix_dir}/sasl_passwd.db # Avoid "postmap: warning: removing zero-length database file" chown postfix ${pending_dir}/etc/postfix chown postfix ${pending_dir}/etc/postfix/sasl_passwd - chown postfix ${pending_dir}/etc/postfix/sasl_passwd.db cat <<< "[${relay_host}]:${relay_port} ${relay_user}:${relay_password}" > ${postfix_dir}/sasl_passwd postmap ${postfix_dir}/sasl_passwd From a5ecf52c30955ab3c1f8092a1d2f1952eec10131 Mon Sep 17 00:00:00 2001 From: ljf Date: Wed, 29 Apr 2020 03:38:10 +0200 Subject: [PATCH 08/71] [fix] chown postfix to avoid warning --- data/hooks/conf_regen/19-postfix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/hooks/conf_regen/19-postfix b/data/hooks/conf_regen/19-postfix index 1a1b88a25..67ca22991 100755 --- a/data/hooks/conf_regen/19-postfix +++ b/data/hooks/conf_regen/19-postfix @@ -67,8 +67,8 @@ do_pre_regen() { do_post_regen() { regen_conf_files=$1 - chmod o=--- /etc/postfix/sasl_passwd - chmod o=--- /etc/postfix/sasl_passwd.db + chmod o=--- /etc/postfix/sasl_passwd* + chown postfix /etc/postfix/sasl_passwd* [[ -z "$regen_conf_files" ]] \ || { service postfix restart && service postsrsd restart; } From 05aa54ac0f2f055aa5401a0d11d8069ce960a894 Mon Sep 17 00:00:00 2001 From: Laurent Peuch Date: Tue, 26 May 2020 06:03:49 +0200 Subject: [PATCH 09/71] [mod] refactor the whole argument parsing flow into a component oriented way --- src/yunohost/app.py | 293 +++++++++++------- .../tests/test_apps_arguments_parsing.py | 7 +- 2 files changed, 186 insertions(+), 114 deletions(-) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index 0b16123cb..027a3a558 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -2391,6 +2391,184 @@ def _parse_args_for_action(action, args={}): return _parse_args_in_yunohost_format(args, action_args) +class Question: + "empty class to store questions information" + + +class YunoHostArgumentFormatParser(object): + hide_user_input_in_prompt = False + + def parse_question(self, question, user_answers): + parsed_question = Question() + + parsed_question.name = question['name'] + parsed_question.default = question.get('default', None) + parsed_question.choices = question.get('choices', []) + parsed_question.optional = question.get('optional', False) + parsed_question.ask = question.get('ask') + parsed_question.value = user_answers.get(parsed_question.name) + + if parsed_question.ask is None: + parsed_question.ask = "Enter value for '%s':" % parsed_question.name + + return parsed_question + + def parse(self, question, user_answers): + question = self.parse_question(question, user_answers) + + if question.value is None: + text_for_user_input_in_cli = self._format_text_for_user_input_in_cli(question) + + try: + question.value = msignals.prompt(text_for_user_input_in_cli, self.hide_user_input_in_prompt) + except NotImplementedError: + question.value = None + + # we don't have an answer, check optional and default_value + if question.value is None: + if not question.optional and question.default is None: + raise YunohostError('app_argument_required', name=question.name) + else: + question.value = self.default_value if question.default is None else question.default + + # we have an answer, do some post checks + if question.value is not None: + if question.choices and question.value not in question.choices: + raise YunohostError('app_argument_choice_invalid', name=question.name, + choices=', '.join(question.choices)) + + # this is done to enforce a certain formating like for boolean + # by default it doesn't do anything + question.value = self._post_parse_value(question) + + return (question.value, self.argument_type) + + def _format_text_for_user_input_in_cli(self, question): + text_for_user_input_in_cli = _value_for_locale(question.ask) + + if question.default is not None: + text_for_user_input_in_cli += ' (default: {0})'.format(question.default) + + if question.choices: + text_for_user_input_in_cli += ' [{0}]'.format(' | '.join(question.choices)) + + return text_for_user_input_in_cli + + def _post_parse_value(self, question): + return question.value + + +class StringArgumentParser(YunoHostArgumentFormatParser): + argument_type = "string" + default_value = "" + + +class PasswordArgumentParser(YunoHostArgumentFormatParser): + hide_user_input_in_prompt = True + argument_type = "password" + default_value = "" + + +class PathArgumentParser(YunoHostArgumentFormatParser): + argument_type = "path" + default_value = "" + + +class BooleanArgumentParser(YunoHostArgumentFormatParser): + argument_type = "boolean" + default_value = False + + def parse_question(self, question, user_answers): + question = super(BooleanArgumentParser, self).parse_question(question, user_answers) + + if question.default is None: + question.default = False + + return question + + def _format_text_for_user_input_in_cli(self, question): + text_for_user_input_in_cli = _value_for_locale(question.ask) + + text_for_user_input_in_cli += " [yes | no]" + + if question.default is not None: + formatted_default = "yes" if question.default else "no" + text_for_user_input_in_cli += ' (default: {0})'.format(formatted_default) + + return text_for_user_input_in_cli + + def _post_parse_value(self, question): + if isinstance(question.value, bool): + return 1 if question.value else 0 + + if str(question.value).lower() in ["1", "yes", "y"]: + return 1 + + if str(question.value).lower() in ["0", "no", "n"]: + return 0 + + raise YunohostError('app_argument_choice_invalid', name=question.name, + choices='yes, no, y, n, 1, 0') + + +class DomainArgumentParser(YunoHostArgumentFormatParser): + argument_type = "domain" + + def parse_question(self, question, user_answers): + from yunohost.domain import domain_list, _get_maindomain + + question = super(DomainArgumentParser, self).parse_question(question, user_answers) + + if question.default is None: + question.default = _get_maindomain() + + question.choices = domain_list()["domains"] + + return question + + +class UserArgumentParser(YunoHostArgumentFormatParser): + argument_type = "user" + + def parse_question(self, question, user_answers): + from yunohost.user import user_list + + question = super(UserArgumentParser, self).parse_question(question, user_answers) + question.choices = user_list()["users"] + + return question + + +class AppArgumentParser(YunoHostArgumentFormatParser): + argument_type = "app" + + def parse_question(self, question, user_answers): + from yunohost.app import app_list + + question = super(AppArgumentParser, self).parse_question(question, user_answers) + question.choices = [x["id"] for x in app_list()["apps"]] + + return question + + +class DisplayTextArgumentParser(YunoHostArgumentFormatParser): + + def parse(self, question, user_answers): + print(question["ask"]) + + +ARGUMENTS_TYPE_PARSERS = { + "string": StringArgumentParser, + "password": PasswordArgumentParser, + "path": PathArgumentParser, + "boolean": BooleanArgumentParser, + "domain": DomainArgumentParser, + "user": UserArgumentParser, + "app": AppArgumentParser, + "display_text": DisplayTextArgumentParser, +} + + def _parse_args_in_yunohost_format(user_answers, argument_questions): """Parse arguments store in either manifest.json or actions.json or from a config panel against the user answers when they are present. @@ -2402,121 +2580,14 @@ def _parse_args_in_yunohost_format(user_answers, argument_questions): format from actions.json/toml, manifest.json/toml or config_panel.json/toml """ - from yunohost.domain import domain_list, _get_maindomain - from yunohost.user import user_list - parsed_answers_dict = OrderedDict() for question in argument_questions: - question_name = question['name'] - question_type = question.get('type', 'string') - question_default = question.get('default', None) - question_choices = question.get('choices', []) - question_value = None + parser = ARGUMENTS_TYPE_PARSERS[question.get("type", "string")]() - # Transpose default value for boolean type and set it to - # false if not defined. - if question_type == 'boolean': - question_default = 1 if question_default else 0 - - # do not print for webadmin - if question_type == 'display_text' and msettings.get('interface') != 'api': - print(_value_for_locale(question['ask'])) - continue - - # Attempt to retrieve argument value - if question_name in user_answers: - question_value = user_answers[question_name] - else: - if 'ask' in question: - # Retrieve proper ask string - text_for_user_input_in_cli = _value_for_locale(question['ask']) - - # Append extra strings - if question_type == 'boolean': - text_for_user_input_in_cli += ' [yes | no]' - elif question_choices: - text_for_user_input_in_cli += ' [{0}]'.format(' | '.join(question_choices)) - - if question_default is not None: - if question_type == 'boolean': - text_for_user_input_in_cli += ' (default: {0})'.format("yes" if question_default == 1 else "no") - else: - text_for_user_input_in_cli += ' (default: {0})'.format(question_default) - - # Check for a password argument - is_password = True if question_type == 'password' else False - - if question_type == 'domain': - question_default = _get_maindomain() - text_for_user_input_in_cli += ' (default: {0})'.format(question_default) - msignals.display(m18n.n('domains_available')) - for domain in domain_list()['domains']: - msignals.display("- {}".format(domain)) - - elif question_type == 'user': - msignals.display(m18n.n('users_available')) - for user in user_list()['users'].keys(): - msignals.display("- {}".format(user)) - - elif question_type == 'password': - msignals.display(m18n.n('good_practices_about_user_password')) - - try: - input_string = msignals.prompt(text_for_user_input_in_cli, is_password) - except NotImplementedError: - input_string = None - if (input_string == '' or input_string is None) \ - and question_default is not None: - question_value = question_default - else: - question_value = input_string - elif question_default is not None: - question_value = question_default - - # If the value is empty (none or '') - # then check if question is optional or not - if question_value is None or question_value == '': - if question.get("optional", False): - # Argument is optional, keep an empty value - # and that's all for this question! - parsed_answers_dict[question_name] = ('', question_type) - continue - else: - # The argument is required ! - raise YunohostError('app_argument_required', name=question_name) - - # Validate argument choice - if question_choices and question_value not in question_choices: - raise YunohostError('app_argument_choice_invalid', name=question_name, choices=', '.join(question_choices)) - - # Validate argument type - if question_type == 'domain': - if question_value not in domain_list()['domains']: - raise YunohostError('app_argument_invalid', name=question_name, error=m18n.n('domain_unknown')) - elif question_type == 'user': - if question_value not in user_list()["users"].keys(): - raise YunohostError('app_argument_invalid', name=question_name, error=m18n.n('user_unknown', user=question_value)) - elif question_type == 'app': - if not _is_installed(question_value): - raise YunohostError('app_argument_invalid', name=question_name, error=m18n.n('app_unknown')) - elif question_type == 'boolean': - if isinstance(question_value, bool): - question_value = 1 if question_value else 0 - else: - if str(question_value).lower() in ["1", "yes", "y"]: - question_value = 1 - elif str(question_value).lower() in ["0", "no", "n"]: - question_value = 0 - else: - raise YunohostError('app_argument_choice_invalid', name=question_name, choices='yes, no, y, n, 1, 0') - elif question_type == 'password': - forbidden_chars = "{}" - if any(char in question_value for char in forbidden_chars): - raise YunohostError('pattern_password_app', forbidden_chars=forbidden_chars) - from yunohost.utils.password import assert_password_is_strong_enough - assert_password_is_strong_enough('user', question_value) - parsed_answers_dict[question_name] = (question_value, question_type) + answer = parser.parse(question=question, user_answers=user_answers) + if answer is not None: + parsed_answers_dict[question["name"]] = answer return parsed_answers_dict diff --git a/src/yunohost/tests/test_apps_arguments_parsing.py b/src/yunohost/tests/test_apps_arguments_parsing.py index a3d5b7f09..c127cc414 100644 --- a/src/yunohost/tests/test_apps_arguments_parsing.py +++ b/src/yunohost/tests/test_apps_arguments_parsing.py @@ -705,15 +705,16 @@ def test_parse_args_in_yunohost_format_boolean_input_test_ask_with_default(): def test_parse_args_in_yunohost_format_domain_empty(): questions = [{"name": "some_domain", "type": "domain",}] + main_domain = "my_main_domain.com" + expected_result = OrderedDict({"some_domain": (main_domain, "domain")}) answers = {} with patch.object( domain, "_get_maindomain", return_value="my_main_domain.com" ), patch.object( - domain, "domain_list", return_value={"domains": ["my_main_domain.com"]} + domain, "domain_list", return_value={"domains": [main_domain]} ): - with pytest.raises(YunohostError): - _parse_args_in_yunohost_format(answers, questions) + assert _parse_args_in_yunohost_format(answers, questions) == expected_result def test_parse_args_in_yunohost_format_domain(): From 40dc8397c130581a73135f0c2fc6149fc30fa82a Mon Sep 17 00:00:00 2001 From: Laurent Peuch Date: Mon, 1 Jun 2020 11:43:39 +0200 Subject: [PATCH 10/71] [mod] stop skipping tests that now works --- src/yunohost/tests/test_apps_arguments_parsing.py | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/yunohost/tests/test_apps_arguments_parsing.py b/src/yunohost/tests/test_apps_arguments_parsing.py index c127cc414..5eed5bdfe 100644 --- a/src/yunohost/tests/test_apps_arguments_parsing.py +++ b/src/yunohost/tests/test_apps_arguments_parsing.py @@ -70,7 +70,6 @@ def test_parse_args_in_yunohost_format_string_input(): assert _parse_args_in_yunohost_format(answers, questions) == expected_result -@pytest.mark.skip # that shit should work x( def test_parse_args_in_yunohost_format_string_input_no_ask(): questions = [{"name": "some_string",}] answers = {} @@ -96,7 +95,6 @@ def test_parse_args_in_yunohost_format_string_optional_with_input(): assert _parse_args_in_yunohost_format(answers, questions) == expected_result -@pytest.mark.skip # this should work without ask def test_parse_args_in_yunohost_format_string_optional_with_input_without_ask(): questions = [{"name": "some_string", "optional": True,}] answers = {} @@ -237,7 +235,6 @@ def test_parse_args_in_yunohost_format_password_input(): assert _parse_args_in_yunohost_format(answers, questions) == expected_result -@pytest.mark.skip # that shit should work x( def test_parse_args_in_yunohost_format_password_input_no_ask(): questions = [{"name": "some_password", "type": "password",}] answers = {} @@ -270,7 +267,6 @@ def test_parse_args_in_yunohost_format_password_optional_with_input(): assert _parse_args_in_yunohost_format(answers, questions) == expected_result -@pytest.mark.skip # this should work without ask def test_parse_args_in_yunohost_format_password_optional_with_input_without_ask(): questions = [{"name": "some_password", "type": "password", "optional": True,}] answers = {} @@ -388,7 +384,6 @@ def test_parse_args_in_yunohost_format_path_input(): assert _parse_args_in_yunohost_format(answers, questions) == expected_result -@pytest.mark.skip # that shit should work x( def test_parse_args_in_yunohost_format_path_input_no_ask(): questions = [{"name": "some_path", "type": "path",}] answers = {} @@ -416,7 +411,6 @@ def test_parse_args_in_yunohost_format_path_optional_with_input(): assert _parse_args_in_yunohost_format(answers, questions) == expected_result -@pytest.mark.skip # this should work without ask def test_parse_args_in_yunohost_format_path_optional_with_input_without_ask(): questions = [{"name": "some_path", "type": "path", "optional": True,}] answers = {} @@ -604,11 +598,10 @@ def test_parse_args_in_yunohost_format_boolean_input(): assert _parse_args_in_yunohost_format(answers, questions) == expected_result -@pytest.mark.skip # we should work def test_parse_args_in_yunohost_format_boolean_input_no_ask(): questions = [{"name": "some_boolean", "type": "boolean",}] answers = {} - expected_result = OrderedDict({"some_boolean": ("some_value", "boolean")}) + expected_result = OrderedDict({"some_boolean": (1, "boolean")}) with patch.object(msignals, "prompt", return_value="y"): assert _parse_args_in_yunohost_format(answers, questions) == expected_result @@ -660,7 +653,6 @@ def test_parse_args_in_yunohost_format_boolean_no_input_default(): assert _parse_args_in_yunohost_format(answers, questions) == expected_result -@pytest.mark.skip # we should raise def test_parse_args_in_yunohost_format_boolean_bad_default(): questions = [ { @@ -769,7 +761,6 @@ def test_parse_args_in_yunohost_format_domain_two_domains_wrong_answer(): _parse_args_in_yunohost_format(answers, questions) -@pytest.mark.skip # XXX should work def test_parse_args_in_yunohost_format_domain_two_domains_default_no_ask(): main_domain = "my_main_domain.com" other_domain = "some_other_domain.tld" From dc6a12f14b9ef3b1d27df97203cc925c73f5f79b Mon Sep 17 00:00:00 2001 From: Laurent Peuch Date: Mon, 1 Jun 2020 12:02:04 +0200 Subject: [PATCH 11/71] [mod] password argument can't have a default value --- locales/en.json | 1 + src/yunohost/app.py | 8 ++++++++ src/yunohost/tests/test_apps_arguments_parsing.py | 1 - 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/locales/en.json b/locales/en.json index 851656532..5952e8b2a 100644 --- a/locales/en.json +++ b/locales/en.json @@ -13,6 +13,7 @@ "app_already_up_to_date": "{app:s} is already up-to-date", "app_argument_choice_invalid": "Use one of these choices '{choices:s}' for the argument '{name:s}'", "app_argument_invalid": "Pick a valid value for the argument '{name:s}': {error:s}", + "app_argument_password_no_default": "Error while parsing password argument '{name}': password argument can't have a default value for security reason", "app_argument_required": "Argument '{name:s}' is required", "app_change_url_failed_nginx_reload": "Could not reload NGINX. Here is the output of 'nginx -t':\n{nginx_errors:s}", "app_change_url_identical_domains": "The old and new domain/url_path are identical ('{domain:s}{path:s}'), nothing to do.", diff --git a/src/yunohost/app.py b/src/yunohost/app.py index 027a3a558..4ec043687 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -2468,6 +2468,14 @@ class PasswordArgumentParser(YunoHostArgumentFormatParser): argument_type = "password" default_value = "" + def parse_question(self, question, user_answers): + question = super(PasswordArgumentParser, self).parse_question(question, user_answers) + + if question.default is not None: + raise YunohostError('app_argument_password_no_default', name=question.name) + + return question + class PathArgumentParser(YunoHostArgumentFormatParser): argument_type = "path" diff --git a/src/yunohost/tests/test_apps_arguments_parsing.py b/src/yunohost/tests/test_apps_arguments_parsing.py index 5eed5bdfe..7b835c410 100644 --- a/src/yunohost/tests/test_apps_arguments_parsing.py +++ b/src/yunohost/tests/test_apps_arguments_parsing.py @@ -276,7 +276,6 @@ def test_parse_args_in_yunohost_format_password_optional_with_input_without_ask( assert _parse_args_in_yunohost_format(answers, questions) == expected_result -@pytest.mark.skip # this should raises def test_parse_args_in_yunohost_format_password_no_input_default(): questions = [ { From ecb52b4f1187e6e977ede50f2748c1ed009d3586 Mon Sep 17 00:00:00 2001 From: Laurent Peuch Date: Mon, 1 Jun 2020 12:37:10 +0200 Subject: [PATCH 12/71] [fix] allow optional app argument --- src/yunohost/app.py | 2 +- src/yunohost/tests/test_apps_arguments_parsing.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index 4ec043687..4abaaecca 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -2429,7 +2429,7 @@ class YunoHostArgumentFormatParser(object): if not question.optional and question.default is None: raise YunohostError('app_argument_required', name=question.name) else: - question.value = self.default_value if question.default is None else question.default + question.value = getattr(self, "default_value", None) if question.default is None else question.default # we have an answer, do some post checks if question.value is not None: diff --git a/src/yunohost/tests/test_apps_arguments_parsing.py b/src/yunohost/tests/test_apps_arguments_parsing.py index 7b835c410..1ea73cc0a 100644 --- a/src/yunohost/tests/test_apps_arguments_parsing.py +++ b/src/yunohost/tests/test_apps_arguments_parsing.py @@ -1011,14 +1011,14 @@ def test_parse_args_in_yunohost_format_app_no_apps(): _parse_args_in_yunohost_format(answers, questions) -@pytest.mark.skip # XXX should work def test_parse_args_in_yunohost_format_app_no_apps_optional(): apps = [] questions = [{"name": "some_app", "type": "app", "optional": True}] answers = {} + expected_result = OrderedDict({"some_app": (None, "app")}) with patch.object(app, "app_list", return_value={"apps": apps}): - assert _parse_args_in_yunohost_format(answers, questions) == [] + assert _parse_args_in_yunohost_format(answers, questions) == expected_result def test_parse_args_in_yunohost_format_app(): From 1ff3c1cd0799bed749b48d97eb010af3c8224960 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Pi=C3=A9dallu?= Date: Sun, 21 Jun 2020 14:15:46 +0200 Subject: [PATCH 13/71] Add default domain to API response --- src/yunohost/domain.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/yunohost/domain.py b/src/yunohost/domain.py index e1d2b1649..f76ab2bb0 100644 --- a/src/yunohost/domain.py +++ b/src/yunohost/domain.py @@ -61,7 +61,11 @@ def domain_list(exclude_subdomains=False): continue result_list.append(domain) - return {'domains': result_list} + result_list.sort() + return { + 'domains': result_list, + 'default': result_list.index(_get_maindomain()) + } @is_unit_operation() @@ -89,7 +93,7 @@ def domain_add(operation_logger, domain, dyndns=False): raise YunohostError('domain_exists') operation_logger.start() - + # Lower domain to avoid some edge cases issues # See: https://forum.yunohost.org/t/invalid-domain-causes-diagnosis-web-to-fail-fr-on-demand/11765 domain = domain.lower() From 49b91460654718c9637fdf6091220b433c46bbaf Mon Sep 17 00:00:00 2001 From: Laurent Peuch Date: Fri, 3 Jul 2020 00:33:44 +0200 Subject: [PATCH 14/71] [fix] reintroduce custom exceptions for input fields type --- src/yunohost/app.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index 4abaaecca..9c76e73eb 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -2434,8 +2434,7 @@ class YunoHostArgumentFormatParser(object): # we have an answer, do some post checks if question.value is not None: if question.choices and question.value not in question.choices: - raise YunohostError('app_argument_choice_invalid', name=question.name, - choices=', '.join(question.choices)) + self._raise_invalide_answer(question) # this is done to enforce a certain formating like for boolean # by default it doesn't do anything @@ -2443,6 +2442,10 @@ class YunoHostArgumentFormatParser(object): return (question.value, self.argument_type) + def _raise_invalide_answer(self, question): + raise YunohostError('app_argument_choice_invalid', name=question.name, + choices=', '.join(question.choices)) + def _format_text_for_user_input_in_cli(self, question): text_for_user_input_in_cli = _value_for_locale(question.ask) @@ -2534,6 +2537,10 @@ class DomainArgumentParser(YunoHostArgumentFormatParser): return question + def _raise_invalide_answer(self, question): + raise YunohostError('app_argument_invalid', name=question.name, + error=m18n.n('domain_unknown')) + class UserArgumentParser(YunoHostArgumentFormatParser): argument_type = "user" @@ -2546,6 +2553,10 @@ class UserArgumentParser(YunoHostArgumentFormatParser): return question + def _raise_invalide_answer(self, question): + raise YunohostError('app_argument_invalid', name=question.name, + error=m18n.n('user_unknown', user=question.value)) + class AppArgumentParser(YunoHostArgumentFormatParser): argument_type = "app" @@ -2558,6 +2569,10 @@ class AppArgumentParser(YunoHostArgumentFormatParser): return question + def _raise_invalide_answer(self, question): + raise YunohostError('app_argument_invalid', name=question.name, + error=m18n.n('app_unknown')) + class DisplayTextArgumentParser(YunoHostArgumentFormatParser): From 2eb5f6b6da3d398f890c68240da2786852e01726 Mon Sep 17 00:00:00 2001 From: Laurent Peuch Date: Fri, 3 Jul 2020 00:49:14 +0200 Subject: [PATCH 15/71] [fix] re-put forbidding some chars in passwords --- src/yunohost/app.py | 7 +++++++ .../tests/test_apps_arguments_parsing.py | 17 ++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index 9c76e73eb..a3244abe1 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -2470,6 +2470,7 @@ class PasswordArgumentParser(YunoHostArgumentFormatParser): hide_user_input_in_prompt = True argument_type = "password" default_value = "" + forbidden_chars = "{}" def parse_question(self, question, user_answers): question = super(PasswordArgumentParser, self).parse_question(question, user_answers) @@ -2479,6 +2480,12 @@ class PasswordArgumentParser(YunoHostArgumentFormatParser): return question + def _post_parse_value(self, question): + if any(char in question.value for char in self.forbidden_chars): + raise YunohostError('pattern_password_app', forbidden_chars=self.forbidden_chars) + + return super(PasswordArgumentParser, self)._post_parse_value(question) + class PathArgumentParser(YunoHostArgumentFormatParser): argument_type = "path" diff --git a/src/yunohost/tests/test_apps_arguments_parsing.py b/src/yunohost/tests/test_apps_arguments_parsing.py index 1ea73cc0a..9576ce0bf 100644 --- a/src/yunohost/tests/test_apps_arguments_parsing.py +++ b/src/yunohost/tests/test_apps_arguments_parsing.py @@ -8,7 +8,7 @@ from collections import OrderedDict from moulinette import msignals from yunohost import domain, user, app -from yunohost.app import _parse_args_in_yunohost_format +from yunohost.app import _parse_args_in_yunohost_format, PasswordArgumentParser from yunohost.utils.error import YunohostError @@ -359,6 +359,21 @@ def test_parse_args_in_yunohost_format_password_input_test_ask_with_help(): assert help_text in prompt.call_args[0][0] +def test_parse_args_in_yunohost_format_password_bad_chars(): + questions = [ + { + "name": "some_password", + "type": "password", + "ask": "some question", + "example": "some_value", + } + ] + + for i in PasswordArgumentParser.forbidden_chars: + with pytest.raises(YunohostError): + _parse_args_in_yunohost_format({"some_password": i * 8}, questions) + + def test_parse_args_in_yunohost_format_path(): questions = [{"name": "some_path", "type": "path",}] answers = {"some_path": "some_value"} From bcd2364d74378753b7d16bc5db9f7b2113706196 Mon Sep 17 00:00:00 2001 From: Laurent Peuch Date: Fri, 3 Jul 2020 00:57:09 +0200 Subject: [PATCH 16/71] [fix] re-put assert password is strong enough --- src/yunohost/app.py | 3 +++ .../tests/test_apps_arguments_parsing.py | 23 +++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index a3244abe1..1aba439e8 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -2484,6 +2484,9 @@ class PasswordArgumentParser(YunoHostArgumentFormatParser): if any(char in question.value for char in self.forbidden_chars): raise YunohostError('pattern_password_app', forbidden_chars=self.forbidden_chars) + from yunohost.utils.password import assert_password_is_strong_enough + assert_password_is_strong_enough('user', question.value) + return super(PasswordArgumentParser, self)._post_parse_value(question) diff --git a/src/yunohost/tests/test_apps_arguments_parsing.py b/src/yunohost/tests/test_apps_arguments_parsing.py index 9576ce0bf..8224c443e 100644 --- a/src/yunohost/tests/test_apps_arguments_parsing.py +++ b/src/yunohost/tests/test_apps_arguments_parsing.py @@ -247,8 +247,9 @@ def test_parse_args_in_yunohost_format_password_input_no_ask(): def test_parse_args_in_yunohost_format_password_no_input_optional(): questions = [{"name": "some_password", "type": "password", "optional": True,}] answers = {} - expected_result = OrderedDict({"some_password": ("", "password")}) - assert _parse_args_in_yunohost_format(answers, questions) == expected_result + + with pytest.raises(YunohostError): + _parse_args_in_yunohost_format(answers, questions) def test_parse_args_in_yunohost_format_password_optional_with_input(): @@ -374,6 +375,24 @@ def test_parse_args_in_yunohost_format_password_bad_chars(): _parse_args_in_yunohost_format({"some_password": i * 8}, questions) +def test_parse_args_in_yunohost_format_password_strong_enough(): + questions = [ + { + "name": "some_password", + "type": "password", + "ask": "some question", + "example": "some_value", + } + ] + + with pytest.raises(YunohostError): + # too short + _parse_args_in_yunohost_format({"some_password": "a"}, questions) + + with pytest.raises(YunohostError): + _parse_args_in_yunohost_format({"some_password": "password"}, questions) + + def test_parse_args_in_yunohost_format_path(): questions = [{"name": "some_path", "type": "path",}] answers = {"some_path": "some_value"} From 5807d256679a07d1da96e16fee3751c5bffc1cb3 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sun, 6 Sep 2020 21:24:06 +0200 Subject: [PATCH 17/71] Add possibility to download backups --- data/actionsmap/yunohost.yml | 8 ++++++++ src/yunohost/backup.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/data/actionsmap/yunohost.yml b/data/actionsmap/yunohost.yml index 4acd4edd3..0c19a5e48 100644 --- a/data/actionsmap/yunohost.yml +++ b/data/actionsmap/yunohost.yml @@ -913,6 +913,14 @@ backup: help: Print sizes in human readable format action: store_true + ### backup_download() + download: + action_help: (API only) Request to download the file + api: GET /backup/download/ + arguments: + name: + help: Name of the local backup archive + ### backup_delete() delete: action_help: Delete a backup archive diff --git a/src/yunohost/backup.py b/src/yunohost/backup.py index bfe958a89..0780d9044 100644 --- a/src/yunohost/backup.py +++ b/src/yunohost/backup.py @@ -2186,6 +2186,36 @@ def backup_list(with_info=False, human_readable=False): return {'archives': archives} +def backup_download(name): + + if msettings.get('interface') != 'api': + logger.error("This option is only meant for the API/webadmin and doesn't make sense for the command line.") + return + + archive_file = '%s/%s.tar' % (ARCHIVES_PATH, name) + + # Check file exist (even if it's a broken symlink) + if not os.path.lexists(archive_file): + archive_file += ".gz" + if not os.path.lexists(archive_file): + raise YunohostError('backup_archive_name_unknown', name=name) + + # If symlink, retrieve the real path + if os.path.islink(archive_file): + archive_file = os.path.realpath(archive_file) + + # Raise exception if link is broken (e.g. on unmounted external storage) + if not os.path.exists(archive_file): + raise YunohostError('backup_archive_broken_link', + path=archive_file) + + # We return a raw bottle HTTPresponse (instead of serializable data like + # list/dict, ...), which is gonna be picked and used directly by moulinette + from bottle import static_file + archive_folder, archive_file_name = archive_file.rsplit("/", 1) + return static_file(archive_file_name, archive_folder, download=archive_file_name) + + def backup_info(name, with_details=False, human_readable=False): """ Get info about a local backup archive From 9a2a6385bb225bdcf56c14a3bc2e77e560ef0e07 Mon Sep 17 00:00:00 2001 From: SiM Date: Tue, 8 Sep 2020 18:10:34 +0200 Subject: [PATCH 18/71] move BACKUP_CORE_ONLY msg to standard output --- data/helpers.d/backup | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/helpers.d/backup b/data/helpers.d/backup index a62f6c104..27f6ddf26 100644 --- a/data/helpers.d/backup +++ b/data/helpers.d/backup @@ -67,9 +67,9 @@ ynh_backup() { then if [ $BACKUP_CORE_ONLY -eq 1 ] then - ynh_print_warn --message="$src_path will not be saved, because 'BACKUP_CORE_ONLY' is set." + ynh_print_info --message="$src_path will not be saved, because 'BACKUP_CORE_ONLY' is set." else - ynh_print_warn --message="$src_path will not be saved, because 'do_not_backup_data' is set." + ynh_print_info --message="$src_path will not be saved, because 'do_not_backup_data' is set." fi return 0 fi From db93307feaedc8f9aebf4d0021c87edef9773a85 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 8 Sep 2020 19:48:05 +0200 Subject: [PATCH 19/71] Update src/yunohost/app.py Co-authored-by: Kayou --- src/yunohost/app.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index a36bd1d85..3c9b9d352 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -2683,6 +2683,12 @@ class UserArgumentParser(YunoHostArgumentFormatParser): question = super(UserArgumentParser, self).parse_question(question, user_answers) question.choices = user_list()["users"] + if question.default is None: + root_mail = "root@%s" % _get_maindomain() + for user in question.choices.keys(): + if root_mail in user_info(user)["mail-aliases"]: + question.default = user + break return question From 07fb33597239bc8214fece2032acab4c6f79e4e2 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 8 Sep 2020 21:20:40 +0200 Subject: [PATCH 20/71] Missing imports --- src/yunohost/app.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index 3c9b9d352..bd6987efd 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -2679,7 +2679,8 @@ class UserArgumentParser(YunoHostArgumentFormatParser): argument_type = "user" def parse_question(self, question, user_answers): - from yunohost.user import user_list + from yunohost.user import user_list, user_info + from yunohost.domain import _get_maindomain question = super(UserArgumentParser, self).parse_question(question, user_answers) question.choices = user_list()["users"] From b9189b1979db2a640faa742ca19a545498e73941 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 9 Sep 2020 23:58:30 +0200 Subject: [PATCH 21/71] Fix tests --- locales/en.json | 1 - src/yunohost/app.py | 1 + .../tests/test_apps_arguments_parsing.py | 22 +++++++++++-------- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/locales/en.json b/locales/en.json index 67ef69922..9fb31c663 100644 --- a/locales/en.json +++ b/locales/en.json @@ -600,7 +600,6 @@ "user_unknown": "Unknown user: {user:s}", "user_update_failed": "Could not update user {user}: {error}", "user_updated": "User info changed", - "users_available": "Available users:", "yunohost_already_installed": "YunoHost is already installed", "yunohost_ca_creation_failed": "Could not create certificate authority", "yunohost_ca_creation_success": "Local certification authority created.", diff --git a/src/yunohost/app.py b/src/yunohost/app.py index aab4f2a41..336e2a71b 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -2715,6 +2715,7 @@ class AppArgumentParser(YunoHostArgumentFormatParser): class DisplayTextArgumentParser(YunoHostArgumentFormatParser): + argument_type = "display_text" def parse(self, question, user_answers): print(question["ask"]) diff --git a/src/yunohost/tests/test_apps_arguments_parsing.py b/src/yunohost/tests/test_apps_arguments_parsing.py index 79e87b7bc..dede7a0f9 100644 --- a/src/yunohost/tests/test_apps_arguments_parsing.py +++ b/src/yunohost/tests/test_apps_arguments_parsing.py @@ -883,7 +883,8 @@ def test_parse_args_in_yunohost_format_user(): expected_result = OrderedDict({"some_user": (username, "user")}) with patch.object(user, "user_list", return_value={"users": users}): - assert _parse_args_in_yunohost_format(answers, questions) == expected_result + with patch.object(user, "user_info", return_value={}): + assert _parse_args_in_yunohost_format(answers, questions) == expected_result def test_parse_args_in_yunohost_format_user_two_users(): @@ -913,13 +914,15 @@ def test_parse_args_in_yunohost_format_user_two_users(): expected_result = OrderedDict({"some_user": (other_user, "user")}) with patch.object(user, "user_list", return_value={"users": users}): - assert _parse_args_in_yunohost_format(answers, questions) == expected_result + with patch.object(user, "user_info", return_value={}): + assert _parse_args_in_yunohost_format(answers, questions) == expected_result answers = {"some_user": username} expected_result = OrderedDict({"some_user": (username, "user")}) with patch.object(user, "user_list", return_value={"users": users}): - assert _parse_args_in_yunohost_format(answers, questions) == expected_result + with patch.object(user, "user_info", return_value={}): + assert _parse_args_in_yunohost_format(answers, questions) == expected_result def test_parse_args_in_yunohost_format_user_two_users_wrong_answer(): @@ -1008,13 +1011,14 @@ def test_parse_args_in_yunohost_format_user_two_users_default_input(): answers = {} with patch.object(user, "user_list", return_value={"users": users}): - expected_result = OrderedDict({"some_user": (username, "user")}) - with patch.object(msignals, "prompt", return_value=username): - assert _parse_args_in_yunohost_format(answers, questions) == expected_result + with patch.object(user, "user_info", return_value={}): + expected_result = OrderedDict({"some_user": (username, "user")}) + with patch.object(msignals, "prompt", return_value=username): + assert _parse_args_in_yunohost_format(answers, questions) == expected_result - expected_result = OrderedDict({"some_user": (other_user, "user")}) - with patch.object(msignals, "prompt", return_value=other_user): - assert _parse_args_in_yunohost_format(answers, questions) == expected_result + expected_result = OrderedDict({"some_user": (other_user, "user")}) + with patch.object(msignals, "prompt", return_value=other_user): + assert _parse_args_in_yunohost_format(answers, questions) == expected_result def test_parse_args_in_yunohost_format_app_empty(): From ce9689e0ef79182204314646bdeb7c52ac791903 Mon Sep 17 00:00:00 2001 From: "ljf (zamentur)" Date: Thu, 10 Sep 2020 03:27:13 +0200 Subject: [PATCH 22/71] [enh] Force encrypt if we are using an smtp relay Thanks to @khimaros for this suggestion --- data/templates/postfix/main.cf | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/data/templates/postfix/main.cf b/data/templates/postfix/main.cf index b15964241..43151e672 100644 --- a/data/templates/postfix/main.cf +++ b/data/templates/postfix/main.cf @@ -52,8 +52,12 @@ smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache smtpd_tls_loglevel=1 # -- TLS for outgoing connections +{% if smtp_relayhost %} +smtp_tls_security_level = encrypt +{% else %} # Use TLS if this is supported by the remote SMTP server, otherwise use plaintext. -smtp_tls_security_level=may +smtp_tls_security_level = may +{% endif %} smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache smtp_tls_exclude_ciphers = aNULL, MD5, DES, ADH, RC4, 3DES smtp_tls_mandatory_ciphers= high From bc2de62c7bf97f4bde4e3be6e9eb0c8a2307a696 Mon Sep 17 00:00:00 2001 From: "ljf (zamentur)" Date: Thu, 10 Sep 2020 03:29:09 +0200 Subject: [PATCH 23/71] [fix] Typo in setting name --- data/templates/postfix/main.cf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/templates/postfix/main.cf b/data/templates/postfix/main.cf index 43151e672..4d27498c4 100644 --- a/data/templates/postfix/main.cf +++ b/data/templates/postfix/main.cf @@ -52,7 +52,7 @@ smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache smtpd_tls_loglevel=1 # -- TLS for outgoing connections -{% if smtp_relayhost %} +{% if relay_host != "" %} smtp_tls_security_level = encrypt {% else %} # Use TLS if this is supported by the remote SMTP server, otherwise use plaintext. From 78c5ea9098bf196705079846287a84786dc34212 Mon Sep 17 00:00:00 2001 From: ljf Date: Thu, 10 Sep 2020 04:02:25 +0200 Subject: [PATCH 24/71] [enh] Refactoring of package download process --- src/yunohost/app.py | 127 +++++++++++++------------------------------- 1 file changed, 37 insertions(+), 90 deletions(-) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index dfea9dc52..d2b93ee34 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -39,6 +39,7 @@ from collections import OrderedDict from moulinette import msignals, m18n, msettings from moulinette.utils.log import getActionLogger from moulinette.utils.network import download_json +from moulinette.utils.process import run_commands from moulinette.utils.filesystem import read_file, read_json, read_toml, read_yaml, write_to_file, write_to_json, write_to_yaml, chmod, chown, mkdir from yunohost.service import service_status, _run_service_command @@ -2237,61 +2238,15 @@ def _fetch_app_from_git(app): logger.debug(m18n.n('downloading')) + # Extract URL, branch and revision to download if ('@' in app) or ('http://' in app) or ('https://' in app): url = app branch = 'master' - github_repo = re_github_repo.match(app) - if github_repo: - if github_repo.group('tree'): - branch = github_repo.group('tree') - url = "https://github.com/{owner}/{repo}".format( - owner=github_repo.group('owner'), - repo=github_repo.group('repo'), - ) - tarball_url = "{url}/archive/{tree}.zip".format( - url=url, tree=branch - ) - try: - subprocess.check_call([ - 'wget', '-qO', app_tmp_archive, tarball_url]) - except subprocess.CalledProcessError: - logger.exception('unable to download %s', tarball_url) - raise YunohostError('app_sources_fetch_failed') - else: - manifest, extracted_app_folder = _extract_app_from_file( - app_tmp_archive, remove=True) - else: - tree_index = url.rfind('/tree/') - if tree_index > 0: - url = url[:tree_index] - branch = app[tree_index + 6:] - try: - # We use currently git 2.1 so we can't use --shallow-submodules - # option. When git will be in 2.9 (with the new debian version) - # we will be able to use it. Without this option all the history - # of the submodules repo is downloaded. - subprocess.check_call([ - 'git', 'clone', '-b', branch, '--single-branch', '--recursive', '--depth=1', url, - extracted_app_folder]) - subprocess.check_call([ - 'git', 'reset', '--hard', branch - ], cwd=extracted_app_folder) - manifest = _get_manifest_of_app(extracted_app_folder) - except subprocess.CalledProcessError: - raise YunohostError('app_sources_fetch_failed') - except ValueError as e: - raise YunohostError('app_manifest_invalid', error=e) - else: - logger.debug(m18n.n('done')) - - # Store remote repository info into the returned manifest - manifest['remote'] = {'type': 'git', 'url': url, 'branch': branch} - try: - revision = _get_git_last_commit_hash(url, branch) - except Exception as e: - logger.debug("cannot get last commit hash because: %s ", e) - else: - manifest['remote']['revision'] = revision + tree_index = url.rfind('/tree/') + if tree_index > 0: + url = url[:tree_index] + branch = app[tree_index + 6:] + revision = 'HEAD' else: app_dict = _load_apps_catalog()["apps"] @@ -2303,47 +2258,39 @@ def _fetch_app_from_git(app): raise YunohostError('app_unsupported_remote_type') app_info = app_dict[app_id] - app_info['manifest']['lastUpdate'] = app_info['lastUpdate'] - manifest = app_info['manifest'] url = app_info['git']['url'] + branch = app_info['git']['branch'] + revision = str(app_info['git']['revision']) - if 'github.com' in url: - tarball_url = "{url}/archive/{tree}.zip".format( - url=url, tree=app_info['git']['revision'] - ) - try: - subprocess.check_call([ - 'wget', '-qO', app_tmp_archive, tarball_url]) - except subprocess.CalledProcessError: - logger.exception('unable to download %s', tarball_url) - raise YunohostError('app_sources_fetch_failed') - else: - manifest, extracted_app_folder = _extract_app_from_file( - app_tmp_archive, remove=True) - else: - try: - subprocess.check_call([ - 'git', 'clone', app_info['git']['url'], - '-b', app_info['git']['branch'], extracted_app_folder]) - subprocess.check_call([ - 'git', 'reset', '--hard', - str(app_info['git']['revision']) - ], cwd=extracted_app_folder) - manifest = _get_manifest_of_app(extracted_app_folder) - except subprocess.CalledProcessError: - raise YunohostError('app_sources_fetch_failed') - except ValueError as e: - raise YunohostError('app_manifest_invalid', error=e) - else: - logger.debug(m18n.n('done')) + # Download only this commit + try: + # We don't use git clone because, git clone can't download + # a specific revision only + run_commands([['git', 'init', extracted_app_folder]], shell=False) + run_commands([ + ['git', 'remote', 'add', 'origin', url], + ['git', 'fetch', '--depth=1', 'origin', + branch if revision == 'HEAD' else revision], + ['git', 'reset', '--hard', 'FETCH_HEAD'] + ], cwd=extracted_app_folder, shell=False) + manifest = _get_manifest_of_app(extracted_app_folder) + except subprocess.CalledProcessError: + raise YunohostError('app_sources_fetch_failed') + except ValueError as e: + raise YunohostError('app_manifest_invalid', error=e) + else: + logger.debug(m18n.n('done')) - # Store remote repository info into the returned manifest - manifest['remote'] = { - 'type': 'git', - 'url': url, - 'branch': app_info['git']['branch'], - 'revision': app_info['git']['revision'], - } + # Store remote repository info into the returned manifest + manifest['remote'] = {'type': 'git', 'url': url, 'branch': branch} + if revision == 'HEAD': + try: + manifest['remote']['revision'] = _get_git_last_commit_hash(url, branch) + except Exception as e: + logger.debug("cannot get last commit hash because: %s ", e) + else: + manifest['remote']['revision'] = revision + manifest['lastUpdate'] = app_info['lastUpdate'] return manifest, extracted_app_folder From 5923114b20abddc886b6d34e24517b10324522a6 Mon Sep 17 00:00:00 2001 From: "ljf (zamentur)" Date: Fri, 11 Sep 2020 20:27:40 +0200 Subject: [PATCH 25/71] [fix] Reduce right given to ynh users with ssh (#1050) * [fix] Avoid ynh user to be able to use X11 forwarding * [fix] Avoid some bad situations * [fix] Remove chroot restrictions and x11 authorization * Update comments Co-authored-by: Alexandre Aubin --- data/templates/ssh/sshd_config | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/data/templates/ssh/sshd_config b/data/templates/ssh/sshd_config index bd3efdef3..84f06d4e5 100644 --- a/data/templates/ssh/sshd_config +++ b/data/templates/ssh/sshd_config @@ -66,12 +66,19 @@ AcceptEnv LANG LC_* # SFTP stuff Subsystem sftp internal-sftp -Match User sftpusers - ForceCommand internal-sftp - ChrootDirectory /home/%u - AllowTcpForwarding no - GatewayPorts no - X11Forwarding no + +# Forbid users from using their account SSH as a VPN (even if SSH login is disabled) +AllowTcpForwarding no +AllowStreamLocalForwarding no + +# Disable .ssh/rc, which could be edited (e.g. from Nextcloud or whatever) by users to execute arbitrary commands even if SSH login is disabled +PermitUserRC no + +Match User admin,root + AllowTcpForwarding yes + AllowStreamLocalForwarding yes + PermitUserRC yes + # root login is allowed on local networks # It's meant to be a backup solution in case LDAP is down and From d2bd6b6c12618d11ee6dae5d9edcf971f4115ef1 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Sun, 3 May 2020 21:09:45 +0200 Subject: [PATCH 26/71] Add doc about is_big --- data/helpers.d/backup | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/data/helpers.d/backup b/data/helpers.d/backup index a62f6c104..b5dfd7b03 100644 --- a/data/helpers.d/backup +++ b/data/helpers.d/backup @@ -40,6 +40,24 @@ CAN_BIND=${CAN_BIND:-1} # ynh_backup "/etc/nginx/conf.d/$domain.d/$app.conf" "/conf/" # # => "/etc/nginx/conf.d/$domain.d/$app.conf","apps/wordpress/conf/$app.conf" # +# +# How to use --is_big: +# --is_big is used to specify that this part of the backup can be quite huge. +# So, you don't want that your package does backup that part during ynh_backup_before_upgrade. +# In the same way, an user may doesn't want to backup this big part of the app for +# each of his backup. And so handle that part differently. +# +# As this part of your backup may not be done, your restore script has to handle it. +# In your restore script, use --not_mandatory with ynh_restore_file +# As well in your remove script, you should not remove those data ! Or an user may end up with +# a failed upgrade restoring an app without data anymore ! +# +# To have the benefit of --is_big while doing a backup, you can whether set the environement +# variable BACKUP_CORE_ONLY to 1 (BACKUP_CORE_ONLY=1) before the backup command. It will affect +# only that backup command. +# Or set the config do_not_backup_data to 1 into the settings.yml of the app. This will affect +# all backups for this app until the setting is removed. +# # Requires YunoHost version 2.4.0 or higher. # Requires YunoHost version 3.5.0 or higher for the argument --not_mandatory ynh_backup() { From ca5f264baf2f2ab681b3692cdbccf5fe443f9371 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Mon, 14 Sep 2020 17:06:40 +0200 Subject: [PATCH 27/71] Remove pipe char when trying to re-run apt with dry-run ... Because apt becomes absolutely crazy and make every package installed conflict with weird stuff --- data/helpers.d/apt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/helpers.d/apt b/data/helpers.d/apt index 1a4a9f74a..1e880af76 100644 --- a/data/helpers.d/apt +++ b/data/helpers.d/apt @@ -198,7 +198,7 @@ ynh_package_install_from_equivs () { # (the following is ran inside { } to not start a subshell otherwise ynh_die wouldnt exit the original process) # Get the list of dependencies from the deb local dependencies="$(dpkg --info "$TMPDIR/${pkgname}_${pkgversion}_all.deb" | grep Depends | \ - sed 's/^ Depends: //' | sed 's/,//g')" + sed 's/^ Depends: //' | sed 's/,//g' | tr -d '|')" # Fake an install of those dependencies to see the errors # The sed command here is, Print only from '--fix-broken' to the end. ynh_package_install $dependencies --dry-run | sed --quiet '/--fix-broken/,$p' >&2 From 9156b1e56af2dba336305557c4f2146a7c798bc8 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Mon, 14 Sep 2020 17:54:20 +0200 Subject: [PATCH 28/71] Fix warnings and weird stuff >_> --- data/hooks/conf_regen/19-postfix | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/data/hooks/conf_regen/19-postfix b/data/hooks/conf_regen/19-postfix index 67ca22991..29787576e 100755 --- a/data/hooks/conf_regen/19-postfix +++ b/data/hooks/conf_regen/19-postfix @@ -27,22 +27,21 @@ do_pre_regen() { # Add possibility to specify a relay # Could be useful with some isp with no 25 port open or more complex setup export relay_host="$(yunohost settings get 'smtp.relay.host')" - if [ ! -z "${relay_host}" ]; then + if [ -n "${relay_host}" ] + then export relay_port="$(yunohost settings get 'smtp.relay.port')" export relay_user="$(yunohost settings get 'smtp.relay.user')" relay_password="$(yunohost settings get 'smtp.relay.password')" # Avoid to display "Relay account paswword" to other users touch ${postfix_dir}/sasl_passwd - chmod o=--- ${postfix_dir}/sasl_passwd + chmod 750 ${postfix_dir}/sasl_passwd # Avoid "postmap: warning: removing zero-length database file" chown postfix ${pending_dir}/etc/postfix chown postfix ${pending_dir}/etc/postfix/sasl_passwd cat <<< "[${relay_host}]:${relay_port} ${relay_user}:${relay_password}" > ${postfix_dir}/sasl_passwd postmap ${postfix_dir}/sasl_passwd - - fi export main_domain export domain_list="$YNH_DOMAINS" @@ -67,8 +66,12 @@ do_pre_regen() { do_post_regen() { regen_conf_files=$1 - chmod o=--- /etc/postfix/sasl_passwd* - chown postfix /etc/postfix/sasl_passwd* + + if [ -e /etc/postfix/sasl_passwd ] + then + chmod 750 /etc/postfix/sasl_passwd* + chown postfix:root /etc/postfix/sasl_passwd* + fi [[ -z "$regen_conf_files" ]] \ || { service postfix restart && service postsrsd restart; } From 15a7967f474be96d27381ecb739ac4ae09d243e9 Mon Sep 17 00:00:00 2001 From: Kayou Date: Tue, 15 Sep 2020 20:53:26 +0200 Subject: [PATCH 29/71] Epic bugfix --- data/helpers.d/php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/helpers.d/php b/data/helpers.d/php index 489c448a8..c538d8688 100644 --- a/data/helpers.d/php +++ b/data/helpers.d/php @@ -219,7 +219,7 @@ ynh_add_fpm_config () { if [ -e "../conf/php-fpm.ini" ] then - ynh_print_warn -message="Packagers ! Please do not use a separate php ini file, merge your directives in the pool file instead." + ynh_print_warn --message="Packagers ! Please do not use a separate php ini file, merge your directives in the pool file instead." finalphpini="$fpm_config_dir/conf.d/20-$app.ini" ynh_backup_if_checksum_is_different "$finalphpini" cp ../conf/php-fpm.ini "$finalphpini" From 6945867f860f5a42390f36dd88dfabd6b7e92a65 Mon Sep 17 00:00:00 2001 From: Kayou Date: Wed, 16 Sep 2020 13:23:10 +0200 Subject: [PATCH 30/71] detect wrong arguments --- data/helpers.d/getopts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/data/helpers.d/getopts b/data/helpers.d/getopts index a4bbe20e6..8d9e55826 100644 --- a/data/helpers.d/getopts +++ b/data/helpers.d/getopts @@ -130,6 +130,12 @@ ynh_handle_getopts_args () { then # Remove the option and the space, so keep only the value itself. all_args[0]="${all_args[0]#-${parameter} }" + + # At this point, if all_args[0] start with "-", then the argument is not well formed + if [ "${all_args[0]:0:1}" == "-" ] + then + ynh_die --message="Argument \"${all_args[0]}\" not valid! Did you use a single \"-\" instead of two?" + fi # Reduce the value of shift, because the option has been removed manually shift_value=$(( shift_value - 1 )) fi From 6a618b0f332606fd2a75f8398da2c69ef352e47d Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 16 Sep 2020 15:24:09 +0200 Subject: [PATCH 31/71] Use php7.3 by default in CLI --- data/hooks/conf_regen/10-apt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/data/hooks/conf_regen/10-apt b/data/hooks/conf_regen/10-apt index 4ce838e4c..5446c262c 100755 --- a/data/hooks/conf_regen/10-apt +++ b/data/hooks/conf_regen/10-apt @@ -18,6 +18,9 @@ Pin-Priority: -1" >> "/etc/apt/preferences.d/extra_php_version" do_post_regen() { regen_conf_files=$1 + + # Make sure php7.3 is the default version when using php in cli + update-alternatives --set php /usr/bin/php7.3 } FORCE=${2:-0} From 4805d43b96c24a8be2afdd61b4d8925bb0fb9efd Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 16 Sep 2020 15:27:32 +0200 Subject: [PATCH 32/71] Force locale to C during postgresql migration to avoid some stupid issue related to locale --- src/yunohost/data_migrations/0017_postgresql_9p6_to_11.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/yunohost/data_migrations/0017_postgresql_9p6_to_11.py b/src/yunohost/data_migrations/0017_postgresql_9p6_to_11.py index b81cbd8be..2f277443e 100644 --- a/src/yunohost/data_migrations/0017_postgresql_9p6_to_11.py +++ b/src/yunohost/data_migrations/0017_postgresql_9p6_to_11.py @@ -36,9 +36,9 @@ class MyMigration(Migration): raise YunohostError("migration_0017_not_enough_space", path="/var/lib/postgresql/") self.runcmd("systemctl stop postgresql") - self.runcmd("pg_dropcluster --stop 11 main || true") # We do not trigger an exception if the command fails because that probably means cluster 11 doesn't exists, which is fine because it's created during the pg_upgradecluster) - self.runcmd("pg_upgradecluster -m upgrade 9.6 main") - self.runcmd("pg_dropcluster --stop 9.6 main") + self.runcmd("LC_ALL=C pg_dropcluster --stop 11 main || true") # We do not trigger an exception if the command fails because that probably means cluster 11 doesn't exists, which is fine because it's created during the pg_upgradecluster) + self.runcmd("LC_ALL=C pg_upgradecluster -m upgrade 9.6 main") + self.runcmd("LC_ALL=C pg_dropcluster --stop 9.6 main") self.runcmd("systemctl start postgresql") def package_is_installed(self, package_name): From d243fe76ce1fe8cb8f31ec89404c8359d4974c3f Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 16 Sep 2020 16:14:03 +0200 Subject: [PATCH 33/71] [enh] Better problematic apt dependencies auto-investigation mechanism (#1051) * [enh] Better problematic apt dependencies auto-investigation mechanism * Misc tweak / fixes following tests --- data/helpers.d/apt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/data/helpers.d/apt b/data/helpers.d/apt index 1e880af76..59f233c60 100644 --- a/data/helpers.d/apt +++ b/data/helpers.d/apt @@ -191,17 +191,17 @@ ynh_package_install_from_equivs () { cp "$controlfile" "${TMPDIR}/control" (cd "$TMPDIR" LC_ALL=C equivs-build ./control 1> /dev/null - dpkg --force-depends --install "./${pkgname}_${pkgversion}_all.deb" 2>&1) + LC_ALL=C dpkg --force-depends --install "./${pkgname}_${pkgversion}_all.deb" 2>&1 | tee ./dpkg_log) ynh_package_install --fix-broken || \ { # If the installation failed # (the following is ran inside { } to not start a subshell otherwise ynh_die wouldnt exit the original process) - # Get the list of dependencies from the deb - local dependencies="$(dpkg --info "$TMPDIR/${pkgname}_${pkgversion}_all.deb" | grep Depends | \ - sed 's/^ Depends: //' | sed 's/,//g' | tr -d '|')" + # Parse the list of problematic dependencies from dpkg's log ... + # (relevant lines look like: "foo-ynh-deps depends on bar; however:") + local problematic_dependencies="$(cat $TMPDIR/dpkg_log | grep -oP '(?<=-ynh-deps depends on ).*(?=; however)' | tr '\n' ' ')" # Fake an install of those dependencies to see the errors - # The sed command here is, Print only from '--fix-broken' to the end. - ynh_package_install $dependencies --dry-run | sed --quiet '/--fix-broken/,$p' >&2 + # The sed command here is, Print only from 'Reading state info' to the end. + [[ -n "$problematic_dependencies" ]] && ynh_package_install $problematic_dependencies --dry-run 2>&1 | sed --quiet '/Reading state info/,$p' | grep -v "fix-broken\|Reading state info" >&2 ynh_die --message="Unable to install dependencies"; } [[ -n "$TMPDIR" ]] && rm --recursive --force $TMPDIR # Remove the temp dir. From a60cd4f559288e5364add334670a50fdc43ffb6a Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 16 Sep 2020 16:18:10 +0200 Subject: [PATCH 34/71] Diagnose ssl libs installed from sury (#1053) * Small fix / syntax improvement in apt conf regen hook * Diagnose, report and add a tip if some ssl libs are installed from Sury (shouldnt happen with the new pinning strategy, but some user still encounter issues because of this because of legacy installs) --- data/hooks/conf_regen/10-apt | 5 +++-- data/hooks/diagnosis/00-basesystem.py | 23 +++++++++++++++++++++++ locales/en.json | 2 ++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/data/hooks/conf_regen/10-apt b/data/hooks/conf_regen/10-apt index 5446c262c..09789470b 100755 --- a/data/hooks/conf_regen/10-apt +++ b/data/hooks/conf_regen/10-apt @@ -7,12 +7,13 @@ do_pre_regen() { mkdir --parents "${pending_dir}/etc/apt/preferences.d" - for package in "php" "php-fpm" "php-mysql" "php-xml" "php-zip" "php-mbstring" "php-ldap" "php-gd" "php-curl" "php-bz2" "php-json" "php-sqlite3" "php-intl" "openssl" "libssl1.1" "libssl-dev" + packages_to_refuse_from_sury="php php-fpm php-mysql php-xml php-zip php-mbstring php-ldap php-gd php-curl php-bz2 php-json php-sqlite3 php-intl openssl libssl1.1 libssl-dev" + for package in $packages_to_refuse_from_sury do echo " Package: $package Pin: origin \"packages.sury.org\" -Pin-Priority: -1" >> "/etc/apt/preferences.d/extra_php_version" +Pin-Priority: -1" >> "${pending_dir}/etc/apt/preferences.d/extra_php_version" done } diff --git a/data/hooks/diagnosis/00-basesystem.py b/data/hooks/diagnosis/00-basesystem.py index 8773f8b53..d58ca4aff 100644 --- a/data/hooks/diagnosis/00-basesystem.py +++ b/data/hooks/diagnosis/00-basesystem.py @@ -82,6 +82,29 @@ class BaseSystemDiagnoser(Diagnoser): details=["diagnosis_security_vulnerable_to_meltdown_details"] ) + bad_sury_packages = list(self.bad_sury_packages()) + if bad_sury_packages: + cmd_to_fix = "apt install --allow-downgrades " \ + + " ".join(["%s=%s" % (package, version) for package, version in bad_sury_packages]) + yield dict(meta={"test": "packages_from_sury"}, + data={"cmd_to_fix": cmd_to_fix}, + status="WARNING", + summary="diagnosis_package_installed_from_sury", + details=["diagnosis_package_installed_from_sury_details"]) + + def bad_sury_packages(self): + + packages_to_check = ["openssl", "libssl1.1", "libssl-dev"] + for package in packages_to_check: + cmd = "dpkg --list | grep '^ii' | grep gbp | grep -q -w %s" % package + # If version currently installed is not from sury, nothing to report + if os.system(cmd) != 0: + continue + + cmd = "LC_ALL=C apt policy %s 2>&1 | grep http -B1 | tr -d '*' | grep '+deb' | grep -v 'gbp' | head -n 1 | awk '{print $1}'" % package + version_to_downgrade_to = check_output(cmd).strip() + yield (package, version_to_downgrade_to) + def is_vulnerable_to_meltdown(self): # meltdown CVE: https://security-tracker.debian.org/tracker/CVE-2017-5754 diff --git a/locales/en.json b/locales/en.json index 340696054..1a620124b 100644 --- a/locales/en.json +++ b/locales/en.json @@ -146,6 +146,8 @@ "diagnosis_basesystem_ynh_single_version": "{package} version: {version} ({repo})", "diagnosis_basesystem_ynh_main_version": "Server is running YunoHost {main_version} ({repo})", "diagnosis_basesystem_ynh_inconsistent_versions": "You are running inconsistent versions of the YunoHost packages... most probably because of a failed or partial upgrade.", + "diagnosis_package_installed_from_sury": "Some system packages should be downgraded", + "diagnosis_package_installed_from_sury_details": "Some packages were inadvertendly installed from a third-party repository called Sury. The Yunohost team improved the strategy that handle these packages, but it's expected that some setups that installed PHP7.3 apps while still on Stretch have some remaining inconsistencies. To fix this situation, you should try running the following command: {cmd_to_fix}", "diagnosis_display_tip": "To see the issues found, you can go to the Diagnosis section of the webadmin, or run 'yunohost diagnosis show --issues' from the command-line.", "diagnosis_failed_for_category": "Diagnosis failed for category '{category}': {error}", "diagnosis_cache_still_valid": "(Cache still valid for {category} diagnosis. Won't re-diagnose it yet!)", From 674d8e7cb970d982e8cf41961c7306bb420dbfae Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 16 Sep 2020 17:01:21 +0200 Subject: [PATCH 35/71] [fix] Minor issues in app questions parsing --- src/yunohost/app.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index 97dc09621..300cc07b5 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -2542,7 +2542,7 @@ class YunoHostArgumentFormatParser(object): question.value = None # we don't have an answer, check optional and default_value - if question.value is None: + if question.value is None or question.value == '': if not question.optional and question.default is None: raise YunohostError('app_argument_required', name=question.name) else: @@ -2566,12 +2566,12 @@ class YunoHostArgumentFormatParser(object): def _format_text_for_user_input_in_cli(self, question): text_for_user_input_in_cli = _value_for_locale(question.ask) - if question.default is not None: - text_for_user_input_in_cli += ' (default: {0})'.format(question.default) - if question.choices: text_for_user_input_in_cli += ' [{0}]'.format(' | '.join(question.choices)) + if question.default is not None: + text_for_user_input_in_cli += ' (default: {0})'.format(question.default) + return text_for_user_input_in_cli def _post_parse_value(self, question): From 56ebb06d2b468f873d7b8ed5818f7bc3cf7f052f Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 16 Sep 2020 18:49:17 +0200 Subject: [PATCH 36/71] Typo --- src/yunohost/app.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index d34a18d80..5bd9d7f08 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -2498,7 +2498,7 @@ class YunoHostArgumentFormatParser(object): # we have an answer, do some post checks if question.value is not None: if question.choices and question.value not in question.choices: - self._raise_invalide_answer(question) + self._raise_invalid_answer(question) # this is done to enforce a certain formating like for boolean # by default it doesn't do anything @@ -2506,7 +2506,7 @@ class YunoHostArgumentFormatParser(object): return (question.value, self.argument_type) - def _raise_invalide_answer(self, question): + def _raise_invalid_answer(self, question): raise YunohostError('app_argument_choice_invalid', name=question.name, choices=', '.join(question.choices)) @@ -2611,7 +2611,7 @@ class DomainArgumentParser(YunoHostArgumentFormatParser): return question - def _raise_invalide_answer(self, question): + def _raise_invalid_answer(self, question): raise YunohostError('app_argument_invalid', name=question.name, error=m18n.n('domain_unknown')) @@ -2634,7 +2634,7 @@ class UserArgumentParser(YunoHostArgumentFormatParser): return question - def _raise_invalide_answer(self, question): + def _raise_invalid_answer(self, question): raise YunohostError('app_argument_invalid', name=question.name, error=m18n.n('user_unknown', user=question.value)) @@ -2650,7 +2650,7 @@ class AppArgumentParser(YunoHostArgumentFormatParser): return question - def _raise_invalide_answer(self, question): + def _raise_invalid_answer(self, question): raise YunohostError('app_argument_invalid', name=question.name, error=m18n.n('app_unknown')) From d5f8eb06c8996d66ae8de79a863241a1192b2742 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 16 Sep 2020 19:28:45 +0200 Subject: [PATCH 37/71] Simplify code (suggestion from Bram) --- src/yunohost/app.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index 5bd9d7f08..7d5d36c4d 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -60,12 +60,6 @@ APPS_CATALOG_CRON_PATH = "/etc/cron.daily/yunohost-fetch-apps-catalog" APPS_CATALOG_API_VERSION = 2 APPS_CATALOG_DEFAULT_URL = "https://app.yunohost.org/default" -re_github_repo = re.compile( - r'^(http[s]?://|git@)github.com[/:]' - '(?P[\w\-_]+)/(?P[\w\-_]+)(.git)?' - '(/tree/(?P.+))?' -) - re_app_instance_name = re.compile( r'^(?P[\w-]+?)(__(?P[1-9][0-9]*))?$' ) @@ -2242,10 +2236,8 @@ def _fetch_app_from_git(app): if ('@' in app) or ('http://' in app) or ('https://' in app): url = app branch = 'master' - tree_index = url.rfind('/tree/') - if tree_index > 0: - url = url[:tree_index] - branch = app[tree_index + 6:] + if "/tree/" in url: + url, branch = url.split("/tree/", 1) revision = 'HEAD' else: app_dict = _load_apps_catalog()["apps"] From dd92828bf680d6179593d067e6340fc3444e1495 Mon Sep 17 00:00:00 2001 From: Baptiste Wojtkowski Date: Mon, 7 Sep 2020 11:56:06 +0000 Subject: [PATCH 38/71] Translated using Weblate (French) Currently translated at 96.4% (586 of 608 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/fr/ --- locales/fr.json | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/locales/fr.json b/locales/fr.json index 022ec23a1..dd78eacd7 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -668,5 +668,22 @@ "migration_description_0015_migrate_to_buster": "Mise à niveau du système vers Debian Buster et YunoHost 4.x", "diagnosis_dns_try_dyndns_update_force": "La configuration DNS de ce domaine devrait être automatiquement gérée par Yunohost. Si ce n'est pas le cas, vous pouvez essayer de forcer une mise à jour en utilisant yunohost dyndns update --force.", "app_packaging_format_not_supported": "Cette application ne peut pas être installée car son format n'est pas pris en charge par votre version de YunoHost. Vous devriez probablement envisager de mettre à jour votre système.", - "migration_0015_weak_certs": "Il a été constaté que les certificats suivants utilisent encore des algorithmes de signature peu robustes et doivent être mis à jour pour être compatibles avec la prochaine version de nginx : {certs}" + "migration_0015_weak_certs": "Il a été constaté que les certificats suivants utilisent encore des algorithmes de signature peu robustes et doivent être mis à jour pour être compatibles avec la prochaine version de nginx : {certs}", + "global_settings_setting_backup_compress_tar_archives": "Compresser les archives (.tar.gz) au lieu de des archives non-compressées lors de la création des backups. N.B. Activer cette option implique de créer des archives plus légères, mais aussi d'avoir des procédures de backup significativement plus longues et plus gourmandes en CPU.", + "migration_description_0018_xtable_to_nftable": "Migrer les anciennes règles de trafic réseau vers les nouvelles nftables système", + "service_description_php7.3-fpm": "Lancer les applications écrites en PHP avec NGINX", + "migration_0018_failed_to_reset_legacy_rules": "La réinitialisation des règles iptable legacy a échoué :", + "migration_0018_failed_to_migrate_iptables_rules": "La migration des iptables legacy vers nftables a échoué: {error}", + "migration_0017_not_enough_space": "Laissez suffisamment d'espace disponible dans {path} avant de lancer la migration.", + "migration_0017_postgresql_11_not_installed": "PostgreSQL 9.6 est installé mais pas posgreSQL 11 ? Il s'est sans doute passé quelque chose d'étrange sur votre système :(...", + "migration_0017_postgresql_96_not_installed": "PostgreSQL n'a pas été installé sur votre système. Aucune opération à effectuer.", + "migration_description_0017_postgresql_9p6_to_11": "Migrer les bases de données de PostgreSQL 9.6 vers 11", + "migration_description_0016_php70_to_php73_pools": "Migrer php7.0-fpm 'pool' conf files vers php7.3", + "diagnosis_processes_killed_by_oom_reaper": "Certains processus ont été arrêtés récemment par le système car il manquait de mémoire. Cela apparaît généralement quand le système manque de mémoire ou qu'un processus consomme trop de mémoire. Liste des processus tués :", + "ask_user_domain": "Domaine à utiliser pour l'adresse mail des utilisateurs et le compte XMPP", + "app_manifest_install_ask_is_public": "Cette application devrait-elle apparaître aux visiteurs anonymes ?", + "app_manifest_install_ask_admin": "Choisissez un administrateur pour cette application", + "app_manifest_install_ask_password": "Choisissez un mot de passez administrateur pour cette application", + "app_manifest_install_ask_path": "Choisissez le chemin où cette application devrait être installée", + "app_manifest_install_ask_domain": "Choisissez le domaine où cette application devrait être insttallée" } From adc7a4f156bbd294507bc2b42460071040b31ddf Mon Sep 17 00:00:00 2001 From: Christian Wehrli Date: Tue, 8 Sep 2020 13:18:04 +0000 Subject: [PATCH 39/71] Translated using Weblate (French) Currently translated at 96.4% (586 of 608 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/fr/ --- locales/fr.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/locales/fr.json b/locales/fr.json index dd78eacd7..88fbf3468 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -451,10 +451,10 @@ "migrations_exclusive_options": "'auto', '--skip' et '--force-rerun' sont des options mutuellement exclusives.", "migrations_not_pending_cant_skip": "Ces migrations ne sont pas en attente et ne peuvent donc pas être ignorées : {ids}", "migration_0011_can_not_backup_before_migration": "La sauvegarde du système n’a pas pu être terminée avant l’échec de la migration. Erreur : {error:s}", - "migration_0011_migrate_permission": "Migration des autorisations des paramètres des applications vers LDAP…", + "migration_0011_migrate_permission": "Migration des autorisations des paramètres des applications vers LDAP...", "migration_0011_migration_failed_trying_to_rollback": "La migration a échoué… Tentative de restauration du système.", "migration_0011_rollback_success": "Système restauré.", - "migration_0011_update_LDAP_database": "Mise à jour de la base de données LDAP…", + "migration_0011_update_LDAP_database": "Mise à jour de la base de données LDAP...", "migration_0011_backup_before_migration": "Création d’une sauvegarde des paramètres de la base de données LDAP et des applications avant la migration.", "permission_not_found": "Autorisation '{permission:s}' introuvable", "permission_update_failed": "Impossible de mettre à jour l’autorisation '{permission}' : {error}", @@ -638,7 +638,7 @@ "diagnosis_http_partially_unreachable": "Le domaine {domain} semble inaccessible en HTTP depuis l’extérieur du réseau local en IPv{failed}, bien qu’il fonctionne en IPv{passed}.", "diagnosis_http_nginx_conf_not_up_to_date": "La configuration Nginx de ce domaine semble avoir été modifiée manuellement et empêche YunoHost de diagnostiquer si elle est accessible en HTTP.", "diagnosis_http_nginx_conf_not_up_to_date_details": "Pour corriger la situation, inspectez la différence avec la ligne de commande en utilisant les outils yunohost tools regen-conf nginx --dry-run --with-diff et si vous êtes d’accord, appliquez les modifications avec yunohost tools regen-conf nginx --force.", - "backup_archive_cant_retrieve_info_json": "Impossible d'avoir des informations sur l'archive '{archive}' ... Le fichier info.json ne peut pas être trouvé (ou n'est pas un fichier json valide).", + "backup_archive_cant_retrieve_info_json": "Impossible d'avoir des informations sur l'archive '{archive}'... Le fichier info.json ne peut pas être trouvé (ou n'est pas un fichier json valide).", "backup_archive_corrupted": "Il semble que l'archive de la sauvegarde '{archive}' est corrompue : {error}", "diagnosis_ip_no_ipv6_tip": "L'utilisation de IPv6 n'est pas obligatoire pour le fonctionnement de votre serveur, mais cela contribue à la santé d'Internet dans son ensemble. IPv6 généralement configuré automatiquement par votre système ou votre FAI s'il est disponible. Autrement, vous devrez prendre quelque minutes pour le configurer manuellement à l'aide de cette documentation: https://yunohost.org/#/ipv6. Si vous ne pouvez pas activer IPv6 ou si c'est trop technique pour vous, vous pouvez aussi ignorer cet avertissement sans que cela pose problème.", "diagnosis_domain_expiration_not_found": "Impossible de vérifier la date d'expiration de certains domaines", From 16b5257ad3e6d6188d5c5aa4a552ef2ee4a47eb2 Mon Sep 17 00:00:00 2001 From: Christian Wehrli Date: Tue, 8 Sep 2020 12:41:17 +0000 Subject: [PATCH 40/71] Translated using Weblate (German) Currently translated at 48.7% (296 of 608 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/de/ --- locales/de.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/locales/de.json b/locales/de.json index 59c48ef0c..1f4bc4850 100644 --- a/locales/de.json +++ b/locales/de.json @@ -402,5 +402,10 @@ "migration_description_0018_xtable_to_nftable": "Alte Netzwerkverkehrsregeln zum neuen nftable-System migrieren", "service_reload_failed": "Der Dienst '{service:s}' konnte nicht erneut geladen werden.\n\nKürzlich erstellte Logs des Dienstes: {logs:s}", "service_reloaded": "Der Dienst '{service:s}' wurde erneut geladen", - "service_restart_failed": "Der Dienst '{service:s}' konnte nicht erneut gestartet werden.\n\nKürzlich erstellte Logs des Dienstes: {logs:s}" + "service_restart_failed": "Der Dienst '{service:s}' konnte nicht erneut gestartet werden.\n\nKürzlich erstellte Logs des Dienstes: {logs:s}", + "app_manifest_install_ask_password": "Wählen Sie ein Verwaltungspasswort für diese Applikation", + "app_manifest_install_ask_domain": "Wählen Sie die Domäne, auf welcher die Applikation installiert werden soll", + "log_letsencrypt_cert_renew": "Erneuern des Let's Encrypt-Zeritifikates von '{}'", + "log_selfsigned_cert_install": "Das selbstsignierte Zertifikat auf der Domäne '{}' installieren", + "log_letsencrypt_cert_install": "Das Let’s Encrypt auf der Domäne '{}' installieren" } From dff93e950bba1d506026e6a72ff716b4dfb1a061 Mon Sep 17 00:00:00 2001 From: Christian Wehrli Date: Wed, 9 Sep 2020 17:06:43 +0000 Subject: [PATCH 41/71] Translated using Weblate (German) Currently translated at 50.7% (308 of 608 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/de/ --- locales/de.json | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/locales/de.json b/locales/de.json index 1f4bc4850..b43457cef 100644 --- a/locales/de.json +++ b/locales/de.json @@ -184,7 +184,7 @@ "domain_cannot_remove_main": "Die primäre Domain konnten nicht entfernt werden. Lege zuerst einen neue primäre Domain fest", "certmanager_self_ca_conf_file_not_found": "Die Konfigurationsdatei der Zertifizierungsstelle für selbstsignierte Zertifikate wurde nicht gefunden (Datei {file:s})", "certmanager_acme_not_configured_for_domain": "Die ACME Challenge kann im Moment nicht für {domain} ausgeführt werden, weil in ihrer nginx conf das entsprechende Code-Snippet fehlt... Bitte stellen Sie sicher, dass Ihre nginx-Konfiguration mit 'yunohost tools regen-conf nginx --dry-run --with-diff' auf dem neuesten Stand ist.", - "certmanager_unable_to_parse_self_CA_name": "Der Name der Zertifizierungsstelle für selbstsignierte Zertifikate konnte nicht analysiert werden (Datei: {file:s})", + "certmanager_unable_to_parse_self_CA_name": "Der Name der Zertifizierungsstelle für selbstsignierte Zertifikate konnte nicht aufgelöst werden (Datei: {file:s})", "certmanager_http_check_timeout": "Eine Zeitüberschreitung ist aufgetreten, als der Server versuchte sich selbst über HTTP mit der öffentlichen IP (Domain '{domain:s}' mit der IP '{ip:s}') zu erreichen. Möglicherweise ist dafür hairpinning oder eine falsch konfigurierte Firewall/Router deines Servers dafür verantwortlich.", "certmanager_couldnt_fetch_intermediate_cert": "Eine Zeitüberschreitung ist aufgetreten als der Server versuchte die Teilzertifikate von Let's Encrypt zusammenzusetzen. Die Installation/Erneuerung des Zertifikats wurde abgebrochen — bitte versuche es später erneut.", "domain_hostname_failed": "Erstellen des neuen Hostnamens fehlgeschlagen", @@ -407,5 +407,16 @@ "app_manifest_install_ask_domain": "Wählen Sie die Domäne, auf welcher die Applikation installiert werden soll", "log_letsencrypt_cert_renew": "Erneuern des Let's Encrypt-Zeritifikates von '{}'", "log_selfsigned_cert_install": "Das selbstsignierte Zertifikat auf der Domäne '{}' installieren", - "log_letsencrypt_cert_install": "Das Let’s Encrypt auf der Domäne '{}' installieren" + "log_letsencrypt_cert_install": "Das Let’s Encrypt auf der Domäne '{}' installieren", + "diagnosis_mail_fcrdns_nok_details": "Sie sollten zuerst versuchen, in Ihrer Internet-Router-Oberfläche oder in Ihrer Hosting-Anbieter-Oberfläche den Reverse-DNS-Eintrag mit {ehlo_domain}zu konfigurieren. (Gewisse Hosting-Anbieter können dafür möglicherweise verlangen, dass Sie dafür ein Support-Ticket erstellen).", + "diagnosis_mail_fcrdns_dns_missing": "Es wurde kein Reverse-DNS-Eintrag definiert für IPv{ipversion}. Einige E-Mails könnten möglicherweise zurückgewiesen oder als Spam markiert werden.", + "diagnosis_mail_fcrdns_ok": "Ihr Reverse-DNS-Eintrag ist korrekt konfiguriert!", + "diagnosis_mail_ehlo_could_not_diagnose_details": "Fehler: {error}", + "diagnosis_mail_ehlo_could_not_diagnose": "Konnte nicht überprüfen, ob der Postfix-Mail-Server von aussen per IPv{ipversion} erreichbar ist.", + "diagnosis_mail_ehlo_wrong_details": "Die vom Remote-Diagnose-Server per IPv{ipversion} empfangene EHLO weicht von der Domäne Ihres Servers ab.
Empfangene EHLO: {wrong_ehlo}
Erwartet: {right_ehlo}
Die geläufigste Ursache für dieses Problem ist, dass der Port 25 nicht korrekt auf Ihren Server weitergeleitet wird. Sie können sich zusätzlich auch versichern, dass keine Firewall oder Reverse-Proxy interferiert.", + "diagnosis_mail_ehlo_bad_answer_details": "Das könnte daran liegen, dass anstelle Ihres Servers eine andere Maschine antwortet.", + "ask_user_domain": "Domäne, welche für die E-Mail-Adresse und den XMPP-Account des Benutzers verwendet werden soll", + "app_manifest_install_ask_is_public": "Soll diese Applikation für anonyme Benutzer sichtbar sein?", + "app_manifest_install_ask_admin": "Wählen Sie einen Administrator für diese Applikation", + "app_manifest_install_ask_path": "Wählen Sie den Pfad, in welchem die Applikation installiert werden soll" } From e9fc4bc7f3efdbfdf38bda3273a3d8dec8ec8d25 Mon Sep 17 00:00:00 2001 From: Christian Wehrli Date: Fri, 11 Sep 2020 11:21:46 +0000 Subject: [PATCH 42/71] Translated using Weblate (German) Currently translated at 51.3% (314 of 612 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/de/ --- locales/de.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/locales/de.json b/locales/de.json index b43457cef..e27b05506 100644 --- a/locales/de.json +++ b/locales/de.json @@ -418,5 +418,11 @@ "ask_user_domain": "Domäne, welche für die E-Mail-Adresse und den XMPP-Account des Benutzers verwendet werden soll", "app_manifest_install_ask_is_public": "Soll diese Applikation für anonyme Benutzer sichtbar sein?", "app_manifest_install_ask_admin": "Wählen Sie einen Administrator für diese Applikation", - "app_manifest_install_ask_path": "Wählen Sie den Pfad, in welchem die Applikation installiert werden soll" + "app_manifest_install_ask_path": "Wählen Sie den Pfad, in welchem die Applikation installiert werden soll", + "diagnosis_mail_blacklist_listed_by": "Ihre IP-Adresse oder Domäne {item} ist auf der Blacklist auf {blacklist_name}", + "diagnosis_mail_blacklist_ok": "Die IP-Adressen und die Domänen, welche von diesem Server verwendet werden, scheinen nicht auf einer Blacklist zu sein", + "diagnosis_mail_fcrdns_different_from_ehlo_domain_details": "Aktueller Reverse-DNS-Eintrag: {rdns_domain}
Erwarteter Wert: {ehlo_domain}", + "diagnosis_mail_fcrdns_different_from_ehlo_domain": "Der Reverse-DNS-Eintrag für IPv{ipversion} ist nicht korrekt konfiguriert. Einige E-Mails könnten abgewiesen oder als Spam markiert werden.", + "diagnosis_mail_fcrdns_nok_alternatives_6": "Einige Provider werden es Ihnen nicht erlauben, Ihren Reverse-DNS-Eintrag zu konfigurieren (oder ihre Funktionalität könnte defekt sein ...). Falls Ihr Reverse-DNS-Eintrag für IPv4 korrekt konfiguiert ist, können Sie versuchen, die Verwendung von IPv6 für das Versenden von E-Mails auszuschalten, indem Sie den Befehl yunohost settings set smtp.allow_ipv6 -v off ausführen. Bemerkung: Die Folge dieser letzten Lösung ist, dass Sie mit Servern, welche ausschliesslich über IPv6 verfügen, keine E-Mails mehr versenden oder empfangen können.", + "diagnosis_mail_fcrdns_nok_alternatives_4": "Einige Anbieter werden es Ihnen nicht erlauben, dass Sie Ihren Reverse-DNS (oder deren Funktionalität ist defekt...) konfigurieren. Falls Sie deswegen auf Probleme stossen sollten, ziehen Sie folgende Lösungen in Betracht:
- Manche ISPs stellen als Alternative die Benutzung eines Mail-Server-Relays zur Verfügung, was jedoch mit sich zieht, dass das Relay Ihren E-Mail-Verkehr ausspionieren kann.
- Eine privatsphärenfreundlichere Alternative ist die Benutzung eines VPN *mit einer dedizierten öffentlichen IP* um Einschränkungen dieser Art zu umgehen. Schauen Sie hier nach https://yunohost.org/#/vpn_advantage
- Schliesslich ist es auch möglich zu einem anderen Anbieter zu wechseln" } From 10abc848bb3e9056dc31191302ef8da93c8bd4b6 Mon Sep 17 00:00:00 2001 From: Christian Wehrli Date: Mon, 14 Sep 2020 06:10:36 +0000 Subject: [PATCH 43/71] Translated using Weblate (German) Currently translated at 52.1% (319 of 612 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/de/ --- locales/de.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/locales/de.json b/locales/de.json index e27b05506..4e0bd7130 100644 --- a/locales/de.json +++ b/locales/de.json @@ -424,5 +424,10 @@ "diagnosis_mail_fcrdns_different_from_ehlo_domain_details": "Aktueller Reverse-DNS-Eintrag: {rdns_domain}
Erwarteter Wert: {ehlo_domain}", "diagnosis_mail_fcrdns_different_from_ehlo_domain": "Der Reverse-DNS-Eintrag für IPv{ipversion} ist nicht korrekt konfiguriert. Einige E-Mails könnten abgewiesen oder als Spam markiert werden.", "diagnosis_mail_fcrdns_nok_alternatives_6": "Einige Provider werden es Ihnen nicht erlauben, Ihren Reverse-DNS-Eintrag zu konfigurieren (oder ihre Funktionalität könnte defekt sein ...). Falls Ihr Reverse-DNS-Eintrag für IPv4 korrekt konfiguiert ist, können Sie versuchen, die Verwendung von IPv6 für das Versenden von E-Mails auszuschalten, indem Sie den Befehl yunohost settings set smtp.allow_ipv6 -v off ausführen. Bemerkung: Die Folge dieser letzten Lösung ist, dass Sie mit Servern, welche ausschliesslich über IPv6 verfügen, keine E-Mails mehr versenden oder empfangen können.", - "diagnosis_mail_fcrdns_nok_alternatives_4": "Einige Anbieter werden es Ihnen nicht erlauben, dass Sie Ihren Reverse-DNS (oder deren Funktionalität ist defekt...) konfigurieren. Falls Sie deswegen auf Probleme stossen sollten, ziehen Sie folgende Lösungen in Betracht:
- Manche ISPs stellen als Alternative die Benutzung eines Mail-Server-Relays zur Verfügung, was jedoch mit sich zieht, dass das Relay Ihren E-Mail-Verkehr ausspionieren kann.
- Eine privatsphärenfreundlichere Alternative ist die Benutzung eines VPN *mit einer dedizierten öffentlichen IP* um Einschränkungen dieser Art zu umgehen. Schauen Sie hier nach https://yunohost.org/#/vpn_advantage
- Schliesslich ist es auch möglich zu einem anderen Anbieter zu wechseln" + "diagnosis_mail_fcrdns_nok_alternatives_4": "Einige Anbieter werden es Ihnen nicht erlauben, dass Sie Ihren Reverse-DNS (oder deren Funktionalität ist defekt...) konfigurieren. Falls Sie deswegen auf Probleme stossen sollten, ziehen Sie folgende Lösungen in Betracht:
- Manche ISPs stellen als Alternative die Benutzung eines Mail-Server-Relays zur Verfügung, was jedoch mit sich zieht, dass das Relay Ihren E-Mail-Verkehr ausspionieren kann.
- Eine privatsphärenfreundlichere Alternative ist die Benutzung eines VPN *mit einer dedizierten öffentlichen IP* um Einschränkungen dieser Art zu umgehen. Schauen Sie hier nach https://yunohost.org/#/vpn_advantage
- Schliesslich ist es auch möglich zu einem anderen Anbieter zu wechseln", + "diagnosis_mail_queue_unavailable_details": "Fehler: {error}", + "diagnosis_mail_queue_unavailable": "Die Anzahl der anstehenden Nachrichten in der Warteschlange kann nicht abgefragt werden", + "diagnosis_mail_queue_ok": "{nb_pending} anstehende E-Mails in der Warteschlange", + "diagnosis_mail_blacklist_reason": "Der Grund für die Blacklist ist: {reason}", + "app_argument_password_no_default": "Fehler beim Verarbeiten des Passwort-Arguments '{name}': Passwort-Argument kann aus Sicherheitsgründen keinen Standardwert haben" } From 5c47a87cc089b8a01493fd70c8c8c78726a7321c Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 16 Sep 2020 19:43:18 +0200 Subject: [PATCH 44/71] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Éric Gaspar <46165813+ericgaspar@users.noreply.github.com> Co-authored-by: Kayou --- locales/fr.json | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/locales/fr.json b/locales/fr.json index 88fbf3468..b947fcb59 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -668,22 +668,22 @@ "migration_description_0015_migrate_to_buster": "Mise à niveau du système vers Debian Buster et YunoHost 4.x", "diagnosis_dns_try_dyndns_update_force": "La configuration DNS de ce domaine devrait être automatiquement gérée par Yunohost. Si ce n'est pas le cas, vous pouvez essayer de forcer une mise à jour en utilisant yunohost dyndns update --force.", "app_packaging_format_not_supported": "Cette application ne peut pas être installée car son format n'est pas pris en charge par votre version de YunoHost. Vous devriez probablement envisager de mettre à jour votre système.", - "migration_0015_weak_certs": "Il a été constaté que les certificats suivants utilisent encore des algorithmes de signature peu robustes et doivent être mis à jour pour être compatibles avec la prochaine version de nginx : {certs}", - "global_settings_setting_backup_compress_tar_archives": "Compresser les archives (.tar.gz) au lieu de des archives non-compressées lors de la création des backups. N.B. Activer cette option implique de créer des archives plus légères, mais aussi d'avoir des procédures de backup significativement plus longues et plus gourmandes en CPU.", - "migration_description_0018_xtable_to_nftable": "Migrer les anciennes règles de trafic réseau vers les nouvelles nftables système", - "service_description_php7.3-fpm": "Lancer les applications écrites en PHP avec NGINX", + "migration_0015_weak_certs": "Il a été constaté que les certificats suivants utilisent encore des algorithmes de signature peu robustes et doivent être mis à jour pour être compatibles avec la prochaine version de NGINX : {certs}", + "global_settings_setting_backup_compress_tar_archives": "Compresser les archives (.tar.gz) au lieu des archives non-compressées lors de la création des backups. N.B. : activer cette option permet d'obtenir des backups plus légers, mais leur création sera significativement plus longue et plus gourmande en CPU.", + "migration_description_0018_xtable_to_nftable": "Migrer les anciennes règles de trafic réseau vers le nouveau système basé sur nftables", + "service_description_php7.3-fpm": "Exécute les applications écrites en PHP avec NGINX", "migration_0018_failed_to_reset_legacy_rules": "La réinitialisation des règles iptable legacy a échoué :", - "migration_0018_failed_to_migrate_iptables_rules": "La migration des iptables legacy vers nftables a échoué: {error}", + "migration_0018_failed_to_migrate_iptables_rules": "La migration des anciennes règles iptables vers nftables a échoué : {error}", "migration_0017_not_enough_space": "Laissez suffisamment d'espace disponible dans {path} avant de lancer la migration.", "migration_0017_postgresql_11_not_installed": "PostgreSQL 9.6 est installé mais pas posgreSQL 11 ? Il s'est sans doute passé quelque chose d'étrange sur votre système :(...", "migration_0017_postgresql_96_not_installed": "PostgreSQL n'a pas été installé sur votre système. Aucune opération à effectuer.", "migration_description_0017_postgresql_9p6_to_11": "Migrer les bases de données de PostgreSQL 9.6 vers 11", - "migration_description_0016_php70_to_php73_pools": "Migrer php7.0-fpm 'pool' conf files vers php7.3", - "diagnosis_processes_killed_by_oom_reaper": "Certains processus ont été arrêtés récemment par le système car il manquait de mémoire. Cela apparaît généralement quand le système manque de mémoire ou qu'un processus consomme trop de mémoire. Liste des processus tués :", - "ask_user_domain": "Domaine à utiliser pour l'adresse mail des utilisateurs et le compte XMPP", - "app_manifest_install_ask_is_public": "Cette application devrait-elle apparaître aux visiteurs anonymes ?", + "migration_description_0016_php70_to_php73_pools": "Migrer les configurations php7.0 vers php7.3", + "diagnosis_processes_killed_by_oom_reaper": "Certains processus ont été arrêtés récemment par le système car il manquait de mémoire. Cela apparaît généralement quand le système manque de mémoire ou qu'un processus consomme trop de mémoire. Liste des processus tués :\n{kills_summary}", + "ask_user_domain": "Domaine à utiliser pour l'adresse mail de l'utilisateur et le compte XMPP", + "app_manifest_install_ask_is_public": "Cette application devrait-elle être visible par les visiteurs anonymes ?", "app_manifest_install_ask_admin": "Choisissez un administrateur pour cette application", - "app_manifest_install_ask_password": "Choisissez un mot de passez administrateur pour cette application", - "app_manifest_install_ask_path": "Choisissez le chemin où cette application devrait être installée", - "app_manifest_install_ask_domain": "Choisissez le domaine où cette application devrait être insttallée" + "app_manifest_install_ask_password": "Choisissez un mot de passe administrateur pour cette application", + "app_manifest_install_ask_path": "Choisissez le chemin sur lequel vous souhaitez installer cette application", + "app_manifest_install_ask_domain": "Choisissez le domaine sur lequel vous souhaitez installer cette application" } From ffcd0e33ac2323551fc587883be606ef6fce6a30 Mon Sep 17 00:00:00 2001 From: Augustin Trancart Date: Sat, 19 Sep 2020 15:29:38 +0200 Subject: [PATCH 45/71] Fix ynh_app_upstream_version : restore ability to read manifest The documentation was saying A, the code was doing B, and calling functions were expecting both A and B (see ynh_check_app_version_changed). So this commit aims at making everyone agree, by matching usage. --- data/helpers.d/utils | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/data/helpers.d/utils b/data/helpers.d/utils index 95f8ddc52..8f79472eb 100644 --- a/data/helpers.d/utils +++ b/data/helpers.d/utils @@ -417,7 +417,7 @@ ynh_read_manifest () { jq ".$manifest_key" "$manifest" --raw-output } -# Read the upstream version from the manifest +# Read the upstream version from the manifest, or from the env variable $YNH_APP_MANIFEST_VERSION if not given # # usage: ynh_app_upstream_version [--manifest="manifest.json"] # | arg: -m, --manifest= - Path of the manifest to read @@ -437,7 +437,13 @@ ynh_app_upstream_version () { # Manage arguments with getopts ynh_handle_getopts_args "$@" - version_key=$YNH_APP_MANIFEST_VERSION + if [[ "$manifest" != "" ]] && [[ -e "$manifest" ]]; + then + version_key=$(ynh_read_manifest --manifest="$manifest" --manifest_key="version") + else + version_key=$YNH_APP_MANIFEST_VERSION + fi + echo "${version_key/~ynh*/}" } From bca4cd0c51ad6452ca66af7afac815f56b7651e9 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 19 Sep 2020 17:27:21 +0200 Subject: [PATCH 46/71] Admin/API wasn't logging or displaying messages anymore --- src/yunohost/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/yunohost/__init__.py b/src/yunohost/__init__.py index d909ad9e2..76449a7e4 100644 --- a/src/yunohost/__init__.py +++ b/src/yunohost/__init__.py @@ -190,7 +190,7 @@ def init_logging(interface="cli", 'loggers': { 'yunohost': { 'level': 'DEBUG', - 'handlers': ['file', 'api'] + ['console'] if debug else [], + 'handlers': ['file', 'api'] + (['console'] if debug else []), 'propagate': False, }, 'moulinette': { @@ -201,6 +201,6 @@ def init_logging(interface="cli", }, 'root': { 'level': 'DEBUG', - 'handlers': ['file'] + ['console'] if debug else [], + 'handlers': ['file'] + (['console'] if debug else []), }, }) From 1e79e50d6829666e53e4c230202061c70d7a6bee Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sun, 20 Sep 2020 20:01:55 +0200 Subject: [PATCH 47/71] Add ynh_add_config helper --- data/helpers.d/utils | 141 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) diff --git a/data/helpers.d/utils b/data/helpers.d/utils index 95f8ddc52..41c429c74 100644 --- a/data/helpers.d/utils +++ b/data/helpers.d/utils @@ -263,6 +263,147 @@ ynh_local_curl () { curl --silent --show-error --insecure --location --header "Host: $domain" --resolve $domain:443:127.0.0.1 $POST_data "$full_page_url" --cookie-jar $cookiefile --cookie $cookiefile } +# Create a dedicated config file from a template +# +# examples: +# ynh_add_config --template=".env" --destination="$final_path/.env" +# ynh_add_config --template="../conf/.env" --destination="$final_path/.env" +# ynh_add_config --template="/etc/nginx/sites-available/default" --destination="etc/nginx/sites-available/mydomain.conf" +# +# usage: ynh_add_config --template="template" --destination="destination" +# | arg: -t, --template= - Template config file to use +# | arg: -d, --destination= - Destination of the config file +# +# The template can be by default the name of a file in the conf directory +# of a YunoHost Package, a relative path or an absolute path +# The helper will use the template $template to generate a config file +# $destination by replacing the following keywords with global variables +# that should be defined before calling this helper : +# __PATH__ by $path_url +# __NAME__ by $app +# __NAMETOCHANGE__ by $app +# __USER__ by $app +# __FINALPATH__ by $final_path +# __PHPVERSION__ by $YNH_PHP_VERSION +# +# And any dynamic variables that should be defined before calling this helper like: +# __DOMAIN__ by $domain +# __APP__ by $app +# __VAR_1__ by $var_1 +# __VAR_2__ by $var_2 +# +# The helper will verify the checksum and backup the destination file +# if it's different before applying the new template. +# And it will calculate and store the destination file checksum +# into the app settings when configuration is done. +# +# Requires YunoHost version 4.1.0 or higher. +ynh_add_config () { + # Declare an array to define the options of this helper. + local legacy_args=tdv + local -A args_array=( [t]=template= [d]=destination= ) + local template + local destination + # Manage arguments with getopts + ynh_handle_getopts_args "$@" + local template_path + + if [ -f "../conf/$template" ]; then + template_path="../conf/$template" + elif [ -f "../settings/conf/$template" ]; then + template_path="../settings/conf/$template" + elif [ -f "$template" ]; then + template_path=$template + else + ynh_die --message="The provided template $template doesn't exist" + fi + + ynh_backup_if_checksum_is_different --file="$destination" + + cp "$template_path" "$destination" + + ynh_replace_vars --file="$destination" + + ynh_store_file_checksum --file="$destination" +} + +# Replace variables in a file +# +# [internal] +# +# usage: ynh_replace_vars --file="file" +# | arg: -f, --file= - File where to replace variables +# +# The helper will replace the following keywords with global variables +# that should be defined before calling this helper : +# __PATH__ by $path_url +# __NAME__ by $app +# __NAMETOCHANGE__ by $app +# __USER__ by $app +# __FINALPATH__ by $final_path +# __PHPVERSION__ by $YNH_PHP_VERSION +# +# And any dynamic variables that should be defined before calling this helper like: +# __DOMAIN__ by $domain +# __APP__ by $app +# __VAR_1__ by $var_1 +# __VAR_2__ by $var_2 +# +# Requires YunoHost version 4.1.0 or higher. +ynh_replace_vars () { + # Declare an array to define the options of this helper. + local legacy_args=f + local -A args_array=( [f]=file= ) + local file + # Manage arguments with getopts + ynh_handle_getopts_args "$@" + + # Replace specific YunoHost variables + if test -n "${path_url:-}" + then + # path_url_slash_less is path_url, or a blank value if path_url is only '/' + local path_url_slash_less=${path_url%/} + ynh_replace_string --match_string="__PATH__/" --replace_string="$path_url_slash_less/" --target_file="$file" + ynh_replace_string --match_string="__PATH__" --replace_string="$path_url" --target_file="$file" + fi + if test -n "${app:-}"; then + ynh_replace_string --match_string="__NAME__" --replace_string="$app" --target_file="$file" + ynh_replace_string --match_string="__NAMETOCHANGE__" --replace_string="$app" --target_file="$file" + ynh_replace_string --match_string="__USER__" --replace_string="$app" --target_file="$file" + fi + if test -n "${final_path:-}"; then + ynh_replace_string --match_string="__FINALPATH__" --replace_string="$final_path" --target_file="$file" + fi + if test -n "${YNH_PHP_VERSION:-}"; then + ynh_replace_string --match_string="__PHPVERSION__" --replace_string="$YNH_PHP_VERSION" --target_file="$file" + fi + if test -n "${ynh_node_load_PATH:-}"; then + ynh_replace_string --match_string="__YNH_NODE_LOAD_PATH__" --replace_string="$ynh_node_load_PATH" --target_file="$file" + fi + + # Replace others variables + + # List other unique (__ __) variables in $file + local uniques_vars=( $(grep -o '__[A-Z0-9_]*__' $file | sort --unique | sed "s@__\([^.]*\)__@\L\1@g" )) + + # Do the replacement + local delimit=@ + for one_var in "${uniques_vars[@]}" + do + # Validate that one_var is indeed defined + test -n "${!one_var:-}" || ynh_die --message="\$$one_var wasn't initialized when trying to replace __${one_var^^}__ in $file" + + # Escape delimiter in match/replace string + match_string="__${one_var^^}__" + match_string=${match_string//${delimit}/"\\${delimit}"} + replace_string="${!one_var}" + replace_string=${replace_string//${delimit}/"\\${delimit}"} + + # Actually replace (sed is used instead of ynh_replace_string to avoid triggering an epic amount of debug logs) + sed --in-place "s${delimit}${match_string}${delimit}${replace_string}${delimit}g" "$file" + done +} + # Render templates with Jinja2 # # [internal] From 3b94b235168807d1767cffb2fbd4dcdeb3abf034 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sun, 20 Sep 2020 20:37:45 +0200 Subject: [PATCH 48/71] Update data/helpers.d/utils MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Éric Gaspar <46165813+ericgaspar@users.noreply.github.com> --- data/helpers.d/utils | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/helpers.d/utils b/data/helpers.d/utils index 41c429c74..76779f268 100644 --- a/data/helpers.d/utils +++ b/data/helpers.d/utils @@ -342,7 +342,7 @@ ynh_add_config () { # __USER__ by $app # __FINALPATH__ by $final_path # __PHPVERSION__ by $YNH_PHP_VERSION -# +# __YNH_NODE_LOAD_PATH__" by $ynh_node_load_PATH # And any dynamic variables that should be defined before calling this helper like: # __DOMAIN__ by $domain # __APP__ by $app From 51c66dde947f67e633e2cc9d7d61b6868edf95cd Mon Sep 17 00:00:00 2001 From: ljf Date: Sun, 20 Sep 2020 20:59:38 +0200 Subject: [PATCH 49/71] [enh] Add x509 fingerprint in /etc/issue --- bin/yunoprompt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bin/yunoprompt b/bin/yunoprompt index 09400639b..252e5a1a4 100755 --- a/bin/yunoprompt +++ b/bin/yunoprompt @@ -1,5 +1,9 @@ #!/bin/bash +# Fetch x509 fingerprint +x509_fingerprint=$(openssl x509 -in /etc/yunohost/certs/yunohost.org/crt.pem -noout -fingerprint -sha256 | cut -d= -f2) + + # Fetch SSH fingerprints i=0 for key in $(ls /etc/ssh/ssh_host_{ed25519,rsa,ecdsa}_key.pub 2> /dev/null) ; do @@ -40,6 +44,7 @@ LOGO_AND_FINGERPRINTS=$(cat << EOF $LOGO IP: ${local_ip} + X509 fingerprint: ${x509_fingerprint} SSH fingerprints: ${fingerprint[0]} ${fingerprint[1]} From ebe6c8a5f2060d03ac299bdf2bc980af6516f980 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sun, 20 Sep 2020 21:15:59 +0200 Subject: [PATCH 50/71] Apply suggestions from code review (comment indentation) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Éric Gaspar <46165813+ericgaspar@users.noreply.github.com> --- data/helpers.d/utils | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/data/helpers.d/utils b/data/helpers.d/utils index 76779f268..c4af2f6f1 100644 --- a/data/helpers.d/utils +++ b/data/helpers.d/utils @@ -279,12 +279,13 @@ ynh_local_curl () { # The helper will use the template $template to generate a config file # $destination by replacing the following keywords with global variables # that should be defined before calling this helper : -# __PATH__ by $path_url -# __NAME__ by $app -# __NAMETOCHANGE__ by $app -# __USER__ by $app -# __FINALPATH__ by $final_path -# __PHPVERSION__ by $YNH_PHP_VERSION +# __PATH__ by $path_url +# __NAME__ by $app +# __NAMETOCHANGE__ by $app +# __USER__ by $app +# __FINALPATH__ by $final_path +# __PHPVERSION__ by $YNH_PHP_VERSION +# __YNH_NODE_LOAD_PATH__ by $ynh_node_load_PATH # # And any dynamic variables that should be defined before calling this helper like: # __DOMAIN__ by $domain @@ -336,13 +337,14 @@ ynh_add_config () { # # The helper will replace the following keywords with global variables # that should be defined before calling this helper : -# __PATH__ by $path_url -# __NAME__ by $app -# __NAMETOCHANGE__ by $app -# __USER__ by $app -# __FINALPATH__ by $final_path -# __PHPVERSION__ by $YNH_PHP_VERSION -# __YNH_NODE_LOAD_PATH__" by $ynh_node_load_PATH +# __PATH__ by $path_url +# __NAME__ by $app +# __NAMETOCHANGE__ by $app +# __USER__ by $app +# __FINALPATH__ by $final_path +# __PHPVERSION__ by $YNH_PHP_VERSION +# __YNH_NODE_LOAD_PATH__ by $ynh_node_load_PATH +# # And any dynamic variables that should be defined before calling this helper like: # __DOMAIN__ by $domain # __APP__ by $app From 4186f757e1f6c32d072fdfe201ff2013a0ad5daf Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 22 Sep 2020 17:48:00 +0200 Subject: [PATCH 51/71] Cleanup some old stuff in postinstall code --- src/yunohost/tools.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py index fcc2810d6..946c876e4 100644 --- a/src/yunohost/tools.py +++ b/src/yunohost/tools.py @@ -303,17 +303,10 @@ def tools_postinstall(operation_logger, domain, password, ignore_dyndns=False, # Change folders permissions os.system('chmod 755 /home/yunohost.app') - # Set hostname to avoid amavis bug - if os.system('hostname -d >/dev/null') != 0: - os.system('hostname yunohost.yunohost.org') - - # Add a temporary SSOwat rule to redirect SSO to admin page + # Init ssowat's conf.json.persistent if not os.path.exists('/etc/ssowat/conf.json.persistent'): - ssowat_conf = {} - else: - ssowat_conf = read_json('/etc/ssowat/conf.json.persistent') + write_to_json('/etc/ssowat/conf.json.persistent', {}) - write_to_json('/etc/ssowat/conf.json.persistent', ssowat_conf) os.system('chmod 644 /etc/ssowat/conf.json.persistent') # Create SSL CA From 3cecc7cb30ec90738a2b683187c5b769f5c94288 Mon Sep 17 00:00:00 2001 From: cyxae Date: Fri, 6 Dec 2019 18:38:19 +0100 Subject: [PATCH 52/71] Sort alphabetically domain list --- src/yunohost/domain.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/yunohost/domain.py b/src/yunohost/domain.py index 160c8f622..195d1e290 100644 --- a/src/yunohost/domain.py +++ b/src/yunohost/domain.py @@ -59,7 +59,10 @@ def domain_list(exclude_subdomains=False): parent_domain = domain.split(".", 1)[1] if parent_domain in result: continue - result_list.append(domain) + result_list.append(".".join(reversed(domain.split(".")))) + result_list = sorted(result_list) + for i in range(len(result_list)): + result_list[i] = ".".join(reversed(result_list[i].split("."))) return {'domains': result_list} From c8e24d898ae076ecb835e8409c742d46d4931dcb Mon Sep 17 00:00:00 2001 From: ljf Date: Wed, 23 Sep 2020 00:57:41 +0200 Subject: [PATCH 53/71] [enh] Group same domains and subdomains together --- src/yunohost/domain.py | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/yunohost/domain.py b/src/yunohost/domain.py index 195d1e290..179d5728f 100644 --- a/src/yunohost/domain.py +++ b/src/yunohost/domain.py @@ -59,10 +59,22 @@ def domain_list(exclude_subdomains=False): parent_domain = domain.split(".", 1)[1] if parent_domain in result: continue - result_list.append(".".join(reversed(domain.split(".")))) - result_list = sorted(result_list) - for i in range(len(result_list)): - result_list[i] = ".".join(reversed(result_list[i].split("."))) + + result_list.append(domain) + + + def cmp_domain(domain1, domain2): + # Keep the main part of the domain and the extension together + # eg: this.is.an.example.com -> ['example.com', 'an', 'is', 'this'] + domain1 = domain1.split('.') + domain2 = domain2.split('.') + domain1[-1] = domain1[-2] + domain1.pop() + domain2[-1] = domain2[-2] + domain2.pop() + domain1 = list(reversed(domain1)) + domain2 = list(reversed(domain2)) + return cmp(domain1, domain2) + + result_list = sorted(result_list, cmp_domain) return {'domains': result_list} From 69e20fa114cbb509ae911d930c50b751c5f255aa Mon Sep 17 00:00:00 2001 From: Julien Jershon Date: Sat, 5 Oct 2019 10:29:01 +0200 Subject: [PATCH 54/71] Update the email regex so it accept the '+' sign. Fix https://github.com/YunoHost/issues/issues/1333. --- data/actionsmap/yunohost.yml | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/data/actionsmap/yunohost.yml b/data/actionsmap/yunohost.yml index 08416b69f..72b30328c 100644 --- a/data/actionsmap/yunohost.yml +++ b/data/actionsmap/yunohost.yml @@ -100,6 +100,12 @@ user: -m: full: --mail help: (Deprecated, see --domain) Main unique email address + extra: + ask: ask_email + required: True + pattern: &pattern_email_without_plus + - !!str ^[\w.-]+@([^\W_A-Z]+([-]*[^\W_A-Z]+)*\.)+([^\W\d_]{2,})$ + - "pattern_email_without_plus" -p: full: --password help: User password @@ -158,9 +164,7 @@ user: -m: full: --mail extra: - pattern: &pattern_email - - !!str ^[\w.-]+@([^\W_A-Z]+([-]*[^\W_A-Z]+)*\.)+((xn--)?[^\W_]{2,})$ - - "pattern_email" + pattern: *pattern_email_without_plus -p: full: --change-password help: New password to set @@ -172,7 +176,9 @@ user: nargs: "*" metavar: MAIL extra: - pattern: *pattern_email + pattern: &pattern_email + - !!str ^[\w\+.-]+@([^\W_A-Z]+([-]*[^\W_A-Z]+)*\.)+([^\W\d_]{2,})$ + - "pattern_email" --remove-mailforward: help: Mailforward addresses to remove nargs: "*" @@ -182,7 +188,7 @@ user: nargs: "*" metavar: MAIL extra: - pattern: *pattern_email + pattern: *pattern_email_without_plus --remove-mailalias: help: Mail aliases to remove nargs: "*" From 4510b2b913427f56a5b566fe14805085455eb2b3 Mon Sep 17 00:00:00 2001 From: ljf Date: Wed, 23 Sep 2020 02:03:46 +0200 Subject: [PATCH 55/71] [fix] Add pattern email desc --- locales/en.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/locales/en.json b/locales/en.json index 1a620124b..e832b5ec8 100644 --- a/locales/en.json +++ b/locales/en.json @@ -468,7 +468,8 @@ "password_too_simple_4": "The password needs to be at least 12 characters long and contain a digit, upper, lower and special characters", "pattern_backup_archive_name": "Must be a valid filename with max 30 characters, alphanumeric and -_. characters only", "pattern_domain": "Must be a valid domain name (e.g. my-domain.org)", - "pattern_email": "Must be a valid e-mail address (e.g. someone@example.com)", + "pattern_email": "Must be a valid e-mail address, '+' symbol accepted(e.g. someone+tag@example.com)", + "pattern_email_without_plus": "Must be a valid e-mail address without '+' symbol (e.g. someone@example.com)", "pattern_firstname": "Must be a valid first name", "pattern_lastname": "Must be a valid last name", "pattern_mailbox_quota": "Must be a size with b/k/M/G/T suffix or 0 to not have a quota", From 95f6772cba53b6c2f8f865f5b3d5c66d4b653c56 Mon Sep 17 00:00:00 2001 From: "ljf (zamentur)" Date: Wed, 23 Sep 2020 03:25:26 +0200 Subject: [PATCH 56/71] [fix] Typo and ssh as system perm --- src/yunohost/permission.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yunohost/permission.py b/src/yunohost/permission.py index cd81489a2..010913556 100644 --- a/src/yunohost/permission.py +++ b/src/yunohost/permission.py @@ -35,7 +35,7 @@ from yunohost.log import is_unit_operation logger = getActionLogger('yunohost.user') -SYSTEM_PERMS = ["mail", "xmpp", "stfp"] +SYSTEM_PERMS = ["mail", "xmpp", "sftp", "ssh"] # # From ae897994cacfd764870ac9f8569d3e3cdc9633ec Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 23 Sep 2020 21:33:10 +0200 Subject: [PATCH 57/71] Remove legacy stuff, every instances that got migrated to Buster already have this applied --- src/yunohost/tools.py | 32 -------------------------------- 1 file changed, 32 deletions(-) diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py index 946c876e4..8799102db 100644 --- a/src/yunohost/tools.py +++ b/src/yunohost/tools.py @@ -908,44 +908,12 @@ def tools_migrations_state(): """ Show current migration state """ - if os.path.exists("/etc/yunohost/migrations_state.json"): - _migrate_legacy_migration_json() - if not os.path.exists(MIGRATIONS_STATE_PATH): return {"migrations": {}} return read_yaml(MIGRATIONS_STATE_PATH) -def _migrate_legacy_migration_json(): - - from moulinette.utils.filesystem import read_json - - logger.debug("Migrating legacy migration state json to yaml...") - - # We fetch the old state containing the last run migration - old_state = read_json("/etc/yunohost/migrations_state.json")["last_run_migration"] - last_run_migration_id = str(old_state["number"]) + "_" + old_state["name"] - - # Extract the list of migration ids - from . import data_migrations - migrations_path = data_migrations.__path__[0] - migration_files = filter(lambda x: re.match(r"^\d+_[a-zA-Z0-9_]+\.py$", x), os.listdir(migrations_path)) - # (here we remove the .py extension and make sure the ids are sorted) - migration_ids = sorted([f.rsplit(".", 1)[0] for f in migration_files]) - - # So now build the new dict for every id up to the last run migration - migrations = {} - for migration_id in migration_ids: - migrations[migration_id] = "done" - if last_run_migration_id in migration_id: - break - - # Write the new file and rename the old one - write_to_yaml(MIGRATIONS_STATE_PATH, {"migrations": migrations}) - os.rename("/etc/yunohost/migrations_state.json", "/etc/yunohost/migrations_state.json.old") - - def _write_migration_state(migration_id, state): current_states = tools_migrations_state() From f2b6a883a8200b58daa2210df401a278c84932ec Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 23 Sep 2020 21:37:08 +0200 Subject: [PATCH 58/71] Unused import --- src/yunohost/tools.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py index 8799102db..1c45ef770 100644 --- a/src/yunohost/tools.py +++ b/src/yunohost/tools.py @@ -33,7 +33,7 @@ from importlib import import_module from moulinette import msignals, m18n from moulinette.utils.log import getActionLogger from moulinette.utils.process import check_output, call_async_output -from moulinette.utils.filesystem import read_json, write_to_json, read_yaml, write_to_yaml +from moulinette.utils.filesystem import write_to_json, read_yaml, write_to_yaml from yunohost.app import _update_apps_catalog, app_info, app_upgrade, _initialize_apps_catalog_system from yunohost.domain import domain_add From c0234a75f52149d2b6650d6cecf566a2703579cc Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 23 Sep 2020 21:46:31 +0200 Subject: [PATCH 59/71] Better naming ? :s --- data/actionsmap/yunohost.yml | 12 ++++++------ locales/en.json | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/data/actionsmap/yunohost.yml b/data/actionsmap/yunohost.yml index 72b30328c..7be0e0899 100644 --- a/data/actionsmap/yunohost.yml +++ b/data/actionsmap/yunohost.yml @@ -103,9 +103,9 @@ user: extra: ask: ask_email required: True - pattern: &pattern_email_without_plus + pattern: &pattern_email - !!str ^[\w.-]+@([^\W_A-Z]+([-]*[^\W_A-Z]+)*\.)+([^\W\d_]{2,})$ - - "pattern_email_without_plus" + - "pattern_email" -p: full: --password help: User password @@ -164,7 +164,7 @@ user: -m: full: --mail extra: - pattern: *pattern_email_without_plus + pattern: *pattern_email -p: full: --change-password help: New password to set @@ -176,9 +176,9 @@ user: nargs: "*" metavar: MAIL extra: - pattern: &pattern_email + pattern: &pattern_email_forward - !!str ^[\w\+.-]+@([^\W_A-Z]+([-]*[^\W_A-Z]+)*\.)+([^\W\d_]{2,})$ - - "pattern_email" + - "pattern_email_forward" --remove-mailforward: help: Mailforward addresses to remove nargs: "*" @@ -188,7 +188,7 @@ user: nargs: "*" metavar: MAIL extra: - pattern: *pattern_email_without_plus + pattern: *pattern_email --remove-mailalias: help: Mail aliases to remove nargs: "*" diff --git a/locales/en.json b/locales/en.json index e832b5ec8..115928001 100644 --- a/locales/en.json +++ b/locales/en.json @@ -468,8 +468,8 @@ "password_too_simple_4": "The password needs to be at least 12 characters long and contain a digit, upper, lower and special characters", "pattern_backup_archive_name": "Must be a valid filename with max 30 characters, alphanumeric and -_. characters only", "pattern_domain": "Must be a valid domain name (e.g. my-domain.org)", - "pattern_email": "Must be a valid e-mail address, '+' symbol accepted(e.g. someone+tag@example.com)", - "pattern_email_without_plus": "Must be a valid e-mail address without '+' symbol (e.g. someone@example.com)", + "pattern_email_forward": "Must be a valid e-mail address, '+' symbol accepted (e.g. someone+tag@example.com)", + "pattern_email": "Must be a valid e-mail address, without '+' symbol (e.g. someone@example.com)", "pattern_firstname": "Must be a valid first name", "pattern_lastname": "Must be a valid last name", "pattern_mailbox_quota": "Must be a size with b/k/M/G/T suffix or 0 to not have a quota", From b48f6521e2cf532a1da0ab76cc51c9834998a10a Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 23 Sep 2020 21:53:06 +0200 Subject: [PATCH 60/71] Removing the pattern/required flag from --mail in user_create was intentional because it's now deprecated ... + restablish support xn-- stuff... --- data/actionsmap/yunohost.yml | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/data/actionsmap/yunohost.yml b/data/actionsmap/yunohost.yml index 7be0e0899..5371d576d 100644 --- a/data/actionsmap/yunohost.yml +++ b/data/actionsmap/yunohost.yml @@ -100,12 +100,6 @@ user: -m: full: --mail help: (Deprecated, see --domain) Main unique email address - extra: - ask: ask_email - required: True - pattern: &pattern_email - - !!str ^[\w.-]+@([^\W_A-Z]+([-]*[^\W_A-Z]+)*\.)+([^\W\d_]{2,})$ - - "pattern_email" -p: full: --password help: User password @@ -164,7 +158,9 @@ user: -m: full: --mail extra: - pattern: *pattern_email + pattern: &pattern_email + - !!str ^[\w.-]+@([^\W_A-Z]+([-]*[^\W_A-Z]+)*\.)+((xn--)?[^\W_]{2,})$ + - "pattern_email" -p: full: --change-password help: New password to set @@ -177,7 +173,7 @@ user: metavar: MAIL extra: pattern: &pattern_email_forward - - !!str ^[\w\+.-]+@([^\W_A-Z]+([-]*[^\W_A-Z]+)*\.)+([^\W\d_]{2,})$ + - !!str ^[\w\+.-]+@([^\W_A-Z]+([-]*[^\W_A-Z]+)*\.)+((xn--)?[^\W_]{2,})$ - "pattern_email_forward" --remove-mailforward: help: Mailforward addresses to remove From 6bd56558303378d5c11db910773c141b456ee376 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 23 Sep 2020 22:11:04 +0200 Subject: [PATCH 61/71] Return main domain directly, not its index Co-authored-by: ljf (zamentur) --- src/yunohost/domain.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yunohost/domain.py b/src/yunohost/domain.py index f76ab2bb0..2e46e7ab8 100644 --- a/src/yunohost/domain.py +++ b/src/yunohost/domain.py @@ -64,7 +64,7 @@ def domain_list(exclude_subdomains=False): result_list.sort() return { 'domains': result_list, - 'default': result_list.index(_get_maindomain()) + 'default': _get_maindomain() } From 5a905769dce406839c04120b85a932fede839a26 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 23 Sep 2020 22:12:47 +0200 Subject: [PATCH 62/71] (Do no sort domain, to be done in other PR) --- src/yunohost/domain.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/yunohost/domain.py b/src/yunohost/domain.py index 2e46e7ab8..b3143e053 100644 --- a/src/yunohost/domain.py +++ b/src/yunohost/domain.py @@ -61,7 +61,6 @@ def domain_list(exclude_subdomains=False): continue result_list.append(domain) - result_list.sort() return { 'domains': result_list, 'default': _get_maindomain() From 8f776d23fc6020bc6fab21ca4c6bffb9a7f09960 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 23 Sep 2020 22:14:42 +0200 Subject: [PATCH 63/71] default -> main --- src/yunohost/domain.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yunohost/domain.py b/src/yunohost/domain.py index b3143e053..2906bcf04 100644 --- a/src/yunohost/domain.py +++ b/src/yunohost/domain.py @@ -63,7 +63,7 @@ def domain_list(exclude_subdomains=False): return { 'domains': result_list, - 'default': _get_maindomain() + 'main': _get_maindomain() } From 14e8888078c760f2cc51c954a90321d0e25c3e51 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 23 Sep 2020 22:45:26 +0200 Subject: [PATCH 64/71] My god, please no, there's no damn jessie anymore --- data/helpers.d/php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/data/helpers.d/php b/data/helpers.d/php index c538d8688..5df31f32b 100644 --- a/data/helpers.d/php +++ b/data/helpers.d/php @@ -111,12 +111,6 @@ ynh_add_fpm_config () { local fpm_service="php${phpversion}-fpm" local fpm_config_dir="/etc/php/$phpversion/fpm" fi - # Configure PHP-FPM 5 on Debian Jessie - if [ "$(ynh_get_debian_release)" == "jessie" ] - then - fpm_config_dir="/etc/php5/fpm" - fpm_service="php5-fpm" - fi # Create the directory for FPM pools mkdir --parents "$fpm_config_dir/pool.d" From f73ae4eeab3efb8059c0b1a51bd7acd8ce9ae9c5 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Mon, 28 Sep 2020 20:00:33 +0200 Subject: [PATCH 65/71] c.f. issue 1274, test at the beginning of postinstall that iptables is working instead of miserably crashing at a later stage --- src/yunohost/tools.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py index 1c45ef770..a842cc590 100644 --- a/src/yunohost/tools.py +++ b/src/yunohost/tools.py @@ -279,6 +279,9 @@ def tools_postinstall(operation_logger, domain, password, ignore_dyndns=False, else: dyndns = False + if os.system("iptables -V >/dev/null 2>/dev/null") != 0: + raise YunohostError("iptables/nftables does not seems to be working on your setup. You may be in a container or your kernel does have the proper modules loaded. Sometimes, rebooting the machine may solve the issue.", raw_msg=True) + operation_logger.start() logger.info(m18n.n('yunohost_installing')) From a1c1057ab4ee8f549b82ee34ed33342589b02af5 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 29 Sep 2020 15:10:03 +0200 Subject: [PATCH 66/71] Add redis hook to enforce permissions on /var/log/redis --- data/hooks/conf_regen/35-redis | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100755 data/hooks/conf_regen/35-redis diff --git a/data/hooks/conf_regen/35-redis b/data/hooks/conf_regen/35-redis new file mode 100755 index 000000000..81d25af5a --- /dev/null +++ b/data/hooks/conf_regen/35-redis @@ -0,0 +1,28 @@ +#!/bin/bash + +do_pre_regen() { +} + +do_post_regen() { + # Enforce these damn permissions because for some reason in some weird cases + # they are spontaneously replaced by root:root -_- + chown -R redis:adm /var/log/redis +} + +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 From 452b178d44d44e69d31bc361477a9686b82ae14c Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 29 Sep 2020 15:57:47 +0200 Subject: [PATCH 67/71] journalctl -x in fact makes everything bloated, the supposedly additional info it displays does not contains anything relevant... --- src/yunohost/service.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yunohost/service.py b/src/yunohost/service.py index 084df471d..cf2798954 100644 --- a/src/yunohost/service.py +++ b/src/yunohost/service.py @@ -720,7 +720,7 @@ def _get_journalctl_logs(service, number="all"): services = _get_services() systemd_service = services.get(service, {}).get("actual_systemd_service", service) try: - return subprocess.check_output("journalctl --no-hostname -xn -u {0} -n{1}".format(systemd_service, number), shell=True) + return subprocess.check_output("journalctl --no-hostname --no-pager -u {0} -n{1}".format(systemd_service, number), shell=True) except: import traceback return "error while get services logs from journalctl:\n%s" % traceback.format_exc() From 6e69df37681ed339facdf8e89cf99c5e37118096 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 29 Sep 2020 16:24:30 +0200 Subject: [PATCH 68/71] Add configuration tests for dnsmasq, fail2ban, slapd --- data/templates/yunohost/services.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/data/templates/yunohost/services.yml b/data/templates/yunohost/services.yml index 73ae9403e..7df563c67 100644 --- a/data/templates/yunohost/services.yml +++ b/data/templates/yunohost/services.yml @@ -1,5 +1,6 @@ avahi-daemon: {} -dnsmasq: {} +dnsmasq: + test_conf: dnsmasq --test dovecot: log: [/var/log/mail.log,/var/log/mail.err] needs_exposed_ports: [993] @@ -7,6 +8,7 @@ dovecot: fail2ban: log: /var/log/fail2ban.log category: security + test_conf: fail2ban-server --test metronome: log: [/var/log/metronome/metronome.log,/var/log/metronome/metronome.err] needs_exposed_ports: [5222, 5269] @@ -37,6 +39,7 @@ rspamd: category: email slapd: category: database + test_conf: slapd -Tt ssh: log: /var/log/auth.log test_conf: sshd -t From 45b1441b30c36a7346f19ecd1be07e6386f7807f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Gaspar?= Date: Mon, 21 Sep 2020 21:42:55 +0000 Subject: [PATCH 69/71] Translated using Weblate (French) Currently translated at 98.9% (607 of 614 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/fr/ --- locales/fr.json | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/locales/fr.json b/locales/fr.json index b947fcb59..19a7cb718 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -107,7 +107,7 @@ "port_already_closed": "Le port {port:d} est déjà fermé pour les connexions {ip_version:s}", "port_already_opened": "Le port {port:d} est déjà ouvert pour les connexions {ip_version:s}", "restore_already_installed_app": "Une application est déjà installée avec l’identifiant '{app:s}'", - "restore_app_failed": "Impossible de restaurer l’application '{app:s}'", + "restore_app_failed": "Impossible de restaurer '{app:s}'", "restore_cleaning_failed": "Impossible de nettoyer le dossier temporaire de restauration", "restore_complete": "Restauré", "restore_confirm_yunohost_installed": "Voulez-vous vraiment restaurer un système déjà installé ? [{answers:s}]", @@ -136,13 +136,13 @@ "ssowat_conf_updated": "La configuration de SSOwat mise à jour", "system_upgraded": "Système mis à jour", "system_username_exists": "Ce nom d’utilisateur existe déjà dans les utilisateurs système", - "unbackup_app": "L’application '{app:s}' ne sera pas sauvegardée", + "unbackup_app": "'{app:s}' ne sera pas sauvegardée", "unexpected_error": "Une erreur inattendue est survenue : {error}", "unlimit": "Pas de quota", - "unrestore_app": "L’application '{app:s}' ne sera pas restaurée", - "updating_apt_cache": "Récupération des mises à jour disponibles pour les paquets du système…", + "unrestore_app": "'{app:s}' ne sera pas restaurée", + "updating_apt_cache": "Récupération des mises à jour disponibles pour les paquets du système...", "upgrade_complete": "Mise à jour terminée", - "upgrading_packages": "Mise à jour des paquets en cours…", + "upgrading_packages": "Mise à jour des paquets en cours...", "upnp_dev_not_found": "Aucun périphérique compatible UPnP n’a été trouvé", "upnp_disabled": "UPnP désactivé", "upnp_enabled": "UPnP activé", @@ -158,7 +158,7 @@ "yunohost_already_installed": "YunoHost est déjà installé", "yunohost_ca_creation_failed": "Impossible de créer l’autorité de certification", "yunohost_configured": "YunoHost est maintenant configuré", - "yunohost_installing": "L’installation de YunoHost est en cours…", + "yunohost_installing": "L’installation de YunoHost est en cours...", "yunohost_not_installed": "YunoHost n’est pas correctement installé. Veuillez exécuter 'yunohost tools postinstall'", "certmanager_attempt_to_replace_valid_cert": "Vous êtes en train de vouloir remplacer un certificat correct et valide pour le domaine {domain:s} ! (Utilisez --force pour contourner cela)", "certmanager_domain_unknown": "Domaine {domain:s} inconnu", @@ -241,10 +241,10 @@ "backup_couldnt_bind": "Impossible de lier {src:s} avec {dest:s}.", "domain_dns_conf_is_just_a_recommendation": "Cette page montre la configuration *recommandée*. Elle ne configure *pas* le DNS pour vous. Il est de votre responsabilité que de configurer votre zone DNS chez votre fournisseur/registrar DNS avec cette recommandation.", "migrations_cant_reach_migration_file": "Impossible d’accéder aux fichiers de migration via le chemin '%s'", - "migrations_loading_migration": "Chargement de la migration {id} …", + "migrations_loading_migration": "Chargement de la migration {id}...", "migrations_migration_has_failed": "La migration {id} a échoué avec l’exception {exception} : annulation", "migrations_no_migrations_to_run": "Aucune migration à lancer", - "migrations_skip_migration": "Ignorer et passer la migration {id}…", + "migrations_skip_migration": "Ignorer et passer la migration {id}...", "server_shutdown": "Le serveur va s’éteindre", "server_shutdown_confirm": "Le serveur va être éteint immédiatement, le voulez-vous vraiment ? [{answers:s}]", "server_reboot": "Le serveur va redémarrer", @@ -415,7 +415,7 @@ "regenconf_would_be_updated": "La configuration aurait dû être mise à jour pour la catégorie '{category}'", "regenconf_dry_pending_applying": "Vérification de la configuration en attente qui aurait été appliquée pour la catégorie '{category}'…", "regenconf_failed": "Impossible de régénérer la configuration pour la ou les catégorie(s) : '{categories}'", - "regenconf_pending_applying": "Applique la configuration en attente pour la catégorie '{category}' …", + "regenconf_pending_applying": "Applique la configuration en attente pour la catégorie '{category}'...", "service_regen_conf_is_deprecated": "'yunohost service regen-conf' est obsolète ! Veuillez plutôt utiliser 'yunohost tools regen-conf' à la place.", "tools_upgrade_at_least_one": "Veuillez spécifier '--apps' ou '--system'", "tools_upgrade_cant_both": "Impossible de mettre à niveau le système et les applications en même temps", @@ -461,11 +461,11 @@ "permission_updated": "Permission '{permission:s}' mise à jour", "permission_update_nothing_to_do": "Aucune autorisation pour mettre à jour", "dyndns_provider_unreachable": "Impossible d’atteindre le fournisseur DynDNS {provider} : votre YunoHost n’est pas correctement connecté à Internet ou le serveur Dynette est en panne.", - "migration_0011_update_LDAP_schema": "Mise à jour du schéma LDAP…", + "migration_0011_update_LDAP_schema": "Mise à jour du schéma LDAP...", "migrations_already_ran": "Ces migrations sont déjà effectuées : {ids}", "migrations_dependencies_not_satisfied": "Exécutez ces migrations : '{dependencies_id}', avant migration {id}.", "migrations_failed_to_load_migration": "Impossible de charger la migration {id} : {error}", - "migrations_running_forward": "Exécution de la migration {id}…", + "migrations_running_forward": "Exécution de la migration {id}...", "migrations_success_forward": "Migration {id} terminée", "operation_interrupted": "L’opération a été interrompue manuellement ?", "permission_already_exist": "L’autorisation '{permission}' existe déjà", @@ -652,24 +652,24 @@ "diagnosis_swap_tip": "Merci d'être prudent et conscient que si vous hébergez une partition SWAP sur une carte SD ou un disque SSD, cela risque de réduire drastiquement l’espérance de vie du périphérique.", "restore_already_installed_apps": "Les applications suivantes ne peuvent pas être restaurées car elles sont déjà installées : {apps}", "regenconf_need_to_explicitly_specify_ssh": "La configuration de ssh a été modifiée manuellement. Vous devez explicitement indiquer la mention --force à \"ssh\" pour appliquer les changements.", - "migration_0015_cleaning_up": "Nettoyage du cache et des paquets qui ne sont plus utiles …", - "migration_0015_specific_upgrade": "Commencement de la mise à jour des paquets du système qui doivent être mis à jour séparément …", + "migration_0015_cleaning_up": "Nettoyage du cache et des paquets qui ne sont plus utiles...", + "migration_0015_specific_upgrade": "Commencement de la mise à jour des paquets du système qui doivent être mis à jour séparément...", "migration_0015_modified_files": "Veuillez noter que les fichiers suivants ont été modifiés manuellement et pourraient être écrasés à la suite de la mise à niveau : {manually_modified_files}", "migration_0015_problematic_apps_warning": "Veuillez noter que des applications qui peuvent poser problèmes ont été détectées. Il semble qu'elles n'aient pas été installées à partir du catalogue d'applications YunoHost, ou bien qu'elles ne soient pas signalées comme \"fonctionnelles\". Par conséquent, il n'est pas possible de garantir que les applications suivantes fonctionneront encore après la mise à niveau : {problematic_apps}", "migration_0015_general_warning": "Veuillez noter que cette migration est une opération délicate. L'équipe YunoHost a fait de son mieux pour la revérifier et la tester, mais la migration pourrait quand même casser des éléments du système ou de ses applications.\n\nIl est donc recommandé :\n…- de faire une sauvegarde de toute donnée ou application critique. Plus d'informations ici https://yunohost.org/backup ;\n…- d'être patient après le lancement de la migration. Selon votre connexion internet et votre matériel, la mise à niveau peut prendre jusqu'à quelques heures.", "migration_0015_system_not_fully_up_to_date": "Votre système n'est pas entièrement à jour. Veuillez effectuer une mise à jour normale avant de lancer la migration vers Buster.", "migration_0015_not_enough_free_space": "L'espace libre est très faible dans /var/ ! Vous devriez avoir au moins 1 Go de libre pour effectuer cette migration.", "migration_0015_not_stretch": "La distribution Debian actuelle n'est pas Stretch !", - "migration_0015_yunohost_upgrade": "Démarrage de la mise à jour de YunoHost …", + "migration_0015_yunohost_upgrade": "Démarrage de la mise à jour de YunoHost...", "migration_0015_still_on_stretch_after_main_upgrade": "Quelque chose s'est mal passé lors de la mise à niveau, le système semble toujours être sous Debian Stretch", - "migration_0015_main_upgrade": "Démarrage de la mise à niveau générale …", - "migration_0015_patching_sources_list": "Mise à jour du fichier sources.lists …", + "migration_0015_main_upgrade": "Démarrage de la mise à niveau générale...", + "migration_0015_patching_sources_list": "Mise à jour du fichier sources.lists...", "migration_0015_start": "Démarrage de la migration vers Buster", "migration_description_0015_migrate_to_buster": "Mise à niveau du système vers Debian Buster et YunoHost 4.x", "diagnosis_dns_try_dyndns_update_force": "La configuration DNS de ce domaine devrait être automatiquement gérée par Yunohost. Si ce n'est pas le cas, vous pouvez essayer de forcer une mise à jour en utilisant yunohost dyndns update --force.", "app_packaging_format_not_supported": "Cette application ne peut pas être installée car son format n'est pas pris en charge par votre version de YunoHost. Vous devriez probablement envisager de mettre à jour votre système.", "migration_0015_weak_certs": "Il a été constaté que les certificats suivants utilisent encore des algorithmes de signature peu robustes et doivent être mis à jour pour être compatibles avec la prochaine version de NGINX : {certs}", - "global_settings_setting_backup_compress_tar_archives": "Compresser les archives (.tar.gz) au lieu des archives non-compressées lors de la création des backups. N.B. : activer cette option permet d'obtenir des backups plus légers, mais leur création sera significativement plus longue et plus gourmande en CPU.", + "global_settings_setting_backup_compress_tar_archives": "Compresser les archives (.tar.gz) au lieu des archives non-compressées lors de la création des backups. N.B. : activer cette option permet d'obtenir des sauvegardes plus légers, mais leur création sera significativement plus longue et plus gourmande en CPU.", "migration_description_0018_xtable_to_nftable": "Migrer les anciennes règles de trafic réseau vers le nouveau système basé sur nftables", "service_description_php7.3-fpm": "Exécute les applications écrites en PHP avec NGINX", "migration_0018_failed_to_reset_legacy_rules": "La réinitialisation des règles iptable legacy a échoué :", @@ -685,5 +685,10 @@ "app_manifest_install_ask_admin": "Choisissez un administrateur pour cette application", "app_manifest_install_ask_password": "Choisissez un mot de passe administrateur pour cette application", "app_manifest_install_ask_path": "Choisissez le chemin sur lequel vous souhaitez installer cette application", - "app_manifest_install_ask_domain": "Choisissez le domaine sur lequel vous souhaitez installer cette application" + "app_manifest_install_ask_domain": "Choisissez le domaine sur lequel vous souhaitez installer cette application", + "global_settings_setting_smtp_relay_user": "Relais de compte utilisateur SMTP", + "global_settings_setting_smtp_relay_port": "Port relais SMTP", + "global_settings_setting_smtp_relay_host": "Relais SMTP à utiliser pour envoyer du courrier à la place de cette instance YunoHost. Utile si vous êtes dans l'une de ces situations : votre port 25 est bloqué par votre FAI ou votre fournisseur VPS, vous avez une IP résidentielle répertoriée sur DUHL, vous ne pouvez pas configurer de DNS inversé ou ce serveur n'est pas directement exposé sur Internet et vous voulez en utiliser un autre pour envoyer des mails.", + "diagnosis_package_installed_from_sury_details": "Certains paquets ont été installés par inadvertance à partir d'un dépôt tiers appelé Sury. L'équipe YunoHost a amélioré la stratégie de gestion de ces paquets, mais on s'attend à ce que certaines configurations qui ont installé des applications PHP7.3 tout en étant toujours sur Stretch présentent des incohérences. Pour résoudre cette situation, vous devez essayer d'exécuter la commande suivante : {cmd_to_fix} ", + "app_argument_password_no_default": "Erreur lors de l'analyse de l'argument de mot de passe '{name}' : l'argument de mot de passe ne peut pas avoir de valeur par défaut pour des raisons de sécurité" } From 82f89c5d7026d59476a6ad1e224935f4e90f2335 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Gaspar?= Date: Mon, 28 Sep 2020 20:01:33 +0000 Subject: [PATCH 70/71] Translated using Weblate (French) Currently translated at 98.7% (607 of 615 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/fr/ --- locales/fr.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/locales/fr.json b/locales/fr.json index 19a7cb718..d1a60a26a 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -653,7 +653,7 @@ "restore_already_installed_apps": "Les applications suivantes ne peuvent pas être restaurées car elles sont déjà installées : {apps}", "regenconf_need_to_explicitly_specify_ssh": "La configuration de ssh a été modifiée manuellement. Vous devez explicitement indiquer la mention --force à \"ssh\" pour appliquer les changements.", "migration_0015_cleaning_up": "Nettoyage du cache et des paquets qui ne sont plus utiles...", - "migration_0015_specific_upgrade": "Commencement de la mise à jour des paquets du système qui doivent être mis à jour séparément...", + "migration_0015_specific_upgrade": "Démarrage de la mise à jour des paquets du système qui doivent être mis à jour séparément...", "migration_0015_modified_files": "Veuillez noter que les fichiers suivants ont été modifiés manuellement et pourraient être écrasés à la suite de la mise à niveau : {manually_modified_files}", "migration_0015_problematic_apps_warning": "Veuillez noter que des applications qui peuvent poser problèmes ont été détectées. Il semble qu'elles n'aient pas été installées à partir du catalogue d'applications YunoHost, ou bien qu'elles ne soient pas signalées comme \"fonctionnelles\". Par conséquent, il n'est pas possible de garantir que les applications suivantes fonctionneront encore après la mise à niveau : {problematic_apps}", "migration_0015_general_warning": "Veuillez noter que cette migration est une opération délicate. L'équipe YunoHost a fait de son mieux pour la revérifier et la tester, mais la migration pourrait quand même casser des éléments du système ou de ses applications.\n\nIl est donc recommandé :\n…- de faire une sauvegarde de toute donnée ou application critique. Plus d'informations ici https://yunohost.org/backup ;\n…- d'être patient après le lancement de la migration. Selon votre connexion internet et votre matériel, la mise à niveau peut prendre jusqu'à quelques heures.", @@ -669,7 +669,7 @@ "diagnosis_dns_try_dyndns_update_force": "La configuration DNS de ce domaine devrait être automatiquement gérée par Yunohost. Si ce n'est pas le cas, vous pouvez essayer de forcer une mise à jour en utilisant yunohost dyndns update --force.", "app_packaging_format_not_supported": "Cette application ne peut pas être installée car son format n'est pas pris en charge par votre version de YunoHost. Vous devriez probablement envisager de mettre à jour votre système.", "migration_0015_weak_certs": "Il a été constaté que les certificats suivants utilisent encore des algorithmes de signature peu robustes et doivent être mis à jour pour être compatibles avec la prochaine version de NGINX : {certs}", - "global_settings_setting_backup_compress_tar_archives": "Compresser les archives (.tar.gz) au lieu des archives non-compressées lors de la création des backups. N.B. : activer cette option permet d'obtenir des sauvegardes plus légers, mais leur création sera significativement plus longue et plus gourmande en CPU.", + "global_settings_setting_backup_compress_tar_archives": "Compresser les archives (.tar.gz) au lieu des archives non-compressées lors de la création des backups. N.B. : activer cette option permet d'obtenir des sauvegardes plus légères, mais leur création sera significativement plus longue et plus gourmande en CPU.", "migration_description_0018_xtable_to_nftable": "Migrer les anciennes règles de trafic réseau vers le nouveau système basé sur nftables", "service_description_php7.3-fpm": "Exécute les applications écrites en PHP avec NGINX", "migration_0018_failed_to_reset_legacy_rules": "La réinitialisation des règles iptable legacy a échoué :", @@ -680,7 +680,7 @@ "migration_description_0017_postgresql_9p6_to_11": "Migrer les bases de données de PostgreSQL 9.6 vers 11", "migration_description_0016_php70_to_php73_pools": "Migrer les configurations php7.0 vers php7.3", "diagnosis_processes_killed_by_oom_reaper": "Certains processus ont été arrêtés récemment par le système car il manquait de mémoire. Cela apparaît généralement quand le système manque de mémoire ou qu'un processus consomme trop de mémoire. Liste des processus tués :\n{kills_summary}", - "ask_user_domain": "Domaine à utiliser pour l'adresse mail de l'utilisateur et le compte XMPP", + "ask_user_domain": "Domaine à utiliser pour l'adresse email de l'utilisateur et le compte XMPP", "app_manifest_install_ask_is_public": "Cette application devrait-elle être visible par les visiteurs anonymes ?", "app_manifest_install_ask_admin": "Choisissez un administrateur pour cette application", "app_manifest_install_ask_password": "Choisissez un mot de passe administrateur pour cette application", From c94a7614ad4a5a89dcc7eae6eec239da0e0acda9 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 30 Sep 2020 18:43:11 +0200 Subject: [PATCH 71/71] Only restore set -x option if it was previously set --- data/helpers | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/helpers b/data/helpers index 5ec562f61..e1b26db5c 100644 --- a/data/helpers +++ b/data/helpers @@ -1,8 +1,8 @@ # -*- shell-script -*- +readonly XTRACE_ENABLE=$(set +o | grep xtrace) # This is a trick to later only restore set -x if it was set when calling this script set +x for helper in $(run-parts --list /usr/share/yunohost/helpers.d 2>/dev/null) ; do [ -r $helper ] && . $helper || true done -set -x - +eval "$XTRACE_BKP"