import 'server-only' import { headers } from 'next/headers' import { redirect } from 'next/navigation' import type { Session } from 'next-auth' import type { Rolle } from '@/generated/prisma/enums' import { rolleReichtAus } from '@/lib/rollen' import { auth } from '@/server/auth' import { PFAD_KOPFZEILE } from '@/proxy' /** * Rollenpruefung. * * Jede schreibende Aktion prueft serverseitig – in der Seite und noch einmal * in der Server Action. Die Oberflaeche blendet Knoepfe nur zusaetzlich aus; * verlassen wird sich darauf nie. */ export type Angemeldet = Session['user'] /** Fehler, den Server Actions dem Aufrufer zurueckgeben. */ export class NichtErlaubt extends Error { constructor(nachricht = 'Dazu fehlt dir die Berechtigung.') { super(nachricht) this.name = 'NichtErlaubt' } } /** Die angemeldete Person, oder null. */ export async function angemeldet(): Promise { const sitzung = await auth() return sitzung?.user?.id ? sitzung.user : null } /** * Riegel fuer Seiten: ohne Anmeldung geht es zur Anmeldeseite zurueck, * mit Ziel, damit es danach dort weitergeht, wo man hinwollte. */ export async function verlangeAnmeldung(zielPfad?: string): Promise { const benutzer = await angemeldet() if (!benutzer) { const ziel = zielPfad ? `?weiter=${encodeURIComponent(zielPfad)}` : '' redirect(`/anmelden${ziel}`) } return benutzer } /** Riegel fuer Seiten, die eine bestimmte Rolle verlangen. */ export async function verlangeRolle( verlangt: Rolle, zielPfad?: string, ): Promise { const benutzer = await verlangeAnmeldung(zielPfad) if (!rolleReichtAus(benutzer.rolle, verlangt)) { redirect('/keine-berechtigung') } return benutzer } /** * Riegel fuer Server Actions. Hier wird nicht umgeleitet, sondern geworfen – * der Aufrufer wandelt das in eine Meldung fuer die Oberflaeche. */ export async function pruefeRolle(verlangt: Rolle): Promise { const benutzer = await angemeldet() if (!benutzer) throw new NichtErlaubt('Bitte zuerst anmelden.') if (!rolleReichtAus(benutzer.rolle, verlangt)) throw new NichtErlaubt() return benutzer } /** * Riegel fuer Route Handler: gibt null zurueck, statt umzuleiten. Der * Aufrufer antwortet dann mit 401. */ export async function verlangeAnmeldungFuerApi(): Promise { return angemeldet() } /** * Der angefragte Pfad, den der Proxy durchgereicht hat. Wird gebraucht, * um nach der Anmeldung wieder dorthin zurueckzufuehren. */ export async function angefragterPfad(): Promise { const kopfzeilen = await headers() const pfad = kopfzeilen.get(PFAD_KOPFZEILE) return pfad && pfad.startsWith('/') ? pfad : undefined }