"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.actorLimiter = exports.adminLimiter = exports.publicLimiter = exports.apiLimiter = exports.authLimiter = void 0; const express_rate_limit_1 = __importStar(require("express-rate-limit")); const tokens_1 = require("../security/tokens"); const sessionCookies_1 = require("../security/sessionCookies"); const SESSION_COOKIE_NAMES = [ (0, sessionCookies_1.getSessionCookieName)('admin'), (0, sessionCookies_1.getSessionCookieName)('employee'), (0, sessionCookies_1.getSessionCookieName)('renter'), ]; function readCookie(cookieHeader, name) { if (!cookieHeader) return null; for (const chunk of cookieHeader.split(';')) { const [rawName, ...rawValue] = chunk.trim().split('='); if (rawName === name) return decodeURIComponent(rawValue.join('=')); } return null; } function getBearerToken(req) { const authHeader = req.headers.authorization; if (!authHeader?.startsWith('Bearer ')) return null; const token = authHeader.slice(7).trim(); return token || null; } function getRequestToken(req) { const cookieHeader = req.headers.cookie; for (const name of SESSION_COOKIE_NAMES) { const token = readCookie(cookieHeader, name); if (token) return token; } return getBearerToken(req); } function getAuthenticatedActorKey(req) { const token = getRequestToken(req); if (!token) return null; try { const payload = (0, tokens_1.verifyAnyActorToken)(token); return `${payload.type}:${payload.sub}`; } catch { return null; } } // req.ip is already the real client IP when app.set('trust proxy', 1) is configured const getClientIpKey = (req) => (0, express_rate_limit_1.ipKeyGenerator)(req.ip ?? ''); // Strict limiter for auth endpoints — prevents brute-force and credential stuffing. // Successful requests (e.g. GET /me profile reads) are skipped so only failed // attempts count toward the cap. exports.authLimiter = (0, express_rate_limit_1.default)({ windowMs: 15 * 60 * 1000, // 15 minutes max: 20, standardHeaders: 'draft-7', legacyHeaders: false, skipSuccessfulRequests: true, keyGenerator: (req) => getClientIpKey(req), message: { error: 'too_many_requests', message: 'Too many attempts, please try again later', statusCode: 429 }, }); // Standard limiter for general authenticated API endpoints exports.apiLimiter = (0, express_rate_limit_1.default)({ windowMs: 60 * 1000, // 1 minute max: 120, standardHeaders: 'draft-7', legacyHeaders: false, keyGenerator: (req) => { const ip = getClientIpKey(req); const actorKey = getAuthenticatedActorKey(req); const companyId = req.companyId ?? ''; const renterId = req.renterId ?? ''; return `${ip}:${actorKey || companyId || renterId || 'anonymous'}`; }, message: { error: 'too_many_requests', message: 'Rate limit exceeded', statusCode: 429 }, }); // Limiter for public marketplace and site endpoints (no auth) exports.publicLimiter = (0, express_rate_limit_1.default)({ windowMs: 60 * 1000, max: 60, standardHeaders: 'draft-7', legacyHeaders: false, keyGenerator: (req) => getClientIpKey(req), message: { error: 'too_many_requests', message: 'Rate limit exceeded', statusCode: 429 }, }); // Tight limiter for admin endpoints exports.adminLimiter = (0, express_rate_limit_1.default)({ windowMs: 15 * 60 * 1000, max: 100, standardHeaders: 'draft-7', legacyHeaders: false, keyGenerator: (req) => { const ip = getClientIpKey(req); return `${ip}:${getAuthenticatedActorKey(req) || 'anonymous'}`; }, message: { error: 'too_many_requests', message: 'Too many admin requests', statusCode: 429 }, }); // Applied after authentication so limits can include actor identity rather than // pretending every employee behind the same NAT is the same organism. exports.actorLimiter = (0, express_rate_limit_1.default)({ windowMs: 60 * 1000, max: 240, standardHeaders: 'draft-7', legacyHeaders: false, keyGenerator: (req) => { const ip = getClientIpKey(req); const actorKey = getAuthenticatedActorKey(req); const companyId = req.companyId ?? ''; const employeeId = req.employee?.id ?? ''; const renterId = req.renterId ?? ''; const adminId = req.admin?.id ?? ''; return `${ip}:${companyId}:${actorKey || employeeId || renterId || adminId || 'anonymous'}`; }, message: { error: 'too_many_requests', message: 'Authenticated rate limit exceeded', statusCode: 429 }, }); //# sourceMappingURL=rateLimiter.js.map