#!/bin/bash

#=================================================
# GENERIC START
#=================================================
# IMPORT GENERIC HELPERS
#=================================================

source _common.sh
source experimental_helper.sh
source /usr/share/yunohost/helpers

#=================================================
# LOAD SETTINGS
#=================================================
ynh_script_progression --message="Loading installation settings..." --weight=3

app=$YNH_APP_INSTANCE_NAME

domain=$(ynh_app_setting_get --app=$app --key=domain)
server_name=$(ynh_app_setting_get --app=$app --key=server_name)
path_url=$(ynh_app_setting_get --app=$app --key=path)
final_path=$(ynh_app_setting_get --app=$app --key=final_path)
synapse_old_version=$(ynh_app_setting_get --app=$app --key=synapse_version)
is_public=$(ynh_app_setting_get --app=$app --key=is_public)
port=$(ynh_app_setting_get --app=$app --key=synapse_port)
synapse_tls_port=$(ynh_app_setting_get --app=$app --key=synapse_tls_port)
turnserver_tls_port=$(ynh_app_setting_get --app=$app --key=turnserver_tls_port)
turnserver_alt_tls_port=$(ynh_app_setting_get --app=$app --key=turnserver_alt_tls_port)
cli_port=$(ynh_app_setting_get --app=$app --key=cli_port)
report_stats=$(ynh_app_setting_get --app=$app --key=report_stats)
allow_public_rooms=$(ynh_app_setting_get --app=$app --key=allow_public_rooms)
ynh_print_OFF
synapse_db_pwd=$(ynh_app_setting_get --app=$app --key=synapse_db_pwd)
turnserver_pwd=$(ynh_app_setting_get --app=$app --key=turnserver_pwd)
registration_shared_secret=$(ynh_app_setting_get --app=$app --key=registration_shared_secret)
form_secret=$(ynh_app_setting_get --app=$app --key=form_secret)
macaroon_secret_key=$(ynh_app_setting_get --app=$app --key=macaroon_secret_key)
ynh_print_ON

#=================================================
# SET ALL CONSTANT
#=================================================

synapse_user="matrix-$app"
synapse_db_name="matrix_$app"
synapse_db_user="matrix_$app"
upstream_version=$(ynh_app_upstream_version)
final_www_path="/var/www/$app"

#=================================================
# CHECK VERSION
#=================================================

upgrade_type=$(ynh_check_app_version_changed)

#=================================================
# ENSURE DOWNWARD COMPATIBILITY
#=================================================
ynh_script_progression --message="Ensuring downward compatibility..." --weight=1

# Following the discussion here https://github.com/YunoHost-Apps/synapse_ynh/pull/51 we decided to remove definitely the support of the old package migration.
if [ -z "$synapse_old_version" ]
then
	ynh_die --message="Update from this synapse version is not available. You need to remove this package and reinstall the new package version."
fi

#=================================================
# BACKUP BEFORE UPGRADE THEN ACTIVE TRAP
#=================================================
ynh_script_progression --message="Backing up the app before upgrading (may take a while)..." --weight=30

# We stop the service before to set ynh_clean_setup
ynh_systemd_action --service_name=matrix-$app.service --action=stop

# Backup the current version of the app
if [ "$(ynh_app_setting_get --app=$app --key=disable_backup_before_upgrade)" != '1' ]
then
    ynh_backup_before_upgrade
    ynh_clean_setup () {
        # Clean installation remainings that are not handled by the remove script.
        ynh_clean_check_starting

        ynh_restore_upgradebackup
    }
fi
# Exit if an error occurs during the execution of the script
ynh_abort_if_errors

#=================================================
# STANDARD UPGRADE STEPS
#=================================================
# MIGRATION 5 : Manage old settings
#=================================================

# Migrate from settings 'special_domain' to 'domain' and 'special_path' to 'path'
if [ -z $domain ]; then
    domain=$(ynh_app_setting_get --app=$app --key=special_domain)
    path_url=$(ynh_app_setting_get --app=$app --key=special_path)
    ynh_app_setting_set --app=$app --key=domain --value=$domain
    ynh_app_setting_set --app=$app --key=path --value=$path_url
    ynh_app_setting_delete --app=$app --key=special_domain
    ynh_app_setting_delete --app=$app --key=special_path
    ynh_app_setting_set --app=$app --key=no_sso --value true
fi

