feat(hosts): Host-Key und Bootstrap in der Oberflaeche (#009, #010)

Auf der Hostseite: Host-Key abrufen, Fingerprint vergleichen und
vertrauen oder ablehnen. Weicht ein Key vom vertrauten ab, erscheint
eine deutliche Warnung, und Annehmen geht nur mit Haekchen und frischer
Bestaetigung. Danach Bootstrap per Einmal-Passwort oder per Befehl und
Verbindungspruefung, jeweils mit Fortschrittsanzeige.

Der sshd-Befund empfiehlt prohibit-password, wenn root sich per
Passwort anmelden darf - nur als Hinweis, geaendert wird nichts.

E2E im gebauten Stand mit Worker gegen ein echtes sshd.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-12 10:00:43 +02:00
co-authored by Claude Opus 5.5
parent c87c7b4e43
commit 4584669962
12 changed files with 450 additions and 45 deletions
+45
View File
@@ -0,0 +1,45 @@
"use client";
import { Check, Copy } from "lucide-react";
import { useState } from "react";
/** Mehrzeiliger technischer Text (Befehle, Skripte) mit Kopier-Button (#010). */
export function MonoBlock({
wert,
beschriftung,
hoehe,
}: {
wert: string;
beschriftung: string;
hoehe?: string;
}) {
const [kopiert, setKopiert] = useState(false);
return (
<div className="border-border bg-bg rounded-box relative min-w-0 border">
<button
type="button"
onClick={async () => {
try {
await navigator.clipboard.writeText(wert);
setKopiert(true);
setTimeout(() => setKopiert(false), 1800);
} catch {
// Ohne https keine Clipboard-API – der Text bleibt markierbar.
}
}}
aria-label={`${beschriftung} kopieren`}
className="bg-surface border-border-strong text-muted hover:text-text rounded-feld absolute top-2 right-2 flex size-11 items-center justify-center border"
>
{kopiert ? <Check className="text-ok size-4" aria-hidden /> : <Copy className="size-4" aria-hidden />}
</button>
<pre
className="text-text overflow-auto p-4 pr-16 font-mono text-[12.5px] leading-[1.55]"
style={hoehe ? { maxHeight: hoehe } : undefined}
tabIndex={0}
aria-label={beschriftung}
>
{wert}
</pre>
</div>
);
}