#!/bin/bash
# postinst for edgeguard-api — creates system user, filesystem layout,
# initialises PostgreSQL (role + db + migrations), enables systemd
# units. Each step idempotent; safe to re-run on every upgrade.
set -e

export LC_ALL=C
export LANG=C

EG_USER="edgeguard"
EG_HOME="/var/lib/edgeguard"

case "$1" in
    configure)
        # ── System user ──────────────────────────────────────────────
        if ! getent passwd "$EG_USER" >/dev/null; then
            adduser --system --group --home "$EG_HOME" \
                    --shell /usr/sbin/nologin --no-create-home \
                    --gecos "EdgeGuard daemon" "$EG_USER"
        fi

        # ── Directories ──────────────────────────────────────────────
        for d in /etc/edgeguard /var/lib/edgeguard /var/log/edgeguard \
                 /etc/edgeguard/haproxy /etc/edgeguard/squid \
                 /etc/edgeguard/wireguard /etc/edgeguard/unbound \
                 /etc/edgeguard/nftables.d /etc/edgeguard/tls \
                 /var/lib/edgeguard/acme; do
            install -d -m 0750 -o "$EG_USER" -g "$EG_USER" "$d"
        done
        # ACME-Account-Dir 0700 — hält den lego-Account-Schlüssel,
        # gehört nur edgeguard.
        install -d -m 0700 -o "$EG_USER" -g "$EG_USER" /var/lib/edgeguard/acme-account

        # ── sudoers: HAProxy reload + (later) systemd-networkd reload
        # Damit edgeguard-api nach einer SSL- oder Netzwerk-Mutation
        # selbst reloaden kann ohne root zu sein. NOPASSWD ist auf
        # genau dieses Kommando beschränkt.
        cat > /etc/sudoers.d/edgeguard <<'SUDOERS'
edgeguard ALL=(root) NOPASSWD: /usr/bin/systemctl reload haproxy.service
edgeguard ALL=(root) NOPASSWD: /bin/systemctl reload haproxy.service
edgeguard ALL=(root) NOPASSWD: /usr/sbin/nft -f /etc/edgeguard/nftables.d/ruleset.nft
edgeguard ALL=(root) NOPASSWD: /usr/bin/systemctl start wg-quick@*.service
edgeguard ALL=(root) NOPASSWD: /usr/bin/systemctl restart wg-quick@*.service
edgeguard ALL=(root) NOPASSWD: /usr/bin/systemctl stop wg-quick@*.service
edgeguard ALL=(root) NOPASSWD: /bin/systemctl start wg-quick@*.service
edgeguard ALL=(root) NOPASSWD: /bin/systemctl restart wg-quick@*.service
edgeguard ALL=(root) NOPASSWD: /bin/systemctl stop wg-quick@*.service
edgeguard ALL=(root) NOPASSWD: /usr/bin/wg show all dump
edgeguard ALL=(root) NOPASSWD: /usr/bin/wg show *
SUDOERS
        chmod 0440 /etc/sudoers.d/edgeguard

        # ── Sysctl-Profil für Edge-Gateway (NAT + HAProxy + Forwarding) ──
        # Voraussetzung für NAT/DNAT/Masquerade + sinnvolle Defaults
        # für eine high-throughput Forwarding-Box. Edit nicht von Hand
        # — Re-install vom Package überschreibt die Datei. Eigene
        # Tweaks gehören in eine Datei mit höherer Nummer als 99.
        rm -f /etc/sysctl.d/99-edgeguard-forward.conf  # Vorgänger
        cat > /etc/sysctl.d/99-edgeguard.conf <<'SYSCTL'
# ── Managed by edgeguard ────────────────────────────────────────────
# Lade-Reihenfolge: 99-* überschreibt distro-Defaults. Eigene
# Operator-Tweaks: /etc/sysctl.d/99-zzz-local.conf (lexikografisch
# später) — nicht in DIESE Datei!

# ─── Forwarding (NAT/DNAT/Masquerade) ───────────────────────────────
net.ipv4.ip_forward                 = 1
net.ipv6.conf.all.forwarding        = 1
net.ipv4.conf.all.send_redirects    = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.all.accept_redirects  = 0
net.ipv6.conf.all.accept_redirects  = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0

# ─── Reverse-Path-Filter (anti-spoof, loose-Modus für asymmetrisches
#     Routing wie Multi-WAN / WireGuard split) ─────────────────────
net.ipv4.conf.all.rp_filter      = 2
net.ipv4.conf.default.rp_filter  = 2

# ─── Conntrack — Edge-Box trackt viele parallele Sessions ─────────
net.netfilter.nf_conntrack_max                        = 524288
net.netfilter.nf_conntrack_tcp_timeout_established    = 86400
net.netfilter.nf_conntrack_tcp_timeout_time_wait      = 30
net.netfilter.nf_conntrack_tcp_timeout_close_wait     = 30
net.netfilter.nf_conntrack_buckets                    = 131072

# ─── TCP/IP-Stack-Tuning für HAProxy + viele Backends ─────────────
net.core.somaxconn          = 65535
net.core.netdev_max_backlog = 16384
net.core.rmem_max           = 16777216
net.core.wmem_max           = 16777216
net.core.rmem_default       = 262144
net.core.wmem_default       = 262144
net.ipv4.tcp_rmem           = 4096 87380 16777216
net.ipv4.tcp_wmem           = 4096 65536 16777216
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_fin_timeout    = 15
net.ipv4.tcp_tw_reuse       = 1
net.ipv4.tcp_keepalive_time     = 300
net.ipv4.tcp_keepalive_probes   = 5
net.ipv4.tcp_keepalive_intvl    = 30
net.ipv4.tcp_mtu_probing    = 1
net.ipv4.tcp_slow_start_after_idle = 0
net.ipv4.tcp_no_metrics_save = 1
net.ipv4.ip_local_port_range = 10240 65535