# Define $server_name if not already defined
if [ -z $server_name ]; then
   server_name=$domain
   ynh_app_setting_set $app server_name  $domain
fi

#=================================================
# INSTALL DEPENDENCIES
#=================================================
ynh_script_progression --message="Upgrading dependencies..." --weight=6

# WARNING : theses command are used in INSTALL, UPGRADE, RESTORE
# For any update do it in all files
ynh_install_app_dependencies $dependances

#=================================================
# DOWNLOAD, CHECK AND UNPACK SOURCE
#=================================================

if [ "$upgrade_type" == "UPGRADE_APP" ]
then
	ynh_script_progression --message="Upgrading source files..." --weight=6

	# Install/upgrade synapse in virtualenv

	# Clean venv is it was on python2.7
	test -e $final_path/bin/python3 || ynh_secure_remove --file=$final_path

	# WARNING : these commands are used in INSTALL, UPGRADE
	# For any update do it in all files

	if [ -n "$(uname -m | grep arm)" ]
	then
		# Clean old file, sometimes it could make some big issues if we don't do this!!
		ynh_secure_remove --file=$final_path/bin
		ynh_secure_remove --file=$final_path/lib
		ynh_secure_remove --file=$final_path/include
		ynh_secure_remove --file=$final_path/share
		ynh_setup_source --dest_dir=$final_path/ --source_id="armv7_$(lsb_release --codename --short)"
	else
		# Install virtualenv if it don't exist
		test -e $final_path/bin/python3 || python3 -m venv $final_path

		# Install synapse in virtualenv
		cp ../conf/virtualenv_activate $final_path/bin/activate
		ynh_replace_string --match_string=__FINAL_PATH__ --replace_string=$final_path --target_file=$final_path/bin/activate

		# We set all necessary environement variable to create a python virtualenvironnement.
		source $final_path/bin/activate
		pip3 install --upgrade setuptools wheel
		pip3 install --upgrade cffi ndg-httpsclient psycopg2 lxml jinja2
		pip3 install --upgrade matrix-synapse==$upstream_version matrix-synapse-ldap3

		# This function was defined when we called "source $final_path/bin/activate". With this function we undo what "$final_path/bin/activate" does
		deactivate
	fi
fi

#=================================================
# CREATE SMALL CAS SERVER
#=================================================
# WARNING : theses command are used in INSTALL, UPGRADE
# For any update do it in all files

mkdir -p $final_www_path
cp ../sources/cas_server.php $final_www_path/
chmod u=rwX,g=rX,o= -R $final_www_path
chown $synapse_user:root -R $final_www_path

#=================================================
# MIGRATION 1 : GENERATE SYNAPSE SECRET
#=================================================

ynh_print_OFF
if [ -z "$registration_shared_secret" ] || [ "$form_secret" == "form_secret: " ]
then
    ynh_print_ON
    ynh_script_progression --message="Generating synapse secret..." --weight=1

    # Go in virtualenvironnement
    PS1=${PS1:-}
    source $final_path/bin/activate

    # Generate config and keys
    python -m synapse.app.homeserver --keys-directory /etc/matrix-$app/ --generate-config --generate-keys --server-name $server_name --report-stats=no -c homeserver.yml

    # This function was defined when we called "source $final_path/bin/activate". With this function we undo what "$final_path/bin/activate" does
    deactivate

    # Get random values from config
    ynh_print_OFF
    registration_shared_secret=$(egrep "^registration_shared_secret:" homeserver.yml | cut -d'"' -f2)
    form_secret=$(egrep "^form_secret:" homeserver.yml | cut -d'"' -f2)

    # store in yunohost settings
    ynh_app_setting_set --app=$app --key=registration_shared_secret --value="$registration_shared_secret"
    ynh_app_setting_set --app=$app --key=form_secret --value="$form_secret"
    ynh_print_ON
fi
ynh_print_ON

#=================================================
# MIGRATION 5 : DEFINE UNDEFINED SETTINGS
#=================================================

if [ -n $report_stats ]; then
    report_stats="false"
fi

if [ -n $allow_public_rooms ]; then
    allow_public_rooms="false"
fi

#=================================================
# UPDATE SYNAPSE CONFIG
#=================================================
ynh_script_progression --message="Updating synapse config..." --weight=2

# WARNING : theses command are used in INSTALL, UPGRADE, CONFIG, CHANGE-URL (4 times)
# For any update do it in all files

homeserver_config_path="/etc/matrix-$app/homeserver.yaml"

