mirror of
https://github.com/YunoHost/yunohost.git
synced 2024-09-03 20:06:10 +02:00
wip
This commit is contained in:
parent
3f9fd91334
commit
b6085fef8d
6 changed files with 294 additions and 285 deletions
|
@ -374,26 +374,26 @@
|
|||
"global_settings_cant_write_settings": "Could not save settings file, reason: {reason}",
|
||||
"global_settings_key_doesnt_exists": "The key '{settings_key}' does not exist in the global settings, you can see all the available keys by running 'yunohost settings list'",
|
||||
"global_settings_reset_success": "Previous settings now backed up to {path}",
|
||||
"global_settings_setting_admin_strength": "Admin password strength",
|
||||
"global_settings_setting_backup_compress_tar_archives": "When creating new backups, compress the archives (.tar.gz) instead of uncompressed archives (.tar). N.B. : enabling this option means create lighter backup archives, but the initial backup procedure will be significantly longer and heavy on CPU.",
|
||||
"global_settings_setting_nginx_compatibility": "Compatibility vs. security tradeoff for the web server NGINX. Affects the ciphers (and other security-related aspects)",
|
||||
"global_settings_setting_nginx_redirect_to_https": "Redirect HTTP requests to HTTPs by default (DO NOT TURN OFF unless you really know what you're doing!)",
|
||||
"global_settings_setting_pop3_enabled": "Enable the POP3 protocol for the mail server",
|
||||
"global_settings_setting_postfix_compatibility": "Compatibility vs. security tradeoff for the Postfix server. Affects the ciphers (and other security-related aspects)",
|
||||
"global_settings_setting_security_experimental_enabled": "Enable experimental security features (don't enable this if you don't know what you're doing!)",
|
||||
"global_settings_setting_security_nginx_compatibility": "Compatibility vs. security tradeoff for the web server NGINX. Affects the ciphers (and other security-related aspects)",
|
||||
"global_settings_setting_security_nginx_redirect_to_https": "Redirect HTTP requests to HTTPs by default (DO NOT TURN OFF unless you really know what you're doing!)",
|
||||
"global_settings_setting_security_password_admin_strength": "Admin password strength",
|
||||
"global_settings_setting_security_password_user_strength": "User password strength",
|
||||
"global_settings_setting_security_postfix_compatibility": "Compatibility vs. security tradeoff for the Postfix server. Affects the ciphers (and other security-related aspects)",
|
||||
"global_settings_setting_security_ssh_compatibility": "Compatibility vs. security tradeoff for the SSH server. Affects the ciphers (and other security-related aspects)",
|
||||
"global_settings_setting_security_ssh_password_authentication": "Allow password authentication for SSH",
|
||||
"global_settings_setting_security_ssh_port": "SSH port",
|
||||
"global_settings_setting_security_webadmin_allowlist": "IP adresses allowed to access the webadmin. Comma-separated.",
|
||||
"global_settings_setting_security_webadmin_allowlist_enabled": "Allow only some IPs to access the webadmin.",
|
||||
"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_password": "SMTP relay host password",
|
||||
"global_settings_setting_smtp_relay_port": "SMTP relay port",
|
||||
"global_settings_setting_smtp_relay_user": "SMTP relay user account",
|
||||
"global_settings_setting_ssh_allow_deprecated_dsa_hostkey": "Allow the use of (deprecated) DSA hostkey for the SSH daemon configuration",
|
||||
"global_settings_setting_ssh_compatibility": "Compatibility vs. security tradeoff for the SSH server. Affects the ciphers (and other security-related aspects)",
|
||||
"global_settings_setting_ssh_password_authentication": "Allow password authentication for SSH",
|
||||
"global_settings_setting_ssh_port": "SSH port",
|
||||
"global_settings_setting_ssowat_panel_overlay_enabled": "Enable SSOwat panel overlay",
|
||||
"global_settings_setting_user_strength": "User password strength",
|
||||
"global_settings_setting_webadmin_allowlist": "IP adresses allowed to access the webadmin. Comma-separated.",
|
||||
"global_settings_setting_webadmin_allowlist_enabled": "Allow only some IPs to access the webadmin.",
|
||||
"global_settings_unknown_setting_from_settings_file": "Unknown key in settings: '{setting_key}', discard it and save it in /etc/yunohost/settings-unknown.json",
|
||||
"global_settings_unknown_type": "Unexpected situation, the setting {setting} appears to have the type {unknown_type} 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).",
|
||||
|
|
|
@ -1093,6 +1093,11 @@ settings:
|
|||
list:
|
||||
action_help: list all entries of the settings
|
||||
api: GET /settings
|
||||
arguments:
|
||||
-f:
|
||||
full: --full
|
||||
help: Display all details (meant to be used by the API)
|
||||
action: store_true
|
||||
|
||||
### settings_get()
|
||||
get:
|
||||
|
@ -1101,22 +1106,29 @@ settings:
|
|||
arguments:
|
||||
key:
|
||||
help: Settings key
|
||||
--full:
|
||||
help: Show more details
|
||||
-f:
|
||||
full: --full
|
||||
help: Display all details (meant to be used by the API)
|
||||
action: store_true
|
||||
-e:
|
||||
full: --export
|
||||
help: Only export key/values, meant to be reimported using "config set --args-file"
|
||||
action: store_true
|
||||
|
||||
### settings_set()
|
||||
set:
|
||||
action_help: set an entry value in the settings
|
||||
api: POST /settings/<key>
|
||||
api: PUT /settings
|
||||
arguments:
|
||||
key:
|
||||
help: Settings key
|
||||
help: The question or form key
|
||||
nargs: '?'
|
||||
-v:
|
||||
full: --value
|
||||
help: new value
|
||||
extra:
|
||||
required: True
|
||||
-a:
|
||||
full: --args
|
||||
help: Serialized arguments for new configuration (i.e. "mail_in=0&mail_out=0")
|
||||
|
||||
### settings_reset_all()
|
||||
reset-all:
|
||||
|
|
125
share/config_settings.toml
Normal file
125
share/config_settings.toml
Normal file
|
@ -0,0 +1,125 @@
|
|||
version = "1.0"
|
||||
i18n = "global_settings"
|
||||
|
||||
[security]
|
||||
name = "Security"
|
||||
[security.password]
|
||||
name = "Passwords"
|
||||
[security.password.admin_strength]
|
||||
type = "number"
|
||||
default = 1
|
||||
|
||||
[security.password.user_strength]
|
||||
type = "number"
|
||||
default = 1
|
||||
|
||||
[security.ssh]
|
||||
name = "SSH"
|
||||
[security.ssh.ssh_compatibility]
|
||||
type = "select"
|
||||
default = "modern"
|
||||
choices = ["intermediate", "modern"]
|
||||
|
||||
[security.ssh.ssh_port]
|
||||
type = "number"
|
||||
default = 22
|
||||
|
||||
[security.ssh.ssh_password_authentication]
|
||||
type = "boolean"
|
||||
default = "false"
|
||||
|
||||
[security.ssh.ssh_allow_deprecated_dsa_hostkey]
|
||||
type = "boolean"
|
||||
default = "false"
|
||||
|
||||
[security.nginx]
|
||||
name = "NGINX"
|
||||
[security.nginx.nginx_redirect_to_https]
|
||||
type = "boolean"
|
||||
default = "true"
|
||||
|
||||
[security.nginx.nginx_compatibility]
|
||||
type = "select"
|
||||
default = "intermediate"
|
||||
choices = ["intermediate", "modern"]
|
||||
|
||||
[security.postfix]
|
||||
name = "Postfix"
|
||||
[security.postfix.postfix_compatibility]
|
||||
type = "select"
|
||||
default = "intermediate"
|
||||
choices = ["intermediate", "modern"]
|
||||
|
||||
[security.webadmin]
|
||||
name = "Webadmin"
|
||||
[security.webadmin.webadmin_allowlist_enabled]
|
||||
type = "boolean"
|
||||
default = "false"
|
||||
|
||||
[security.webadmin.webadmin_allowlist]
|
||||
type = "tags"
|
||||
visible = "webadmin_allowlist_enabled"
|
||||
optional = true
|
||||
default = ""
|
||||
|
||||
[security.experimental]
|
||||
name = "Experimental"
|
||||
[security.experimental.security_experimental_enabled]
|
||||
type = "boolean"
|
||||
default = "false"
|
||||
|
||||
|
||||
[email]
|
||||
name = "Email"
|
||||
[email.pop3]
|
||||
name = "POP3"
|
||||
[email.pop3.pop3_enabled]
|
||||
type = "boolean"
|
||||
default = "false"
|
||||
|
||||
[email.smtp]
|
||||
name = "SMTP"
|
||||
[email.smtp.smtp_allow_ipv6]
|
||||
type = "boolean"
|
||||
default = "true"
|
||||
|
||||
[email.smtp.smtp_relay_enabled]
|
||||
type = "boolean"
|
||||
default = "false"
|
||||
|
||||
[email.smtp.smtp_relay_host]
|
||||
type = "string"
|
||||
default = ""
|
||||
optional = true
|
||||
visible="smtp_relay_enabled"
|
||||
|
||||
[email.smtp.smtp_relay_port]
|
||||
type = "number"
|
||||
default = 587
|
||||
visible="smtp_relay_enabled"
|
||||
|
||||
[email.smtp.smtp_relay_user]
|
||||
type = "string"
|
||||
default = ""
|
||||
optional = true
|
||||
visible="smtp_relay_enabled"
|
||||
|
||||
[email.smtp.smtp_relay_password]
|
||||
type = "password"
|
||||
default = ""
|
||||
optional = true
|
||||
visible="smtp_relay_enabled"
|
||||
|
||||
[misc]
|
||||
name = "Other"
|
||||
[misc.ssowat]
|
||||
name = "SSOwat"
|
||||
[misc.ssowat.ssowat_panel_overlay_enabled]
|
||||
type = "boolean"
|
||||
default = "true"
|
||||
|
||||
[misc.backup]
|
||||
name = "Backup"
|
||||
[misc.backup.backup_compress_tar_archives]
|
||||
type = "boolean"
|
||||
default = "false"
|
378
src/settings.py
378
src/settings.py
|
@ -7,14 +7,17 @@ from collections import OrderedDict
|
|||
|
||||
from moulinette import m18n
|
||||
from yunohost.utils.error import YunohostError, YunohostValidationError
|
||||
from yunohost.utils.config import ConfigPanel, Question
|
||||
from moulinette.utils.log import getActionLogger
|
||||
from yunohost.regenconf import regen_conf
|
||||
from yunohost.firewall import firewall_reload
|
||||
from yunohost.log import is_unit_operation
|
||||
from yunohost.utils.legacy import translate_legacy_settings_to_configpanel_settings
|
||||
|
||||
logger = getActionLogger("yunohost.settings")
|
||||
|
||||
SETTINGS_PATH = "/etc/yunohost/settings.json"
|
||||
SETTINGS_PATH_OTHER_LOCATION = "/etc/yunohost/settings-%s.json"
|
||||
SETTINGS_PATH = "/etc/yunohost/settings.yaml"
|
||||
SETTINGS_PATH_OTHER_LOCATION = "/etc/yunohost/settings-%s.yaml"
|
||||
|
||||
|
||||
def is_boolean(value):
|
||||
|
@ -59,71 +62,7 @@ def is_boolean(value):
|
|||
# * string
|
||||
# * enum (in the form of a python list)
|
||||
|
||||
DEFAULTS = OrderedDict(
|
||||
[
|
||||
# Password Validation
|
||||
# -1 disabled, 0 alert if listed, 1 8-letter, 2 normal, 3 strong, 4 strongest
|
||||
("security.password.admin.strength", {"type": "int", "default": 1}),
|
||||
("security.password.user.strength", {"type": "int", "default": 1}),
|
||||
(
|
||||
"service.ssh.allow_deprecated_dsa_hostkey",
|
||||
{"type": "bool", "default": False},
|
||||
),
|
||||
(
|
||||
"security.ssh.compatibility",
|
||||
{
|
||||
"type": "enum",
|
||||
"default": "modern",
|
||||
"choices": ["intermediate", "modern"],
|
||||
},
|
||||
),
|
||||
(
|
||||
"security.ssh.port",
|
||||
{"type": "int", "default": 22},
|
||||
),
|
||||
(
|
||||
"security.ssh.password_authentication",
|
||||
{"type": "bool", "default": True},
|
||||
),
|
||||
(
|
||||
"security.nginx.redirect_to_https",
|
||||
{
|
||||
"type": "bool",
|
||||
"default": True,
|
||||
},
|
||||
),
|
||||
(
|
||||
"security.nginx.compatibility",
|
||||
{
|
||||
"type": "enum",
|
||||
"default": "intermediate",
|
||||
"choices": ["intermediate", "modern"],
|
||||
},
|
||||
),
|
||||
(
|
||||
"security.postfix.compatibility",
|
||||
{
|
||||
"type": "enum",
|
||||
"default": "intermediate",
|
||||
"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": ""}),
|
||||
("backup.compress_tar_archives", {"type": "bool", "default": False}),
|
||||
("ssowat.panel_overlay.enabled", {"type": "bool", "default": True}),
|
||||
("security.webadmin.allowlist.enabled", {"type": "bool", "default": False}),
|
||||
("security.webadmin.allowlist", {"type": "string", "default": ""}),
|
||||
("security.experimental.enabled", {"type": "bool", "default": False}),
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def settings_get(key, full=False):
|
||||
def settings_get(key="", full=False, export=False):
|
||||
"""
|
||||
Get an entry value in the settings
|
||||
|
||||
|
@ -131,28 +70,42 @@ def settings_get(key, full=False):
|
|||
key -- Settings key
|
||||
|
||||
"""
|
||||
settings = _get_settings()
|
||||
|
||||
if key not in settings:
|
||||
if full and export:
|
||||
raise YunohostValidationError(
|
||||
"global_settings_key_doesnt_exists", settings_key=key
|
||||
"You can't use --full and --export together.", raw_msg=True
|
||||
)
|
||||
|
||||
if full:
|
||||
return settings[key]
|
||||
mode = "full"
|
||||
elif export:
|
||||
mode = "export"
|
||||
else:
|
||||
mode = "classic"
|
||||
|
||||
return settings[key]["value"]
|
||||
if mode == "classic" and key == "":
|
||||
raise YunohostValidationError(
|
||||
"Missing key"
|
||||
)
|
||||
|
||||
settings = SettingsConfigPanel()
|
||||
key = translate_legacy_settings_to_configpanel_settings(key)
|
||||
return settings.get(key, mode)
|
||||
|
||||
|
||||
def settings_list():
|
||||
def settings_list(full=False, export=True):
|
||||
"""
|
||||
List all entries of the settings
|
||||
|
||||
"""
|
||||
return _get_settings()
|
||||
|
||||
if full:
|
||||
export = False
|
||||
|
||||
return settings_get(full=full, export=export)
|
||||
|
||||
|
||||
def settings_set(key, value):
|
||||
@is_unit_operation()
|
||||
def settings_set(operation_logger, key=None, value=None, args=None, args_file=None):
|
||||
"""
|
||||
Set an entry value in the settings
|
||||
|
||||
|
@ -161,78 +114,14 @@ def settings_set(key, value):
|
|||
value -- New value
|
||||
|
||||
"""
|
||||
settings = _get_settings()
|
||||
|
||||
if key not in settings:
|
||||
raise YunohostValidationError(
|
||||
"global_settings_key_doesnt_exists", settings_key=key
|
||||
)
|
||||
|
||||
key_type = settings[key]["type"]
|
||||
|
||||
if key_type == "bool":
|
||||
boolean_value = is_boolean(value)
|
||||
if boolean_value[0]:
|
||||
value = boolean_value[1]
|
||||
else:
|
||||
raise YunohostValidationError(
|
||||
"global_settings_bad_type_for_setting",
|
||||
setting=key,
|
||||
received_type=type(value).__name__,
|
||||
expected_type=key_type,
|
||||
)
|
||||
elif key_type == "int":
|
||||
if not isinstance(value, int) or isinstance(value, bool):
|
||||
if isinstance(value, str):
|
||||
try:
|
||||
value = int(value)
|
||||
except Exception:
|
||||
raise YunohostValidationError(
|
||||
"global_settings_bad_type_for_setting",
|
||||
setting=key,
|
||||
received_type=type(value).__name__,
|
||||
expected_type=key_type,
|
||||
)
|
||||
else:
|
||||
raise YunohostValidationError(
|
||||
"global_settings_bad_type_for_setting",
|
||||
setting=key,
|
||||
received_type=type(value).__name__,
|
||||
expected_type=key_type,
|
||||
)
|
||||
elif key_type == "string":
|
||||
if not isinstance(value, str):
|
||||
raise YunohostValidationError(
|
||||
"global_settings_bad_type_for_setting",
|
||||
setting=key,
|
||||
received_type=type(value).__name__,
|
||||
expected_type=key_type,
|
||||
)
|
||||
elif key_type == "enum":
|
||||
if value not in settings[key]["choices"]:
|
||||
raise YunohostValidationError(
|
||||
"global_settings_bad_choice_for_enum",
|
||||
setting=key,
|
||||
choice=str(value),
|
||||
available_choices=", ".join(settings[key]["choices"]),
|
||||
)
|
||||
else:
|
||||
raise YunohostValidationError(
|
||||
"global_settings_unknown_type", setting=key, unknown_type=key_type
|
||||
)
|
||||
|
||||
old_value = settings[key].get("value")
|
||||
settings[key]["value"] = value
|
||||
_save_settings(settings)
|
||||
|
||||
try:
|
||||
trigger_post_change_hook(key, old_value, value)
|
||||
except Exception as e:
|
||||
logger.error(f"Post-change hook for setting {key} failed : {e}")
|
||||
raise
|
||||
Question.operation_logger = operation_logger
|
||||
settings = SettingsConfigPanel()
|
||||
key = translate_legacy_settings_to_configpanel_settings(key)
|
||||
return settings.set(key, value, args, args_file, operation_logger=operation_logger)
|
||||
|
||||
|
||||
def settings_reset(key):
|
||||
@is_unit_operation()
|
||||
def settings_reset(operation_logger, key):
|
||||
"""
|
||||
Set an entry value to its default one
|
||||
|
||||
|
@ -240,18 +129,14 @@ def settings_reset(key):
|
|||
key -- Settings key
|
||||
|
||||
"""
|
||||
settings = _get_settings()
|
||||
|
||||
if key not in settings:
|
||||
raise YunohostValidationError(
|
||||
"global_settings_key_doesnt_exists", settings_key=key
|
||||
)
|
||||
|
||||
settings[key]["value"] = settings[key]["default"]
|
||||
_save_settings(settings)
|
||||
settings = SettingsConfigPanel()
|
||||
key = translate_legacy_settings_to_configpanel_settings(key)
|
||||
return settings.reset(key, operation_logger=operation_logger)
|
||||
|
||||
|
||||
def settings_reset_all():
|
||||
@is_unit_operation()
|
||||
def settings_reset_all(operation_logger):
|
||||
"""
|
||||
Reset all settings to their default value
|
||||
|
||||
|
@ -259,110 +144,72 @@ def settings_reset_all():
|
|||
yes -- Yes I'm sure I want to do that
|
||||
|
||||
"""
|
||||
settings = _get_settings()
|
||||
|
||||
# For now on, we backup the previous settings in case of but we don't have
|
||||
# any mecanism to take advantage of those backups. It could be a nice
|
||||
# addition but we'll see if this is a common need.
|
||||
# Another solution would be to use etckeeper and integrate those
|
||||
# modification inside of it and take advantage of its git history
|
||||
old_settings_backup_path = (
|
||||
SETTINGS_PATH_OTHER_LOCATION % datetime.utcnow().strftime("%F_%X")
|
||||
)
|
||||
_save_settings(settings, location=old_settings_backup_path)
|
||||
|
||||
for value in settings.values():
|
||||
value["value"] = value["default"]
|
||||
|
||||
_save_settings(settings)
|
||||
|
||||
return {
|
||||
"old_settings_backup_path": old_settings_backup_path,
|
||||
"message": m18n.n(
|
||||
"global_settings_reset_success", path=old_settings_backup_path
|
||||
),
|
||||
}
|
||||
settings = SettingsConfigPanel()
|
||||
return settings.reset(operation_logger=operation_logger)
|
||||
|
||||
|
||||
def _get_setting_description(key):
|
||||
return m18n.n(f"global_settings_setting_{key}".replace(".", "_"))
|
||||
return m18n.n(f"global_settings_setting_{key.split('.')[-1]}")
|
||||
|
||||
|
||||
def _get_settings():
|
||||
class SettingsConfigPanel(ConfigPanel):
|
||||
entity_type = "settings"
|
||||
save_path_tpl = SETTINGS_PATH
|
||||
save_mode = "diff"
|
||||
|
||||
settings = {}
|
||||
def __init__(
|
||||
self, config_path=None, save_path=None, creation=False
|
||||
):
|
||||
super().__init__("settings")
|
||||
|
||||
for key, value in DEFAULTS.copy().items():
|
||||
settings[key] = value
|
||||
settings[key]["value"] = value["default"]
|
||||
settings[key]["description"] = _get_setting_description(key)
|
||||
def _apply(self):
|
||||
super()._apply()
|
||||
|
||||
if not os.path.exists(SETTINGS_PATH):
|
||||
return settings
|
||||
settings = { k: v for k, v in self.future_values.items() if self.values.get(k) != v }
|
||||
for setting_name, value in settings.items():
|
||||
try:
|
||||
trigger_post_change_hook(setting_name, self.values.get(setting_name), value)
|
||||
except Exception as e:
|
||||
logger.error(f"Post-change hook for setting failed : {e}")
|
||||
raise
|
||||
|
||||
# we have a very strict policy on only allowing settings that we know in
|
||||
# the OrderedDict DEFAULTS
|
||||
# For various reason, while reading the local settings we might encounter
|
||||
# settings that aren't in DEFAULTS, those can come from settings key that
|
||||
# we have removed, errors or the user trying to modify
|
||||
# /etc/yunohost/settings.json
|
||||
# To avoid to simply overwrite them, we store them in
|
||||
# /etc/yunohost/settings-unknown.json in case of
|
||||
unknown_settings = {}
|
||||
unknown_settings_path = SETTINGS_PATH_OTHER_LOCATION % "unknown"
|
||||
def reset(self, key = "", operation_logger=None):
|
||||
self.filter_key = key
|
||||
|
||||
# Read config panel toml
|
||||
self._get_config_panel()
|
||||
|
||||
if not self.config:
|
||||
raise YunohostValidationError("config_no_panel")
|
||||
|
||||
# Replace all values with default values
|
||||
self.values = self._get_default_values()
|
||||
|
||||
Question.operation_logger = operation_logger
|
||||
|
||||
if operation_logger:
|
||||
operation_logger.start()
|
||||
|
||||
if os.path.exists(unknown_settings_path):
|
||||
try:
|
||||
unknown_settings = json.load(open(unknown_settings_path, "r"))
|
||||
except Exception as e:
|
||||
logger.warning(f"Error while loading unknown settings {e}")
|
||||
self._apply()
|
||||
except YunohostError:
|
||||
raise
|
||||
# Script got manually interrupted ...
|
||||
# N.B. : KeyboardInterrupt does not inherit from Exception
|
||||
except (KeyboardInterrupt, EOFError):
|
||||
error = m18n.n("operation_interrupted")
|
||||
logger.error(m18n.n("config_apply_failed", error=error))
|
||||
raise
|
||||
# Something wrong happened in Yunohost's code (most probably hook_exec)
|
||||
except Exception:
|
||||
import traceback
|
||||
|
||||
try:
|
||||
with open(SETTINGS_PATH) as settings_fd:
|
||||
local_settings = json.load(settings_fd)
|
||||
error = m18n.n("unexpected_error", error="\n" + traceback.format_exc())
|
||||
logger.error(m18n.n("config_apply_failed", error=error))
|
||||
raise
|
||||
|
||||
for key, value in local_settings.items():
|
||||
if key in settings:
|
||||
settings[key] = value
|
||||
settings[key]["description"] = _get_setting_description(key)
|
||||
else:
|
||||
logger.warning(
|
||||
m18n.n(
|
||||
"global_settings_unknown_setting_from_settings_file",
|
||||
setting_key=key,
|
||||
)
|
||||
)
|
||||
unknown_settings[key] = value
|
||||
except Exception as e:
|
||||
raise YunohostValidationError("global_settings_cant_open_settings", reason=e)
|
||||
|
||||
if unknown_settings:
|
||||
try:
|
||||
_save_settings(unknown_settings, location=unknown_settings_path)
|
||||
_save_settings(settings)
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to save unknown settings (because {e}), aborting.")
|
||||
|
||||
return settings
|
||||
|
||||
|
||||
def _save_settings(settings, location=SETTINGS_PATH):
|
||||
settings_without_description = {}
|
||||
for key, value in settings.items():
|
||||
settings_without_description[key] = value
|
||||
if "description" in value:
|
||||
del settings_without_description[key]["description"]
|
||||
|
||||
try:
|
||||
result = json.dumps(settings_without_description, indent=4)
|
||||
except Exception as e:
|
||||
raise YunohostError("global_settings_cant_serialize_settings", reason=e)
|
||||
|
||||
try:
|
||||
with open(location, "w") as settings_fd:
|
||||
settings_fd.write(result)
|
||||
except Exception as e:
|
||||
raise YunohostError("global_settings_cant_write_settings", reason=e)
|
||||
logger.success("Config updated as expected")
|
||||
operation_logger.success()
|
||||
|
||||
|
||||
# Meant to be a dict of setting_name -> function to call
|
||||
|
@ -370,13 +217,8 @@ post_change_hooks = {}
|
|||
|
||||
|
||||
def post_change_hook(setting_name):
|
||||
# TODO: Check that setting_name exists
|
||||
def decorator(func):
|
||||
assert (
|
||||
setting_name in DEFAULTS.keys()
|
||||
), f"The setting {setting_name} does not exists"
|
||||
assert (
|
||||
setting_name not in post_change_hooks
|
||||
), f"You can only register one post change hook per setting (in particular for {setting_name})"
|
||||
post_change_hooks[setting_name] = func
|
||||
return func
|
||||
|
||||
|
@ -404,48 +246,48 @@ def trigger_post_change_hook(setting_name, old_value, new_value):
|
|||
# ===========================================
|
||||
|
||||
|
||||
@post_change_hook("ssowat.panel_overlay.enabled")
|
||||
@post_change_hook("security.nginx.redirect_to_https")
|
||||
@post_change_hook("security.nginx.compatibility")
|
||||
@post_change_hook("security.webadmin.allowlist.enabled")
|
||||
@post_change_hook("security.webadmin.allowlist")
|
||||
@post_change_hook("ssowat_panel_overlay_enabled")
|
||||
@post_change_hook("nginx_redirect_to_https")
|
||||
@post_change_hook("nginx_compatibility")
|
||||
@post_change_hook("webadmin_allowlist_enabled")
|
||||
@post_change_hook("webadmin_allowlist")
|
||||
def reconfigure_nginx(setting_name, old_value, new_value):
|
||||
if old_value != new_value:
|
||||
regen_conf(names=["nginx"])
|
||||
|
||||
|
||||
@post_change_hook("security.experimental.enabled")
|
||||
@post_change_hook("security_experimental_enabled")
|
||||
def reconfigure_nginx_and_yunohost(setting_name, old_value, new_value):
|
||||
if old_value != new_value:
|
||||
regen_conf(names=["nginx", "yunohost"])
|
||||
|
||||
|
||||
@post_change_hook("security.ssh.compatibility")
|
||||
@post_change_hook("security.ssh.password_authentication")
|
||||
@post_change_hook("ssh_compatibility")
|
||||
@post_change_hook("ssh_password_authentication")
|
||||
def reconfigure_ssh(setting_name, old_value, new_value):
|
||||
if old_value != new_value:
|
||||
regen_conf(names=["ssh"])
|
||||
|
||||
|
||||
@post_change_hook("security.ssh.port")
|
||||
@post_change_hook("ssh_port")
|
||||
def reconfigure_ssh_and_fail2ban(setting_name, old_value, new_value):
|
||||
if old_value != new_value:
|
||||
regen_conf(names=["ssh", "fail2ban"])
|
||||
firewall_reload()
|
||||
|
||||
|
||||
@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")
|
||||
@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("postfix_compatibility")
|
||||
def reconfigure_postfix(setting_name, old_value, new_value):
|
||||
if old_value != new_value:
|
||||
regen_conf(names=["postfix"])
|
||||
|
||||
|
||||
@post_change_hook("pop3.enabled")
|
||||
@post_change_hook("pop3_enabled")
|
||||
def reconfigure_dovecot(setting_name, old_value, new_value):
|
||||
dovecot_package = "dovecot-pop3d"
|
||||
|
||||
|
|
|
@ -801,6 +801,11 @@ class Question:
|
|||
|
||||
def _prevalidate(self):
|
||||
if self.value in [None, ""] and not self.optional:
|
||||
import traceback
|
||||
error = m18n.n("unexpected_error", error="\n" + traceback.format_exc())
|
||||
msg = m18n.n("unexpected_error", app=app_instance_name, error=error)
|
||||
logger.error(msg)
|
||||
operation_logger.error(msg)
|
||||
raise YunohostValidationError("app_argument_required", name=self.name)
|
||||
|
||||
# we have an answer, do some post checks
|
||||
|
|
|
@ -62,6 +62,31 @@ LEGACY_PERMISSION_LABEL = {
|
|||
): "api", # $excaped_domain$excaped_path/[%w-.]*/[%w-.]*/git%-receive%-pack,$excaped_domain$excaped_path/[%w-.]*/[%w-.]*/git%-upload%-pack,$excaped_domain$excaped_path/[%w-.]*/[%w-.]*/info/refs
|
||||
}
|
||||
|
||||
LEGACY_SETTINGS = {
|
||||
"security.password.admin.strength": "security.password.admin_strength",
|
||||
"security.password.user.strength": "security.password.user_strength",
|
||||
"security.ssh.compatibility": "security.ssh.ssh_compatibility",
|
||||
"security.ssh.port": "security.ssh.ssh_port",
|
||||
"security.ssh.password_authentication": "security.ssh.ssh_password_authentication",
|
||||
"service.ssh.allow_deprecated_dsa_hostkey": "security.ssh.ssh_allow_deprecated_dsa_hostkey",
|
||||
"security.nginx.redirect_to_https": "security.nginx.nginx_redirect_to_https",
|
||||
"security.nginx.compatibility": "security.nginx.nginx_compatibility",
|
||||
"security.postfix.compatibility": "security.postfix.postfix_compatibility",
|
||||
"pop3.enabled": "email.pop3.pop3_enabled",
|
||||
"smtp.allow_ipv6": "email.smtp.smtp_allow_ipv6",
|
||||
"smtp.relay.host": "email.smtp.smtp_relay_host",
|
||||
"smtp.relay.port": "email.smtp.smtp_relay_port",
|
||||
"smtp.relay.user": "email.smtp.smtp_relay_user",
|
||||
"smtp.relay.password": "email.smtp.smtp_relay_password",
|
||||
"backup.compress_tar_archives": "misc.backup.backup_compress_tar_archives",
|
||||
"ssowat.panel_overlay.enabled": "misc.ssowat.ssowat_panel_overlay_enabled",
|
||||
"security.webadmin.allowlist.enabled": "security.webadmin.webadmin_allowlist_enabled",
|
||||
"security.webadmin.allowlist": "security.webadmin.webadmin_allowlist",
|
||||
"security.experimental.enabled": "security.experimental.security_experimental_enabled"
|
||||
}
|
||||
|
||||
def translate_legacy_settings_to_configpanel_settings(settings):
|
||||
return LEGACY_SETTINGS.get(settings, settings)
|
||||
|
||||
def legacy_permission_label(app, permission_type):
|
||||
return LEGACY_PERMISSION_LABEL.get(
|
||||
|
|
Loading…
Add table
Reference in a new issue