#!/usr/bin/env bash
#
# Copyright (c) 2024 YunoHost Contributors
#
# This file is part of YunoHost (see https://yunohost.org)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#

# Exit hook on subcommand error or unset variable
set -eu

base_folder_and_perm_init() {

    #############################
    # Base yunohost conf folder #
    #############################

    mkdir -p /etc/yunohost
    # NB: x permission for 'others' is important for ssl-cert (and maybe mdns), otherwise slapd will fail to start because can't access the certs
    chmod 755 /etc/yunohost

    ################
    # Logs folders #
    ################

    mkdir -p /var/log/yunohost
    chown root:root /var/log/yunohost
    chmod 750 /var/log/yunohost

    ##################
    # Portal folders #
    ##################

    getent passwd ynh-portal &> /dev/null || useradd --no-create-home --shell /usr/sbin/nologin --system --user-group ynh-portal

    mkdir -p /etc/yunohost/portal
    chmod 500 /etc/yunohost/portal
    chown ynh-portal:ynh-portal /etc/yunohost/portal

    mkdir -p /usr/share/yunohost/portal/customassets
    chmod 775 /usr/share/yunohost/portal/customassets
    chown root:root /usr/share/yunohost/portal/customassets

    touch /var/log/yunohost-portalapi.log
    chown ynh-portal:root /var/log/yunohost-portalapi.log
    chmod 600 /var/log/yunohost-portalapi.log

    ###############################
    # Sessions folder and secrets #
    ###############################

    # Portal
    mkdir -p /var/cache/yunohost-portal/sessions
    chown ynh-portal:www-data /var/cache/yunohost-portal
    chmod 510 /var/cache/yunohost-portal
    chown ynh-portal:www-data /var/cache/yunohost-portal/sessions
    chmod 710 /var/cache/yunohost-portal/sessions

    # Webadmin
    mkdir -p /var/cache/yunohost/sessions
    chown root:root /var/cache/yunohost/sessions
    chmod 700 /var/cache/yunohost/sessions

    if test -e /etc/yunohost/installed; then
        # Initialize session secrets
        # Obviously we only do this in the post_regen, ie during the postinstall, because we don't want every pre-installed instance to have the same secret
        if [ ! -e /etc/yunohost/.admin_cookie_secret ]; then
            dd if=/dev/urandom bs=1 count=1000 2> /dev/null | tr --complement --delete 'A-Za-z0-9' | head -c 64 > /etc/yunohost/.admin_cookie_secret
        fi
        chown root:root /etc/yunohost/.admin_cookie_secret
        chmod 400 /etc/yunohost/.admin_cookie_secret

        if [ ! -e /etc/yunohost/.ssowat_cookie_secret ]; then
            # NB: we need this to be exactly 32 char long, because it is later used as a key for AES256
            dd if=/dev/urandom bs=1 count=1000 2> /dev/null | tr --complement --delete 'A-Za-z0-9' | head -c 32 > /etc/yunohost/.ssowat_cookie_secret
        fi
        chown ynh-portal:root /etc/yunohost/.ssowat_cookie_secret
        chmod 400 /etc/yunohost/.ssowat_cookie_secret
    fi

    ##################
    # Domain folders #
    ##################

    mkdir -p /etc/yunohost/domains
    chown root /etc/yunohost/domains
    chmod 700 /etc/yunohost/domains

    ###############
    # App folders #
    ###############

    mkdir -p /etc/yunohost/apps
    chown root /etc/yunohost/apps
    chmod 700 /etc/yunohost/apps

    #####################
    # Apps data folders #
    #####################

    mkdir -p /home/yunohost.app
    chmod 755 /home/yunohost.app

    ################
    # Certs folder #
    ################

    mkdir -p /etc/yunohost/certs
    chown -R root:ssl-cert /etc/yunohost/certs
    chmod 750 /etc/yunohost/certs
    # We do this with find because there could be a lot of them...
    find /etc/yunohost/certs/ -type f -exec chmod 640 {} \;
    find /etc/yunohost/certs/ -type d -exec chmod 750 {} \;

    ##################
    # Backup folders #
    ##################

    mkdir -p /home/yunohost.backup/archives
    chmod 770 /home/yunohost.backup
    chmod 770 /home/yunohost.backup/archives

    if test -e /etc/yunohost/installed; then
        # The admins group only exist after the postinstall
        chown root:admins /home/yunohost.backup
        chown root:admins /home/yunohost.backup/archives
    else
        chown root:root /home/yunohost.backup
        chown root:root /home/yunohost.backup/archives
    fi

    ########
    # Misc #
    ########

    mkdir -p /etc/yunohost/hooks.d
    chown root /etc/yunohost/hooks.d
    chmod 700 /etc/yunohost/hooks.d

    mkdir -p /var/cache/yunohost/repo
    chown root:root /var/cache/yunohost
    chmod 700 /var/cache/yunohost

    [ ! -e /var/www/.well-known/ynh-diagnosis/ ] || chmod 775 /var/www/.well-known/ynh-diagnosis/

    if test -e /etc/yunohost/installed; then
        # We use "|| true" because some filesystem do not support ACL (such as NTFS ... for example when incus storage is on an NTFS drive in dir storage)
        setfacl -m g:all_users:--- /var/www || true
        setfacl -m g:all_users:--- /var/log/nginx || true
        setfacl -m g:all_users:--- /etc/yunohost || true
        setfacl -m g:all_users:--- /etc/ssowat || true
    fi
}