ynh_backup_if_checksum_is_different --file="$homeserver_config_path"
ynh_backup_if_checksum_is_different --file=/etc/matrix-$app/log.yaml

cp ../conf/homeserver.yaml "$homeserver_config_path"
cp ../conf/log.yaml /etc/matrix-$app/log.yaml

ynh_replace_string --match_string=__APP__ --replace_string=$app --target_file="$homeserver_config_path"
ynh_replace_string --match_string=__DOMAIN__ --replace_string=$domain --target_file="$homeserver_config_path"
ynh_replace_string --match_string=__SERVER_NAME__ --replace_string=$server_name --target_file="$homeserver_config_path"
ynh_replace_string --match_string=__SYNAPSE_DB_USER__ --replace_string=$synapse_db_user --target_file="$homeserver_config_path"
ynh_replace_string --match_string=__PORT__ --replace_string=$port --target_file="$homeserver_config_path"
ynh_replace_string --match_string=__TLS_PORT__ --replace_string=$synapse_tls_port --target_file="$homeserver_config_path"
ynh_replace_string --match_string=__TURNSERVER_TLS_PORT__ --replace_string=$turnserver_tls_port --target_file="$homeserver_config_path"
ynh_replace_string --match_string=__REPORT_STATS__ --replace_string="$report_stats" --target_file="$homeserver_config_path"
ynh_replace_string --match_string=__ALLOW_PUBLIC_ROOMS__ --replace_string="$allow_public_rooms" --target_file="$homeserver_config_path"
ynh_print_OFF
ynh_replace_special_string --match_string=__SYNAPSE_DB_PWD__ --replace_string=$synapse_db_pwd --target_file="$homeserver_config_path"
ynh_replace_special_string --match_string=__TURNPWD__ --replace_string=$turnserver_pwd --target_file="$homeserver_config_path"
ynh_replace_special_string --match_string=__REGISTRATION_SECRET__ --replace_string="$registration_shared_secret" --target_file="$homeserver_config_path"
ynh_replace_special_string --match_string=__FORM_SECRET__ --replace_string="$form_secret" --target_file="$homeserver_config_path"
if [ -z $macaroon_secret_key ]; then
    # Well, in this package this value was not managed because it was not needed, synapse is able to generate this with some other secret in the config file but after some vulnerability was found with this practice.
    # For more detail about this issue you can see : https://matrix.org/blog/2019/01/15/further-details-on-critical-security-update-in-synapse-affecting-all-versions-prior-to-0-34-1-cve-2019-5885/
    # The problem is that we can't just say generate a new value if the package has not already defined a value. The reason is that changing this value logout all user. And in case of a user has enabled the encryption, the user might lost all conversation !!
    # So for the old install we just leave this as it is. And for the new install we use a real macaroon.
    ynh_replace_special_string --match_string='macaroon_secret_key: "__MACAROON_SECRET_KEY__"' --replace_string='# macaroon_secret_key: "__MACAROON_SECRET_KEY__"' --target_file="$homeserver_config_path"
else
    ynh_replace_special_string --match_string=__MACAROON_SECRET_KEY__ --replace_string="$macaroon_secret_key" --target_file="$homeserver_config_path"
fi
ynh_print_ON

ynh_replace_string --match_string=__APP__ --replace_string=$app --target_file="/etc/matrix-$app/log.yaml"

if [ "$is_public" = "0" ]
then
    ynh_replace_string --match_string=__ALLOWED_ACCESS__ --replace_string=False --target_file="$homeserver_config_path"
else
    ynh_replace_string --match_string=__ALLOWED_ACCESS__ --replace_string=True --target_file="$homeserver_config_path"
fi

ynh_store_file_checksum --file="$homeserver_config_path"
ynh_store_file_checksum --file="/etc/matrix-$app/log.yaml"

#=================================================
# MIGRATION 2 : MULTINSTANCE SUPPORT
#=================================================

