Harden authentication, tenant isolation and security boundaries
This commit is contained in:
@@ -4,7 +4,7 @@ import { redirect } from "next/navigation";
|
||||
import { Prisma, UserRole } from "@prisma/client";
|
||||
import { z } from "zod";
|
||||
|
||||
import { auth } from "@/auth";
|
||||
import { requireSession } from "@/lib/auth-utils";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
|
||||
// =====================================================================
|
||||
@@ -23,9 +23,9 @@ const onboardingSchema = z
|
||||
.trim()
|
||||
.min(2, "Bitte mindestens 2 Zeichen angeben.")
|
||||
.max(120, "Maximal 120 Zeichen."),
|
||||
notdienstModuleEnabled: z.preprocess(checkboxToBool, z.boolean()),
|
||||
terminModuleEnabled: z.preprocess(checkboxToBool, z.boolean()),
|
||||
adressbuchModuleEnabled: z.preprocess(checkboxToBool, z.boolean()),
|
||||
notdienstModuleEnabled: z.preprocess(checkboxToBool, z.boolean()).default(false),
|
||||
terminModuleEnabled: z.preprocess(checkboxToBool, z.boolean()).default(false),
|
||||
adressbuchModuleEnabled: z.preprocess(checkboxToBool, z.boolean()).default(false),
|
||||
notdienstMinPerChildPerMonth: z.coerce
|
||||
.number()
|
||||
.int("Bitte eine ganze Zahl angeben.")
|
||||
@@ -87,10 +87,10 @@ export async function completeOnboardingAction(
|
||||
formData: FormData,
|
||||
): Promise<OnboardingState> {
|
||||
const attempt = prev.attempt + 1;
|
||||
const session = await auth();
|
||||
if (!session?.user) {
|
||||
redirect("/login");
|
||||
}
|
||||
const session = await requireSession();
|
||||
if (session.user.role !== UserRole.ADMIN) redirect("/forbidden");
|
||||
const founder = await prisma.user.findUnique({ where: { id: session.user.id } });
|
||||
if (!founder?.emailVerifiedAt || !founder.privacyPolicyAcceptedAt) redirect("/register");
|
||||
if (session.user.kitaId) {
|
||||
// Onboarding bereits abgeschlossen — verhindert doppeltes Einrichten
|
||||
// (z.B. durch zurück-navigieren oder Replay des Formulars).
|
||||
@@ -124,14 +124,15 @@ export async function completeOnboardingAction(
|
||||
// tatsächlich noch keine Kita hat (verhindert Race-Conditions bei
|
||||
// parallelen Onboarding-Submits).
|
||||
const updated = await tx.user.updateMany({
|
||||
where: { id: session.user.id, kitaId: null },
|
||||
where: { id: session.user.id, kitaId: null, role: UserRole.ADMIN, disabledAt: null,
|
||||
sessionVersion: session.user.sessionVersion, emailVerifiedAt: { not: null }, privacyPolicyAcceptedAt: { not: null } },
|
||||
data: {
|
||||
kitaId: kita.id,
|
||||
role: UserRole.ADMIN,
|
||||
},
|
||||
});
|
||||
|
||||
if (updated.count === 0) {
|
||||
if (updated.count !== 1) {
|
||||
throw new Error("USER_ALREADY_HAS_KITA");
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user