Initial commit

This commit is contained in:
Michilis
2025-12-19 23:56:07 -03:00
commit 23f716255e
48 changed files with 14834 additions and 0 deletions

View File

@@ -0,0 +1,77 @@
/**
* Rate Limiting Middleware
*
* Simple in-memory rate limiter.
* For production, consider using Redis-backed solution.
*/
import { config } from '../config.js';
// In-memory store for request counts
const requestCounts = new Map();
// Cleanup old entries periodically
setInterval(() => {
const now = Date.now();
for (const [key, data] of requestCounts) {
if (now - data.windowStart > config.rateLimitWindowMs * 2) {
requestCounts.delete(key);
}
}
}, 60000); // Every minute
/**
* Get client identifier from request
*/
function getClientId(req) {
// Use X-Forwarded-For header if behind proxy
const forwarded = req.headers['x-forwarded-for'];
if (forwarded) {
return forwarded.split(',')[0].trim();
}
return req.ip || (req.connection ? req.connection.remoteAddress : null) || 'unknown';
}
/**
* Rate limiting middleware
*/
export function rateLimit(req, res, next) {
const clientId = getClientId(req);
const now = Date.now();
let data = requestCounts.get(clientId);
if (!data || now - data.windowStart > config.rateLimitWindowMs) {
// New window
data = {
windowStart: now,
count: 1
};
requestCounts.set(clientId, data);
next();
return;
}
data.count++;
if (data.count > config.rateLimitMaxRequests) {
const retryAfter = Math.ceil((data.windowStart + config.rateLimitWindowMs - now) / 1000);
res.set('Retry-After', retryAfter.toString());
res.set('X-RateLimit-Limit', config.rateLimitMaxRequests.toString());
res.set('X-RateLimit-Remaining', '0');
res.set('X-RateLimit-Reset', new Date(data.windowStart + config.rateLimitWindowMs).toISOString());
return res.status(429).json({
error: 'Too many requests',
retry_after: retryAfter
});
}
// Add rate limit headers
res.set('X-RateLimit-Limit', config.rateLimitMaxRequests.toString());
res.set('X-RateLimit-Remaining', (config.rateLimitMaxRequests - data.count).toString());
res.set('X-RateLimit-Reset', new Date(data.windowStart + config.rateLimitWindowMs).toISOString());
next();
}