express-slow-down
Advanced tools
Comparing version 1.0.1 to 1.1.1
@@ -43,3 +43,3 @@ "use strict"; | ||
options.store.incr(key, function(err, current) { | ||
options.store.incr(key, function(err, current, resetTime) { | ||
if (err) { | ||
@@ -49,5 +49,14 @@ return next(err); | ||
var delay = 0; | ||
if (current > options.delayAfter) { | ||
delay = (current - options.delayAfter) * options.delayMs; | ||
} | ||
req.slowDown = { | ||
limit: options.delayAfter, | ||
current: current, | ||
remaining: Math.max(options.delayAfter - current, 0) | ||
remaining: Math.max(options.delayAfter - current, 0), | ||
resetTime: resetTime, | ||
delay: delay | ||
}; | ||
@@ -59,20 +68,37 @@ | ||
if (options.skipFailedRequests) { | ||
res.on("finish", function() { | ||
if (res.statusCode >= 400) { | ||
if (options.skipFailedRequests || options.skipSuccessfulRequests) { | ||
let decremented = false; | ||
const decrementKey = () => { | ||
if (!decremented) { | ||
options.store.decrement(key); | ||
decremented = true; | ||
} | ||
}); | ||
} | ||
}; | ||
if (options.skipSuccessfulRequests) { | ||
res.on("finish", function() { | ||
if (res.statusCode < 400) { | ||
options.store.decrement(key); | ||
} | ||
}); | ||
if (options.skipFailedRequests) { | ||
res.on("finish", function() { | ||
if (res.statusCode >= 400) { | ||
decrementKey(); | ||
} | ||
}); | ||
res.on("close", () => { | ||
if (!res.finished) { | ||
decrementKey(); | ||
} | ||
}); | ||
res.on("error", () => decrementKey()); | ||
} | ||
if (options.skipSuccessfulRequests) { | ||
res.on("finish", function() { | ||
if (res.statusCode < 400) { | ||
options.store.decrement(key); | ||
} | ||
}); | ||
} | ||
} | ||
if (current > options.delayAfter) { | ||
var delay = (current - options.delayAfter) * options.delayMs; | ||
if (delay !== 0) { | ||
return setTimeout(next, delay); | ||
@@ -79,0 +105,0 @@ } |
"use strict"; | ||
function calculateNextResetTime(windowMs) { | ||
const d = new Date(); | ||
d.setMilliseconds(d.getMilliseconds() + windowMs); | ||
return d; | ||
} | ||
function MemoryStore(windowMs) { | ||
var hits = {}; | ||
let hits = {}; | ||
let resetTime = calculateNextResetTime(windowMs); | ||
@@ -12,3 +20,3 @@ this.incr = function(key, cb) { | ||
cb(null, hits[key]); | ||
cb(null, hits[key], resetTime); | ||
}; | ||
@@ -25,2 +33,3 @@ | ||
hits = {}; | ||
resetTime = calculateNextResetTime(windowMs); | ||
}; | ||
@@ -31,6 +40,7 @@ | ||
delete hits[key]; | ||
delete resetTime[key]; | ||
}; | ||
// simply reset ALL hits every windowMs | ||
var interval = setInterval(this.resetAll, windowMs); | ||
const interval = setInterval(this.resetAll, windowMs); | ||
if (interval.unref) { | ||
@@ -37,0 +47,0 @@ interval.unref(); |
{ | ||
"name": "express-slow-down", | ||
"version": "1.0.1", | ||
"version": "1.1.1", | ||
"description": "Basic IP rate-limiting middleware for Express that slows down responses rather than blocking the user.", | ||
@@ -5,0 +5,0 @@ "homepage": "https://github.com/nfriedly/express-slow-down", |
@@ -20,6 +20,8 @@ # Express Slow Down | ||
Note: when using express-slow-down and express-rate-limit with an external store, you'll need to create two instances of the store and provide different prefixes so that they don't double-count requests. | ||
## Install | ||
```sh | ||
$ npm install --save express-rate-limit | ||
$ npm install --save express-slow-down | ||
``` | ||
@@ -38,7 +40,7 @@ | ||
windowMs: 15*60*1000, // 15 minutes | ||
delayAfter: 100 // allow 100 requests per 10 minutes, then... | ||
delayAfter: 100, // allow 100 requests per 15 minutes, then... | ||
delayMs: 500 // begin adding 500ms of delay per request above 100: | ||
// request # 101 is delayed by 500ms | ||
// request # 102 is delayed by 1000ms | ||
// request # 103 is delayed bu 1500ms | ||
// request # 103 is delayed by 1500ms | ||
// etc. | ||
@@ -70,4 +72,12 @@ }); | ||
A `req.slowDown` property is added to all requests with the `current`, and `remaining` number of requests for usage in your application code. | ||
## `req.slowDown` | ||
A `req.slowDown` property is added to all requests with the following fields: | ||
- `limit`: The options.delayAfter value (defaults to 1) | ||
- `current`: The number of requests in the current window | ||
- `remaining`: The number of requests remaining before rate-limiting begins | ||
- `resetTime`: When the window will reset and current will return to 0, and remaining will return to limit (in milliseconds since epoch - compare to Date.now()). Note: this field depends on store support. It will be undefined if the store does not provide the value. | ||
- `delay`: Amount of delay imposed on current request (milliseconds) | ||
## Configuration | ||
@@ -105,2 +115,3 @@ | ||
- **store**: The storage to use when persisting rate limit attempts. By default, the [MemoryStore](lib/memory-store.js) is used. | ||
- Note: when using express-slow-down and express-rate-limit with an external store, you'll need to create two instances of the store and provide different prefixes so that they don't double-count requests. | ||
@@ -107,0 +118,0 @@ ## License |
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
10601
132
117