diff --git a/data/actionsmap/yunohost.yml b/data/actionsmap/yunohost.yml index cbe959b55..fabdcb923 100644 --- a/data/actionsmap/yunohost.yml +++ b/data/actionsmap/yunohost.yml @@ -1623,6 +1623,32 @@ tools: full: --force action: store_true + ### tools_regen_conf() + regen-conf: + action_help: Regenerate the configuration file(s) + api: PUT /tools/regenconf + arguments: + names: + help: Categories to regenerate configuration of (all by default) + nargs: "*" + metavar: NAME + -d: + full: --with-diff + help: Show differences in case of configuration changes + action: store_true + -f: + full: --force + help: Override all manual modifications in configuration files + action: store_true + -n: + full: --dry-run + help: Show what would have been regenerated + action: store_true + -p: + full: --list-pending + help: List pending configuration files and exit + action: store_true + subcategories: migrations: diff --git a/data/helpers.d/backend b/data/helpers.d/backend index e710da9c7..710e6299b 100644 --- a/data/helpers.d/backend +++ b/data/helpers.d/backend @@ -3,17 +3,19 @@ # Use logrotate to manage the logfile # # usage: ynh_use_logrotate [--logfile=/log/file] [--nonappend] [--specific_user=user/group] -# | arg: -l, --logfile= - absolute path of logfile -# | arg: -n, --nonappend - (Option) Replace the config file instead of appending this new config. +# | arg: -l, --logfile - absolute path of logfile +# | arg: -n, --nonappend - (optional) Replace the config file instead of appending this new config. # | 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} -# You can provide a path with the directory only or with the logfile. +# If no --logfile is provided, /var/log/${app} will be used as default. +# logfile can be just a directory, or a full path to a logfile : # /parentdir/logdir # /parentdir/logdir/logfile.log # -# 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 +# It's possible to use this helper multiple times, each config will be added to +# the same logrotate config file. Unless you use the option --non-append +# +# Requires YunoHost version 2.6.4 or higher. ynh_use_logrotate () { # Declare an array to define the options of this helper. local legacy_args=lnuya @@ -92,6 +94,8 @@ EOF # Remove the app's logrotate config. # # usage: ynh_remove_logrotate +# +# Requires YunoHost version 2.6.4 or higher. ynh_remove_logrotate () { if [ -e "/etc/logrotate.d/$app" ]; then sudo rm "/etc/logrotate.d/$app" @@ -112,6 +116,7 @@ ynh_remove_logrotate () { # __APP__ by $app # __FINALPATH__ by $final_path # +# Requires YunoHost version 2.7.2 or higher. ynh_add_systemd_config () { # Declare an array to define the options of this helper. local legacy_args=st @@ -147,6 +152,7 @@ ynh_add_systemd_config () { # usage: ynh_remove_systemd_config [--service=service] # | arg: -s, --service - Service name (optionnal, $app by default) # +# Requires YunoHost version 2.7.2 or higher. ynh_remove_systemd_config () { # Declare an array to define the options of this helper. local legacy_args=s @@ -158,10 +164,10 @@ ynh_remove_systemd_config () { local finalsystemdconf="/etc/systemd/system/$service.service" if [ -e "$finalsystemdconf" ]; then - sudo systemctl stop $service - sudo systemctl disable $service + ynh_systemd_action --service_name=$service --action=stop + systemctl disable $service ynh_secure_remove --file="$finalsystemdconf" - sudo systemctl daemon-reload + systemctl daemon-reload fi } @@ -169,8 +175,7 @@ ynh_remove_systemd_config () { # # usage: ynh_add_nginx_config "list of others variables to replace" # -# | arg: list of others variables to replace separeted by a space -# | for example : 'path_2 port_2 ...' +# | arg: list - (Optional) list of others variables to replace separated by spaces. For example : 'path_2 port_2 ...' # # This will use a template in ../conf/nginx.conf # __PATH__ by $path_url @@ -183,6 +188,7 @@ ynh_remove_systemd_config () { # __PATH_2__ by $path_2 # __PORT_2__ by $port_2 # +# Requires YunoHost version 2.7.2 or higher. ynh_add_nginx_config () { finalnginxconf="/etc/nginx/conf.d/$domain.d/$app.conf" local others_var=${1:-} @@ -227,24 +233,38 @@ ynh_add_nginx_config () { ynh_store_file_checksum --file="$finalnginxconf" - sudo systemctl reload nginx + ynh_systemd_action --service_name=nginx --action=reload } # Remove the dedicated nginx config # # usage: ynh_remove_nginx_config +# +# Requires YunoHost version 2.7.2 or higher. ynh_remove_nginx_config () { ynh_secure_remove --file="/etc/nginx/conf.d/$domain.d/$app.conf" - sudo systemctl reload nginx + ynh_systemd_action --service_name=nginx --action=reload } # Create a dedicated php-fpm config # -# usage: ynh_add_fpm_config +# usage: ynh_add_fpm_config [--phpversion=7.X] +# | arg: -v, --phpversion - Version of php to use. +# +# Requires YunoHost version 2.7.2 or higher. ynh_add_fpm_config () { + # Declare an array to define the options of this helper. + local legacy_args=v + declare -Ar args_array=( [v]=phpversion= ) + local phpversion + # Manage arguments with getopts + ynh_handle_getopts_args "$@" + # Configure PHP-FPM 7.0 by default - local fpm_config_dir="/etc/php/7.0/fpm" - local fpm_service="php7.0-fpm" + phpversion="${phpversion:-7.0}" + + local fpm_config_dir="/etc/php/$phpversion/fpm" + local fpm_service="php${phpversion}-fpm" # Configure PHP-FPM 5 on Debian Jessie if [ "$(ynh_get_debian_release)" == "jessie" ]; then fpm_config_dir="/etc/php5/fpm" @@ -258,6 +278,7 @@ ynh_add_fpm_config () { ynh_replace_string --match_string="__NAMETOCHANGE__" --replace_string="$app" --target_file="$finalphpconf" ynh_replace_string --match_string="__FINALPATH__" --replace_string="$final_path" --target_file="$finalphpconf" ynh_replace_string --match_string="__USER__" --replace_string="$app" --target_file="$finalphpconf" + ynh_replace_string --match_string="__PHPVERSION__" --replace_string="$phpversion" --target_file="$finalphpconf" sudo chown root: "$finalphpconf" ynh_store_file_checksum --file="$finalphpconf" @@ -270,12 +291,14 @@ ynh_add_fpm_config () { sudo chown root: "$finalphpini" ynh_store_file_checksum "$finalphpini" fi - sudo systemctl reload $fpm_service + ynh_systemd_action --service_name=$fpm_service --action=reload } # Remove the dedicated php-fpm config # # usage: ynh_remove_fpm_config +# +# Requires YunoHost version 2.7.2 or higher. ynh_remove_fpm_config () { local fpm_config_dir=$(ynh_app_setting_get --app=$app --key=fpm_config_dir) local fpm_service=$(ynh_app_setting_get --app=$app --key=fpm_service) @@ -286,7 +309,7 @@ ynh_remove_fpm_config () { fi ynh_secure_remove --file="$fpm_config_dir/pool.d/$app.conf" ynh_secure_remove --file="$fpm_config_dir/conf.d/20-$app.ini" 2>&1 - sudo systemctl reload $fpm_service + ynh_systemd_action --service_name=$fpm_service --action=reload } # Create a dedicated fail2ban config (jail and filter conf files) @@ -350,8 +373,10 @@ ynh_remove_fpm_config () { # To validate your regex you can test with this command: # fail2ban-regex /var/log/YOUR_LOG_FILE_PATH /etc/fail2ban/filter.d/YOUR_APP.conf # +# Requires YunoHost version 3.?.? or higher. ynh_add_fail2ban_config () { # Declare an array to define the options of this helper. + local legacy_args=lrmptv declare -Ar args_array=( [l]=logpath= [r]=failregex= [m]=max_retry= [p]=ports= [t]=use_template [v]=others_var=) local logpath local failregex @@ -429,6 +454,8 @@ EOF # Remove the dedicated fail2ban config (jail and filter conf files) # # usage: ynh_remove_fail2ban_config +# +# Requires YunoHost version 3.?.? or higher. ynh_remove_fail2ban_config () { ynh_secure_remove "/etc/fail2ban/jail.d/$app.conf" ynh_secure_remove "/etc/fail2ban/filter.d/$app.conf" diff --git a/data/helpers.d/debug b/data/helpers.d/debug index a8b7c8d69..7ad097dbd 100644 --- a/data/helpers.d/debug +++ b/data/helpers.d/debug @@ -5,6 +5,8 @@ # usage: ynh_debug [--message=message] [--trace=1/0] # | arg: -m, --message= - The text to print # | arg: -t, --trace= - Turn on or off the trace of the script. Usefull to trace nonly a small part of a script. +# +# Requires YunoHost version 3.?.? or higher. ynh_debug () { # Disable set xtrace for the helper itself, to not pollute the debug log set +x @@ -35,6 +37,8 @@ ynh_debug () { PS4='$(basename ${BASH_SOURCE[0]})-L${LINENO}: ' # Force xtrace to stderr BASH_XTRACEFD=2 + # Force stdout to stderr + exec 1>&2 fi if [ "$trace" == "0" ] then @@ -42,6 +46,8 @@ ynh_debug () { set +x # Put xtrace back to its original fild descriptor BASH_XTRACEFD=$old_bash_xtracefd + # Restore stdout + exec 1>&1 fi # Renable set xtrace set -x @@ -54,6 +60,8 @@ ynh_debug () { # In case of use of pipes, you have to use double quotes. Otherwise, this helper will be executed with the first command, then be sent to the next pipe. # # | arg: command - command to execute +# +# Requires YunoHost version 3.?.? or higher. ynh_debug_exec () { ynh_debug --message="$(eval $@)" } diff --git a/data/helpers.d/filesystem b/data/helpers.d/filesystem index 10123dea4..c471a6872 100644 --- a/data/helpers.d/filesystem +++ b/data/helpers.d/filesystem @@ -15,16 +15,13 @@ CAN_BIND=${CAN_BIND:-1} # If DEST is ended by a slash it complete this path with the basename of SRC. # # usage: ynh_backup --src_path=src_path [--dest_path=dest_path] [--is_big] [--not_mandatory] -# | arg: -s, --src_path - file or directory to bind or symlink or copy. it shouldn't be in -# the backup dir. -# | arg: -d, --dest_path - destination file or directory inside the -# backup dir +# | arg: -s, --src_path - file or directory to bind or symlink or copy. it shouldn't be in the backup dir. +# | arg: -d, --dest_path - destination file or directory inside the backup dir # | arg: -b, --is_big - Indicate data are big (mail, video, image ...) # | arg: -m, --not_mandatory - Indicate that if the file is missing, the backup can ignore it. # | arg: arg - Deprecated arg # -# example: -# # Wordpress app context +# Example in the context of a wordpress app # # ynh_backup "/etc/nginx/conf.d/$domain.d/$app.conf" # # => This line will be added into CSV file @@ -46,6 +43,7 @@ CAN_BIND=${CAN_BIND:-1} # ynh_backup "/etc/nginx/conf.d/$domain.d/$app.conf" "/conf/" # # => "/etc/nginx/conf.d/$domain.d/$app.conf","apps/wordpress/conf/$app.conf" # +# Requires YunoHost version 2.4.0 or higher. ynh_backup() { # TODO find a way to avoid injection by file strange naming ! @@ -79,7 +77,7 @@ ynh_backup() { echo "Source path '${src_path}' does not exist" >&2 if [ "$not_mandatory" == "0" ] then - echo "Source path '${SRC_PATH}' does not exist" >&2 + echo "Source path '${src_path}' does not exist" >&2 # This is a temporary fix for fail2ban config files missing after the migration to stretch. if echo "${src_path}" | grep --quiet "/etc/fail2ban" @@ -158,6 +156,7 @@ ynh_backup() { # # usage: ynh_restore # +# Requires YunoHost version 2.6.4 or higher. ynh_restore () { # Deduce the relative path of $YNH_CWD local REL_DIR="${YNH_CWD#$YNH_BACKUP_DIR/}" @@ -196,29 +195,27 @@ with open(sys.argv[1], 'r') as backup_file: # Restore a file or a directory # # Use the registered path in backup_list by ynh_backup to restore the file at -# the good place. +# the right place. # # usage: ynh_restore_file --origin_path=origin_path [--dest_path=dest_path] [--not_mandatory] -# | 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 -# | 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 archive, the destination will be searched into backup.csv +# | 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 +# | 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 archive, the destination will be searched into backup.csv # | arg: -m, --not_mandatory - Indicate that if the file is missing, the restore process can ignore it. # +# examples: +# ynh_restore_file "/etc/nginx/conf.d/$domain.d/$app.conf" +# # You can also use relative paths: +# ynh_restore_file "conf/nginx.conf" +# # 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. # -# examples: -# ynh_restore_file "/etc/nginx/conf.d/$domain.d/$app.conf" -# # if apps/wordpress/etc/nginx/conf.d/$domain.d/$app.conf exists, restore it into -# # /etc/nginx/conf.d/$domain.d/$app.conf -# # if no, search a correspondance in the csv (eg: conf/nginx.conf) and restore it into -# # /etc/nginx/conf.d/$domain.d/$app.conf -# -# # DON'T GIVE THE ARCHIVE PATH: -# ynh_restore_file "conf/nginx.conf" +# if apps/wordpress/etc/nginx/conf.d/$domain.d/$app.conf exists, restore it into +# /etc/nginx/conf.d/$domain.d/$app.conf +# if no, search for a match in the csv (eg: conf/nginx.conf) and restore it into +# /etc/nginx/conf.d/$domain.d/$app.conf # +# Requires YunoHost version 2.6.4 or higher. ynh_restore_file () { # Declare an array to define the options of this helper. local legacy_args=odm @@ -313,6 +310,8 @@ properly with chmod/chown." >&2 # # usage: ynh_store_file_checksum --file=file # | arg: -f, --file - The file on which the checksum will performed, then stored. +# +# Requires YunoHost version 2.6.4 or higher. ynh_store_file_checksum () { # Declare an array to define the options of this helper. local legacy_args=f @@ -343,8 +342,9 @@ ynh_store_file_checksum () { # # usage: ynh_backup_if_checksum_is_different --file=file # | arg: -f, --file - The file on which the checksum test will be perfomed. +# | ret: the name of a backup file, or nothing # -# | ret: Return the name a the backup file, or nothing +# Requires YunoHost version 2.6.4 or higher. ynh_backup_if_checksum_is_different () { # Declare an array to define the options of this helper. local legacy_args=f @@ -376,6 +376,8 @@ ynh_backup_if_checksum_is_different () { # # usage: ynh_remove_file_checksum file # | arg: -f, --file= - The file for which the checksum will be deleted +# +# Requires YunoHost version 3.3.1 or higher. ynh_delete_file_checksum () { # Declare an array to define the options of this helper. local legacy_args=f @@ -392,6 +394,8 @@ ynh_delete_file_checksum () { # # usage: ynh_secure_remove --file=path_to_remove # | arg: -f, --file - File or directory to remove +# +# Requires YunoHost version 2.6.4 or higher. ynh_secure_remove () { # Declare an array to define the options of this helper. local legacy_args=f diff --git a/data/helpers.d/getopts b/data/helpers.d/getopts index 7055325f1..b6cd95f3c 100644 --- a/data/helpers.d/getopts +++ b/data/helpers.d/getopts @@ -43,6 +43,8 @@ # To keep a retrocompatibility, a package can still call a helper, using getopts, with positional arguments. # The "legacy mode" will manage the positional arguments and fill the variable in the same order than they are given in $args_array. # e.g. for `my_helper "val1" val2`, arg1 will be filled with val1, and arg2 with val2. +# +# Requires YunoHost version 3.2.2 or higher. ynh_handle_getopts_args () { # Manage arguments only if there's some provided set +x @@ -150,10 +152,15 @@ ynh_handle_getopts_args () { # If there's already another value for this option, add a ; before adding the new value eval ${option_var}+="\;" fi - # Escape double quote to prevent any interpretation during the eval - all_args[$i]="${all_args[$i]//\"/\\\"}" - eval ${option_var}+=\"${all_args[$i]}\" + # For the record. + # We're using eval here to get the content of the variable stored itself as simple text in $option_var... + # Other ways to get that content would be to use either ${!option_var} or declare -g ${option_var} + # But... ${!option_var} can't be used as left part of an assignation. + # declare -g ${option_var} will create a local variable (despite -g !) and will not be available for the helper itself. + # So... Stop fucking arguing each time that eval is evil... Go find an other working solution if you can find one! + + eval ${option_var}+='"${all_args[$i]}"' shift_value=$(( shift_value + 1 )) fi done @@ -191,12 +198,9 @@ ynh_handle_getopts_args () { # The variable name will be stored in 'option_var' 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 # The values will be stored in the same order than $args_array - eval ${option_var}+=\"${arguments[$i]}\" + eval ${option_var}+='"${arguments[$i]}"' done unset legacy_args else diff --git a/data/helpers.d/ip b/data/helpers.d/ip index c50d8be73..2ca4053d9 100644 --- a/data/helpers.d/ip +++ b/data/helpers.d/ip @@ -7,6 +7,7 @@ # # example: ynh_validate_ip 4 111.222.333.444 # +# Requires YunoHost version 2.2.4 or higher. ynh_validate_ip() { # http://stackoverflow.com/questions/319279/how-to-validate-ip-address-in-python#319298 @@ -40,6 +41,7 @@ EOF # usage: ynh_validate_ip4 --ip_address=ip_address # | ret: 0 for valid ipv4 addresses, 1 otherwise # +# Requires YunoHost version 2.2.4 or higher. ynh_validate_ip4() { # Declare an array to define the options of this helper. @@ -60,6 +62,7 @@ ynh_validate_ip4() # usage: ynh_validate_ip6 --ip_address=ip_address # | ret: 0 for valid ipv6 addresses, 1 otherwise # +# Requires YunoHost version 2.2.4 or higher. ynh_validate_ip6() { # Declare an array to define the options of this helper. diff --git a/data/helpers.d/mysql b/data/helpers.d/mysql index fa1a61dab..d7400db2d 100644 --- a/data/helpers.d/mysql +++ b/data/helpers.d/mysql @@ -11,6 +11,8 @@ MYSQL_ROOT_PWD_FILE=/etc/yunohost/mysql # | arg: -u, --user - the user name to connect as # | arg: -p, --password - the user password # | arg: -d, --database - the database to connect to +# +# Requires YunoHost version 2.2.4 or higher. ynh_mysql_connect_as() { # Declare an array to define the options of this helper. local legacy_args=upd @@ -30,6 +32,8 @@ ynh_mysql_connect_as() { # usage: ynh_mysql_execute_as_root --sql=sql [--database=database] # | arg: -s, --sql - the SQL command to execute # | arg: -d, --database - the database to connect to +# +# Requires YunoHost version 2.2.4 or higher. ynh_mysql_execute_as_root() { # Declare an array to define the options of this helper. local legacy_args=sd @@ -49,6 +53,8 @@ ynh_mysql_execute_as_root() { # usage: ynh_mysql_execute_file_as_root --file=file [--database=database] # | arg: -f, --file - the file containing SQL commands # | arg: -d, --database - the database to connect to +# +# Requires YunoHost version 2.2.4 or higher. ynh_mysql_execute_file_as_root() { # Declare an array to define the options of this helper. local legacy_args=fd @@ -71,6 +77,8 @@ ynh_mysql_execute_file_as_root() { # | arg: db - the database name to create # | arg: user - the user to grant privilegies # | arg: pwd - the password to identify user by +# +# Requires YunoHost version 2.2.4 or higher. ynh_mysql_create_db() { local db=$1 @@ -95,6 +103,8 @@ ynh_mysql_create_db() { # # usage: ynh_mysql_drop_db db # | arg: db - the database name to drop +# +# Requires YunoHost version 2.2.4 or higher. ynh_mysql_drop_db() { ynh_mysql_execute_as_root --sql="DROP DATABASE ${1};" } @@ -106,6 +116,8 @@ ynh_mysql_drop_db() { # usage: ynh_mysql_dump_db --database=database # | arg: -d, --database - the database name to dump # | ret: the mysqldump output +# +# Requires YunoHost version 2.2.4 or higher. ynh_mysql_dump_db() { # Declare an array to define the options of this helper. local legacy_args=d @@ -124,6 +136,8 @@ ynh_mysql_dump_db() { # usage: ynh_mysql_create_user user pwd [host] # | arg: user - the user name to create # | arg: pwd - the password to identify user by +# +# Requires YunoHost version 2.2.4 or higher. ynh_mysql_create_user() { ynh_mysql_execute_as_root \ --sql="CREATE USER '${1}'@'localhost' IDENTIFIED BY '${2}';" @@ -133,6 +147,8 @@ ynh_mysql_create_user() { # # usage: ynh_mysql_user_exists --user=user # | arg: -u, --user - the user for which to check existence +# +# Requires YunoHost version 2.2.4 or higher. ynh_mysql_user_exists() { # Declare an array to define the options of this helper. @@ -156,6 +172,8 @@ ynh_mysql_user_exists() # # usage: ynh_mysql_drop_user user # | arg: user - the user name to drop +# +# Requires YunoHost version 2.2.4 or higher. ynh_mysql_drop_user() { ynh_mysql_execute_as_root --sql="DROP USER '${1}'@'localhost';" } @@ -168,7 +186,9 @@ ynh_mysql_drop_user() { # usage: ynh_mysql_setup_db --db_user=user --db_name=name [--db_pwd=pwd] # | arg: -u, --db_user - Owner of the database # | arg: -n, --db_name - Name of the database -# | arg: -p, --db_pwd - Password of the database. If not given, a password will be generated +# | arg: -p, --db_pwd - Password of the database. If not provided, a password will be generated +# +# Requires YunoHost version 2.6.4 or higher. ynh_mysql_setup_db () { # Declare an array to define the options of this helper. local legacy_args=unp @@ -180,7 +200,7 @@ ynh_mysql_setup_db () { ynh_handle_getopts_args "$@" local new_db_pwd=$(ynh_string_random) # Generate a random password - # If $db_pwd is not given, use new_db_pwd instead for db_pwd + # If $db_pwd is not provided, use new_db_pwd instead for db_pwd db_pwd="${db_pwd:-$new_db_pwd}" ynh_mysql_create_db "$db_name" "$db_user" "$db_pwd" # Create the database @@ -192,6 +212,8 @@ ynh_mysql_setup_db () { # usage: ynh_mysql_remove_db --db_user=user --db_name=name # | arg: -u, --db_user - Owner of the database # | arg: -n, --db_name - Name of the database +# +# Requires YunoHost version 2.6.4 or higher. ynh_mysql_remove_db () { # Declare an array to define the options of this helper. local legacy_args=un @@ -223,6 +245,8 @@ ynh_mysql_remove_db () { # usage: ynh_sanitize_dbid --db_name=name # | arg: -n, --db_name - name to correct/sanitize # | ret: the corrected name +# +# Requires YunoHost version 2.2.4 or higher. ynh_sanitize_dbid () { # Declare an array to define the options of this helper. local legacy_args=n diff --git a/data/helpers.d/network b/data/helpers.d/network index a765d6346..4dc080203 100644 --- a/data/helpers.d/network +++ b/data/helpers.d/network @@ -1,17 +1,21 @@ #!/bin/bash # Normalize the url path syntax +# # Handle the slash at the beginning of path and its absence at ending # Return a normalized url path # -# example: url_path=$(ynh_normalize_url_path $url_path) -# ynh_normalize_url_path example -> /example -# ynh_normalize_url_path /example -> /example -# ynh_normalize_url_path /example/ -> /example -# ynh_normalize_url_path / -> / +# examples: +# url_path=$(ynh_normalize_url_path $url_path) +# ynh_normalize_url_path example # -> /example +# ynh_normalize_url_path /example # -> /example +# ynh_normalize_url_path /example/ # -> /example +# ynh_normalize_url_path / # -> / # # usage: ynh_normalize_url_path --path_url=path_to_normalize # | arg: -p, --path_url - URL path to normalize before using it +# +# Requires YunoHost version 2.6.4 or higher. ynh_normalize_url_path () { # Declare an array to define the options of this helper. local legacy_args=p @@ -36,6 +40,8 @@ ynh_normalize_url_path () { # # usage: ynh_find_port --port=begin_port # | arg: -p, --port - port to start to search +# +# Requires YunoHost version 2.6.4 or higher. ynh_find_port () { # Declare an array to define the options of this helper. local legacy_args=p @@ -59,6 +65,8 @@ ynh_find_port () { # usage: ynh_webpath_available --domain=domain --path_url=path # | arg: -d, --domain - the domain/host of the url # | arg: -p, --path_url - the web path to check the availability of +# +# Requires YunoHost version 2.6.4 or higher. ynh_webpath_available () { # Declare an array to define the options of this helper. local legacy_args=dp @@ -79,6 +87,8 @@ ynh_webpath_available () { # | arg: -a, --app - the app for which the domain should be registered # | arg: -d, --domain - the domain/host of the web path # | arg: -p, --path_url - the web path to be registered +# +# Requires YunoHost version 2.6.4 or higher. ynh_webpath_register () { # Declare an array to define the options of this helper. local legacy_args=adp diff --git a/data/helpers.d/nodejs b/data/helpers.d/nodejs index 098ed4410..6833b7593 100644 --- a/data/helpers.d/nodejs +++ b/data/helpers.d/nodejs @@ -10,6 +10,8 @@ export N_PREFIX="$n_install_dir" # [internal] # # usage: ynh_install_n +# +# Requires YunoHost version 2.7.12 or higher. ynh_install_n () { echo "Installation of N - Node.js version management" >&2 # Build an app.src for n @@ -36,6 +38,8 @@ SOURCE_SUM=2ba3c9d4dd3c7e38885b37e02337906a1ee91febe6d5c9159d89a9050f2eea8f" > " # That's means it has to be added to any systemd script. # # usage: ynh_use_nodejs +# +# Requires YunoHost version 2.7.12 or higher. ynh_use_nodejs () { nodejs_version=$(ynh_app_setting_get --app=$app --key=nodejs_version) @@ -59,6 +63,8 @@ ynh_use_nodejs () { # | 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). # The crontab will handle the update of minor versions when needed. +# +# Requires YunoHost version 2.7.12 or higher. ynh_install_nodejs () { # Use n, https://github.com/tj/n to manage the nodejs versions @@ -117,7 +123,7 @@ ynh_install_nodejs () { fi # Store the ID of this app and the version of node requested for it - echo "$YNH_APP_ID:$nodejs_version" | tee --append "$n_install_dir/ynh_app_version" + echo "$YNH_APP_INSTANCE_NAME:$nodejs_version" | tee --append "$n_install_dir/ynh_app_version" # Store nodejs_version into the config of this app ynh_app_setting_set --app=$app --key=nodejs_version --value=$nodejs_version @@ -135,11 +141,13 @@ ynh_install_nodejs () { # If no other app uses node, n will be also removed. # # usage: ynh_remove_nodejs +# +# Requires YunoHost version 2.7.12 or higher. ynh_remove_nodejs () { nodejs_version=$(ynh_app_setting_get --app=$app --key=nodejs_version) # 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_INSTANCE_NAME:$nodejs_version/d" "$n_install_dir/ynh_app_version" # If no other app uses this version of nodejs, remove it. if ! grep --quiet "$nodejs_version" "$n_install_dir/ynh_app_version" @@ -164,6 +172,8 @@ ynh_remove_nodejs () { # This cron will check and update all minor node versions used by your apps. # # usage: ynh_cron_upgrade_node +# +# Requires YunoHost version 2.7.12 or higher. ynh_cron_upgrade_node () { # Build the update script cat > "$n_install_dir/node_update.sh" << EOF diff --git a/data/helpers.d/package b/data/helpers.d/package index 000b0ee74..9c2b58458 100644 --- a/data/helpers.d/package +++ b/data/helpers.d/package @@ -5,6 +5,8 @@ # [internal] # # usage: ynh_wait_dpkg_free +# +# Requires YunoHost version 3.3.1 or higher. ynh_wait_dpkg_free() { local try # With seq 1 17, timeout will be almost 30 minutes @@ -44,6 +46,8 @@ ynh_wait_dpkg_free() { # # usage: ynh_package_is_installed --package=name # | arg: -p, --package - the package name to check +# +# Requires YunoHost version 2.2.4 or higher. ynh_package_is_installed() { # Declare an array to define the options of this helper. local legacy_args=p @@ -64,6 +68,8 @@ ynh_package_is_installed() { # usage: ynh_package_version --package=name # | arg: -p, --package - the package name to get version # | ret: the version or an empty string +# +# Requires YunoHost version 2.2.4 or higher. ynh_package_version() { # Declare an array to define the options of this helper. local legacy_args=p @@ -84,6 +90,8 @@ ynh_package_version() { # [internal] # # usage: ynh_apt update +# +# Requires YunoHost version 2.4.0.3 or higher. ynh_apt() { ynh_wait_dpkg_free DEBIAN_FRONTEND=noninteractive apt-get -y $@ @@ -92,6 +100,8 @@ ynh_apt() { # Update package index files # # usage: ynh_package_update +# +# Requires YunoHost version 2.2.4 or higher. ynh_package_update() { ynh_apt update } @@ -100,6 +110,8 @@ ynh_package_update() { # # usage: ynh_package_install name [name [...]] # | arg: name - the package name to install +# +# Requires YunoHost version 2.2.4 or higher. ynh_package_install() { ynh_apt --no-remove -o Dpkg::Options::=--force-confdef \ -o Dpkg::Options::=--force-confold install $@ @@ -109,6 +121,8 @@ ynh_package_install() { # # usage: ynh_package_remove name [name [...]] # | arg: name - the package name to remove +# +# Requires YunoHost version 2.2.4 or higher. ynh_package_remove() { ynh_apt remove $@ } @@ -117,6 +131,8 @@ ynh_package_remove() { # # usage: ynh_package_autoremove name [name [...]] # | arg: name - the package name to remove +# +# Requires YunoHost version 2.2.4 or higher. ynh_package_autoremove() { ynh_apt autoremove $@ } @@ -125,6 +141,8 @@ ynh_package_autoremove() { # # usage: ynh_package_autopurge name [name [...]] # | arg: name - the package name to autoremove and purge +# +# Requires YunoHost version 2.7.2 or higher. ynh_package_autopurge() { ynh_apt autoremove --purge $@ } @@ -139,6 +157,8 @@ ynh_package_autopurge() { # # usage: ynh_package_install_from_equivs controlfile # | arg: controlfile - path of the equivs control file +# +# Requires YunoHost version 2.2.4 or higher. ynh_package_install_from_equivs () { local controlfile=$1 @@ -181,6 +201,8 @@ ynh_package_install_from_equivs () { # You can give a choice between some package with this syntax : "dep1|dep2" # Example : ynh_install_app_dependencies dep1 dep2 "dep3|dep4|dep5" # This mean in the dependence tree : dep1 & dep2 & (dep3 | dep4 | dep5) +# +# Requires YunoHost version 2.6.4 or higher. ynh_install_app_dependencies () { local dependencies=$@ local dependencies=${dependencies// /, } @@ -217,6 +239,8 @@ EOF # Dependencies will removed only if no other package need them. # # usage: ynh_remove_app_dependencies +# +# Requires YunoHost version 2.6.4 or higher. ynh_remove_app_dependencies () { local dep_app=${app//_/-} # Replace all '_' by '-' ynh_package_autopurge ${dep_app}-ynh-deps # Remove the fake package and its dependencies if they not still used. diff --git a/data/helpers.d/print b/data/helpers.d/print index 7f37021ae..468c41e96 100644 --- a/data/helpers.d/print +++ b/data/helpers.d/print @@ -2,6 +2,8 @@ # Print a message to stderr and exit # usage: ynh_die --message=MSG [--ret_code=RETCODE] +# +# Requires YunoHost version 2.4.0 or higher. ynh_die() { # Declare an array to define the options of this helper. local legacy_args=mc @@ -18,6 +20,8 @@ ynh_die() { # Display a message in the 'INFO' logging category # # usage: ynh_print_info --message="Some message" +# +# Requires YunoHost version 3.2.0 or higher. ynh_print_info() { # Declare an array to define the options of this helper. local legacy_args=m @@ -37,6 +41,8 @@ ynh_print_info() { # # Simply duplicate the log, execute the yunohost command and replace the log without the result of this command # It's a very badly hack... +# +# Requires YunoHost version 2.6.4 or higher. ynh_no_log() { local ynh_cli_log=/var/log/yunohost/yunohost-cli.log sudo cp -a ${ynh_cli_log} ${ynh_cli_log}-move @@ -50,6 +56,7 @@ ynh_no_log() { # # [internal] # +# Requires YunoHost version 3.2.0 or higher. ynh_print_log () { echo -e "${1}" } @@ -58,6 +65,8 @@ ynh_print_log () { # # usage: ynh_print_warn --message="Text to print" # | arg: -m, --message - The text to print +# +# Requires YunoHost version 3.2.0 or higher. ynh_print_warn () { # Declare an array to define the options of this helper. local legacy_args=m @@ -73,6 +82,8 @@ ynh_print_warn () { # # usage: ynh_print_err --message="Text to print" # | arg: -m, --message - The text to print +# +# Requires YunoHost version 3.2.0 or higher. ynh_print_err () { # Declare an array to define the options of this helper. local legacy_args=m @@ -89,8 +100,11 @@ ynh_print_err () { # usage: ynh_exec_err command to execute # usage: ynh_exec_err "command to execute | following command" # In case of use of pipes, you have to use double quotes. Otherwise, this helper will be executed with the first command, then be sent to the next pipe. +# If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed. # # | arg: command - command to execute +# +# Requires YunoHost version 3.2.0 or higher. ynh_exec_err () { ynh_print_err "$(eval $@)" } @@ -100,8 +114,11 @@ ynh_exec_err () { # usage: ynh_exec_warn command to execute # usage: ynh_exec_warn "command to execute | following command" # In case of use of pipes, you have to use double quotes. Otherwise, this helper will be executed with the first command, then be sent to the next pipe. +# If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed. # # | arg: command - command to execute +# +# Requires YunoHost version 3.2.0 or higher. ynh_exec_warn () { ynh_print_warn "$(eval $@)" } @@ -111,8 +128,11 @@ ynh_exec_warn () { # usage: ynh_exec_warn_less command to execute # usage: ynh_exec_warn_less "command to execute | following command" # In case of use of pipes, you have to use double quotes. Otherwise, this helper will be executed with the first command, then be sent to the next pipe. +# If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed. # # | arg: command - command to execute +# +# Requires YunoHost version 3.2.0 or higher. ynh_exec_warn_less () { eval $@ 2>&1 } @@ -122,8 +142,11 @@ ynh_exec_warn_less () { # usage: ynh_exec_quiet command to execute # usage: ynh_exec_quiet "command to execute | following command" # In case of use of pipes, you have to use double quotes. Otherwise, this helper will be executed with the first command, then be sent to the next pipe. +# If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed. # # | arg: command - command to execute +# +# Requires YunoHost version 3.2.0 or higher. ynh_exec_quiet () { eval $@ > /dev/null } @@ -133,8 +156,11 @@ ynh_exec_quiet () { # usage: ynh_exec_fully_quiet command to execute # usage: ynh_exec_fully_quiet "command to execute | following command" # In case of use of pipes, you have to use double quotes. Otherwise, this helper will be executed with the first command, then be sent to the next pipe. +# If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed. # # | arg: command - command to execute +# +# Requires YunoHost version 3.2.0 or higher. ynh_exec_fully_quiet () { eval $@ > /dev/null 2>&1 } @@ -143,6 +169,8 @@ ynh_exec_fully_quiet () { # # usage: ynh_print_OFF # WARNING: You should be careful with this helper, and never forget to use ynh_print_ON as soon as possible to restore the logging. +# +# Requires YunoHost version 3.2.0 or higher. ynh_print_OFF () { set +x } @@ -150,6 +178,8 @@ ynh_print_OFF () { # Restore the logging after ynh_print_OFF # # usage: ynh_print_ON +# +# Requires YunoHost version 3.2.0 or higher. ynh_print_ON () { set -x # Print an echo only for the log, to be able to know that ynh_print_ON has been called. @@ -162,13 +192,17 @@ ynh_print_ON () { # | 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. +# The execution time is given for the duration since the previous call. So the weight should be applied to this previous call. # | arg: -l, --last= - Use for the last call of the helper, to fill te progression bar. +# +# Requires YunoHost version 3.?.? or higher. 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. + local legacy_args=mwtl declare -Ar args_array=( [m]=message= [w]=weight= [t]=time [l]=last ) local message local weight @@ -190,9 +224,9 @@ ynh_script_progression () { 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')" + 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 )) diff --git a/data/helpers.d/psql b/data/helpers.d/psql index 2ef13482a..c5e065f07 100644 --- a/data/helpers.d/psql +++ b/data/helpers.d/psql @@ -1,21 +1,277 @@ +#!/bin/bash + +PSQL_ROOT_PWD_FILE=/etc/yunohost/psql + +# Open a connection as a user +# +# example: ynh_psql_connect_as 'user' 'pass' <<< "UPDATE ...;" +# example: ynh_psql_connect_as 'user' 'pass' < /path/to/file.sql +# +# usage: ynh_psql_connect_as --user=user --password=password [--database=database] +# | arg: -u, --user - the user name to connect as +# | arg: -p, --password - the user password +# | arg: -d, --database - the database to connect to +# +# Requires YunoHost version 3.?.? or higher. +ynh_psql_connect_as() { + # 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:-}" + + sudo --login --user=postgres PGUSER="$user" PGPASSWORD="$password" psql "$database" +} + +# Execute a command as root user +# +# usage: ynh_psql_execute_as_root --sql=sql [--database=database] +# | arg: -s, --sql - the SQL command to execute +# | arg: -d, --database - the database to connect to +# +# Requires YunoHost version 3.?.? or higher. +ynh_psql_execute_as_root() { + # Declare an array to define the options of this helper. + 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_psql_connect_as --user="postgres" --password="$(sudo cat $PSQL_ROOT_PWD_FILE)" \ + --database="$database" <<<"$sql" +} + +# Execute a command from a file as root user +# +# usage: ynh_psql_execute_file_as_root --file=file [--database=database] +# | arg: -f, --file - the file containing SQL commands +# | arg: -d, --database - the database to connect to +# +# Requires YunoHost version 3.?.? or higher. +ynh_psql_execute_file_as_root() { + # Declare an array to define the options of this helper. + 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_psql_connect_as --user="postgres" --password="$(sudo cat $PSQL_ROOT_PWD_FILE)" \ + --database="$database" <"$file" +} + +# Create a database and grant optionnaly privilegies to a user +# +# [internal] +# +# usage: ynh_psql_create_db db [user] +# | arg: db - the database name to create +# | arg: user - the user to grant privilegies +# +# Requires YunoHost version 3.?.? or higher. +ynh_psql_create_db() { + local db=$1 + local user=${2:-} + + local sql="CREATE DATABASE ${db};" + + # grant all privilegies to user + if [ -n "$user" ]; then + sql+="GRANT ALL PRIVILEGES ON DATABASE ${db} TO ${user} WITH GRANT OPTION;" + fi + + ynh_psql_execute_as_root --sql="$sql" +} + +# Drop a database +# +# [internal] +# +# If you intend to drop the database *and* the associated user, +# consider using ynh_psql_remove_db instead. +# +# usage: ynh_psql_drop_db db +# | arg: db - the database name to drop +# +# Requires YunoHost version 3.?.? or higher. +ynh_psql_drop_db() { + local db=$1 + sudo --login --user=postgres dropdb $db +} + +# Dump a database +# +# example: ynh_psql_dump_db 'roundcube' > ./dump.sql +# +# usage: ynh_psql_dump_db --database=database +# | arg: -d, --database - the database name to dump +# | ret: the psqldump output +# +# Requires YunoHost version 3.?.? or higher. +ynh_psql_dump_db() { + # 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 "$@" + + sudo --login --user=postgres pg_dump "$database" +} + +# Create a user +# +# [internal] +# +# usage: ynh_psql_create_user user pwd +# | arg: user - the user name to create +# | arg: pwd - the password to identify user by +# +# Requires YunoHost version 3.?.? or higher. +ynh_psql_create_user() { + local user=$1 + local pwd=$2 + ynh_psql_execute_as_root --sql="CREATE USER $user WITH ENCRYPTED PASSWORD '$pwd'" +} + +# Check if a psql user exists +# +# usage: ynh_psql_user_exists --user=user +# | arg: -u, --user - the user for which to check existence +ynh_psql_user_exists() { + # Declare an array to define the options of this helper. + local legacy_args=u + declare -Ar args_array=([u]=user=) + local user + # Manage arguments with getopts + ynh_handle_getopts_args "$@" + + if ! sudo --login --user=postgres PGUSER="postgres" PGPASSWORD="$(sudo cat $PSQL_ROOT_PWD_FILE)" psql -tAc "SELECT rolname FROM pg_roles WHERE rolname='$user';" | grep --quiet "$user" ; then + return 1 + else + return 0 + fi +} + +# Check if a psql database exists +# +# usage: ynh_psql_database_exists --database=database +# | arg: -d, --database - the database for which to check existence +ynh_psql_database_exists() { + # 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 "$@" + + if ! sudo --login --user=postgres PGUSER="postgres" PGPASSWORD="$(sudo cat $PSQL_ROOT_PWD_FILE)" psql -tAc "SELECT datname FROM pg_database WHERE datname='$database';" | grep --quiet "$database"; then + return 1 + else + return 0 + fi +} + +# Drop a user +# +# [internal] +# +# usage: ynh_psql_drop_user user +# | arg: user - the user name to drop +# +# Requires YunoHost version 3.?.? or higher. +ynh_psql_drop_user() { + ynh_psql_execute_as_root --sql="DROP USER ${1};" +} + +# Create a database, an user and its password. Then store the password in the app's config +# +# After executing this helper, the password of the created database will be available in $db_pwd +# It will also be stored as "psqlpwd" into the app settings. +# +# usage: ynh_psql_setup_db --db_user=user --db_name=name [--db_pwd=pwd] +# | arg: -u, --db_user - Owner of the database +# | arg: -n, --db_name - Name of the database +# | arg: -p, --db_pwd - Password of the database. If not given, a password will be generated +ynh_psql_setup_db() { + # Declare an array to define the options of this helper. + 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 + # If $db_pwd is not given, use new_db_pwd instead for db_pwd + db_pwd="${db_pwd:-$new_db_pwd}" + + if ! ynh_psql_user_exists --user=$db_user; then + ynh_psql_create_user "$db_user" "$db_pwd" + fi + + ynh_psql_create_db "$db_name" "$db_user" # Create the database + ynh_app_setting_set --app=$app --key=psqlpwd --value=$db_pwd # Store the password in the app's config +} + +# Remove a database if it exists, and the associated user +# +# usage: ynh_psql_remove_db --db_user=user --db_name=name +# | arg: -u, --db_user - Owner of the database +# | arg: -n, --db_name - Name of the database +ynh_psql_remove_db() { + # Declare an array to define the options of this helper. + 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 psql_root_password=$(sudo cat $PSQL_ROOT_PWD_FILE) + if ynh_psql_database_exists --database=$db_name; then # Check if the database exists + echo "Removing database $db_name" >&2 + ynh_psql_drop_db $db_name # Remove the database + else + echo "Database $db_name not found" >&2 + fi + + # Remove psql user if it exists + if ynh_psql_user_exists --user=$db_user; then + echo "Removing user $db_user" >&2 + ynh_psql_drop_user $db_user + else + echo "User $db_user not found" >&2 + fi +} + # Create a master password and set up global settings # Please always call this script in install and restore scripts # # usage: ynh_psql_test_if_first_run ynh_psql_test_if_first_run() { - if [ -f /etc/yunohost/psql ]; - then + if [ -f "$PSQL_ROOT_PWD_FILE" ]; then echo "PostgreSQL is already installed, no need to create master password" else local pgsql="$(ynh_string_random)" - echo "$pgsql" > /etc/yunohost/psql + echo "$pgsql" >/etc/yunohost/psql - if [ -e /etc/postgresql/9.4/ ] - then + if [ -e /etc/postgresql/9.4/ ]; then local pg_hba=/etc/postgresql/9.4/main/pg_hba.conf - elif [ -e /etc/postgresql/9.6/ ] - then + local logfile=/var/log/postgresql/postgresql-9.4-main.log + elif [ -e /etc/postgresql/9.6/ ]; then local pg_hba=/etc/postgresql/9.6/main/pg_hba.conf + local logfile=/var/log/postgresql/postgresql-9.6-main.log else ynh_die "postgresql shoud be 9.4 or 9.6" fi @@ -27,122 +283,12 @@ ynh_psql_test_if_first_run() { # https://www.postgresql.org/docs/current/static/auth-pg-hba-conf.html#EXAMPLE-PG-HBA.CONF # Note: we can't use peer since YunoHost create users with nologin # See: https://github.com/YunoHost/yunohost/blob/unstable/data/helpers.d/user - sed -i '/local\s*all\s*all\s*peer/i \ - local all all password' "$pg_hba" + ynh_replace_string --match_string="local\(\s*\)all\(\s*\)all\(\s*\)peer" --replace_string="local\1all\2all\3password" --target_file="$pg_hba" + + # Advertise service in admin panel + yunohost service add postgresql --log "$logfile" + systemctl enable postgresql systemctl reload postgresql fi } - -# Open a connection as a user -# -# example: ynh_psql_connect_as 'user' 'pass' <<< "UPDATE ...;" -# example: ynh_psql_connect_as 'user' 'pass' < /path/to/file.sql -# -# usage: ynh_psql_connect_as user pwd [db] -# | arg: user - the user name to connect as -# | arg: pwd - the user password -# | arg: db - the database to connect to -ynh_psql_connect_as() { - local user="$1" - local pwd="$2" - local db="$3" - sudo --login --user=postgres PGUSER="$user" PGPASSWORD="$pwd" psql "$db" -} - -# # Execute a command as root user -# -# usage: ynh_psql_execute_as_root sql [db] -# | arg: sql - the SQL command to execute -ynh_psql_execute_as_root () { - local sql="$1" - sudo --login --user=postgres psql <<< "$sql" -} - -# Execute a command from a file as root user -# -# usage: ynh_psql_execute_file_as_root file [db] -# | arg: file - the file containing SQL commands -# | arg: db - the database to connect to -ynh_psql_execute_file_as_root() { - local file="$1" - local db="$2" - sudo --login --user=postgres psql "$db" < "$file" -} - -# Create a database, an user and its password. Then store the password in the app's config -# -# After executing this helper, the password of the created database will be available in $db_pwd -# It will also be stored as "psqlpwd" into the app settings. -# -# usage: ynh_psql_setup_db user name [pwd] -# | arg: user - Owner of the database -# | arg: name - Name of the database -# | arg: pwd - Password of the database. If not given, a password will be generated -ynh_psql_setup_db () { - local db_user="$1" - local db_name="$2" - local new_db_pwd=$(ynh_string_random) # Generate a random password - # If $3 is not given, use new_db_pwd instead for db_pwd. - local db_pwd="${3:-$new_db_pwd}" - ynh_psql_create_db "$db_name" "$db_user" "$db_pwd" # Create the database - ynh_app_setting_set "$app" psqlpwd "$db_pwd" # Store the password in the app's config -} - -# Create a database and grant privilegies to a user -# -# usage: ynh_psql_create_db db [user [pwd]] -# | arg: db - the database name to create -# | arg: user - the user to grant privilegies -# | arg: pwd - the user password -ynh_psql_create_db() { - local db="$1" - local user="$2" - local pwd="$3" - ynh_psql_create_user "$user" "$pwd" - sudo --login --user=postgres createdb --owner="$user" "$db" -} - -# Drop a database -# -# usage: ynh_psql_drop_db db -# | arg: db - the database name to drop -# | arg: user - the user to drop -ynh_psql_remove_db() { - local db="$1" - local user="$2" - sudo --login --user=postgres dropdb "$db" - ynh_psql_drop_user "$user" -} - -# Dump a database -# -# example: ynh_psql_dump_db 'roundcube' > ./dump.sql -# -# usage: ynh_psql_dump_db db -# | arg: db - the database name to dump -# | ret: the psqldump output -ynh_psql_dump_db() { - local db="$1" - sudo --login --user=postgres pg_dump "$db" -} - - -# Create a user -# -# usage: ynh_psql_create_user user pwd [host] -# | arg: user - the user name to create -ynh_psql_create_user() { - local user="$1" - local pwd="$2" - sudo --login --user=postgres psql -c"CREATE USER $user WITH PASSWORD '$pwd'" postgres -} - -# Drop a user -# -# usage: ynh_psql_drop_user user -# | arg: user - the user name to drop -ynh_psql_drop_user() { - local user="$1" - sudo --login --user=postgres dropuser "$user" -} diff --git a/data/helpers.d/setting b/data/helpers.d/setting index 6f75f6c80..63d9104f3 100644 --- a/data/helpers.d/setting +++ b/data/helpers.d/setting @@ -5,6 +5,8 @@ # usage: ynh_app_setting_get --app=app --key=key # | arg: -a, --app - the application id # | arg: -k, --key - the setting to get +# +# Requires YunoHost version 2.2.4 or higher. ynh_app_setting_get() { # Declare an array to define the options of this helper. local legacy_args=ak @@ -14,7 +16,7 @@ ynh_app_setting_get() { # Manage arguments with getopts ynh_handle_getopts_args "$@" - sudo yunohost app setting "$app" "$key" --output-as plain --quiet + ynh_app_setting "get" "$app" "$key" } # Set an application setting @@ -23,6 +25,8 @@ ynh_app_setting_get() { # | arg: -a, --app - the application id # | arg: -k, --key - the setting name to set # | arg: -v, --value - the setting value to set +# +# Requires YunoHost version 2.2.4 or higher. ynh_app_setting_set() { # Declare an array to define the options of this helper. local legacy_args=akv @@ -33,7 +37,7 @@ ynh_app_setting_set() { # Manage arguments with getopts ynh_handle_getopts_args "$@" - sudo yunohost app setting "$app" "$key" --value="$value" --quiet + ynh_app_setting "set" "$app" "$key" "$value" } # Delete an application setting @@ -41,6 +45,8 @@ ynh_app_setting_set() { # usage: ynh_app_setting_delete --app=app --key=key # | arg: -a, --app - the application id # | arg: -k, --key - the setting to delete +# +# Requires YunoHost version 2.2.4 or higher. ynh_app_setting_delete() { # Declare an array to define the options of this helper. local legacy_args=ak @@ -50,5 +56,38 @@ ynh_app_setting_delete() { # Manage arguments with getopts ynh_handle_getopts_args "$@" - sudo yunohost app setting -d "$app" "$key" --quiet + ynh_app_setting "delete" "$app" "$key" +} + +# Small "hard-coded" interface to avoid calling "yunohost app" directly each +# time dealing with a setting is needed (which may be so slow on ARM boards) +# +# [internal] +# +ynh_app_setting() +{ + ACTION="$1" APP="$2" KEY="$3" VALUE="${4:-}" python - < "$templog" & + # Get the PID of the journalctl command + local pid_tail=$! + else + # Read the specified log file + tail -F -n0 "$log_path" > "$templog" 2>&1 & + # Get the PID of the tail command + local pid_tail=$! + fi + fi + + ynh_print_info --message="${action^} the service $service_name" + + # Use reload-or-restart instead of reload. So it wouldn't fail if the service isn't running. + if [ "$action" == "reload" ]; then + action="reload-or-restart" + fi + + systemctl $action $service_name \ + || ( journalctl --no-pager --lines=$length -u $service_name >&2 \ + ; test -e "$log_path" && echo "--" >&2 && tail --lines=$length "$log_path" >&2 \ + ; false ) + + # Start the timeout and try to find line_match + if [[ -n "${line_match:-}" ]] + then + local i=0 + for i in $(seq 1 $timeout) + do + # Read the log until the sentence is found, that means the app finished to start. Or run until the timeout + if grep --quiet "$line_match" "$templog" + then + ynh_print_info --message="The service $service_name has correctly started." + break + fi + if [ $i -eq 3 ]; then + echo -n "Please wait, the service $service_name is ${action}ing" >&2 + fi + if [ $i -ge 3 ]; then + echo -n "." >&2 + fi + sleep 1 + done + if [ $i -ge 3 ]; then + echo "" >&2 + fi + if [ $i -eq $timeout ] + then + ynh_print_warn --message="The service $service_name didn't fully started before the timeout." + ynh_print_warn --message="Please find here an extract of the end of the log of the service $service_name:" + journalctl --no-pager --lines=$length -u $service_name >&2 + test -e "$log_path" && echo "--" >&2 && tail --lines=$length "$log_path" >&2 + fi + ynh_clean_check_starting + fi +} + +# Clean temporary process and file used by ynh_check_starting +# (usually used in ynh_clean_setup scripts) +# +# usage: ynh_clean_check_starting +ynh_clean_check_starting () { + # Stop the execution of tail. + kill -s 15 $pid_tail 2>&1 + ynh_secure_remove "$templog" 2>&1 +} + # Read the value of a key in a ynh manifest file # # usage: ynh_read_manifest manifest key # | arg: -m, --manifest= - Path of the manifest to read # | arg: -k, --key= - Name of the key to find +# +# Requires YunoHost version 3.?.? or higher. ynh_read_manifest () { # Declare an array to define the options of this helper. + local legacy_args=mk declare -Ar args_array=( [m]=manifest= [k]=manifest_key= ) local manifest local manifest_key @@ -85,7 +199,11 @@ ynh_read_manifest () { # # usage: ynh_app_upstream_version [-m manifest] # | arg: -m, --manifest= - Path of the manifest to read +# +# Requires YunoHost version 3.?.? or higher. ynh_app_upstream_version () { + # Declare an array to define the options of this helper. + local legacy_args=m declare -Ar args_array=( [m]=manifest= ) local manifest # Manage arguments with getopts @@ -104,7 +222,11 @@ ynh_app_upstream_version () { # # usage: ynh_app_package_version [-m manifest] # | arg: -m, --manifest= - Path of the manifest to read +# +# Requires YunoHost version 3.?.? or higher. ynh_app_package_version () { + # Declare an array to define the options of this helper. + local legacy_args=m declare -Ar args_array=( [m]=manifest= ) local manifest # Manage arguments with getopts @@ -119,7 +241,7 @@ ynh_app_package_version () { # - UPGRADE_APP if the upstream app version has changed # - UPGRADE_PACKAGE if only the YunoHost package has changed # -## It stops the current script without error if the package is up-to-date +# It stops the current script without error if the package is up-to-date # # This helper should be used to avoid an upgrade of an app, or the upstream part # of it, when it's not needed @@ -129,6 +251,8 @@ ynh_app_package_version () { # example: sudo YNH_FORCE_UPGRADE=1 yunohost app upgrade MyApp # # usage: ynh_check_app_version_changed +# +# Requires YunoHost version 3.?.? or higher. ynh_check_app_version_changed () { local force_upgrade=${YNH_FORCE_UPGRADE:-0} local package_check=${PACKAGE_CHECK_EXEC:-0} diff --git a/data/helpers.d/user b/data/helpers.d/user index d716bf03b..9ee44515d 100644 --- a/data/helpers.d/user +++ b/data/helpers.d/user @@ -6,6 +6,8 @@ # # usage: ynh_user_exists --username=username # | arg: -u, --username - the username to check +# +# Requires YunoHost version 2.2.4 or higher. ynh_user_exists() { # Declare an array to define the options of this helper. local legacy_args=u @@ -25,6 +27,8 @@ ynh_user_exists() { # | arg: -u, --username - the username to retrieve info from # | arg: -k, --key - the key to retrieve # | ret: string - the key's value +# +# Requires YunoHost version 2.2.4 or higher. ynh_user_get_info() { # Declare an array to define the options of this helper. local legacy_args=uk @@ -43,6 +47,8 @@ ynh_user_get_info() { # # usage: ynh_user_list # | ret: string - one username per line +# +# Requires YunoHost version 2.4.0 or higher. ynh_user_list() { sudo yunohost user list --output-as plain --quiet \ | awk '/^##username$/{getline; print}' @@ -52,6 +58,8 @@ ynh_user_list() { # # usage: ynh_system_user_exists --username=username # | arg: -u, --username - the username to check +# +# Requires YunoHost version 2.2.4 or higher. ynh_system_user_exists() { # Declare an array to define the options of this helper. local legacy_args=u @@ -63,19 +71,35 @@ ynh_system_user_exists() { getent passwd "$username" &>/dev/null } +# Check if a group exists on the system +# +# usage: ynh_system_group_exists --group=group +# | arg: -g, --group - the group to check +ynh_system_group_exists() { + # Declare an array to define the options of this helper. + local legacy_args=g + declare -Ar args_array=( [g]=group= ) + local group + # Manage arguments with getopts + ynh_handle_getopts_args "$@" + + getent group "$group" &>/dev/null +} + # Create a system user # # examples: -# - ynh_system_user_create --username=nextcloud -> creates a nextcloud user with -# 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 +# # Create a nextcloud user with no home directory and /usr/sbin/nologin login shell (hence no login capability) +# ynh_system_user_create --username=nextcloud +# # Create a discourse user using /var/www/discourse as home directory and the default login shell +# ynh_system_user_create --username=discourse --home_dir=/var/www/discourse --use_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 +# | 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 +# +# Requires YunoHost version 2.6.4 or higher. ynh_system_user_create () { # Declare an array to define the options of this helper. local legacy_args=uhs @@ -108,6 +132,8 @@ ynh_system_user_create () { # # usage: ynh_system_user_delete --username=user_name # | arg: -u, --username - Name of the system user that will be create +# +# Requires YunoHost version 2.6.4 or higher. ynh_system_user_delete () { # Declare an array to define the options of this helper. local legacy_args=u @@ -116,11 +142,19 @@ ynh_system_user_delete () { # Manage arguments with getopts ynh_handle_getopts_args "$@" - if ynh_system_user_exists "$username" # Check if the user exists on the system + # Check if the user exists on the system + if ynh_system_user_exists "$username" then echo "Remove the user $username" >&2 - sudo userdel $username + deluser $username else echo "The user $username was not found" >&2 fi + + # Check if the group exists on the system + if ynh_system_group_exists "$username" + then + echo "Remove the group $username" >&2 + delgroup $username + fi } diff --git a/data/helpers.d/utils b/data/helpers.d/utils index 5ba2946a2..5f5e61015 100644 --- a/data/helpers.d/utils +++ b/data/helpers.d/utils @@ -6,6 +6,8 @@ # # usage: ynh_get_plain_key key [subkey [subsubkey ...]] # | ret: string - the key's value +# +# Requires YunoHost version 2.2.4 or higher. ynh_get_plain_key() { local prefix="#" local founded=0 @@ -36,6 +38,7 @@ ynh_get_plain_key() { # } # ynh_abort_if_errors # +# Requires YunoHost version 2.7.2 or higher. ynh_restore_upgradebackup () { echo "Upgrade failed." >&2 local app_bck=${app//_/-} # Replace all '_' by '-' @@ -67,6 +70,7 @@ ynh_restore_upgradebackup () { # } # ynh_abort_if_errors # +# Requires YunoHost version 2.7.2 or higher. ynh_backup_before_upgrade () { if [ ! -e "/etc/yunohost/apps/$app/scripts/backup" ] then @@ -150,6 +154,8 @@ ynh_backup_before_upgrade () { # usage: ynh_setup_source --dest_dir=dest_dir [--source_id=source_id] # | arg: -d, --dest_dir - Directory where to setup sources # | arg: -s, --source_id - Name of the app, if the package contains more than one app +# +# Requires YunoHost version 2.6.4 or higher. ynh_setup_source () { # Declare an array to define the options of this helper. local legacy_args=ds @@ -255,6 +261,8 @@ ynh_setup_source () { # | arg: key1=value1 - (Optionnal) POST key and corresponding value # | arg: key2=value2 - (Optionnal) Another POST key and corresponding value # | arg: ... - (Optionnal) More POST keys and values +# +# Requires YunoHost version 2.6.4 or higher. ynh_local_curl () { # Define url of page to curl local local_page=$(ynh_normalize_url_path $1) diff --git a/data/hooks/conf_regen/03-ssh b/data/hooks/conf_regen/03-ssh index 5bb9cf916..54b7c55b7 100755 --- a/data/hooks/conf_regen/03-ssh +++ b/data/hooks/conf_regen/03-ssh @@ -12,7 +12,7 @@ do_pre_regen() { [[ ! -f /etc/yunohost/from_script ]] || return 0 cd /usr/share/yunohost/templates/ssh - + # do not listen to IPv6 if unavailable [[ -f /proc/net/if_inet6 ]] && ipv6_enabled=true || ipv6_enabled=false @@ -23,6 +23,9 @@ do_pre_regen() { ssh_keys="$ssh_keys $(ls /etc/ssh/ssh_host_dsa_key 2>/dev/null || true)" fi + # Support different strategy for security configurations + export compatibility="$(yunohost settings get 'security.ssh.compatibility')" + export ssh_keys export ipv6_enabled ynh_render_template "sshd_config" "${pending_dir}/etc/ssh/sshd_config" diff --git a/data/hooks/conf_regen/15-nginx b/data/hooks/conf_regen/15-nginx index 7ca63c003..59654a771 100755 --- a/data/hooks/conf_regen/15-nginx +++ b/data/hooks/conf_regen/15-nginx @@ -10,7 +10,25 @@ do_init_regen() { exit 1 fi - do_pre_regen "" + cd /usr/share/yunohost/templates/nginx + + nginx_dir="/etc/nginx" + nginx_conf_dir="${nginx_dir}/conf.d" + mkdir -p "$nginx_conf_dir" + + # install plain conf files + cp plain/* "$nginx_conf_dir" + + # probably run with init: just disable default site, restart NGINX and exit + rm -f "${nginx_dir}/sites-enabled/default" + + export compatibility="intermediate" + ynh_render_template "yunohost_admin.conf" "${nginx_conf_dir}/yunohost_admin.conf" + + # Restart nginx if conf looks good, otherwise display error and exit unhappy + nginx -t 2>/dev/null && service nginx restart || (nginx -t && exit 1) + + exit 0 } do_pre_regen() { @@ -22,20 +40,16 @@ do_pre_regen() { nginx_conf_dir="${nginx_dir}/conf.d" mkdir -p "$nginx_conf_dir" - # install plain conf files + # install / update plain conf files cp plain/* "$nginx_conf_dir" - # probably run with init: just disable default site, restart NGINX and exit - if [[ -z "$pending_dir" ]]; then - rm -f "${nginx_dir}/sites-enabled/default" - service nginx restart - exit 0 - fi - # retrieve variables main_domain=$(cat /etc/yunohost/current_host) domain_list=$(sudo yunohost domain list --output-as plain --quiet) + # Support different strategy for security configurations + export compatibility="$(yunohost settings get 'security.nginx.compatibility')" + # add domain conf files for domain in $domain_list; do domain_conf_dir="${nginx_conf_dir}/${domain}.d" @@ -58,6 +72,8 @@ do_pre_regen() { done + ynh_render_template "yunohost_admin.conf" "${nginx_conf_dir}/yunohost_admin.conf" + # remove old domain conf files conf_files=$(ls -1 /etc/nginx/conf.d \ | awk '/^[^\.]+\.[^\.]+.*\.conf$/ { print $1 }') diff --git a/data/templates/dnsmasq/plain/resolv.dnsmasq.conf b/data/templates/dnsmasq/plain/resolv.dnsmasq.conf index 7eed1142f..197ee2d64 100644 --- a/data/templates/dnsmasq/plain/resolv.dnsmasq.conf +++ b/data/templates/dnsmasq/plain/resolv.dnsmasq.conf @@ -9,25 +9,37 @@ # (FR) FDN nameserver 80.67.169.12 +nameserver 2001:910:800::12 nameserver 80.67.169.40 +nameserver 2001:910:800::40 # (FR) LDN nameserver 80.67.188.188 +nameserver 2001:913::8 # (FR) ARN nameserver 89.234.141.66 +nameserver 2a00:5881:8100:1000::3 # (FR) Aquilenet nameserver 185.233.100.100 +nameserver 2a0c:e300::100 nameserver 185.233.100.101 +nameserver 2a0c:e300::101 # (FR) gozmail / grifon nameserver 80.67.190.200 +nameserver 2a00:5884:8218::1 # (DE) FoeBud / Digital Courage nameserver 85.214.20.141 # (DE) CCC Berlin nameserver 195.160.173.53 # (DE) AS250 nameserver 194.150.168.168 +nameserver 2001:4ce8::53 # (DE) Ideal-Hosting nameserver 84.200.69.80 +nameserver 2001:1608:10:25::1c04:b12f nameserver 84.200.70.40 +nameserver 2001:1608:10:25::9249:d69b # (DK) censurfridns nameserver 91.239.100.100 +nameserver 2001:67c:28a4:: nameserver 89.233.43.71 +nameserver 2002:d596:2a92:1:71:53:: diff --git a/data/templates/nginx/plain/global.conf b/data/templates/nginx/plain/global.conf index ca8721afb..b3a5f356a 100644 --- a/data/templates/nginx/plain/global.conf +++ b/data/templates/nginx/plain/global.conf @@ -1,2 +1 @@ server_tokens off; -gzip_types text/css text/javascript application/javascript; diff --git a/data/templates/nginx/plain/yunohost_panel.conf.inc b/data/templates/nginx/plain/yunohost_panel.conf.inc index 34afe136d..1c5a2d656 100644 --- a/data/templates/nginx/plain/yunohost_panel.conf.inc +++ b/data/templates/nginx/plain/yunohost_panel.conf.inc @@ -1,8 +1,8 @@ -# Insert YunoHost panel -sub_filter ''; +# Insert YunoHost button + portal overlay +sub_filter ''; sub_filter_once on; # Apply to other mime types than text/html sub_filter_types application/xhtml+xml; # Prevent YunoHost panel files from being blocked by specific app rules -location ~ ynhpanel\.(js|json|css) { +location ~ (ynh_portal.js|ynh_overlay.css|ynh_userinfo.json) { } diff --git a/data/templates/nginx/server.tpl.conf b/data/templates/nginx/server.tpl.conf index 43d38ca98..fa8b6586b 100644 --- a/data/templates/nginx/server.tpl.conf +++ b/data/templates/nginx/server.tpl.conf @@ -29,6 +29,14 @@ server { ssl_session_timeout 5m; ssl_session_cache shared:SSL:50m; + {% if compatibility == "modern" %} + # Ciphers with modern compatibility + # https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=nginx-1.6.2&openssl=1.0.1t&hsts=yes&profile=modern + # The following configuration use modern ciphers, but remove compatibility with some old clients (android < 5.0, Internet Explorer < 10, ...) + ssl_protocols TLSv1.2; + ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256'; + ssl_prefer_server_ciphers on; + {% else %} # As suggested by Mozilla : https://wiki.mozilla.org/Security/Server_Side_TLS and https://en.wikipedia.org/wiki/Curve25519 ssl_ecdh_curve secp521r1:secp384r1:prime256v1; ssl_prefer_server_ciphers on; @@ -38,15 +46,10 @@ server { ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS'; - # Ciphers with modern compatibility - # https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=nginx-1.6.2&openssl=1.0.1t&hsts=yes&profile=modern - # Uncomment the following to use modern ciphers, but remove compatibility with some old clients (android < 5.0, Internet Explorer < 10, ...) - #ssl_protocols TLSv1.2; - #ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256'; - # Uncomment the following directive after DH generation # > openssl dhparam -out /etc/ssl/private/dh2048.pem -outform PEM -2 2048 #ssl_dhparam /etc/ssl/private/dh2048.pem; + {% endif %} # Follows the Web Security Directives from the Mozilla Dev Lab and the Mozilla Obervatory + Partners # https://wiki.mozilla.org/Security/Guidelines/Web_Security @@ -71,6 +74,10 @@ server { resolver_timeout 5s; {% endif %} + # Disable gzip to protect against BREACH + # Read https://trac.nginx.org/nginx/ticket/1720 (text/html cannot be disabled!) + gzip off; + access_by_lua_file /usr/share/ssowat/access.lua; include /etc/nginx/conf.d/{{ domain }}.d/*.conf; diff --git a/data/templates/nginx/plain/yunohost_admin.conf b/data/templates/nginx/yunohost_admin.conf similarity index 84% rename from data/templates/nginx/plain/yunohost_admin.conf rename to data/templates/nginx/yunohost_admin.conf index 2493e4033..e0d9f6bb1 100644 --- a/data/templates/nginx/plain/yunohost_admin.conf +++ b/data/templates/nginx/yunohost_admin.conf @@ -20,6 +20,14 @@ server { ssl_session_timeout 5m; ssl_session_cache shared:SSL:50m; + {% if compatibility == "modern" %} + # Ciphers with modern compatibility + # https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=nginx-1.6.2&openssl=1.0.1t&hsts=yes&profile=modern + # Uncomment the following to use modern ciphers, but remove compatibility with some old clients (android < 5.0, Internet Explorer < 10, ...) + ssl_protocols TLSv1.2; + ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256'; + ssl_prefer_server_ciphers on; + {% else %} # As suggested by Mozilla : https://wiki.mozilla.org/Security/Server_Side_TLS and https://en.wikipedia.org/wiki/Curve25519 ssl_ecdh_curve secp521r1:secp384r1:prime256v1; ssl_prefer_server_ciphers on; @@ -29,20 +37,15 @@ server { ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS'; - # Ciphers with modern compatibility - # https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=nginx-1.6.2&openssl=1.0.1t&hsts=yes&profile=modern - # Uncomment the following to use modern ciphers, but remove compatibility with some old clients (android < 5.0, Internet Explorer < 10, ...) - #ssl_protocols TLSv1.2; - #ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256'; - # Uncomment the following directive after DH generation # > openssl dhparam -out /etc/ssl/private/dh2048.pem -outform PEM -2 2048 #ssl_dhparam /etc/ssl/private/dh2048.pem; - + {% endif %} + # Follows the Web Security Directives from the Mozilla Dev Lab and the Mozilla Obervatory + Partners # https://wiki.mozilla.org/Security/Guidelines/Web_Security - # https://observatory.mozilla.org/ - more_set_headers "Strict-Transport-Security : max-age=63072000; includeSubDomains; preload"; + # https://observatory.mozilla.org/ + more_set_headers "Strict-Transport-Security : max-age=63072000; includeSubDomains; preload"; more_set_headers "Referrer-Policy : 'same-origin'"; more_set_headers "Content-Security-Policy : upgrade-insecure-requests; object-src 'none'; script-src https: 'unsafe-eval'"; more_set_headers "X-Content-Type-Options : nosniff"; @@ -51,6 +54,10 @@ server { more_set_headers "X-Permitted-Cross-Domain-Policies : none"; more_set_headers "X-Frame-Options : SAMEORIGIN"; + # Disable gzip to protect against BREACH + # Read https://trac.nginx.org/nginx/ticket/1720 (text/html cannot be disabled!) + gzip off; + location / { return 302 https://$http_host/yunohost/admin; } diff --git a/data/templates/ssh/sshd_config b/data/templates/ssh/sshd_config index ed870e5dc..8dc0e8dfc 100644 --- a/data/templates/ssh/sshd_config +++ b/data/templates/ssh/sshd_config @@ -15,10 +15,17 @@ HostKey {{ key }}{% endfor %} # https://infosec.mozilla.org/guidelines/openssh # ############################################## -# Keys, ciphers and MACS -KexAlgorithms curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256 -Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr -MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com +{% if compatibility == "intermediate" %} + KexAlgorithms diffie-hellman-group-exchange-sha256 + Ciphers aes256-ctr,aes192-ctr,aes128-ctr + MACs hmac-sha2-512,hmac-sha2-256 +{% else %} + # By default use "modern" Mozilla configuration + # Keys, ciphers and MACS + KexAlgorithms curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256 + Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr + MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com +{% endif %} # Use kernel sandbox mechanisms where possible in unprivileged processes UsePrivilegeSeparation sandbox diff --git a/data/templates/yunohost/services.yml b/data/templates/yunohost/services.yml index 62509e1e9..0d79b182f 100644 --- a/data/templates/yunohost/services.yml +++ b/data/templates/yunohost/services.yml @@ -20,8 +20,6 @@ mysql: glances: {} ssh: log: /var/log/auth.log -ssl: - status: null metronome: log: [/var/log/metronome/metronome.log,/var/log/metronome/metronome.err] slapd: @@ -34,10 +32,9 @@ yunohost-firewall: need_lock: true nslcd: log: /var/log/syslog -nsswitch: - status: null -yunohost: - status: null +nsswitch: null +ssl: null +yunohost: null bind9: null tahoe-lafs: null memcached: null diff --git a/debian/changelog b/debian/changelog index 7be4212fe..a22959899 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,119 @@ +yunohost (3.5.2.2) stable; urgency=low + + - Hotfix for ynh_psql_remove_db (from ljf) + + -- Alexandre Aubin Thu, 18 Apr 2019 17:32:00 +0000 + +yunohost (3.5.2.1) stable; urgency=low + + - [fix] Fresh install was broken because of yunohost_admin.conf initialization + + -- Alexandre Aubin Thu, 11 Apr 2019 14:38:00 +0000 + +yunohost (3.5.2) stable; urgency=low + + - Release as stable ! + - [doc] Update script to automatically generate helper doc + - [i18n] Update translations for Catalan, Arabic, Italian + + Thanks to all contributors: Aleks, xaloc, BoF, silkevicious ! <3 + + -- Alexandre Aubin Wed, 10 Apr 2019 01:53:00 +0000 + +yunohost (3.5.1.1) testing; urgency=low + + - [fix] enabled/disabled status for sysv services + - [fix] Nodejs helpers : use YNH_APP_INSTANCE_NAME instead of YNH_APP_ID (#700) + - [fix] nginx diagnosis when there's an error throwing a huge useless traceback. Use Popen instead to display the real error + - [fix] service_status returns different type of data if you ask for one or multiple services + + -- Alexandre Aubin Wed, 03 Apr 2019 17:28:00 +0000 + +yunohost (3.5.1) testing; urgency=low + + - [fix] Fix the dbus interface to get info for services (#698) + - [mod] Use ask key for display_text instead and support i18n (#697) + - [fix] Rework tools update (#695) + - [enh] Nginx conf tweaks for theme (#689) + - [fix] Fix argument escaping in getopts (#685, #683) + - [enh] Support php versions in ynh_add_fpm_config (#674) + - [enh] Check that required services are up before running app install and upgrade (#670) + - [doc] Add min version for all helpers (#664) + - [enh] Add a setting to control compatibility/security tradeoff for nginx and ssh configurations (#640) + - [enh] Hooks to allow apps to extend the recommended DNS configuration (#517) + - Misc technical fixes / improvements (0bd781b, fad3edf, 1268872, 847ceca, 26e77b7, b6cff68) + - [i18n] Update translation for French, Catalan, Esperanto, Occitan + + Thanks to all contributors: Aleks, Bram, Gabriel Corona, Jibec, Josue, Maniack C, Mélanie C., Quentí, Romuald du Song, ljf, ppr, Xaloc ! <3 + + -- Alexandre Aubin Wed, 03 Apr 2019 02:13:00 +0000 + +yunohost (3.5.0.2) testing; urgency=low + + - [fix] Make sure that `ynh_system_user_delete` also deletes the group (#680) + - [enh] `ynh_systemd_action` : reload-or-restart instead of just reload (#681) + + Last minute fixes by Maniack ;) + + -- Alexandre Aubin Thu, 14 Mar 2019 03:45:00 +0000 + +yunohost (3.5.0.1) testing; urgency=low + + - [fix] #675 introduced a bug in nginx conf ... + + -- Alexandre Aubin Wed, 13 Mar 2019 19:23:00 +0000 + +yunohost (3.5.0) testing; urgency=low + + Core + ---- + + - [fix] Disable gzip entirely to avoid BREACH attacks (#675) + - [fix] Backup tests were broken (#673) + - [fix] Backup fails because output directory not empty (#672) + - [fix] Reject app password if they contains { or } (#671) + - [enh] Allow `display_text` 'fake' argument in manifest.json (#669) + - [fix] Optimize dyndns requests (#662) + - [enh] Don't add Strict-Transport-Security header in nginx conf if using a selfsigned cert (#661) + - [enh] Add apt-transport-https to dependencies (#658) + - [enh] Cache results from meltdown vulnerability checker (#656) + - [enh] Ensure the tar file is closed during the backup (#655) + - [enh] Be able to define hook to trigger when changing a setting (#654) + - [enh] Assert dpkg is not broken before app install (#652) + - [fix] Loading only one helper file leads to errors because missing getopts (#651) + - [enh] Improve / add some messages to improve UX (#650) + - [enh] Reload fail2ban instead of restart (#649) + - [enh] Add IPv6 resolvers from diyisp.org to resolv.dnsmasq.conf (#639) + - [fix] Remove old SMTP port (465) from fail2ban jail.conf (#637) + - [enh] Improve protection against indexation from the robots. (#622) + - [enh] Allow hooks to return data (#526) + - [fix] Do not make version number available from web API to unauthenticated users (#291) + - [i18n] Improve Russian and Chinese (Mandarin) translations + + App helpers + ----------- + + - [enh] Optimize app setting helpers (#663, #676) + - [enh] Handle `ynh_install_nodejs` for arm64 / aarch64 (#660) + - [enh] Update postgresql helpers (#657) + - [enh] Print diff of files when backup by `ynh_backup_if_checksum_is_different` (#648) + - [enh] Add app debugger helper (#647) + - [fix] Escape double quote before eval in getopts (#646) + - [fix] `ynh_local_curl` not using the right url in some cases (#644) + - [fix] Get rid of annoying 'unable to initialize frontend' messages (#643) + - [enh] Check if dpkg is not broken when calling `ynh_wait_dpkg_free` (#638) + - [enh] Warn the packager that `ynh_secure_remove` should be used with only one arg… (#635, #642) + - [enh] Add `ynh_script_progression` helper (#634) + - [enh] Add `ynh_systemd_action` helper (#633) + - [enh] Allow to dig deeper into an archive with `ynh_setup_source` (#630) + - [enh] Use getops (#561) + - [enh] Add `ynh_check_app_version_changed` helper (#521) + - [enh] Add fail2ban helpers (#364) + + Contributors: Alexandre Aubin, Jimmy Monin, Josué Tille, Kayou, Laurent Peuch, Lukas Fülling, Maniack Crudelis, Taekiro, frju365, ljf, opi, yalh76, Алексей + + -- Alexandre Aubin Wed, 13 Mar 2019 16:10:00 +0000 + yunohost (3.4.2.4) stable; urgency=low - [fix] Meltdown vulnerability checker something outputing trash instead of pure json diff --git a/debian/postinst b/debian/postinst index df7112b9d..83220ae0b 100644 --- a/debian/postinst +++ b/debian/postinst @@ -12,7 +12,7 @@ do_configure() { bash /usr/share/yunohost/hooks/conf_regen/15-nginx init else echo "Regenerating configuration, this might take a while..." - yunohost service regen-conf --output-as none + yunohost tools regen-conf --output-as none echo "Launching migrations.." yunohost tools migrations migrate --auto diff --git a/doc/generate_helper_doc.py b/doc/generate_helper_doc.py index 7d8c489b7..5b51dda02 100644 --- a/doc/generate_helper_doc.py +++ b/doc/generate_helper_doc.py @@ -4,7 +4,12 @@ import os import glob import datetime -def render(data): +def render(helpers): + + data = { "helpers": helpers, + "date": datetime.datetime.now().strftime("%m/%d/%Y"), + "version": open("../debian/changelog").readlines()[0].split()[1].strip("()") + } from jinja2 import Template from ansi2html import Ansi2HTMLConverter @@ -43,7 +48,7 @@ class Parser(): "code": [] } for i, line in enumerate(self.file): - + if line.startswith("#!/bin/bash"): continue @@ -103,7 +108,6 @@ class Parser(): b["usage"] = "" b["args"] = [] b["ret"] = "" - b["example"] = "" subblocks = '\n'.join(b["comments"]).split("\n\n") @@ -114,17 +118,29 @@ class Parser(): b["brief"] = subblock continue - elif subblock.startswith("example"): + elif subblock.startswith("example:"): b["example"] = " ".join(subblock.split()[1:]) continue + elif subblock.startswith("examples:"): + b["examples"] = subblock.split("\n")[1:] + continue + elif subblock.startswith("usage"): for line in subblock.split("\n"): if line.startswith("| arg"): - argname = line.split()[2] - argdescr = " ".join(line.split()[4:]) - b["args"].append((argname, argdescr)) + linesplit = line.split() + argname = linesplit[2] + # Detect that there's a long argument version (-f, --foo - Some description) + if argname.endswith(",") and linesplit[3].startswith("--"): + argname = argname.strip(",") + arglongname = linesplit[3] + argdescr = " ".join(linesplit[5:]) + b["args"].append((argname, arglongname, argdescr)) + else: + argdescr = " ".join(linesplit[4:]) + b["args"].append((argname, argdescr)) elif line.startswith("| ret"): b["ret"] = " ".join(line.split()[2:]) else: @@ -136,9 +152,17 @@ class Parser(): elif subblock.startswith("| arg"): for line in subblock.split("\n"): if line.startswith("| arg"): - argname = line.split()[2] - argdescr = line.split()[4:] - b["args"].append((argname, argdescr)) + linesplit = line.split() + argname = linesplit[2] + # Detect that there's a long argument version (-f, --foo - Some description) + if argname.endswith(",") and linesplit[3].startswith("--"): + argname = argname.strip(",") + arglongname = linesplit[3] + argdescr = " ".join(linesplit[5:]) + b["args"].append((argname, arglongname, argdescr)) + else: + argdescr = " ".join(linesplit[4:]) + b["args"].append((argname, argdescr)) continue else: diff --git a/doc/helper_doc_template.html b/doc/helper_doc_template.html index 1fa1f68ad..92611c737 100644 --- a/doc/helper_doc_template.html +++ b/doc/helper_doc_template.html @@ -2,7 +2,7 @@

App helpers

-{% for category, helpers in data %} +{% for category, helpers in data.helpers %}

{{ category }}

@@ -27,8 +27,12 @@

Arguments:

    - {% for name, descr in h.args %} -
  • {{ name }} : {{ descr }}
  • + {% for infos in h.args %} + {% if infos|length == 2 %} +
  • {{ infos[0] }} : {{ infos[1] }}
  • + {% else %} +
  • {{ infos[0] }}, {{ infos[1] }} : {{ infos[2] }}
  • + {% endif %} {% endfor %}

@@ -38,11 +42,25 @@ Returns: {{ h.ret }}

{% endif %} - {% if h.example %} + {% if "example" in h.keys() %}

Example: {{ h.example }}

{% endif %} + {% if "examples" in h.keys() %} +

+ Examples:

    + {% for example in h.examples %} + {% if not example.strip().startswith("# ") %} + {{ example }} + {% else %} + {{ example.strip("# ") }} + {% endif %} +
    + {% endfor %} +
+

+ {% endif %} {% if h.details %}

Details: @@ -63,6 +81,8 @@ {% endfor %} {% endfor %} +

Generated by this script on {{data.date}} (Yunohost version {{data.version}})

+