do_init_regen() {

    cd /usr/share/yunohost/conf/yunohost

    base_folder_and_perm_init

    # Empty ssowat json persistent conf
    echo "{}" > '/etc/ssowat/conf.json.persistent'
    chmod 644 /etc/ssowat/conf.json.persistent
    chown root:root /etc/ssowat/conf.json.persistent
    echo "{}" > '/etc/ssowat/conf.json'
    chmod 644 /etc/ssowat/conf.json
    chown root:root /etc/ssowat/conf.json

    # Empty service conf
    touch /etc/yunohost/services.yml

    # set default current_host
    [[ -f /etc/yunohost/current_host ]] \
        || echo "yunohost.org" > /etc/yunohost/current_host

    # copy default services and firewall
    [[ -f /etc/yunohost/firewall.yml ]] \
        || cp firewall.yml /etc/yunohost/firewall.yml

    # allow users to access /media directory
    [[ -d /etc/skel/media ]] \
        || (mkdir -p /media && ln -s /media /etc/skel/media)

    # YunoHost services
    cp yunohost-api.service /etc/systemd/system/yunohost-api.service
    cp yunohost-portal-api.service /etc/systemd/system/yunohost-portal-api.service
    cp yunoprompt.service /etc/systemd/system/yunoprompt.service

    systemctl daemon-reload

    systemctl enable yunohost-api.service --quiet
    systemctl start yunohost-api.service

    systemctl enable yunohost-portal-api.service --quiet
    systemctl start yunohost-portal-api.service

    # Enable yunoprompt (in particular for installs from ISO where we want this to show on first boot instead of asking for a login/password)
    systemctl enable yunoprompt --quiet

    # Yunohost-firewall is enabled only during postinstall, not init, not 100% sure why

    cp dpkg-origins /etc/dpkg/origins/yunohost

    # Change dpkg vendor
    # see https://wiki.debian.org/Derivatives/Guidelines#Vendor
    if readlink -f /etc/dpkg/origins/default | grep -q debian; then
        rm -f /etc/dpkg/origins/default
        ln -s /etc/dpkg/origins/yunohost /etc/dpkg/origins/default
    fi
}

