feat(schluessel): Zuweisen und Ausrollen auf der Schluesselseite (#017)
Auf der Seite eines Schluessels: Public Key einem Host oder einer Gruppe zuweisen, Private Key (nur Admin) auf einen Quell-Host legen - mit ~/.ssh/config-Eintrag und dem Host-Key des Ziels in known_hosts -, Dry-Run fuer alle Ziele, anwenden und die Verbindung von A nach B testen. Der Kern-Anwendungsfall laeuft damit im Browser durch (E2E). Der Dry-Run nimmt Private-Key-Ziele nur fuer Admins auf: sonst koennte ein Operator einen vorbereiteten Private Key ausrollen lassen. Die Vorschau zeigt je Datei die Aktion; der Inhalt eines Private Keys erreicht den Browser nie. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -4,13 +4,17 @@ import { revalidatePath } from "next/cache";
|
||||
import { z } from "@/lib/validierung";
|
||||
import { BestaetigungFehler, RechteFehler, rechtErforderlich } from "@/server/auth/sitzungspflicht";
|
||||
import { akteurVon, textfeld, type FormularZustand } from "@/server/actions/formular";
|
||||
import { darf } from "@/server/auth/rechte";
|
||||
import {
|
||||
VerwendungsFehler,
|
||||
ausrollenStarten,
|
||||
privateVerwendungAnlegen,
|
||||
privateVerwendungEntfernen,
|
||||
publicVerwendungAnlegen,
|
||||
publicVerwendungEntfernen,
|
||||
trockenlaufStarten,
|
||||
} from "@/server/services/verwendungen";
|
||||
import { vorgangEinreihen } from "@/server/vorgaenge/vorgaenge";
|
||||
|
||||
/** Public-Key-Zuweisungen und Ausrollen (#016). Duenn: Recht, Eingabe, Service. */
|
||||
|
||||
@@ -82,6 +86,8 @@ export async function trockenlaufAktion(auswahl: AusrollAuswahl): Promise<Vorgan
|
||||
? { schluesselId: id.parse(auswahl.schluesselId) }
|
||||
: { hostId: id.parse(auswahl.hostId) },
|
||||
akteurVon(benutzer),
|
||||
// Private-Key-Ziele nur fuer Admins – ein Operator rollt so nie einen Private Key aus.
|
||||
darf(benutzer.rolle, "privateKeyAusrollen"),
|
||||
),
|
||||
};
|
||||
} catch (fehler) {
|
||||
@@ -99,3 +105,69 @@ export async function ausrollenAktion(trockenlaufId: string): Promise<VorgangsAn
|
||||
return alsAntwort(fehler);
|
||||
}
|
||||
}
|
||||
|
||||
/** Private Key einem Quell-Host zuweisen (#017) – nur Admins. */
|
||||
export async function privateZuweisenAktion(
|
||||
_vorher: FormularZustand,
|
||||
formular: FormData,
|
||||
): Promise<FormularZustand> {
|
||||
try {
|
||||
const { benutzer } = await rechtErforderlich("privateKeyAusrollen");
|
||||
const schluesselId = z.string().min(1).max(64).parse(textfeld(formular, "schluesselId"));
|
||||
const alias = (textfeld(formular, "alias") ?? "").trim();
|
||||
const zielHostId = textfeld(formular, "zielHostId");
|
||||
await privateVerwendungAnlegen(
|
||||
{
|
||||
schluesselId,
|
||||
hostId: textfeld(formular, "hostId") ?? "",
|
||||
zielbenutzer: (textfeld(formular, "zielbenutzer") ?? "").trim(),
|
||||
pfad: textfeld(formular, "pfad") ?? "",
|
||||
sshConfig: alias
|
||||
? {
|
||||
alias,
|
||||
hostName: (textfeld(formular, "hostName") ?? "").trim(),
|
||||
benutzer: (textfeld(formular, "sshBenutzer") ?? "").trim(),
|
||||
port: Number(textfeld(formular, "port") ?? "22"),
|
||||
}
|
||||
: null,
|
||||
knownHostsFuer: zielHostId ? [zielHostId] : [],
|
||||
beimWiderruf: textfeld(formular, "beimWiderruf") === "UMBENENNEN" ? "UMBENENNEN" : "LOESCHEN",
|
||||
},
|
||||
akteurVon(benutzer),
|
||||
);
|
||||
revalidatePath(`/schluessel/${schluesselId}`);
|
||||
return {};
|
||||
} catch (fehler) {
|
||||
return alsAntwort(fehler);
|
||||
}
|
||||
}
|
||||
|
||||
export async function privateEntfernenAktion(
|
||||
verwendungId: string,
|
||||
schluesselId: string,
|
||||
): Promise<{ fehler?: string }> {
|
||||
try {
|
||||
const { benutzer } = await rechtErforderlich("privateKeyAusrollen");
|
||||
await privateVerwendungEntfernen(z.string().min(1).max(64).parse(verwendungId), akteurVon(benutzer));
|
||||
revalidatePath(`/schluessel/${schluesselId}`);
|
||||
return {};
|
||||
} catch (fehler) {
|
||||
return alsAntwort(fehler);
|
||||
}
|
||||
}
|
||||
|
||||
/** Verbindungstest A → B (#020). Harmlos, aber nur fuer Rollen, die Hosts verwalten. */
|
||||
export async function verbindungTestenAktion(privatVerwendungId: string): Promise<VorgangsAntwort> {
|
||||
try {
|
||||
const { benutzer } = await rechtErforderlich("hostsVerwalten");
|
||||
return {
|
||||
vorgangId: await vorgangEinreihen({
|
||||
art: "VERBINDUNGSTEST",
|
||||
angefordertVonId: benutzer.id,
|
||||
eingabe: { privatVerwendungId: z.string().min(1).max(64).parse(privatVerwendungId) },
|
||||
}),
|
||||
};
|
||||
} catch (fehler) {
|
||||
return alsAntwort(fehler);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user