Files
poshmanager/server/middleware/rateLimit.js
2026-06-25 12:05:53 -05:00

38 lines
1.3 KiB
JavaScript

// Lightweight in-memory rate limiter for sensitive endpoints such as login.
// Keeps POSHManager dependency-free for a single-process deployment. For a
// multi-replica deployment behind a load balancer, replace the Map with a
// shared store (Redis) so limits are enforced across instances.
const buckets = new Map();
export function rateLimit({ windowMs = 60_000, max = 10, keyPrefix = 'rl' } = {}) {
return function rateLimiter(req, res, next) {
const ip = req.ip || req.socket?.remoteAddress || 'unknown';
const key = `${keyPrefix}:${ip}`;
const nowTs = Date.now();
const entry = buckets.get(key);
if (!entry || nowTs > entry.resetAt) {
buckets.set(key, { count: 1, resetAt: nowTs + windowMs });
return next();
}
entry.count += 1;
if (entry.count > max) {
const retryAfter = Math.max(1, Math.ceil((entry.resetAt - nowTs) / 1000));
res.setHeader('Retry-After', String(retryAfter));
return res.status(429).json({ error: 'Too many requests. Please slow down and try again shortly.' });
}
return next();
};
}
// Periodically drop expired buckets so the Map cannot grow unbounded.
const sweep = setInterval(() => {
const nowTs = Date.now();
for (const [key, entry] of buckets) {
if (nowTs > entry.resetAt) buckets.delete(key);
}
}, 5 * 60_000);
sweep.unref?.();