#!/bin/bash
################################################################################
# Script Name: version/3.4.0/UPDATE.sh
# Description: Apply version 3.4.0 migrations - the Resource & Isolation,
#              Backup and Security platforms of the feature blueprint:
#              - HiTech Resource Engine (native-limits in Rust: overrides,
#                live usage, history, one-minute policy timer)
#              - CageFS-like jail in Rust, SecureLinks/ptrace sysctls, cron
#                jobs inside the jail (sudoers rule for every account)
#              - php-fpm master per account inside its slice (native-fpm;
#                opt-in on updated servers, see below)
#              - PHP Selector per account, HardenedPHP status, Runtime Selector
#              - restic backup engine, immutable/DR backups (opt-in per account)
#              - WAF risk bands + progressive ban + Security Center; the WAF
#                now has an origin for Caddy/Lighttpd/H2O/Cherokee sites
#              - Varnish cache tags (purge by tag, warm-up)
#              - hitechcloud-rustcli is required from this version on
# Company/Brand: HiTechCloud by Pho Tue SoftWare Solutions JSC
################################################################################

set -uo pipefail
GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
ok()   { echo -e "[3.4.0] ${GREEN}✓${NC} $*"; }
warn() { echo -e "[3.4.0] ${YELLOW}!${NC} $*" >&2; }
[[ $EUID -eq 0 ]] || { echo "[3.4.0] This update must run as root." >&2; exit 1; }

VERSION="3.4.0"
SRC="${HITECHCLOUD_SRC:-/opt/hitechcloud}"
CLI_DIR="/usr/local/hitechcloudcli"
RUSTCLI="/usr/local/bin/hitechcloud-rustcli"

mkdir -p /usr/local/hitechcloud /etc/hitechcloud 2>/dev/null || true
echo "$VERSION" > /usr/local/hitechcloud/version 2>/dev/null || true
echo "$VERSION" > /etc/hitechcloud/version 2>/dev/null || true

# 1. CLI scripts (the regular updater copied the tree; make sure of it).
if [[ -d "${SRC}/hitechcloudcli" ]]; then
    rsync -a --exclude '.git' --exclude 'rustcli/target' "${SRC}/hitechcloudcli/" "${CLI_DIR}/" 2>/dev/null || cp -a "${SRC}/hitechcloudcli/." "${CLI_DIR}/"
    ok "CLI scripts synced from ${SRC}/hitechcloudcli"
fi
find "$CLI_DIR" -name '*.sh' -exec chmod +x {} \; 2>/dev/null || true
[[ -f "${CLI_DIR}/hitechcloudcli" ]] && install -m 755 "${CLI_DIR}/hitechcloudcli" /usr/local/bin/hitechcloudcli

# 2. The Rust CLI is required now: every feature this version adds lives in
#    it. The updater refreshes it with the panel binaries; this fetches it
#    when that did not happen (an older updater) or when what is installed
#    predates the commands the scripts now call.
need_rustcli=1
if [[ -x "$RUSTCLI" ]] && "$RUSTCLI" ported 2>/dev/null | grep -qx native-fpm; then
    need_rustcli=0
fi
if (( need_rustcli )); then
    arch=$(uname -m); case "$arch" in x86_64) arch=amd64 ;; aarch64) arch=arm64 ;; esac
    tmp=$(mktemp /tmp/hitechcloud-rustcli.XXXXXX)
    if curl -fsSL --retry 3 --connect-timeout 20 "https://mirrors.hitechcloud.org/releases/${VERSION}/hitechcloud-rustcli-linux-${arch}" -o "$tmp" 2>/dev/null \
       || curl -fsSL --retry 3 --connect-timeout 20 "https://github.com/hitechcloud-vietnam/HiTechCloud-Panel/releases/download/v${VERSION}/hitechcloud-rustcli-linux-${arch}" -o "$tmp" 2>/dev/null; then
        if head -c 4 "$tmp" | grep -q $'\x7fELF'; then
            install -m 755 "$tmp" "$RUSTCLI" && ok "hitechcloud-rustcli ${VERSION} installed"
        else
            warn "the downloaded hitechcloud-rustcli is not an executable; not installed"
        fi
    else
        warn "hitechcloud-rustcli could not be downloaded - the Resource Engine, jail, backup engine and Security Center need it: rerun the update once the mirror is reachable"
    fi
    rm -f "$tmp"
fi
[[ -x "$RUSTCLI" ]] || { warn "no hitechcloud-rustcli; the rest of this update is skipped"; systemctl restart hitechcloud >/dev/null 2>&1 || true; exit 0; }

