Import source: backend/src/middleware/rateLimit

Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality.
This commit is contained in:
arsam
2026-09-18 23:12:27 +03:30
parent 772f738050
commit 04a7c5ee93
+38
View File
@@ -0,0 +1,38 @@
import type { RequestHandler } from 'express';
import { HttpError } from './errorHandler.js';
const log = new Map<string, number[]>();
// Prune entries older than 1 hour every 10 minutes
setInterval(() => {
const cutoff = Date.now() - 3_600_000;
for (const [ip, ts] of log) {
const fresh = ts.filter((t) => t > cutoff);
if (fresh.length === 0) log.delete(ip);
else log.set(ip, fresh);
}
}, 600_000).unref();
/**
* Sliding-window rate limiter — in-memory, per IP.
* maxRequests allowed within windowMs milliseconds.
*/
export function rateLimit(maxRequests: number, windowMs: number): RequestHandler {
return (req, res, next) => {
const ip = req.ip ?? req.socket.remoteAddress ?? 'unknown';
const now = Date.now();
const windowStart = now - windowMs;
const timestamps = (log.get(ip) ?? []).filter((t) => t > windowStart);
if (timestamps.length >= maxRequests) {
const retryAfterSecs = Math.ceil((timestamps[0] - windowStart) / 1000);
res.setHeader('Retry-After', String(retryAfterSecs));
return next(new HttpError(429, 'RATE_LIMITED', `Too many requests — retry after ${retryAfterSecs}s`));
}
timestamps.push(now);
log.set(ip, timestamps);
next();
};
}