Merge branch 'dev' into manifestv2

This commit is contained in:
Alexandre Aubin 2022-02-01 14:24:21 +01:00
commit 8939ba66d3
24 changed files with 315 additions and 133 deletions

View file

@ -1,6 +1,7 @@
[Unit]
Description=YunoHost mDNS service
After=network.target
Wants=network-online.target
After=network-online.target
[Service]
User=mdns

32
debian/changelog vendored
View file

@ -1,3 +1,35 @@
yunohost (11.0.4) testing; urgency=low
- [mod] certificate: drop unused 'staging' LE mode (4b78e8e3)
- [fix] cli: bash_completion was broken ([#1423](https://github.com/YunoHost/yunohost/pull/1423))
- [enh] mdns: Wait for network to be fully up to start the service ([#1425](https://github.com/YunoHost/yunohost/pull/1425))
- [fix] regenconf: make some systemctl enable/disable quiet (bccff1b4, 345e50ae)
- [fix] configpanels: Compute choices for the yunohost admin when installing an app ([#1427](https://github.com/YunoHost/yunohost/pull/1427))
- [fix] configpanels: optimize _get_toml for domains to not load the whole DNS section stuff when just getting a simple info from another section (bf6252ac)
- [fix] configpanel: oopsies, could only change the default app for domain configs :P (0a59f863)
- [fix] php73_to_php74: another search&replace for synapse (f0a01ba2)
- [fix] php73_to_php74: stopping php7.3 before starting 7.4 should be more robust in case confs are conflicting (9ae7ec59)
- [i18n] Translations updated for French, Ukrainian
Thanks to all contributors <3 ! (Éric Gaspar, Kay0u, Tagadda, tituspijean, Tymofii-Lytvynenko)
-- Alexandre Aubin <alex.aubin@mailoo.org> Sat, 29 Jan 2022 19:19:44 +0100
yunohost (11.0.3) testing; urgency=low
- [enh] mail: Add SNI support for postfix and dovecot ([#1413](https://github.com/YunoHost/yunohost/pull/1413))
- [fix] services: fix a couple edge cases (4571c5b2)
- [fix] services: Do not save php-fpm services in services.yml (5d0f8021)
- [fix] diagnosis: diagnosers were run in a funky order ([#1418](https://github.com/YunoHost/yunohost/pull/1418))
- [fix] configpanels: config_get should return possible choices for domain, user questions (and other dynamic-choices questions) ([#1420](https://github.com/YunoHost/yunohost/pull/1420))
- [enh] apps/domain: Clarify the default app mecanism, handle it fron domain config panel ([#1406](https://github.com/YunoHost/yunohost/pull/1406))
- [fix] apps: When no main app permission found, fallback to default label instead of having a 'None' label to prevent the webadmin from displaying an empty app list (07396b8b)
- [i18n] Translations updated for Galician
Thanks to all contributors <3 ! (José M, Kay0u, Tagadda, tituspijean)
-- Alexandre Aubin <alex.aubin@mailoo.org> Tue, 25 Jan 2022 13:06:10 +0100
yunohost (11.0.2) testing; urgency=low
- [mod] Various tweaks for Python 3.9, PHP 7.4, PostgreSQL 13, and other changes related to Buster->Bullseye ecosystem

2
debian/install vendored
View file

@ -5,6 +5,6 @@ helpers/* /usr/share/yunohost/helpers.d/
conf/* /usr/share/yunohost/conf/
locales/* /usr/share/yunohost/locales/
doc/yunohost.8.gz /usr/share/man/man8/
doc/bash-completion.sh /etc/bash_completion.d/yunohost
doc/bash_completion.d/* /etc/bash_completion.d/
conf/metronome/modules/* /usr/lib/metronome/modules/
src/* /usr/lib/python3/dist-packages/yunohost/

View file

@ -13,7 +13,8 @@ import yaml
THIS_SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
ACTIONSMAP_FILE = THIS_SCRIPT_DIR + "/../share/actionsmap.yml"
BASH_COMPLETION_FILE = THIS_SCRIPT_DIR + "/bash-completion.sh"
BASH_COMPLETION_FOLDER = THIS_SCRIPT_DIR + "/bash_completion.d"
BASH_COMPLETION_FILE = BASH_COMPLETION_FOLDER + "/yunohost"
def get_dict_actions(OPTION_SUBTREE, category):
@ -61,6 +62,8 @@ with open(ACTIONSMAP_FILE, "r") as stream:
OPTION_TREE[category]["subcategories"], subcategory
)
os.makedirs(BASH_COMPLETION_FOLDER, exist_ok=True)
with open(BASH_COMPLETION_FILE, "w") as generated_file:
# header of the file

View file

@ -62,7 +62,7 @@ do_init_regen() {
systemctl daemon-reload
systemctl enable yunohost-api.service
systemctl enable yunohost-api.service --quiet
systemctl start yunohost-api.service
# Yunohost-firewall is enabled only during postinstall, not init, not 100% sure why

View file

@ -27,7 +27,7 @@ _generate_config() {
do_init_regen() {
do_pre_regen
do_post_regen /etc/systemd/system/yunomdns.service
systemctl enable yunomdns
systemctl enable yunomdns --quiet
}
do_pre_regen() {
@ -53,12 +53,12 @@ do_post_regen() {
systemctl daemon-reload
fi
systemctl disable avahi-daemon.socket --now 2>&1|| true
systemctl disable avahi-daemon --now 2>&1 || true
systemctl disable avahi-daemon.socket --quiet --now 2>/dev/null || true
systemctl disable avahi-daemon --quiet --now 2>/dev/null || true
# Legacy stuff to enable the new yunomdns service on legacy systems
if [[ -e /etc/avahi/avahi-daemon.conf ]] && grep -q 'yunohost' /etc/avahi/avahi-daemon.conf; then
systemctl enable yunomdns --now
systemctl enable yunomdns --now --quiet
sleep 2
fi

1
locales/da.json Normal file
View file

@ -0,0 +1 @@
{}

View file

@ -310,6 +310,7 @@
"domain_config_auth_key": "Authentication key",
"domain_config_auth_secret": "Authentication secret",
"domain_config_auth_token": "Authentication token",
"domain_config_default_app": "Default app",
"domain_config_features_disclaimer": "So far, enabling/disabling mail or XMPP features only impact the recommended and automatic DNS configuration, not system configurations!",
"domain_config_mail_in": "Incoming emails",
"domain_config_mail_out": "Outgoing emails",
@ -500,7 +501,7 @@
"migration_0021_yunohost_upgrade": "Starting YunoHost core upgrade...",
"migration_0023_not_enough_space": "Make sufficient space available in {path} to run the migration.",
"migration_0023_postgresql_11_not_installed": "PostgreSQL was not installed on your system. Nothing to do.",
"migration_0023_postgresql_13_not_installed": "PostgreSQL 11 is installed, but not postgresql 13!? Something weird might have happened on your system :(...",
"migration_0023_postgresql_13_not_installed": "PostgreSQL 11 is installed, but not PostgreSQL 13!? Something weird might have happened on your system :(...",
"migration_description_0021_migrate_to_bullseye": "Upgrade the system to Debian Bullseye and YunoHost 11.x",
"migration_description_0022_php73_to_php74_pools": "Migrate php7.3-fpm 'pool' conf files to php7.4",
"migration_description_0023_postgresql_11_to_13": "Migrate databases from PostgreSQL 11 to 13",

View file

@ -676,5 +676,14 @@
"migration_0021_patch_yunohost_conflicts": "Application du correctif pour contourner le problème de conflit...",
"migration_0021_not_buster": "La distribution Debian actuelle n'est pas Buster !",
"migration_description_0021_migrate_to_bullseye": "Mise à niveau du système vers Debian Bullseye et YunoHost 11.x",
"global_settings_setting_security_ssh_password_authentication": "Autoriser l'authentification par mot de passe pour SSH"
}
"global_settings_setting_security_ssh_password_authentication": "Autoriser l'authentification par mot de passe pour SSH",
"domain_config_default_app": "Application par défaut",
"migration_description_0022_php73_to_php74_pools": "Migration des fichiers de configuration php7.3-fpm 'pool' vers php7.4",
"migration_description_0023_postgresql_11_to_13": "Migration des bases de données de PostgreSQL 11 vers 13",
"service_description_postgresql": "Stocke les données d'application (base de données SQL)",
"tools_upgrade": "Mise à niveau des packages système",
"migration_0023_postgresql_13_not_installed": "PostgreSQL 11 est installé, mais pas PostgreSQL 13 ! ? Quelque chose d'anormal s'est peut-être produit sur votre système :(...",
"tools_upgrade_failed": "Impossible de mettre à jour les paquets : {packages_list}",
"migration_0023_not_enough_space": "Prévoyez suffisamment d'espace disponible dans {path} pour exécuter la migration.",
"migration_0023_postgresql_11_not_installed": "PostgreSQL n'a pas été installé sur votre système. Il n'y a rien à faire."
}

View file

@ -676,5 +676,13 @@
"migration_description_0021_migrate_to_bullseye": "Actualizar o sistema a Debian Bullseye e YunoHost 11.x",
"migration_0021_system_not_fully_up_to_date": "O teu sistema non está completamente actualizado. Fai unha actualización normal antes de executar a migración a Bullseye.",
"migration_0021_general_warning": "Ten en conta que a migración é unha operación delicada. O equipo de YunoHost fixo todo o que puido para revisalo e probalo, pero aínda así poderían acontecer fallos no sistema ou apps.\n\nAsí as cousas, é recomendable:\n - Facer unha copia de apoio dos datos e apps importantes. Máis info en https://yunohost.org/backup;\n - Ter paciencia unha vez inicias a migración: dependendo da túa conexión a internet e hardware, podería levarlle varias horas completar o proceso.",
"global_settings_setting_security_ssh_password_authentication": "Permitir autenticación con contrasinal para SSH"
}
"global_settings_setting_security_ssh_password_authentication": "Permitir autenticación con contrasinal para SSH",
"tools_upgrade_failed": "Non se actualizaron os paquetes: {packages_list}",
"migration_0023_not_enough_space": "Crear espazo suficiente en {path} para realizar a migración.",
"migration_0023_postgresql_11_not_installed": "PostgreSQL non estaba instalado no sistema. Nada que facer.",
"migration_0023_postgresql_13_not_installed": "PostgreSQL 11 está instalado, pero PostgreSQL 13 non!? Algo raro debeu pasarlle ao teu sistema :(...",
"migration_description_0022_php73_to_php74_pools": "Migrar ficheiros de configuración de php7.3-fpm 'pool' a php7.4",
"migration_description_0023_postgresql_11_to_13": "Migrar bases de datos de PostgreSQL 11 a 13",
"service_description_postgresql": "Almacena datos da app (Base datos SQL)",
"tools_upgrade": "Actualizando paquetes do sistema"
}

View file

@ -676,5 +676,14 @@
"migration_0021_system_not_fully_up_to_date": "Ваша система не повністю оновлена. Будь ласка, виконайте регулярне оновлення перед запуском міграції на Bullseye.",
"migration_0021_general_warning": "Будь ласка, зверніть увагу, що ця міграція є делікатною операцією. Команда YunoHost зробила все можливе, щоб перевірити і протестувати її, але міграція все ще може порушити частину системи або її застосунків.\n\nТому рекомендовано:\n - Виконати резервне копіювання всіх важливих даних або застосунків. Подробиці на сайті https://yunohost.org/backup; \n - Наберіться терпіння після запуску міграції: В залежності від вашого з'єднання з Інтернетом і апаратного забезпечення, оновлення може зайняти до декількох годин.",
"migration_description_0021_migrate_to_bullseye": "Оновлення системи до Debian Bullseye і YunoHost 11.x",
"global_settings_setting_security_ssh_password_authentication": "Дозволити автентифікацію паролем для SSH"
}
"global_settings_setting_security_ssh_password_authentication": "Дозволити автентифікацію паролем для SSH",
"service_description_postgresql": "Зберігає дані застосунків (база даних SQL)",
"domain_config_default_app": "Типовий застосунок",
"migration_0023_postgresql_13_not_installed": "PostgreSQL 11 встановлено, але не PostgreSQL 13!? У вашій системі могло статися щось неприємне :(...",
"migration_description_0023_postgresql_11_to_13": "Перенесення баз даних з PostgreSQL 11 на 13",
"tools_upgrade": "Оновлення системних пакетів",
"tools_upgrade_failed": "Не вдалося оновити наступні пакети: {packages_list}",
"migration_0023_not_enough_space": "Звільніть достатньо місця в {path} для виконання міграції.",
"migration_0023_postgresql_11_not_installed": "PostgreSQL не було встановлено у вашій системі. Нічого робити.",
"migration_description_0022_php73_to_php74_pools": "Перенесення конфігураційних файлів php7.3-fpm 'pool' на php7.4"
}

View file

@ -531,9 +531,6 @@ domain:
--self-signed:
help: Install self-signed certificate instead of Let's Encrypt
action: store_true
--staging:
help: Use the fake/staging Let's Encrypt certification authority. The new certificate won't actually be enabled - it is only intended to test the main steps of the procedure.
action: store_true
### certificate_renew()
cert-renew:
@ -552,9 +549,6 @@ domain:
--no-checks:
help: Does not perform any check that your domain seems correctly configured (DNS, reachability) before attempting to renew. (Not recommended)
action: store_true
--staging:
help: Use the fake/staging Let's Encrypt certification authority. The new certificate won't actually be enabled - it is only intended to test the main steps of the procedure.
action: store_true
### domain_url_available()
url-available:
@ -677,9 +671,6 @@ domain:
--self-signed:
help: Install self-signed certificate instead of Let's Encrypt
action: store_true
--staging:
help: Use the fake/staging Let's Encrypt certification authority. The new certificate won't actually be enabled - it is only intended to test the main steps of the procedure.
action: store_true
### certificate_renew()
renew:
@ -698,9 +689,6 @@ domain:
--no-checks:
help: Does not perform any check that your domain seems correctly configured (DNS, reachability) before attempting to renew. (Not recommended)
action: store_true
--staging:
help: Use the fake/staging Let's Encrypt certification authority. The new certificate won't actually be enabled - it is only intended to test the main steps of the procedure.
action: store_true
#############################
@ -896,6 +884,10 @@ app:
-d:
full: --domain
help: Specific domain to put app on (the app domain by default)
-u:
full: --undo
help: Undo redirection
action: store_true
### app_ssowatconf()
ssowatconf:

View file

@ -11,6 +11,11 @@ i18n = "domain_config"
#
[feature]
[feature.app]
[feature.app.default_app]
type = "app"
filter = "is_webapp"
default = "_none"
[feature.mail]
#services = ['postfix', 'dovecot']

View file

@ -58,6 +58,7 @@ from yunohost.utils.config import (
ask_questions_and_parse_answers,
DomainQuestion,
PathQuestion,
hydrate_questions_with_choices,
)
from yunohost.utils.i18n import _value_for_locale
from yunohost.utils.error import YunohostError, YunohostValidationError
@ -126,6 +127,7 @@ def app_info(app, full=False):
Get info for a specific app
"""
from yunohost.permission import user_permission_list
from yunohost.domain import domain_config_get
_assert_is_installed(app)
@ -162,6 +164,11 @@ def app_info(app, full=False):
ret["is_webapp"] = "domain" in settings and "path" in settings
if ret["is_webapp"]:
ret["is_default"] = (
domain_config_get(settings["domain"], "feature.app.default_app") == app
)
ret["supports_change_url"] = os.path.exists(
os.path.join(setting_path, "scripts", "change_url")
)
@ -178,6 +185,7 @@ def app_info(app, full=False):
if not ret["label"]:
logger.warning(f"Failed to get label for app {app} ?")
ret["label"] = local_manifest["name"]
return ret
@ -722,6 +730,9 @@ def app_manifest(app):
shutil.rmtree(extracted_app_folder)
raw_questions = manifest.get("arguments", {}).get("install", [])
manifest["arguments"]["install"] = hydrate_questions_with_choices(raw_questions)
return manifest
@ -1069,6 +1080,7 @@ def app_remove(operation_logger, app, purge=False):
permission_delete,
permission_sync_to_user,
)
from yunohost.domain import domain_list, domain_config_get, domain_config_set
if not _is_installed(app):
raise YunohostValidationError(
@ -1131,6 +1143,10 @@ def app_remove(operation_logger, app, purge=False):
hook_remove(app)
for domain in domain_list()["domains"]:
if domain_config_get(domain, "feature.app.default_app") == app:
domain_config_set(domain, "feature.app.default_app", "_none")
if ret == 0:
logger.success(m18n.n("app_removed", app=app))
hook_callback("post_app_remove", env=env_dict)
@ -1142,7 +1158,7 @@ def app_remove(operation_logger, app, purge=False):
@is_unit_operation()
def app_makedefault(operation_logger, app, domain=None):
def app_makedefault(operation_logger, app, domain=None, undo=False):
"""
Redirect domain root to an app
@ -1151,11 +1167,10 @@ def app_makedefault(operation_logger, app, domain=None):
domain
"""
from yunohost.domain import _assert_domain_exists
from yunohost.domain import _assert_domain_exists, domain_config_set
app_settings = _get_app_settings(app)
app_domain = app_settings["domain"]
app_path = app_settings["path"]
if domain is None:
domain = app_domain
@ -1164,36 +1179,12 @@ def app_makedefault(operation_logger, app, domain=None):
operation_logger.related_to.append(("domain", domain))
if "/" in app_map(raw=True)[domain]:
raise YunohostValidationError(
"app_make_default_location_already_used",
app=app,
domain=app_domain,
other_app=app_map(raw=True)[domain]["/"]["id"],
)
operation_logger.start()
# TODO / FIXME : current trick is to add this to conf.json.persisten
# This is really not robust and should be improved
# e.g. have a flag in /etc/yunohost/apps/$app/ to say that this is the
# default app or idk...
if not os.path.exists("/etc/ssowat/conf.json.persistent"):
ssowat_conf = {}
if undo:
domain_config_set(domain, "feature.app.default_app", "_none")
else:
ssowat_conf = read_json("/etc/ssowat/conf.json.persistent")
if "redirected_urls" not in ssowat_conf:
ssowat_conf["redirected_urls"] = {}
ssowat_conf["redirected_urls"][domain + "/"] = app_domain + app_path
write_to_json(
"/etc/ssowat/conf.json.persistent", ssowat_conf, sort_keys=True, indent=4
)
chmod("/etc/ssowat/conf.json.persistent", 0o644)
logger.success(m18n.n("ssowat_conf_updated"))
domain_config_set(domain, "feature.app.default_app", app)
def app_setting(app, key, value=None, delete=False):
@ -1392,7 +1383,7 @@ def app_ssowatconf():
"""
from yunohost.domain import domain_list, _get_maindomain
from yunohost.domain import domain_list, _get_maindomain, domain_config_get
from yunohost.permission import user_permission_list
main_domain = _get_maindomain()
@ -1430,6 +1421,23 @@ def app_ssowatconf():
redirected_urls.update(app_settings.get("redirected_urls", {}))
redirected_regex.update(app_settings.get("redirected_regex", {}))
from .utils.legacy import (
translate_legacy_default_app_in_ssowant_conf_json_persistent,
)
translate_legacy_default_app_in_ssowant_conf_json_persistent()
for domain in domains:
default_app = domain_config_get(domain, "feature.app.default_app")
if default_app != "_none" and _is_installed(default_app):
app_settings = _get_app_settings(default_app)
app_domain = app_settings["domain"]
app_path = app_settings["path"]
# Prevent infinite redirect loop...
if domain + "/" != app_domain + app_path:
redirected_urls[domain + "/"] = app_domain + app_path
# New permission system
for perm_name, perm_info in all_permissions.items():

View file

@ -60,8 +60,6 @@ KEY_SIZE = 3072
VALIDITY_LIMIT = 15 # days
# For tests
STAGING_CERTIFICATION_AUTHORITY = "https://acme-staging-v02.api.letsencrypt.org"
# For prod
PRODUCTION_CERTIFICATION_AUTHORITY = "https://acme-v02.api.letsencrypt.org"
@ -113,9 +111,7 @@ def certificate_status(domains, full=False):
return {"certificates": certificates}
def certificate_install(
domain_list, force=False, no_checks=False, self_signed=False, staging=False
):
def certificate_install(domain_list, force=False, no_checks=False, self_signed=False):
"""
Install a Let's Encrypt certificate for given domains (all by default)
@ -130,7 +126,7 @@ def certificate_install(
if self_signed:
_certificate_install_selfsigned(domain_list, force)
else:
_certificate_install_letsencrypt(domain_list, force, no_checks, staging)
_certificate_install_letsencrypt(domain_list, force, no_checks)
def _certificate_install_selfsigned(domain_list, force=False):
@ -233,9 +229,7 @@ def _certificate_install_selfsigned(domain_list, force=False):
operation_logger.error(msg)
def _certificate_install_letsencrypt(
domains, force=False, no_checks=False, staging=False
):
def _certificate_install_letsencrypt(domains, force=False, no_checks=False):
from yunohost.domain import domain_list, _assert_domain_exists
if not os.path.exists(ACCOUNT_KEY_FILE):
@ -264,11 +258,6 @@ def _certificate_install_letsencrypt(
"certmanager_domain_cert_not_selfsigned", domain=domain
)
if staging:
logger.warning(
"Please note that you used the --staging option, and that no new certificate will actually be enabled !"
)
# Actual install steps
for domain in domains:
@ -284,12 +273,12 @@ def _certificate_install_letsencrypt(
operation_logger = OperationLogger(
"letsencrypt_cert_install",
[("domain", domain)],
args={"force": force, "no_checks": no_checks, "staging": staging},
args={"force": force, "no_checks": no_checks},
)
operation_logger.start()
try:
_fetch_and_enable_new_certificate(domain, staging, no_checks=no_checks)
_fetch_and_enable_new_certificate(domain, no_checks=no_checks)
except Exception as e:
msg = f"Certificate installation for {domain} failed !\nException: {e}"
logger.error(msg)
@ -304,9 +293,7 @@ def _certificate_install_letsencrypt(
operation_logger.success()
def certificate_renew(
domains, force=False, no_checks=False, email=False, staging=False
):
def certificate_renew(domains, force=False, no_checks=False, email=False):
"""
Renew Let's Encrypt certificate for given domains (all by default)
@ -373,11 +360,6 @@ def certificate_renew(
"certmanager_acme_not_configured_for_domain", domain=domain
)
if staging:
logger.warning(
"Please note that you used the --staging option, and that no new certificate will actually be enabled !"
)
# Actual renew steps
for domain in domains:
@ -399,14 +381,13 @@ def certificate_renew(
args={
"force": force,
"no_checks": no_checks,
"staging": staging,
"email": email,
},
)
operation_logger.start()
try:
_fetch_and_enable_new_certificate(domain, staging, no_checks=no_checks)
_fetch_and_enable_new_certificate(domain, no_checks=no_checks)
except Exception as e:
import traceback
from io import StringIO
@ -473,7 +454,7 @@ def _check_acme_challenge_configuration(domain):
return "include /etc/nginx/conf.d/acme-challenge.conf.inc" in read_file(domain_conf)
def _fetch_and_enable_new_certificate(domain, staging=False, no_checks=False):
def _fetch_and_enable_new_certificate(domain, no_checks=False):
if not os.path.exists(ACCOUNT_KEY_FILE):
_generate_account_key()
@ -507,11 +488,6 @@ def _fetch_and_enable_new_certificate(domain, staging=False, no_checks=False):
domain_csr_file = f"{TMP_FOLDER}/{domain}.csr"
if staging:
certification_authority = STAGING_CERTIFICATION_AUTHORITY
else:
certification_authority = PRODUCTION_CERTIFICATION_AUTHORITY
try:
signed_certificate = sign_certificate(
ACCOUNT_KEY_FILE,
@ -519,7 +495,7 @@ def _fetch_and_enable_new_certificate(domain, staging=False, no_checks=False):
WEBROOT_FOLDER,
log=logger,
disable_check=no_checks,
CA=certification_authority,
CA=PRODUCTION_CERTIFICATION_AUTHORITY,
)
except ValueError as e:
if "urn:acme:error:rateLimited" in str(e):
@ -539,12 +515,7 @@ def _fetch_and_enable_new_certificate(domain, staging=False, no_checks=False):
# Create corresponding directory
date_tag = datetime.utcnow().strftime("%Y%m%d.%H%M%S")
if staging:
folder_flag = "staging"
else:
folder_flag = "letsencrypt"
new_cert_folder = f"{CERT_FOLDER}/{domain}-history/{date_tag}-{folder_flag}"
new_cert_folder = f"{CERT_FOLDER}/{domain}-history/{date_tag}-letsencrypt"
os.makedirs(new_cert_folder)
@ -563,9 +534,6 @@ def _fetch_and_enable_new_certificate(domain, staging=False, no_checks=False):
_set_permissions(domain_cert_file, "root", "ssl-cert", 0o640)
if staging:
return
_enable_certificate(domain, new_cert_folder)
# Check the status of the certificate is now good
@ -677,12 +645,6 @@ def _get_status(domain):
"verbose": "Let's Encrypt",
}
elif cert_issuer.startswith("Fake LE"):
CA_type = {
"code": "fake-lets-encrypt",
"verbose": "Fake Let's Encrypt",
}
else:
CA_type = {
"code": "other-unknown",

View file

@ -18,7 +18,7 @@ class MyDiagnoser(Diagnoser):
def run(self):
MB = 1024 ** 2
MB = 1024**2
GB = MB * 1024
#

View file

@ -656,9 +656,10 @@ class Diagnoser:
def _list_diagnosis_categories():
paths = glob.glob(os.path.dirname(__file__) + "/diagnosers/??-*.py")
names = [name.split("-")[-1] for name in sorted(
[os.path.basename(path)[: -len(".py")] for path in paths]
)]
names = [
name.split("-")[-1]
for name in sorted([os.path.basename(path)[: -len(".py")] for path in paths])
]
return names

View file

@ -454,19 +454,50 @@ class DomainConfigPanel(ConfigPanel):
save_path_tpl = f"{DOMAIN_SETTINGS_DIR}/{{entity}}.yml"
save_mode = "diff"
def _apply(self):
if (
"default_app" in self.future_values
and self.future_values["default_app"] != self.values["default_app"]
):
from yunohost.app import app_ssowatconf, app_map
if "/" in app_map(raw=True)[self.entity]:
raise YunohostValidationError(
"app_make_default_location_already_used",
app=self.future_values["default_app"],
domain=self.entity,
other_app=app_map(raw=True)[self.entity]["/"]["id"],
)
super()._apply()
# Reload ssowat if default app changed
if (
"default_app" in self.future_values
and self.future_values["default_app"] != self.values["default_app"]
):
app_ssowatconf()
def _get_toml(self):
from yunohost.dns import _get_registrar_config_section
toml = super()._get_toml()
toml["feature"]["xmpp"]["xmpp"]["default"] = (
1 if self.entity == _get_maindomain() else 0
)
toml["dns"]["registrar"] = _get_registrar_config_section(self.entity)
# FIXME: Ugly hack to save the registar id/value and reinject it in _load_current_values ...
self.registar_id = toml["dns"]["registrar"]["registrar"]["value"]
del toml["dns"]["registrar"]["registrar"]["value"]
# Optimize wether or not to load the DNS section,
# e.g. we don't want to trigger the whole _get_registary_config_section
# when just getting the current value from the feature section
filter_key = self.filter_key.split(".") if self.filter_key != "" else []
if not filter_key or filter_key[0] == "dns":
from yunohost.dns import _get_registrar_config_section
toml["dns"]["registrar"] = _get_registrar_config_section(self.entity)
# FIXME: Ugly hack to save the registar id/value and reinject it in _load_current_values ...
self.registar_id = toml["dns"]["registrar"]["registrar"]["value"]
del toml["dns"]["registrar"]["registrar"]["value"]
return toml
@ -476,7 +507,9 @@ class DomainConfigPanel(ConfigPanel):
super()._load_current_values()
# FIXME: Ugly hack to save the registar id/value and reinject it in _load_current_values ...
self.values["registrar"] = self.registar_id
filter_key = self.filter_key.split(".") if self.filter_key != "" else []
if not filter_key or filter_key[0] == "dns":
self.values["registrar"] = self.registar_id
def _get_domain_settings(domain: str) -> dict:
@ -509,20 +542,16 @@ def domain_cert_status(domain_list, full=False):
return certificate_status(domain_list, full)
def domain_cert_install(
domain_list, force=False, no_checks=False, self_signed=False, staging=False
):
def domain_cert_install(domain_list, force=False, no_checks=False, self_signed=False):
from yunohost.certificate import certificate_install
return certificate_install(domain_list, force, no_checks, self_signed, staging)
return certificate_install(domain_list, force, no_checks, self_signed)
def domain_cert_renew(
domain_list, force=False, no_checks=False, email=False, staging=False
):
def domain_cert_renew(domain_list, force=False, no_checks=False, email=False):
from yunohost.certificate import certificate_renew
return certificate_renew(domain_list, force, no_checks, email, staging)
return certificate_renew(domain_list, force, no_checks, email)
def domain_dns_conf(domain):

View file

@ -293,7 +293,7 @@ class MyMigration(Migration):
raise YunohostError("migration_0021_not_buster")
# Have > 1 Go free space on /var/ ?
if free_space_in_directory("/var/") / (1024 ** 3) < 1.0:
if free_space_in_directory("/var/") / (1024**3) < 1.0:
raise YunohostError("migration_0021_not_enough_free_space")
# Check system is up to date

View file

@ -17,6 +17,10 @@ NEWPHP_POOLS = "/etc/php/7.4/fpm/pool.d"
OLDPHP_SOCKETS_PREFIX = "/run/php/php7.3-fpm"
NEWPHP_SOCKETS_PREFIX = "/run/php/php7.4-fpm"
# Because of synapse é_è
OLDPHP_SOCKETS_PREFIX2 = "/run/php7.3-fpm"
NEWPHP_SOCKETS_PREFIX2 = "/run/php7.4-fpm"
MIGRATION_COMMENT = (
"; YunoHost note : this file was automatically moved from {}".format(OLDPHP_POOLS)
)
@ -50,6 +54,10 @@ class MyMigration(Migration):
OLDPHP_SOCKETS_PREFIX, NEWPHP_SOCKETS_PREFIX, dest
)
os.system(c)
c = "sed -i -e 's@{}@{}@g' {}".format(
OLDPHP_SOCKETS_PREFIX2, NEWPHP_SOCKETS_PREFIX2, dest
)
os.system(c)
# Also add a comment that it was automatically moved from php7.3
# (for human traceability and backward migration)
@ -69,16 +77,20 @@ class MyMigration(Migration):
OLDPHP_SOCKETS_PREFIX, NEWPHP_SOCKETS_PREFIX, nf
)
os.system(c)
c = "sed -i -e 's@{}@{}@g' {}".format(
OLDPHP_SOCKETS_PREFIX2, NEWPHP_SOCKETS_PREFIX2, nf
)
os.system(c)
os.system(
"rm /etc/logrotate.d/php7.3-fpm"
) # We remove this otherwise the logrotate cron will be unhappy
# Reload/restart the php pools
_run_service_command("restart", "php7.4-fpm")
_run_service_command("enable", "php7.4-fpm")
os.system("systemctl stop php7.3-fpm")
os.system("systemctl disable php7.3-fpm")
_run_service_command("restart", "php7.4-fpm")
_run_service_command("enable", "php7.4-fpm")
# Reload nginx
_run_service_command("reload", "nginx")

View file

@ -19,6 +19,7 @@ from yunohost.app import (
app_config_set,
app_ssowatconf,
)
from yunohost.user import user_create, user_delete
from yunohost.utils.error import YunohostError, YunohostValidationError
@ -101,6 +102,8 @@ def config_app(request):
def test_app_config_get(config_app):
user_create("alice", "Alice", "White", _get_maindomain(), "test123Ynh")
assert isinstance(app_config_get(config_app), dict)
assert isinstance(app_config_get(config_app, full=True), dict)
assert isinstance(app_config_get(config_app, export=True), dict)
@ -108,6 +111,8 @@ def test_app_config_get(config_app):
assert isinstance(app_config_get(config_app, "main.components"), dict)
assert app_config_get(config_app, "main.components.boolean") == "0"
user_delete("alice")
def test_app_config_nopanel(legacy_app):

View file

@ -214,7 +214,7 @@ def tools_postinstall(
main_space = sum(
psutil.disk_usage(d.mountpoint).total for d in main_disk_partitions
)
GB = 1024 ** 3
GB = 1024**3
if not force_diskspace and main_space < 10 * GB:
raise YunohostValidationError("postinstall_low_rootfsspace")
@ -440,7 +440,7 @@ def tools_upgrade(operation_logger, target=None):
raise YunohostValidationError("dpkg_lock_not_available")
if target not in ["apps", "system"]:
raise Exception(
raise YunohostValidationError(
"Uhoh ?! tools_upgrade should have 'apps' or 'system' value for argument target"
)

View file

@ -285,8 +285,10 @@ class ConfigPanel:
ask = m18n.n(self.config["i18n"] + "_" + option["id"])
if mode == "full":
# edit self.config directly
option["ask"] = ask
question_class = ARGUMENTS_TYPE_PARSERS[option.get("type", "string")]
# FIXME : maybe other properties should be taken from the question, not just choices ?.
option["choices"] = question_class(option).choices
else:
result[key] = {"ask": ask}
if "current_value" in option:
@ -438,6 +440,7 @@ class ConfigPanel:
"step",
"accept",
"redact",
"filter",
],
"defaults": {},
},
@ -703,6 +706,7 @@ class Question:
self.ask = question.get("ask", {"en": self.name})
self.help = question.get("help")
self.redact = question.get("redact", False)
self.filter = question.get("filter", "true")
# .current_value is the currently stored value
self.current_value = question.get("current_value")
# .value is the "proposed" value which we got from the user
@ -1109,7 +1113,10 @@ class DomainQuestion(Question):
if self.default is None:
self.default = _get_maindomain()
self.choices = domain_list()["domains"]
self.choices = {
domain: domain + "" if domain == self.default else domain
for domain in domain_list()["domains"]
}
@staticmethod
def normalize(value, option={}):
@ -1124,6 +1131,33 @@ class DomainQuestion(Question):
return value
class AppQuestion(Question):
argument_type = "app"
def __init__(
self, question, context: Mapping[str, Any] = {}, hooks: Dict[str, Callable] = {}
):
from yunohost.app import app_list
super().__init__(question, context, hooks)
apps = app_list(full=True)["apps"]
if self.filter:
apps = [
app
for app in apps
if evaluate_simple_js_expression(self.filter, context=app)
]
def _app_display(app):
domain_path_or_id = f" ({app.get('domain_path', app['id'])})"
return app["label"] + domain_path_or_id
self.choices = {"_none": "---"}
self.choices.update({app["id"]: _app_display(app) for app in apps})
class UserQuestion(Question):
argument_type = "user"
@ -1134,7 +1168,11 @@ class UserQuestion(Question):
from yunohost.domain import _get_maindomain
super().__init__(question, context, hooks)
self.choices = list(user_list()["users"].keys())
self.choices = {
username: f"{infos['fullname']} ({infos['mail']})"
for username, infos in user_list()["users"].items()
}
if not self.choices:
raise YunohostValidationError(
@ -1145,7 +1183,7 @@ class UserQuestion(Question):
if self.default is None:
root_mail = "root@%s" % _get_maindomain()
for user in self.choices:
for user in self.choices.keys():
if root_mail in user_info(user).get("mail-aliases", []):
self.default = user
break
@ -1331,6 +1369,7 @@ ARGUMENTS_TYPE_PARSERS = {
"alert": DisplayTextQuestion,
"markdown": DisplayTextQuestion,
"file": FileQuestion,
"app": AppQuestion,
}
@ -1378,3 +1417,18 @@ def ask_questions_and_parse_answers(
out.append(question)
return out
def hydrate_questions_with_choices(raw_questions: List) -> List:
out = []
for raw_question in raw_questions:
question = ARGUMENTS_TYPE_PARSERS[raw_question.get("type", "string")](
raw_question
)
if question.choices:
raw_question["choices"] = question.choices
raw_question["default"] = question.default
out.append(raw_question)
return out

View file

@ -7,6 +7,7 @@ from moulinette.utils.filesystem import (
read_file,
write_to_file,
write_to_yaml,
write_to_json,
read_yaml,
)
@ -68,6 +69,55 @@ def legacy_permission_label(app, permission_type):
)
def translate_legacy_default_app_in_ssowant_conf_json_persistent():
from yunohost.app import app_list
from yunohost.domain import domain_config_set
persistent_file_name = "/etc/ssowat/conf.json.persistent"
if not os.path.exists(persistent_file_name):
return
# Ugly hack because for some reason so many people have tabs in their conf.json.persistent ...
os.system(r"sed -i 's/\t/ /g' /etc/ssowat/conf.json.persistent")
# Ugly hack to try not to misarably fail migration
persistent = read_yaml(persistent_file_name)
if "redirected_urls" not in persistent:
return
redirected_urls = persistent["redirected_urls"]
if not any(
from_url.count("/") == 1 and from_url.endswith("/")
for from_url in redirected_urls
):
return
apps = app_list()["apps"]
if not any(app.get("domain_path") in redirected_urls.values() for app in apps):
return
for from_url, dest_url in redirected_urls.copy().items():
# Not a root domain, skip
if from_url.count("/") != 1 or not from_url.endswith("/"):
continue
for app in apps:
if app.get("domain_path") != dest_url:
continue
domain_config_set(from_url.strip("/"), "feature.app.default_app", app["id"])
del redirected_urls[from_url]
persistent["redirected_urls"] = redirected_urls
write_to_json(persistent_file_name, persistent, sort_keys=True, indent=4)
logger.warning(
"YunoHost automatically translated some legacy redirections in /etc/ssowat/conf.json.persistent to match the new default application using domain configuration"
)
LEGACY_PHP_VERSION_REPLACEMENTS = [
("/etc/php5", "/etc/php/7.4"),
("/etc/php/7.0", "/etc/php/7.4"),