# 3. The jail: /usr/local/bin/hitechcloud-jail is the script, which now hands
#    the shell to the Rust binary; every account gets the sudoers rule that
#    lets it open its own jail (cron jobs run through it), and the host gets
#    the SecureLinks / ptrace sysctls.
if [[ -f "${CLI_DIR}/native/jail.sh" ]]; then
    install -m 755 "${CLI_DIR}/native/jail.sh" /usr/local/bin/hitechcloud-jail
    install -m 755 "${CLI_DIR}/native/restricted-shell.sh" /usr/local/bin/hitechcloud-shell 2>/dev/null || true
    ok "hitechcloud-jail refreshed (Rust jail behind it)"
fi

if [[ -f /etc/hitechcloud/native/native.conf ]]; then
    "$RUSTCLI" native-jail sudoers --all >/dev/null 2>&1 && ok "jail sudoers rule written for every account" || warn "native-jail sudoers --all reported a problem"
    "$RUSTCLI" native-jail harden >/dev/null 2>&1 && ok "isolation sysctls applied (SecureLinks, ptrace)" || warn "isolation sysctls could not be applied"

    # 4. Templates (policy.vcl with cache tags, waf.conf.default with every
    #    engine's origin) and the per-account Varnish VCLs rendered from them.
    if [[ -d "${SRC}/hitechcloudpanel/configuration-native" ]]; then
        cp -a "${SRC}/hitechcloudpanel/configuration-native/." /etc/hitechcloud/native/templates/ 2>/dev/null && ok "Templates refreshed"
    fi
    hitechcloudcli native-varnish sync >/dev/null 2>&1 && ok "Varnish VCLs re-rendered (cache tags)" || true

    # 5. Resource Engine: plan limits re-applied (the account's Varnish and
    #    memcached instances join its slice; existing overrides are kept),
    #    then the one-minute policy timer.
    hitechcloudcli native-limits apply-all >/dev/null 2>&1 && ok "plan limits re-applied to every account" || warn "native-limits apply-all did not run cleanly"
    "$RUSTCLI" native-limits enable >/dev/null 2>&1 && ok "hitechcloud-resources.timer enabled (usage, violations, throttling)" || warn "the Resource Engine timer could not be enabled"

    # 6. DB Governor's timer, where the server has a database.
    if command -v mysql >/dev/null 2>&1; then
        "$RUSTCLI" native-dbgovernor enable >/dev/null 2>&1 && ok "DB Governor timer enabled" || true
    fi

    # 7. The firewall service: the updater installed the new binary; a
    #    restart makes the risk bands and the bans endpoint live.
    if systemctl is-active --quiet hitechcloud-waf 2>/dev/null; then
        systemctl restart hitechcloud-waf >/dev/null 2>&1 && ok "hitechcloud-waf restarted" || warn "hitechcloud-waf did not restart; check: journalctl -u hitechcloud-waf"
    fi

    # 8. restic, for the backup engine an account may now choose. Best
    #    effort: without it the schedule page offers tar chains only.
    if ! command -v restic >/dev/null 2>&1 && [[ "${HITECHCLOUD_UPDATE_SKIP_RESTIC:-0}" != "1" ]]; then
        "$RUSTCLI" native-backup install >/dev/null 2>&1 && ok "restic installed (repository backups available)" || warn "restic not installed; accounts keep tar chains (hitechcloudcli native-backup install)"
    fi

    # 9. A php-fpm master per account, inside its slice. On by default for a
    #    fresh install; an updated server switches over here only when asked,
    #    because it moves every site's PHP workers to a new master (a
    #    second of 502 per site while sockets change hands).
    if [[ "${HITECHCLOUD_UPDATE_FPM_PER_ACCOUNT:-0}" == "1" ]]; then
        "$RUSTCLI" native-fpm enable && ok "per-account PHP-FPM enabled"
    else
        echo "[3.4.0] per-account PHP-FPM (every account's PHP workers under its own plan limits) is one command away:"
        echo "[3.4.0]     hitechcloudcli native-fpm enable"
    fi
fi

# 10. Both panels read their catalogue and units at startup.
systemctl restart hitechcloud >/dev/null 2>&1 || true
systemctl restart hitechadmin >/dev/null 2>&1 || true
ok "Version ${VERSION} applied. Security Center: https://<server>:2087/security/waf - Resource Engine: hitechcloudcli native-limits usage"
