express-better-ratelimit
Version:
Express.js request rate limit middleware by IP with MemoryStore
100 lines (79 loc) • 2.34 kB
JavaScript
/**
* express-better-ratelimit <https://github.com/tunnckoCore/express-better-ratelimit>
*
* Copyright (c) 2014 Charlike Mike Reagent, contributors.
* Released under the MIT license.
*/
;
/**
* Module dependencies.
*/
var ipchecker = require('ipchecker');
var defaults = {
duration: 1000 * 60 * 60 * 24,
whiteList: [],
blackList: [],
accessLimited: '429: Too Many Requests.',
accessForbidden: '403: This is forbidden area for you.',
max: 500,
env: null
};
/**
* With options through init you can control
* black/white lists, limit per ip and reset interval.
*
* @param {Object} options
* @api public
*/
module.exports = function expressBetterRatelimit(options) {
options = options || {};
var db = {};
for (var key in defaults) {
if (!options[key]) {
options[key] = defaults[key];
}
}
if (options.message_429) {
options.accessLimited = options.message_429;
}
if (options.message_403) {
options.accessForbidden = options.message_403;
}
var whiteListMap = ipchecker.map(options.whiteList);
var blackListMap = ipchecker.map(options.blackList);
return function ratelimit(req, res, next) {
var ip = options.env === 'test' ? req.headers['x-expressip'] : req.ip;
if (ipchecker.check(ip, blackListMap)) {
res.status(403).send(options.accessForbidden);
return;
}
if (ipchecker.check(ip, whiteListMap)) {
return next()
}
var now = Date.now()
var reset = now + options.duration;
if (!db.hasOwnProperty(ip)) {
db[ip] = {ip: ip, reset: reset, limit: options.max}
}
var delta = db[ip].reset - now;
var retryAfter = delta / 1000 | 0;
db[ip].limit = db[ip].limit - 1
res.set('X-RateLimit-Limit', options.max);
if (db[ip].reset > now) {
res.set('X-RateLimit-Remaining', db[ip].limit < 0 ? 0 : db[ip].limit);
}
/* istanbul ignore if */
if (db[ip].limit < 0 && db[ip].reset < now) {
db[ip] = {ip: ip, reset: reset, limit: options.max};
db[ip].limit = db[ip].limit - 1;
res.set('X-RateLimit-Remaining', db[ip].limit);
}
res.set('X-RateLimit-Reset', db[ip].reset);
if (db[ip].limit < 0) {
res.set('Retry-After', retryAfter);
res.status(429).send(options.accessLimited);
return;
}
return next();
};
}