express-rate-limit
Advanced tools
Comparing version 2.2.0 to 2.3.0
'use strict'; | ||
var defaults = require('defaults'); | ||
var MemoryStore = require('./memory-store'); | ||
@@ -31,2 +32,12 @@ function RateLimit(options) { | ||
// store to use for persisting rate limit data | ||
options.store = options.store || new MemoryStore(options.windowMs); | ||
// ensure that the store has the incr method | ||
if (typeof options.store.incr !== 'function' || typeof options.store.resetKey !== 'function') { | ||
throw new Error('The store is not valid.'); | ||
} | ||
if (options.global) { | ||
@@ -37,42 +48,27 @@ throw new Error('The global option was removed from express-rate-limit v2.'); | ||
// this is shared by all endpoints that use this instance | ||
var hits = {}; | ||
function rateLimit(req, res, next) { | ||
var key = options.keyGenerator(req, res); | ||
if (hits[key]) { | ||
hits[key]++; | ||
} else { | ||
hits[key] = 1; | ||
} | ||
options.store.incr(key, function(err, current) { | ||
if (err) { | ||
return next(err); | ||
} | ||
if (options.max && hits[key] > options.max) { | ||
return options.handler(req,res, next); | ||
} | ||
if (options.max && current > options.max) { | ||
return options.handler(req,res, next); | ||
} | ||
if (options.delayAfter && options.delayMs && hits[key] > options.delayAfter) { | ||
var delay = (hits[key] - options.delayAfter) * options.delayMs; | ||
setTimeout(next, delay); | ||
} else { | ||
next(); | ||
} | ||
if (options.delayAfter && options.delayMs && current > options.delayAfter) { | ||
var delay = (current - options.delayAfter) * options.delayMs; | ||
setTimeout(next, delay); | ||
} else { | ||
next(); | ||
} | ||
}); | ||
} | ||
function resetAll() { | ||
hits = {}; | ||
} | ||
rateLimit.resetKey = options.store.resetKey.bind(options.store); | ||
// simply reset ALL hits every windowMs | ||
setInterval(resetAll, options.windowMs); | ||
// export an API to allow hits from one or all IPs to be reset | ||
function resetKey(key) { | ||
delete hits[key]; | ||
} | ||
rateLimit.resetKey = resetKey; | ||
// Backward compatibility function | ||
rateLimit.resetIp = resetKey; | ||
rateLimit.resetIp = rateLimit.resetKey; | ||
@@ -79,0 +75,0 @@ return rateLimit; |
{ | ||
"name": "express-rate-limit", | ||
"version": "2.2.0", | ||
"version": "2.3.0", | ||
"description": "Basic IP rate-limiting middleware for Express. Use to limit repeated requests to public APIs and/or endpoints such as password reset.", | ||
@@ -46,3 +46,3 @@ "homepage": "https://github.com/nfriedly/express-rate-limit", | ||
"jshint-stylish": "^2.1.0", | ||
"load-grunt-tasks": "^3.4.0", | ||
"load-grunt-tasks": "^3.5.0", | ||
"supertest": "^1.1.0", | ||
@@ -49,0 +49,0 @@ "time-grunt": "^1.3.0" |
@@ -10,3 +10,3 @@ # Express Rate Limit | ||
Note: this module does not share state with other processes/servers. | ||
Note: this module does not share state with other processes/servers by default. | ||
If you need a more robust solution, I recommend checking out [strict-rate-limiter](https://www.npmjs.com/package/strict-rate-limiter) or [express-brute](https://www.npmjs.com/package/express-brute), both are excellent pieces of software. | ||
@@ -111,3 +111,37 @@ | ||
``` | ||
* **store**: The storage to use when persisting rate limit attempts. By default, the [MemoryStore](lib/memory-store.js) is used. It must implement the following in order to function: | ||
```js | ||
function SomeStore() { | ||
/** | ||
* Increments the value in the underlying store for the given key. | ||
* @method function | ||
* @param {string} key - The key to use as the unique identifier passed | ||
* down from RateLimit. | ||
* @param {Store~incrCallback} cb - The callback issued when the underlying | ||
* store is finished. | ||
*/ | ||
this.incr = function(key, cb) { | ||
// ... | ||
}; | ||
/** | ||
* This callback is called by the underlying store when an answer to the | ||
* increment is available. | ||
* @callback Store~incrCallback | ||
* @param {?object} err - The error from the underlying store, or null if no | ||
* error occurred. | ||
* @param {number} value - The current value of the counter | ||
*/ | ||
/** | ||
* Resets a value with the given key. | ||
* @method function | ||
* @param {[type]} key - The key to reset | ||
*/ | ||
this.resetKey = function(key) { | ||
// ... | ||
}; | ||
}; | ||
``` | ||
The `delayAfter` and `delayMs` options were written for human-facing pages such as login and password reset forms. | ||
@@ -114,0 +148,0 @@ For public APIs, setting these to `0` (disabled) and relying on only `windowMs` and `max` for rate-limiting usually makes the most sense. |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
10688
4
80
160