express-rate-limit 2.13.1 → 2.14.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Express Rate Limit
1
+ # Express Rate Limit
2
2
 
3
3
  [![Build Status](https://secure.travis-ci.org/nfriedly/express-rate-limit.png?branch=master)](http://travis-ci.org/nfriedly/express-rate-limit)
4
4
  [![NPM version](http://badge.fury.io/js/express-rate-limit.png)](https://npmjs.org/package/express-rate-limit "View this project on NPM")
@@ -12,18 +12,17 @@ If you need a more robust solution, I recommend using an addon store or trying o
12
12
 
13
13
  ### Stores
14
14
 
15
- * Memory Store _(default, built-in)_ - stores hits in-memory in the Node.js process. Does not share state with other servers or processes.
16
- * [Redis Store](https://npmjs.com/package/rate-limit-redis)
17
- * [Memcached Store](https://npmjs.org/package/rate-limit-memcached)
15
+ - Memory Store _(default, built-in)_ - stores hits in-memory in the Node.js process. Does not share state with other servers or processes.
16
+ - [Redis Store](https://npmjs.com/package/rate-limit-redis)
17
+ - [Memcached Store](https://npmjs.org/package/rate-limit-memcached)
18
18
 
19
19
  ### Alternate Rate-limiters
20
20
 
21
21
  This module was designed to only handle the basics and didn't even support external stores initially. These other options all are excellent pieces of software and may be more appropriate for some situations:
22
22
 
23
- * [strict-rate-limiter](https://www.npmjs.com/package/strict-rate-limiter)
24
- * [express-brute](https://www.npmjs.com/package/express-brute)
25
- * [rate-limiter](https://www.npmjs.com/package/express-limiter)
26
-
23
+ - [strict-rate-limiter](https://www.npmjs.com/package/strict-rate-limiter)
24
+ - [express-brute](https://www.npmjs.com/package/express-brute)
25
+ - [rate-limiter](https://www.npmjs.com/package/express-limiter)
27
26
 
28
27
  ## Install
29
28
 
@@ -36,12 +35,12 @@ $ npm install --save express-rate-limit
36
35
  For an API-only server where the rate-limiter should be applied to all requests:
37
36
 
38
37
  ```js
39
- var RateLimit = require('express-rate-limit');
38
+ var RateLimit = require("express-rate-limit");
40
39
 
41
- app.enable('trust proxy'); // only if you're behind a reverse proxy (Heroku, Bluemix, AWS if you use an ELB, custom Nginx setup, etc)
40
+ app.enable("trust proxy"); // only if you're behind a reverse proxy (Heroku, Bluemix, AWS if you use an ELB, custom Nginx setup, etc)
42
41
 
43
42
  var limiter = new RateLimit({
44
- windowMs: 15*60*1000, // 15 minutes
43
+ windowMs: 15 * 60 * 1000, // 15 minutes
45
44
  max: 100, // limit each IP to 100 requests per windowMs
46
45
  delayMs: 0 // disable delaying - full speed until the max limit is reached
47
46
  });
@@ -53,73 +52,78 @@ app.use(limiter);
53
52
  For a "regular" web server (e.g. anything that uses `express.static()`), where the rate-limiter should only apply to certain requests:
54
53
 
55
54
  ```js
56
- var RateLimit = require('express-rate-limit');
55
+ var RateLimit = require("express-rate-limit");
57
56
 
58
- app.enable('trust proxy'); // only if you're behind a reverse proxy (Heroku, Bluemix, AWS if you use an ELB, custom Nginx setup, etc)
57
+ app.enable("trust proxy"); // only if you're behind a reverse proxy (Heroku, Bluemix, AWS if you use an ELB, custom Nginx setup, etc)
59
58
 
60
59
  var apiLimiter = new RateLimit({
61
- windowMs: 15*60*1000, // 15 minutes
60
+ windowMs: 15 * 60 * 1000, // 15 minutes
62
61
  max: 100,
63
62
  delayMs: 0 // disabled
64
63
  });
65
64
 
66
65
  // only apply to requests that begin with /api/
67
- app.use('/api/', apiLimiter);
68
-
66
+ app.use("/api/", apiLimiter);
69
67
  ```
70
68
 
71
69
  Create multiple instances to apply different rules to different routes:
72
70
 
73
71
  ```js
74
- var RateLimit = require('express-rate-limit');
72
+ var RateLimit = require("express-rate-limit");
75
73
 
76
- app.enable('trust proxy'); // only if you're behind a reverse proxy (Heroku, Bluemix, AWS if you use an ELB, custom Nginx setup, etc)
74
+ app.enable("trust proxy"); // only if you're behind a reverse proxy (Heroku, Bluemix, AWS if you use an ELB, custom Nginx setup, etc)
77
75
 
78
76
  var apiLimiter = new RateLimit({
79
- windowMs: 15*60*1000, // 15 minutes
77
+ windowMs: 15 * 60 * 1000, // 15 minutes
80
78
  max: 100,
81
79
  delayMs: 0 // disabled
82
80
  });
83
- app.use('/api/', apiLimiter);
81
+ app.use("/api/", apiLimiter);
84
82
 
85
83
  var createAccountLimiter = new RateLimit({
86
- windowMs: 60*60*1000, // 1 hour window
84
+ windowMs: 60 * 60 * 1000, // 1 hour window
87
85
  delayAfter: 1, // begin slowing down responses after the first request
88
- delayMs: 3*1000, // slow down subsequent responses by 3 seconds per request
86
+ delayMs: 3 * 1000, // slow down subsequent responses by 3 seconds per request
89
87
  max: 5, // start blocking after 5 requests
90
- message: "Too many accounts created from this IP, please try again after an hour"
88
+ message:
89
+ "Too many accounts created from this IP, please try again after an hour"
91
90
  });
92
- app.post('/create-account', createAccountLimiter, function(req, res) {
93
- //...
91
+ app.post("/create-account", createAccountLimiter, function(req, res) {
92
+ //...
94
93
  });
95
94
  ```
96
95
 
97
- A `req.rateLimit` property is added to all requests with the `limit`, `current`, and `remaining` number of requests for usage in your application code.
96
+ A `req.rateLimit` property is added to all requests with the `limit`, `current`, and `remaining` number of requests for usage in your application code and, if the store provides it, a resetTime Date object.
98
97
 
99
98
  ## Configuration
100
99
 
101
- * **windowMs**: milliseconds - how long to keep records of requests in memory. Defaults to `60000` (1 minute).
102
- * **delayAfter**: max number of connections during `windowMs` before starting to delay responses. Defaults to `1`. Set to `0` to disable delaying.
103
- * **delayMs**: milliseconds - how long to delay the response, multiplied by (number of recent hits - `delayAfter`). Defaults to `1000` (1 second). Set to `0` to disable delaying.
104
- * **max**: max number of connections during `windowMs` milliseconds before sending a 429 response. Defaults to `5`. Set to `0` to disable.
105
- * **message**: Error message returned when `max` is exceeded. Defaults to `'Too many requests, please try again later.'`
106
- * **statusCode**: HTTP status code returned when `max` is exceeded. Defaults to `429`.
107
- * **headers**: Enable headers for request limit (`X-RateLimit-Limit`) and current usage (`X-RateLimit-Remaining`) on all responses and time to wait before retrying (`Retry-After`) when `max` is exceeded.
108
- * **skipFailedRequests**: when `true` failed requests (response status >= 400) won't be counted. Defaults to `false`.
109
- * **skipSuccessfulRequests**: when `true` successful requests (response status < 400) won't be counted. Defaults to `false`.
110
- * **keyGenerator**: Function used to generate keys. By default user IP address (req.ip) is used. Defaults:
100
+ - **windowMs**: milliseconds - how long to keep records of requests in memory. Defaults to `60000` (1 minute).
101
+ - **delayAfter**: max number of connections during `windowMs` before starting to delay responses. Defaults to `1`. Set to `0` to disable delaying.
102
+ - **delayMs**: milliseconds - how long to delay the response, multiplied by (number of recent hits - `delayAfter`). Defaults to `1000` (1 second). Set to `0` to disable delaying.
103
+ - **max**: max number of connections during `windowMs` milliseconds before sending a 429 response. Defaults to `5`. Set to `0` to disable.
104
+ - **message**: Error message returned when `max` is exceeded. Defaults to `'Too many requests, please try again later.'`
105
+ - **statusCode**: HTTP status code returned when `max` is exceeded. Defaults to `429`.
106
+ - **headers**: Enable headers for request limit (`X-RateLimit-Limit`) and current usage (`X-RateLimit-Remaining`) on all responses and time to wait before retrying (`Retry-After`) when `max` is exceeded.
107
+ - **skipFailedRequests**: when `true` failed requests (response status >= 400) won't be counted. Defaults to `false`.
108
+ - **skipSuccessfulRequests**: when `true` successful requests (response status < 400) won't be counted. Defaults to `false`.
109
+ - **keyGenerator**: Function used to generate keys. By default user IP address (req.ip) is used. Defaults:
110
+
111
111
  ```js
112
112
  function (req /*, res*/) {
113
113
  return req.ip;
114
114
  }
115
115
  ```
116
- * **skip**: Function used to skip requests. Returning true from the function will skip limiting for that request. Defaults:
116
+
117
+ - **skip**: Function used to skip requests. Returning true from the function will skip limiting for that request. Defaults:
118
+
117
119
  ```js
118
120
  function (/*req, res*/) {
119
121
  return false;
120
122
  }
121
123
  ```
122
- * **handler**: The function to execute once the max limit is exceeded. It receives the request and the response objects. The "next" param is available if you need to pass to the next middleware. Defaults:
124
+
125
+ - **handler**: The function to execute once the max limit is exceeded. It receives the request and the response objects. The "next" param is available if you need to pass to the next middleware. Defaults:
126
+
123
127
  ```js
124
128
  function (req, res, /*next*/) {
125
129
  if (options.headers) {
@@ -135,70 +139,78 @@ function (req, res, /*next*/) {
135
139
  });
136
140
  }
137
141
  ```
138
- * **onLimitReached**: Function to listen each time the limit is reached. You can use it to debug/log. Defaults:
142
+
143
+ - **onLimitReached**: Function to listen each time the limit is reached. You can use it to debug/log. Defaults:
144
+
139
145
  ```js
140
146
  function (req, res, options) {
141
147
  /* empty */
142
148
  }
143
149
  ```
144
- * **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:
150
+
151
+ - **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:
152
+
145
153
  ```js
146
154
  function SomeStore() {
147
- /**
148
- * Increments the value in the underlying store for the given key.
149
- * @method function
150
- * @param {string} key - The key to use as the unique identifier passed
151
- * down from RateLimit.
152
- * @param {Store~incrCallback} cb - The callback issued when the underlying
153
- * store is finished.
154
- */
155
- this.incr = function(key, cb) {
156
- // ...
157
- };
158
-
159
- /**
160
- * Decrements the value in the underlying store for the given key. Used only when skipFailedRequests is true
161
- * @method function
162
- * @param {string} key - The key to use as the unique identifier passed
163
- * down from RateLimit.
164
- */
165
- this.decrement = function(key) {
166
- // ...
167
- };
168
-
169
- /**
170
- * This callback is called by the underlying store when an answer to the
171
- * increment is available.
172
- * @callback Store~incrCallback
173
- * @param {?object} err - The error from the underlying store, or null if no
174
- * error occurred.
175
- * @param {number} value - The current value of the counter
176
- */
177
-
178
- /**
179
- * Resets a value with the given key.
180
- * @method function
181
- * @param {[type]} key - The key to reset
182
- */
183
- this.resetKey = function(key) {
184
- // ...
185
- };
186
- };
155
+ /**
156
+ * Increments the value in the underlying store for the given key.
157
+ * @method function
158
+ * @param {string} key - The key to use as the unique identifier passed
159
+ * down from RateLimit.
160
+ * @param {Store~incrCallback} cb - The callback issued when the underlying
161
+ * store is finished.
162
+ *
163
+ * The callback should be triggered with three values:
164
+ * - error (usually null)
165
+ * - hitCount for this IP
166
+ * - resetTime - JS Date object (optional, but necessary for X-RateLimit-Reset header)
167
+ */
168
+ this.incr = function(key, cb) {
169
+ // ...
170
+ };
171
+
172
+ /**
173
+ * Decrements the value in the underlying store for the given key. Used only when skipFailedRequests is true
174
+ * @method function
175
+ * @param {string} key - The key to use as the unique identifier passed
176
+ * down from RateLimit.
177
+ */
178
+ this.decrement = function(key) {
179
+ // ...
180
+ };
181
+
182
+ /**
183
+ * This callback is called by the underlying store when an answer to the
184
+ * increment is available.
185
+ * @callback Store~incrCallback
186
+ * @param {?object} err - The error from the underlying store, or null if no
187
+ * error occurred.
188
+ * @param {number} value - The current value of the counter
189
+ */
190
+
191
+ /**
192
+ * Resets a value with the given key.
193
+ * @method function
194
+ * @param {[type]} key - The key to reset
195
+ */
196
+ this.resetKey = function(key) {
197
+ // ...
198
+ };
199
+ }
187
200
  ```
188
201
 
189
- Avaliable data stores are:
190
- * MemoryStore: _(default)_ Simple in-memory option. Does not share state when app has multiple processes or servers.
191
- * [rate-limit-redis](https://npmjs.com/package/rate-limit-redis): A [Redis](http://redis.io/)-backed store, more suitable for large or demanding deployments.
192
- * [rate-limit-memcached](https://npmjs.org/package/rate-limit-memcached): A [Memcached](https://memcached.org/)-backed store.
202
+ Available data stores are:
193
203
 
204
+ - MemoryStore: _(default)_ Simple in-memory option. Does not share state when app has multiple processes or servers.
205
+ - [rate-limit-redis](https://npmjs.com/package/rate-limit-redis): A [Redis](http://redis.io/)-backed store, more suitable for large or demanding deployments.
206
+ - [rate-limit-memcached](https://npmjs.org/package/rate-limit-memcached): A [Memcached](https://memcached.org/)-backed store.
194
207
 
195
208
  The `delayAfter` and `delayMs` options were written for human-facing pages such as login and password reset forms.
196
209
  For public APIs, setting these to `0` (disabled) and relying on only `windowMs` and `max` for rate-limiting usually makes the most sense.
197
210
 
198
-
199
211
  ## Instance API
200
212
 
201
- * **resetKey(key)**: Resets the rate limiting for a given key. (Allow users to complete a captcha or whatever to reset their rate limit, then call this method.)
213
+ - **resetKey(key)**: Resets the rate limiting for a given key. (Allow users to complete a captcha or whatever to reset their rate limit, then call this method.)
202
214
 
203
215
  ## v2 changes
204
216
 
@@ -78,10 +78,13 @@ function RateLimit(options) {
78
78
  if (options.headers) {
79
79
  res.setHeader("X-RateLimit-Limit", options.max);
80
80
  res.setHeader("X-RateLimit-Remaining", req.rateLimit.remaining);
81
- if (resetTime) {
81
+ if (resetTime instanceof Date) {
82
82
  // if we have a resetTime, also provide the current date to help avoid issues with incorrect clocks
83
83
  res.setHeader("Date", new Date().toGMTString());
84
- res.setHeader("X-RateLimit-Reset", resetTime);
84
+ res.setHeader(
85
+ "X-RateLimit-Reset",
86
+ Math.ceil(resetTime.getTime() / 1000)
87
+ );
85
88
  }
86
89
  }
87
90
 
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
2
 
3
3
  function calculateNextResetTime(windowMs) {
4
- return Math.ceil((Date.now() + windowMs) / 1000);
4
+ var d = new Date();
5
+ d.setMilliseconds(d.getMilliseconds() + windowMs);
6
+ return d;
5
7
  }
6
8
 
7
9
  function MemoryStore(windowMs) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "express-rate-limit",
3
- "version": "2.13.1",
3
+ "version": "2.14.2",
4
4
  "description": "Basic IP rate-limiting middleware for Express. Use to limit repeated requests to public APIs and/or endpoints such as password reset.",
5
5
  "homepage": "https://github.com/nfriedly/express-rate-limit",
6
6
  "author": {