if [ ! -e /etc/matrix-$app/coturn.conf ]
then
    ynh_script_progression --message="Creating an independant service for coturn..." --weight=1

    #=================================================
    # CREATE AN INDEPENDANT SERVICE FOR COTURN
    #=================================================

    # Disable default config for turnserver and create a new service
    systemctl stop coturn.service

    # Set by default the system config for coturn
    echo "" > /etc/turnserver.conf
    ynh_replace_string --match_string="TURNSERVER_ENABLED=1" --replace_string="TURNSERVER_ENABLED=0" --target_file=/etc/default/coturn

    # Set a port for each service in turnserver
    turnserver_alt_tls_port=$(ynh_find_port --port=$((turnserver_tls_port+1)))
    cli_port=$(ynh_find_port --port=5766)

    ynh_app_setting_set --app=$app --key=turnserver_alt_tls_port --value=$turnserver_alt_tls_port
    ynh_app_setting_set --app=$app --key=cli_port --value=$cli_port

    yunohost firewall allow Both $turnserver_alt_tls_port > /dev/null 2>&1

    #=================================================
    # MAKE A CLEAN LOGROTATE CONFIG
    #=================================================

    ynh_use_logrotate --logfile /var/log/matrix-$app --nonappend
fi

#=================================================
# MIGRATION 3 : USE STANDARD ACCESS FOR CERTIFCATE
#=================================================

# Fix issue about certificates access
if [ ! $(grep "ssl-cert:x:[0-9]*:.*matrix-$app" /etc/group) ]
then
    ynh_script_progression --message="Use standard access for certificate..." --weight=1

    adduser $synapse_user ssl-cert
    adduser turnserver ssl-cert
fi

#=================================================
# MIGRATION 4 : CREATE A DH FILE
#=================================================

# WARNING : theses command are used in INSTALL, UPGRADE, RESTORE
# For any update do it in all files

# Make dh cert for synapse if it doesn't exist
if [ ! -e /etc/ssl/private/dh2048.pem ]
then
    ynh_script_progression --message="Creating a dh file..." --weight=1

    openssl dhparam -out /etc/ssl/private/dh2048.pem -outform PEM -2 2048 -dsaparam 2> /dev/null
    chown root:ssl-cert /etc/ssl/private/dh2048.pem
    chmod 640 /etc/ssl/private/dh2048.pem
fi

#=================================================
# STANDARD UPGRADE STEPS
#=================================================
# NGINX CONFIGURATION
#=================================================
ynh_script_progression --message="Upgrading nginx web server configuration..." --weight=2

# Create a dedicated php-fpm config
ynh_script_progression --message="Configuring application..."
ynh_add_fpm_config

# Create a dedicated nginx config
ynh_add_nginx_config app

# Create .well-known redirection for access by federation
if yunohost --output-as plain domain list | grep -q "^$server_name$"
then
    cp ../conf/server_name.conf /etc/nginx/conf.d/${server_name}.d/${app}_server_name.conf
    ynh_replace_string --match_string=__DOMAIN__ --replace_string=$domain --target_file="/etc/nginx/conf.d/${server_name}.d/${app}_server_name.conf"
    ynh_replace_string --match_string=__PORT__ --replace_string=$synapse_tls_port --target_file="/etc/nginx/conf.d/${server_name}.d/${app}_server_name.conf"
    ynh_store_file_checksum --file="/etc/nginx/conf.d/${server_name}.d/${app}_server_name.conf"
fi

#=================================================
# SPECIFIC UPGRADE
#=================================================
# UPDATE COTURN CONFIG
#=================================================
ynh_script_progression --message="Updating coturn config..." --weight=1

# WARNING : theses command are used in INSTALL, UPGRADE
# For any update do it in all files

coturn_config_path="/etc/matrix-$app/coturn.conf"

cp ../conf/turnserver.conf "$coturn_config_path"

ynh_replace_string --match_string=__APP__ --replace_string=$app --target_file="$coturn_config_path"
ynh_replace_string --match_string=__DOMAIN__ --replace_string=$domain --target_file="$coturn_config_path"
ynh_replace_string --match_string=__TLS_PORT__ --replace_string=$turnserver_tls_port --target_file="$coturn_config_path"
ynh_replace_string --match_string=__TLS_ALT_PORT__ --replace_string=$turnserver_alt_tls_port --target_file="$coturn_config_path"
ynh_replace_string --match_string=__CLI_PORT__ --replace_string=$cli_port --target_file="$coturn_config_path"
ynh_print_OFF
ynh_replace_string --match_string=__TURNPWD__ --replace_string=$turnserver_pwd --target_file="$coturn_config_path"
ynh_print_ON

# Get public IP and set as external IP for coturn
# note : '|| true' is used to ignore the errors if we can't get the public ipv4 or ipv6
public_ip4="$(curl ip.yunohost.org)" || true
public_ip6="$(curl ipv6.yunohost.org)" || true

