express-rate-limit 5.5.0 → 6.0.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 ADDED
@@ -0,0 +1,492 @@
1
+ # <div align="center"> Express Rate Limit </div>
2
+
3
+ <div align="center">
4
+
5
+ [![Tests](https://github.com/nfriedly/express-rate-limit/workflows/Test/badge.svg)](https://github.com/nfriedly/express-rate-limit/actions)
6
+ [![npm version](https://img.shields.io/npm/v/express-rate-limit.svg)](https://npmjs.org/package/express-rate-limit 'View this project on NPM')
7
+ [![npm downloads](https://img.shields.io/npm/dm/express-rate-limit)](https://www.npmjs.com/package/express-rate-limit)
8
+
9
+ Basic rate-limiting middleware for Express. Use to limit repeated requests to
10
+ public APIs and/or endpoints such as password reset. Plays nice with
11
+ [express-slow-down](https://www.npmjs.com/package/express-slow-down).
12
+
13
+ </div>
14
+
15
+ ### Alternate Rate-limiters
16
+
17
+ > This module does not share state with other processes/servers by default. If
18
+ > you need a more robust solution, I recommend using an external store. See the
19
+ > [`stores` section](#store) below for a list of external stores.
20
+
21
+ This module was designed to only handle the basics and didn't even support
22
+ external stores initially. These other options all are excellent pieces of
23
+ software and may be more appropriate for some situations:
24
+
25
+ - [rate-limiter-flexible](https://www.npmjs.com/package/rate-limiter-flexible)
26
+ - [express-brute](https://www.npmjs.com/package/express-brute)
27
+ - [rate-limiter](https://www.npmjs.com/package/express-limiter)
28
+
29
+ ## Install
30
+
31
+ From the npm registry:
32
+
33
+ ```sh
34
+ # Using npm
35
+ > npm install express-rate-limit
36
+ # Using yarn or pnpm
37
+ > yarn/pnpm add express-rate-limit
38
+ ```
39
+
40
+ From Github Releases:
41
+
42
+ ```sh
43
+ # Using npm
44
+ > npm install https://github.com/nfriedly/express-rate-limit/releases/download/v{version}/express-rate-limit.tgz
45
+ # Using yarn or pnpm
46
+ > yarn/pnpm add https://github.com/nfriedly/express-rate-limit/releases/download/v{version}/express-rate-limit.tgz
47
+ ```
48
+
49
+ Replace `{version}` with the version of the package that you want to your, e.g.:
50
+ `6.0.0`.
51
+
52
+ ## Usage
53
+
54
+ This library is provided in ESM as well as CJS forms. To import it in a CJS
55
+ project:
56
+
57
+ ```ts
58
+ const rateLimit = require('express-rate-limit')
59
+ ```
60
+
61
+ To import it in a Typescript/ESM project:
62
+
63
+ ```ts
64
+ import rateLimit from 'express-rate-limit'
65
+ ```
66
+
67
+ ### Examples
68
+
69
+ To use it in an API-only server where the rate-limiter should be applied to all
70
+ requests:
71
+
72
+ ```ts
73
+ import rateLimit from 'express-rate-limit'
74
+
75
+ // Enable if you're behind a reverse proxy (Heroku, Bluemix, AWS ELB, Nginx, etc)
76
+ // see https://expressjs.com/en/guide/behind-proxies.html
77
+ // app.set('trust proxy', 1);
78
+
79
+ const limiter = rateLimit({
80
+ windowMs: 15 * 60 * 1000, // 15 minutes
81
+ max: 100, // Limit each IP to 100 requests per `window` (here, per 15 minutes)
82
+ standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
83
+ legacyHeaders: false, // Disable the `X-RateLimit-*` headers
84
+ })
85
+
86
+ // Apply the rate limiting middleware to all requests
87
+ app.use(limiter)
88
+ ```
89
+
90
+ To use it in a 'regular' web server (e.g. anything that uses
91
+ `express.static()`), where the rate-limiter should only apply to certain
92
+ requests:
93
+
94
+ ```ts
95
+ import rateLimit from 'express-rate-limit'
96
+
97
+ // Enable if you're behind a reverse proxy (Heroku, Bluemix, AWS ELB, Nginx, etc)
98
+ // see https://expressjs.com/en/guide/behind-proxies.html
99
+ // app.set('trust proxy', 1);
100
+
101
+ const apiLimiter = rateLimit({
102
+ windowMs: 15 * 60 * 1000, // 15 minutes
103
+ max: 100, // Limit each IP to 100 requests per `window` (here, per 15 minutes)
104
+ standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
105
+ legacyHeaders: false, // Disable the `X-RateLimit-*` headers
106
+ })
107
+
108
+ // Apply the rate limiting middleware to API calls only
109
+ app.use('/api', apiLimiter)
110
+ ```
111
+
112
+ To create multiple instances to apply different rules to different endpoints:
113
+
114
+ ```ts
115
+ import rateLimit from 'express-rate-limit'
116
+
117
+ // Enable if you're behind a reverse proxy (Heroku, Bluemix, AWS ELB, Nginx, etc)
118
+ // see https://expressjs.com/en/guide/behind-proxies.html
119
+ // app.set('trust proxy', 1);
120
+
121
+ const apiLimiter = rateLimit({
122
+ windowMs: 15 * 60 * 1000, // 15 minutes
123
+ max: 100, // Limit each IP to 100 requests per `window` (here, per 15 minutes)
124
+ standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
125
+ legacyHeaders: false, // Disable the `X-RateLimit-*` headers
126
+ })
127
+
128
+ app.use('/api/', apiLimiter)
129
+
130
+ const createAccountLimiter = rateLimit({
131
+ windowMs: 60 * 60 * 1000, // 1 hour
132
+ max: 5, // Limit each IP to 5 create account requests per `window` (here, per hour)
133
+ message:
134
+ 'Too many accounts created from this IP, please try again after an hour',
135
+ standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
136
+ legacyHeaders: false, // Disable the `X-RateLimit-*` headers
137
+ })
138
+
139
+ app.post('/create-account', createAccountLimiter, (request, response) => {
140
+ //...
141
+ })
142
+ ```
143
+
144
+ To use a custom store:
145
+
146
+ ```ts
147
+ import rateLimit from 'express-rate-limit'
148
+ import MemoryStore from 'express-rate-limit/memory-store.js'
149
+
150
+ // Enable if you're behind a reverse proxy (Heroku, Bluemix, AWS ELB, Nginx, etc)
151
+ // see https://expressjs.com/en/guide/behind-proxies.html
152
+ // app.set('trust proxy', 1);
153
+
154
+ const apiLimiter = rateLimit({
155
+ windowMs: 15 * 60 * 1000, // 15 minutes
156
+ max: 100, // Limit each IP to 100 requests per `window` (here, per 15 minutes)
157
+ standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
158
+ store: new MemoryStore(),
159
+ })
160
+
161
+ // Apply the rate limiting middleware to API calls only
162
+ app.use('/api', apiLimiter)
163
+ ```
164
+
165
+ > **Note:** most stores will require additional configuration, such as custom
166
+ > prefixes, when using multiple instances. The default built-in memory store is
167
+ > an exception to this rule.
168
+
169
+ ## Request API
170
+
171
+ A `request.rateLimit` property is added to all requests with the `limit`,
172
+ `current`, and `remaining` number of requests and, if the store provides it, a
173
+ `resetTime` Date object. These may be used in your application code to take
174
+ additional actions or inform the user of their status.
175
+
176
+ The property name can be configured with the configuration option
177
+ `requestPropertyName`
178
+
179
+ ## Configuration options
180
+
181
+ ### `windowMs`
182
+
183
+ Time frame for which requests are checked/remembered. Also used in the
184
+ `Retry-After` header when the limit is reached.
185
+
186
+ Note: with non-default stores, you may need to configure this value twice, once
187
+ here and once on the store. In some cases the units also differ (e.g. seconds vs
188
+ miliseconds)
189
+
190
+ Defaults to `60000` ms (= 1 minute).
191
+
192
+ ### `max`
193
+
194
+ Max number of connections during `windowMs` milliseconds before sending a 429
195
+ response.
196
+
197
+ May be a number, or a function that returns a number or a promise. If `max` is a
198
+ function, it will be called with `request` and `response` params.
199
+
200
+ Defaults to `5`. Set to `0` to disable.
201
+
202
+ Example of using a function:
203
+
204
+ ```ts
205
+ import rateLimit from 'express-rate-limit'
206
+
207
+ const isPremium = (request) => {
208
+ // ...
209
+ }
210
+
211
+ const limiter = rateLimit({
212
+ // `max` could also be an async function or return a promise
213
+ max: (request, response) => {
214
+ if (isPremium(request)) return 10
215
+ else return 5
216
+ },
217
+ // ...
218
+ })
219
+
220
+ // Apply the rate limiting middleware to all requests
221
+ app.use(limiter)
222
+ ```
223
+
224
+ ### `message`
225
+
226
+ Error message sent to user when `max` is exceeded.
227
+
228
+ May be a `string`, JSON object, or any other value that Express's
229
+ [response.send](https://expressjs.com/en/4x/api.html#response.send) method
230
+ supports.
231
+
232
+ Defaults to `'Too many requests, please try again later.'`
233
+
234
+ ### `statusCode`
235
+
236
+ HTTP status code returned when `max` is exceeded.
237
+
238
+ Defaults to `429`.
239
+
240
+ ### `legacyHeaders`
241
+
242
+ Enable headers for request limit (`X-RateLimit-Limit`) and current usage
243
+ (`X-RateLimit-Remaining`) on all responses and time to wait before retrying
244
+ (`Retry-After`) when `max` is exceeded.
245
+
246
+ Defaults to `true`.
247
+
248
+ > Renamed in `6.x` from `headers` to `legacyHeaders`.
249
+
250
+ ### `standardHeaders`
251
+
252
+ Enable headers conforming to the
253
+ [ratelimit standardization draft](https://github.com/ietf-wg-httpapi/ratelimit-headers/blob/main/draft-ietf-httpapi-ratelimit-headers.md)
254
+ adopted by the IETF: `RateLimit-Limit`, `RateLimit-Remaining`, and, if the store
255
+ supports it, `RateLimit-Reset`. May be used in conjunction with, or instead of
256
+ the `legacyHeaders` option.
257
+
258
+ This setting also enables the `Retry-After` header when `max` is exceeded.
259
+
260
+ Defaults to `false` (for backward compatibility), but recommended to use.
261
+
262
+ > Renamed in `6.x` from `draft_polli_ratelimit_headers` to `standardHeaders`.
263
+
264
+ ### `keyGenerator`
265
+
266
+ Function used to generate keys.
267
+
268
+ Defaults to `request.ip`, similar to this:
269
+
270
+ ```ts
271
+ const keyGenerator = (request /*, response*/) => request.ip
272
+ ```
273
+
274
+ ### `handler`
275
+
276
+ The function to handle requests once the max limit is exceeded. It receives the
277
+ `request` and the `response` objects. The `next` param is available if you need
278
+ to pass to the next middleware/route. Finally, the `options` param has all of
279
+ the options that originally passed in when creating the current limiter and the
280
+ default values for other options.
281
+
282
+ The `request.rateLimit` object has `limit`, `current`, and `remaining` number of
283
+ requests and, if the store provides it, a `resetTime` Date object.
284
+
285
+ Defaults to:
286
+
287
+ ```ts
288
+ const handler = (request, response, next, options) => {
289
+ response.status(options.statusCode).send(options.message)
290
+ }
291
+ ```
292
+
293
+ ### `requestWasSuccessful`
294
+
295
+ Function that is called when `skipFailedRequests` and/or
296
+ `skipSuccessfulRequests` are set to `true`. May be overridden if, for example, a
297
+ service sends out a 200 status code on errors.
298
+
299
+ Defaults to
300
+
301
+ ```ts
302
+ const requestWasSuccessful = (request, response) => response.statusCode < 400
303
+ ```
304
+
305
+ ### `skipFailedRequests`
306
+
307
+ When set to `true`, failed requests won't be counted. Request considered failed
308
+ when:
309
+
310
+ - response status >= 400
311
+ - requests that were cancelled before last chunk of data was sent (response
312
+ `close` event triggered)
313
+ - response `error` event was triggered by response
314
+
315
+ (Technically they are counted and then un-counted, so a large number of slow
316
+ requests all at once could still trigger a rate-limit. This may be fixed in a
317
+ future release.)
318
+
319
+ Defaults to `false`.
320
+
321
+ ### `skipSuccessfulRequests`
322
+
323
+ When set to `true` successful requests (response status < 400) won't be counted.
324
+ (Technically they are counted and then un-counted, so a large number of slow
325
+ requests all at once could still trigger a rate-limit. This may be fixed in a
326
+ future release.)
327
+
328
+ Defaults to `false`.
329
+
330
+ ### `skip`
331
+
332
+ Function used to skip (whitelist) requests. Returning `true`, or a promise that
333
+ resolves with `true`, from the function will skip limiting for that request.
334
+
335
+ Defaults to always `false` (count all requests):
336
+
337
+ ```ts
338
+ const skip = (/*request, response*/) => false
339
+ ```
340
+
341
+ ### `requestPropertyName`
342
+
343
+ The name of the property that contains the rate limit information to add to the
344
+ `request` object.
345
+
346
+ Defaults to `rateLimit`.
347
+
348
+ ### `store`
349
+
350
+ The storage to use when persisting rate limit attempts.
351
+
352
+ By default, the [memory store](source/memory-store.ts) is used.
353
+
354
+ Available data stores are:
355
+
356
+ - [memory-store](source/memory-store.ts): _(default)_ Simple in-memory option.
357
+ Does not share state when app has multiple processes or servers.
358
+ - [rate-limit-redis](https://npmjs.com/package/rate-limit-redis): A
359
+ [Redis](http://redis.io/)-backed store, more suitable for large or demanding
360
+ deployments.
361
+ - [rate-limit-memcached](https://npmjs.org/package/rate-limit-memcached): A
362
+ [Memcached](https://memcached.org/)-backed store.
363
+ - [rate-limit-mongo](https://www.npmjs.com/package/rate-limit-mongo): A
364
+ [MongoDB](https://www.mongodb.com/)-backed store.
365
+ - [precise-memory-rate-limit](https://www.npmjs.com/package/precise-memory-rate-limit) -
366
+ A memory store similar to the built-in one, except that it stores a distinct
367
+ timestamp for each IP rather than bucketing them together.
368
+
369
+ You may also create your own store. It must implement the `Store` interface as
370
+ follows:
371
+
372
+ ```ts
373
+ import rateLimit, {
374
+ Store,
375
+ Options,
376
+ IncrementResponse,
377
+ } from 'express-rate-limit'
378
+
379
+ /**
380
+ * A {@link Store} that stores the hit count for each client.
381
+ *
382
+ * @public
383
+ */
384
+ class SomeStore implements Store {
385
+ /**
386
+ * Some store-specific parameter.
387
+ */
388
+ customParam!: string
389
+ /**
390
+ * The duration of time before which all hit counts are reset (in milliseconds).
391
+ */
392
+ windowMs!: number
393
+
394
+ /**
395
+ * @constructor for {@link SomeStore}. Only required if the user needs to pass
396
+ * some store specific parameters. For example, in a Mongo Store, the user will
397
+ * need to pass the URI, username and password for the Mongo database.
398
+ *
399
+ * @param customParam {string} - Some store-specific parameter.
400
+ */
401
+ constructor(customParam: string) {
402
+ this.customParam = customParam
403
+ }
404
+
405
+ /**
406
+ * Method that actually initializes the store. Must be synchronous.
407
+ *
408
+ * @param options {Options} - The options used to setup the middleware.
409
+ *
410
+ * @public
411
+ */
412
+ init(options: Options): void {
413
+ this.windowMs = options.windowMs
414
+
415
+ // ...
416
+ }
417
+
418
+ /**
419
+ * Method to increment a client's hit counter.
420
+ *
421
+ * @param key {string} - The identifier for a client
422
+ *
423
+ * @returns {IncrementResponse} - The number of hits and reset time for that client
424
+ *
425
+ * @public
426
+ */
427
+ async increment(key: string): Promise<IncrementResponse> {
428
+ // ...
429
+
430
+ return {
431
+ totalHits,
432
+ resetTime,
433
+ }
434
+ }
435
+
436
+ /**
437
+ * Method to decrement a client's hit counter.
438
+ *
439
+ * @param key {string} - The identifier for a client
440
+ *
441
+ * @public
442
+ */
443
+ async decrement(key: string): Promise<void> {
444
+ // ...
445
+ }
446
+
447
+ /**
448
+ * Method to reset a client's hit counter.
449
+ *
450
+ * @param key {string} - The identifier for a client
451
+ *
452
+ * @public
453
+ */
454
+ async resetKey(key: string): Promise<void> {
455
+ // ...
456
+ }
457
+
458
+ /**
459
+ * Method to reset everyone's hit counter.
460
+ *
461
+ * @public
462
+ */
463
+ async resetAll(): Promise<void> {
464
+ // ...
465
+ }
466
+ }
467
+
468
+ export default SomeStore
469
+ ```
470
+
471
+ ## Instance API
472
+
473
+ ### `resetKey(key)`
474
+
475
+ Resets the rate limiting for a given key. An example use case is to allow users
476
+ to complete a captcha or whatever to reset their rate limit, then call this
477
+ method.
478
+
479
+ ## Issues and Contributing
480
+
481
+ If you encounter a bug or want to see something added/changed, please go ahead
482
+ and [open an issue](https://github.com/nfriedly/express-rate-limit/issues/new)!
483
+ If you need help with something, feel free to
484
+ [start a discussion](https://github.com/nfriedly/express-rate-limit/discussions/new)!
485
+
486
+ If you wish to contribute to the library, thanks! First, please read
487
+ [the contributing guide](contributing.md). Then you can pick up any issue and
488
+ fix/implement it!
489
+
490
+ ## License
491
+
492
+ MIT © [Nathan Friedly](http://nfriedly.com/)
package/tsconfig.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "compilerOptions": {
3
+ "declaration": true,
4
+
5
+ "strict": true,
6
+ "noUnusedLocals": true,
7
+ "noImplicitReturns": true,
8
+ "noFallthroughCasesInSwitch": true,
9
+
10
+ "moduleResolution": "node",
11
+ "esModuleInterop": true
12
+ },
13
+ "include": ["./source/**/*.ts"],
14
+ "exclude": ["./node_modules"]
15
+ }
package/LICENSE DELETED
@@ -1,7 +0,0 @@
1
- Copyright 2020 Nathan Friedly
2
-
3
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
-
5
- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
-
7
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.