Merge branch 'stretch-unstable' into hook_return

This commit is contained in:
Josué Tille 2019-02-11 16:06:03 +01:00
commit cbf2c1f82a
No known key found for this signature in database
GPG key ID: D5E068C6DFA8681D
55 changed files with 3234 additions and 815 deletions

View file

@ -13,7 +13,8 @@ DEFAULT_HOST = 'localhost'
DEFAULT_PORT = 6787 DEFAULT_PORT = 6787
# Level for which loggers will log # Level for which loggers will log
LOGGERS_LEVEL = 'INFO' LOGGERS_LEVEL = 'DEBUG'
API_LOGGER_LEVEL = 'INFO'
# Handlers that will be used by loggers # Handlers that will be used by loggers
# - file: log to the file LOG_DIR/LOG_FILE # - file: log to the file LOG_DIR/LOG_FILE
@ -97,8 +98,10 @@ def _init_moulinette(use_websocket=True, debug=False, verbose=False):
# Define loggers level # Define loggers level
level = LOGGERS_LEVEL level = LOGGERS_LEVEL
api_level = API_LOGGER_LEVEL
if debug: if debug:
level = 'DEBUG' level = 'DEBUG'
api_level = 'DEBUG'
# Custom logging configuration # Custom logging configuration
logging = { logging = {
@ -119,6 +122,7 @@ def _init_moulinette(use_websocket=True, debug=False, verbose=False):
}, },
'handlers': { 'handlers': {
'api': { 'api': {
'level': api_level,
'class': 'moulinette.interfaces.api.APIQueueHandler', 'class': 'moulinette.interfaces.api.APIQueueHandler',
}, },
'file': { 'file': {
@ -145,6 +149,11 @@ def _init_moulinette(use_websocket=True, debug=False, verbose=False):
'handlers': [], 'handlers': [],
'propagate': True, 'propagate': True,
}, },
'gnupg': {
'level': 'INFO',
'handlers': [],
'propagate': False,
},
}, },
'root': { 'root': {
'level': level, 'level': level,

View file

@ -1,8 +1,5 @@
#!/bin/bash #!/bin/bash
# Fetch ips
ip=$(hostname --all-ip-address)
# Fetch SSH fingerprints # Fetch SSH fingerprints
i=0 i=0
for key in $(ls /etc/ssh/ssh_host_{ed25519,rsa,ecdsa}_key.pub 2> /dev/null) ; do for key in $(ls /etc/ssh/ssh_host_{ed25519,rsa,ecdsa}_key.pub 2> /dev/null) ; do
@ -32,11 +29,17 @@ EOF
# Build the actual message # Build the actual message
# #
sleep 5
# Get local IP
# (we do this after the sleep 5 to have
# better chances that the network is up)
local_ip=$(hostname --all-ip-address | awk '{print $1}')
LOGO_AND_FINGERPRINTS=$(cat << EOF LOGO_AND_FINGERPRINTS=$(cat << EOF
$LOGO $LOGO
IP: ${ip} IP: ${local_ip}
SSH fingerprints: SSH fingerprints:
${fingerprint[0]} ${fingerprint[0]}
${fingerprint[1]} ${fingerprint[1]}
@ -51,17 +54,35 @@ if [[ -f /etc/yunohost/installed ]]
then then
echo "$LOGO_AND_FINGERPRINTS" > /etc/issue echo "$LOGO_AND_FINGERPRINTS" > /etc/issue
else else
sleep 5
chvt 2 chvt 2
# Formatting
[[ -n "$local_ip" ]] && local_ip=$(echo -e "https://$local_ip/") || local_ip="(no ip detected?)"
echo "$LOGO_AND_FINGERPRINTS" echo "$LOGO_AND_FINGERPRINTS"
echo -e "\e[m Post-installation \e[0m" cat << EOF
echo "Congratulations! YunoHost has been successfully installed.\nTwo more steps are required to activate the services of your server." ===============================================================================
read -p "Proceed to post-installation? (y/n)\nAlternatively, you can proceed the post-installation on https://${ip}" -n 1 You should now proceed with Yunohost post-installation. This is where you will
be asked for :
- the main domain of your server ;
- the administration password.
You can perform this step :
- from your web browser, by accessing : ${local_ip}
- or in this terminal by answering 'yes' to the following question
If this is your first time with YunoHost, it is strongly recommended to take
time to read the administator documentation and in particular the sections
'Finalizing your setup' and 'Getting to know YunoHost'. It is available at
the following URL : https://yunohost.org/admindoc
===============================================================================
EOF
read -p "Proceed with post-installation? (y/n) "
RESULT=1 RESULT=1
while [ $RESULT -gt 0 ]; do while [ $RESULT -gt 0 ]; do
if [[ $REPLY =~ ^[Nn]$ ]]; then if [[ $REPLY =~ ^[Nn]$ ]]; then
chvt 1 break
exit 0
fi fi
echo -e "\n" echo -e "\n"
/usr/bin/yunohost tools postinstall /usr/bin/yunohost tools postinstall
@ -71,4 +92,6 @@ else
read -p "Retry? (y/n) " -n 1 read -p "Retry? (y/n) " -n 1
fi fi
done done
chvt 1
exit 0
fi fi

View file

@ -148,6 +148,7 @@ user:
extra: extra:
pattern: *pattern_username pattern: *pattern_username
--purge: --purge:
help: Purge user's home and mail directories
action: store_true action: store_true
### user_update() ### user_update()
@ -605,14 +606,14 @@ app:
full: --domain full: --domain
help: New app domain on which the application will be moved help: New app domain on which the application will be moved
extra: extra:
ask: ask_main_domain ask: ask_new_domain
pattern: *pattern_domain pattern: *pattern_domain
required: True required: True
-p: -p:
full: --path full: --path
help: New path at which the application will be moved help: New path at which the application will be moved
extra: extra:
ask: ask_path ask: ask_new_path
required: True required: True
### app_setting() ### app_setting()
@ -1148,6 +1149,14 @@ service:
-d: -d:
full: --description full: --description
help: Description of the service help: Description of the service
-t:
full: --log_type
help: Type of the log (file or systemd)
nargs: "+"
choices:
- file
- systemd
default: file
### service_remove() ### service_remove()
remove: remove:
@ -1177,6 +1186,33 @@ service:
nargs: "+" nargs: "+"
metavar: NAME metavar: NAME
### service_reload()
reload:
action_help: Reload one or more services
arguments:
names:
help: Service name to reload
nargs: "+"
metavar: NAME
### service_restart()
restart:
action_help: Restart one or more services. If the services are not running yet, they will be started.
arguments:
names:
help: Service name to restart
nargs: "+"
metavar: NAME
### service_reload_or_restart()
reload_or_restart:
action_help: Reload one or more services if they support it. If not, restart them instead. If the services are not running yet, they will be started.
arguments:
names:
help: Service name to reload or restart
nargs: "+"
metavar: NAME
### service_enable() ### service_enable()
enable: enable:
action_help: Enable one or more services action_help: Enable one or more services

View file

@ -1,9 +1,11 @@
#!/bin/bash
# Use logrotate to manage the logfile # Use logrotate to manage the logfile
# #
# usage: ynh_use_logrotate [logfile] [--non-append|--append] [specific_user/specific_group] # usage: ynh_use_logrotate [--logfile=/log/file] [--nonappend] [--specific_user=user/group]
# | arg: logfile - absolute path of logfile # | arg: -l, --logfile= - absolute path of logfile
# | arg: --non-append - (Option) Replace the config file instead of appending this new config. # | arg: -n, --nonappend - (Option) Replace the config file instead of appending this new config.
# | arg: specific_user : run logrotate as the specified user and group. If not specified logrotate is runned as root. # | arg: -u, --specific_user : run logrotate as the specified user and group. If not specified logrotate is runned as root.
# #
# If no argument provided, a standard directory will be use. /var/log/${app} # If no argument provided, a standard directory will be use. /var/log/${app}
# You can provide a path with the directory only or with the logfile. # You can provide a path with the directory only or with the logfile.
@ -13,28 +15,53 @@
# It's possible to use this helper several times, each config will be added to the same logrotate config file. # It's possible to use this helper several times, each config will be added to the same logrotate config file.
# Unless you use the option --non-append # Unless you use the option --non-append
ynh_use_logrotate () { ynh_use_logrotate () {
local customtee="tee -a" # Declare an array to define the options of this helper.
local user_group="${3:-}" local legacy_args=lnuya
declare -Ar args_array=( [l]=logfile= [n]=nonappend [u]=specific_user= [y]=non [a]=append )
# [y]=non [a]=append are only for legacy purpose, to not fail on the old option '--non-append'
local logfile
local nonappend
local specific_user
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
local logfile="${logfile:-}"
local nonappend="${nonappend:-0}"
local specific_user="${specific_user:-}"
# LEGACY CODE - PRE GETOPTS
if [ $# -gt 0 ] && [ "$1" == "--non-append" ]; then if [ $# -gt 0 ] && [ "$1" == "--non-append" ]; then
customtee="tee" nonappend=1
# Destroy this argument for the next command. # Destroy this argument for the next command.
shift shift
elif [ $# -gt 1 ] && [ "$2" == "--non-append" ]; then elif [ $# -gt 1 ] && [ "$2" == "--non-append" ]; then
customtee="tee" nonappend=1
fi fi
if [ $# -gt 0 ]; then
if [ $# -gt 0 ] && [ "$(echo ${1:0:1})" != "-" ]; then
if [ "$(echo ${1##*.})" == "log" ]; then # Keep only the extension to check if it's a logfile if [ "$(echo ${1##*.})" == "log" ]; then # Keep only the extension to check if it's a logfile
local logfile=$1 # In this case, focus logrotate on the logfile local logfile=$1 # In this case, focus logrotate on the logfile
else else
local logfile=$1/*.log # Else, uses the directory and all logfile into it. local logfile=$1/*.log # Else, uses the directory and all logfile into it.
fi fi
fi
# LEGACY CODE
local customtee="tee -a"
if [ "$nonappend" -eq 1 ]; then
customtee="tee"
fi
if [ -n "$logfile" ]
then
if [ "$(echo ${logfile##*.})" != "log" ]; then # Keep only the extension to check if it's a logfile
local logfile="$1/*.log" # Else, uses the directory and all logfile into it.
fi
else else
local logfile="/var/log/${app}/*.log" # Without argument, use a defaut directory in /var/log logfile="/var/log/${app}/*.log" # Without argument, use a defaut directory in /var/log
fi fi
local su_directive="" local su_directive=""
if [[ -n $user_group ]]; then if [[ -n $specific_user ]]; then
su_directive=" # Run logorotate as specific user - group su_directive=" # Run logorotate as specific user - group
su ${user_group%/*} ${user_group#*/}" su ${specific_user%/*} ${specific_user#*/}"
fi fi
cat > ./${app}-logrotate << EOF # Build a config file for logrotate cat > ./${app}-logrotate << EOF # Build a config file for logrotate
@ -73,9 +100,9 @@ ynh_remove_logrotate () {
# Create a dedicated systemd config # Create a dedicated systemd config
# #
# usage: ynh_add_systemd_config [service] [template] # usage: ynh_add_systemd_config [--service=service] [--template=template]
# | arg: service - Service name (optionnal, $app by default) # | arg: -s, --service - Service name (optionnal, $app by default)
# | arg: template - Name of template file (optionnal, this is 'systemd' by default, meaning ./conf/systemd.service will be used as template) # | arg: -t, --template - Name of template file (optionnal, this is 'systemd' by default, meaning ./conf/systemd.service will be used as template)
# #
# This will use the template ../conf/<templatename>.service # This will use the template ../conf/<templatename>.service
# to generate a systemd config, by replacing the following keywords # to generate a systemd config, by replacing the following keywords
@ -86,40 +113,54 @@ ynh_remove_logrotate () {
# __FINALPATH__ by $final_path # __FINALPATH__ by $final_path
# #
ynh_add_systemd_config () { ynh_add_systemd_config () {
local service_name="${1:-$app}" # Declare an array to define the options of this helper.
local legacy_args=st
declare -Ar args_array=( [s]=service= [t]=template= )
local service
local template
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
local service="${service:-$app}"
local template="${template:-systemd.service}"
finalsystemdconf="/etc/systemd/system/$service_name.service" finalsystemdconf="/etc/systemd/system/$service.service"
ynh_backup_if_checksum_is_different "$finalsystemdconf" ynh_backup_if_checksum_is_different --file="$finalsystemdconf"
sudo cp ../conf/${2:-systemd.service} "$finalsystemdconf" sudo cp ../conf/$template "$finalsystemdconf"
# To avoid a break by set -u, use a void substitution ${var:-}. If the variable is not set, it's simply set with an empty variable. # To avoid a break by set -u, use a void substitution ${var:-}. If the variable is not set, it's simply set with an empty variable.
# Substitute in a nginx config file only if the variable is not empty # Substitute in a nginx config file only if the variable is not empty
if test -n "${final_path:-}"; then if test -n "${final_path:-}"; then
ynh_replace_string "__FINALPATH__" "$final_path" "$finalsystemdconf" ynh_replace_string --match_string="__FINALPATH__" --replace_string="$final_path" --target_file="$finalsystemdconf"
fi fi
if test -n "${app:-}"; then if test -n "${app:-}"; then
ynh_replace_string "__APP__" "$app" "$finalsystemdconf" ynh_replace_string --match_string="__APP__" --replace_string="$app" --target_file="$finalsystemdconf"
fi fi
ynh_store_file_checksum "$finalsystemdconf" ynh_store_file_checksum --file="$finalsystemdconf"
sudo chown root: "$finalsystemdconf" sudo chown root: "$finalsystemdconf"
sudo systemctl enable $service_name sudo systemctl enable $service
sudo systemctl daemon-reload sudo systemctl daemon-reload
} }
# Remove the dedicated systemd config # Remove the dedicated systemd config
# #
# usage: ynh_remove_systemd_config [service] # usage: ynh_remove_systemd_config [--service=service]
# | arg: service - Service name (optionnal, $app by default) # | arg: -s, --service - Service name (optionnal, $app by default)
# #
ynh_remove_systemd_config () { ynh_remove_systemd_config () {
local service_name="${1:-$app}" # Declare an array to define the options of this helper.
local legacy_args=s
declare -Ar args_array=( [s]=service= )
local service
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
local service="${service:-$app}"
local finalsystemdconf="/etc/systemd/system/$service_name.service" local finalsystemdconf="/etc/systemd/system/$service.service"
if [ -e "$finalsystemdconf" ]; then if [ -e "$finalsystemdconf" ]; then
sudo systemctl stop $service_name sudo systemctl stop $service
sudo systemctl disable $service_name sudo systemctl disable $service
ynh_secure_remove "$finalsystemdconf" ynh_secure_remove --file="$finalsystemdconf"
sudo systemctl daemon-reload sudo systemctl daemon-reload
fi fi
} }
@ -145,7 +186,7 @@ ynh_remove_systemd_config () {
ynh_add_nginx_config () { ynh_add_nginx_config () {
finalnginxconf="/etc/nginx/conf.d/$domain.d/$app.conf" finalnginxconf="/etc/nginx/conf.d/$domain.d/$app.conf"
local others_var=${1:-} local others_var=${1:-}
ynh_backup_if_checksum_is_different "$finalnginxconf" ynh_backup_if_checksum_is_different --file="$finalnginxconf"
sudo cp ../conf/nginx.conf "$finalnginxconf" sudo cp ../conf/nginx.conf "$finalnginxconf"
# To avoid a break by set -u, use a void substitution ${var:-}. If the variable is not set, it's simply set with an empty variable. # To avoid a break by set -u, use a void substitution ${var:-}. If the variable is not set, it's simply set with an empty variable.
@ -153,20 +194,20 @@ ynh_add_nginx_config () {
if test -n "${path_url:-}"; then if test -n "${path_url:-}"; then
# path_url_slash_less is path_url, or a blank value if path_url is only '/' # path_url_slash_less is path_url, or a blank value if path_url is only '/'
local path_url_slash_less=${path_url%/} local path_url_slash_less=${path_url%/}
ynh_replace_string "__PATH__/" "$path_url_slash_less/" "$finalnginxconf" ynh_replace_string --match_string="__PATH__/" --replace_string="$path_url_slash_less/" --target_file="$finalnginxconf"
ynh_replace_string "__PATH__" "$path_url" "$finalnginxconf" ynh_replace_string --match_string="__PATH__" --replace_string="$path_url" --target_file="$finalnginxconf"
fi fi
if test -n "${domain:-}"; then if test -n "${domain:-}"; then
ynh_replace_string "__DOMAIN__" "$domain" "$finalnginxconf" ynh_replace_string --match_string="__DOMAIN__" --replace_string="$domain" --target_file="$finalnginxconf"
fi fi
if test -n "${port:-}"; then if test -n "${port:-}"; then
ynh_replace_string "__PORT__" "$port" "$finalnginxconf" ynh_replace_string --match_string="__PORT__" --replace_string="$port" --target_file="$finalnginxconf"
fi fi
if test -n "${app:-}"; then if test -n "${app:-}"; then
ynh_replace_string "__NAME__" "$app" "$finalnginxconf" ynh_replace_string --match_string="__NAME__" --replace_string="$app" --target_file="$finalnginxconf"
fi fi
if test -n "${final_path:-}"; then if test -n "${final_path:-}"; then
ynh_replace_string "__FINALPATH__" "$final_path" "$finalnginxconf" ynh_replace_string --match_string="__FINALPATH__" --replace_string="$final_path" --target_file="$finalnginxconf"
fi fi
# Replace all other variable given as arguments # Replace all other variable given as arguments
@ -174,17 +215,17 @@ ynh_add_nginx_config () {
do do
# ${var_to_replace^^} make the content of the variable on upper-cases # ${var_to_replace^^} make the content of the variable on upper-cases
# ${!var_to_replace} get the content of the variable named $var_to_replace # ${!var_to_replace} get the content of the variable named $var_to_replace
ynh_replace_string "__${var_to_replace^^}__" "${!var_to_replace}" "$finalnginxconf" ynh_replace_string --match_string="__${var_to_replace^^}__" --replace_string="${!var_to_replace}" --target_file="$finalnginxconf"
done done
if [ "${path_url:-}" != "/" ] if [ "${path_url:-}" != "/" ]
then then
ynh_replace_string "^#sub_path_only" "" "$finalnginxconf" ynh_replace_string --match_string="^#sub_path_only" --replace_string="" --target_file="$finalnginxconf"
else else
ynh_replace_string "^#root_path_only" "" "$finalnginxconf" ynh_replace_string --match_string="^#root_path_only" --replace_string="" --target_file="$finalnginxconf"
fi fi
ynh_store_file_checksum "$finalnginxconf" ynh_store_file_checksum --file="$finalnginxconf"
sudo systemctl reload nginx sudo systemctl reload nginx
} }
@ -193,7 +234,7 @@ ynh_add_nginx_config () {
# #
# usage: ynh_remove_nginx_config # usage: ynh_remove_nginx_config
ynh_remove_nginx_config () { ynh_remove_nginx_config () {
ynh_secure_remove "/etc/nginx/conf.d/$domain.d/$app.conf" ynh_secure_remove --file="/etc/nginx/conf.d/$domain.d/$app.conf"
sudo systemctl reload nginx sudo systemctl reload nginx
} }
@ -209,20 +250,25 @@ ynh_add_fpm_config () {
fpm_config_dir="/etc/php5/fpm" fpm_config_dir="/etc/php5/fpm"
fpm_service="php5-fpm" fpm_service="php5-fpm"
fi fi
ynh_app_setting_set $app fpm_config_dir "$fpm_config_dir" ynh_app_setting_set --app=$app --key=fpm_config_dir --value="$fpm_config_dir"
ynh_app_setting_set $app fpm_service "$fpm_service" ynh_app_setting_set --app=$app --key=fpm_service --value="$fpm_service"
finalphpconf="$fpm_config_dir/pool.d/$app.conf" finalphpconf="$fpm_config_dir/pool.d/$app.conf"
ynh_backup_if_checksum_is_different "$finalphpconf" ynh_backup_if_checksum_is_different --file="$finalphpconf"
sudo cp ../conf/php-fpm.conf "$finalphpconf" sudo cp ../conf/php-fpm.conf "$finalphpconf"
ynh_replace_string "__NAMETOCHANGE__" "$app" "$finalphpconf" ynh_replace_string --match_string="__NAMETOCHANGE__" --replace_string="$app" --target_file="$finalphpconf"
ynh_replace_string "__FINALPATH__" "$final_path" "$finalphpconf" ynh_replace_string --match_string="__FINALPATH__" --replace_string="$final_path" --target_file="$finalphpconf"
ynh_replace_string "__USER__" "$app" "$finalphpconf" ynh_replace_string --match_string="__USER__" --replace_string="$app" --target_file="$finalphpconf"
sudo chown root: "$finalphpconf" sudo chown root: "$finalphpconf"
ynh_store_file_checksum "$finalphpconf" ynh_store_file_checksum --file="$finalphpconf"
if [ -e "../conf/php-fpm.ini" ] if [ -e "../conf/php-fpm.ini" ]
then then
echo "Please do not use a separate ini file, merge you directives in the pool file instead." &>2 echo "Packagers ! Please do not use a separate php ini file, merge your directives in the pool file instead." >&2
finalphpini="$fpm_config_dir/conf.d/20-$app.ini"
ynh_backup_if_checksum_is_different "$finalphpini"
sudo cp ../conf/php-fpm.ini "$finalphpini"
sudo chown root: "$finalphpini"
ynh_store_file_checksum "$finalphpini"
fi fi
sudo systemctl reload $fpm_service sudo systemctl reload $fpm_service
} }
@ -231,14 +277,14 @@ ynh_add_fpm_config () {
# #
# usage: ynh_remove_fpm_config # usage: ynh_remove_fpm_config
ynh_remove_fpm_config () { ynh_remove_fpm_config () {
local fpm_config_dir=$(ynh_app_setting_get $app fpm_config_dir) local fpm_config_dir=$(ynh_app_setting_get --app=$app --key=fpm_config_dir)
local fpm_service=$(ynh_app_setting_get $app fpm_service) local fpm_service=$(ynh_app_setting_get --app=$app --key=fpm_service)
# Assume php version 7 if not set # Assume php version 7 if not set
if [ -z "$fpm_config_dir" ]; then if [ -z "$fpm_config_dir" ]; then
fpm_config_dir="/etc/php/7.0/fpm" fpm_config_dir="/etc/php/7.0/fpm"
fpm_service="php7.0-fpm" fpm_service="php7.0-fpm"
fi fi
ynh_secure_remove "$fpm_config_dir/pool.d/$app.conf" ynh_secure_remove --file="$fpm_config_dir/pool.d/$app.conf"
ynh_secure_remove "$fpm_config_dir/conf.d/20-$app.ini" 2>&1 ynh_secure_remove --file="$fpm_config_dir/conf.d/20-$app.ini" 2>&1
sudo systemctl reload $fpm_service sudo systemctl reload $fpm_service
} }

View file

@ -1,3 +1,7 @@
#!/bin/bash
source /usr/share/yunohost/helpers.d/getopts
CAN_BIND=${CAN_BIND:-1} CAN_BIND=${CAN_BIND:-1}
# Add a file or a directory to the list of paths to backup # Add a file or a directory to the list of paths to backup
@ -10,13 +14,13 @@ CAN_BIND=${CAN_BIND:-1}
# #
# If DEST is ended by a slash it complete this path with the basename of SRC. # If DEST is ended by a slash it complete this path with the basename of SRC.
# #
# usage: ynh_backup src [dest [is_big [not_mandatory [arg]]]] # usage: ynh_backup --src_path=src_path [--dest_path=dest_path] [--is_big] [--not_mandatory]
# | arg: src - file or directory to bind or symlink or copy. it shouldn't be in # | arg: -s, --src_path - file or directory to bind or symlink or copy. it shouldn't be in
# the backup dir. # the backup dir.
# | arg: dest - destination file or directory inside the # | arg: -d, --dest_path - destination file or directory inside the
# backup dir # backup dir
# | arg: is_big - 1 to indicate data are big (mail, video, image ...) # | arg: -b, --is_big - Indicate data are big (mail, video, image ...)
# | arg: not_mandatory - 1 to indicate that if the file is missing, the backup can ignore it. # | arg: -m, --not_mandatory - Indicate that if the file is missing, the backup can ignore it.
# | arg: arg - Deprecated arg # | arg: arg - Deprecated arg
# #
# example: # example:
@ -44,16 +48,26 @@ CAN_BIND=${CAN_BIND:-1}
# #
ynh_backup() { ynh_backup() {
# TODO find a way to avoid injection by file strange naming ! # TODO find a way to avoid injection by file strange naming !
local SRC_PATH="$1"
local DEST_PATH="${2:-}" # Declare an array to define the options of this helper.
local IS_BIG="${3:-0}" local legacy_args=sdbm
local NOT_MANDATORY="${4:-0}" declare -Ar args_array=( [s]=src_path= [d]=dest_path= [b]=is_big [m]=not_mandatory )
local src_path
local dest_path
local is_big
local not_mandatory
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
local dest_path="${dest_path:-}"
local is_big="${is_big:-0}"
local not_mandatory="${not_mandatory:-0}"
BACKUP_CORE_ONLY=${BACKUP_CORE_ONLY:-0} BACKUP_CORE_ONLY=${BACKUP_CORE_ONLY:-0}
# If backing up core only (used by ynh_backup_before_upgrade), # If backing up core only (used by ynh_backup_before_upgrade),
# don't backup big data items # don't backup big data items
if [ "$IS_BIG" == "1" ] && [ "$BACKUP_CORE_ONLY" == "1" ] ; then if [ "$is_big" == "1" ] && [ "$BACKUP_CORE_ONLY" == "1" ] ; then
echo "$SRC_PATH will not be saved, because backup_core_only is set." >&2 echo "$src_path will not be saved, because backup_core_only is set." >&2
return 0 return 0
fi fi
@ -61,13 +75,16 @@ ynh_backup() {
# Format correctly source and destination paths # Format correctly source and destination paths
# ============================================================================== # ==============================================================================
# Be sure the source path is not empty # Be sure the source path is not empty
[[ -e "${SRC_PATH}" ]] || { [[ -e "${src_path}" ]] || {
if [ "$NOT_MANDATORY" == "0" ] echo "Source path '${src_path}' does not exist" >&2
if [ "$not_mandatory" == "0" ]
then then
echo "Source path '${SRC_PATH}' does not exist" >&2
# This is a temporary fix for fail2ban config files missing after the migration to stretch. # This is a temporary fix for fail2ban config files missing after the migration to stretch.
if echo "${SRC_PATH}" | grep --quiet "/etc/fail2ban" if echo "${src_path}" | grep --quiet "/etc/fail2ban"
then then
touch "${SRC_PATH}" touch "${src_path}"
echo "The missing file will be replaced by a dummy one for the backup !!!" >&2 echo "The missing file will be replaced by a dummy one for the backup !!!" >&2
else else
return 1 return 1
@ -79,17 +96,17 @@ ynh_backup() {
# Transform the source path as an absolute path # Transform the source path as an absolute path
# If it's a dir remove the ending / # If it's a dir remove the ending /
SRC_PATH=$(realpath "$SRC_PATH") src_path=$(realpath "$src_path")
# If there is no destination path, initialize it with the source path # If there is no destination path, initialize it with the source path
# relative to "/". # relative to "/".
# eg: SRC_PATH=/etc/yunohost -> DEST_PATH=etc/yunohost # eg: src_path=/etc/yunohost -> dest_path=etc/yunohost
if [[ -z "$DEST_PATH" ]]; then if [[ -z "$dest_path" ]]; then
DEST_PATH="${SRC_PATH#/}" dest_path="${src_path#/}"
else else
if [[ "${DEST_PATH:0:1}" == "/" ]]; then if [[ "${dest_path:0:1}" == "/" ]]; then
# If the destination path is an absolute path, transform it as a path # If the destination path is an absolute path, transform it as a path
# relative to the current working directory ($YNH_CWD) # relative to the current working directory ($YNH_CWD)
@ -98,43 +115,43 @@ ynh_backup() {
# $YNH_BACKUP_DIR/apps/APP_INSTANCE_NAME/backup/ # $YNH_BACKUP_DIR/apps/APP_INSTANCE_NAME/backup/
# #
# If it's a system part backup script, YNH_CWD is equal to $YNH_BACKUP_DIR # If it's a system part backup script, YNH_CWD is equal to $YNH_BACKUP_DIR
DEST_PATH="${DEST_PATH#$YNH_CWD/}" dest_path="${dest_path#$YNH_CWD/}"
# Case where $2 is an absolute dir but doesn't begin with $YNH_CWD # Case where $2 is an absolute dir but doesn't begin with $YNH_CWD
[[ "${DEST_PATH:0:1}" == "/" ]] \ [[ "${dest_path:0:1}" == "/" ]] \
&& DEST_PATH="${DEST_PATH#/}" && dest_path="${dest_path#/}"
fi fi
# Complete DEST_PATH if ended by a / # Complete dest_path if ended by a /
[[ "${DEST_PATH: -1}" == "/" ]] \ [[ "${dest_path: -1}" == "/" ]] \
&& DEST_PATH="${DEST_PATH}/$(basename $SRC_PATH)" && dest_path="${dest_path}/$(basename $src_path)"
fi fi
# Check if DEST_PATH already exists in tmp archive # Check if dest_path already exists in tmp archive
[[ ! -e "${DEST_PATH}" ]] || { [[ ! -e "${dest_path}" ]] || {
echo "Destination path '${DEST_PATH}' already exist" >&2 echo "Destination path '${dest_path}' already exist" >&2
return 1 return 1
} }
# Add the relative current working directory to the destination path # Add the relative current working directory to the destination path
local REL_DIR="${YNH_CWD#$YNH_BACKUP_DIR}" local rel_dir="${YNH_CWD#$YNH_BACKUP_DIR}"
REL_DIR="${REL_DIR%/}/" rel_dir="${rel_dir%/}/"
DEST_PATH="${REL_DIR}${DEST_PATH}" dest_path="${rel_dir}${dest_path}"
DEST_PATH="${DEST_PATH#/}" dest_path="${dest_path#/}"
# ============================================================================== # ==============================================================================
# ============================================================================== # ==============================================================================
# Write file to backup into backup_list # Write file to backup into backup_list
# ============================================================================== # ==============================================================================
local SRC=$(echo "${SRC_PATH}" | sed -r 's/"/\"\"/g') local src=$(echo "${src_path}" | sed -r 's/"/\"\"/g')
local DEST=$(echo "${DEST_PATH}" | sed -r 's/"/\"\"/g') local dest=$(echo "${dest_path}" | sed -r 's/"/\"\"/g')
echo "\"${SRC}\",\"${DEST}\"" >> "${YNH_BACKUP_CSV}" echo "\"${src}\",\"${dest}\"" >> "${YNH_BACKUP_CSV}"
# ============================================================================== # ==============================================================================
# Create the parent dir of the destination path # Create the parent dir of the destination path
# It's for retro compatibility, some script consider ynh_backup creates this dir # It's for retro compatibility, some script consider ynh_backup creates this dir
mkdir -p $(dirname "$YNH_BACKUP_DIR/${DEST_PATH}") mkdir -p $(dirname "$YNH_BACKUP_DIR/${dest_path}")
} }
# Restore all files linked to the restore hook or to the restore app script # Restore all files linked to the restore hook or to the restore app script
@ -151,7 +168,7 @@ ynh_restore () {
while read line; do while read line; do
local ORIGIN_PATH=$(echo "$line" | grep -ohP "^\"\K.*(?=\",\".*\"$)") local ORIGIN_PATH=$(echo "$line" | grep -ohP "^\"\K.*(?=\",\".*\"$)")
local ARCHIVE_PATH=$(echo "$line" | grep -ohP "^\".*\",\"$REL_DIR\K.*(?=\"$)") local ARCHIVE_PATH=$(echo "$line" | grep -ohP "^\".*\",\"$REL_DIR\K.*(?=\"$)")
ynh_restore_file "$ARCHIVE_PATH" "$ORIGIN_PATH" ynh_restore_file --origin_path="$ARCHIVE_PATH" --dest_path="$ORIGIN_PATH"
done done
} }
@ -181,13 +198,13 @@ with open(sys.argv[1], 'r') as backup_file:
# Use the registered path in backup_list by ynh_backup to restore the file at # Use the registered path in backup_list by ynh_backup to restore the file at
# the good place. # the good place.
# #
# usage: ynh_restore_file ORIGIN_PATH [ DEST_PATH [NOT_MANDATORY]] # usage: ynh_restore_file --origin_path=origin_path [--dest_path=dest_path] [--not_mandatory]
# | arg: ORIGIN_PATH - Path where was located the file or the directory before # | arg: -o, --origin_path - Path where was located the file or the directory before
# to be backuped or relative path to $YNH_CWD where it is located in the backup archive # to be backuped or relative path to $YNH_CWD where it is located in the backup archive
# | arg: DEST_PATH - Path where restore the file or the dir, if unspecified, # | arg: -d, --dest_path - Path where restore the file or the dir, if unspecified,
# the destination will be ORIGIN_PATH or if the ORIGIN_PATH doesn't exist in # the destination will be ORIGIN_PATH or if the ORIGIN_PATH doesn't exist in
# the archive, the destination will be searched into backup.csv # the archive, the destination will be searched into backup.csv
# | arg: NOT_MANDATORY - 1 to indicate that if the file is missing, the restore process can ignore it. # | arg: -m, --not_mandatory - Indicate that if the file is missing, the restore process can ignore it.
# #
# If DEST_PATH already exists and is lighter than 500 Mo, a backup will be made in # If DEST_PATH already exists and is lighter than 500 Mo, a backup will be made in
# /home/yunohost.conf/backup/. Otherwise, the existing file is removed. # /home/yunohost.conf/backup/. Otherwise, the existing file is removed.
@ -203,49 +220,58 @@ with open(sys.argv[1], 'r') as backup_file:
# ynh_restore_file "conf/nginx.conf" # ynh_restore_file "conf/nginx.conf"
# #
ynh_restore_file () { ynh_restore_file () {
local ORIGIN_PATH="/${1#/}" # Declare an array to define the options of this helper.
local ARCHIVE_PATH="$YNH_CWD${ORIGIN_PATH}" local legacy_args=odm
# Default value for DEST_PATH = /$ORIGIN_PATH declare -Ar args_array=( [o]=origin_path= [d]=dest_path= [m]=not_mandatory )
local DEST_PATH="${2:-$ORIGIN_PATH}" local origin_path
local NOT_MANDATORY="${3:-0}" local archive_path
local dest_path
local not_mandatory
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
local origin_path="/${origin_path#/}"
local archive_path="$YNH_CWD${origin_path}"
# Default value for dest_path = /$origin_path
local dest_path="${dest_path:-$origin_path}"
local not_mandatory="${not_mandatory:-0}"
# If ARCHIVE_PATH doesn't exist, search for a corresponding path in CSV # If archive_path doesn't exist, search for a corresponding path in CSV
if [ ! -d "$ARCHIVE_PATH" ] && [ ! -f "$ARCHIVE_PATH" ] && [ ! -L "$ARCHIVE_PATH" ]; then if [ ! -d "$archive_path" ] && [ ! -f "$archive_path" ] && [ ! -L "$archive_path" ]; then
if [ "$NOT_MANDATORY" == "0" ] if [ "$not_mandatory" == "0" ]
then then
ARCHIVE_PATH="$YNH_BACKUP_DIR/$(_get_archive_path \"$ORIGIN_PATH\")" archive_path="$YNH_BACKUP_DIR/$(_get_archive_path \"$origin_path\")"
else else
return 0 return 0
fi fi
fi fi
# Move the old directory if it already exists # Move the old directory if it already exists
if [[ -e "${DEST_PATH}" ]] if [[ -e "${dest_path}" ]]
then then
# Check if the file/dir size is less than 500 Mo # Check if the file/dir size is less than 500 Mo
if [[ $(du -sb ${DEST_PATH} | cut -d"/" -f1) -le "500000000" ]] if [[ $(du -sb ${dest_path} | cut -d"/" -f1) -le "500000000" ]]
then then
local backup_file="/home/yunohost.conf/backup/${DEST_PATH}.backup.$(date '+%Y%m%d.%H%M%S')" local backup_file="/home/yunohost.conf/backup/${dest_path}.backup.$(date '+%Y%m%d.%H%M%S')"
mkdir -p "$(dirname "$backup_file")" mkdir -p "$(dirname "$backup_file")"
mv "${DEST_PATH}" "$backup_file" # Move the current file or directory mv "${dest_path}" "$backup_file" # Move the current file or directory
else else
ynh_secure_remove ${DEST_PATH} ynh_secure_remove --file=${dest_path}
fi fi
fi fi
# Restore ORIGIN_PATH into DEST_PATH # Restore origin_path into dest_path
mkdir -p $(dirname "$DEST_PATH") mkdir -p $(dirname "$dest_path")
# Do a copy if it's just a mounting point # Do a copy if it's just a mounting point
if mountpoint -q $YNH_BACKUP_DIR; then if mountpoint -q $YNH_BACKUP_DIR; then
if [[ -d "${ARCHIVE_PATH}" ]]; then if [[ -d "${archive_path}" ]]; then
ARCHIVE_PATH="${ARCHIVE_PATH}/." archive_path="${archive_path}/."
mkdir -p "$DEST_PATH" mkdir -p "$dest_path"
fi fi
cp -a "$ARCHIVE_PATH" "${DEST_PATH}" cp -a "$archive_path" "${dest_path}"
# Do a move if YNH_BACKUP_DIR is already a copy # Do a move if YNH_BACKUP_DIR is already a copy
else else
mv "$ARCHIVE_PATH" "${DEST_PATH}" mv "$archive_path" "${dest_path}"
fi fi
} }
@ -285,11 +311,18 @@ properly with chmod/chown." >&2
# #
# $app should be defined when calling this helper # $app should be defined when calling this helper
# #
# usage: ynh_store_file_checksum file # usage: ynh_store_file_checksum --file=file
# | arg: file - The file on which the checksum will performed, then stored. # | arg: -f, --file - The file on which the checksum will performed, then stored.
ynh_store_file_checksum () { ynh_store_file_checksum () {
local checksum_setting_name=checksum_${1//[\/ ]/_} # Replace all '/' and ' ' by '_' # Declare an array to define the options of this helper.
ynh_app_setting_set $app $checksum_setting_name $(sudo md5sum "$1" | cut -d' ' -f1) local legacy_args=f
declare -Ar args_array=( [f]=file= )
local file
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
local checksum_setting_name=checksum_${file//[\/ ]/_} # Replace all '/' and ' ' by '_'
ynh_app_setting_set --app=$app --key=$checksum_setting_name --value=$(sudo md5sum "$file" | cut -d' ' -f1)
} }
# Verify the checksum and backup the file if it's different # Verify the checksum and backup the file if it's different
@ -298,14 +331,20 @@ ynh_store_file_checksum () {
# #
# $app should be defined when calling this helper # $app should be defined when calling this helper
# #
# usage: ynh_backup_if_checksum_is_different file # usage: ynh_backup_if_checksum_is_different --file=file
# | arg: file - The file on which the checksum test will be perfomed. # | arg: -f, --file - The file on which the checksum test will be perfomed.
# #
# | ret: Return the name a the backup file, or nothing # | ret: Return the name a the backup file, or nothing
ynh_backup_if_checksum_is_different () { ynh_backup_if_checksum_is_different () {
local file=$1 # Declare an array to define the options of this helper.
local legacy_args=f
declare -Ar args_array=( [f]=file= )
local file
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
local checksum_setting_name=checksum_${file//[\/ ]/_} # Replace all '/' and ' ' by '_' local checksum_setting_name=checksum_${file//[\/ ]/_} # Replace all '/' and ' ' by '_'
local checksum_value=$(ynh_app_setting_get $app $checksum_setting_name) local checksum_value=$(ynh_app_setting_get --app=$app --key=$checksum_setting_name)
if [ -n "$checksum_value" ] if [ -n "$checksum_value" ]
then # Proceed only if a value was stored into the app settings then # Proceed only if a value was stored into the app settings
if ! echo "$checksum_value $file" | sudo md5sum -c --status if ! echo "$checksum_value $file" | sudo md5sum -c --status
@ -327,39 +366,51 @@ ynh_backup_if_checksum_is_different () {
# | arg: -f, --file= - The file for which the checksum will be deleted # | arg: -f, --file= - The file for which the checksum will be deleted
ynh_delete_file_checksum () { ynh_delete_file_checksum () {
# Declare an array to define the options of this helper. # Declare an array to define the options of this helper.
local legacy_args=f
declare -Ar args_array=( [f]=file= ) declare -Ar args_array=( [f]=file= )
local file local file
# Manage arguments with getopts # Manage arguments with getopts
ynh_handle_getopts_args "$@" ynh_handle_getopts_args "$@"
local checksum_setting_name=checksum_${file//[\/ ]/_} # Replace all '/' and ' ' by '_' local checksum_setting_name=checksum_${file//[\/ ]/_} # Replace all '/' and ' ' by '_'
ynh_app_setting_delete $app $checksum_setting_name ynh_app_setting_delete --app=$app --key=$checksum_setting_name
} }
# Remove a file or a directory securely # Remove a file or a directory securely
# #
# usage: ynh_secure_remove path_to_remove # usage: ynh_secure_remove --file=path_to_remove
# | arg: path_to_remove - File or directory to remove # | arg: -f, --file - File or directory to remove
ynh_secure_remove () { ynh_secure_remove () {
local path_to_remove=$1 # Declare an array to define the options of this helper.
local legacy_args=f
declare -Ar args_array=( [f]=file= )
local file
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
local forbidden_path=" \ local forbidden_path=" \
/var/www \ /var/www \
/home/yunohost.app" /home/yunohost.app"
if [[ "$forbidden_path" =~ "$path_to_remove" \ if [ $# -ge 2 ]
then
echo "/!\ Packager ! You provided more than one argument to ynh_secure_remove but it will be ignored... Use this helper with one argument at time." >&2
fi
if [[ "$forbidden_path" =~ "$file" \
# Match all paths or subpaths in $forbidden_path # Match all paths or subpaths in $forbidden_path
|| "$path_to_remove" =~ ^/[[:alnum:]]+$ \ || "$file" =~ ^/[[:alnum:]]+$ \
# Match all first level paths from / (Like /var, /root, etc...) # Match all first level paths from / (Like /var, /root, etc...)
|| "${path_to_remove:${#path_to_remove}-1}" = "/" ]] || "${file:${#file}-1}" = "/" ]]
# Match if the path finishes by /. Because it seems there is an empty variable # Match if the path finishes by /. Because it seems there is an empty variable
then then
echo "Avoid deleting $path_to_remove." >&2 echo "Avoid deleting $file." >&2
else else
if [ -e "$path_to_remove" ] if [ -e "$file" ]
then then
sudo rm -R "$path_to_remove" sudo rm -R "$file"
else else
echo "$path_to_remove wasn't deleted because it doesn't exist." >&2 echo "$file wasn't deleted because it doesn't exist." >&2
fi fi
fi fi
} }

View file

@ -53,33 +53,33 @@ ynh_handle_getopts_args () {
# For each option in the array, reduce to short options for getopts (e.g. for [u]=user, --user will be -u) # For each option in the array, reduce to short options for getopts (e.g. for [u]=user, --user will be -u)
# And built parameters string for getopts # And built parameters string for getopts
# ${!args_array[@]} is the list of all keys in the array (A key is 'u' in [u]=user, user is a value) # ${!args_array[@]} is the list of all option_flags in the array (An option_flag is 'u' in [u]=user, user is a value)
local getopts_parameters="" local getopts_parameters=""
local key="" local option_flag=""
for key in "${!args_array[@]}" for option_flag in "${!args_array[@]}"
do do
# Concatenate each keys of the array to build the string of arguments for getopts # Concatenate each option_flags of the array to build the string of arguments for getopts
# Will looks like 'abcd' for -a -b -c -d # Will looks like 'abcd' for -a -b -c -d
# If the value of a key finish by =, it's an option with additionnal values. (e.g. --user bob or -u bob) # If the value of an option_flag finish by =, it's an option with additionnal values. (e.g. --user bob or -u bob)
# Check the last character of the value associate to the key # Check the last character of the value associate to the option_flag
if [ "${args_array[$key]: -1}" = "=" ] if [ "${args_array[$option_flag]: -1}" = "=" ]
then then
# For an option with additionnal values, add a ':' after the letter for getopts. # For an option with additionnal values, add a ':' after the letter for getopts.
getopts_parameters="${getopts_parameters}${key}:" getopts_parameters="${getopts_parameters}${option_flag}:"
else else
getopts_parameters="${getopts_parameters}${key}" getopts_parameters="${getopts_parameters}${option_flag}"
fi fi
# Check each argument given to the function # Check each argument given to the function
local arg="" local arg=""
# ${#arguments[@]} is the size of the array # ${#arguments[@]} is the size of the array
for arg in `seq 0 $(( ${#arguments[@]} - 1 ))` for arg in `seq 0 $(( ${#arguments[@]} - 1 ))`
do do
# And replace long option (value of the key) by the short option, the key itself # And replace long option (value of the option_flag) by the short option, the option_flag itself
# (e.g. for [u]=user, --user will be -u) # (e.g. for [u]=user, --user will be -u)
# Replace long option with = # Replace long option with =
arguments[arg]="${arguments[arg]//--${args_array[$key]}/-${key} }" arguments[arg]="${arguments[arg]//--${args_array[$option_flag]}/-${option_flag} }"
# And long option without = # And long option without =
arguments[arg]="${arguments[arg]//--${args_array[$key]%=}/-${key}}" arguments[arg]="${arguments[arg]//--${args_array[$option_flag]%=}/-${option_flag}}"
done done
done done
@ -98,10 +98,10 @@ ynh_handle_getopts_args () {
if [ "$parameter" = "?" ] if [ "$parameter" = "?" ]
then then
ynh_die "Invalid argument: -${OPTARG:-}" ynh_die --message="Invalid argument: -${OPTARG:-}"
elif [ "$parameter" = ":" ] elif [ "$parameter" = ":" ]
then then
ynh_die "-$OPTARG parameter requires an argument." ynh_die --message="-$OPTARG parameter requires an argument."
else else
local shift_value=1 local shift_value=1
# Use the long option, corresponding to the short option read by getopts, as a variable # Use the long option, corresponding to the short option read by getopts, as a variable
@ -132,10 +132,11 @@ ynh_handle_getopts_args () {
# Declare the content of option_var as a variable. # Declare the content of option_var as a variable.
eval ${option_var}="" eval ${option_var}=""
# Then read the array value per value # Then read the array value per value
local i
for i in `seq 0 $(( ${#all_args[@]} - 1 ))` for i in `seq 0 $(( ${#all_args[@]} - 1 ))`
do do
# If this argument is an option, end here. # If this argument is an option, end here.
if [ "${all_args[$i]:0:1}" == "-" ] || [ -z "${all_args[$i]}" ] if [ "${all_args[$i]:0:1}" == "-" ]
then then
# Ignore the first value of the array, which is the option itself # Ignore the first value of the array, which is the option itself
if [ "$i" -ne 0 ]; then if [ "$i" -ne 0 ]; then
@ -149,6 +150,9 @@ ynh_handle_getopts_args () {
# If there's already another value for this option, add a ; before adding the new value # If there's already another value for this option, add a ; before adding the new value
eval ${option_var}+="\;" eval ${option_var}+="\;"
fi fi
# Escape double quote to prevent any interpretation during the eval
all_args[$i]="${all_args[$i]//\"/\\\"}"
eval ${option_var}+=\"${all_args[$i]}\" eval ${option_var}+=\"${all_args[$i]}\"
shift_value=$(( shift_value + 1 )) shift_value=$(( shift_value + 1 ))
fi fi
@ -165,25 +169,36 @@ ynh_handle_getopts_args () {
# Check if there's getopts arguments # Check if there's getopts arguments
if [ "${arguments[0]:0:1}" != "-" ] if [ "${arguments[0]:0:1}" != "-" ]
then then
# If not, enter in legacy mode and manage the arguments as positionnal ones. # If not, enter in legacy mode and manage the arguments as positionnal ones..
echo "! Helper used in legacy mode !" # Dot not echo, to prevent to go through a helper output. But print only in the log.
set -x; echo "! Helper used in legacy mode !" > /dev/null; set +x
local i
for i in `seq 0 $(( ${#arguments[@]} -1 ))` for i in `seq 0 $(( ${#arguments[@]} -1 ))`
do do
# Use getopts_parameters as a list of key of the array args_array # Try to use legacy_args as a list of option_flag of the array args_array
# Otherwise, fallback to getopts_parameters to get the option_flag. But an associative arrays isn't always sorted in the correct order...
# Remove all ':' in getopts_parameters # Remove all ':' in getopts_parameters
getopts_parameters=${getopts_parameters//:} getopts_parameters=${legacy_args:-${getopts_parameters//:}}
# Get the key from getopts_parameters, by using the key according to the position of the argument. # Get the option_flag from getopts_parameters, by using the option_flag according to the position of the argument.
key=${getopts_parameters:$i:1} option_flag=${getopts_parameters:$i:1}
# Use the long option, corresponding to the key, as a variable if [ -z "$option_flag" ]; then
ynh_print_warn --message="Too many arguments ! \"${arguments[$i]}\" will be ignored."
continue
fi
# Use the long option, corresponding to the option_flag, as a variable
# (e.g. for [u]=user, 'user' will be used as a variable) # (e.g. for [u]=user, 'user' will be used as a variable)
# Also, remove '=' at the end of the long option # Also, remove '=' at the end of the long option
# The variable name will be stored in 'option_var' # The variable name will be stored in 'option_var'
local option_var="${args_array[$key]%=}" local option_var="${args_array[$option_flag]%=}"
# Escape double quote to prevent any interpretation during the eval
arguments[$i]="${arguments[$i]//\"/\\\"}"
# Store each value given as argument in the corresponding variable # Store each value given as argument in the corresponding variable
# The values will be stored in the same order than $args_array # The values will be stored in the same order than $args_array
eval ${option_var}+=\"${arguments[$i]}\" eval ${option_var}+=\"${arguments[$i]}\"
done done
unset legacy_args
else else
# END LEGACY MODE # END LEGACY MODE
# Call parse_arg and pass the modified list of args as an array of arguments. # Call parse_arg and pass the modified list of args as an array of arguments.

View file

@ -1,6 +1,8 @@
#!/bin/bash
# Validate an IP address # Validate an IP address
# #
# usage: ynh_validate_ip [family] [ip_address] # usage: ynh_validate_ip --family=family --ip_address=ip_address
# | ret: 0 for valid ip addresses, 1 otherwise # | ret: 0 for valid ip addresses, 1 otherwise
# #
# example: ynh_validate_ip 4 111.222.333.444 # example: ynh_validate_ip 4 111.222.333.444
@ -9,17 +11,22 @@ ynh_validate_ip()
{ {
# http://stackoverflow.com/questions/319279/how-to-validate-ip-address-in-python#319298 # http://stackoverflow.com/questions/319279/how-to-validate-ip-address-in-python#319298
local IP_ADDRESS_FAMILY=$1 # Declare an array to define the options of this helper.
local IP_ADDRESS=$2 local legacy_args=fi
declare -Ar args_array=( [f]=family= [i]=ip_address= )
local family
local ip_address
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
[ "$IP_ADDRESS_FAMILY" == "4" ] || [ "$IP_ADDRESS_FAMILY" == "6" ] || return 1 [ "$family" == "4" ] || [ "$family" == "6" ] || return 1
python /dev/stdin << EOF python /dev/stdin << EOF
import socket import socket
import sys import sys
family = { "4" : socket.AF_INET, "6" : socket.AF_INET6 } family = { "4" : socket.AF_INET, "6" : socket.AF_INET6 }
try: try:
socket.inet_pton(family["$IP_ADDRESS_FAMILY"], "$IP_ADDRESS") socket.inet_pton(family["$family"], "$ip_address")
except socket.error: except socket.error:
sys.exit(1) sys.exit(1)
sys.exit(0) sys.exit(0)
@ -30,12 +37,19 @@ EOF
# #
# example: ynh_validate_ip4 111.222.333.444 # example: ynh_validate_ip4 111.222.333.444
# #
# usage: ynh_validate_ip4 <ip_address> # usage: ynh_validate_ip4 --ip_address=ip_address
# | ret: 0 for valid ipv4 addresses, 1 otherwise # | ret: 0 for valid ipv4 addresses, 1 otherwise
# #
ynh_validate_ip4() ynh_validate_ip4()
{ {
ynh_validate_ip 4 $1 # Declare an array to define the options of this helper.
local legacy_args=i
declare -Ar args_array=( [i]=ip_address= )
local ip_address
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
ynh_validate_ip 4 $ip_address
} }
@ -43,10 +57,17 @@ ynh_validate_ip4()
# #
# example: ynh_validate_ip6 2000:dead:beef::1 # example: ynh_validate_ip6 2000:dead:beef::1
# #
# usage: ynh_validate_ip6 <ip_address> # usage: ynh_validate_ip6 --ip_address=ip_address
# | ret: 0 for valid ipv6 addresses, 1 otherwise # | ret: 0 for valid ipv6 addresses, 1 otherwise
# #
ynh_validate_ip6() ynh_validate_ip6()
{ {
ynh_validate_ip 6 $1 # Declare an array to define the options of this helper.
local legacy_args=i
declare -Ar args_array=( [i]=ip_address= )
local ip_address
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
ynh_validate_ip 6 $ip_address
} }

View file

@ -1,3 +1,5 @@
#!/bin/bash
MYSQL_ROOT_PWD_FILE=/etc/yunohost/mysql MYSQL_ROOT_PWD_FILE=/etc/yunohost/mysql
# Open a connection as a user # Open a connection as a user
@ -5,32 +7,60 @@ MYSQL_ROOT_PWD_FILE=/etc/yunohost/mysql
# example: ynh_mysql_connect_as 'user' 'pass' <<< "UPDATE ...;" # example: ynh_mysql_connect_as 'user' 'pass' <<< "UPDATE ...;"
# example: ynh_mysql_connect_as 'user' 'pass' < /path/to/file.sql # example: ynh_mysql_connect_as 'user' 'pass' < /path/to/file.sql
# #
# usage: ynh_mysql_connect_as user pwd [db] # usage: ynh_mysql_connect_as --user=user --password=password [--database=database]
# | arg: user - the user name to connect as # | arg: -u, --user - the user name to connect as
# | arg: pwd - the user password # | arg: -p, --password - the user password
# | arg: db - the database to connect to # | arg: -d, --database - the database to connect to
ynh_mysql_connect_as() { ynh_mysql_connect_as() {
mysql -u "$1" --password="$2" -B "${3:-}" # Declare an array to define the options of this helper.
local legacy_args=upd
declare -Ar args_array=( [u]=user= [p]=password= [d]=database= )
local user
local password
local database
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
database="${database:-}"
mysql -u "$user" --password="$password" -B "$database"
} }
# Execute a command as root user # Execute a command as root user
# #
# usage: ynh_mysql_execute_as_root sql [db] # usage: ynh_mysql_execute_as_root --sql=sql [--database=database]
# | arg: sql - the SQL command to execute # | arg: -s, --sql - the SQL command to execute
# | arg: db - the database to connect to # | arg: -d, --database - the database to connect to
ynh_mysql_execute_as_root() { ynh_mysql_execute_as_root() {
ynh_mysql_connect_as "root" "$(sudo cat $MYSQL_ROOT_PWD_FILE)" \ # Declare an array to define the options of this helper.
"${2:-}" <<< "$1" local legacy_args=sd
declare -Ar args_array=( [s]=sql= [d]=database= )
local sql
local database
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
database="${database:-}"
ynh_mysql_connect_as --user="root" --password="$(sudo cat $MYSQL_ROOT_PWD_FILE)" \
--database="$database" <<< "$sql"
} }
# Execute a command from a file as root user # Execute a command from a file as root user
# #
# usage: ynh_mysql_execute_file_as_root file [db] # usage: ynh_mysql_execute_file_as_root --file=file [--database=database]
# | arg: file - the file containing SQL commands # | arg: -f, --file - the file containing SQL commands
# | arg: db - the database to connect to # | arg: -d, --database - the database to connect to
ynh_mysql_execute_file_as_root() { ynh_mysql_execute_file_as_root() {
ynh_mysql_connect_as "root" "$(sudo cat $MYSQL_ROOT_PWD_FILE)" \ # Declare an array to define the options of this helper.
"${2:-}" < "$1" local legacy_args=fd
declare -Ar args_array=( [f]=file= [d]=database= )
local file
local database
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
database="${database:-}"
ynh_mysql_connect_as --user="root" --password="$(sudo cat $MYSQL_ROOT_PWD_FILE)" \
--database="$database" < "$file"
} }
# Create a database and grant optionnaly privilegies to a user # Create a database and grant optionnaly privilegies to a user
@ -53,7 +83,7 @@ ynh_mysql_create_db() {
sql+=" WITH GRANT OPTION;" sql+=" WITH GRANT OPTION;"
fi fi
ynh_mysql_execute_as_root "$sql" ynh_mysql_execute_as_root --sql="$sql"
} }
# Drop a database # Drop a database
@ -66,18 +96,25 @@ ynh_mysql_create_db() {
# usage: ynh_mysql_drop_db db # usage: ynh_mysql_drop_db db
# | arg: db - the database name to drop # | arg: db - the database name to drop
ynh_mysql_drop_db() { ynh_mysql_drop_db() {
ynh_mysql_execute_as_root "DROP DATABASE ${1};" ynh_mysql_execute_as_root --sql="DROP DATABASE ${1};"
} }
# Dump a database # Dump a database
# #
# example: ynh_mysql_dump_db 'roundcube' > ./dump.sql # example: ynh_mysql_dump_db 'roundcube' > ./dump.sql
# #
# usage: ynh_mysql_dump_db db # usage: ynh_mysql_dump_db --database=database
# | arg: db - the database name to dump # | arg: -d, --database - the database name to dump
# | ret: the mysqldump output # | ret: the mysqldump output
ynh_mysql_dump_db() { ynh_mysql_dump_db() {
mysqldump -u "root" -p"$(sudo cat $MYSQL_ROOT_PWD_FILE)" --single-transaction --skip-dump-date "$1" # Declare an array to define the options of this helper.
local legacy_args=d
declare -Ar args_array=( [d]=database= )
local database
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
mysqldump -u "root" -p"$(sudo cat $MYSQL_ROOT_PWD_FILE)" --single-transaction --skip-dump-date "$database"
} }
# Create a user # Create a user
@ -89,17 +126,23 @@ ynh_mysql_dump_db() {
# | arg: pwd - the password to identify user by # | arg: pwd - the password to identify user by
ynh_mysql_create_user() { ynh_mysql_create_user() {
ynh_mysql_execute_as_root \ ynh_mysql_execute_as_root \
"CREATE USER '${1}'@'localhost' IDENTIFIED BY '${2}';" --sql="CREATE USER '${1}'@'localhost' IDENTIFIED BY '${2}';"
} }
# Check if a mysql user exists # Check if a mysql user exists
# #
# usage: ynh_mysql_user_exists user # usage: ynh_mysql_user_exists --user=user
# | arg: user - the user for which to check existence # | arg: -u, --user - the user for which to check existence
ynh_mysql_user_exists() ynh_mysql_user_exists()
{ {
local user=$1 # Declare an array to define the options of this helper.
if [[ -z $(ynh_mysql_execute_as_root "SELECT User from mysql.user WHERE User = '$user';") ]] local legacy_args=u
declare -Ar args_array=( [u]=user= )
local user
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
if [[ -z $(ynh_mysql_execute_as_root --sql="SELECT User from mysql.user WHERE User = '$user';") ]]
then then
return 1 return 1
else else
@ -114,7 +157,7 @@ ynh_mysql_user_exists()
# usage: ynh_mysql_drop_user user # usage: ynh_mysql_drop_user user
# | arg: user - the user name to drop # | arg: user - the user name to drop
ynh_mysql_drop_user() { ynh_mysql_drop_user() {
ynh_mysql_execute_as_root "DROP USER '${1}'@'localhost';" ynh_mysql_execute_as_root --sql="DROP USER '${1}'@'localhost';"
} }
# Create a database, an user and its password. Then store the password in the app's config # Create a database, an user and its password. Then store the password in the app's config
@ -122,28 +165,42 @@ ynh_mysql_drop_user() {
# After executing this helper, the password of the created database will be available in $db_pwd # After executing this helper, the password of the created database will be available in $db_pwd
# It will also be stored as "mysqlpwd" into the app settings. # It will also be stored as "mysqlpwd" into the app settings.
# #
# usage: ynh_mysql_setup_db user name [pwd] # usage: ynh_mysql_setup_db --db_user=user --db_name=name [--db_pwd=pwd]
# | arg: user - Owner of the database # | arg: -u, --db_user - Owner of the database
# | arg: name - Name of the database # | arg: -n, --db_name - Name of the database
# | arg: pwd - Password of the database. If not given, a password will be generated # | arg: -p, --db_pwd - Password of the database. If not given, a password will be generated
ynh_mysql_setup_db () { ynh_mysql_setup_db () {
local db_user="$1" # Declare an array to define the options of this helper.
local db_name="$2" local legacy_args=unp
declare -Ar args_array=( [u]=db_user= [n]=db_name= [p]=db_pwd= )
local db_user
local db_name
db_pwd=""
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
local new_db_pwd=$(ynh_string_random) # Generate a random password local new_db_pwd=$(ynh_string_random) # Generate a random password
# If $3 is not given, use new_db_pwd instead for db_pwd. # If $db_pwd is not given, use new_db_pwd instead for db_pwd
db_pwd="${3:-$new_db_pwd}" db_pwd="${db_pwd:-$new_db_pwd}"
ynh_mysql_create_db "$db_name" "$db_user" "$db_pwd" # Create the database ynh_mysql_create_db "$db_name" "$db_user" "$db_pwd" # Create the database
ynh_app_setting_set $app mysqlpwd $db_pwd # Store the password in the app's config ynh_app_setting_set --app=$app --key=mysqlpwd --value=$db_pwd # Store the password in the app's config
} }
# Remove a database if it exists, and the associated user # Remove a database if it exists, and the associated user
# #
# usage: ynh_mysql_remove_db user name # usage: ynh_mysql_remove_db --db_user=user --db_name=name
# | arg: user - Owner of the database # | arg: -u, --db_user - Owner of the database
# | arg: name - Name of the database # | arg: -n, --db_name - Name of the database
ynh_mysql_remove_db () { ynh_mysql_remove_db () {
local db_user="$1" # Declare an array to define the options of this helper.
local db_name="$2" local legacy_args=un
declare -Ar args_array=( [u]=db_user= [n]=db_name= )
local db_user
local db_name
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
local mysql_root_password=$(sudo cat $MYSQL_ROOT_PWD_FILE) local mysql_root_password=$(sudo cat $MYSQL_ROOT_PWD_FILE)
if mysqlshow -u root -p$mysql_root_password | grep -q "^| $db_name"; then # Check if the database exists if mysqlshow -u root -p$mysql_root_password | grep -q "^| $db_name"; then # Check if the database exists
echo "Removing database $db_name" >&2 echo "Removing database $db_name" >&2
@ -153,7 +210,7 @@ ynh_mysql_remove_db () {
fi fi
# Remove mysql user if it exists # Remove mysql user if it exists
if $(ynh_mysql_user_exists $db_user); then if $(ynh_mysql_user_exists --user=$db_user); then
ynh_mysql_drop_user $db_user ynh_mysql_drop_user $db_user
fi fi
} }
@ -163,10 +220,17 @@ ynh_mysql_remove_db () {
# #
# example: dbname=$(ynh_sanitize_dbid $app) # example: dbname=$(ynh_sanitize_dbid $app)
# #
# usage: ynh_sanitize_dbid name # usage: ynh_sanitize_dbid --db_name=name
# | arg: name - name to correct/sanitize # | arg: -n, --db_name - name to correct/sanitize
# | ret: the corrected name # | ret: the corrected name
ynh_sanitize_dbid () { ynh_sanitize_dbid () {
local dbid=${1//[-.]/_} # We should avoid having - and . in the name of databases. They are replaced by _ # Declare an array to define the options of this helper.
echo $dbid local legacy_args=n
declare -Ar args_array=( [n]=db_name= )
local db_name
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
# We should avoid having - and . in the name of databases. They are replaced by _
echo ${db_name//[-.]/_}
} }

View file

@ -1,3 +1,5 @@
#!/bin/bash
# Normalize the url path syntax # Normalize the url path syntax
# Handle the slash at the beginning of path and its absence at ending # Handle the slash at the beginning of path and its absence at ending
# Return a normalized url path # Return a normalized url path
@ -8,11 +10,17 @@
# ynh_normalize_url_path /example/ -> /example # ynh_normalize_url_path /example/ -> /example
# ynh_normalize_url_path / -> / # ynh_normalize_url_path / -> /
# #
# usage: ynh_normalize_url_path path_to_normalize # usage: ynh_normalize_url_path --path_url=path_to_normalize
# | arg: url_path_to_normalize - URL path to normalize before using it # | arg: -p, --path_url - URL path to normalize before using it
ynh_normalize_url_path () { ynh_normalize_url_path () {
local path_url=$1 # Declare an array to define the options of this helper.
test -n "$path_url" || ynh_die "ynh_normalize_url_path expect a URL path as first argument and received nothing." local legacy_args=p
declare -Ar args_array=( [p]=path_url= )
local path_url
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
test -n "$path_url" || ynh_die --message="ynh_normalize_url_path expect a URL path as first argument and received nothing."
if [ "${path_url:0:1}" != "/" ]; then # If the first character is not a / if [ "${path_url:0:1}" != "/" ]; then # If the first character is not a /
path_url="/$path_url" # Add / at begin of path variable path_url="/$path_url" # Add / at begin of path variable
fi fi
@ -24,13 +32,19 @@ ynh_normalize_url_path () {
# Find a free port and return it # Find a free port and return it
# #
# example: port=$(ynh_find_port 8080) # example: port=$(ynh_find_port --port=8080)
# #
# usage: ynh_find_port begin_port # usage: ynh_find_port --port=begin_port
# | arg: begin_port - port to start to search # | arg: -p, --port - port to start to search
ynh_find_port () { ynh_find_port () {
local port=$1 # Declare an array to define the options of this helper.
test -n "$port" || ynh_die "The argument of ynh_find_port must be a valid port." local legacy_args=p
declare -Ar args_array=( [p]=port= )
local port
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
test -n "$port" || ynh_die --message="The argument of ynh_find_port must be a valid port."
while netcat -z 127.0.0.1 $port # Check if the port is free while netcat -z 127.0.0.1 $port # Check if the port is free
do do
port=$((port+1)) # Else, pass to next port port=$((port+1)) # Else, pass to next port
@ -40,28 +54,40 @@ ynh_find_port () {
# Check availability of a web path # Check availability of a web path
# #
# example: ynh_webpath_available some.domain.tld /coffee # example: ynh_webpath_available --domain=some.domain.tld --path_url=/coffee
# #
# usage: ynh_webpath_available domain path # usage: ynh_webpath_available --domain=domain --path_url=path
# | arg: domain - the domain/host of the url # | arg: -d, --domain - the domain/host of the url
# | arg: path - the web path to check the availability of # | arg: -p, --path_url - the web path to check the availability of
ynh_webpath_available () { ynh_webpath_available () {
local domain=$1 # Declare an array to define the options of this helper.
local path=$2 local legacy_args=dp
sudo yunohost domain url-available $domain $path declare -Ar args_array=( [d]=domain= [p]=path_url= )
local domain
local path_url
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
sudo yunohost domain url-available $domain $path_url
} }
# Register/book a web path for an app # Register/book a web path for an app
# #
# example: ynh_webpath_register wordpress some.domain.tld /coffee # example: ynh_webpath_register --app=wordpress --domain=some.domain.tld --path_url=/coffee
# #
# usage: ynh_webpath_register app domain path # usage: ynh_webpath_register --app=app --domain=domain --path_url=path
# | arg: app - the app for which the domain should be registered # | arg: -a, --app - the app for which the domain should be registered
# | arg: domain - the domain/host of the web path # | arg: -d, --domain - the domain/host of the web path
# | arg: path - the web path to be registered # | arg: -p, --path_url - the web path to be registered
ynh_webpath_register () { ynh_webpath_register () {
local app=$1 # Declare an array to define the options of this helper.
local domain=$2 local legacy_args=adp
local path=$3 declare -Ar args_array=( [a]=app= [d]=domain= [p]=path_url= )
sudo yunohost app register-url $app $domain $path local app
local domain
local path_url
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
sudo yunohost app register-url $app $domain $path_url
} }

View file

@ -1,3 +1,5 @@
#!/bin/bash
n_install_dir="/opt/node_n" n_install_dir="/opt/node_n"
node_version_path="$n_install_dir/n/versions/node" node_version_path="$n_install_dir/n/versions/node"
# N_PREFIX is the directory of n, it needs to be loaded as a environment variable. # N_PREFIX is the directory of n, it needs to be loaded as a environment variable.
@ -15,7 +17,7 @@ ynh_install_n () {
echo "SOURCE_URL=https://github.com/tj/n/archive/v2.1.7.tar.gz echo "SOURCE_URL=https://github.com/tj/n/archive/v2.1.7.tar.gz
SOURCE_SUM=2ba3c9d4dd3c7e38885b37e02337906a1ee91febe6d5c9159d89a9050f2eea8f" > "../conf/n.src" SOURCE_SUM=2ba3c9d4dd3c7e38885b37e02337906a1ee91febe6d5c9159d89a9050f2eea8f" > "../conf/n.src"
# Download and extract n # Download and extract n
ynh_setup_source "$n_install_dir/git" n ynh_setup_source --dest_dir="$n_install_dir/git" --source_id=n
# Install n # Install n
(cd "$n_install_dir/git" (cd "$n_install_dir/git"
PREFIX=$N_PREFIX make install 2>&1) PREFIX=$N_PREFIX make install 2>&1)
@ -35,7 +37,7 @@ SOURCE_SUM=2ba3c9d4dd3c7e38885b37e02337906a1ee91febe6d5c9159d89a9050f2eea8f" > "
# #
# usage: ynh_use_nodejs # usage: ynh_use_nodejs
ynh_use_nodejs () { ynh_use_nodejs () {
nodejs_version=$(ynh_app_setting_get $app nodejs_version) nodejs_version=$(ynh_app_setting_get --app=$app --key=nodejs_version)
nodejs_use_version="echo \"Deprecated command, should be removed\"" nodejs_use_version="echo \"Deprecated command, should be removed\""
@ -53,13 +55,19 @@ ynh_use_nodejs () {
# #
# ynh_install_nodejs will install the version of node provided as argument by using n. # ynh_install_nodejs will install the version of node provided as argument by using n.
# #
# usage: ynh_install_nodejs [nodejs_version] # usage: ynh_install_nodejs --nodejs_version=nodejs_version
# | arg: nodejs_version - Version of node to install. # | arg: -n, --nodejs_version - Version of node to install.
# If possible, prefer to use major version number (e.g. 8 instead of 8.10.0). # If possible, prefer to use major version number (e.g. 8 instead of 8.10.0).
# The crontab will handle the update of minor versions when needed. # The crontab will handle the update of minor versions when needed.
ynh_install_nodejs () { ynh_install_nodejs () {
# Use n, https://github.com/tj/n to manage the nodejs versions # Use n, https://github.com/tj/n to manage the nodejs versions
nodejs_version="$1"
# Declare an array to define the options of this helper.
local legacy_args=n
declare -Ar args_array=( [n]=nodejs_version= )
local nodejs_version
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
# Create $n_install_dir # Create $n_install_dir
mkdir -p "$n_install_dir" mkdir -p "$n_install_dir"
@ -80,7 +88,7 @@ ynh_install_nodejs () {
fi fi
# Modify the default N_PREFIX in n script # Modify the default N_PREFIX in n script
ynh_replace_string "^N_PREFIX=\${N_PREFIX-.*}$" "N_PREFIX=\${N_PREFIX-$N_PREFIX}" "$n_install_dir/bin/n" ynh_replace_string --match_string="^N_PREFIX=\${N_PREFIX-.*}$" --replace_string="N_PREFIX=\${N_PREFIX-$N_PREFIX}" --target_file="$n_install_dir/bin/n"
# Restore /usr/local/bin in PATH # Restore /usr/local/bin in PATH
PATH=$CLEAR_PATH PATH=$CLEAR_PATH
@ -106,7 +114,7 @@ ynh_install_nodejs () {
echo "$YNH_APP_ID:$nodejs_version" | tee --append "$n_install_dir/ynh_app_version" echo "$YNH_APP_ID:$nodejs_version" | tee --append "$n_install_dir/ynh_app_version"
# Store nodejs_version into the config of this app # Store nodejs_version into the config of this app
ynh_app_setting_set $app nodejs_version $nodejs_version ynh_app_setting_set --app=$app --key=nodejs_version --value=$nodejs_version
# Build the update script and set the cronjob # Build the update script and set the cronjob
ynh_cron_upgrade_node ynh_cron_upgrade_node
@ -122,7 +130,7 @@ ynh_install_nodejs () {
# #
# usage: ynh_remove_nodejs # usage: ynh_remove_nodejs
ynh_remove_nodejs () { ynh_remove_nodejs () {
nodejs_version=$(ynh_app_setting_get $app nodejs_version) nodejs_version=$(ynh_app_setting_get --app=$app --key=nodejs_version)
# Remove the line for this app # Remove the line for this app
sed --in-place "/$YNH_APP_ID:$nodejs_version/d" "$n_install_dir/ynh_app_version" sed --in-place "/$YNH_APP_ID:$nodejs_version/d" "$n_install_dir/ynh_app_version"
@ -136,8 +144,8 @@ ynh_remove_nodejs () {
# If no other app uses n, remove n # If no other app uses n, remove n
if [ ! -s "$n_install_dir/ynh_app_version" ] if [ ! -s "$n_install_dir/ynh_app_version" ]
then then
ynh_secure_remove "$n_install_dir" ynh_secure_remove --file="$n_install_dir"
ynh_secure_remove "/usr/local/n" ynh_secure_remove --file="/usr/local/n"
sed --in-place "/N_PREFIX/d" /root/.bashrc sed --in-place "/N_PREFIX/d" /root/.bashrc
rm -f /etc/cron.daily/node_update rm -f /etc/cron.daily/node_update
fi fi

View file

@ -1,3 +1,5 @@
#!/bin/bash
# Check if apt is free to use, or wait, until timeout. # Check if apt is free to use, or wait, until timeout.
# #
# [internal] # [internal]
@ -23,26 +25,40 @@ ynh_wait_dpkg_free() {
# Check either a package is installed or not # Check either a package is installed or not
# #
# example: ynh_package_is_installed 'yunohost' && echo "ok" # example: ynh_package_is_installed --package=yunohost && echo "ok"
# #
# usage: ynh_package_is_installed name # usage: ynh_package_is_installed --package=name
# | arg: name - the package name to check # | arg: -p, --package - the package name to check
ynh_package_is_installed() { ynh_package_is_installed() {
# Declare an array to define the options of this helper.
local legacy_args=p
declare -Ar args_array=( [p]=package= )
local package
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
ynh_wait_dpkg_free ynh_wait_dpkg_free
dpkg-query -W -f '${Status}' "$1" 2>/dev/null \ dpkg-query -W -f '${Status}' "$package" 2>/dev/null \
| grep -c "ok installed" &>/dev/null | grep -c "ok installed" &>/dev/null
} }
# Get the version of an installed package # Get the version of an installed package
# #
# example: version=$(ynh_package_version 'yunohost') # example: version=$(ynh_package_version --package=yunohost)
# #
# usage: ynh_package_version name # usage: ynh_package_version --package=name
# | arg: name - the package name to get version # | arg: -p, --package - the package name to get version
# | ret: the version or an empty string # | ret: the version or an empty string
ynh_package_version() { ynh_package_version() {
if ynh_package_is_installed "$1"; then # Declare an array to define the options of this helper.
dpkg-query -W -f '${Version}' "$1" 2>/dev/null local legacy_args=p
declare -Ar args_array=( [p]=package= )
local package
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
if ynh_package_is_installed "$package"; then
dpkg-query -W -f '${Version}' "$package" 2>/dev/null
else else
echo '' echo ''
fi fi
@ -131,11 +147,11 @@ ynh_package_install_from_equivs () {
# Install the fake package without its dependencies with dpkg # Install the fake package without its dependencies with dpkg
# Install missing dependencies with ynh_package_install # Install missing dependencies with ynh_package_install
ynh_wait_dpkg_free ynh_wait_dpkg_free
(cp "$controlfile" "${TMPDIR}/control" && cd "$TMPDIR" \ cp "$controlfile" "${TMPDIR}/control"
&& equivs-build ./control 1>/dev/null \ (cd "$TMPDIR"
&& sudo dpkg --force-depends \ equivs-build ./control 1> /dev/null
-i "./${pkgname}_${pkgversion}_all.deb" 2>&1 \ dpkg --force-depends -i "./${pkgname}_${pkgversion}_all.deb" 2>&1)
&& ynh_package_install -f) || ynh_die "Unable to install dependencies" ynh_package_install -f || ynh_die --message="Unable to install dependencies"
[[ -n "$TMPDIR" ]] && rm -rf $TMPDIR # Remove the temp dir. [[ -n "$TMPDIR" ]] && rm -rf $TMPDIR # Remove the temp dir.
# check if the package is actually installed # check if the package is actually installed
@ -176,9 +192,9 @@ Description: Fake package for ${app} (YunoHost app) dependencies
This meta-package is only responsible of installing its dependencies. This meta-package is only responsible of installing its dependencies.
EOF EOF
ynh_package_install_from_equivs /tmp/${dep_app}-ynh-deps.control \ ynh_package_install_from_equivs /tmp/${dep_app}-ynh-deps.control \
|| ynh_die "Unable to install dependencies" # Install the fake package and its dependencies || ynh_die --message="Unable to install dependencies" # Install the fake package and its dependencies
rm /tmp/${dep_app}-ynh-deps.control rm /tmp/${dep_app}-ynh-deps.control
ynh_app_setting_set $app apt_dependencies $dependencies ynh_app_setting_set --app=$app --key=apt_dependencies --value="$dependencies"
} }
# Remove fake package and its dependencies # Remove fake package and its dependencies

View file

@ -1,15 +1,32 @@
#!/bin/bash
# Print a message to stderr and exit # Print a message to stderr and exit
# usage: ynh_die MSG [RETCODE] # usage: ynh_die --message=MSG [--ret_code=RETCODE]
ynh_die() { ynh_die() {
echo "$1" 1>&2 # Declare an array to define the options of this helper.
exit "${2:-1}" local legacy_args=mc
declare -Ar args_array=( [m]=message= [c]=ret_code= )
local message
local ret_code
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
echo "$message" 1>&2
exit "${ret_code:-1}"
} }
# Display a message in the 'INFO' logging category # Display a message in the 'INFO' logging category
# #
# usage: ynh_print_info "Some message" # usage: ynh_print_info --message="Some message"
ynh_print_info() { ynh_print_info() {
echo "$1" >> "$YNH_STDINFO" # Declare an array to define the options of this helper.
local legacy_args=m
declare -Ar args_array=( [m]=message= )
local message
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
echo "$message" >> "$YNH_STDINFO"
} }
# Ignore the yunohost-cli log to prevent errors with conditional commands # Ignore the yunohost-cli log to prevent errors with conditional commands
@ -39,18 +56,32 @@ ynh_print_log () {
# Print a warning on stderr # Print a warning on stderr
# #
# usage: ynh_print_warn "Text to print" # usage: ynh_print_warn --message="Text to print"
# | arg: text - The text to print # | arg: -m, --message - The text to print
ynh_print_warn () { ynh_print_warn () {
ynh_print_log "\e[93m\e[1m[WARN]\e[0m ${1}" >&2 # Declare an array to define the options of this helper.
local legacy_args=m
declare -Ar args_array=( [m]=message= )
local message
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
ynh_print_log "\e[93m\e[1m[WARN]\e[0m ${message}" >&2
} }
# Print an error on stderr # Print an error on stderr
# #
# usage: ynh_print_err "Text to print" # usage: ynh_print_err --message="Text to print"
# | arg: text - The text to print # | arg: -m, --message - The text to print
ynh_print_err () { ynh_print_err () {
ynh_print_log "\e[91m\e[1m[ERR]\e[0m ${1}" >&2 # Declare an array to define the options of this helper.
local legacy_args=m
declare -Ar args_array=( [m]=message= )
local message
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
ynh_print_log "\e[91m\e[1m[ERR]\e[0m ${message}" >&2
} }
# Execute a command and print the result as an error # Execute a command and print the result as an error
@ -124,3 +155,81 @@ ynh_print_ON () {
# Print an echo only for the log, to be able to know that ynh_print_ON has been called. # Print an echo only for the log, to be able to know that ynh_print_ON has been called.
echo ynh_print_ON > /dev/null echo ynh_print_ON > /dev/null
} }
# Print a message as INFO and show progression during an app script
#
# usage: ynh_script_progression --message=message [--weight=weight] [--time]
# | arg: -m, --message= - The text to print
# | arg: -w, --weight= - The weight for this progression. This value is 1 by default. Use a bigger value for a longer part of the script.
# | arg: -t, --time= - Print the execution time since the last call to this helper. Especially usefull to define weights.
# | arg: -l, --last= - Use for the last call of the helper, to fill te progression bar.
increment_progression=0
previous_weight=0
# Define base_time when the file is sourced
base_time=$(date +%s)
ynh_script_progression () {
# Declare an array to define the options of this helper.
declare -Ar args_array=( [m]=message= [w]=weight= [t]=time [l]=last )
local message
local weight
local time
local last
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
weight=${weight:-1}
time=${time:-0}
last=${last:-0}
# Get execution time since the last $base_time
local exec_time=$(( $(date +%s) - $base_time ))
base_time=$(date +%s)
# Get the number of occurrences of 'ynh_script_progression' in the script. Except those are commented.
local helper_calls="$(grep --count "^[^#]*ynh_script_progression" $0)"
# Get the number of call with a weight value
local weight_calls=$(grep --perl-regexp --count "^[^#]*ynh_script_progression.*(--weight|-w )" $0)
# Get the weight of each occurrences of 'ynh_script_progression' in the script using --weight
local weight_valuesA="$(grep --perl-regexp "^[^#]*ynh_script_progression.*--weight" $0 | sed 's/.*--weight[= ]\([[:digit:]].*\)/\1/g')"
# Get the weight of each occurrences of 'ynh_script_progression' in the script using -w
local weight_valuesB="$(grep --perl-regexp "^[^#]*ynh_script_progression.*-w " $0 | sed 's/.*-w[= ]\([[:digit:]].*\)/\1/g')"
# Each value will be on a different line.
# Remove each 'end of line' and replace it by a '+' to sum the values.
local weight_values=$(( $(echo "$weight_valuesA" | tr '\n' '+') + $(echo "$weight_valuesB" | tr '\n' '+') 0 ))
# max_progression is a total number of calls to this helper.
# Less the number of calls with a weight value.
# Plus the total of weight values
local max_progression=$(( $helper_calls - $weight_calls + $weight_values ))
# Increment each execution of ynh_script_progression in this script by the weight of the previous call.
increment_progression=$(( $increment_progression + $previous_weight ))
# Store the weight of the current call in $previous_weight for next call
previous_weight=$weight
# Set the scale of the progression bar
local scale=20
# progress_string(1,2) should have the size of the scale.
local progress_string1="####################"
local progress_string0="...................."
# Reduce $increment_progression to the size of the scale
if [ $last -eq 0 ]
then
local effective_progression=$(( $increment_progression * $scale / $max_progression ))
# If last is specified, fill immediately the progression_bar
else
local effective_progression=$scale
fi
# Build $progression_bar from progress_string(1,2) according to $effective_progression
local progression_bar="${progress_string1:0:$effective_progression}${progress_string0:0:$(( $scale - $effective_progression ))}"
local print_exec_time=""
if [ $time -eq 1 ]
then
print_exec_time=" [$(date +%Hh%Mm,%Ss --date="0 + $exec_time sec")]"
fi
ynh_print_info "[$progression_bar] > ${message}${print_exec_time}"
}

View file

@ -1,27 +1,54 @@
#!/bin/bash
# Get an application setting # Get an application setting
# #
# usage: ynh_app_setting_get app key # usage: ynh_app_setting_get --app=app --key=key
# | arg: app - the application id # | arg: -a, --app - the application id
# | arg: key - the setting to get # | arg: -k, --key - the setting to get
ynh_app_setting_get() { ynh_app_setting_get() {
sudo yunohost app setting "$1" "$2" --output-as plain --quiet # Declare an array to define the options of this helper.
local legacy_args=ak
declare -Ar args_array=( [a]=app= [k]=key= )
local app
local key
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
sudo yunohost app setting "$app" "$key" --output-as plain --quiet
} }
# Set an application setting # Set an application setting
# #
# usage: ynh_app_setting_set app key value # usage: ynh_app_setting_set --app=app --key=key --value=value
# | arg: app - the application id # | arg: -a, --app - the application id
# | arg: key - the setting name to set # | arg: -k, --key - the setting name to set
# | arg: value - the setting value to set # | arg: -v, --value - the setting value to set
ynh_app_setting_set() { ynh_app_setting_set() {
sudo yunohost app setting "$1" "$2" --value="$3" --quiet # Declare an array to define the options of this helper.
local legacy_args=akv
declare -Ar args_array=( [a]=app= [k]=key= [v]=value= )
local app
local key
local value
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
sudo yunohost app setting "$app" "$key" --value="$value" --quiet
} }
# Delete an application setting # Delete an application setting
# #
# usage: ynh_app_setting_delete app key # usage: ynh_app_setting_delete --app=app --key=key
# | arg: app - the application id # | arg: -a, --app - the application id
# | arg: key - the setting to delete # | arg: -k, --key - the setting to delete
ynh_app_setting_delete() { ynh_app_setting_delete() {
sudo yunohost app setting -d "$1" "$2" --quiet # Declare an array to define the options of this helper.
local legacy_args=ak
declare -Ar args_array=( [a]=app= [k]=key= )
local app
local key
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
sudo yunohost app setting -d "$app" "$key" --quiet
} }

View file

@ -1,51 +1,71 @@
#!/bin/bash
# Generate a random string # Generate a random string
# #
# example: pwd=$(ynh_string_random 8) # example: pwd=$(ynh_string_random --length=8)
# #
# usage: ynh_string_random [length] # usage: ynh_string_random [--length=string_length]
# | arg: length - the string length to generate (default: 24) # | arg: -l, --length - the string length to generate (default: 24)
ynh_string_random() { ynh_string_random() {
# Declare an array to define the options of this helper.
local legacy_args=l
declare -Ar args_array=( [l]=length= )
local length
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
length=${length:-24}
dd if=/dev/urandom bs=1 count=1000 2> /dev/null \ dd if=/dev/urandom bs=1 count=1000 2> /dev/null \
| tr -c -d 'A-Za-z0-9' \ | tr -c -d 'A-Za-z0-9' \
| sed -n 's/\(.\{'"${1:-24}"'\}\).*/\1/p' | sed -n 's/\(.\{'"$length"'\}\).*/\1/p'
} }
# Substitute/replace a string (or expression) by another in a file # Substitute/replace a string (or expression) by another in a file
# #
# usage: ynh_replace_string match_string replace_string target_file # usage: ynh_replace_string --match_string=match_string --replace_string=replace_string --target_file=target_file
# | arg: match_string - String to be searched and replaced in the file # | arg: -m, --match_string - String to be searched and replaced in the file
# | arg: replace_string - String that will replace matches # | arg: -r, --replace_string - String that will replace matches
# | arg: target_file - File in which the string will be replaced. # | arg: -f, --target_file - File in which the string will be replaced.
# #
# As this helper is based on sed command, regular expressions and # As this helper is based on sed command, regular expressions and
# references to sub-expressions can be used # references to sub-expressions can be used
# (see sed manual page for more information) # (see sed manual page for more information)
ynh_replace_string () { ynh_replace_string () {
local delimit=@ # Declare an array to define the options of this helper.
local match_string=$1 local legacy_args=mrf
local replace_string=$2 declare -Ar args_array=( [m]=match_string= [r]=replace_string= [f]=target_file= )
local workfile=$3 local match_string
local replace_string
local target_file
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
local delimit=@
# Escape the delimiter if it's in the string. # Escape the delimiter if it's in the string.
match_string=${match_string//${delimit}/"\\${delimit}"} match_string=${match_string//${delimit}/"\\${delimit}"}
replace_string=${replace_string//${delimit}/"\\${delimit}"} replace_string=${replace_string//${delimit}/"\\${delimit}"}
sudo sed --in-place "s${delimit}${match_string}${delimit}${replace_string}${delimit}g" "$workfile" sudo sed --in-place "s${delimit}${match_string}${delimit}${replace_string}${delimit}g" "$target_file"
} }
# Substitute/replace a special string by another in a file # Substitute/replace a special string by another in a file
# #
# usage: ynh_replace_special_string match_string replace_string target_file # usage: ynh_replace_special_string --match_string=match_string --replace_string=replace_string --target_file=target_file
# | arg: match_string - String to be searched and replaced in the file # | arg: -m, --match_string - String to be searched and replaced in the file
# | arg: replace_string - String that will replace matches # | arg: -r, --replace_string - String that will replace matches
# | arg: target_file - File in which the string will be replaced. # | arg: -t, --target_file - File in which the string will be replaced.
# #
# This helper will use ynh_replace_string, but as you can use special # This helper will use ynh_replace_string, but as you can use special
# characters, you can't use some regular expressions and sub-expressions. # characters, you can't use some regular expressions and sub-expressions.
ynh_replace_special_string () { ynh_replace_special_string () {
local match_string=$1 # Declare an array to define the options of this helper.
local replace_string=$2 local legacy_args=mrf
local workfile=$3 declare -Ar args_array=( [m]=match_string= [r]=replace_string= [f]=target_file= )
local match_string
local replace_string
local target_file
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
# Escape any backslash to preserve them as simple backslash. # Escape any backslash to preserve them as simple backslash.
match_string=${match_string//\\/"\\\\"} match_string=${match_string//\\/"\\\\"}
@ -55,5 +75,5 @@ ynh_replace_special_string () {
match_string=${match_string//&/"\&"} match_string=${match_string//&/"\&"}
replace_string=${replace_string//&/"\&"} replace_string=${replace_string//&/"\&"}
ynh_replace_string "$match_string" "$replace_string" "$workfile" ynh_replace_string --match_string="$match_string" --replace_string="$replace_string" --target_file="$target_file"
} }

View file

@ -1,3 +1,5 @@
#!/bin/bash
# Manage a fail of the script # Manage a fail of the script
# #
# [internal] # [internal]

View file

@ -1,23 +1,40 @@
#!/bin/bash
# Check if a YunoHost user exists # Check if a YunoHost user exists
# #
# example: ynh_user_exists 'toto' || exit 1 # example: ynh_user_exists 'toto' || exit 1
# #
# usage: ynh_user_exists username # usage: ynh_user_exists --username=username
# | arg: username - the username to check # | arg: -u, --username - the username to check
ynh_user_exists() { ynh_user_exists() {
sudo yunohost user list --output-as json | grep -q "\"username\": \"${1}\"" # Declare an array to define the options of this helper.
local legacy_args=u
declare -Ar args_array=( [u]=username= )
local username
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
sudo yunohost user list --output-as json | grep -q "\"username\": \"${username}\""
} }
# Retrieve a YunoHost user information # Retrieve a YunoHost user information
# #
# example: mail=$(ynh_user_get_info 'toto' 'mail') # example: mail=$(ynh_user_get_info 'toto' 'mail')
# #
# usage: ynh_user_get_info username key # usage: ynh_user_get_info --username=username --key=key
# | arg: username - the username to retrieve info from # | arg: -u, --username - the username to retrieve info from
# | arg: key - the key to retrieve # | arg: -k, --key - the key to retrieve
# | ret: string - the key's value # | ret: string - the key's value
ynh_user_get_info() { ynh_user_get_info() {
sudo yunohost user info "$1" --output-as plain | ynh_get_plain_key "$2" # Declare an array to define the options of this helper.
local legacy_args=uk
declare -Ar args_array=( [u]=username= [k]=key= )
local username
local key
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
sudo yunohost user info "$username" --output-as plain | ynh_get_plain_key "$key"
} }
# Get the list of YunoHost users # Get the list of YunoHost users
@ -33,39 +50,77 @@ ynh_user_list() {
# Check if a user exists on the system # Check if a user exists on the system
# #
# usage: ynh_system_user_exists username # usage: ynh_system_user_exists --username=username
# | arg: username - the username to check # | arg: -u, --username - the username to check
ynh_system_user_exists() { ynh_system_user_exists() {
getent passwd "$1" &>/dev/null # Declare an array to define the options of this helper.
local legacy_args=u
declare -Ar args_array=( [u]=username= )
local username
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
getent passwd "$username" &>/dev/null
} }
# Create a system user # Create a system user
# #
# usage: ynh_system_user_create user_name [home_dir] # examples:
# | arg: user_name - Name of the system user that will be create # - ynh_system_user_create --username=nextcloud -> creates a nextcloud user with
# | arg: home_dir - Path of the home dir for the user. Usually the final path of the app. If this argument is omitted, the user will be created without home # no home directory and /usr/sbin/nologin login shell (hence no login capability)
# - ynh_system_user_create --username=discourse --home_dir=/var/www/discourse --use_shell --> creates a
# discourse user using /var/www/discourse as home directory and the default login shell
#
# usage: ynh_system_user_create --username=user_name [--home_dir=home_dir] [--use_shell]
# | arg: -u, --username - Name of the system user that will be create
# | arg: -h, --home_dir - Path of the home dir for the user. Usually the final path of the app. If this argument is omitted, the user will be created without home
# | arg: -s, --use_shell - Create a user using the default login shell if present.
# If this argument is omitted, the user will be created with /usr/sbin/nologin shell
ynh_system_user_create () { ynh_system_user_create () {
if ! ynh_system_user_exists "$1" # Check if the user exists on the system # Declare an array to define the options of this helper.
local legacy_args=uhs
declare -Ar args_array=( [u]=username= [h]=home_dir= [s]=use_shell )
local username
local home_dir
local use_shell
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
use_shell="${use_shell:-0}"
home_dir="${home_dir:-}"
if ! ynh_system_user_exists "$username" # Check if the user exists on the system
then # If the user doesn't exist then # If the user doesn't exist
if [ $# -ge 2 ]; then # If a home dir is mentioned if [ -n "$home_dir" ]; then # If a home dir is mentioned
local user_home_dir="-d $2" local user_home_dir="-d $home_dir"
else else
local user_home_dir="--no-create-home" local user_home_dir="--no-create-home"
fi fi
sudo useradd $user_home_dir --system --user-group $1 --shell /usr/sbin/nologin || ynh_die "Unable to create $1 system account" if [ $use_shell -eq 1 ]; then # If we want a shell for the user
local shell="" # Use default shell
else
local shell="--shell /usr/sbin/nologin"
fi
useradd $user_home_dir --system --user-group $username $shell || ynh_die "Unable to create $username system account"
fi fi
} }
# Delete a system user # Delete a system user
# #
# usage: ynh_system_user_delete user_name # usage: ynh_system_user_delete --username=user_name
# | arg: user_name - Name of the system user that will be create # | arg: -u, --username - Name of the system user that will be create
ynh_system_user_delete () { ynh_system_user_delete () {
if ynh_system_user_exists "$1" # Check if the user exists on the system # Declare an array to define the options of this helper.
local legacy_args=u
declare -Ar args_array=( [u]=username= )
local username
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
if ynh_system_user_exists "$username" # Check if the user exists on the system
then then
echo "Remove the user $1" >&2 echo "Remove the user $username" >&2
sudo userdel $1 sudo userdel $username
else else
echo "The user $1 was not found" >&2 echo "The user $username was not found" >&2
fi fi
} }

View file

@ -1,3 +1,5 @@
#!/bin/bash
# Extract a key from a plain command output # Extract a key from a plain command output
# #
# example: yunohost user info tata --output-as plain | ynh_get_plain_key mail # example: yunohost user info tata --output-as plain | ynh_get_plain_key mail
@ -48,8 +50,8 @@ ynh_restore_upgradebackup () {
# Remove the application then restore it # Remove the application then restore it
sudo yunohost app remove $app sudo yunohost app remove $app
# Restore the backup # Restore the backup
sudo yunohost backup restore $app_bck-pre-upgrade$backup_number --apps $app --force sudo yunohost backup restore $app_bck-pre-upgrade$backup_number --apps $app --force --debug
ynh_die "The app was restored to the way it was before the failed upgrade." ynh_die --message="The app was restored to the way it was before the failed upgrade."
fi fi
else else
echo "\$NO_BACKUP_UPGRADE is set, that means there's no backup to restore. You have to fix this upgrade by yourself !" >&2 echo "\$NO_BACKUP_UPGRADE is set, that means there's no backup to restore. You have to fix this upgrade by yourself !" >&2
@ -87,7 +89,7 @@ ynh_backup_before_upgrade () {
fi fi
# Create backup # Create backup
sudo BACKUP_CORE_ONLY=1 yunohost backup create --apps $app --name $app_bck-pre-upgrade$backup_number sudo BACKUP_CORE_ONLY=1 yunohost backup create --apps $app --name $app_bck-pre-upgrade$backup_number --debug
if [ "$?" -eq 0 ] if [ "$?" -eq 0 ]
then then
# If the backup succeeded, remove the previous backup # If the backup succeeded, remove the previous backup
@ -97,7 +99,7 @@ ynh_backup_before_upgrade () {
sudo yunohost backup delete $app_bck-pre-upgrade$old_backup_number > /dev/null sudo yunohost backup delete $app_bck-pre-upgrade$old_backup_number > /dev/null
fi fi
else else
ynh_die "Backup failed, the upgrade process was aborted." ynh_die --message="Backup failed, the upgrade process was aborted."
fi fi
else else
echo "\$NO_BACKUP_UPGRADE is set, backup will be avoided. Be careful, this upgrade is going to be operated without a security backup" echo "\$NO_BACKUP_UPGRADE is set, backup will be avoided. Be careful, this upgrade is going to be operated without a security backup"
@ -118,6 +120,8 @@ ynh_backup_before_upgrade () {
# SOURCE_FORMAT=tar.gz # SOURCE_FORMAT=tar.gz
# # (Optional) Put false if sources are directly in the archive root # # (Optional) Put false if sources are directly in the archive root
# # default: true # # default: true
# # Instead of true, SOURCE_IN_SUBDIR could be the number of sub directories
# # to remove.
# SOURCE_IN_SUBDIR=false # SOURCE_IN_SUBDIR=false
# # (Optionnal) Name of the local archive (offline setup support) # # (Optionnal) Name of the local archive (offline setup support)
# # default: ${src_id}.${src_format} # # default: ${src_id}.${src_format}
@ -136,27 +140,35 @@ ynh_backup_before_upgrade () {
# If it's ok, the source archive will be uncompressed in $dest_dir. If the # If it's ok, the source archive will be uncompressed in $dest_dir. If the
# SOURCE_IN_SUBDIR is true, the first level directory of the archive will be # SOURCE_IN_SUBDIR is true, the first level directory of the archive will be
# removed. # removed.
# If SOURCE_IN_SUBDIR is a numeric value, 2 for example, the 2 first level
# directories will be removed
# #
# Finally, patches named sources/patches/${src_id}-*.patch and extra files in # Finally, patches named sources/patches/${src_id}-*.patch and extra files in
# sources/extra_files/$src_id will be applied to dest_dir # sources/extra_files/$src_id will be applied to dest_dir
# #
# #
# usage: ynh_setup_source dest_dir [source_id] # usage: ynh_setup_source --dest_dir=dest_dir [--source_id=source_id]
# | arg: dest_dir - Directory where to setup sources # | arg: -d, --dest_dir - Directory where to setup sources
# | arg: source_id - Name of the app, if the package contains more than one app # | arg: -s, --source_id - Name of the app, if the package contains more than one app
ynh_setup_source () { ynh_setup_source () {
local dest_dir=$1 # Declare an array to define the options of this helper.
local src_id=${2:-app} # If the argument is not given, source_id equals "app" local legacy_args=ds
declare -Ar args_array=( [d]=dest_dir= [s]=source_id= )
local dest_dir
local source_id
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
source_id="${source_id:-app}" # If the argument is not given, source_id equals "app"
# Load value from configuration file (see above for a small doc about this file # Load value from configuration file (see above for a small doc about this file
# format) # format)
local src_url=$(grep 'SOURCE_URL=' "$YNH_CWD/../conf/${src_id}.src" | cut -d= -f2-) local src_url=$(grep 'SOURCE_URL=' "$YNH_CWD/../conf/${source_id}.src" | cut -d= -f2-)
local src_sum=$(grep 'SOURCE_SUM=' "$YNH_CWD/../conf/${src_id}.src" | cut -d= -f2-) local src_sum=$(grep 'SOURCE_SUM=' "$YNH_CWD/../conf/${source_id}.src" | cut -d= -f2-)
local src_sumprg=$(grep 'SOURCE_SUM_PRG=' "$YNH_CWD/../conf/${src_id}.src" | cut -d= -f2-) local src_sumprg=$(grep 'SOURCE_SUM_PRG=' "$YNH_CWD/../conf/${source_id}.src" | cut -d= -f2-)
local src_format=$(grep 'SOURCE_FORMAT=' "$YNH_CWD/../conf/${src_id}.src" | cut -d= -f2-) local src_format=$(grep 'SOURCE_FORMAT=' "$YNH_CWD/../conf/${source_id}.src" | cut -d= -f2-)
local src_extract=$(grep 'SOURCE_EXTRACT=' "$YNH_CWD/../conf/${src_id}.src" | cut -d= -f2-) local src_extract=$(grep 'SOURCE_EXTRACT=' "$YNH_CWD/../conf/${source_id}.src" | cut -d= -f2-)
local src_in_subdir=$(grep 'SOURCE_IN_SUBDIR=' "$YNH_CWD/../conf/${src_id}.src" | cut -d= -f2-) local src_in_subdir=$(grep 'SOURCE_IN_SUBDIR=' "$YNH_CWD/../conf/${source_id}.src" | cut -d= -f2-)
local src_filename=$(grep 'SOURCE_FILENAME=' "$YNH_CWD/../conf/${src_id}.src" | cut -d= -f2-) local src_filename=$(grep 'SOURCE_FILENAME=' "$YNH_CWD/../conf/${source_id}.src" | cut -d= -f2-)
# Default value # Default value
src_sumprg=${src_sumprg:-sha256sum} src_sumprg=${src_sumprg:-sha256sum}
@ -165,7 +177,7 @@ ynh_setup_source () {
src_format=$(echo "$src_format" | tr '[:upper:]' '[:lower:]') src_format=$(echo "$src_format" | tr '[:upper:]' '[:lower:]')
src_extract=${src_extract:-true} src_extract=${src_extract:-true}
if [ "$src_filename" = "" ] ; then if [ "$src_filename" = "" ] ; then
src_filename="${src_id}.${src_format}" src_filename="${source_id}.${src_format}"
fi fi
local local_src="/opt/yunohost-apps-src/${YNH_APP_ID}/${src_filename}" local local_src="/opt/yunohost-apps-src/${YNH_APP_ID}/${src_filename}"
@ -173,12 +185,12 @@ ynh_setup_source () {
then # Use the local source file if it is present then # Use the local source file if it is present
cp $local_src $src_filename cp $local_src $src_filename
else # If not, download the source else # If not, download the source
local out=`wget -nv -O $src_filename $src_url 2>&1` || ynh_print_err $out local out=`wget -nv -O $src_filename $src_url 2>&1` || ynh_print_err --message="$out"
fi fi
# Check the control sum # Check the control sum
echo "${src_sum} ${src_filename}" | ${src_sumprg} -c --status \ echo "${src_sum} ${src_filename}" | ${src_sumprg} -c --status \
|| ynh_die "Corrupt source" || ynh_die --message="Corrupt source"
# Extract source into the app dir # Extract source into the app dir
mkdir -p "$dest_dir" mkdir -p "$dest_dir"
@ -194,35 +206,41 @@ ynh_setup_source () {
local tmp_dir=$(mktemp -d) local tmp_dir=$(mktemp -d)
unzip -quo $src_filename -d "$tmp_dir" unzip -quo $src_filename -d "$tmp_dir"
cp -a $tmp_dir/*/. "$dest_dir" cp -a $tmp_dir/*/. "$dest_dir"
ynh_secure_remove "$tmp_dir" ynh_secure_remove --file="$tmp_dir"
else else
unzip -quo $src_filename -d "$dest_dir" unzip -quo $src_filename -d "$dest_dir"
fi fi
else else
local strip="" local strip=""
if $src_in_subdir ; then if [ "$src_in_subdir" != "false" ]
strip="--strip-components 1" then
if [ "$src_in_subdir" == "true" ]; then
local sub_dirs=1
else
local sub_dirs="$src_in_subdir"
fi
strip="--strip-components $sub_dirs"
fi fi
if [[ "$src_format" =~ ^tar.gz|tar.bz2|tar.xz$ ]] ; then if [[ "$src_format" =~ ^tar.gz|tar.bz2|tar.xz$ ]] ; then
tar -xf $src_filename -C "$dest_dir" $strip tar -xf $src_filename -C "$dest_dir" $strip
else else
ynh_die "Archive format unrecognized." ynh_die --message="Archive format unrecognized."
fi fi
fi fi
# Apply patches # Apply patches
if (( $(find $YNH_CWD/../sources/patches/ -type f -name "${src_id}-*.patch" 2> /dev/null | wc -l) > "0" )); then if (( $(find $YNH_CWD/../sources/patches/ -type f -name "${source_id}-*.patch" 2> /dev/null | wc -l) > "0" )); then
local old_dir=$(pwd) local old_dir=$(pwd)
(cd "$dest_dir" \ (cd "$dest_dir" \
&& for p in $YNH_CWD/../sources/patches/${src_id}-*.patch; do \ && for p in $YNH_CWD/../sources/patches/${source_id}-*.patch; do \
patch -p1 < $p; done) \ patch -p1 < $p; done) \
|| ynh_die "Unable to apply patches" || ynh_die --message="Unable to apply patches"
cd $old_dir cd $old_dir
fi fi
# Add supplementary files # Add supplementary files
if test -e "$YNH_CWD/../sources/extra_files/${src_id}"; then if test -e "$YNH_CWD/../sources/extra_files/${source_id}"; then
cp -a $YNH_CWD/../sources/extra_files/$src_id/. "$dest_dir" cp -a $YNH_CWD/../sources/extra_files/$source_id/. "$dest_dir"
fi fi
} }

View file

@ -16,17 +16,11 @@ do_pre_regen() {
# do not listen to IPv6 if unavailable # do not listen to IPv6 if unavailable
[[ -f /proc/net/if_inet6 ]] && ipv6_enabled=true || ipv6_enabled=false [[ -f /proc/net/if_inet6 ]] && ipv6_enabled=true || ipv6_enabled=false
# Support legacy setting (this setting might be disabled by a user during a migration) ssh_keys=$(ls /etc/ssh/ssh_host_{ed25519,rsa,ecdsa}_key 2>/dev/null || true)
ssh_keys=$(ls /etc/ssh/ssh_host_{ed25519,rsa,ecdsa}_key 2>/dev/null)
if [[ "$(yunohost settings get 'service.ssh.allow_deprecated_dsa_hostkey')" == "True" ]]; then
ssh_keys="$ssh_keys $(ls /etc/ssh/ssh_host_dsa_key 2>/dev/null)"
fi
ssh_keys=$(ls /etc/ssh/ssh_host_{ed25519,rsa,ecdsa}_key 2>/dev/null)
# Support legacy setting (this setting might be disabled by a user during a migration) # Support legacy setting (this setting might be disabled by a user during a migration)
if [[ "$(yunohost settings get 'service.ssh.allow_deprecated_dsa_hostkey')" == "True" ]]; then if [[ "$(yunohost settings get 'service.ssh.allow_deprecated_dsa_hostkey')" == "True" ]]; then
ssh_keys="$ssh_keys $(ls /etc/ssh/ssh_host_dsa_key 2>/dev/null)" ssh_keys="$ssh_keys $(ls /etc/ssh/ssh_host_dsa_key 2>/dev/null || true)"
fi fi
export ssh_keys export ssh_keys

View file

@ -14,15 +14,17 @@ nameserver 80.67.169.40
nameserver 80.67.188.188 nameserver 80.67.188.188
# (FR) ARN # (FR) ARN
nameserver 89.234.141.66 nameserver 89.234.141.66
# (FR) Aquilenet
nameserver 185.233.100.100
nameserver 185.233.100.101
# (FR) gozmail / grifon # (FR) gozmail / grifon
nameserver 89.234.186.18 nameserver 80.67.190.200
# (DE) FoeBud / Digital Courage # (DE) FoeBud / Digital Courage
nameserver 85.214.20.141 nameserver 85.214.20.141
# (FR) Aquilenet [added manually, following comments from @sachaz]
nameserver 141.255.128.100
nameserver 141.255.128.101
# (DE) CCC Berlin # (DE) CCC Berlin
nameserver 213.73.91.35 nameserver 195.160.173.53
# (DE) AS250
nameserver 194.150.168.168
# (DE) Ideal-Hosting # (DE) Ideal-Hosting
nameserver 84.200.69.80 nameserver 84.200.69.80
nameserver 84.200.70.40 nameserver 84.200.70.40

View file

@ -513,27 +513,27 @@ logpath = %(vsftpd_log)s
# ASSP SMTP Proxy Jail # ASSP SMTP Proxy Jail
[assp] [assp]
port = smtp,465,submission port = smtp,submission
logpath = /root/path/to/assp/logs/maillog.txt logpath = /root/path/to/assp/logs/maillog.txt
[courier-smtp] [courier-smtp]
port = smtp,465,submission port = smtp,submission
logpath = %(syslog_mail)s logpath = %(syslog_mail)s
backend = %(syslog_backend)s backend = %(syslog_backend)s
[postfix] [postfix]
port = smtp,465,submission port = smtp,submission
logpath = %(postfix_log)s logpath = %(postfix_log)s
backend = %(postfix_backend)s backend = %(postfix_backend)s
[postfix-rbl] [postfix-rbl]
port = smtp,465,submission port = smtp,submission
logpath = %(postfix_log)s logpath = %(postfix_log)s
backend = %(postfix_backend)s backend = %(postfix_backend)s
maxretry = 1 maxretry = 1
@ -541,14 +541,14 @@ maxretry = 1
[sendmail-auth] [sendmail-auth]
port = submission,465,smtp port = submission,smtp
logpath = %(syslog_mail)s logpath = %(syslog_mail)s
backend = %(syslog_backend)s backend = %(syslog_backend)s
[sendmail-reject] [sendmail-reject]
port = smtp,465,submission port = smtp,submission
logpath = %(syslog_mail)s logpath = %(syslog_mail)s
backend = %(syslog_backend)s backend = %(syslog_backend)s
@ -556,7 +556,7 @@ backend = %(syslog_backend)s
[qmail-rbl] [qmail-rbl]
filter = qmail filter = qmail
port = smtp,465,submission port = smtp,submission
logpath = /service/qmail/log/main/current logpath = /service/qmail/log/main/current
@ -564,14 +564,14 @@ logpath = /service/qmail/log/main/current
# but can be set by syslog_facility in the dovecot configuration. # but can be set by syslog_facility in the dovecot configuration.
[dovecot] [dovecot]
port = pop3,pop3s,imap,imaps,submission,465,sieve port = pop3,pop3s,imap,imaps,submission,sieve
logpath = %(dovecot_log)s logpath = %(dovecot_log)s
backend = %(dovecot_backend)s backend = %(dovecot_backend)s
[sieve] [sieve]
port = smtp,465,submission port = smtp,submission
logpath = %(dovecot_log)s logpath = %(dovecot_log)s
backend = %(dovecot_backend)s backend = %(dovecot_backend)s
@ -584,19 +584,19 @@ logpath = %(solidpop3d_log)s
[exim] [exim]
port = smtp,465,submission port = smtp,submission
logpath = %(exim_main_log)s logpath = %(exim_main_log)s
[exim-spam] [exim-spam]
port = smtp,465,submission port = smtp,submission
logpath = %(exim_main_log)s logpath = %(exim_main_log)s
[kerio] [kerio]
port = imap,smtp,imaps,465 port = imap,smtp,imaps
logpath = /opt/kerio/mailserver/store/logs/security.log logpath = /opt/kerio/mailserver/store/logs/security.log
@ -607,14 +607,14 @@ logpath = /opt/kerio/mailserver/store/logs/security.log
[courier-auth] [courier-auth]
port = smtp,465,submission,imaps,pop3,pop3s port = smtp,submission,imaps,pop3,pop3s
logpath = %(syslog_mail)s logpath = %(syslog_mail)s
backend = %(syslog_backend)s backend = %(syslog_backend)s
[postfix-sasl] [postfix-sasl]
port = smtp,465,submission,imap,imaps,pop3,pop3s port = smtp,submission,imap,imaps,pop3,pop3s
# You might consider monitoring /var/log/mail.warn instead if you are # You might consider monitoring /var/log/mail.warn instead if you are
# running postfix since it would provide the same log lines at the # running postfix since it would provide the same log lines at the
# "warn" level but overall at the smaller filesize. # "warn" level but overall at the smaller filesize.
@ -631,7 +631,7 @@ backend = %(syslog_backend)s
[squirrelmail] [squirrelmail]
port = smtp,465,submission,imap,imap2,imaps,pop3,pop3s,http,https,socks port = smtp,submission,imap,imap2,imaps,pop3,pop3s,http,https,socks
logpath = /var/lib/squirrelmail/prefs/squirrelmail_access_log logpath = /var/lib/squirrelmail/prefs/squirrelmail_access_log

View file

@ -12,11 +12,8 @@ server {
} }
server { server {
# Disabling http2 for now as it's causing weird issues with curl listen 443 ssl http2 default_server;
#listen 443 ssl http2 default_server; listen [::]:443 ssl http2 default_server;
#listen [::]:443 ssl http2 default_server;
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
ssl_certificate /etc/yunohost/certs/yunohost.org/crt.pem; ssl_certificate /etc/yunohost/certs/yunohost.org/crt.pem;
ssl_certificate_key /etc/yunohost/certs/yunohost.org/key.pem; ssl_certificate_key /etc/yunohost/certs/yunohost.org/key.pem;
@ -24,12 +21,7 @@ server {
ssl_session_cache shared:SSL:50m; ssl_session_cache shared:SSL:50m;
# As suggested by Mozilla : https://wiki.mozilla.org/Security/Server_Side_TLS and https://en.wikipedia.org/wiki/Curve25519 # As suggested by Mozilla : https://wiki.mozilla.org/Security/Server_Side_TLS and https://en.wikipedia.org/wiki/Curve25519
# (this doesn't work on jessie though ...?) ssl_ecdh_curve secp521r1:secp384r1:prime256v1;
# ssl_ecdh_curve secp521r1:secp384r1:prime256v1;
# As suggested by https://cipherli.st/
ssl_ecdh_curve secp384r1;
ssl_prefer_server_ciphers on; ssl_prefer_server_ciphers on;
# Ciphers with intermediate compatibility # Ciphers with intermediate compatibility
@ -50,14 +42,14 @@ server {
# Follows the Web Security Directives from the Mozilla Dev Lab and the Mozilla Obervatory + Partners # Follows the Web Security Directives from the Mozilla Dev Lab and the Mozilla Obervatory + Partners
# https://wiki.mozilla.org/Security/Guidelines/Web_Security # https://wiki.mozilla.org/Security/Guidelines/Web_Security
# https://observatory.mozilla.org/ # https://observatory.mozilla.org/
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"; more_set_headers "Strict-Transport-Security : max-age=63072000; includeSubDomains; preload";
add_header 'Referrer-Policy' 'same-origin'; more_set_headers "Referrer-Policy : 'same-origin'";
add_header Content-Security-Policy "upgrade-insecure-requests; object-src 'none'; script-src https: 'unsafe-eval'"; more_set_headers "Content-Security-Policy : upgrade-insecure-requests; object-src 'none'; script-src https: 'unsafe-eval'";
add_header X-Content-Type-Options nosniff; more_set_headers "X-Content-Type-Options : nosniff";
add_header X-XSS-Protection "1; mode=block"; more_set_headers "X-XSS-Protection : 1; mode=block";
add_header X-Download-Options noopen; more_set_headers "X-Download-Options : noopen";
add_header X-Permitted-Cross-Domain-Policies none; more_set_headers "X-Permitted-Cross-Domain-Policies : none";
add_header X-Frame-Options "SAMEORIGIN"; more_set_headers "X-Frame-Options : SAMEORIGIN";
location / { location / {
return 302 https://$http_host/yunohost/admin; return 302 https://$http_host/yunohost/admin;

View file

@ -12,7 +12,7 @@ server {
} }
location /.well-known/autoconfig/mail/ { location /.well-known/autoconfig/mail/ {
alias /var/www/.well-known/{{ domain }}/autoconfig/mail; alias /var/www/.well-known/{{ domain }}/autoconfig/mail/;
} }
access_log /var/log/nginx/{{ domain }}-access.log; access_log /var/log/nginx/{{ domain }}-access.log;

91
debian/changelog vendored
View file

@ -1,3 +1,94 @@
yunohost (3.4.2.3) stable; urgency=low
- [fix] Admin password appearing in logs after logging in on webadmin
- [fix] Update friendly DNS resolver list
-- Alexandre Aubin <alex.aubin@mailoo.org> Thu, 07 Feb 2019 03:20:10 +0000
yunohost (3.4.2.2) stable; urgency=low
- Silly bug in migraton 8 :|
-- Alexandre Aubin <alex.aubin@mailoo.org> Wed, 30 Jan 2019 21:17:00 +0000
yunohost (3.4.2.1) stable; urgency=low
Small issues
- Fix parsing of the Meltdown vulnerability checker (ignore stderr :/)
- Mail autoconfig was broken, follow-up of #564
- Handle the fact that the archive folder might not exist, in migration 0008
-- Alexandre Aubin <alex.aubin@mailoo.org> Wed, 30 Jan 2019 16:37:00 +0000
yunohost (3.4.2) stable; urgency=low
- [fix] Do not log stretch migration in /tmp/ (#632)
- [fix] Some issues with ynh_handle_getopts_args (#628)
- [fix] Revert some stuff about separates php-ini file (c.f. #548) (#627)
- [fix] App conflicted with itself during change_url (#626)
- [fix] Improve `ynh_package_install_from_equivs` debuggability (#625)
- [enh] Add systemd log handling (#624)
- [enh] Update spectre meltdown checker (#620)
- [fix] Propagate HTTP2, more_set_headers and ecdh_curve changes to webadmin (#618)
- [enh] Control the login shell when creating users in ynh_system_user_create (#455, #629)
- [fix] Postgresql-9.4 was being detected as installed whereas it was in fact not (969577b)
- [fix] Restoring system failed because of temporary dumb password being refused (51712f9)
Thanks to all contributors (Aleks, frju365, JimboJoe, kay0u, Maniack, opi) ! <3
-- Alexandre Aubin <alex.aubin@mailoo.org> Tue, 29 Jan 2019 16:42:00 +0000
yunohost (3.4.1) testing; urgency=low
* [fix] `_run_service_command` not properly returning False if command fails (#616)
* [enh] Change git clone for gitlab working with branch (#615)
* [fix] Set owner of archives folder to 'admin' (#613)
* [enh] Add reload and restart actions to 'yunohost service' (#611)
* [fix] propagate --no-checks cert-install option to renew crontab (#610)
* [fix] Several issues with bootprompt (#609)
* [fix] Fix the way change_url updates the domain/path (#608)
* [fix] Repair tests (#607)
* [fix] Explicit dependance to iptables (1667ba1)
* [i18n] Tiny typographic changes (#612)
* [i18n] Improve translations for Hungarian, Esperanto, German
* Misc minor fixes and improvements.
Thanks to all contributors (Aleks, Bram, J. Meggyeshazi, Jibec, Josué, M. Martin, P. Bourré, anubis) ! <3
-- Alexandre Aubin <alex.aubin@mailoo.org> Thu, 17 Jan 2019 22:16:00 +0000
yunohost (3.4.0) testing; urgency=low
* Misc fixes (#601, #600, #593)
* [fix] DEBUG-level messages not appearing in actions performed via the API (#603)
* [enh] Also remove /var/mail/<username> directory on user delete (with --purge option) (#602)
* [enh] Ask confirmation before installing low-quality, experimental or third party apps (#598)
* [fix] Repair tests (#595)
* [enh] Clean + harden sshd config using Mozilla recommendation (#590
* [fix] Add libpam-ldapd as dependency to be able to login through SSH with LDAP? (#587)
* [enh] Add post_cert_update hook each time certificate is updated (#586)
* [enh] Enable HTTP2 (#580)
* [enh] Update ECDH curves recommended by Mozilla, now that we are on stretch (#579)
* [enh] Allow to not fail on backup and restore for non-mandatory files (#576)
* [enh] Simplify error management (#574)
* [enh] Use more_set_headers in nginx config + fixes for path traversal issues (#564)
* [enh] Display human readable date and clarify timezone handling (#552)
* [fix] Do not use separate ini file for php pools anymore (#548)
* [enh] Improve UPnP support (#542)
* [fix] Standardize sshd configuration (#518)
* [fix] DKIM keys for new domains werent generated (0445aed)
* [i18n] Improve translations for Arabic, Italian and Spanish
Thanks to all contributors (Aleks, A. Pierré, ButterflyOfFire, Bram, irina11y, Josué, Maniack Crudelis, Sylkevicious, T. Hill, chateau, frju365, gdayon, liberodark, ljf, nqb, wilPoly) ! <3
-- Alexandre Aubin <alex.aubin@mailoo.org> Thu, 20 Dec 2018 22:13:00 +0000
yunohost (3.3.4) stable; urgency=low
* [fix] Use --force-confold and noninteractive debian frontend during core upgrade (#614)
-- Alexandre Aubin <alex.aubin@mailoo.org> Thu, 17 Jan 2019 02:00:00 +0000
yunohost (3.3.3) stable; urgency=low yunohost (3.3.3) stable; urgency=low
* [fix] ynh_wait_dpkg_free displaying a warning despite everything being okay (#593) * [fix] ynh_wait_dpkg_free displaying a warning despite everything being okay (#593)

2
debian/control vendored
View file

@ -20,7 +20,7 @@ Depends: ${python:Depends}, ${misc:Depends}
, slapd, ldap-utils, sudo-ldap, libnss-ldapd, unscd, libpam-ldapd , slapd, ldap-utils, sudo-ldap, libnss-ldapd, unscd, libpam-ldapd
, postfix-ldap, postfix-policyd-spf-perl, postfix-pcre, procmail, mailutils, postsrsd , postfix-ldap, postfix-policyd-spf-perl, postfix-pcre, procmail, mailutils, postsrsd
, dovecot-ldap, dovecot-lmtpd, dovecot-managesieved , dovecot-ldap, dovecot-lmtpd, dovecot-managesieved
, dovecot-antispam, fail2ban , dovecot-antispam, fail2ban, iptables
, nginx-extras (>=1.6.2), php-fpm, php-ldap, php-intl , nginx-extras (>=1.6.2), php-fpm, php-ldap, php-intl
, dnsmasq, openssl, avahi-daemon, libnss-mdns, resolvconf, libnss-myhostname , dnsmasq, openssl, avahi-daemon, libnss-mdns, resolvconf, libnss-myhostname
, metronome , metronome

View file

@ -152,11 +152,11 @@
"domain_dyndns_dynette_is_unreachable": "Unable to reach YunoHost dynette, either your YunoHost is not correctly connected to the internet or the dynette server is down. Error: {error}", "domain_dyndns_dynette_is_unreachable": "Unable to reach YunoHost dynette, either your YunoHost is not correctly connected to the internet or the dynette server is down. Error: {error}",
"domain_dyndns_invalid": "Invalid domain to use with DynDNS", "domain_dyndns_invalid": "Invalid domain to use with DynDNS",
"domain_dyndns_root_unknown": "Unknown DynDNS root domain", "domain_dyndns_root_unknown": "Unknown DynDNS root domain",
"domain_exists": "Domain already exists", "domain_exists": "اسم النطاق موجود مِن قبل",
"domain_hostname_failed": "Failed to set new hostname", "domain_hostname_failed": "Failed to set new hostname",
"domain_uninstall_app_first": "One or more apps are installed on this domain. Please uninstall them before proceeding to domain removal", "domain_uninstall_app_first": "One or more apps are installed on this domain. Please uninstall them before proceeding to domain removal",
"domain_unknown": "النطاق مجهول", "domain_unknown": "النطاق مجهول",
"domain_zone_exists": "DNS zone file already exists", "domain_zone_exists": "ملف منطقة أسماء النطاقات موجود مِن قبل",
"domain_zone_not_found": "DNS zone file not found for domain {:s}", "domain_zone_not_found": "DNS zone file not found for domain {:s}",
"domains_available": "النطاقات المتوفرة :", "domains_available": "النطاقات المتوفرة :",
"done": "تم", "done": "تم",
@ -166,9 +166,9 @@
"dyndns_cron_remove_failed": "Unable to remove the DynDNS cron job", "dyndns_cron_remove_failed": "Unable to remove the DynDNS cron job",
"dyndns_cron_removed": "The DynDNS cron job has been removed", "dyndns_cron_removed": "The DynDNS cron job has been removed",
"dyndns_ip_update_failed": "Unable to update IP address on DynDNS", "dyndns_ip_update_failed": "Unable to update IP address on DynDNS",
"dyndns_ip_updated": "Your IP address has been updated on DynDNS", "dyndns_ip_updated": "لقد تم تحديث عنوان الإيبي الخاص بك على نظام أسماء النطاقات الديناميكي",
"dyndns_key_generating": "DNS key is being generated, it may take a while...", "dyndns_key_generating": "عملية توليد مفتاح نظام أسماء النطاقات جارية. يمكن للعملية أن تستغرق بعضا من الوقت…",
"dyndns_key_not_found": "DNS key not found for the domain", "dyndns_key_not_found": "لم يتم العثور على مفتاح DNS الخاص باسم النطاق هذا",
"dyndns_no_domain_registered": "No domain has been registered with DynDNS", "dyndns_no_domain_registered": "No domain has been registered with DynDNS",
"dyndns_registered": "The DynDNS domain has been registered", "dyndns_registered": "The DynDNS domain has been registered",
"dyndns_registration_failed": "Unable to register DynDNS domain: {error:s}", "dyndns_registration_failed": "Unable to register DynDNS domain: {error:s}",

View file

@ -12,7 +12,7 @@
"app_install_files_invalid": "Ungültige Installationsdateien", "app_install_files_invalid": "Ungültige Installationsdateien",
"app_location_already_used": "Eine andere App ({app}) ist bereits an diesem Ort ({path}) installiert", "app_location_already_used": "Eine andere App ({app}) ist bereits an diesem Ort ({path}) installiert",
"app_location_install_failed": "Die App kann nicht an diesem Ort installiert werden, da es mit der App {other_app} die bereits in diesem Pfad ({other_path}) installiert ist Probleme geben würde", "app_location_install_failed": "Die App kann nicht an diesem Ort installiert werden, da es mit der App {other_app} die bereits in diesem Pfad ({other_path}) installiert ist Probleme geben würde",
"app_manifest_invalid": "Ungültiges App-Manifest", "app_manifest_invalid": "Ungültiges App-Manifest: {error}",
"app_no_upgrade": "Keine Aktualisierungen für Apps verfügbar", "app_no_upgrade": "Keine Aktualisierungen für Apps verfügbar",
"app_not_installed": "{app:s} ist nicht installiert", "app_not_installed": "{app:s} ist nicht installiert",
"app_recent_version_required": "Für {:s} benötigt eine aktuellere Version von moulinette", "app_recent_version_required": "Für {:s} benötigt eine aktuellere Version von moulinette",
@ -294,7 +294,7 @@
"backup_applying_method_tar": "Erstellen des Backup-tar Archives...", "backup_applying_method_tar": "Erstellen des Backup-tar Archives...",
"backup_applying_method_copy": "Kopiere alle Dateien ins Backup...", "backup_applying_method_copy": "Kopiere alle Dateien ins Backup...",
"app_change_url_no_script": "Die Anwendung '{app_name:s}' unterstützt bisher keine URL-Modufikation. Vielleicht gibt es eine Aktualisierung der Anwendung.", "app_change_url_no_script": "Die Anwendung '{app_name:s}' unterstützt bisher keine URL-Modufikation. Vielleicht gibt es eine Aktualisierung der Anwendung.",
"app_location_unavailable": "Diese URL ist nicht verfügbar oder wird von einer installierten Anwendung genutzt", "app_location_unavailable": "Diese URL ist nicht verfügbar oder wird von einer installierten Anwendung genutzt:\n{apps:s}",
"backup_applying_method_custom": "Rufe die benutzerdefinierte Backup-Methode '{method:s}' auf...", "backup_applying_method_custom": "Rufe die benutzerdefinierte Backup-Methode '{method:s}' auf...",
"backup_archive_system_part_not_available": "Der System-Teil '{part:s}' ist in diesem Backup nicht enthalten", "backup_archive_system_part_not_available": "Der System-Teil '{part:s}' ist in diesem Backup nicht enthalten",
"backup_archive_mount_failed": "Das Einbinden des Backup-Archives ist fehlgeschlagen", "backup_archive_mount_failed": "Das Einbinden des Backup-Archives ist fehlgeschlagen",

View file

@ -30,20 +30,20 @@
"app_not_properly_removed": "{app:s} has not been properly removed", "app_not_properly_removed": "{app:s} has not been properly removed",
"app_package_need_update": "The app {app} package needs to be updated to follow YunoHost changes", "app_package_need_update": "The app {app} package needs to be updated to follow YunoHost changes",
"app_removed": "{app:s} has been removed", "app_removed": "{app:s} has been removed",
"app_requirements_checking": "Checking required packages for {app}...", "app_requirements_checking": "Checking required packages for {app}",
"app_requirements_failed": "Unable to meet requirements for {app}: {error}", "app_requirements_failed": "Unable to meet requirements for {app}: {error}",
"app_requirements_unmeet": "Requirements are not met for {app}, the package {pkgname} ({version}) must be {spec}", "app_requirements_unmeet": "Requirements are not met for {app}, the package {pkgname} ({version}) must be {spec}",
"app_sources_fetch_failed": "Unable to fetch sources files", "app_sources_fetch_failed": "Unable to fetch sources files",
"app_unknown": "Unknown app", "app_unknown": "Unknown app",
"app_unsupported_remote_type": "Unsupported remote type used for the app", "app_unsupported_remote_type": "Unsupported remote type used for the app",
"app_upgrade_app_name": "Upgrading app {app}...", "app_upgrade_app_name": "Upgrading app {app}",
"app_upgrade_failed": "Unable to upgrade {app:s}", "app_upgrade_failed": "Unable to upgrade {app:s}",
"app_upgrade_some_app_failed": "Unable to upgrade some applications", "app_upgrade_some_app_failed": "Unable to upgrade some applications",
"app_upgraded": "{app:s} has been upgraded", "app_upgraded": "{app:s} has been upgraded",
"appslist_corrupted_json": "Could not load the application lists. It looks like {filename:s} is corrupted.", "appslist_corrupted_json": "Could not load the application lists. It looks like {filename:s} is corrupted.",
"appslist_could_not_migrate": "Could not migrate app list {appslist:s} ! Unable to parse the url... The old cron job has been kept in {bkp_file:s}.", "appslist_could_not_migrate": "Could not migrate app list {appslist:s}! Unable to parse the url… The old cron job has been kept in {bkp_file:s}.",
"appslist_fetched": "The application list {appslist:s} has been fetched", "appslist_fetched": "The application list {appslist:s} has been fetched",
"appslist_migrating": "Migrating application list {appslist:s} ...", "appslist_migrating": "Migrating application list {appslist:s}",
"appslist_name_already_tracked": "There is already a registered application list with name {name:s}.", "appslist_name_already_tracked": "There is already a registered application list with name {name:s}.",
"appslist_removed": "The application list {appslist:s} has been removed", "appslist_removed": "The application list {appslist:s} has been removed",
"appslist_retrieve_bad_format": "Retrieved file for application list {appslist:s} is not valid", "appslist_retrieve_bad_format": "Retrieved file for application list {appslist:s} is not valid",
@ -57,15 +57,17 @@
"ask_list_to_remove": "List to remove", "ask_list_to_remove": "List to remove",
"ask_main_domain": "Main domain", "ask_main_domain": "Main domain",
"ask_new_admin_password": "New administration password", "ask_new_admin_password": "New administration password",
"ask_new_domain": "New domain",
"ask_new_path": "New path",
"ask_password": "Password", "ask_password": "Password",
"ask_path": "Path", "ask_path": "Path",
"backup_abstract_method": "This backup method hasn't yet been implemented", "backup_abstract_method": "This backup method hasn't yet been implemented",
"backup_action_required": "You must specify something to save", "backup_action_required": "You must specify something to save",
"backup_app_failed": "Unable to back up the app '{app:s}'", "backup_app_failed": "Unable to back up the app '{app:s}'",
"backup_applying_method_borg": "Sending all files to backup into borg-backup repository...", "backup_applying_method_borg": "Sending all files to backup into borg-backup repository",
"backup_applying_method_copy": "Copying all files to backup...", "backup_applying_method_copy": "Copying all files to backup",
"backup_applying_method_custom": "Calling the custom backup method '{method:s}'...", "backup_applying_method_custom": "Calling the custom backup method '{method:s}'",
"backup_applying_method_tar": "Creating the backup tar archive...", "backup_applying_method_tar": "Creating the backup tar archive",
"backup_archive_app_not_found": "App '{app:s}' not found in the backup archive", "backup_archive_app_not_found": "App '{app:s}' not found in the backup archive",
"backup_archive_broken_link": "Unable to access backup archive (broken link to {path:s})", "backup_archive_broken_link": "Unable to access backup archive (broken link to {path:s})",
"backup_archive_mount_failed": "Mounting the backup archive failed", "backup_archive_mount_failed": "Mounting the backup archive failed",
@ -81,7 +83,7 @@
"backup_copying_to_organize_the_archive": "Copying {size:s}MB to organize the archive", "backup_copying_to_organize_the_archive": "Copying {size:s}MB to organize the archive",
"backup_couldnt_bind": "Couldn't bind {src:s} to {dest:s}.", "backup_couldnt_bind": "Couldn't bind {src:s} to {dest:s}.",
"backup_created": "Backup created", "backup_created": "Backup created",
"backup_creating_archive": "Creating the backup archive...", "backup_creating_archive": "Creating the backup archive",
"backup_creation_failed": "Backup creation failed", "backup_creation_failed": "Backup creation failed",
"backup_csv_addition_failed": "Unable to add files to backup into the CSV file", "backup_csv_addition_failed": "Unable to add files to backup into the CSV file",
"backup_csv_creation_failed": "Unable to create the CSV file needed for future restore operations", "backup_csv_creation_failed": "Unable to create the CSV file needed for future restore operations",
@ -90,7 +92,7 @@
"backup_custom_need_mount_error": "Custom backup method failure on 'need_mount' step", "backup_custom_need_mount_error": "Custom backup method failure on 'need_mount' step",
"backup_delete_error": "Unable to delete '{path:s}'", "backup_delete_error": "Unable to delete '{path:s}'",
"backup_deleted": "The backup has been deleted", "backup_deleted": "The backup has been deleted",
"backup_extracting_archive": "Extracting the backup archive...", "backup_extracting_archive": "Extracting the backup archive",
"backup_hook_unknown": "Backup hook '{hook:s}' unknown", "backup_hook_unknown": "Backup hook '{hook:s}' unknown",
"backup_invalid_archive": "Invalid backup archive", "backup_invalid_archive": "Invalid backup archive",
"backup_method_borg_finished": "Backup into borg finished", "backup_method_borg_finished": "Backup into borg finished",
@ -104,8 +106,8 @@
"backup_output_directory_required": "You must provide an output directory for the backup", "backup_output_directory_required": "You must provide an output directory for the backup",
"backup_output_symlink_dir_broken": "You have a broken symlink instead of your archives directory '{path:s}'. You may have a specific setup to backup your data on an other filesystem, in this case you probably forgot to remount or plug your hard dirve or usb key.", "backup_output_symlink_dir_broken": "You have a broken symlink instead of your archives directory '{path:s}'. You may have a specific setup to backup your data on an other filesystem, in this case you probably forgot to remount or plug your hard dirve or usb key.",
"backup_php5_to_php7_migration_may_fail": "Could not convert your archive to support php7, your php apps may fail to restore (reason: {error:s})", "backup_php5_to_php7_migration_may_fail": "Could not convert your archive to support php7, your php apps may fail to restore (reason: {error:s})",
"backup_running_app_script": "Running backup script of app '{app:s}'...", "backup_running_app_script": "Running backup script of app '{app:s}'",
"backup_running_hooks": "Running backup hooks...", "backup_running_hooks": "Running backup hooks",
"backup_system_part_failed": "Unable to backup the '{part:s}' system part", "backup_system_part_failed": "Unable to backup the '{part:s}' system part",
"backup_unable_to_organize_files": "Unable to organize files in the archive with the quick method", "backup_unable_to_organize_files": "Unable to organize files in the archive with the quick method",
"backup_with_no_backup_script_for_app": "App {app:s} has no backup script. Ignoring.", "backup_with_no_backup_script_for_app": "App {app:s} has no backup script. Ignoring.",
@ -119,7 +121,7 @@
"certmanager_cert_install_success_selfsigned": "Successfully installed a self-signed certificate for domain {domain:s}!", "certmanager_cert_install_success_selfsigned": "Successfully installed a self-signed certificate for domain {domain:s}!",
"certmanager_cert_renew_success": "Successfully renewed Let's Encrypt certificate for domain {domain:s}!", "certmanager_cert_renew_success": "Successfully renewed Let's Encrypt certificate for domain {domain:s}!",
"certmanager_cert_signing_failed": "Signing the new certificate failed", "certmanager_cert_signing_failed": "Signing the new certificate failed",
"certmanager_certificate_fetching_or_enabling_failed": "Sounds like enabling the new certificate for {domain:s} failed somehow...", "certmanager_certificate_fetching_or_enabling_failed": "Sounds like enabling the new certificate for {domain:s} failed somehow",
"certmanager_conflicting_nginx_file": "Unable to prepare domain for ACME challenge: the nginx configuration file {filepath:s} is conflicting and should be removed first", "certmanager_conflicting_nginx_file": "Unable to prepare domain for ACME challenge: the nginx configuration file {filepath:s} is conflicting and should be removed first",
"certmanager_couldnt_fetch_intermediate_cert": "Timed out when trying to fetch intermediate certificate from Let's Encrypt. Certificate installation/renewal aborted - please try again later.", "certmanager_couldnt_fetch_intermediate_cert": "Timed out when trying to fetch intermediate certificate from Let's Encrypt. Certificate installation/renewal aborted - please try again later.",
"certmanager_domain_cert_not_selfsigned": "The certificate for domain {domain:s} is not self-signed. Are you sure you want to replace it? (Use --force)", "certmanager_domain_cert_not_selfsigned": "The certificate for domain {domain:s} is not self-signed. Are you sure you want to replace it? (Use --force)",
@ -164,25 +166,27 @@
"domain_zone_not_found": "DNS zone file not found for domain {:s}", "domain_zone_not_found": "DNS zone file not found for domain {:s}",
"domains_available": "Available domains:", "domains_available": "Available domains:",
"done": "Done", "done": "Done",
"downloading": "Downloading...", "downloading": "Downloading",
"dyndns_could_not_check_provide": "Could not check if {provider:s} can provide {domain:s}.", "dyndns_could_not_check_provide": "Could not check if {provider:s} can provide {domain:s}.",
"dyndns_could_not_check_available": "Could not check if {domain:s} is available on {provider:s}.",
"dyndns_cron_installed": "The DynDNS cron job has been installed", "dyndns_cron_installed": "The DynDNS cron job has been installed",
"dyndns_cron_remove_failed": "Unable to remove the DynDNS cron job", "dyndns_cron_remove_failed": "Unable to remove the DynDNS cron job",
"dyndns_cron_removed": "The DynDNS cron job has been removed", "dyndns_cron_removed": "The DynDNS cron job has been removed",
"dyndns_ip_update_failed": "Unable to update IP address on DynDNS", "dyndns_ip_update_failed": "Unable to update IP address on DynDNS",
"dyndns_ip_updated": "Your IP address has been updated on DynDNS", "dyndns_ip_updated": "Your IP address has been updated on DynDNS",
"dyndns_key_generating": "DNS key is being generated, it may take a while...", "dyndns_key_generating": "DNS key is being generated, it may take a while",
"dyndns_key_not_found": "DNS key not found for the domain", "dyndns_key_not_found": "DNS key not found for the domain",
"dyndns_no_domain_registered": "No domain has been registered with DynDNS", "dyndns_no_domain_registered": "No domain has been registered with DynDNS",
"dyndns_registered": "The DynDNS domain has been registered", "dyndns_registered": "The DynDNS domain has been registered",
"dyndns_registration_failed": "Unable to register DynDNS domain: {error:s}", "dyndns_registration_failed": "Unable to register DynDNS domain: {error:s}",
"dyndns_domain_not_provided": "Dyndns provider {provider:s} cannot provide domain {domain:s}.", "dyndns_domain_not_provided": "Dyndns provider {provider:s} cannot provide domain {domain:s}.",
"dyndns_unavailable": "Domain {domain:s} is not available.", "dyndns_unavailable": "Domain {domain:s} is not available.",
"executing_command": "Executing command '{command:s}'...", "executing_command": "Executing command '{command:s}'",
"executing_script": "Executing script '{script:s}'...", "executing_script": "Executing script '{script:s}'",
"extracting": "Extracting...", "extracting": "Extracting",
"experimental_feature": "Warning: this feature is experimental and not consider stable, you shouldn't be using it except if you know what you are doing.", "experimental_feature": "Warning: this feature is experimental and not consider stable, you shouldn't be using it except if you know what you are doing.",
"field_invalid": "Invalid field '{:s}'", "field_invalid": "Invalid field '{:s}'",
"file_does_not_exist": "The file {path:s} does not exists.",
"firewall_reload_failed": "Unable to reload the firewall", "firewall_reload_failed": "Unable to reload the firewall",
"firewall_reloaded": "The firewall has been reloaded", "firewall_reloaded": "The firewall has been reloaded",
"firewall_rules_cmd_failed": "Some firewall rules commands have failed. For more information, see the log.", "firewall_rules_cmd_failed": "Some firewall rules commands have failed. For more information, see the log.",
@ -215,13 +219,12 @@
"invalid_url_format": "Invalid URL format", "invalid_url_format": "Invalid URL format",
"ip6tables_unavailable": "You cannot play with ip6tables here. You are either in a container or your kernel does not support it", "ip6tables_unavailable": "You cannot play with ip6tables here. You are either in a container or your kernel does not support it",
"iptables_unavailable": "You cannot play with iptables here. You are either in a container or your kernel does not support it", "iptables_unavailable": "You cannot play with iptables here. You are either in a container or your kernel does not support it",
"log_corrupted_md_file": "The yaml metadata file associated with logs is corrupted : '{md_file}'", "log_corrupted_md_file": "The yaml metadata file associated with logs is corrupted: '{md_file}'",
"log_category_404": "The log category '{category}' does not exist", "log_category_404": "The log category '{category}' does not exist",
"log_link_to_log": "Full log of this operation: '<a href=\"#/tools/logs/{name}\" style=\"text-decoration:underline\">{desc}</a>'", "log_link_to_log": "Full log of this operation: '<a href=\"#/tools/logs/{name}\" style=\"text-decoration:underline\">{desc}</a>'",
"log_help_to_get_log": "To view the log of the operation '{desc}', use the command 'yunohost log display {name}'", "log_help_to_get_log": "To view the log of the operation '{desc}', use the command 'yunohost log display {name}'",
"log_link_to_failed_log": "The operation '{desc}' has failed ! To get help, please <a href=\"#/tools/logs/{name}\">provide the full log of this operation by clicking here</a>", "log_link_to_failed_log": "The operation '{desc}' has failed! To get help, please <a href=\"#/tools/logs/{name}\">provide the full log of this operation by clicking here</a>",
"log_help_to_get_failed_log": "The operation '{desc}' has failed ! To get help, please share the full log of this operation using the command 'yunohost log display {name} --share'", "log_help_to_get_failed_log": "The operation '{desc}' has failed! To get help, please share the full log of this operation using the command 'yunohost log display {name} --share'",
"log_category_404": "The log category '{category}' does not exist",
"log_does_exists": "There is not operation log with the name '{log}', use 'yunohost log list to see all available operation logs'", "log_does_exists": "There is not operation log with the name '{log}', use 'yunohost log list to see all available operation logs'",
"log_operation_unit_unclosed_properly": "Operation unit has not been closed properly", "log_operation_unit_unclosed_properly": "Operation unit has not been closed properly",
"log_app_addaccess": "Add access to '{}'", "log_app_addaccess": "Add access to '{}'",
@ -271,11 +274,11 @@
"migrate_tsig_end": "Migration to hmac-sha512 finished", "migrate_tsig_end": "Migration to hmac-sha512 finished",
"migrate_tsig_failed": "Migrating the dyndns domain {domain} to hmac-sha512 failed, rolling back. Error: {error_code} - {error}", "migrate_tsig_failed": "Migrating the dyndns domain {domain} to hmac-sha512 failed, rolling back. Error: {error_code} - {error}",
"migrate_tsig_start": "Not secure enough key algorithm detected for TSIG signature of domain '{domain}', initiating migration to the more secure one hmac-sha512", "migrate_tsig_start": "Not secure enough key algorithm detected for TSIG signature of domain '{domain}', initiating migration to the more secure one hmac-sha512",
"migrate_tsig_wait": "Let's wait 3min for the dyndns server to take the new key into account...", "migrate_tsig_wait": "Let's wait 3min for the dyndns server to take the new key into account",
"migrate_tsig_wait_2": "2min...", "migrate_tsig_wait_2": "2min",
"migrate_tsig_wait_3": "1min...", "migrate_tsig_wait_3": "1min",
"migrate_tsig_wait_4": "30 secondes...", "migrate_tsig_wait_4": "30 secondes",
"migrate_tsig_not_needed": "You do not appear to use a dyndns domain, so no migration is needed !", "migrate_tsig_not_needed": "You do not appear to use a dyndns domain, so no migration is needed!",
"migration_description_0001_change_cert_group_to_sslcert": "Change certificates group permissions from 'metronome' to 'ssl-cert'", "migration_description_0001_change_cert_group_to_sslcert": "Change certificates group permissions from 'metronome' to 'ssl-cert'",
"migration_description_0002_migrate_to_tsig_sha256": "Improve security of dyndns TSIG by using SHA512 instead of MD5", "migration_description_0002_migrate_to_tsig_sha256": "Improve security of dyndns TSIG by using SHA512 instead of MD5",
"migration_description_0003_migrate_to_stretch": "Upgrade the system to Debian Stretch and YunoHost 3.0", "migration_description_0003_migrate_to_stretch": "Upgrade the system to Debian Stretch and YunoHost 3.0",
@ -286,29 +289,29 @@
"migration_description_0008_ssh_conf_managed_by_yunohost_step2": "Let the SSH configuration be managed by YunoHost (step 2, manual)", "migration_description_0008_ssh_conf_managed_by_yunohost_step2": "Let the SSH configuration be managed by YunoHost (step 2, manual)",
"migration_0003_backward_impossible": "The stretch migration cannot be reverted.", "migration_0003_backward_impossible": "The stretch migration cannot be reverted.",
"migration_0003_start": "Starting migration to Stretch. The logs will be available in {logfile}.", "migration_0003_start": "Starting migration to Stretch. The logs will be available in {logfile}.",
"migration_0003_patching_sources_list": "Patching the sources.lists ...", "migration_0003_patching_sources_list": "Patching the sources.lists",
"migration_0003_main_upgrade": "Starting main upgrade ...", "migration_0003_main_upgrade": "Starting main upgrade",
"migration_0003_fail2ban_upgrade": "Starting the fail2ban upgrade ...", "migration_0003_fail2ban_upgrade": "Starting the fail2ban upgrade",
"migration_0003_restoring_origin_nginx_conf": "Your file /etc/nginx/nginx.conf was edited somehow. The migration is going to reset back to its original state first... The previous file will be available as {backup_dest}.", "migration_0003_restoring_origin_nginx_conf": "Your file /etc/nginx/nginx.conf was edited somehow. The migration is going to reset back to its original state first The previous file will be available as {backup_dest}.",
"migration_0003_yunohost_upgrade": "Starting the yunohost package upgrade ... The migration will end, but the actual upgrade will happen right after. After the operation is complete, you might have to re-log on the webadmin.", "migration_0003_yunohost_upgrade": "Starting the yunohost package upgrade The migration will end, but the actual upgrade will happen right after. After the operation is complete, you might have to re-log on the webadmin.",
"migration_0003_not_jessie": "The current debian distribution is not Jessie !", "migration_0003_not_jessie": "The current debian distribution is not Jessie!",
"migration_0003_system_not_fully_up_to_date": "Your system is not fully up to date. Please perform a regular upgrade before running the migration to stretch.", "migration_0003_system_not_fully_up_to_date": "Your system is not fully up to date. Please perform a regular upgrade before running the migration to stretch.",
"migration_0003_still_on_jessie_after_main_upgrade": "Something wrong happened during the main upgrade : system is still on Jessie !? To investigate the issue, please look at {log} :s ...", "migration_0003_still_on_jessie_after_main_upgrade": "Something wrong happened during the main upgrade: system is still on Jessie!? To investigate the issue, please look at {log}:s…",
"migration_0003_general_warning": "Please note that this migration is a delicate operation. While the YunoHost team did its best to review and test it, the migration might still break parts of the system or apps.\n\nTherefore, we recommend you to :\n - Perform a backup of any critical data or app. More infos on https://yunohost.org/backup ;\n - Be patient after launching the migration : depending on your internet connection and hardware, it might take up to a few hours for everything to upgrade.\n\nAdditionally, the port for SMTP, used by external email clients (like Thunderbird or K9-Mail) was changed from 465 (SSL/TLS) to 587 (STARTTLS). The old port 465 will automatically be closed and the new port 587 will be opened in the firewall. You and your users *will* have to adapt the configuration of your email clients accordingly!", "migration_0003_general_warning": "Please note that this migration is a delicate operation. While the YunoHost team did its best to review and test it, the migration might still break parts of the system or apps.\n\nTherefore, we recommend you to:\n - Perform a backup of any critical data or app. More infos on https://yunohost.org/backup;\n - Be patient after launching the migration: depending on your internet connection and hardware, it might take up to a few hours for everything to upgrade.\n\nAdditionally, the port for SMTP, used by external email clients (like Thunderbird or K9-Mail) was changed from 465 (SSL/TLS) to 587 (STARTTLS). The old port 465 will automatically be closed and the new port 587 will be opened in the firewall. You and your users *will* have to adapt the configuration of your email clients accordingly!",
"migration_0003_problematic_apps_warning": "Please note that the following possibly problematic installed apps were detected. It looks like those were not installed from an applist or are not flagged as 'working'. Consequently, we cannot guarantee that they will still work after the upgrade : {problematic_apps}", "migration_0003_problematic_apps_warning": "Please note that the following possibly problematic installed apps were detected. It looks like those were not installed from an applist or are not flagged as 'working'. Consequently, we cannot guarantee that they will still work after the upgrade: {problematic_apps}",
"migration_0003_modified_files": "Please note that the following files were found to be manually modified and might be overwritten at the end of the upgrade : {manually_modified_files}", "migration_0003_modified_files": "Please note that the following files were found to be manually modified and might be overwritten at the end of the upgrade: {manually_modified_files}",
"migration_0005_postgresql_94_not_installed": "Postgresql was not installed on your system. Nothing to do!", "migration_0005_postgresql_94_not_installed": "Postgresql was not installed on your system. Nothing to do!",
"migration_0005_postgresql_96_not_installed": "Postgresql 9.4 has been found to be installed, but not postgresql 9.6 !? Something weird might have happened on your system :( ...", "migration_0005_postgresql_96_not_installed": "Postgresql 9.4 has been found to be installed, but not postgresql 9.6!? Something weird might have happened on your system:(…",
"migration_0005_not_enough_space": "Not enough space is available in {path} to run the migration right now :(.", "migration_0005_not_enough_space": "Not enough space is available in {path} to run the migration right now:(.",
"migration_0006_disclaimer": "Yunohost now expects admin and root passwords to be synchronized. By running this migration, your root password is going to be replaced by the admin password.", "migration_0006_disclaimer": "Yunohost now expects admin and root passwords to be synchronized. By running this migration, your root password is going to be replaced by the admin password.",
"migration_0007_cancelled": "YunoHost has failed to improve the way your SSH conf is managed.", "migration_0007_cancelled": "YunoHost has failed to improve the way your SSH conf is managed.",
"migration_0007_cannot_restart": "SSH can't be restarted after trying to cancel migration number 6.", "migration_0007_cannot_restart": "SSH can't be restarted after trying to cancel migration number 6.",
"migration_0008_general_disclaimer": "To improve the security of your server, it is recommended to let YunoHost manage the SSH configuration. Your current SSH configuration differs from the recommended configuration. If you let YunoHost reconfigure it, the way you connect to your server through SSH will change in the following way:", "migration_0008_general_disclaimer": "To improve the security of your server, it is recommended to let YunoHost manage the SSH configuration. Your current SSH configuration differs from the recommended configuration. If you let YunoHost reconfigure it, the way you connect to your server through SSH will change in the following way:",
"migration_0008_port": " - you will have to connect using port 22 instead of your current custom SSH port. Feel free to reconfigure it ;", "migration_0008_port": " - you will have to connect using port 22 instead of your current custom SSH port. Feel free to reconfigure it;",
"migration_0008_root": " - you will not be able to connect as root through SSH. Instead you should use the admin user ;", "migration_0008_root": " - you will not be able to connect as root through SSH. Instead you should use the admin user;",
"migration_0008_dsa": " - the DSA key will be disabled. Hence, you might need to invalidate a spooky warning from your SSH client, and recheck the fingerprint of your server ;", "migration_0008_dsa": " - the DSA key will be disabled. Hence, you might need to invalidate a spooky warning from your SSH client, and recheck the fingerprint of your server;",
"migration_0008_warning": "If you understand those warnings and agree to let YunoHost override your current configuration, run the migration. Otherwise, you can also skip the migration - though it is not recommended.", "migration_0008_warning": "If you understand those warnings and agree to let YunoHost override your current configuration, run the migration. Otherwise, you can also skip the migration - though it is not recommended.",
"migration_0008_no_warning": "No major risk has been indentified about overriding your SSH configuration - but we can't be absolutely sure ;) ! If you agree to let YunoHost override your current configuration, run the migration. Otherwise, you can also skip the migration - though it is not recommended.", "migration_0008_no_warning": "No major risk has been indentified about overriding your SSH configuration - but we can't be absolutely sure ;)! If you agree to let YunoHost override your current configuration, run the migration. Otherwise, you can also skip the migration - though it is not recommended.",
"migrations_backward": "Migrating backward.", "migrations_backward": "Migrating backward.",
"migrations_bad_value_for_target": "Invalid number for target argument, available migrations numbers are 0 or {}", "migrations_bad_value_for_target": "Invalid number for target argument, available migrations numbers are 0 or {}",
"migrations_cant_reach_migration_file": "Can't access migrations files at path %s", "migrations_cant_reach_migration_file": "Can't access migrations files at path %s",
@ -316,12 +319,12 @@
"migrations_error_failed_to_load_migration": "ERROR: failed to load migration {number} {name}", "migrations_error_failed_to_load_migration": "ERROR: failed to load migration {number} {name}",
"migrations_forward": "Migrating forward", "migrations_forward": "Migrating forward",
"migrations_list_conflict_pending_done": "You cannot use both --previous and --done at the same time.", "migrations_list_conflict_pending_done": "You cannot use both --previous and --done at the same time.",
"migrations_loading_migration": "Loading migration {number} {name}...", "migrations_loading_migration": "Loading migration {number} {name}",
"migrations_migration_has_failed": "Migration {number} {name} has failed with exception {exception}, aborting", "migrations_migration_has_failed": "Migration {number} {name} has failed with exception {exception}, aborting",
"migrations_no_migrations_to_run": "No migrations to run", "migrations_no_migrations_to_run": "No migrations to run",
"migrations_show_currently_running_migration": "Running migration {number} {name}...", "migrations_show_currently_running_migration": "Running migration {number} {name}",
"migrations_show_last_migration": "Last ran migration is {}", "migrations_show_last_migration": "Last ran migration is {}",
"migrations_skip_migration": "Skipping migration {number} {name}...", "migrations_skip_migration": "Skipping migration {number} {name}",
"migrations_success": "Successfully ran migration {number} {name}!", "migrations_success": "Successfully ran migration {number} {name}!",
"migrations_to_be_ran_manually": "Migration {number} {name} has to be ran manually. Please go to Tools > Migrations on the webadmin, or run `yunohost tools migrations migrate`.", "migrations_to_be_ran_manually": "Migration {number} {name} has to be ran manually. Please go to Tools > Migrations on the webadmin, or run `yunohost tools migrations migrate`.",
"migrations_need_to_accept_disclaimer": "To run the migration {number} {name}, your must accept the following disclaimer:\n---\n{disclaimer}\n---\nIf you accept to run the migration, please re-run the command with the option --accept-disclaimer.", "migrations_need_to_accept_disclaimer": "To run the migration {number} {name}, your must accept the following disclaimer:\n---\n{disclaimer}\n---\nIf you accept to run the migration, please re-run the command with the option --accept-disclaimer.",
@ -381,7 +384,7 @@
"restore_cleaning_failed": "Unable to clean-up the temporary restoration directory", "restore_cleaning_failed": "Unable to clean-up the temporary restoration directory",
"restore_complete": "Restore complete", "restore_complete": "Restore complete",
"restore_confirm_yunohost_installed": "Do you really want to restore an already installed system? [{answers:s}]", "restore_confirm_yunohost_installed": "Do you really want to restore an already installed system? [{answers:s}]",
"restore_extracting": "Extracting needed files from the archive...", "restore_extracting": "Extracting needed files from the archive",
"restore_failed": "Unable to restore the system", "restore_failed": "Unable to restore the system",
"restore_hook_unavailable": "Restoration script for '{part:s}' not available on your system and not in the archive either", "restore_hook_unavailable": "Restoration script for '{part:s}' not available on your system and not in the archive either",
"restore_may_be_not_enough_disk_space": "Your system seems not to have enough disk space (freespace: {free_space:d} B, needed space: {needed_space:d} B, security margin: {margin:d} B)", "restore_may_be_not_enough_disk_space": "Your system seems not to have enough disk space (freespace: {free_space:d} B, needed space: {needed_space:d} B, security margin: {margin:d} B)",
@ -389,10 +392,10 @@
"restore_not_enough_disk_space": "Not enough disk space (freespace: {free_space:d} B, needed space: {needed_space:d} B, security margin: {margin:d} B)", "restore_not_enough_disk_space": "Not enough disk space (freespace: {free_space:d} B, needed space: {needed_space:d} B, security margin: {margin:d} B)",
"restore_nothings_done": "Nothing has been restored", "restore_nothings_done": "Nothing has been restored",
"restore_removing_tmp_dir_failed": "Unable to remove an old temporary directory", "restore_removing_tmp_dir_failed": "Unable to remove an old temporary directory",
"restore_running_app_script": "Running restore script of app '{app:s}'...", "restore_running_app_script": "Running restore script of app '{app:s}'",
"restore_running_hooks": "Running restoration hooks...", "restore_running_hooks": "Running restoration hooks",
"restore_system_part_failed": "Unable to restore the '{part:s}' system part", "restore_system_part_failed": "Unable to restore the '{part:s}' system part",
"root_password_desynchronized": "The admin password has been changed, but YunoHost was unable to propagate this on the root password !", "root_password_desynchronized": "The admin password has been changed, but YunoHost was unable to propagate this on the root password!",
"root_password_replaced_by_admin_password": "Your root password have been replaced by your admin password.", "root_password_replaced_by_admin_password": "Your root password have been replaced by your admin password.",
"server_shutdown": "The server will shutdown", "server_shutdown": "The server will shutdown",
"server_shutdown_confirm": "The server will shutdown immediatly, are you sure? [{answers:s}]", "server_shutdown_confirm": "The server will shutdown immediatly, are you sure? [{answers:s}]",
@ -438,11 +441,17 @@
"service_enable_failed": "Unable to enable service '{service:s}'\n\nRecent service logs:{logs:s}", "service_enable_failed": "Unable to enable service '{service:s}'\n\nRecent service logs:{logs:s}",
"service_enabled": "The service '{service:s}' has been enabled", "service_enabled": "The service '{service:s}' has been enabled",
"service_no_log": "No log to display for service '{service:s}'", "service_no_log": "No log to display for service '{service:s}'",
"service_regenconf_dry_pending_applying": "Checking pending configuration which would have been applied for service '{service}'...", "service_regenconf_dry_pending_applying": "Checking pending configuration which would have been applied for service '{service}'",
"service_regenconf_failed": "Unable to regenerate the configuration for service(s): {services}", "service_regenconf_failed": "Unable to regenerate the configuration for service(s): {services}",
"service_regenconf_pending_applying": "Applying pending configuration for service '{service}'...", "service_regenconf_pending_applying": "Applying pending configuration for service '{service}'",
"service_remove_failed": "Unable to remove service '{service:s}'", "service_remove_failed": "Unable to remove service '{service:s}'",
"service_removed": "The service '{service:s}' has been removed", "service_removed": "The service '{service:s}' has been removed",
"service_reload_failed": "Unable to reload service '{service:s}'\n\nRecent service logs:{logs:s}",
"service_reloaded": "The service '{service:s}' has been reloaded",
"service_restart_failed": "Unable to restart service '{service:s}'\n\nRecent service logs:{logs:s}",
"service_restarted": "The service '{service:s}' has been restarted",
"service_reload_or_restart_failed": "Unable to reload or restart service '{service:s}'\n\nRecent service logs:{logs:s}",
"service_reloaded_or_restarted": "The service '{service:s}' has been reloaded or restarted",
"service_start_failed": "Unable to start service '{service:s}'\n\nRecent service logs:{logs:s}", "service_start_failed": "Unable to start service '{service:s}'\n\nRecent service logs:{logs:s}",
"service_started": "The service '{service:s}' has been started", "service_started": "The service '{service:s}' has been started",
"service_status_failed": "Unable to determine status of service '{service:s}'", "service_status_failed": "Unable to determine status of service '{service:s}'",
@ -456,14 +465,14 @@
"system_upgraded": "The system has been upgraded", "system_upgraded": "The system has been upgraded",
"system_username_exists": "Username already exists in the system users", "system_username_exists": "Username already exists in the system users",
"unbackup_app": "App '{app:s}' will not be saved", "unbackup_app": "App '{app:s}' will not be saved",
"unexpected_error": "An unexpected error occured", "unexpected_error": "An unexpected error occured: {error}",
"unit_unknown": "Unknown unit '{unit:s}'", "unit_unknown": "Unknown unit '{unit:s}'",
"unlimit": "No quota", "unlimit": "No quota",
"unrestore_app": "App '{app:s}' will not be restored", "unrestore_app": "App '{app:s}' will not be restored",
"update_cache_failed": "Unable to update APT cache", "update_cache_failed": "Unable to update APT cache",
"updating_apt_cache": "Updating the list of available packages...", "updating_apt_cache": "Fetching available upgrades for system packages…",
"upgrade_complete": "Upgrade complete", "upgrade_complete": "Upgrade complete",
"upgrading_packages": "Upgrading packages...", "upgrading_packages": "Upgrading packages",
"upnp_dev_not_found": "No UPnP device found", "upnp_dev_not_found": "No UPnP device found",
"upnp_disabled": "UPnP has been disabled", "upnp_disabled": "UPnP has been disabled",
"upnp_enabled": "UPnP has been enabled", "upnp_enabled": "UPnP has been enabled",
@ -482,6 +491,6 @@
"yunohost_ca_creation_failed": "Unable to create certificate authority", "yunohost_ca_creation_failed": "Unable to create certificate authority",
"yunohost_ca_creation_success": "The local certification authority has been created.", "yunohost_ca_creation_success": "The local certification authority has been created.",
"yunohost_configured": "YunoHost has been configured", "yunohost_configured": "YunoHost has been configured",
"yunohost_installing": "Installing YunoHost...", "yunohost_installing": "Installing YunoHost",
"yunohost_not_installed": "YunoHost is not or not correctly installed. Please execute 'yunohost tools postinstall'" "yunohost_not_installed": "YunoHost is not or not correctly installed. Please execute 'yunohost tools postinstall'"
} }

View file

@ -1 +1,36 @@
{} {
"admin_password_change_failed": "Malebla ŝanĝi pasvorton",
"admin_password_changed": "Pasvorto de la estro estas ŝanĝita",
"app_already_installed": "{app:s} estas jam instalita",
"app_already_up_to_date": "{app:s} estas ĝisdata",
"app_argument_required": "Parametro {name:s} estas bezonata",
"app_change_url_identical_domains": "Malnovaj kaj novaj domajno/URL estas la sama ('{domain:s}{path:s}'), nenio fareblas.",
"app_change_url_success": "URL de appo {app:s} ŝanĝita al {domain:s}{path:s}",
"app_extraction_failed": "Malebla malkompaktigi instaldosierojn",
"app_id_invalid": "Nevalida apo id",
"app_incompatible": "Apo {app} ne estas kongrua kun via YunoHost versio",
"app_install_files_invalid": "Nevalidaj instaldosieroj",
"app_location_already_used": "Apo {app} jam estas instalita al tiu loco ({path})",
"user_updated": "Uzanto estas ĝisdatita",
"users_available": "Uzantoj disponeblaj :",
"yunohost_already_installed": "YunoHost estas jam instalita",
"yunohost_ca_creation_failed": "Ne eblas krei atestan aŭtoritaton",
"yunohost_ca_creation_success": "Loka atesta aŭtoritato estas kreita.",
"yunohost_installing": "Instalata YunoHost...",
"service_description_glances": "monitoras sisteminformojn de via servilo",
"service_description_metronome": "mastrumas XMPP tujmesaĝilon kontojn",
"service_description_mysql": "stokas aplikaĵojn datojn (SQL datumbazo)",
"service_description_nginx": "servas aŭ permesas atingi ĉiujn retejojn gastigita sur via servilo",
"service_description_nslcd": "mastrumas Yunohost uzantojn konektojn per komanda linio",
"service_description_php7.0-fpm": "rulas aplikaĵojn skibita en PHP kun nginx",
"service_description_postfix": "uzita por sendi kaj ricevi retpoŝtojn",
"service_description_redis-server": "specialita datumbazo uzita por rapida datumo atingo, atendovicoj kaj komunikadoj inter programoj",
"service_description_rmilter": "kontrolas diversajn parametrojn en retpoŝtoj",
"service_description_rspamd": "filtras trudmesaĝojn, kaj aliaj funkcioj rilate al retpoŝto",
"service_description_slapd": "stokas uzantojn, domajnojn kaj rilatajn informojn",
"service_description_ssh": "permesas al vi konekti al via servilo kun fora terminalo (SSH protokolo)",
"service_description_yunohost-api": "mastrumas interagojn inter la YunoHost retinterfaco kaj la sistemo",
"service_description_yunohost-firewall": "mastrumas malfermitajn kaj fermitajn konektejojn al servoj",
"service_disable_failed": "Neebla malaktivigi servon '{service:s}'\n\nFreŝaj protokoloj de la servo : {logs:s}",
"service_disabled": "Servo '{service:s}' estas malaktivigita"
}

View file

@ -97,7 +97,7 @@
"dyndns_no_domain_registered": "Ningún dominio ha sido registrado con DynDNS", "dyndns_no_domain_registered": "Ningún dominio ha sido registrado con DynDNS",
"dyndns_registered": "El dominio DynDNS ha sido registrado", "dyndns_registered": "El dominio DynDNS ha sido registrado",
"dyndns_registration_failed": "No se pudo registrar el dominio DynDNS: {error:s}", "dyndns_registration_failed": "No se pudo registrar el dominio DynDNS: {error:s}",
"dyndns_unavailable": "El subdominio DynDNS no está disponible", "dyndns_unavailable": "El dominio {domain:s} no está disponible.",
"executing_command": "Ejecutando el comando '{command:s}'...", "executing_command": "Ejecutando el comando '{command:s}'...",
"executing_script": "Ejecutando el script '{script:s}'...", "executing_script": "Ejecutando el script '{script:s}'...",
"extracting": "Extrayendo...", "extracting": "Extrayendo...",
@ -174,7 +174,7 @@
"restore_complete": "Restauración finalizada", "restore_complete": "Restauración finalizada",
"restore_confirm_yunohost_installed": "¿Realmente desea restaurar un sistema ya instalado? [{answers:s}]", "restore_confirm_yunohost_installed": "¿Realmente desea restaurar un sistema ya instalado? [{answers:s}]",
"restore_failed": "No se pudo restaurar el sistema", "restore_failed": "No se pudo restaurar el sistema",
"restore_hook_unavailable": "El hook de restauración '{hook:s}' no está disponible en su sistema", "restore_hook_unavailable": "El script de restauración '{part:s}' no está disponible en su sistema y tampoco en el archivo",
"restore_nothings_done": "No se ha restaurado nada", "restore_nothings_done": "No se ha restaurado nada",
"restore_running_app_script": "Ejecutando el script de restauración de la aplicación '{app:s}'...", "restore_running_app_script": "Ejecutando el script de restauración de la aplicación '{app:s}'...",
"restore_running_hooks": "Ejecutando los hooks de restauración...", "restore_running_hooks": "Ejecutando los hooks de restauración...",
@ -204,7 +204,7 @@
"service_regenconf_pending_applying": "Aplicando la configuración pendiente para el servicio '{service}'...", "service_regenconf_pending_applying": "Aplicando la configuración pendiente para el servicio '{service}'...",
"service_remove_failed": "No se pudo desinstalar el servicio '{service:s}'", "service_remove_failed": "No se pudo desinstalar el servicio '{service:s}'",
"service_removed": "El servicio '{service:s}' ha sido desinstalado", "service_removed": "El servicio '{service:s}' ha sido desinstalado",
"service_start_failed": "No se pudo iniciar el servicio '{service:s}'", "service_start_failed": "No se pudo iniciar el servicio '{service:s}'\n\nRegistros de servicio recientes : {logs:s}",
"service_started": "El servicio '{service:s}' ha sido iniciado", "service_started": "El servicio '{service:s}' ha sido iniciado",
"service_status_failed": "No se pudo determinar el estado del servicio '{service:s}'", "service_status_failed": "No se pudo determinar el estado del servicio '{service:s}'",
"service_stop_failed": "No se pudo detener el servicio '{service:s}'", "service_stop_failed": "No se pudo detener el servicio '{service:s}'",
@ -281,7 +281,7 @@
"app_change_url_identical_domains": "El antiguo y nuevo dominio/url_path son idénticos ('{domain:s} {path:s}'), no se realizarán cambios.", "app_change_url_identical_domains": "El antiguo y nuevo dominio/url_path son idénticos ('{domain:s} {path:s}'), no se realizarán cambios.",
"app_change_url_no_script": "Esta aplicación '{app_name:s}' aún no permite modificar su URL. Quizás debería actualizar la aplicación.", "app_change_url_no_script": "Esta aplicación '{app_name:s}' aún no permite modificar su URL. Quizás debería actualizar la aplicación.",
"app_change_url_success": "El URL de la aplicación {app:s} ha sido cambiado correctamente a {domain:s} {path:s}", "app_change_url_success": "El URL de la aplicación {app:s} ha sido cambiado correctamente a {domain:s} {path:s}",
"app_location_unavailable": "Este URL no está disponible o está en conflicto con otra aplicación instalada", "app_location_unavailable": "Este URL no está disponible o está en conflicto con otra aplicación instalada:\n{apps:s}",
"app_already_up_to_date": "La aplicación {app:s} ya está actualizada", "app_already_up_to_date": "La aplicación {app:s} ya está actualizada",
"appslist_name_already_tracked": "Ya existe una lista de aplicaciones registrada con el nombre {name:s}.", "appslist_name_already_tracked": "Ya existe una lista de aplicaciones registrada con el nombre {name:s}.",
"appslist_url_already_tracked": "Ya existe una lista de aplicaciones registrada con el URL {url:s}.", "appslist_url_already_tracked": "Ya existe una lista de aplicaciones registrada con el URL {url:s}.",
@ -307,5 +307,15 @@
"backup_copying_to_organize_the_archive": "Copiando {size:s}MB para organizar el archivo", "backup_copying_to_organize_the_archive": "Copiando {size:s}MB para organizar el archivo",
"backup_couldnt_bind": "No puede enlazar {src:s} con {dest:s}", "backup_couldnt_bind": "No puede enlazar {src:s} con {dest:s}",
"backup_csv_addition_failed": "No puede añadir archivos al backup en el archivo CSV", "backup_csv_addition_failed": "No puede añadir archivos al backup en el archivo CSV",
"backup_csv_creation_failed": "No se puede crear el archivo CSV necesario para futuras operaciones de restauración" "backup_csv_creation_failed": "No se puede crear el archivo CSV necesario para futuras operaciones de restauración",
"backup_custom_mount_error": "Fracaso del método de copia de seguridad personalizada en la etapa \"mount\"",
"backup_custom_need_mount_error": "Fracaso del método de copia de seguridad personalizada en la étapa \"need_mount\"",
"backup_no_uncompress_archive_dir": "El directorio del archivo descomprimido no existe",
"backup_php5_to_php7_migration_may_fail": "No se ha podido convertir su archivo para soportar php7, la restauración de sus aplicaciones php puede fallar (razón : {error:s})",
"backup_system_part_failed": "No se puede hacer una copia de seguridad de la parte \"{part:s}\" del sistema",
"backup_with_no_backup_script_for_app": "La aplicación {app:s} no tiene script de respaldo. Se ha ignorado.",
"backup_with_no_restore_script_for_app": "La aplicación {app:s} no tiene script de restauración, no podrá restaurar automáticamente la copia de seguridad de esta aplicación.",
"dyndns_could_not_check_provide": "No se pudo verificar si {provider:s} puede ofrecer {domain:s}.",
"dyndns_domain_not_provided": "El proveedor Dyndns {provider:s} no puede proporcionar el dominio {domain:s}.",
"experimental_feature": "Cuidado : esta funcionalidad es experimental y no es considerada estable, no debería usarla excepto si sabe lo que hace."
} }

1
locales/eu.json Normal file
View file

@ -0,0 +1 @@
{}

13
locales/hu.json Normal file
View file

@ -0,0 +1,13 @@
{
"aborting": "Megszakítás.",
"action_invalid": "Érvénytelen művelet '{action:s}'",
"admin_password": "Adminisztrátori jelszó",
"admin_password_change_failed": "Nem lehet a jelszót megváltoztatni",
"admin_password_changed": "Az adminisztrátori jelszó megváltozott",
"app_already_installed": "{app:s} már telepítve van",
"app_already_installed_cant_change_url": "Ez az app már telepítve van. Ezzel a funkcióval az url nem változtatható. Javaslat 'app url változtatás' ha lehetséges.",
"app_already_up_to_date": "{app:s} napra kész",
"app_argument_choice_invalid": "{name:s} érvénytelen választás, csak egyike lehet {choices:s} közül",
"app_argument_invalid": "'{name:s}' hibás paraméter érték :{error:s}",
"app_argument_required": "Parameter '{name:s}' kötelező"
}

View file

@ -275,5 +275,28 @@
"backup_applying_method_tar": "Creando l'archivio tar del backup...", "backup_applying_method_tar": "Creando l'archivio tar del backup...",
"backup_archive_mount_failed": "Montaggio dell'archivio del backup non riuscito", "backup_archive_mount_failed": "Montaggio dell'archivio del backup non riuscito",
"backup_archive_system_part_not_available": "La parte di sistema '{part:s}' non è disponibile in questo backup", "backup_archive_system_part_not_available": "La parte di sistema '{part:s}' non è disponibile in questo backup",
"backup_archive_writing_error": "Impossibile aggiungere i file al backup nell'archivio compresso" "backup_archive_writing_error": "Impossibile aggiungere i file al backup nell'archivio compresso",
"backup_ask_for_copying_if_needed": "Alcuni files non possono essere preparati al backup utilizzando il metodo che consente di evitare il consumo temporaneo di spazio nel sistema. Per eseguire il backup, {size:s}MB dovranno essere utilizzati temporaneamente. Sei d'accordo?",
"backup_borg_not_implemented": "Il metodo di backup Borg non è ancora stato implementato",
"backup_cant_mount_uncompress_archive": "Impossibile montare in modalità sola lettura la cartella di archivio non compressa",
"backup_copying_to_organize_the_archive": "Copiando {size:s}MB per organizzare l'archivio",
"backup_couldnt_bind": "Impossibile legare {src:s} a {dest:s}.",
"backup_csv_addition_failed": "Impossibile aggiungere file del backup nel file CSV",
"backup_csv_creation_failed": "Impossibile creare il file CVS richiesto per le future operazioni di ripristino",
"backup_custom_backup_error": "Il metodo di backup personalizzato è fallito allo step 'backup'",
"backup_custom_mount_error": "Il metodo di backup personalizzato è fallito allo step 'mount'",
"backup_custom_need_mount_error": "Il metodo di backup personalizzato è fallito allo step 'need_mount'",
"backup_method_borg_finished": "Backup in borg terminato",
"backup_method_copy_finished": "Copia di backup terminata",
"backup_method_custom_finished": "Metodo di backup personalizzato '{method:s}' terminato",
"backup_method_tar_finished": "Archivio tar di backup creato",
"backup_no_uncompress_archive_dir": "La cartella di archivio non compressa non esiste",
"backup_php5_to_php7_migration_may_fail": "Conversione del tuo archivio per supportare php7 non riuscita, le tue app php potrebbero fallire in fase di ripristino (motivo: {error:s})",
"backup_system_part_failed": "Impossibile creare il backup della parte di sistema '{part:s}'",
"backup_unable_to_organize_files": "Impossibile organizzare i file nell'archivio con il metodo veloce",
"backup_with_no_backup_script_for_app": "L'app {app:s} non ha script di backup. Ignorata.",
"backup_with_no_restore_script_for_app": "L'app {app:s} non ha script di ripristino, non sarai in grado di ripristinarla automaticamente dal backup di questa app.",
"certmanager_acme_not_configured_for_domain": "Il certificato per il dominio {domain:s} non sembra essere correttamente installato. Per favore esegui cert-install per questo dominio prima.",
"certmanager_cannot_read_cert": "Qualcosa è andato storto nel tentativo di aprire il certificato attuale per il dominio {domain:s} (file: {file:s}), motivo: {reason:s}",
"certmanager_cert_install_success": "Certificato Let's Encrypt per il dominio {domain:s} installato con successo!"
} }

View file

@ -445,6 +445,7 @@ def app_change_url(operation_logger, auth, app, domain, path):
""" """
from yunohost.hook import hook_exec, hook_callback from yunohost.hook import hook_exec, hook_callback
from yunohost.domain import _normalize_domain_path, _get_conflicting_apps
installed = _is_installed(app) installed = _is_installed(app)
if not installed: if not installed:
@ -457,18 +458,24 @@ def app_change_url(operation_logger, auth, app, domain, path):
old_path = app_setting(app, "path") old_path = app_setting(app, "path")
# Normalize path and domain format # Normalize path and domain format
domain = domain.strip().lower() old_domain, old_path = _normalize_domain_path(old_domain, old_path)
domain, path = _normalize_domain_path(domain, path)
old_path = normalize_url_path(old_path)
path = normalize_url_path(path)
if (domain, path) == (old_domain, old_path): if (domain, path) == (old_domain, old_path):
raise YunohostError("app_change_url_identical_domains", domain=domain, path=path) raise YunohostError("app_change_url_identical_domains", domain=domain, path=path)
# WARNING / FIXME : checkurl will modify the settings # Check the url is available
# (this is a non intuitive behavior that should be changed) conflicts = _get_conflicting_apps(auth, domain, path, ignore_app=app)
# (or checkurl renamed in reserve_url) if conflicts:
app_checkurl(auth, '%s%s' % (domain, path), app) apps = []
for path, app_id, app_label in conflicts:
apps.append(" * {domain:s}{path:s}{app_label:s} ({app_id:s})".format(
domain=domain,
path=path,
app_id=app_id,
app_label=app_label,
))
raise YunohostError('app_location_unavailable', apps="\n".join(apps))
manifest = json.load(open(os.path.join(APPS_SETTING_PATH, app, "manifest.json"))) manifest = json.load(open(os.path.join(APPS_SETTING_PATH, app, "manifest.json")))
@ -486,9 +493,9 @@ def app_change_url(operation_logger, auth, app, domain, path):
env_dict["YNH_APP_INSTANCE_NUMBER"] = str(app_instance_nb) env_dict["YNH_APP_INSTANCE_NUMBER"] = str(app_instance_nb)
env_dict["YNH_APP_OLD_DOMAIN"] = old_domain env_dict["YNH_APP_OLD_DOMAIN"] = old_domain
env_dict["YNH_APP_OLD_PATH"] = old_path.rstrip("/") env_dict["YNH_APP_OLD_PATH"] = old_path
env_dict["YNH_APP_NEW_DOMAIN"] = domain env_dict["YNH_APP_NEW_DOMAIN"] = domain
env_dict["YNH_APP_NEW_PATH"] = path.rstrip("/") env_dict["YNH_APP_NEW_PATH"] = path
if domain != old_domain: if domain != old_domain:
operation_logger.related_to.append(('domain', old_domain)) operation_logger.related_to.append(('domain', old_domain))
@ -725,10 +732,10 @@ def app_install(operation_logger, auth, app, label=None, args=None, no_remove_on
answer = msignals.prompt(m18n.n('confirm_app_install_' + confirm, answer = msignals.prompt(m18n.n('confirm_app_install_' + confirm,
answers='Y/N')) answers='Y/N'))
if answer.upper() != "Y": if answer.upper() != "Y":
raise MoulinetteError(errno.EINVAL, m18n.n("aborting")) raise YunohostError("aborting")
raw_app_list = app_list(raw=True) raw_app_list = app_list(raw=True)
if app in raw_app_list or ('@' in app) or ('http://' in app) or ('https://' in app): if app in raw_app_list or ('@' in app) or ('http://' in app) or ('https://' in app):
if app in raw_app_list: if app in raw_app_list:
state = raw_app_list[app].get("state", "notworking") state = raw_app_list[app].get("state", "notworking")
@ -830,11 +837,12 @@ def app_install(operation_logger, auth, app, label=None, args=None, no_remove_on
)[0] )[0]
except (KeyboardInterrupt, EOFError): except (KeyboardInterrupt, EOFError):
install_retcode = -1 install_retcode = -1
except: except Exception:
logger.exception(m18n.n('unexpected_error')) import traceback
logger.exception(m18n.n('unexpected_error', error=u"\n" + traceback.format_exc()))
finally: finally:
if install_retcode != 0: if install_retcode != 0:
error_msg = operation_logger.error(m18n.n('unexpected_error')) error_msg = operation_logger.error(m18n.n('unexpected_error', error='shell command return code: %s' % install_retcode))
if not no_remove_on_failure: if not no_remove_on_failure:
# Setup environment for remove script # Setup environment for remove script
env_dict_remove = {} env_dict_remove = {}
@ -1165,7 +1173,7 @@ def app_makedefault(operation_logger, auth, app, domain=None):
with open('/etc/ssowat/conf.json.persistent') as json_conf: with open('/etc/ssowat/conf.json.persistent') as json_conf:
ssowat_conf = json.loads(str(json_conf.read())) ssowat_conf = json.loads(str(json_conf.read()))
except ValueError as e: except ValueError as e:
raise YunohostError('ssowat_persistent_conf_read_error', error=e.strerror) raise YunohostError('ssowat_persistent_conf_read_error', error=e)
except IOError: except IOError:
ssowat_conf = {} ssowat_conf = {}
@ -1178,7 +1186,7 @@ def app_makedefault(operation_logger, auth, app, domain=None):
with open('/etc/ssowat/conf.json.persistent', 'w+') as f: with open('/etc/ssowat/conf.json.persistent', 'w+') as f:
json.dump(ssowat_conf, f, sort_keys=True, indent=4) json.dump(ssowat_conf, f, sort_keys=True, indent=4)
except IOError as e: except IOError as e:
raise YunohostError('ssowat_persistent_conf_write_error', error=e.strerror) raise YunohostError('ssowat_persistent_conf_write_error', error=e)
os.system('chmod 644 /etc/ssowat/conf.json.persistent') os.system('chmod 644 /etc/ssowat/conf.json.persistent')
@ -1201,8 +1209,8 @@ def app_setting(app, key, value=None, delete=False):
if value is None and not delete: if value is None and not delete:
try: try:
return app_settings[key] return app_settings[key]
except: except Exception as e:
logger.debug("cannot get app setting '%s' for '%s'", key, app) logger.debug("cannot get app setting '%s' for '%s' (%s)", key, app, e)
return None return None
else: else:
if delete and key in app_settings: if delete and key in app_settings:
@ -1251,7 +1259,6 @@ def app_register_url(auth, app, domain, path):
# We cannot change the url of an app already installed simply by changing # We cannot change the url of an app already installed simply by changing
# the settings... # the settings...
# FIXME should look into change_url once it's merged
installed = app in app_list(installed=True, raw=True).keys() installed = app in app_list(installed=True, raw=True).keys()
if installed: if installed:
@ -1289,7 +1296,7 @@ def app_checkurl(auth, url, app=None):
logger.error("Packagers /!\\ : 'app checkurl' is deprecated ! Please use the helper 'ynh_webpath_register' instead !") logger.error("Packagers /!\\ : 'app checkurl' is deprecated ! Please use the helper 'ynh_webpath_register' instead !")
from yunohost.domain import domain_list from yunohost.domain import domain_list, _normalize_domain_path
if "https://" == url[:8]: if "https://" == url[:8]:
url = url[8:] url = url[8:]
@ -1303,8 +1310,7 @@ def app_checkurl(auth, url, app=None):
path = url[url.index('/'):] path = url[url.index('/'):]
installed = False installed = False
if path[-1:] != '/': domain, path = _normalize_domain_path(domain, path)
path = path + '/'
apps_map = app_map(raw=True) apps_map = app_map(raw=True)
@ -1388,7 +1394,8 @@ def app_ssowatconf(auth):
try: try:
apps_list = app_list(installed=True)['apps'] apps_list = app_list(installed=True)['apps']
except: except Exception as e:
logger.debug("cannot get installed app list because %s", e)
apps_list = [] apps_list = []
def _get_setting(settings, name): def _get_setting(settings, name):
@ -1818,7 +1825,7 @@ def _extract_app_from_file(path, remove=False):
except IOError: except IOError:
raise YunohostError('app_install_files_invalid') raise YunohostError('app_install_files_invalid')
except ValueError as e: except ValueError as e:
raise YunohostError('app_manifest_invalid', error=e.strerror) raise YunohostError('app_manifest_invalid', error=e)
logger.debug(m18n.n('done')) logger.debug(m18n.n('done'))
@ -1901,7 +1908,7 @@ def _fetch_app_from_git(app):
# we will be able to use it. Without this option all the history # we will be able to use it. Without this option all the history
# of the submodules repo is downloaded. # of the submodules repo is downloaded.
subprocess.check_call([ subprocess.check_call([
'git', 'clone', '--depth=1', '--recursive', url, 'git', 'clone', '-b', branch, '--single-branch', '--recursive', '--depth=1', url,
extracted_app_folder]) extracted_app_folder])
subprocess.check_call([ subprocess.check_call([
'git', 'reset', '--hard', branch 'git', 'reset', '--hard', branch
@ -1911,7 +1918,7 @@ def _fetch_app_from_git(app):
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
raise YunohostError('app_sources_fetch_failed') raise YunohostError('app_sources_fetch_failed')
except ValueError as e: except ValueError as e:
raise YunohostError('app_manifest_invalid', error=e.strerror) raise YunohostError('app_manifest_invalid', error=e)
else: else:
logger.debug(m18n.n('done')) logger.debug(m18n.n('done'))
@ -1919,8 +1926,8 @@ def _fetch_app_from_git(app):
manifest['remote'] = {'type': 'git', 'url': url, 'branch': branch} manifest['remote'] = {'type': 'git', 'url': url, 'branch': branch}
try: try:
revision = _get_git_last_commit_hash(url, branch) revision = _get_git_last_commit_hash(url, branch)
except: except Exception as e:
pass logger.debug("cannot get last commit hash because: %s ", e)
else: else:
manifest['remote']['revision'] = revision manifest['remote']['revision'] = revision
else: else:
@ -1964,7 +1971,7 @@ def _fetch_app_from_git(app):
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
raise YunohostError('app_sources_fetch_failed') raise YunohostError('app_sources_fetch_failed')
except ValueError as e: except ValueError as e:
raise YunohostError('app_manifest_invalid', error=e.strerror) raise YunohostError('app_manifest_invalid', error=e)
else: else:
logger.debug(m18n.n('done')) logger.debug(m18n.n('done'))
@ -2244,7 +2251,7 @@ def _parse_action_args_in_yunohost_format(args, action_args, auth=None):
try: try:
user_info(auth, arg_value) user_info(auth, arg_value)
except YunohostError as e: except YunohostError as e:
raise YunohostError('app_argument_invalid', name=arg_name, error=e.strerror) raise YunohostError('app_argument_invalid', name=arg_name, error=e)
elif arg_type == 'app': elif arg_type == 'app':
if not _is_installed(arg_value): if not _is_installed(arg_value):
raise YunohostError('app_argument_invalid', name=arg_name, error=m18n.n('app_unknown')) raise YunohostError('app_argument_invalid', name=arg_name, error=m18n.n('app_unknown'))
@ -2529,13 +2536,6 @@ def random_password(length=8):
return ''.join([random.SystemRandom().choice(char_set) for x in range(length)]) return ''.join([random.SystemRandom().choice(char_set) for x in range(length)])
def normalize_url_path(url_path):
if url_path.strip("/").strip():
return '/' + url_path.strip("/").strip() + '/'
return "/"
def unstable_apps(): def unstable_apps():
raw_app_installed = app_list(installed=True, raw=True) raw_app_installed = app_list(installed=True, raw=True)

View file

@ -40,7 +40,7 @@ from moulinette import msignals, m18n
from yunohost.utils.error import YunohostError from yunohost.utils.error import YunohostError
from moulinette.utils import filesystem from moulinette.utils import filesystem
from moulinette.utils.log import getActionLogger from moulinette.utils.log import getActionLogger
from moulinette.utils.filesystem import read_file from moulinette.utils.filesystem import read_file, mkdir
from yunohost.app import ( from yunohost.app import (
app_info, _is_installed, _parse_app_instance_name, _patch_php5 app_info, _is_installed, _parse_app_instance_name, _patch_php5
@ -885,7 +885,7 @@ class RestoreManager():
raise YunohostError('backup_invalid_archive') raise YunohostError('backup_invalid_archive')
logger.debug("executing the post-install...") logger.debug("executing the post-install...")
tools_postinstall(domain, 'yunohost', True) tools_postinstall(domain, 'Yunohost', True)
def clean(self): def clean(self):
""" """
@ -1746,8 +1746,8 @@ class CopyBackupMethod(BackupMethod):
return return
else: else:
logger.warning(m18n.n("bind_mouting_disable")) logger.warning(m18n.n("bind_mouting_disable"))
subprocess.call(["mountpoint", "-q", dest, subprocess.call(["mountpoint", "-q", self.work_dir,
"&&", "umount", "-R", dest]) "&&", "umount", "-R", self.work_dir])
raise YunohostError('backup_cant_mount_uncompress_archive') raise YunohostError('backup_cant_mount_uncompress_archive')
@ -2295,7 +2295,9 @@ def _create_archive_dir():
if os.path.lexists(ARCHIVES_PATH): if os.path.lexists(ARCHIVES_PATH):
raise YunohostError('backup_output_symlink_dir_broken', path=ARCHIVES_PATH) raise YunohostError('backup_output_symlink_dir_broken', path=ARCHIVES_PATH)
os.mkdir(ARCHIVES_PATH, 0o750) # Create the archive folder, with 'admin' as owner, such that
# people can scp archives out of the server
mkdir(ARCHIVES_PATH, mode=0o750, parents=True, uid="admin", gid="root")
def _call_for_each_path(self, callback, csv_path=None): def _call_for_each_path(self, callback, csv_path=None):

View file

@ -286,7 +286,7 @@ def _certificate_install_letsencrypt(auth, domain_list, force=False, no_checks=F
_configure_for_acme_challenge(auth, domain) _configure_for_acme_challenge(auth, domain)
_fetch_and_enable_new_certificate(domain, staging, no_checks=no_checks) _fetch_and_enable_new_certificate(domain, staging, no_checks=no_checks)
_install_cron() _install_cron(no_checks=no_checks)
logger.success( logger.success(
m18n.n("certmanager_cert_install_success", domain=domain)) m18n.n("certmanager_cert_install_success", domain=domain))
@ -407,12 +407,27 @@ def certificate_renew(auth, domain_list, force=False, no_checks=False, email=Fal
# #
def _install_cron(): def _install_cron(no_checks=False):
cron_job_file = "/etc/cron.daily/yunohost-certificate-renew" cron_job_file = "/etc/cron.daily/yunohost-certificate-renew"
# we need to check if "--no-checks" isn't already put inside the existing
# crontab, if it's the case it's probably because another domain needed it
# at some point so we keep it
if not no_checks and os.path.exists(cron_job_file):
with open(cron_job_file, "r") as f:
# no the best test in the world but except if we uses a shell
# script parser I'm not expected a much more better way to do that
no_checks = "--no-checks" in f.read()
command = "yunohost domain cert-renew --email\n"
if no_checks:
# handle trailing "\n with ":-1"
command = command[:-1] + " --no-checks\n"
with open(cron_job_file, "w") as f: with open(cron_job_file, "w") as f:
f.write("#!/bin/bash\n") f.write("#!/bin/bash\n")
f.write("yunohost domain cert-renew --email\n") f.write(command)
_set_permissions(cron_job_file, "root", "root", 0o755) _set_permissions(cron_job_file, "root", "root", 0o755)

View file

@ -35,7 +35,7 @@ class MyMigration(Migration):
def migrate(self): def migrate(self):
self.logfile = "/tmp/{}.log".format(self.name) self.logfile = "/var/log/yunohost/{}.log".format(self.name)
self.check_assertions() self.check_assertions()

View file

@ -38,6 +38,6 @@ class MyMigration(Migration):
def package_is_installed(self, package_name): def package_is_installed(self, package_name):
p = subprocess.Popen("dpkg --list | grep -q -w {}".format(package_name), shell=True) p = subprocess.Popen("dpkg --list | grep '^ii ' | grep -q -w {}".format(package_name), shell=True)
p.communicate() p.communicate()
return p.returncode == 0 return p.returncode == 0

View file

@ -1,6 +1,9 @@
import os
import re import re
from moulinette import m18n
from moulinette.utils.log import getActionLogger from moulinette.utils.log import getActionLogger
from moulinette.utils.filesystem import chown
from yunohost.tools import Migration from yunohost.tools import Migration
from yunohost.service import service_regen_conf, \ from yunohost.service import service_regen_conf, \
@ -8,6 +11,8 @@ from yunohost.service import service_regen_conf, \
_calculate_hash _calculate_hash
from yunohost.settings import settings_set, settings_get from yunohost.settings import settings_set, settings_get
from yunohost.utils.error import YunohostError from yunohost.utils.error import YunohostError
from yunohost.backup import ARCHIVES_PATH
logger = getActionLogger('yunohost.migration') logger = getActionLogger('yunohost.migration')
@ -33,6 +38,11 @@ class MyMigration(Migration):
settings_set("service.ssh.allow_deprecated_dsa_hostkey", False) settings_set("service.ssh.allow_deprecated_dsa_hostkey", False)
service_regen_conf(names=['ssh'], force=True) service_regen_conf(names=['ssh'], force=True)
# Update local archives folder permissions, so that
# admin can scp archives out of the server
if os.path.isdir(ARCHIVES_PATH):
chown(ARCHIVES_PATH, uid="admin", gid="root")
def backward(self): def backward(self):
raise YunohostError("migration_0008_backward_impossible") raise YunohostError("migration_0008_backward_impossible")

View file

@ -25,7 +25,6 @@
""" """
import os import os
import re import re
import json
import yaml import yaml
from moulinette import m18n, msettings from moulinette import m18n, msettings
@ -112,19 +111,16 @@ def domain_add(operation_logger, auth, domain, dyndns=False):
# Don't regen these conf if we're still in postinstall # Don't regen these conf if we're still in postinstall
if os.path.exists('/etc/yunohost/installed'): if os.path.exists('/etc/yunohost/installed'):
service_regen_conf(names=['nginx', 'metronome', 'dnsmasq', 'postfix']) service_regen_conf(names=['nginx', 'metronome', 'dnsmasq', 'postfix', 'rspamd'])
app_ssowatconf(auth) app_ssowatconf(auth)
except Exception as e: except Exception:
from sys import exc_info
t, v, tb = exc_info()
# Force domain removal silently # Force domain removal silently
try: try:
domain_remove(auth, domain, True) domain_remove(auth, domain, True)
except: except:
pass pass
raise t, v, tb raise
hook_callback('post_domain_add', args=[domain]) hook_callback('post_domain_add', args=[domain])
@ -230,13 +226,14 @@ def domain_cert_renew(auth, domain_list, force=False, no_checks=False, email=Fal
return yunohost.certificate.certificate_renew(auth, domain_list, force, no_checks, email, staging) return yunohost.certificate.certificate_renew(auth, domain_list, force, no_checks, email, staging)
def _get_conflicting_apps(auth, domain, path): def _get_conflicting_apps(auth, domain, path, ignore_app=None):
""" """
Return a list of all conflicting apps with a domain/path (it can be empty) Return a list of all conflicting apps with a domain/path (it can be empty)
Keyword argument: Keyword argument:
domain -- The domain for the web path (e.g. your.domain.tld) domain -- The domain for the web path (e.g. your.domain.tld)
path -- The path to check (e.g. /coffee) path -- The path to check (e.g. /coffee)
ignore_app -- An optional app id to ignore (c.f. the change_url usecase)
""" """
domain, path = _normalize_domain_path(domain, path) domain, path = _normalize_domain_path(domain, path)
@ -257,6 +254,8 @@ def _get_conflicting_apps(auth, domain, path):
if domain in apps_map: if domain in apps_map:
# Loop through apps # Loop through apps
for p, a in apps_map[domain].items(): for p, a in apps_map[domain].items():
if a["id"] == ignore_app:
continue
if path == p: if path == p:
conflicts.append((p, a["id"], a["label"])) conflicts.append((p, a["id"], a["label"]))
# We also don't want conflicts with other apps starting with # We also don't want conflicts with other apps starting with
@ -302,7 +301,7 @@ def _normalize_domain_path(domain, path):
domain = domain[len("http://"):] domain = domain[len("http://"):]
# Remove trailing slashes # Remove trailing slashes
domain = domain.rstrip("/") domain = domain.rstrip("/").lower()
path = "/" + path.strip("/") path = "/" + path.strip("/")
return domain, path return domain, path

View file

@ -27,14 +27,13 @@ import os
import re import re
import json import json
import glob import glob
import time
import base64 import base64
import subprocess import subprocess
from moulinette import m18n from moulinette import m18n
from moulinette.core import MoulinetteError from moulinette.core import MoulinetteError
from moulinette.utils.log import getActionLogger from moulinette.utils.log import getActionLogger
from moulinette.utils.filesystem import read_file, write_to_file, rm from moulinette.utils.filesystem import write_to_file
from moulinette.utils.network import download_json from moulinette.utils.network import download_json
from moulinette.utils.process import check_output from moulinette.utils.process import check_output

View file

@ -342,8 +342,7 @@ def firewall_upnp(action='status', no_refresh=False):
# Refresh port mapping using UPnP # Refresh port mapping using UPnP
if not no_refresh: if not no_refresh:
upnpc = miniupnpc.UPnP() upnpc = miniupnpc.UPnP()
upnpc.discoverdelay = 62000 upnpc.discoverdelay = 3000
upnpc.localport = 1900
# Discover UPnP device(s) # Discover UPnP device(s)
logger.debug('discovering UPnP devices...') logger.debug('discovering UPnP devices...')

View file

@ -316,7 +316,7 @@ def hook_exec(path, args=None, raise_on_error=False, no_trace=False,
if path[0] != '/': if path[0] != '/':
path = os.path.realpath(path) path = os.path.realpath(path)
if not os.path.isfile(path): if not os.path.isfile(path):
raise YunohostError('file_not_exist', path=path) raise YunohostError('file_does_not_exist', path=path)
# Construct command variables # Construct command variables
cmd_args = '' cmd_args = ''

View file

@ -30,7 +30,6 @@ import collections
from datetime import datetime from datetime import datetime
from logging import FileHandler, getLogger, Formatter from logging import FileHandler, getLogger, Formatter
from sys import exc_info
from moulinette import m18n, msettings from moulinette import m18n, msettings
from yunohost.utils.error import YunohostError from yunohost.utils.error import YunohostError

View file

@ -49,7 +49,7 @@ MOULINETTE_LOCK = "/var/run/moulinette_yunohost.lock"
logger = log.getActionLogger('yunohost.service') logger = log.getActionLogger('yunohost.service')
def service_add(name, status=None, log=None, runlevel=None, need_lock=False, description=None): def service_add(name, status=None, log=None, runlevel=None, need_lock=False, description=None, log_type="file"):
""" """
Add a custom service Add a custom service
@ -60,6 +60,7 @@ def service_add(name, status=None, log=None, runlevel=None, need_lock=False, des
runlevel -- Runlevel priority of the service runlevel -- Runlevel priority of the service
need_lock -- Use this option to prevent deadlocks if the service does invoke yunohost commands. need_lock -- Use this option to prevent deadlocks if the service does invoke yunohost commands.
description -- description of the service description -- description of the service
log_type -- Precise if the corresponding log is a file or a systemd log
""" """
services = _get_services() services = _get_services()
@ -69,8 +70,23 @@ def service_add(name, status=None, log=None, runlevel=None, need_lock=False, des
services[name] = {'status': status} services[name] = {'status': status}
if log is not None: if log is not None:
if not isinstance(log, list):
log = [log]
services[name]['log'] = log services[name]['log'] = log
if not isinstance(log_type, list):
log_type = [log_type]
if len(log_type) < len(log):
log_type.extend([log_type[-1]] * (len(log) - len(log_type))) # extend list to have the same size as log
if len(log_type) == len(log):
services[name]['log_type'] = log_type
else:
raise YunohostError('service_add_failed', service=name)
if runlevel is not None: if runlevel is not None:
services[name]['runlevel'] = runlevel services[name]['runlevel'] = runlevel
@ -152,6 +168,60 @@ def service_stop(names):
logger.debug(m18n.n('service_already_stopped', service=name)) logger.debug(m18n.n('service_already_stopped', service=name))
def service_reload(names):
"""
Reload one or more services
Keyword argument:
name -- Services name to reload
"""
if isinstance(names, str):
names = [names]
for name in names:
if _run_service_command('reload', name):
logger.success(m18n.n('service_reloaded', service=name))
else:
if service_status(name)['status'] != 'inactive':
raise YunohostError('service_reload_failed', service=name, logs=_get_journalctl_logs(name))
def service_restart(names):
"""
Restart one or more services. If the services are not running yet, they will be started.
Keyword argument:
name -- Services name to restart
"""
if isinstance(names, str):
names = [names]
for name in names:
if _run_service_command('restart', name):
logger.success(m18n.n('service_restarted', service=name))
else:
if service_status(name)['status'] != 'inactive':
raise YunohostError('service_restart_failed', service=name, logs=_get_journalctl_logs(name))
def service_reload_or_restart(names):
"""
Reload one or more services if they support it. If not, restart them instead. If the services are not running yet, they will be started.
Keyword argument:
name -- Services name to reload or restart
"""
if isinstance(names, str):
names = [names]
for name in names:
if _run_service_command('reload-or-restart', name):
logger.success(m18n.n('service_reloaded_or_restarted', service=name))
else:
if service_status(name)['status'] != 'inactive':
raise YunohostError('service_reload_or_restart_failed', service=name, logs=_get_journalctl_logs(name))
@is_unit_operation() @is_unit_operation()
def service_enable(operation_logger, names): def service_enable(operation_logger, names):
""" """
@ -313,13 +383,19 @@ def service_log(name, number=50):
raise YunohostError('service_no_log', service=name) raise YunohostError('service_no_log', service=name)
log_list = services[name]['log'] log_list = services[name]['log']
log_type_list = services[name].get('log_type', [])
if not isinstance(log_list, list): if not isinstance(log_list, list):
log_list = [log_list] log_list = [log_list]
if len(log_type_list) < len(log_list):
log_type_list.extend(["file"] * (len(log_list)-len(log_type_list)))
result = {} result = {}
for log_path in log_list: for index, log_path in enumerate(log_list):
log_type = log_type_list[index]
if log_type == "file":
# log is a file, read it # log is a file, read it
if not os.path.isdir(log_path): if not os.path.isdir(log_path):
result[log_path] = _tail(log_path, int(number)) if os.path.exists(log_path) else [] result[log_path] = _tail(log_path, int(number)) if os.path.exists(log_path) else []
@ -335,6 +411,9 @@ def service_log(name, number=50):
continue continue
result[log_file_path] = _tail(log_file_path, int(number)) if os.path.exists(log_file_path) else [] result[log_file_path] = _tail(log_file_path, int(number)) if os.path.exists(log_file_path) else []
else:
# get log with journalctl
result[log_path] = _get_journalctl_logs(log_path, int(number)).splitlines()
return result return result
@ -597,14 +676,14 @@ def _run_service_command(action, service):
if service not in services.keys(): if service not in services.keys():
raise YunohostError('service_unknown', service=service) raise YunohostError('service_unknown', service=service)
possible_actions = ['start', 'stop', 'restart', 'reload', 'enable', 'disable'] possible_actions = ['start', 'stop', 'restart', 'reload', 'reload-or-restart', 'enable', 'disable']
if action not in possible_actions: if action not in possible_actions:
raise ValueError("Unknown action '%s', available actions are: %s" % (action, ", ".join(possible_actions))) raise ValueError("Unknown action '%s', available actions are: %s" % (action, ", ".join(possible_actions)))
cmd = 'systemctl %s %s' % (action, service) cmd = 'systemctl %s %s' % (action, service)
need_lock = services[service].get('need_lock', False) \ need_lock = services[service].get('need_lock', False) \
and action in ['start', 'stop', 'restart', 'reload'] and action in ['start', 'stop', 'restart', 'reload', 'reload-or-restart']
try: try:
# Launch the command # Launch the command
@ -617,9 +696,12 @@ def _run_service_command(action, service):
# Wait for the command to complete # Wait for the command to complete
p.communicate() p.communicate()
except subprocess.CalledProcessError as e: if p.returncode != 0:
# TODO: Log output? logger.warning(m18n.n('service_cmd_exec_failed', command=cmd))
logger.warning(m18n.n('service_cmd_exec_failed', command=' '.join(e.cmd))) return False
except Exception as e:
logger.warning(m18n.n("unexpected_error", error=str(e)))
return False return False
finally: finally:
@ -990,9 +1072,9 @@ def manually_modified_files():
return output return output
def _get_journalctl_logs(service): def _get_journalctl_logs(service, number="all"):
try: try:
return subprocess.check_output("journalctl -xn -u %s" % service, shell=True) return subprocess.check_output("journalctl -xn -u {0} -n{1}".format(service, number), shell=True)
except: except:
import traceback import traceback
return "error while get services logs from journalctl:\n%s" % traceback.format_exc() return "error while get services logs from journalctl:\n%s" % traceback.format_exc()

View file

@ -5,7 +5,6 @@ import os
import pwd import pwd
import subprocess import subprocess
from moulinette import m18n
from yunohost.utils.error import YunohostError from yunohost.utils.error import YunohostError
from moulinette.utils.filesystem import read_file, write_to_file, chown, chmod, mkdir from moulinette.utils.filesystem import read_file, write_to_file, chown, chmod, mkdir

View file

@ -51,18 +51,18 @@ def test_urlavailable():
def test_registerurl(): def test_registerurl():
app_install(auth, "./tests/apps/register_url_app_ynh", app_install(auth, "./tests/apps/register_url_app_ynh",
args="domain=%s&path=%s" % (maindomain, "/urlregisterapp")) args="domain=%s&path=%s" % (maindomain, "/urlregisterapp"), force=True)
assert not domain_url_available(auth, maindomain, "/urlregisterapp") assert not domain_url_available(auth, maindomain, "/urlregisterapp")
# Try installing at same location # Try installing at same location
with pytest.raises(YunohostError): with pytest.raises(YunohostError):
app_install(auth, "./tests/apps/register_url_app_ynh", app_install(auth, "./tests/apps/register_url_app_ynh",
args="domain=%s&path=%s" % (maindomain, "/urlregisterapp")) args="domain=%s&path=%s" % (maindomain, "/urlregisterapp"), force=True)
def test_registerurl_baddomain(): def test_registerurl_baddomain():
with pytest.raises(YunohostError): with pytest.raises(YunohostError):
app_install(auth, "./tests/apps/register_url_app_ynh", app_install(auth, "./tests/apps/register_url_app_ynh",
args="domain=%s&path=%s" % ("yolo.swag", "/urlregisterapp")) args="domain=%s&path=%s" % ("yolo.swag", "/urlregisterapp"), force=True)

View file

@ -171,7 +171,7 @@ def install_app(app, path, additionnal_args=""):
app_install(auth, "./tests/apps/%s" % app, app_install(auth, "./tests/apps/%s" % app,
args="domain=%s&path=%s%s" % (maindomain, path, args="domain=%s&path=%s%s" % (maindomain, path,
additionnal_args)) additionnal_args), force=True)
def add_archive_wordpress_from_2p4(): def add_archive_wordpress_from_2p4():

View file

@ -28,15 +28,15 @@ def teardown_function(function):
def install_changeurl_app(path): def install_changeurl_app(path):
app_install(auth, "./tests/apps/change_url_app_ynh", app_install(auth, "./tests/apps/change_url_app_ynh",
args="domain=%s&path=%s" % (maindomain, path)) args="domain=%s&path=%s" % (maindomain, path), force=True)
def check_changeurl_app(path): def check_changeurl_app(path):
appmap = app_map(raw=True) appmap = app_map(raw=True)
assert path + "/" in appmap[maindomain].keys() assert path in appmap[maindomain].keys()
assert appmap[maindomain][path + "/"]["id"] == "change_url_app" assert appmap[maindomain][path]["id"] == "change_url_app"
r = requests.get("https://127.0.0.1%s/" % path, headers={"domain": maindomain}, verify=False) r = requests.get("https://127.0.0.1%s/" % path, headers={"domain": maindomain}, verify=False)
assert r.status_code == 200 assert r.status_code == 200

View file

@ -27,7 +27,6 @@ import re
import os import os
import yaml import yaml
import json import json
import logging
import subprocess import subprocess
import pwd import pwd
import socket import socket
@ -151,7 +150,7 @@ def tools_adminpw(auth, new_password, check_strength=True):
with open('/etc/shadow', 'w') as after_file: with open('/etc/shadow', 'w') as after_file:
after_file.write(before.replace("root:" + hash_root, after_file.write(before.replace("root:" + hash_root,
"root:" + new_hash.replace('{CRYPT}', ''))) "root:" + new_hash.replace('{CRYPT}', '')))
except IOError as e: except IOError:
logger.warning(m18n.n('root_password_desynchronized')) logger.warning(m18n.n('root_password_desynchronized'))
return return
@ -207,7 +206,7 @@ def tools_maindomain(operation_logger, auth, new_domain=None):
# Regen configurations # Regen configurations
try: try:
with open('/etc/yunohost/installed', 'r') as f: with open('/etc/yunohost/installed', 'r'):
service_regen_conf() service_regen_conf()
except IOError: except IOError:
pass pass
@ -473,7 +472,7 @@ def tools_update(ignore_apps=False, ignore_packages=False):
cache = apt.Cache() cache = apt.Cache()
# Update APT cache # Update APT cache
logger.debug(m18n.n('updating_apt_cache')) logger.info(m18n.n('updating_apt_cache'))
if not cache.update(): if not cache.update():
raise YunohostError('update_cache_failed') raise YunohostError('update_cache_failed')
@ -531,6 +530,11 @@ def tools_upgrade(operation_logger, auth, ignore_apps=False, ignore_packages=Fal
is_api = True if msettings.get('interface') == 'api' else False is_api = True if msettings.get('interface') == 'api' else False
if not ignore_packages: if not ignore_packages:
apt.apt_pkg.init()
apt.apt_pkg.config.set("DPkg::Options::", "--force-confdef")
apt.apt_pkg.config.set("DPkg::Options::", "--force-confold")
cache = apt.Cache() cache = apt.Cache()
cache.open(None) cache.open(None)
cache.upgrade(True) cache.upgrade(True)
@ -559,6 +563,7 @@ def tools_upgrade(operation_logger, auth, ignore_apps=False, ignore_packages=Fal
operation_logger.start() operation_logger.start()
try: try:
os.environ["DEBIAN_FRONTEND"] = "noninteractive"
# Apply APT changes # Apply APT changes
# TODO: Logs output for the API # TODO: Logs output for the API
cache.commit(apt.progress.text.AcquireProgress(), cache.commit(apt.progress.text.AcquireProgress(),
@ -571,6 +576,8 @@ def tools_upgrade(operation_logger, auth, ignore_apps=False, ignore_packages=Fal
else: else:
logger.info(m18n.n('done')) logger.info(m18n.n('done'))
operation_logger.success() operation_logger.success()
finally:
del os.environ["DEBIAN_FRONTEND"]
else: else:
logger.info(m18n.n('packages_no_upgrade')) logger.info(m18n.n('packages_no_upgrade'))
@ -718,9 +725,14 @@ def _check_if_vulnerable_to_meltdown():
call = subprocess.Popen("bash %s --batch json --variant 3" % call = subprocess.Popen("bash %s --batch json --variant 3" %
SCRIPT_PATH, shell=True, SCRIPT_PATH, shell=True,
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT) stderr=subprocess.PIPE)
output, _ = call.communicate() # TODO / FIXME : here we are ignoring error messages ...
# in particular on RPi2 and other hardware, the script complains about
# "missing some kernel info (see -v), accuracy might be reduced"
# Dunno what to do about that but we probably don't want to harass
# users with this warning ...
output, err = call.communicate()
assert call.returncode in (0, 2, 3), "Return code: %s" % call.returncode assert call.returncode in (0, 2, 3), "Return code: %s" % call.returncode
CVEs = json.loads(output) CVEs = json.loads(output)
@ -861,7 +873,7 @@ def tools_migrations_migrate(target=None, skip=False, auto=False, accept_disclai
# no new migrations to run # no new migrations to run
if target == last_run_migration_number: if target == last_run_migration_number:
logger.warn(m18n.n('migrations_no_migrations_to_run')) logger.info(m18n.n('migrations_no_migrations_to_run'))
return return
logger.debug(m18n.n('migrations_show_last_migration', last_run_migration_number)) logger.debug(m18n.n('migrations_show_last_migration', last_run_migration_number))

View file

@ -251,6 +251,7 @@ def user_delete(operation_logger, auth, username, purge=False):
if auth.update('cn=sftpusers,ou=groups', {'memberUid': memberlist}): if auth.update('cn=sftpusers,ou=groups', {'memberUid': memberlist}):
if purge: if purge:
subprocess.call(['rm', '-rf', '/home/{0}'.format(username)]) subprocess.call(['rm', '-rf', '/home/{0}'.format(username)])
subprocess.call(['rm', '-rf', '/var/mail/{0}'.format(username)])
else: else:
raise YunohostError('user_deletion_failed') raise YunohostError('user_deletion_failed')

View file

@ -32,9 +32,9 @@ class YunohostError(MoulinetteError):
are translated via m18n.n (namespace) instead of m18n.g (global?) are translated via m18n.n (namespace) instead of m18n.g (global?)
""" """
def __init__(self, key, __raw_msg__=False, *args, **kwargs): def __init__(self, key, raw_msg=False, *args, **kwargs):
if __raw_msg__: if raw_msg:
msg = key msg = key
else: else:
msg = m18n.n(key, *args, **kwargs) msg = m18n.n(key, *args, **kwargs)
super(YunohostError, self).__init__(msg, __raw_msg__=True) super(YunohostError, self).__init__(msg, raw_msg=True)

View file

@ -0,0 +1,7 @@
FROM alpine:3.7
RUN apk --update --no-cache add kmod binutils grep perl
COPY . /check
ENTRYPOINT ["/check/spectre-meltdown-checker.sh"]

View file

@ -1,7 +1,15 @@
Spectre & Meltdown Checker Spectre & Meltdown Checker
========================== ==========================
A shell script to tell if your system is vulnerable against the 3 "speculative execution" CVEs that were made public early 2018. A shell script to tell if your system is vulnerable against the several "speculative execution" CVEs that were made public in 2018.
- CVE-2017-5753 [bounds check bypass] aka 'Spectre Variant 1'
- CVE-2017-5715 [branch target injection] aka 'Spectre Variant 2'
- CVE-2017-5754 [rogue data cache load] aka 'Meltdown' aka 'Variant 3'
- CVE-2018-3640 [rogue system register read] aka 'Variant 3a'
- CVE-2018-3639 [speculative store bypass] aka 'Variant 4'
- CVE-2018-3615 [L1 terminal fault] aka 'Foreshadow (SGX)'
- CVE-2018-3620 [L1 terminal fault] aka 'Foreshadow-NG (OS)'
- CVE-2018-3646 [L1 terminal fault] aka 'Foreshadow-NG (VMM)'
Supported operating systems: Supported operating systems:
- Linux (all versions, flavors and distros) - Linux (all versions, flavors and distros)
@ -39,6 +47,22 @@ chmod +x spectre-meltdown-checker.sh
sudo ./spectre-meltdown-checker.sh sudo ./spectre-meltdown-checker.sh
``` ```
### Run the script in a docker container
#### With docker-compose
```shell
docker-compose build
docker-compose run --rm spectre-meltdown-checker
```
#### Without docker-compose
```shell
docker build -t spectre-meltdown-checker .
docker run --rm --privileged -v /boot:/boot:ro -v /dev/cpu:/dev/cpu:ro -v /lib/modules:/lib/modules:ro spectre-meltdown-checker
```
## Example of script output ## Example of script output
- Intel Haswell CPU running under Ubuntu 16.04 LTS - Intel Haswell CPU running under Ubuntu 16.04 LTS
@ -74,7 +98,38 @@ sudo ./spectre-meltdown-checker.sh
- Mitigation: updated kernel (with PTI/KPTI patches), updating the kernel is enough - Mitigation: updated kernel (with PTI/KPTI patches), updating the kernel is enough
- Performance impact of the mitigation: low to medium - Performance impact of the mitigation: low to medium
## Disclaimer **CVE-2018-3640** rogue system register read (Variant 3a)
- Impact: TBC
- Mitigation: microcode update only
- Performance impact of the mitigation: negligible
**CVE-2018-3639** speculative store bypass (Variant 4)
- Impact: software using JIT (no known exploitation against kernel)
- Mitigation: microcode update + kernel update making possible for affected software to protect itself
- Performance impact of the mitigation: low to medium
**CVE-2018-3615** l1 terminal fault (Foreshadow-NG SGX)
- Impact: Kernel & all software (any physical memory address in the system)
- Mitigation: microcode update
- Performance impact of the mitigation: negligible
**CVE-2018-3620** l1 terminal fault (Foreshadow-NG SMM)
- Impact: Kernel & System management mode
- Mitigation: updated kernel (with PTE inversion)
- Performance impact of the mitigation: negligible
**CVE-2018-3646** l1 terminal fault (Foreshadow-NG VMM)
- Impact: Virtualization software and Virtual Machine Monitors
- Mitigation: disable ept (extended page tables), disable hyper-threading (SMT), or
updated kernel (with L1d flush)
- Performance impact of the mitigation: low to significant
## Understanding what this script does and doesn't
This tool does its best to determine whether your system is immune (or has proper mitigations in place) for the collectively named "speculative execution" vulnerabilities. It doesn't attempt to run any kind of exploit, and can't guarantee that your system is secure, but rather helps you verifying whether your system has the known correct mitigations in place. This tool does its best to determine whether your system is immune (or has proper mitigations in place) for the collectively named "speculative execution" vulnerabilities. It doesn't attempt to run any kind of exploit, and can't guarantee that your system is secure, but rather helps you verifying whether your system has the known correct mitigations in place.
However, some mitigations could also exist in your kernel that this script doesn't know (yet) how to detect, or it might falsely detect mitigations that in the end don't work as expected (for example, on backported or modified kernels). However, some mitigations could also exist in your kernel that this script doesn't know (yet) how to detect, or it might falsely detect mitigations that in the end don't work as expected (for example, on backported or modified kernels).

View file

@ -0,0 +1,15 @@
version: '2'
services:
spectre-meltdown-checker:
build:
context: ./
dockerfile: ./Dockerfile
image: spectre-meltdown-checker:latest
container_name: spectre-meltdown-checker
privileged: true
network_mode: none
volumes:
- /boot:/boot:ro
- /dev/cpu:/dev/cpu:ro
- /lib/modules:/lib/modules:ro

File diff suppressed because it is too large Load diff