import { and, eq, gt, or } from "drizzle-orm"; import { headers } from "next/headers"; import { redirect } from "next/navigation"; import { auth } from "@/lib/auth"; import { unixNow } from "@/lib/bans"; import { Ban, db } from "@/lib/db"; import { safeRedirect } from "@/lib/foundation/security"; import { logger } from "@/lib/logger"; import { isIpBlacklisted, recordRequest } from "@/lib/services/abuse-guard"; import { siteSettings } from "@/lib/services/site-settings"; const EXEMPT = [ "/banned", "/maintenance", "/login", "/register", "/forgot", "/reset", "/api", ]; function isExempt(path: string): boolean { return EXEMPT.some((p) => path === p || path.startsWith(`${p}/`)); } export async function enforceSiteAccess(): Promise { const h = await headers(); const path = h.get("x-pathname") ?? "/"; const ip = h.get("x-real-client-ip") ?? h.get("x-forwarded-for")?.split(",")[0]?.trim() ?? "0.0.0.0"; void recordRequest(ip).catch(() => {}); if (isExempt(path)) return; let target: string | null = null; let checksDegraded = false; try { if (await isIpBlacklisted(ip)) target = "/banned"; } catch { checksDegraded = true; } try { const session = await auth(); const rank = session?.user?.rank ?? 0; try { if ( !target && (await siteSettings.getBool("maintenance_enabled", false)) ) { const minLogin = Number(await siteSettings.get("min_maintenance_login_rank", "7")) || 7; if (rank < minLogin) target = "/maintenance"; } } catch { checksDegraded = true; } try { if (!target && session?.user?.id) { const now = unixNow(); const [ban] = await db .select({ id: Ban.id }) .from(Ban) .where( and( eq(Ban.userId, Number(session.user.id)), or(eq(Ban.banExpire, 0), gt(Ban.banExpire, now)), ), ) .limit(1); if (ban) target = "/banned"; } } catch { checksDegraded = true; } } catch { checksDegraded = true; } if (target) { redirect(safeRedirect(target, target)); } if (checksDegraded) { logger.warn("Access guard degraded — some checks skipped", { ip, path }); } }