express-rate-limit 6.11.2 → 7.0.0

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/license.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # MIT License
2
2
 
3
- Copyright 2021 Nathan Friedly
3
+ Copyright 2023 Nathan Friedly, Vedant K
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy of
6
6
  this software and associated documentation files (the "Software"), to deal in
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "express-rate-limit",
3
- "version": "6.11.2",
3
+ "version": "7.0.0",
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
  "author": {
6
6
  "name": "Nathan Friedly",
@@ -52,12 +52,12 @@
52
52
  "changelog.md"
53
53
  ],
54
54
  "engines": {
55
- "node": ">= 14"
55
+ "node": ">= 16"
56
56
  },
57
57
  "scripts": {
58
58
  "clean": "del-cli dist/ coverage/ *.log *.tmp *.bak *.tgz",
59
- "build:cjs": "esbuild --platform=node --bundle --target=es2019 --format=cjs --outfile=dist/index.cjs --footer:js=\"module.exports = rateLimit; module.exports.default = rateLimit; module.exports.rateLimit = rateLimit; module.exports.MemoryStore = MemoryStore;\" source/index.ts",
60
- "build:esm": "esbuild --platform=node --bundle --target=es2019 --format=esm --outfile=dist/index.mjs source/index.ts",
59
+ "build:cjs": "esbuild --platform=node --bundle --target=es2022 --format=cjs --outfile=dist/index.cjs --footer:js=\"module.exports = rateLimit; module.exports.default = rateLimit; module.exports.rateLimit = rateLimit; module.exports.MemoryStore = MemoryStore;\" source/index.ts",
60
+ "build:esm": "esbuild --platform=node --bundle --target=es2022 --format=esm --outfile=dist/index.mjs source/index.ts",
61
61
  "build:types": "dts-bundle-generator --out-file=dist/index.d.ts source/index.ts && cp dist/index.d.ts dist/index.d.cts && cp dist/index.d.ts dist/index.d.mts",
62
62
  "compile": "run-s clean build:*",
63
63
  "lint:code": "xo",
@@ -66,7 +66,7 @@
66
66
  "format:code": "xo --fix",
67
67
  "format:rest": "prettier --write .",
68
68
  "format": "run-s format:*",
69
- "test:lib": "cross-env NODE_NO_WARNINGS=1 NODE_OPTIONS=--experimental-vm-modules jest --config config/jest.json",
69
+ "test:lib": "jest",
70
70
  "test:ext": "cd test/external/ && bash run-all-tests",
71
71
  "test": "run-s lint test:lib",
72
72
  "pre-commit": "lint-staged",
@@ -76,28 +76,28 @@
76
76
  "express": "^4 || ^5"
77
77
  },
78
78
  "devDependencies": {
79
- "@express-rate-limit/prettier": "1.0.0",
80
- "@express-rate-limit/tsconfig": "1.0.0",
81
- "@jest/globals": "29.6.2",
82
- "@types/express": "4.17.17",
83
- "@types/jest": "29.5.3",
84
- "@types/node": "20.4.0",
85
- "@types/supertest": "2.0.12",
86
- "cross-env": "7.0.3",
87
- "del-cli": "5.0.0",
88
- "dts-bundle-generator": "7.0.0",
89
- "esbuild": "0.18.11",
90
- "express": "4.18.2",
91
- "husky": "8.0.3",
92
- "jest": "29.6.2",
93
- "lint-staged": "13.2.3",
94
- "npm-run-all": "4.1.5",
95
- "ratelimit-header-parser": "0.1.0",
96
- "supertest": "6.3.3",
97
- "ts-jest": "29.1.1",
98
- "ts-node": "10.9.1",
99
- "typescript": "4.9.5",
100
- "xo": "0.54.2"
79
+ "@express-rate-limit/prettier": "1.1.0",
80
+ "@express-rate-limit/tsconfig": "1.0.0",
81
+ "@jest/globals": "29.6.4",
82
+ "@types/express": "4.17.17",
83
+ "@types/jest": "29.5.4",
84
+ "@types/node": "20.5.9",
85
+ "@types/supertest": "2.0.12",
86
+ "cross-env": "7.0.3",
87
+ "del-cli": "5.1.0",
88
+ "dts-bundle-generator": "8.0.1",
89
+ "esbuild": "0.19.2",
90
+ "express": "4.18.2",
91
+ "husky": "8.0.3",
92
+ "jest": "29.6.4",
93
+ "lint-staged": "14.0.1",
94
+ "npm-run-all": "4.1.5",
95
+ "ratelimit-header-parser": "0.1.0",
96
+ "supertest": "6.3.3",
97
+ "ts-jest": "29.1.1",
98
+ "ts-node": "10.9.1",
99
+ "typescript": "5.2.2",
100
+ "xo": "0.56.0"
101
101
  },
