#!/usr/bin/env bash
# Setzt die Cloud-Firewall der Webserver und prüft danach, ob der Shop lebt.
#
#   hetzner-firewall.sh zeigen                    # aktuelle Regeln
#   hetzner-firewall.sh setzen  <ip>[,<ip>…]      # neue Regeln, SSH nur von diesen Quellen
#   hetzner-firewall.sh zurueck <sicherung.json>  # alten Stand wiederherstellen
#
# Token: Datei ~/.hetzner-token oder Umgebungsvariable HCLOUD_TOKEN.
#
# Warum 80 und 443 wegfallen können: der Load Balancer spricht die Webserver
# über das INTERNE Netz an (Ziele mit use_private_ip), auch für die
# Gesundheitsprüfung. Cloud-Firewalls filtern internen Verkehr nicht. Die
# TLS-Zertifikate sind Hetzner-verwaltet und werden am Load Balancer erneuert,
# nicht auf den Servern – es braucht also auch kein öffentliches Port 80 für
# eine ACME-Prüfung. Nach der Umstellung sind die Webserver aus dem Internet
# nur noch über SSH erreichbar, der Shop läuft unverändert über den LB.
set -euo pipefail

FIREWALL_ID="${FIREWALL_ID:-10593979}"   # Standard: "Webserver-Filter-Inbound"; per Umgebungsvariable überschreibbar
SHOP=https://shop.riccardo-zigarette.de/

TOKEN="${HCLOUD_TOKEN:-$(cat ~/.hetzner-token 2>/dev/null || true)}"
[ -n "$TOKEN" ] || { echo "Kein Token. HCLOUD_TOKEN setzen oder ~/.hetzner-token anlegen."; exit 1; }

api() { curl -sS -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" "$@"; }

zeigen() {
    api "https://api.hetzner.cloud/v1/firewalls/$FIREWALL_ID" | python3 -c '
import sys, json
f = json.load(sys.stdin)["firewall"]
print(f["name"])
for r in f["rules"]:
    q = ", ".join(r.get("source_ips", []))
    print("  %-3s %-4s %-12s %s" % (r["direction"], r["protocol"], r.get("port", "-"), q))'
}

case "${1:-zeigen}" in
zeigen)
    zeigen
    ;;
setzen)
    QUELLEN="${2:?IP-Liste fehlt, z. B. 178.105.61.101,203.0.113.7}"
    SICHERUNG="/tmp/firewall-$FIREWALL_ID-$(date +%Y%m%d-%H%M%S).json"
    api "https://api.hetzner.cloud/v1/firewalls/$FIREWALL_ID" > "$SICHERUNG"
    echo "Alter Stand gesichert: $SICHERUNG"

    echo -n "Shop vor der Änderung: "; curl -s -o /dev/null -w "%{http_code}\n" "$SHOP"

    REGELN=$(python3 - "$QUELLEN" <<'PY'
import json, sys
quellen = [q if "/" in q else q + "/32" for q in sys.argv[1].split(",") if q.strip()]
print(json.dumps({"rules": [{
    "direction": "in", "protocol": "tcp", "port": "22",
    "source_ips": quellen,
    "description": "SSH nur von festen Quellen",
}]}))
PY
)
    api -X POST "https://api.hetzner.cloud/v1/firewalls/$FIREWALL_ID/actions/set_rules" -d "$REGELN" >/dev/null
    echo "Regeln gesetzt. Neue Lage:"; zeigen

    sleep 8
    echo -n "Shop nach der Änderung: "
    CODE=$(curl -s -o /dev/null -w "%{http_code}" "$SHOP")
    echo "$CODE"
    if [ "$CODE" = "000" ]; then
        echo "KEINE ANTWORT – Rückweg: $0 zurueck $SICHERUNG"
        exit 1
    fi
    ;;
zurueck)
    DATEI="${2:?Sicherungsdatei fehlt}"
    REGELN=$(python3 -c 'import json,sys; print(json.dumps({"rules": json.load(open(sys.argv[1]))["firewall"]["rules"]}))' "$DATEI")
    api -X POST "https://api.hetzner.cloud/v1/firewalls/$FIREWALL_ID/actions/set_rules" -d "$REGELN" >/dev/null
    echo "Alter Stand wiederhergestellt:"; zeigen
    ;;
*)
    echo "Unbekannter Befehl. zeigen | setzen <ips> | zurueck <datei>"; exit 1
    ;;
esac