do_pre_regen() {
    pending_dir=$1

    cd /usr/share/yunohost/conf/yunohost

    mkdir -p "$pending_dir/etc/systemd/system"
    mkdir -p "$pending_dir/etc/cron.d/"
    mkdir -p "$pending_dir/etc/cron.daily/"

    # Twice a day job for YunoHost diagnosis
    cp yunohost-diagnosis.timer "$pending_dir/etc/systemd/system/yunohost-diagnosis.timer"
    cp yunohost-diagnosis.service "$pending_dir/etc/systemd/system/yunohost-diagnosis.service"

    # Daily job for app catalog update
    cp yunohost-update-catalog.timer "$pending_dir/etc/systemd/system/yunohost-update-catalog.timer"
    cp yunohost-update-catalog.service "$pending_dir/etc/systemd/system/yunohost-update-catalog.service"

    # Daily job for SSL certificate update
    cp yunohost-renew-certs.timer "$pending_dir/etc/systemd/system/yunohost-renew-certs.timer"
    cp yunohost-renew-certs.service "$pending_dir/etc/systemd/system/yunohost-renew-certs.service"

    # Every 10 minutes job to update the DynDNS records
    # It will only be enabled if we actually subscribed to a dyndns domain
    cp yunohost-dyndns.timer "$pending_dir/etc/systemd/system/yunohost-dyndns.timer"
    cp yunohost-dyndns.service "$pending_dir/etc/systemd/system/yunohost-dyndns.service"

    # Every 10 minutes job to update UPnP (if enabled)
    cp yunohost-firewall-upnp.timer "$pending_dir/etc/systemd/system/yunohost-firewall-upnp.timer"
    cp yunohost-firewall-upnp.service "$pending_dir/etc/systemd/system/yunohost-firewall-upnp.service"

    # Skip ntp if inside a container (inspired from the conf of systemd-timesyncd)
    if systemctl | grep -q 'ntp.service'; then
        mkdir -p "$pending_dir/etc/systemd/system/ntp.service.d/"
        cp ntp-ynh-override.conf "$pending_dir/etc/systemd/system/ntp.service.d/ynh-override.conf"
    fi

    mkdir -p "$pending_dir/etc/systemd/system/nftables.service.d/"
    cp yunohost-nftables-hooks-override.conf "$pending_dir/etc/systemd/system/nftables.service.d/yunohost-nftables-hooks.conf"

    # Don't suspend computer on LidSwitch
    mkdir -p "$pending_dir/etc/systemd/logind.conf.d/"
    cp logind-ynh-override.conf "$pending_dir/etc/systemd/logind.conf.d/ynh-override.conf"

    cp yunohost-api.service "$pending_dir/etc/systemd/system/yunohost-api.service"
    cp yunohost-portal-api.service "$pending_dir/etc/systemd/system/yunohost-portal-api.service"
    cp yunoprompt.service "$pending_dir/etc/systemd/system/yunoprompt.service"
    cp proc-hidepid.service "$pending_dir/etc/systemd/system/proc-hidepid.service"

    mkdir -p "$pending_dir/etc/dpkg/origins/"
    cp dpkg-origins "$pending_dir/etc/dpkg/origins/yunohost"

    # Delete legacy conflict between yunohost and nftables
    touch "$pending_dir/etc/systemd/system/nftables.service.d/ynh-override.conf"

    # Delete legacy yunohost-firewall service
    touch "$pending_dir/etc/systemd/system/yunohost-firewall.service"

    # Remove legacy hackish/clumsy nodejs autoupdate which ends up filling up space with ambiguous upgrades >_>
    touch "$pending_dir/etc/cron.daily/node_update"

    # Remove legacy crons replaced with systemd timers/services
    touch "$pending_dir/etc/cron.d/yunohost-diagnosis"
    touch "$pending_dir/etc/cron.daily/yunohost-fetch-apps-catalog"
    touch "$pending_dir/etc/cron.daily/yunohost-certificate-renew"
    touch "$pending_dir/etc/cron.d/yunohost-dyndns"
}

