Files
FPT/src/app/page.tsx
T
admGitAICDS b47d3d0a3e
Deploy App / deploy (push) Successful in 1m10s
Modul-Review 1: Auth-Nachbesserungen (Sicherheit & UX)
Ergebnis der ersten Test- und Review-Runde zum Modul "Zugang & App-Rahmen":

- Login-Timing-Ausgleich: unbekannter Benutzer wird gegen Dummy-bcrypt-Hash
  geprueft -> Antwortzeit verraet nicht mehr, ob ein Name existiert
- Zurueck-Knopf nach Logout: pageshow-Waechter prueft die Session erneut und
  leitet die aus dem bfcache zurueckgeholte Ansicht auf /login
- Rate-Limiting (neues lib/rate-limit.ts): Login 10/15min, Registrierung
  5/h je IP, Passwortaenderung 10/15min je Benutzer; 429 + Retry-After
- Passwort-Dialog laeuft neu ueber Modal -> schliesst auf Esc (Fokus-Falle,
  aria-modal inklusive)
- Registrierungs-Fehler getrennt: nur belegter Name = 409 mit freundlicher
  Meldung, sonst 500 statt roher Prisma-Meldung

SPEZIFIKATION 0.27 (3.1.2/3/4, neues 3.1.6). 261 -> 267 Tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 20:45:31 +02:00

45 lines
1.5 KiB
TypeScript

"use client";
import { useEffect, useState } from "react";
import { AppShell } from "@/components/AppShell";
import { api } from "@/lib/api-client";
export default function Home() {
const [username, setUsername] = useState<string | null>(null);
useEffect(() => {
api
.get<{ user: { username: string } }>("/api/auth/me")
.then((data) => setUsername(data.user.username))
.catch(() => {
// Session abgelaufen/ungültig -- Middleware leitet beim nächsten Request um.
window.location.href = "/login";
});
}, []);
// Nach dem Abmelden führt der Zurück-Knopf zu dieser Seite aus dem Browser-Cache (bfcache)
// zurück -- OHNE neue Anfrage, also ohne dass Middleware oder Session-Prüfung greifen. Die
// eingefrorene Ansicht darf nicht stehen bleiben: Bei einer aus dem bfcache zurückgeholten
// Seite die Session erneut prüfen und bei fehlender Anmeldung sofort auf /login gehen.
useEffect(() => {
function onPageShow(e: PageTransitionEvent) {
if (!e.persisted) return;
api.get("/api/auth/me").catch(() => {
window.location.href = "/login";
});
}
window.addEventListener("pageshow", onPageShow);
return () => window.removeEventListener("pageshow", onPageShow);
}, []);
if (username === null) {
return (
<div className="flex flex-1 items-center justify-center">
<p className="text-sm text-muted">Lädt</p>
</div>
);
}
return <AppShell username={username} />;
}