From ebcc3607c281839238007cebae0c15bff9d6af76 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Tue, 10 May 2016 17:40:07 -0400 Subject: [PATCH] ratelimiter: rename every to interval and add tests --- lib/ratelimiter.js | 17 +++--- test/ratelimeter.js | 139 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 148 insertions(+), 8 deletions(-) create mode 100644 test/ratelimeter.js diff --git a/lib/ratelimiter.js b/lib/ratelimiter.js index c4b2f66..d1cbe99 100644 --- a/lib/ratelimiter.js +++ b/lib/ratelimiter.js @@ -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]; diff --git a/test/ratelimeter.js b/test/ratelimeter.js new file mode 100644 index 0000000..3b2051f --- /dev/null +++ b/test/ratelimeter.js @@ -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']); + }); + }); + +});