do_post_regen() {
    regen_conf_files=$1

    # Re-mkdir / apply permission to all basic folders etc
    base_folder_and_perm_init

    # Legacy log tree structure
    if [ ! -e /var/log/yunohost/operations ]; then
        mkdir -p /var/log/yunohost/operations
    fi
    if [ -d /var/log/yunohost/categories/operation ] && [ ! -L /var/log/yunohost/categories/operation ]; then
        # (we use find -type f instead of mv /folder/* to make sure to also move hidden files which are not included in globs by default)
        find /var/log/yunohost/categories/operation/ -type f -print0 | xargs -0 -I {} mv {} /var/log/yunohost/operations/
        # Attempt to delete the old dir (because we want it to be a symlink) or just rename it if it can't be removed (not empty) for some reason
        rmdir /var/log/yunohost/categories/operation || mv /var/log/yunohost/categories/operation /var/log/yunohost/categories/operation.old
        ln -s /var/log/yunohost/operations /var/log/yunohost/categories/operation
    fi

    # Make sure conf files why may be created by apps are owned and writable only by root
    find /etc/systemd/system/*.service -type f | xargs -r chown root:root
    find /etc/systemd/system/*.service -type f | xargs -r chmod 0644

    if ls -l /etc/php/*/fpm/pool.d/*.conf 2> /dev/null; then
        chown root:root /etc/php/*/fpm/pool.d/*.conf
        chmod 644 /etc/php/*/fpm/pool.d/*.conf
    fi

    for USER in $(yunohost user list --quiet --output-as json | jq -r '.users | .[] | .username'); do
        [ ! -e "/home/$USER" ] || setfacl -m g:all_users:--- "/home/$USER"
    done

    # Misc configuration / state files
    for file in /etc/yunohost/{*.yml,*.yaml,*.json,mysql,psql}; do
        if [ -f "$file" ]; then
            if [ "$file" != "mdns.yml" ]; then
                chown root:root "$file"
            fi
            chmod 600 "$file"
        fi
    done

    # Create ssh.app and sftp.app groups if they don't exist yet
    grep -q '^ssh.app:' /etc/group || groupadd ssh.app
    grep -q '^sftp.app:' /etc/group || groupadd sftp.app


    # Reload systemd if any system service was touched
    if [[ "$regen_conf_files" =~ "/etc/systemd/system" ]]; then
        systemctl daemon-reload
    fi

    # Propagates changes in systemd service config overrides
    if systemctl | grep -q 'ntp.service'; then
        [[ ! "$regen_conf_files" =~ "ntp.service.d/ynh-override.conf" ]] || {
            systemctl restart ntp
        }
    fi

    [[ ! "$regen_conf_files" =~ "login.conf.d/ynh-override.conf" ]] || {
        systemctl restart systemd-logind
    }

    if [[ "$regen_conf_files" =~ "yunoprompt.service" ]]; then
        action=$([[ -e /etc/systemd/system/yunoprompt.service ]] && echo 'enable' || echo 'disable')
        systemctl "$action" yunoprompt --quiet --now
    fi
    if [[ "$regen_conf_files" =~ "proc-hidepid.service" ]]; then
        action=$([[ -e /etc/systemd/system/proc-hidepid.service ]] && echo 'enable' || echo 'disable')
        systemctl "$action" proc-hidepid --quiet --now
    fi

    systemctl enable yunohost-diagnosis.timer --quiet --now
    systemctl enable yunohost-update-catalog.timer --quiet --now
    systemctl enable yunohost-renew-certs.timer --quiet --now

    # If we subscribed to a dyndns domain, enable the dyndns timer
    if ls -l /etc/yunohost/dyndns/K*.key 2> /dev/null; then
        systemctl enable yunohost-dyndns.timer --quiet --now
    else
        if systemctl is-active yunohost-dyndns.timer --quiet; then
            systemctl stop yunohost-dyndns.timer --quiet
        fi
        systemctl disable yunohost-dyndns.timer --quiet
    fi

    systemctl enable yunohost-portal-api.service --quiet
    systemctl is-active yunohost-portal-api --quiet || systemctl start yunohost-portal-api.service

    # If the legacy UPnP cron was installed, enable the systemd timer
    if [[ -f "/etc/cron.d/yunohost-firewall-upnp" ]]; then
        rm "/etc/cron.d/yunohost-firewall-upnp"
        systemctl enable yunohost-firewall-upnp.timer --quiet --now
    fi

    # Change dpkg vendor
    # see https://wiki.debian.org/Derivatives/Guidelines#Vendor
    if readlink -f /etc/dpkg/origins/default | grep -q debian; then
        rm -f /etc/dpkg/origins/default
        ln -s /etc/dpkg/origins/yunohost /etc/dpkg/origins/default
    fi

    if test -e /etc/yunohost/installed && test -e /etc/profile.d/check_yunohost_is_installed.sh; then
        rm /etc/profile.d/check_yunohost_is_installed.sh
    fi
}

"do_$1_regen" "$(echo "${*:2}" | xargs)"
