/** * Rate Limiting Middleware (inst_045 - Quick Win Version) * Prevents brute force, DoS, and spam attacks * * QUICK WIN: In-memory rate limiting (no Redis required) * Full version in Phase 4 will use Redis for distributed rate limiting */ const rateLimit = require('express-rate-limit'); const { logSecurityEvent, getClientIp } = require('../utils/security-logger'); /** * Create rate limiter with custom handler for security logging */ function createRateLimiter(options) { const { windowMs, max, tier, message, skipSuccessfulRequests = false } = options; return rateLimit({ windowMs, max, skipSuccessfulRequests, standardHeaders: true, legacyHeaders: false, handler: async (req, res) => { const clientIp = getClientIp(req); await logSecurityEvent({ type: 'rate_limit_exceeded', sourceIp: clientIp, userId: req.user?.id || req.user?.userId, endpoint: req.path, userAgent: req.get('user-agent'), details: { tier, limit: max, window_ms: windowMs, window_display: `${windowMs / 1000} seconds` }, action: 'blocked', severity: 'medium' }); res.status(429).json({ error: 'Rate limit exceeded', message: message || `Too many requests. Limit: ${max} per ${windowMs / 1000} seconds`, retryAfter: Math.ceil(windowMs / 1000) }); } }); } /** * Public endpoints: 100 requests per 15 minutes per IP (inst_045) */ const publicRateLimiter = createRateLimiter({ windowMs: 15 * 60 * 1000, // 15 minutes max: 100, tier: 'public', message: 'Too many requests from this IP. Please try again later.' }); /** * Form submissions: 5 requests per minute per IP (inst_043) * More restrictive for form spam prevention */ const formRateLimiter = createRateLimiter({ windowMs: 60 * 1000, // 1 minute max: 5, tier: 'form', message: 'Too many form submissions. Please wait before submitting again.' }); /** * Authentication endpoints: 10 attempts per 5 minutes * Prevents brute force authentication attacks */ const authRateLimiter = createRateLimiter({ windowMs: 5 * 60 * 1000, // 5 minutes max: 10, tier: 'auth', message: 'Too many authentication attempts. Please try again later.', skipSuccessfulRequests: true // Don't count successful logins }); module.exports = { publicRateLimiter, formRateLimiter, authRateLimiter, createRateLimiter };