kopia lustrzana https://github.com/c9/core
55 wiersze
1.6 KiB
JavaScript
55 wiersze
1.6 KiB
JavaScript
var error = require("http-error");
|
|
var RateLimiter = require('limiter').RateLimiter;
|
|
|
|
var MAX_EXPIRE_INTERVAL = 5000;
|
|
|
|
/**
|
|
* In memory rate limiter as connect middleware
|
|
*/
|
|
module.exports = ratelimit;
|
|
|
|
function ratelimit(key, duration, max) {
|
|
|
|
var buckets = Object.create(null); // in case there handles like 'constructor'
|
|
var rootKey = "params";
|
|
if (/^req\./.test(key)) {
|
|
rootKey = null;
|
|
key = key.replace(/^req\./, "");
|
|
}
|
|
|
|
// Returns a deep value from an object. E.g. resolveValue({user: {id: 5}}, "user.id") === 5
|
|
function resolveValue(obj, path) {
|
|
if (path === "*")
|
|
return "*";
|
|
|
|
return path.split('.').reduce(function(prev, curr) {
|
|
return prev ? prev[curr] : undefined;
|
|
}, obj);
|
|
}
|
|
|
|
// cleanup empty buckets
|
|
setInterval(function() {
|
|
Object.keys(buckets).forEach(function(handle) {
|
|
var bucket = buckets[handle];
|
|
if (bucket.tokenBucket.content === 0) {
|
|
delete buckets[handle];
|
|
}
|
|
});
|
|
}, 5 * 1000);
|
|
|
|
return function(req, res, next) {
|
|
var root = rootKey ? req[rootKey] : req;
|
|
var handle = resolveValue(root, key);
|
|
|
|
buckets[handle] = buckets[handle] || new RateLimiter(max, duration, true);
|
|
var removed = buckets[handle].tryRemoveTokens(1);
|
|
if (!removed) {
|
|
var err = new error.TooManyRequests("Rate limit exceeded");
|
|
err.retryIn = Math.min(duration, 5000);
|
|
return next(err);
|
|
}
|
|
|
|
return next();
|
|
};
|
|
}
|