"use client"; import { Download, Eye, Trash2, TriangleAlert } from "lucide-react"; import { usePathname, useRouter, useSearchParams } from "next/navigation"; import { useEffect, useRef, useState, useTransition } from "react"; import { Ankreuzfeld, Button, Formularfehler } from "@/components/ui"; import { MonoBlock } from "@/components/ui/MonoBlock"; import { istLaufend, useVorgang } from "@/components/vorgang/useVorgang"; import { abholungAnfordernAktion, privateKeyAnzeigenAktion, privateKeyLoeschenAktion, type PrivateKeyAntwort, } from "@/server/actions/privatekey"; /** * Private Key anzeigen, herunterladen und loeschen (#014). Alles verlangt frische * Bestaetigung; fehlt sie, geht es nach /bestaetigen und von dort mit `?privatekey=1` zurueck, * damit der Dialog gleich wieder offen ist. * * Der Key lebt nur im Zustand dieses Dialogs und wird beim Schliessen verworfen. */ const DIALOG_KLASSEN = "border-border-strong bg-surface text-text rounded-karte m-auto w-[calc(100%-32px)] max-w-2xl border p-5 backdrop:bg-black/70 sm:p-6"; function useBestaetigungUmleitung() { const router = useRouter(); const pfad = usePathname(); return (antwort: PrivateKeyAntwort): boolean => { if (!antwort.bestaetigen) return false; router.push(`/bestaetigen?ziel=${encodeURIComponent(`${pfad}?privatekey=1`)}`); return true; }; } export function PrivateKeyAnzeigen({ schluesselId, name }: { schluesselId: string; name: string }) { const dialog = useRef(null); const download = useRef(null); const suche = useSearchParams(); const umleiten = useBestaetigungUmleitung(); const [zweck, setZweck] = useState<"anzeigen" | "herunterladen">(); const [vorgangId, setVorgangId] = useState(); const [privateKey, setPrivateKey] = useState(); const [fehler, setFehler] = useState(); const [startet, starten] = useTransition(); const { stand, abfrageFehler } = useVorgang(vorgangId); const abgeholt = useRef(undefined); // Zurueck von /bestaetigen: Dialog gleich oeffnen. useEffect(() => { if (suche.get("privatekey") === "1") dialog.current?.showModal(); }, [suche]); // Bereit? Dann genau einmal abholen – als Anzeige oder als Download-Formular. useEffect(() => { if (!vorgangId || stand?.status !== "ERLEDIGT" || abgeholt.current === vorgangId) return; abgeholt.current = vorgangId; if (zweck === "herunterladen") { download.current?.submit(); return; } void privateKeyAnzeigenAktion(vorgangId).then((antwort) => { if (umleiten(antwort)) return; if (antwort.fehler) setFehler(antwort.fehler); else setPrivateKey(antwort.privateKey); }); }, [vorgangId, stand?.status, zweck, umleiten]); function anfordern(art: "anzeigen" | "herunterladen") { starten(async () => { setFehler(undefined); setPrivateKey(undefined); setZweck(art); const antwort = await abholungAnfordernAktion(schluesselId, art); if (umleiten(antwort)) return; if (antwort.fehler) setFehler(antwort.fehler); else setVorgangId(antwort.vorgangId); }); } function schliessen() { // Nichts vom Key bleibt im Zustand stehen. setPrivateKey(undefined); setVorgangId(undefined); setFehler(undefined); dialog.current?.close(); } const laeuft = startet || (vorgangId !== undefined && istLaufend(stand) && !abfrageFehler); const vorgangsFehler = stand?.status === "FEHLGESCHLAGEN" ? (stand.fehler ?? undefined) : undefined; const downloadGestartet = zweck === "herunterladen" && vorgangId !== undefined && stand?.status === "ERLEDIGT"; return ( <>

Private Key von „{name}“

{privateKey ? ( <>

Wird nicht erneut angezeigt. Kopieren Sie ihn jetzt an einen sicheren Ort.

) : downloadGestartet ? (

Download gestartet. Der Private Key wird nicht erneut angeboten.

) : ( <>

Der Private Key wird im Worker entschlüsselt und genau einmal ausgeliefert. Jede Anzeige und jeder Download steht im Audit-Log.

)}
{vorgangId &&
); } /** „Private Key aus SSHKeyVault loeschen“ (#014) – endgueltig, mit Rueckfrage. */ export function PrivateKeyLoeschen({ schluesselId, name }: { schluesselId: string; name: string }) { const dialog = useRef(null); const router = useRouter(); const umleiten = useBestaetigungUmleitung(); const [verstanden, setVerstanden] = useState(false); const [vorgangId, setVorgangId] = useState(); const [fehler, setFehler] = useState(); const [startet, starten] = useTransition(); const { stand, abfrageFehler } = useVorgang(vorgangId); useEffect(() => { if (stand?.status === "ERLEDIGT") { dialog.current?.close(); router.refresh(); } }, [stand?.status, router]); const laeuft = startet || (vorgangId !== undefined && istLaufend(stand) && !abfrageFehler); const vorgangsFehler = stand?.status === "FEHLGESCHLAGEN" ? (stand.fehler ?? undefined) : undefined; return ( <>

Private Key von „{name}“ aus SSHKeyVault löschen?

sshkv verwirft den verschlüsselten Private Key endgültig. Der Public Key und alle Zuweisungen bleiben; auf den Hosts ändert sich nichts. Danach kann sshkv den Private Key weder anzeigen noch auf weitere Hosts ausrollen.

setVerstanden(e.target.checked)} beschriftung="Ich habe verstanden, dass sich das nicht rückgängig machen lässt." />
); }