import { redirect } from "next/navigation"; import { isStaff } from "@/lib/admin/is-staff"; import { canAccess, getAdminContext, PERMS } from "@/lib/permissions"; import { clientIp, rateLimit } from "@/lib/rate-limit"; export { isStaff }; export interface StaffUser { id: number; rank: number; username: string; } /** * Gate for admin pages and actions: redirects to /login when unauthenticated * and to / when authenticated but not staff. Returns the staff user otherwise. */ export async function requireStaff(): Promise { const { session, permissions } = await getAdminContext(); if (!canAccess(permissions, PERMS.ADMIN_DASHBOARD, session.user.rank)) redirect("/"); return { id: session.user.id, rank: session.user.rank, username: session.user.username }; } /** * Like requireStaff but also rate-limits the action per staff user (30 requests * per minute). Use on sensitive admin actions (ban, rank-change, settings edit). */ export async function requireStaffRateLimited(): Promise { const staff = await requireStaff(); const ip = await clientIp(); if (!(await rateLimit(`admin:${staff.id}:${ip}`, 30, 60_000)).ok) redirect("/admin?error=ratelimit"); return staff; }