Details und Diff laufen durch schwaerzen(), damit kein Private Key und kein Passwort ins unveraenderliche Protokoll geraet - was dort einmal steht, laesst sich per Trigger nicht mehr entfernen. Der Wortstamm privat ist dafuer zu breit: er schwaerzte auch Pfade und Verwendungszaehler, die das Protokoll gerade zeigen soll. Jetzt greifen nur Felder, die den Schluessel selbst tragen, und jeder PEM-Block. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
53 lines
2.1 KiB
TypeScript
53 lines
2.1 KiB
TypeScript
import type { Prisma } from "@/generated/prisma/client";
|
||
import type { ProtokollErgebnis } from "@/generated/prisma/enums";
|
||
import { prisma } from "@/lib/db";
|
||
import { schwaerzen } from "@/lib/protokoll-schwaerzen";
|
||
|
||
/**
|
||
* Schreibt einen Eintrag ins revisionssichere Protokoll (#005).
|
||
*
|
||
* Hash und Verkettung berechnet die Datenbank (Trigger), hier wird nur eingefuegt.
|
||
* `details` laeuft vor dem Schreiben durch `schwaerzen()` (#006), damit kein Private Key
|
||
* und kein Passwort hineingeraet – auch nicht aus Versehen ueber ein Fehlerobjekt.
|
||
*/
|
||
export type ProtokollEintrag = {
|
||
readonly akteur: { readonly id: string; readonly name: string } | "System";
|
||
readonly aktion: string;
|
||
readonly ergebnis: ProtokollErgebnis;
|
||
readonly hostName?: string | null;
|
||
readonly zielbenutzer?: string | null;
|
||
readonly fingerprint?: string | null;
|
||
readonly diff?: string | null;
|
||
readonly details?: Record<string, unknown>;
|
||
};
|
||
|
||
export async function protokollieren(
|
||
eintrag: ProtokollEintrag,
|
||
client: Prisma.TransactionClient = prisma,
|
||
): Promise<void> {
|
||
const akteur = eintrag.akteur === "System" ? { id: null, name: "System" } : eintrag.akteur;
|
||
await client.protokoll.create({
|
||
data: {
|
||
akteurId: akteur.id,
|
||
akteurName: akteur.name,
|
||
aktion: eintrag.aktion,
|
||
ergebnis: eintrag.ergebnis,
|
||
hostName: eintrag.hostName ?? null,
|
||
zielbenutzer: eintrag.zielbenutzer ?? null,
|
||
fingerprint: eintrag.fingerprint ?? null,
|
||
// Auch der Diff: er stammt aus Dateien auf den Hosts, und eine authorized_keys-Datei
|
||
// kann versehentlich einen eingefuegten Private Key enthalten.
|
||
diff: eintrag.diff ? (schwaerzen(eintrag.diff) as string) : null,
|
||
details: eintrag.details ? (schwaerzen(eintrag.details) as Prisma.InputJsonValue) : undefined,
|
||
},
|
||
});
|
||
}
|
||
|
||
/** Prueft die Hash-Kette in der Datenbank; liefert die erste fehlerhafte ID oder null. */
|
||
export async function protokollKettePruefen(): Promise<bigint | null> {
|
||
const [zeile] = await prisma.$queryRaw<
|
||
{ ergebnis: bigint | null }[]
|
||
>`SELECT protokoll_kette_pruefen() AS ergebnis`;
|
||
return zeile?.ergebnis ?? null;
|
||
}
|