Harden authentication, tenant isolation and security boundaries

This commit is contained in:
t.indorf
2026-10-09 22:49:55 +02:00
parent ec3f4f933d
commit 656ada80bd
71 changed files with 3107 additions and 1200 deletions
+12 -28
View File
@@ -1,34 +1,18 @@
"use server";
import { revalidatePath } from "next/cache";
import { NotdienstAlertStatus } from "@prisma/client";
import { prisma } from "@/lib/prisma";
import { activeAlertTokenWhere } from "@/lib/alert-tokens";
import { hashToken, isPublicToken } from "@/lib/tokens";
import { limitPublicAction } from "@/lib/rate-limit";
export async function confirmAlertAction(token: string) {
try {
const alert = await prisma.notdienstAlert.findUnique({
where: { confirmationToken: token },
});
if (!alert) {
return { error: "Ungültiger Bestätigungs-Link." };
}
if (alert.status !== NotdienstAlertStatus.PENDING) {
return { error: "Dieser Alarm wurde bereits bestätigt oder abgebrochen." };
}
await prisma.notdienstAlert.update({
where: { id: alert.id },
data: {
status: NotdienstAlertStatus.CONFIRMED,
confirmedAt: new Date(),
},
});
revalidatePath("/dashboard");
return { success: true };
} catch {
return { error: "Fehler bei der Bestätigung." };
}
if (!isPublicToken(token)) return { error: "Ungültiger Bestätigungs-Link." };
if (!(await limitPublicAction("alert-confirm", hashToken(token), 10, 900))) return { error: "Bitte versuche es später erneut." };
const updated = await prisma.notdienstAlert.updateMany({
where: activeAlertTokenWhere(token),
data: { status: NotdienstAlertStatus.CONFIRMED, confirmedAt: new Date() },
});
if (updated.count !== 1) return { error: "Dieser Link ist abgelaufen oder wurde bereits verwendet." };
revalidatePath("/dashboard");
return { success: true };
}