102
102
  "xo": {
103
103
  "prettier": true,
package/readme.md CHANGED
@@ -25,31 +25,23 @@ Plays nice with
25
25
 
26
26
  ## Use Cases
27
27
 
28
- Depending on your use case, you may need to switch to a different
28
+ Depending on your use case, you may want to switch to a different
29
29
  [store](#store).
30
30
 
31
- #### Abuse Prevention
31
+ ### Abuse Prevention
32
32
 
33
33
  The default `MemoryStore` is probably fine.
34
34
 
35
- #### API Rate Limit Enforcement
35
+ ### API Rate Limit Enforcement
36
36
 
37
- You likely want to switch to a different [store](#store). As a performance
38
- optimization, the default `MemoryStore` uses a global time window, so if your
39
- limit is 10 requests per minute, a single user might be able to get an initial
40
- burst of up to 20 requests in a row if they happen to get the first 10 in at the
41
- end of one minute and the next 10 in at the start of the next minute. (After the
42
- initial burst, they will be limited to the expected 10 requests per minute.) All
43
- other stores use per-user time windows, so a user will get exactly 10 requests
44
- regardless.
45
-
46
- Additionally, if you have multiple servers or processes (for example, with the
47
- [node:cluster](https://nodejs.org/api/cluster.html) module), you'll likely want
48
- to use an external data store to syhcnronize hits
37
+ You may want to switch to a different [store](#store), especially if you have
38
+ multiple servers or processes (for example, with the
39
+ [node:cluster](https://nodejs.org/api/cluster.html) module). Using an external
40
+ data store to syhcnronize hits
49
41
  ([redis](https://npmjs.com/package/rate-limit-redis),
50
42
  [memcached](https://npmjs.org/package/rate-limit-memcached), [etc.](#store))
51
- This will guarentee the expected result even if some requests get handled by
52
- different servers/processes.
43
+ guarentees the expected result even if some requests get handled by different
44
+ servers/processes or a server is restarted.
53
45
 
54
46
  ### Alternate Rate Limiters
55
47
 
@@ -91,7 +83,7 @@ Replace `{version}` with the version of the package that you want to your, e.g.:
91
83
  This library is provided in ESM as well as CJS forms, and works with both
92
84
  Javascript and Typescript projects.
93
85
 
94
- **This package requires you to use Node 14 or above.**
86
+ **This package requires you to use Node 16 or above.**
95
87
 
96
88
  Import it in a CommonJS project (`type: commonjs` or no `type` field in
97
89
  `package.json`) as follows:
@@ -116,9 +108,9 @@ import { rateLimit } from 'express-rate-limit'
116
108
 
117
109
  const limiter = rateLimit({
118
110
  windowMs: 15 * 60 * 1000, // 15 minutes
119
- max: 100, // Limit each IP to 100 requests per `window` (here, per 15 minutes)
120
- standardHeaders: 'draft-7', // draft-6: RateLimit-* headers; draft-7: combined RateLimit header
121
- legacyHeaders: false, // X-RateLimit-* headers
111
+ limit: 100, // Limit each IP to 100 requests per `window` (here, per 15 minutes)
112
+ standardHeaders: 'draft-7', // draft-6: `RateLimit-*` headers; draft-7: combined `RateLimit` header
113
+ legacyHeaders: false, // Disable the `X-RateLimit-*` headers
122
114
  // store: ... , // Use an external store for more precise rate limiting
123
115
  })
124
116
 
@@ -135,8 +127,8 @@ import { rateLimit } from 'express-rate-limit'
135
127
 
136
128
  const apiLimiter = rateLimit({
137
129
  windowMs: 15 * 60 * 1000, // 15 minutes
138
- max: 100, // Limit each IP to 100 requests per `window` (here, per 15 minutes)
139
- standardHeaders: 'draft-7', // Set `RateLimit` and `RateLimit-Policy`` headers
130
+ limit: 100, // Limit each IP to 100 requests per `window` (here, per 15 minutes)
131
+ standardHeaders: 'draft-7', // Set `RateLimit` and `RateLimit-Policy` headers
140
132
  legacyHeaders: false, // Disable the `X-RateLimit-*` headers
141
133
  // store: ... , // Use an external store for more precise rate limiting
142
134
  })
@@ -152,9 +144,9 @@ import { rateLimit } from 'express-rate-limit'
152
144
 
153
145
  const apiLimiter = rateLimit({
154
146
  windowMs: 15 * 60 * 1000, // 15 minutes
155
- max: 100, // Limit each IP to 100 requests per `window` (here, per 15 minutes)
156
- standardHeaders: 'draft-7', // draft-6: RateLimit-* headers; draft-7: combined RateLimit header
157
- legacyHeaders: false, // X-RateLimit-* headers
147
+ limit: 100, // Limit each IP to 100 requests per `window` (here, per 15 minutes)
148
+ standardHeaders: 'draft-7', // draft-6: `RateLimit-*` headers; draft-7: combined `RateLimit` header
149
+ legacyHeaders: false, // Disable the `X-RateLimit-*` headers
158
150
  // store: ... , // Use an external store for more precise rate limiting
159
151
  })
160
152
 
@@ -162,14 +154,14 @@ app.use('/api/', apiLimiter)
162
154
 
163
155
  const createAccountLimiter = rateLimit({
164
156
  windowMs: 60 * 60 * 1000, // 1 hour
165
- max: 5, // Limit each IP to 5 create account requests per `window` (here, per hour)
157
+ limit: 5, // Limit each IP to 5 create account requests per `window` (here, per hour)
166
158
  message:
167
159
  'Too many accounts created from this IP, please try again after an hour',
168
- standardHeaders: 'draft-7', // draft-6: RateLimit-* headers; draft-7: combined RateLimit header
169
- legacyHeaders: false, // X-RateLimit-* headers
160
+ standardHeaders: 'draft-7', // draft-6: `RateLimit-*` headers; draft-7: combined `RateLimit` header
161
+ legacyHeaders: false, // Disable the `X-RateLimit-*` headers
170
162
  })
171
163
 
172
- app.post('/create-account', createAccountLimiter, (request, response) => {
164
+ app.post('/create-account', createAccountLimiter, (req, res) => {
173
165
  //...
174
166
  })
175
167
  ```
@@ -184,9 +176,9 @@ import RedisClient from 'ioredis'
184
176
  const redisClient = new RedisClient()
185
177
  const rateLimiter = rateLimit({
186
178
  windowMs: 15 * 60 * 1000, // 15 minutes
187
- max: 100, // Limit each IP to 100 requests per `window` (here, per 15 minutes)
188
- standardHeaders: 'draft-7', // draft-6: RateLimit-* headers; draft-7: combined RateLimit header
189
- legacyHeaders: false, // X-RateLimit-* headers
179
+ limit: 100, // Limit each IP to 100 requests per `window` (here, per 15 minutes)
180
+ standardHeaders: 'draft-7', // draft-6: `RateLimit-*` headers; draft-7: combined `RateLimit` header
181
+ legacyHeaders: false, // Disable the `X-RateLimit-*` headers
190
182
  store: new RedisStore({
191
183
  /* ... */
192
184
  }), // Use the external store
@@ -202,34 +194,9 @@ app.use(rateLimiter)
202
194
 
203
195
  ### Troubleshooting Proxy Issues
204
196
 
205
- If you are behind a proxy/load balancer (usually the case with most hosting
206
- services, e.g. Heroku, Bluemix, AWS ELB, Nginx, Cloudflare, Akamai, Fastly,
207
- Firebase Hosting, Rackspace LB, Riverbed Stingray, etc.), the IP address of the
208
- request might be the IP of the load balancer/reverse proxy (making the rate
209
- limiter effectively a global one and blocking all requests once the limit is
210
- reached) or `undefined`. To solve this issue, add the following line to your
211
- code (right after you create the express application):
212
-
213
- ```ts
214
- app.set('trust proxy', numberOfProxies)
215
- ```
216
-
217
- Where `numberOfProxies` is the number of proxies between the user and the
218
- server. To find the correct number, create a test endpoint that returns the
219
- client IP:
220
-
221
- ```ts
222
- app.set('trust proxy', 1)
223
- app.get('/ip', (request, response) => response.send(request.ip))
224
- ```
225
-
226
- Go to `/ip` and see the IP address returned in the response. If it matches your
227
- public IP address, then the number of proxies is correct and the rate limiter
228
- should now work correctly. If not, then keep increasing the number until it
229
- does.
230
-
231
- For more information about the `trust proxy` setting, take a look at the
232
- [official Express documentation](https://expressjs.com/en/guide/behind-proxies.html).
197
+ Please take a look at
198
+ [the wiki page](https://github.com/express-rate-limit/express-rate-limit/wiki/Troubleshooting-Proxy-Issues)
199
+ on this issue.
233
200
 
234
201
  ## Configuration
235
202
 
@@ -247,7 +214,7 @@ twice, once here and once on the store. In some cases the units also differ
247
214
 
248
215
  Defaults to `60000` ms (= 1 minute).
249
216
 
250
- ### `max`
217
+ ### `limit`
251
218
 
252
219
  > `number | function`
253
220
 
@@ -255,9 +222,16 @@ The maximum number of connections to allow during the `window` before rate
255
222
  limiting the client.
256
223
 
257
224
  Can be the limit itself as a number or a (sync/async) function that accepts the
258
- Express `request` and `response` objects and then returns a number.
225
+ Express `req` and `res` objects and then returns a number.
259
226
 
260
- Defaults to `5`. Set it to `0` to disable the rate limiter.
227
+ ~Set it to `0` to disable the rate limiter.~ As of version 7.0.0, setting `max`
228
+ to zero will no longer disable the rate limiter - instead, it will 'block' all
229
+ requests to that endpoint.
230
+
231
+ Defaults to `5`.
232
+
233
+ > Renamed in v7.x from `max` to `limit`. However, `max` will still be supported
234
+ > for backwards-compatibility.
261
235
 
262
236
  An example of using a function:
263
237
 
@@ -268,8 +242,8 @@ const isPremium = async (user) => {
268
242
 
269
243
  const limiter = rateLimit({
270
244
  // ...
271
- max: async (request, response) => {
272
- if (await isPremium(request.user)) return 10
245
+ limit: async (req, res) => {
246
+ if (await isPremium(req.user)) return 10
273
247
  else return 5
274
248
  },
275
249
  })
@@ -282,10 +256,10 @@ const limiter = rateLimit({
282
256
  The response body to send back when a client is rate limited.
283
257
 
284
258
  May be a `string`, JSON object, or any other value that Express's
285
- [`response.send`](https://expressjs.com/en/4x/api.html#res.send) method
286
- supports. It can also be a (sync/async) function that accepts the Express
287
- request and response objects and then returns a `string`, JSON object or any
288
- other value the Express `response.send` function accepts.
259
+ [`res.send`](https://expressjs.com/en/4x/api.html#res.send) method supports. It
260
+ can also be a (sync/async) function that accepts the Express request and
261
+ response objects and then returns a `string`, JSON object or any other value the
262
+ Express `res.send` function accepts.
289
263
 
290
264
  Defaults to `'Too many requests, please try again later.'`
291
265
 
@@ -298,8 +272,8 @@ const isPremium = async (user) => {
298
272
 
299
273
  const limiter = rateLimit({
300
274
  // ...
301
- message: async (request, response) => {
302
- if (await isPremium(request.user))
275
+ message: async (req, res) => {
276
+ if (await isPremium(req.user))
303
277
  return 'You can only make 10 requests every hour.'
304
278
  else return 'You can only make 5 requests every hour.'
305
279
  },
@@ -422,7 +396,7 @@ By default, the client's IP address is used:
422
396
  ```ts
423
397
  const limiter = rateLimit({
424
398
  // ...
425
- keyGenerator: (request, response) => request.ip,
399
+ keyGenerator: (req, res) => req.ip,
426
400
  })
427
401
  ```
428
402
 
@@ -443,8 +417,8 @@ similar to this:
443
417
  ```ts
444
418
  const limiter = rateLimit({
445
419
  // ...
446
- handler: (request, response, next, options) =>
447
- response.status(options.statusCode).send(options.message),
420
+ handler: (req, res, next, options) =>
421
+ res.status(options.statusCode).send(options.message),
448
422
  })
449
423
  ```
450
424
 
@@ -452,9 +426,8 @@ const limiter = rateLimit({
452
426
 
453
427
  > `function`
454
428
 
455
- A (sync/async) function that accepts the Express `request` and `response`
456
- objects that is called the on the request where a client has just exceeded their
457
- rate limit.
429
+ A (sync/async) function that accepts the Express `req` and `res` objects that is
430
+ called the on the request where a client has just exceeded their rate limit.
458
431
 
459
432
  This method was
460
433
  [deprecated in v6](https://github.com/express-rate-limit/express-rate-limit/releases/v6.0.0) -
@@ -475,7 +448,7 @@ const allowlist = ['192.168.0.56', '192.168.0.21']
475
448
 
476
449
  const limiter = rateLimit({
477
450
  // ...
478
- skip: (request, response) => allowlist.includes(request.ip),
451
+ skip: (req, res) => allowlist.includes(req.ip),
479
452
  })
480
453
  ```
481
454
 
@@ -484,7 +457,7 @@ By default, it skips no requests:
484
457
  ```ts
485
458
  const limiter = rateLimit({
486
459
  // ...
487
- skip: (request, response) => false,
460
+ skip: (req, res) => false,
488
461
  })
489
462
  ```
490
463
 
@@ -494,8 +467,8 @@ const limiter = rateLimit({
494
467
 
495
468
  Method to determine whether or not the request counts as 'succesful'. Used when
496
469
  either `skipSuccessfulRequests` or `skipFailedRequests` is set to true. Should
497
- be a (sync/async) function that accepts the Express `request` and `response`
498
- objects and then returns `true` or `false`.
470
+ be a (sync/async) function that accepts the Express `req` and `res` objects and
471
+ then returns `true` or `false`.
499
472
 
500
473
  By default, requests with a response status code less than 400 are considered
501
474
  successful:
@@ -503,24 +476,43 @@ successful:
503
476
  ```ts
504
477
  const limiter = rateLimit({
505
478
  // ...
506
- requestWasSuccessful: (request, response) => response.statusCode < 400,
479
+ requestWasSuccessful: (req, res) => res.statusCode < 400,
507
480
  })
508
481
  ```
509
482
 
510
483
  ### `validate`
511
484
 
512
- > `boolean`
485
+ > `boolean | Object`
513
486
 
514
- When enabled, a set of validation checks are run on the first request to detect
515
- common misconfigurations with proxies, etc. Prints an error to the console if
516
- any issue is detected.
487
+ When enabled, a set of validation checks are run at creation and on the first
488
+ request to detect common misconfigurations with proxies, etc. Prints an error to
489
+ the console if any issue is detected.
517
490
 
518
491
  Automatically disables after the first request is processed.
519
492
 
493
+ If set to `true` or `false`, all validations are enabled or disabled.
494
+
495
+ If set to an object, individual validations can be enabled or disabled by name,
496
+ and the key `default` controls all unspecified validations. For example:
497
+
498
+ ```js
499
+ const limiter = rateLimit({
500
+ validate: {
501
+ xForwardedForHeader: false,
502
+ default: true,
503
+ },
504
+ // ...
505
+ })
506
+ ```
507
+
508
+ Supported options are `ip`, `trustProxy`, `xForwardedForHeader`, `positiveHits`,
509
+ `singleCount`, `limit`, `draftPolliHeaders`, `onLimitReached`,
510
+ `headersResetTime`, `validationsConfig`, and `default`.
511
+
520
512
  See https://github.com/express-rate-limit/express-rate-limit/wiki/Error-Codes
521
513
  for more info.
522
514
 
523
- Defaults to true.
515
+ Defaults to `true`.
524
516
 
525
517
  ### `store`
526
518
 
@@ -546,10 +538,12 @@ if you wish to create your own store.
546
538
 
547
539
  ## Request API
548
540
 
549
- A `request.rateLimit` property is added to all requests with the `limit`,
550
- `current`, and `remaining` number of requests and, if the store provides it, a
551
- `resetTime` Date object. These may be used in your application code to take
552
- additional actions or inform the user of their status.
541
+ A `req.rateLimit` property is added to all requests with the `limit`, `used`,
542
+ and `remaining` number of requests and, if the store provides it, a `resetTime`
543
+ Date object. These may be used in your application code to take additional
544
+ actions or inform the user of their status.
545
+
546
+ Note that `used` includes the current request, so it should always be > 0.
553
547
 
554
548
  The property name can be configured with the configuration option
555
549
  `requestPropertyName`.
@@ -576,4 +570,5 @@ fix/implement it!
576
570
 
577
571
  ## License
578
572
 
579
- MIT © [Nathan Friedly](http://nfriedly.com/)
573
+ MIT © [Nathan Friedly](http://nfriedly.com/),
574
+ [Vedant K](https://github.com/gamemaker1)
package/tsconfig.json CHANGED
@@ -1,5 +1,8 @@
1
1
  {
2
2
  "include": ["source/"],
3
3
  "exclude": ["node_modules/"],
4
- "extends": "@express-rate-limit/tsconfig"
4
+ "extends": "@express-rate-limit/tsconfig",
5
+ "compilerOptions": {
6
+ "target": "ES2020"
7
+ }
5
8
  }