#!/bin/sh
# SPDX-FileCopyrightText: 2025-2026 Jörg Bernau <blacksmith@forgeiec.io>
# SPDX-License-Identifier: AGPL-3.0-or-later
#
# DIE GEMEINSAME MCP-CA anlegen — einmalig, idempotent.
#
# ── Warum das hier liegt und nicht in den Anwendungen ───────────────────────
#
# Weil die CA der Bibliothek gehört. `FMcpCertManager` stellt damit aus, also
# richtet das Paket der Bibliothek sie ein. Läge dasselbe in jedem Postinst von
# hearth-server, bellows-server und anvil-server, gäbe es drei Fassungen einer
# Zusage — und sie liefen auseinander, ohne sich zu melden.
#
# ── Warum eine CA und nicht wie bisher ──────────────────────────────────────
#
# Vorher war jedes Serverzertifikat selbstsigniert und trug `CA:TRUE`, damit
# Node es als Anker annimmt. Das Blatt war damit seine eigene Wurzel, und jede
# Neuausstellung entwertete den Anker: Bündel neu bauen UND jeden Client neu
# starten, weil Node `NODE_EXTRA_CA_CERTS` nur beim Prozessstart liest.
#
# Mit dieser Wurzel ändert sich der Anker nie mehr.
#
# ── Was es NICHT tut ────────────────────────────────────────────────────────
#
# Eine vorhandene CA ersetzen. Sie ist der Anker, den die Clients kennen; sie
# neu zu erzeugen holt genau das Problem zurück, das sie löst.
#
# Und sie NICHT in den Systemvertrauensspeicher legen. Sie gilt für
# MCP-Clients, und dafür genügt NODE_EXTRA_CA_CERTS. Unter
# /usr/local/share/ca-certificates glaubte jedes Programm der Maschine jedes
# von ihr signierte Zertifikat.
set -eu

CA_DIR=/etc/forgeiec/mcp-ca
CA_CRT="$CA_DIR/ca.crt"
CA_KEY="$CA_DIR/ca.key"

# Wer ausstellen darf. Die Anwendungen laufen unter diesem Konto bzw. ihre
# Bediener sind Mitglied dieser Gruppe.
SIGN_GROUP=blacksmith

install -d -m 0755 /etc/forgeiec
install -d -m 0755 "$CA_DIR"

if [ ! -f "$CA_CRT" ] || [ ! -f "$CA_KEY" ]; then
    if ! command -v openssl >/dev/null 2>&1; then
        echo "forgeiec-mcp-ca: openssl fehlt — CA nicht erzeugt, MCP bleibt ohne TLS" >&2
        exit 0
    fi
    # 20 Jahre: der Anker soll nicht ablaufen und damit dasselbe Neu-Vertrauen
    # erzwingen, das wir gerade abschaffen. pathlen:0 — sie stellt nur Blätter
    # aus, keine weiteren CAs.
    umask 077
    if openssl req -x509 -newkey rsa:4096 -nodes -days 7300 \
            -keyout "$CA_KEY" -out "$CA_CRT" \
            -subj "/CN=ForgeIEC MCP CA/O=ForgeIEC" \
            -addext "basicConstraints=critical,CA:TRUE,pathlen:0" \
            -addext "keyUsage=critical,keyCertSign,cRLSign" >/dev/null 2>&1; then
        echo "forgeiec-mcp-ca: CA erzeugt unter $CA_DIR"
    else
        echo "forgeiec-mcp-ca: CA konnte nicht erzeugt werden" >&2
        exit 0
    fi
fi

# Der SCHLÜSSEL nur für die Gruppe, die ausstellen darf; das ZERTIFIKAT für
# alle — es ist der Anker und muss gelesen werden können.
if [ -f "$CA_KEY" ]; then
    if getent group "$SIGN_GROUP" >/dev/null 2>&1; then
        chown "root:$SIGN_GROUP" "$CA_KEY" 2>/dev/null || true
        chmod 0640 "$CA_KEY" 2>/dev/null || true
    else
        # Ohne die Gruppe bleibt er root-only. Das ist die sichere Seite: dann
        # kann niemand ausstellen, statt dass jeder es kann.
        chmod 0600 "$CA_KEY" 2>/dev/null || true
        echo "forgeiec-mcp-ca: Gruppe $SIGN_GROUP fehlt — ca.key bleibt root-only" >&2
    fi
fi
[ -f "$CA_CRT" ] && chmod 0644 "$CA_CRT" 2>/dev/null || true

exit 0
