agent-smith/dist-in/middleware/rateLimiter.js
2026-02-26 19:41:09 +01:00

92 lines
7.9 KiB
JavaScript

import { rateLimiter } from 'hono-rate-limiter';
import { recordViolation } from './autoBan.js';
// Rate limit configuration from environment variables
const RATE_LIMIT_MAX = parseInt(process.env.RATE_LIMIT_MAX || '1', 10);
const RATE_LIMIT_WINDOW_MS = parseInt(process.env.RATE_LIMIT_WINDOW_MS || '50', 10);
console.log('🔒 Rate Limiter Configuration:');
console.log(` Max: ${RATE_LIMIT_MAX} requests per ${RATE_LIMIT_WINDOW_MS}ms`);
console.log(` Auto-ban threshold: ${process.env.AUTO_BAN_THRESHOLD || 10} violations`);
/**
* Rate limiter middleware configuration
* Limits requests per user/IP address
*/
export const apiRateLimiter = rateLimiter({
windowMs: RATE_LIMIT_WINDOW_MS, // Time window in milliseconds
limit: RATE_LIMIT_MAX, // Max requests per window
standardHeaders: 'draft-6', // Return rate limit info in headers
keyGenerator: (c) => {
// Try to get user ID from auth header, fallback to IP
const authHeader = c.req.header('authorization');
if (authHeader) {
// Extract user ID from JWT or auth token if available
// For now, use the auth header as key
return `user:${authHeader}`;
}
// Fallback to IP address
const forwarded = c.req.header('x-forwarded-for');
const ip = forwarded ? forwarded.split(',')[0] : c.req.header('x-real-ip') || 'unknown';
return `ip:${ip}`;
},
handler: (c) => {
// Record violation for auto-ban tracking
const authHeader = c.req.header('authorization');
let key;
if (authHeader) {
key = `user:${authHeader}`;
}
else {
const forwarded = c.req.header('x-forwarded-for');
const ip = forwarded ? forwarded.split(',')[0] : c.req.header('x-real-ip') || 'unknown';
key = `ip:${ip}`;
}
console.log(`⚠️ Rate limit exceeded for ${key}`);
recordViolation(key);
return c.json({
error: 'Too many requests',
message: `Rate limit exceeded. Maximum ${RATE_LIMIT_MAX} requests per ${RATE_LIMIT_WINDOW_MS}ms`,
}, 429);
},
});
/**
* Custom rate limiter for specific endpoints with different limits
*/
export function createCustomRateLimiter(limit, windowMs) {
return rateLimiter({
windowMs,
limit,
standardHeaders: 'draft-6',
keyGenerator: (c) => {
const authHeader = c.req.header('authorization');
if (authHeader) {
return `user:${authHeader}`;
}
const forwarded = c.req.header('x-forwarded-for');
const ip = forwarded ? forwarded.split(',')[0] : c.req.header('x-real-ip') || 'unknown';
return `ip:${ip}`;
},
handler: (c) => {
// Record violation for auto-ban tracking
const authHeader = c.req.header('authorization');
let key;
if (authHeader) {
key = `user:${authHeader}`;
}
else {
const forwarded = c.req.header('x-forwarded-for');
const ip = forwarded ? forwarded.split(',')[0] : c.req.header('x-real-ip') || 'unknown';
key = `ip:${ip}`;
}
recordViolation(key);
return c.json({
error: 'Too many requests',
message: `Rate limit exceeded. Maximum ${limit} requests per ${windowMs}ms`,
}, 429);
},
});
}
// Export configuration for testing
export const rateLimitConfig = {
max: RATE_LIMIT_MAX,
windowMs: RATE_LIMIT_WINDOW_MS,
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmF0ZUxpbWl0ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvbWlkZGxld2FyZS9yYXRlTGltaXRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFDL0MsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLGNBQWMsQ0FBQTtBQUU5QyxzREFBc0Q7QUFDdEQsTUFBTSxjQUFjLEdBQUcsUUFBUSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsY0FBYyxJQUFJLEdBQUcsRUFBRSxFQUFFLENBQUMsQ0FBQTtBQUN0RSxNQUFNLG9CQUFvQixHQUFHLFFBQVEsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLG9CQUFvQixJQUFJLElBQUksRUFBRSxFQUFFLENBQUMsQ0FBQTtBQUVuRixPQUFPLENBQUMsR0FBRyxDQUFDLGdDQUFnQyxDQUFDLENBQUE7QUFDN0MsT0FBTyxDQUFDLEdBQUcsQ0FBQyxXQUFXLGNBQWMsaUJBQWlCLG9CQUFvQixJQUFJLENBQUMsQ0FBQTtBQUMvRSxPQUFPLENBQUMsR0FBRyxDQUFDLDBCQUEwQixPQUFPLENBQUMsR0FBRyxDQUFDLGtCQUFrQixJQUFJLEVBQUUsYUFBYSxDQUFDLENBQUE7QUFHeEY7OztHQUdHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sY0FBYyxHQUFHLFdBQVcsQ0FBQztJQUN0QyxRQUFRLEVBQUUsb0JBQW9CLEVBQUUsOEJBQThCO0lBQzlELEtBQUssRUFBRSxjQUFjLEVBQUUsMEJBQTBCO0lBQ2pELGVBQWUsRUFBRSxTQUFTLEVBQUUsb0NBQW9DO0lBQ2hFLFlBQVksRUFBRSxDQUFDLENBQVUsRUFBRSxFQUFFO1FBQ3pCLHNEQUFzRDtRQUN0RCxNQUFNLFVBQVUsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxlQUFlLENBQUMsQ0FBQTtRQUNoRCxJQUFJLFVBQVUsRUFBRSxDQUFDO1lBQ2Isc0RBQXNEO1lBQ3RELHNDQUFzQztZQUN0QyxPQUFPLFFBQVEsVUFBVSxFQUFFLENBQUE7UUFDL0IsQ0FBQztRQUVELHlCQUF5QjtRQUN6QixNQUFNLFNBQVMsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxpQkFBaUIsQ0FBQyxDQUFBO1FBQ2pELE1BQU0sRUFBRSxHQUFHLFNBQVMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLElBQUksU0FBUyxDQUFBO1FBQ3ZGLE9BQU8sTUFBTSxFQUFFLEVBQUUsQ0FBQTtJQUNyQixDQUFDO0lBQ0QsT0FBTyxFQUFFLENBQUMsQ0FBVSxFQUFFLEVBQUU7UUFDcEIseUNBQXlDO1FBQ3pDLE1BQU0sVUFBVSxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLGVBQWUsQ0FBQyxDQUFBO1FBQ2hELElBQUksR0FBVyxDQUFBO1FBQ2YsSUFBSSxVQUFVLEVBQUUsQ0FBQztZQUNiLEdBQUcsR0FBRyxRQUFRLFVBQVUsRUFBRSxDQUFBO1FBQzlCLENBQUM7YUFBTSxDQUFDO1lBQ0osTUFBTSxTQUFTLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsaUJBQWlCLENBQUMsQ0FBQTtZQUNqRCxNQUFNLEVBQUUsR0FBRyxTQUFTLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLFdBQVcsQ0FBQyxJQUFJLFNBQVMsQ0FBQTtZQUN2RixHQUFHLEdBQUcsTUFBTSxFQUFFLEVBQUUsQ0FBQTtRQUNwQixDQUFDO1FBRUQsT0FBTyxDQUFDLEdBQUcsQ0FBQywrQkFBK0IsR0FBRyxFQUFFLENBQUMsQ0FBQTtRQUNqRCxlQUFlLENBQUMsR0FBRyxDQUFDLENBQUE7UUFFcEIsT0FBTyxDQUFDLENBQUMsSUFBSSxDQUNUO1lBQ0ksS0FBSyxFQUFFLG1CQUFtQjtZQUMxQixPQUFPLEVBQUUsZ0NBQWdDLGNBQWMsaUJBQWlCLG9CQUFvQixJQUFJO1NBQ25HLEVBQ0QsR0FBRyxDQUNOLENBQUE7SUFDTCxDQUFDO0NBQ0osQ0FBQyxDQUFBO0FBRUY7O0dBRUc7QUFDSCxNQUFNLFVBQVUsdUJBQXVCLENBQUMsS0FBYSxFQUFFLFFBQWdCO0lBQ25FLE9BQU8sV0FBVyxDQUFDO1FBQ2YsUUFBUTtRQUNSLEtBQUs7UUFDTCxlQUFlLEVBQUUsU0FBUztRQUMxQixZQUFZLEVBQUUsQ0FBQyxDQUFVLEVBQUUsRUFBRTtZQUN6QixNQUFNLFVBQVUsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxlQUFlLENBQUMsQ0FBQTtZQUNoRCxJQUFJLFVBQVUsRUFBRSxDQUFDO2dCQUNiLE9BQU8sUUFBUSxVQUFVLEVBQUUsQ0FBQTtZQUMvQixDQUFDO1lBQ0QsTUFBTSxTQUFTLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsaUJBQWlCLENBQUMsQ0FBQTtZQUNqRCxNQUFNLEVBQUUsR0FBRyxTQUFTLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLFdBQVcsQ0FBQyxJQUFJLFNBQVMsQ0FBQTtZQUN2RixPQUFPLE1BQU0sRUFBRSxFQUFFLENBQUE7UUFDckIsQ0FBQztRQUNELE9BQU8sRUFBRSxDQUFDLENBQVUsRUFBRSxFQUFFO1lBQ3BCLHlDQUF5QztZQUN6QyxNQUFNLFVBQVUsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxlQUFlLENBQUMsQ0FBQTtZQUNoRCxJQUFJLEdBQVcsQ0FBQTtZQUNmLElBQUksVUFBVSxFQUFFLENBQUM7Z0JBQ2IsR0FBRyxHQUFHLFFBQVEsVUFBVSxFQUFFLENBQUE7WUFDOUIsQ0FBQztpQkFBTSxDQUFDO2dCQUNKLE1BQU0sU0FBUyxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLGlCQUFpQixDQUFDLENBQUE7Z0JBQ2pELE1BQU0sRUFBRSxHQUFHLFNBQVMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLElBQUksU0FBUyxDQUFBO2dCQUN2RixHQUFHLEdBQUcsTUFBTSxFQUFFLEVBQUUsQ0FBQTtZQUNwQixDQUFDO1lBQ0QsZUFBZSxDQUFDLEdBQUcsQ0FBQyxDQUFBO1lBRXBCLE9BQU8sQ0FBQyxDQUFDLElBQUksQ0FDVDtnQkFDSSxLQUFLLEVBQUUsbUJBQW1CO2dCQUMxQixPQUFPLEVBQUUsZ0NBQWdDLEtBQUssaUJBQWlCLFFBQVEsSUFBSTthQUM5RSxFQUNELEdBQUcsQ0FDTixDQUFBO1FBQ0wsQ0FBQztLQUNKLENBQUMsQ0FBQTtBQUNOLENBQUM7QUFFRCxtQ0FBbUM7QUFDbkMsTUFBTSxDQUFDLE1BQU0sZUFBZSxHQUFHO0lBQzNCLEdBQUcsRUFBRSxjQUFjO0lBQ25CLFFBQVEsRUFBRSxvQkFBb0I7Q0FDakMsQ0FBQSJ9