import { defineMiddleware } from "astro:middleware"; import { checkRateLimit, getRouteLimit, hashToken } from "@/lib/rateLimit"; export const onRequest = defineMiddleware(async (context, next) => { const { request, url } = context; if (url.pathname.startsWith("/api/")) { const authHeader = request.headers.get("Authorization"); let identifier: string; if (authHeader?.startsWith("Bearer ")) { identifier = await hashToken(authHeader.slice(7)); } else { identifier = request.headers.get("cf-connecting-ip") || request.headers.get("x-forwarded-for")?.split(",")[0].trim() || "unknown"; } const { route, limit } = getRouteLimit(request.method, url.pathname); const { allowed, retryAfter } = await checkRateLimit(identifier, route, limit); if (!allowed) { return new Response(JSON.stringify({ error: "Rate limit exceeded" }), { status: 429, headers: { "Content-Type": "application/json", "Retry-After": String(retryAfter) }, }); } } const response = await next(); response.headers.set("X-Content-Type-Options", "nosniff"); response.headers.set("X-Frame-Options", "DENY"); response.headers.set("Referrer-Policy", "strict-origin-when-cross-origin"); response.headers.set("Permissions-Policy", "camera=(), microphone=(), geolocation=()"); response.headers.set("Strict-Transport-Security", "max-age=31536000; includeSubDomains"); return response; });