feat(admin): Kontoverwaltung und Admin-Einstellungen
"Mein Konto": Profil, Passwort setzen oder wechseln, Passkeys anlegen, umbenennen und entfernen, aktive Sitzungen einsehen und ueberall abmelden. Der letzte Passkey laesst sich nicht entfernen, solange kein Passwort gesetzt ist - sonst waere das Konto ausgesperrt. Admin-Einstellungen: Betriebsart umschalten, Selbstregistrierung freigeben, Konten anlegen, bearbeiten, deaktivieren und loeschen. Die Instanzwerte aus der .env werden angezeigt, damit sichtbar ist, warum Passkeys gegebenenfalls nicht verfuegbar sind. Schutzregeln: - Der Wechsel in den Einzelbetrieb wird abgelehnt, solange mehr als ein Konto existiert. - Der letzte aktive Administrator kann weder herabgestuft noch deaktiviert oder geloescht werden. - Das eigene Konto laesst sich nicht loeschen oder deaktivieren. - Deaktivieren oder ein neues Passwort beenden sofort alle Sitzungen des Kontos. Administratoren verwalten Konten, keine Inhalte: fremde Projekte sehen auch sie nicht. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { requireUserApi } from "@/lib/auth/guard";
|
||||
import { createSession, destroyAllSessions, setSessionCookie } from "@/lib/auth/session";
|
||||
import { prisma } from "@/lib/db";
|
||||
import { clientIp } from "@/lib/security/request";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
/** Uebersicht der eigenen aktiven Sitzungen. */
|
||||
export async function GET() {
|
||||
const auth = await requireUserApi();
|
||||
if (!auth.ok) return auth.response;
|
||||
|
||||
const sessions = await prisma.session.findMany({
|
||||
where: { userId: auth.user.id, expiresAt: { gt: new Date() } },
|
||||
select: {
|
||||
id: true,
|
||||
userAgent: true,
|
||||
ip: true,
|
||||
createdAt: true,
|
||||
lastSeenAt: true,
|
||||
expiresAt: true,
|
||||
},
|
||||
orderBy: { lastSeenAt: "desc" },
|
||||
});
|
||||
|
||||
return NextResponse.json({ sessions });
|
||||
}
|
||||
|
||||
/** Ueberall abmelden – das aktuelle Geraet bleibt angemeldet. */
|
||||
export async function DELETE(request: Request) {
|
||||
const auth = await requireUserApi();
|
||||
if (!auth.ok) return auth.response;
|
||||
|
||||
await destroyAllSessions(auth.user.id);
|
||||
const session = await createSession(auth.user.id, {
|
||||
userAgent: request.headers.get("user-agent"),
|
||||
ip: clientIp(request),
|
||||
});
|
||||
|
||||
const response = NextResponse.json({ ok: true });
|
||||
setSessionCookie(response, session.token, session.expiresAt);
|
||||
return response;
|
||||
}
|
||||
Reference in New Issue
Block a user