/** * @copyright 2026 NHCarrigan * @license Naomi's Public License * @author Naomi Carrigan */ import { FastifyPluginAsync } from "fastify"; import fastifyPlugin from "fastify-plugin"; import fastifyRateLimit from "@fastify/rate-limit"; import { AuditService } from "../services/audit.service"; import { AuditAction, AuditCategory } from "@library/shared-types"; const rateLimitPlugin: FastifyPluginAsync = async (app) => { await app.register(fastifyRateLimit, { max: async (request) => { // Try to get user from JWT try { await request.jwtVerify(); // Authenticated users get higher limits return 500; } catch { // Unauthenticated users get lower limits return 100; } }, timeWindow: "1 minute", allowList: async (request) => { // Bypass rate limiting entirely for admin users try { await request.jwtVerify(); return request.user?.isAdmin === true; } catch { return false; } }, errorResponseBuilder: (request) => { // Log rate limit exceeded event AuditService.log({ action: AuditAction.rateLimitExceeded, category: AuditCategory.security, details: `Rate limit exceeded for URL: ${request.url}`, success: false, }, request).catch(() => { // Ignore logging errors to avoid blocking the response }); return { statusCode: 429, error: "Too Many Requests", message: "You have exceeded the rate limit. Please try again later.", }; }, }); }; export default fastifyPlugin(rateLimitPlugin);