#!/usr/bin/env bash
# BrowserDesk Relay — Docker-Installation aus dem BrowserDesk-Feed (KB-0015).
#
# Lädt das fertige, versionierte Image (docker save) + das Compose-Bundle aus
# updates.browserdesk.de, prüft die SHA-256, lädt das Image und startet den Stack.
# Alles landet in EINEM Ordner (Default: ./browserdesk-relay); der Zustand liegt in dessen data/.
#
# Aufruf:
#   bash install-browserdesk-relay-docker.sh                       # neueste Version, Ordner ./browserdesk-relay
#   bash install-browserdesk-relay-docker.sh mein-relay 20260720.20  # Zielordner + feste Version
#   (per Pipe: curl -fsSL …/install-browserdesk-relay-docker.sh | bash -s -- mein-relay)
#
# Voraussetzungen: docker, Docker Compose v2, curl. Entpacken: unzip ODER python3.
set -euo pipefail

FEED="${BD_FEED:-https://updates.browserdesk.de/browserdesk-relay-docker}"

# Audit 04.09.2026 (S34): die Index-Datei des Feeds ist mit dem BrowserDesk-Feed-Schluessel signiert (ECDSA
# P-256, SHA-256). Ohne gueltige Signatur wird nichts installiert - ein untergeschobener Feed bleibt folgenlos.
BD_FEED_PUBKEY='-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEr0HItMnzx1CbztVnFFrIz2NJKr9b
hpYmU+VJ5AVCtoUni5zuMnzAu9DbKo8JeEBDQIMdj76zAbPuLz+Rk5QO7Q==
-----END PUBLIC KEY-----'
pruefe_feed_signatur() { # $1 = lokale Datei, $2 = URL der Datei (Signatur liegt unter URL.sig)
  command -v openssl >/dev/null 2>&1 || { echo "FEHLER: openssl fehlt - Feed-Signatur nicht pruefbar. Abbruch."; return 1; }
  local sig pub der
  sig="$(mktemp)"; pub="$(mktemp)"; der="$(mktemp)"
  if ! curl -fsSL --max-time 60 "$2.sig" -o "$sig"; then rm -f "$sig" "$pub" "$der"; echo "FEHLER: Signatur $2.sig fehlt - Abbruch."; return 1; fi
  printf '%s\n' "$BD_FEED_PUBKEY" > "$pub"
  if ! base64 -d "$sig" > "$der" 2>/dev/null; then rm -f "$sig" "$pub" "$der"; echo "FEHLER: Signatur $2.sig unlesbar - Abbruch."; return 1; fi
  if openssl dgst -sha256 -verify "$pub" -signature "$der" "$1" >/dev/null 2>&1; then rm -f "$sig" "$pub" "$der"; return 0; fi
  rm -f "$sig" "$pub" "$der"; echo "FEHLER: Signatur von $2 UNGUELTIG - Abbruch."; return 1
}
DIR="${1:-browserdesk-relay}"
WANT="${2:-}"

command -v docker >/dev/null 2>&1 || { echo "FEHLER: docker nicht gefunden."; exit 1; }
docker compose version >/dev/null 2>&1 || { echo "FEHLER: Docker Compose v2 nicht gefunden (docker compose)."; exit 1; }
command -v curl >/dev/null 2>&1 || { echo "FEHLER: curl nicht gefunden."; exit 1; }

mkdir -p "$DIR"
cd "$DIR"

echo "==> Feed lesen: $FEED/updates.ini"
curl -fsSL "$FEED/updates.ini" -o updates.ini
pruefe_feed_signatur updates.ini "$FEED/updates.ini" || exit 1
VER="$(sed -n 's/^version=//p' updates.ini | tr -d '\r')"
SHA="$(sed -n 's/^sha256=//p' updates.ini | tr -d '\r')"
URL="$(sed -n 's/^url=//p' updates.ini | tr -d '\r')"
CZIP="$(sed -n 's/^compose=//p' updates.ini | tr -d '\r')"
if [ -n "$WANT" ]; then
  # Feste Version gewünscht: URLs deterministisch bilden; die SHA aus updates.ini gilt nur
  # für die NEUESTE Version — bei einer älteren entfällt die Prüfung (Feed ist HTTPS).
  VER="$WANT"
  URL="$FEED/browserdesk-relay-docker-$VER.tar.gz"
  CZIP="$FEED/browserdesk-relay-docker-compose-$VER.zip"
  [ "$WANT" != "$(sed -n 's/^version=//p' updates.ini | tr -d '\r')" ] && SHA=""
