ratelimiter: rename every to interval and add tests

This commit is contained in:
Braydon Fuller 2016-05-10 17:40:07 -04:00
parent 98d5314ef2
commit ebcc3607c2
2 changed files with 148 additions and 8 deletions

View File

@ -1,19 +1,20 @@
'use strict';
var THREE_HOURS = 3* 60 * 60 * 1000;
var THREE_HOURS = 3 * 60 * 60 * 1000;
/**
* A rate limiter to be used as an express middleware.
*
* @param {Object} options
* @param {Object} options.node - The bitcore node object
* @param {Number} options.limit - Number of requests for normal rate limiter
* @param {Number} options.every - Interval of the normal rate limiter
* @param {Number} options.interval - Interval of the normal rate limiter
* @param {Array} options.whitelist - IP addresses that should have whitelist rate limiting
* @param {Array} options.blacklist - IP addresses that should be blacklist rate limiting
* @param {Number} options.whitelistLimit - Number of requests for whitelisted clients
* @param {Number} options.whitelistEvery - Interval for whitelisted clients
* @param {Number} options.whitelistInterval - Interval for whitelisted clients
* @param {Number} options.blacklistLimit - Number of requests for blacklisted clients
* @param {Number} options.blacklistEvery - Interval for blacklisted clients
* @param {Number} options.blacklistInterval - Interval for blacklisted clients
*/
function RateLimiter(options) {
if (!(this instanceof RateLimiter)) {
@ -32,15 +33,15 @@ function RateLimiter(options) {
this.config = {
whitelist: {
totalRequests: options.whitelistLimit || 3 * 60 * 60 * 10, // 108,000
every: options.whitelistEvery || THREE_HOURS
interval: options.whitelistInterval || THREE_HOURS
},
blacklist: {
totalRequests: options.blacklistLimit || 0,
every: options.blacklistEvery || THREE_HOURS
interval: options.blacklistInterval || THREE_HOURS
},
normal: {
totalRequests: options.limit || 3 * 60 * 60, // 10,800
every: options.every || THREE_HOURS
interval: options.interval || THREE_HOURS
}
};
@ -117,7 +118,7 @@ RateLimiter.prototype.addClient = function(name) {
visits: 1
};
var resetTime = this.config[client.type].every;
var resetTime = this.config[client.type].interval;
setTimeout(function() {
delete self.clients[name];

139
test/ratelimeter.js Normal file
View File

@ -0,0 +1,139 @@
'use strict';
var should = require('should');
var sinon = require('sinon');
var RateLimiter = require('../lib/ratelimiter');
describe('RateLimiter', function() {
describe('@constructor', function() {
it('will instantiate without options', function() {
var limiter = new RateLimiter();
should.exist(limiter);
});
it('will instantiate without new', function() {
/* jshint newcap:false */
var limiter = RateLimiter();
should.exist(limiter);
});
it('will instantiate with options', function() {
var whitelist = [];
var blacklist = [];
var node = {};
var limiter = new RateLimiter({
node: node,
whitelist: whitelist,
blacklist: blacklist,
limit: 1,
interval: 1,
whitelistLimit: 1,
whitelistInterval: 1,
blacklistLimit: 1,
blacklistInterval: 1
});
should.exist(limiter);
should.exist(limiter.config);
should.exist(limiter.clients);
should.exist(limiter.node);
limiter.whitelist.should.equal(whitelist);
limiter.blacklist.should.equal(blacklist);
limiter.config.whitelist.totalRequests.should.equal(1);
limiter.config.whitelist.interval.should.equal(1);
limiter.config.blacklist.totalRequests.should.equal(1);
limiter.config.blacklist.interval.should.equal(1);
limiter.config.normal.interval.should.equal(1);
limiter.config.normal.totalRequests.should.equal(1);
});
});
describe('#middleware', function() {
});
describe('#exceeded', function() {
it('should not be exceeded', function() {
var node = {};
var limiter = new RateLimiter({node: node});
var client = limiter.addClient('127.0.0.1');
var exceeded = limiter.exceeded(client);
exceeded.should.equal(false);
});
it('should be exceeded', function() {
var node = {};
var limiter = new RateLimiter({node: node});
var client = limiter.addClient('127.0.0.1');
client.visits = 3 * 60 * 60 + 1;
var exceeded = limiter.exceeded(client);
exceeded.should.equal(true);
});
it('should exclude whitelisted with no limit', function() {
var node = {};
var limiter = new RateLimiter({
whitelist: [
'127.0.0.1'
],
node: node,
whitelistLimit: -1
});
var client = limiter.addClient('127.0.0.1');
client.visits = Infinity;
var exceeded = limiter.exceeded(client);
exceeded.should.equal(false);
});
});
describe('#getClientName', function() {
it('should get client name from cloudflare header', function() {
var node = {};
var limiter = new RateLimiter({node: node});
var req = {
headers: {
'cf-connecting-ip': '127.0.0.1'
}
};
var name = limiter.getClientName(req);
name.should.equal('127.0.0.1');
});
it('should get client name from x forwarded header', function() {
var node = {};
var limiter = new RateLimiter({node: node});
var req = {
headers: {
'x-forwarded-for': '127.0.0.1'
}
};
var name = limiter.getClientName(req);
name.should.equal('127.0.0.1');
});
it('should get client name from connection remote address', function() {
var node = {};
var limiter = new RateLimiter({node: node});
var req = {
headers: {},
connection: {
remoteAddress: '127.0.0.1'
}
};
var name = limiter.getClientName(req);
name.should.equal('127.0.0.1');
});
});
describe('#addClient', function() {
var sandbox = sinon.sandbox.create();
afterEach(function() {
sandbox.restore();
});
it('will remove client after interval', function() {
var THREE_HOURS_PLUS = 3 * 60 * 60 * 1000 + 1;
var clock = sandbox.useFakeTimers();
var node = {};
var limiter = new RateLimiter({node: node});
limiter.addClient('127.0.0.1');
should.exist(limiter.clients['127.0.0.1']);
clock.tick(THREE_HOURS_PLUS);
should.not.exist(limiter.clients['127.0.0.1']);
});
});
});