# ─── Modern congestion control + queueing (BBR + fq) ──────────────
# Wenn der Kernel BBR nicht hat, fällt Linux still auf cubic zurück.
net.ipv4.tcp_congestion_control = bbr
net.core.default_qdisc          = fq

# ─── Anti-DoS / Hardening ─────────────────────────────────────────
net.ipv4.tcp_syncookies                  = 1
net.ipv4.icmp_echo_ignore_broadcasts     = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
net.ipv4.conf.all.log_martians           = 1
kernel.kptr_restrict                     = 2
kernel.dmesg_restrict                    = 1

# ─── Memory ───────────────────────────────────────────────────────
vm.swappiness     = 10
vm.dirty_ratio    = 20
vm.dirty_background_ratio = 5
SYSCTL
        sysctl --system >/dev/null 2>&1 || true

        # ── Self-signed default cert so HAProxy starts cleanly ───────
        # HAProxy `bind :443 ssl crt /etc/edgeguard/tls/` needs at least
        # one PEM in the directory to come up. Operator runs certbot
        # later; until then, browsers see an unverified cert which is
        # the expected first-boot UX.
        DEFAULT_PEM="/etc/edgeguard/tls/_default.pem"
        if [ ! -f "$DEFAULT_PEM" ]; then
            HOSTNAME_FQDN="$(hostname -f 2>/dev/null || hostname)"
            TMP_KEY="$(mktemp)"
            TMP_CRT="$(mktemp)"
            openssl req -x509 -nodes -newkey rsa:2048 \
                -keyout "$TMP_KEY" -out "$TMP_CRT" \
                -days 3650 \
                -subj "/CN=$HOSTNAME_FQDN" \
                -addext "subjectAltName = DNS:$HOSTNAME_FQDN,DNS:localhost" \
                >/dev/null 2>&1
            cat "$TMP_CRT" "$TMP_KEY" > "$DEFAULT_PEM"
            chown "$EG_USER:$EG_USER" "$DEFAULT_PEM"
            chmod 0640 "$DEFAULT_PEM"
            rm -f "$TMP_KEY" "$TMP_CRT"
        fi

        # ── Pre-flight: validate embedded migration set ──────────────
        # Catches duplicate version prefixes BEFORE we touch the DB,
        # so a broken upgrade can't half-apply migrations and leave
        # the cluster wedged (mail-gateway 2026-05-08 incident).
        if ! /usr/bin/edgeguard-ctl migrate check; then
            echo "postinst: embedded migrations failed validation — aborting" >&2
            exit 1
        fi

        # ── PostgreSQL: ensure role + database exist ─────────────────
        # Requires postgresql-16 (or -17) running locally — guaranteed
        # by Depends. Idempotent — re-runs on upgrade are no-ops.
        if ! /usr/bin/edgeguard-ctl initdb; then
            echo "postinst: edgeguard-ctl initdb failed — aborting" >&2
            exit 1
        fi

        # ── Apply pending schema migrations ──────────────────────────
        if ! sudo -n -u "$EG_USER" /usr/bin/edgeguard-ctl migrate up; then
            echo "postinst: edgeguard-ctl migrate up failed — aborting" >&2
            exit 1
        fi

        # ── Render initial service configs ───────────────────────────
        # Writes /etc/edgeguard/haproxy/haproxy.cfg + nftables.d/
        # ruleset.nft from the (just-migrated, empty) PG state.
        #
        # haproxy bekommt --no-reload (drop-in unten zeigt erst danach
        # auf unsere cfg; wir restarten explizit); nftables muss aber
        # aktiv reloadet werden, sonst läuft das Kernel-Set bei Template-
        # Änderungen (z.B. neue anti-lockout-Ports) hinterher.
        if ! sudo -n -u "$EG_USER" /usr/bin/edgeguard-ctl render-config --only=haproxy --no-reload; then
            echo "postinst: edgeguard-ctl render-config (haproxy) failed — aborting" >&2
            exit 1
        fi
        if ! sudo -n -u "$EG_USER" /usr/bin/edgeguard-ctl render-config --only=nftables; then
            echo "postinst: edgeguard-ctl render-config (nftables) failed — aborting" >&2
            exit 1
        fi

        # ── HAProxy systemd drop-in: read EdgeGuard config ───────────
        # Keeps the distro /etc/haproxy/haproxy.cfg untouched (it's a
        # conffile of the haproxy package). Drop-in is reversible by
        # removing the file + daemon-reload.
        install -d /etc/systemd/system/haproxy.service.d
        if [ -f /etc/edgeguard/systemd/haproxy-edgeguard.conf ]; then
            install -m 0644 /etc/edgeguard/systemd/haproxy-edgeguard.conf \
                            /etc/systemd/system/haproxy.service.d/edgeguard.conf
        fi

        # ── systemd: pick up new units + restart haproxy with our cfg
        systemctl daemon-reload
        systemctl restart haproxy.service || true
        systemctl enable --now edgeguard-api.service edgeguard-scheduler.service || true
        ;;

    abort-upgrade|abort-remove|abort-deconfigure)
        ;;

    *)
        echo "postinst called with unknown argument \`$1'" >&2
        exit 1
        ;;
esac

#DEBHELPER#

exit 0
