From 34005803da60c8243eba4ddb35d49f2a03479862 Mon Sep 17 00:00:00 2001 From: chahinebrini Date: Wed, 20 May 2026 04:17:24 +0200 Subject: [PATCH] fix(protection): cooldown-elapse must set protectionDisabledAt in state endpoint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: nach Cooldown-Ablauf reaktivierte sich der Schutz automatisch. Root-Cause: Race zwischen zwei Endpoints die abgelaufene Cooldowns auflösen. /api/cooldown/status setzt korrekt profile.protectionDisabledAt. /api/ protection/state — alle 5s während Cooldown gepollt — machte beim Ablauf NUR resolveCooldown(), ohne protectionDisabledAt. state.get gewann das Race fast immer → protectionDisabledAt blieb null → protectionShouldBeActive=true → Frontend-Bypass-Detection reaktivierte den Schutz. Fix: state.get.ts setzt im expired-Branch ebenfalls protectionDisabledAt + cooldownJustResolved-Flag. --- backend/server/api/protection/state.get.ts | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/backend/server/api/protection/state.get.ts b/backend/server/api/protection/state.get.ts index d339de4..2d413f8 100644 --- a/backend/server/api/protection/state.get.ts +++ b/backend/server/api/protection/state.get.ts @@ -1,6 +1,7 @@ import { requireUser } from "../../utils/auth"; import { getActiveCooldown, resolveCooldown } from "../../db/cooldown"; import { getProfile } from "../../db/profile"; +import { usePrisma } from "../../utils/prisma"; /** * GET /api/protection/state @@ -18,11 +19,26 @@ export default defineEventHandler(async (event) => { let active = false; let remainingSeconds = 0; let cooldownEndsAt: string | null = null; + // True wenn dieser Request gerade einen abgelaufenen Cooldown resolved hat. + let cooldownJustResolved = false; if (cooldown) { const expired = now >= cooldown.cooldownEndsAt; if (expired) { await resolveCooldown(cooldown.id); + // Anti-Auto-Reactivation: Cooldown wurde durchgehalten → Schutz bleibt + // jetzt AUS, User muss explizit reaktivieren. MUSS hier passieren — + // dieser Endpoint wird alle 5s während Cooldown gepollt und gewinnt das + // Race gegen /api/cooldown/status fast immer. Ohne dieses Update bliebe + // protectionDisabledAt null → protectionShouldBeActive=true → Frontend- + // Bypass-Detection würde den Schutz automatisch wieder anschalten. + await usePrisma() + .profile.update({ + where: { id: user.id }, + data: { protectionDisabledAt: new Date() }, + }) + .catch(() => {}); + cooldownJustResolved = true; // After resolve: no active cooldown } else { active = true; @@ -42,7 +58,8 @@ export default defineEventHandler(async (event) => { // (protectionDisabledAt gesetzt) → Frontend macht KEINE Auto-Reactivation, // User muss explizit re-aktivieren via /api/protection/mark-active. // - true sonst (Normal-Zustand: Schutz sollte laufen) - const protectionShouldBeActive = !active && profile?.protectionDisabledAt === null; + const protectionShouldBeActive = + !active && profile?.protectionDisabledAt === null && !cooldownJustResolved; return { success: true,