Schluessel werden jetzt verwaltet statt nur im Prototyp gezeigt: Liste mit Filter, Anlegen (erzeugen oder importieren), Detail nach dem Prototyp aus #002, Bearbeiten der Metadaten und Download <slug>.pub. Warum so: - Erzeugen und Import eines Paars laufen als Vorgang im Worker, weil nur er den Master-Key hat. Passphrase und importierter Private Key reisen wie das Bootstrap-Passwort mit SSHKV_APP_SECRET verschluesselt im Job, nie in Vorgang.eingabe; der Worker loescht den Job danach. - Ein reiner Public Key ist kein Geheimnis und wird direkt im Web angelegt, mit verstaendlicher Meldung bei einem Duplikat. - Das Web liest nie das Chiffrat: ob ein Private Key gespeichert ist, verraet masterKeyVersion (per CHECK an das Chiffrat gekoppelt). Ein struktureller Test verlangt fuer jede zeilenliefernde Abfrage auf Schluessel ausserhalb des Workers ein festes select. - Migration: Vorgangsarten fuer Erzeugen, Import und (fuer #014) das Loeschen des Private Keys; CHECKs fuer den Slug (landet in Dateinamen) und "geloescht nur ohne Chiffrat". - Platzhalter PublicAusrollenAktion/PrivateAusrollenAktion fuer #016/#017. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
26 lines
1.1 KiB
TypeScript
26 lines
1.1 KiB
TypeScript
import { NextResponse } from "next/server";
|
||
import { RechteFehler, rechtErforderlich } from "@/server/auth/sitzungspflicht";
|
||
import { publicKeyExport } from "@/server/queries/schluessel";
|
||
|
||
/**
|
||
* Public Key als Datei `<slug>.pub` (#012). Ein Public Key ist kein Geheimnis – jede
|
||
* angemeldete Rolle darf ihn holen. Der Slug passt per DB-CHECK in einen Dateinamen.
|
||
*/
|
||
export async function GET(_anfrage: Request, { params }: { params: Promise<{ id: string }> }) {
|
||
try {
|
||
await rechtErforderlich("lesen");
|
||
} catch (fehler) {
|
||
if (fehler instanceof RechteFehler) return NextResponse.json({ fehler: fehler.message }, { status: 403 });
|
||
throw fehler;
|
||
}
|
||
const schluessel = await publicKeyExport((await params).id);
|
||
if (!schluessel) return NextResponse.json({ fehler: "Unbekannter Schlüssel." }, { status: 404 });
|
||
return new NextResponse(`${schluessel.publicKey}\n`, {
|
||
headers: {
|
||
"Content-Type": "text/plain; charset=utf-8",
|
||
"Content-Disposition": `attachment; filename="${schluessel.slug}.pub"`,
|
||
"Cache-Control": "no-store",
|
||
},
|
||
});
|
||
}
|