Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | 2x 2x 10x 10x 10x 8x 1x 7x 7x 7x 7x 7x 7x 7x 1x 1x 6x 2x | // Part II & III - Express middleware that rate limits by client IP.
//
// Applied to the sensitive zip-generation endpoint. It resolves the caller's
// IP, spends the configured token cost from that IP's bucket, and either lets
// the request through or answers 429 Too Many Requests.
const config = require('../config');
const { consume } = require('./rate_limiter');
// Resolve the client IP the way the TP suggests:
// var ip = req.headers['x-forwarded-for'] || req.socket.remoteAddress || null;
// `x-forwarded-for` can be a comma-separated list "client, proxy1, proxy2"; the
// original client is the first entry.
function clientIp(req) {
const forwarded = req.headers['x-forwarded-for'];
const ip = forwarded || (req.socket && req.socket.remoteAddress) || null;
return ip ? String(ip).split(',')[0].trim() : null;
}
// Express middleware. No-op when rate limiting is disabled (e.g. tests).
async function rateLimit(req, res, next) {
if (!config.rateLimitEnabled) {
return next();
}
const ip = clientIp(req);
Iif (!ip) {
// Can't identify the caller: fail open rather than block everyone.
console.warn('[ratelimit] could not determine client IP; letting request through');
return next();
}
try {
const { allowed, remaining, retryAfter, limit } = await consume(ip);
res.setHeader('X-RateLimit-Limit', limit);
res.setHeader('X-RateLimit-Remaining', remaining);
if (!allowed) {
res.setHeader('Retry-After', retryAfter);
return res.status(429).send({
error: 'Too many requests. Please slow down and try again shortly.',
retryAfter
});
}
return next();
} catch (err) {
// Never let a limiter failure take down the endpoint: fail open and log.
console.error('[ratelimit] unexpected error, letting request through:', err);
return next();
}
}
module.exports = {
rateLimit,
clientIp
};
|