feat(auth): Anmeldeseiten, TOTP-Einrichtung und Bestaetigung (#004)
Anmeldung, Einrichtung des zweiten Faktors fuer den Notfall-Admin, erneute Bestaetigung vor kritischen Aktionen und die Seite fuer fehlende Rechte. Die Huelle zeigt jetzt den echten Benutzer, und jede Seite prueft die Sitzung selbst; ein struktureller Test haelt das fest. Die Ablaeufe sind im gebauten Stand gegen den Mock-OIDC geprueft (pnpm test:e2e): Admin, Konto ohne Gruppe, Notfall-Admin mit TOTP. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
import { readFileSync, readdirSync, statSync } from "node:fs";
|
||||
import path from "node:path";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
/**
|
||||
* Struktureller Test (#004, Muster aus Laufzettel): jede Seite und jeder Route Handler
|
||||
* prueft selbst, wer zugreift. Die Ausnahmen stehen hier namentlich mit Begruendung – ein
|
||||
* neuer ungepruefter Handler soll jemanden zwingen, sie aufzuschreiben.
|
||||
*/
|
||||
const AUSNAHMEN: Record<string, string> = {
|
||||
"src/app/anmelden/page.tsx": "Anmeldeseite selbst",
|
||||
"src/app/anmelden/totp/page.tsx": "nur mit Einrichtungs-Cookie aus richtigem Passwort erreichbar",
|
||||
"src/app/api/auth/abmelden/route.ts": "Abmelden braucht keine Pruefung",
|
||||
"src/app/api/auth/oidc/start/route.ts": "Beginn der Anmeldung",
|
||||
"src/app/api/auth/oidc/rueckruf/route.ts": "Ende der Anmeldung; prueft state, nonce und PKCE",
|
||||
"src/app/api/gesundheit/route.ts": "Healthcheck, verraet nur die Version",
|
||||
};
|
||||
|
||||
const PRUEFUNGEN = /sitzungErforderlich\(|rechtErforderlich\(|totpEinrichtungLesen\(/;
|
||||
|
||||
function dateien(verzeichnis: string): string[] {
|
||||
return readdirSync(verzeichnis).flatMap((name) => {
|
||||
const pfad = path.join(verzeichnis, name);
|
||||
if (statSync(pfad).isDirectory()) return dateien(pfad);
|
||||
return /^(page\.tsx|route\.ts)$/.test(name) ? [pfad] : [];
|
||||
});
|
||||
}
|
||||
|
||||
describe("Zugangspruefung", () => {
|
||||
const alle = dateien("src/app").map((p) => p.split(path.sep).join("/"));
|
||||
|
||||
it("findet Seiten und Handler", () => {
|
||||
expect(alle.length).toBeGreaterThan(10);
|
||||
});
|
||||
|
||||
it.each(alle)("%s prueft selbst oder steht in den Ausnahmen", (datei) => {
|
||||
if (AUSNAHMEN[datei]) return;
|
||||
const inhalt = readFileSync(datei, "utf8");
|
||||
expect(PRUEFUNGEN.test(inhalt), `${datei} prueft keine Sitzung`).toBe(true);
|
||||
});
|
||||
|
||||
it("listet keine Ausnahme fuer eine Datei, die es nicht mehr gibt", () => {
|
||||
for (const datei of Object.keys(AUSNAHMEN)) expect(alle).toContain(datei);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user