if [ -n "$public_ip4" ] && ynh_validate_ip4 --ip_address="$public_ip4"
then
    ynh_replace_string --match_string='__IPV4__' --replace_string="$public_ip4" --target_file="$coturn_config_path"
else
    ynh_replace_string --match_string='__IPV4__,' --replace_string="" --target_file="$coturn_config_path"
fi

if [ -n "$public_ip6" ] && ynh_validate_ip6 --ip_address="$public_ip6"
then
    ynh_replace_string --match_string='__IPV6__' --replace_string="$public_ip6" --target_file="$coturn_config_path"
else
    ynh_replace_string --match_string=',__IPV6__' --replace_string="" --target_file="$coturn_config_path"
fi

ynh_store_file_checksum --file="$coturn_config_path"

#=================================================
# ADD SCRIPT FOR COTURN CRON
#=================================================

# WARNING : theses command are used in INSTALL, UPGRADE
# For any update do it in all files

cp ../sources/Coturn_config_rotate.sh $final_path/
ynh_replace_string --match_string=__APP__ --replace_string=$app --target_file="$final_path/Coturn_config_rotate.sh"

#=================================================
# UPDATE SYSTEMD
#=================================================
ynh_script_progression --message="Upgrading systemd configuration..." --weight=3

# Create systemd service for synapse and turnserver
cp ../conf/default_matrix-synapse /etc/default/matrix-$app
ynh_add_systemd_config --service=matrix-$app --template=matrix-synapse.service

cp ../conf/default_coturn /etc/default/coturn-$app
ynh_add_systemd_config --service=coturn-$app --template=coturn-synapse.service

#=================================================
# UPGRADE FAIL2BAN
#=================================================
ynh_script_progression --message="Reconfiguring fail2ban..." --weight=8

# WARNING : theses command are used in INSTALL, UPGRADE
# For any update do it in all files

ynh_add_fail2ban_config --use_template

#=================================================
# GENERIC FINALIZATION
#=================================================
# SETUP SSOWAT
#=================================================
ynh_script_progression --message="Configuring SSOwat..." --weight=1

# Open access to server without a button the home
# The script "add_sso_conf.py" will just add en entry for the path "/_matrix" in the sso conf.json.persistent file in the cathegory "skipped_urls".
python3 ../conf/add_sso_conf.py $domain $server_name || ynh_die --message="Your file /etc/ssowat/conf.json.persistent doesn't respect the json syntax. Please fix the syntax to install this app. For more information see here: https://github.com/YunoHost-Apps/synapse_ynh/issues/32"
ynh_permission_url --permission main --url $domain/_matrix/cas_server.php/login

#=================================================
# SECURE FILES AND DIRECTORIES
#=================================================

# WARNING : theses command are used in INSTALL, UPGRADE, RESTORE
# For any update do it in all files
chown $synapse_user:root -R $final_path
chmod 770 $final_path/Coturn_config_rotate.sh
chown $synapse_user:root -R /var/lib/matrix-$app
chown $synapse_user:root -R /var/log/matrix-$app
chown $synapse_user:root -R /etc/matrix-$app
chmod u=rwX,g=rX,o= -R /etc/matrix-$app
chmod 600 /etc/matrix-$app/$server_name.signing.key
setfacl -R -m user:turnserver:rX  /etc/matrix-$app
setfacl -R -m user:turnserver:rwX  /var/log/matrix-$app

#=================================================
# UPDATE HOOKS
#=================================================

# WARNING : theses command are used in INSTALL, UPGRADE
# For any update do it in all files
ynh_replace_string __APP__ $app ../hooks/post_cert_update
ynh_replace_string __DOMAIN__ $domain ../hooks/post_cert_update

#=================================================
# UPDATE VERSION SETTINGS
#=================================================

ynh_app_setting_set --app=$app --key=synapse_version --value=$upstream_version

#=================================================
# RELOAD SERVICES
#=================================================
ynh_script_progression --message="Restarting synapse services..." --weight=5

ynh_systemd_action --service_name=coturn-$app.service --action=restart
ynh_systemd_action --service_name=matrix-$app --action=restart --line_match="Synapse now listening on TCP port $synapse_tls_port" --log_path="/var/log/matrix-$app/homeserver.log" --timeout=300

#=================================================
# END OF SCRIPT
#=================================================

ynh_script_progression --message="Upgrade of $app completed" --last