fi
[ -n "$VER" ] || { echo "FEHLER: Feed unlesbar (version fehlt)."; exit 1; }
echo "==> Version: $VER"

TAR="browserdesk-relay-docker-$VER.tar.gz"
if [ ! -f "$TAR" ]; then
  echo "==> Image laden ($URL)"
  curl -fL --progress-bar "$URL" -o "$TAR"
fi
if [ -n "$SHA" ]; then
  echo "==> SHA-256 prüfen"
  echo "$SHA  $TAR" | sha256sum -c - || { echo "FEHLER: Prüfsumme stimmt NICHT — Abbruch."; exit 1; }
fi

echo "==> docker load"
docker load < "$TAR"

echo "==> Compose-Bundle laden + entpacken"
curl -fsSL "$CZIP" -o compose-bundle.zip
if command -v unzip >/dev/null 2>&1; then
  unzip -o -q compose-bundle.zip
elif command -v python3 >/dev/null 2>&1; then
  python3 -m zipfile -e compose-bundle.zip .
else
  echo "FEHLER: weder unzip noch python3 vorhanden."; exit 1
fi
rm -f compose-bundle.zip

mkdir -p data
[ -f data/relay.json ] || { cp relay.sample.json data/relay.json; echo "==> data/relay.json aus Vorlage angelegt"; }

# TLS: die Vorlage erwartet /data/cert.pfx — OHNE die Datei startet der Relay nicht (Crash-Loop).
# Deshalb: selbstsigniertes Zertifikat gleich erzeugen (openssl); ohne openssl auf HTTP zurückfallen.
if [ ! -f data/cert.pfx ] && grep -q '"CertificateFile": "/data/cert.pfx"' data/relay.json 2>/dev/null; then
  HOSTFQDN="$(hostname -f 2>/dev/null || hostname)"
  if command -v openssl >/dev/null 2>&1 && [ -f gen-cert.sh ]; then
    echo "==> Selbstsigniertes TLS-Zertifikat für '$HOSTFQDN' erzeugen (Browser warnt — für Produktion echtes Zertifikat, siehe README.md)"
    bash gen-cert.sh "$HOSTFQDN" >/dev/null
  else
    echo "==> Kein openssl gefunden — Relay startet ohne TLS (HTTP). Der Web-Client /app braucht HTTPS; später nachrüsten: ./gen-cert.sh <host> und CertificateFile in data/relay.json wieder auf /data/cert.pfx setzen."
    sed -i.bak 's#"CertificateFile": "/data/cert.pfx"#"CertificateFile": ""#' data/relay.json && rm -f data/relay.json.bak
  fi
fi
if [ ! -f .env ]; then
  if [ -f .env.example ]; then cp .env.example .env; else printf 'PUBLIC_IP=\n' > .env; fi
fi
# RELAY_VERSION auf das geladene Image zeigen lassen (Compose nutzt browserdesk-relay:<RELAY_VERSION>).
# Audit 04.09.2026 (S40): Datenbank-Passwort nie als Standardwert - fehlt es oder ist es leer, wird eines erzeugt.
if ! grep -q '^PG_PASSWORD=.\+' .env; then
  PW="$(head -c 32 /dev/urandom | base64 | tr -d '/+=' | head -c 28)"
  sed -i.bak '/^PG_PASSWORD=/d' .env && rm -f .env.bak
  printf 'PG_PASSWORD=%s\n' "$PW" >> .env
  echo "==> Datenbank-Passwort erzeugt und in .env eingetragen (PG_PASSWORD leer war)."
fi
if grep -q '^RELAY_VERSION=' .env; then
  sed -i.bak "s/^RELAY_VERSION=.*/RELAY_VERSION=$VER/" .env && rm -f .env.bak
else
  printf 'RELAY_VERSION=%s\n' "$VER" >> .env
fi

echo "==> Stack starten (docker compose up -d)"
docker compose up -d

echo
echo "FERTIG — BrowserDesk Relay $VER läuft."
echo "  Admin-Passwort : cat $(pwd)/data/admin-password.txt   (Erststart braucht ~1 Minute)"
echo "  Admin-Konsole  : https://<host>:9013/admin/   (selbstsigniertes Zertifikat → Browser-Warnung; ohne TLS: http://)"
echo "  WAN-Betrieb    : PUBLIC_IP in .env UND Turn.PublicIp in data/relay.json setzen, dann: docker compose up -d"
echo "  Backup         : der Ordner data/ enthält den kompletten Zustand."
