import rateLimit from "express-rate-limit";
import { env } from "./env";
/**
* General rate limiter for all API endpoints
* @category Middleware
*/
export const generalLimiter = rateLimit({
windowMs: env.RATE_LIMIT_GENERAL_WINDOW_MS,
max: env.RATE_LIMIT_GENERAL_MAX,
message: {
error: "Too many requests from this IP, please try again later.",
retryAfter: `${env.RATE_LIMIT_GENERAL_WINDOW_MS / 1000} seconds`,
},
standardHeaders: true,
legacyHeaders: false,
skipSuccessfulRequests: false,
skipFailedRequests: false,
});
/**
* Strict rate limiter for authentication endpoints
* Used to prevent brute-force attacks on login/auth endpoints
* @category Middleware
*/
export const authLimiter = rateLimit({
windowMs: env.RATE_LIMIT_AUTH_WINDOW_MS,
max: env.RATE_LIMIT_AUTH_MAX,
message: {
error: "Too many authentication attempts from this IP, please try again later.",
retryAfter: `${env.RATE_LIMIT_AUTH_WINDOW_MS / 1000} seconds`,
},
standardHeaders: true,
legacyHeaders: false,
skipSuccessfulRequests: false,
skipFailedRequests: false,
});
/**
* Rate limiter for API key-based requests
* More lenient for authenticated API access
* @category Middleware
*/
export const apiKeyLimiter = rateLimit({
windowMs: env.RATE_LIMIT_API_KEY_WINDOW_MS,
max: env.RATE_LIMIT_API_KEY_MAX,
message: {
error: "API key rate limit exceeded, please try again later.",
retryAfter: `${env.RATE_LIMIT_API_KEY_WINDOW_MS / 1000} seconds`,
},
standardHeaders: true,
legacyHeaders: false,
keyGenerator: (req) => {
const apiKey = req.headers["x-api-key"] || req.headers["authorization"];
return typeof apiKey === "string" ? apiKey : req.ip || "unknown";
},
skipSuccessfulRequests: false,
skipFailedRequests: false,
});
/**
* Stricter rate limiter for file upload endpoints
* @category Middleware
*/
export const uploadLimiter = rateLimit({
windowMs: env.RATE_LIMIT_UPLOAD_WINDOW_MS,
max: env.RATE_LIMIT_UPLOAD_MAX,
message: {
error: "Too many upload requests from this IP, please try again later.",
retryAfter: `${env.RATE_LIMIT_UPLOAD_WINDOW_MS / 1000} seconds`,
},
standardHeaders: true,
legacyHeaders: false,
skipSuccessfulRequests: false,
skipFailedRequests: false,
});
Source