express-rate-limit 8.0.1 → 8.2.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/dist/index.cjs +78 -4
- package/dist/index.d.cts +20 -2
- package/dist/index.d.mts +20 -2
- package/dist/index.d.ts +20 -2
- package/dist/index.mjs +78 -4
- package/package.json +13 -13
package/dist/index.cjs
CHANGED
|
@@ -39,7 +39,8 @@ function ipKeyGenerator(ip, ipv6Subnet = 56) {
|
|
|
39
39
|
|
|
40
40
|
// source/memory-store.ts
|
|
41
41
|
var MemoryStore = class {
|
|
42
|
-
constructor() {
|
|
42
|
+
constructor(validations2) {
|
|
43
|
+
this.validations = validations2;
|
|
43
44
|
/**
|
|
44
45
|
* These two maps store usage (requests) and reset time by key (for example, IP
|
|
45
46
|
* addresses or API keys).
|
|
@@ -65,6 +66,7 @@ var MemoryStore = class {
|
|
|
65
66
|
*/
|
|
66
67
|
init(options) {
|
|
67
68
|
this.windowMs = options.windowMs;
|
|
69
|
+
this.validations?.windowMs(this.windowMs);
|
|
68
70
|
if (this.interval) clearInterval(this.interval);
|
|
69
71
|
this.interval = setInterval(() => {
|
|
70
72
|
this.clearExpired();
|
|
@@ -237,7 +239,7 @@ var setDraft6Headers = (response, info, windowMs) => {
|
|
|
237
239
|
response.setHeader("RateLimit-Policy", `${info.limit};w=${windowSeconds}`);
|
|
238
240
|
response.setHeader("RateLimit-Limit", info.limit.toString());
|
|
239
241
|
response.setHeader("RateLimit-Remaining", info.remaining.toString());
|
|
240
|
-
if (resetSeconds)
|
|
242
|
+
if (typeof resetSeconds === "number")
|
|
241
243
|
response.setHeader("RateLimit-Reset", resetSeconds.toString());
|
|
242
244
|
};
|
|
243
245
|
var setDraft7Headers = (response, info, windowMs) => {
|
|
@@ -367,6 +369,21 @@ var validations = {
|
|
|
367
369
|
);
|
|
368
370
|
}
|
|
369
371
|
},
|
|
372
|
+
/**
|
|
373
|
+
* Alert the user if the Forwarded header is set (standardized version of X-Forwarded-For - not supported by express as of version 5.1.0)
|
|
374
|
+
*
|
|
375
|
+
* @param request {Request} - The Express request object.
|
|
376
|
+
*
|
|
377
|
+
* @returns {void}
|
|
378
|
+
*/
|
|
379
|
+
forwardedHeader(request) {
|
|
380
|
+
if (request.headers.forwarded && request.ip === request.socket?.remoteAddress) {
|
|
381
|
+
throw new ValidationError(
|
|
382
|
+
"ERR_ERL_FORWARDED_HEADER",
|
|
383
|
+
`The 'Forwarded' header (standardized X-Forwarded-For) is set but currently being ignored. Add a custom keyGenerator to use a value from this header.`
|
|
384
|
+
);
|
|
385
|
+
}
|
|
386
|
+
},
|
|
370
387
|
/**
|
|
371
388
|
* Ensures totalHits value from store is a positive integer.
|
|
372
389
|
*
|
|
@@ -504,12 +521,50 @@ var validations = {
|
|
|
504
521
|
);
|
|
505
522
|
}
|
|
506
523
|
},
|
|
524
|
+
knownOptions(passedOptions) {
|
|
525
|
+
if (!passedOptions) return;
|
|
526
|
+
const optionsMap = {
|
|
527
|
+
windowMs: true,
|
|
528
|
+
limit: true,
|
|
529
|
+
message: true,
|
|
530
|
+
statusCode: true,
|
|
531
|
+
legacyHeaders: true,
|
|
532
|
+
standardHeaders: true,
|
|
533
|
+
identifier: true,
|
|
534
|
+
requestPropertyName: true,
|
|
535
|
+
skipFailedRequests: true,
|
|
536
|
+
skipSuccessfulRequests: true,
|
|
537
|
+
keyGenerator: true,
|
|
538
|
+
ipv6Subnet: true,
|
|
539
|
+
handler: true,
|
|
540
|
+
skip: true,
|
|
541
|
+
requestWasSuccessful: true,
|
|
542
|
+
store: true,
|
|
543
|
+
validate: true,
|
|
544
|
+
headers: true,
|
|
545
|
+
max: true,
|
|
546
|
+
passOnStoreError: true
|
|
547
|
+
};
|
|
548
|
+
const validOptions = Object.keys(optionsMap).concat(
|
|
549
|
+
"draft_polli_ratelimit_headers"
|
|
550
|
+
// not a valid option anymore, but we have a more specific check for this one, so don't warn for it here
|
|
551
|
+
);
|
|
552
|
+
for (const key of Object.keys(passedOptions)) {
|
|
553
|
+
if (!validOptions.includes(key)) {
|
|
554
|
+
throw new ValidationError(
|
|
555
|
+
"ERR_ERL_UNKNOWN_OPTION",
|
|
556
|
+
`Unexpected configuration option: ${key}`
|
|
557
|
+
// todo: suggest a valid option with a short levenstein distance?
|
|
558
|
+
);
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
},
|
|
507
562
|
/**
|
|
508
563
|
* Checks the options.validate setting to ensure that only recognized
|
|
509
564
|
* validations are enabled or disabled.
|
|
510
565
|
*
|
|
511
566
|
* If any unrecognized values are found, an error is logged that
|
|
512
|
-
* includes the list of supported
|
|
567
|
+
* includes the list of supported validations.
|
|
513
568
|
*/
|
|
514
569
|
validationsConfig() {
|
|
515
570
|
const supportedValidations = Object.keys(this).filter(
|
|
@@ -580,6 +635,21 @@ var validations = {
|
|
|
580
635
|
"Custom keyGenerator appears to use request IP without calling the ipKeyGenerator helper function for IPv6 addresses. This could allow IPv6 users to bypass limits."
|
|
581
636
|
);
|
|
582
637
|
}
|
|
638
|
+
},
|
|
639
|
+
/**
|
|
640
|
+
* Checks to see if the window duration is greater than 2^32 - 1. This is only
|
|
641
|
+
* called by the default MemoryStore, since it uses Node's setInterval method.
|
|
642
|
+
*
|
|
643
|
+
* See https://nodejs.org/api/timers.html#setintervalcallback-delay-args.
|
|
644
|
+
*/
|
|
645
|
+
windowMs(windowMs) {
|
|
646
|
+
const SET_TIMEOUT_MAX = 2 ** 31 - 1;
|
|
647
|
+
if (typeof windowMs !== "number" || Number.isNaN(windowMs) || windowMs < 1 || windowMs > SET_TIMEOUT_MAX) {
|
|
648
|
+
throw new ValidationError(
|
|
649
|
+
"ERR_ERL_WINDOW_MS",
|
|
650
|
+
`Invalid windowMs value: ${windowMs}${typeof windowMs !== "number" ? ` (${typeof windowMs})` : ""}, must be a number between 1 and ${SET_TIMEOUT_MAX} when using the default MemoryStore`
|
|
651
|
+
);
|
|
652
|
+
}
|
|
583
653
|
}
|
|
584
654
|
};
|
|
585
655
|
var getValidations = (_enabled) => {
|
|
@@ -664,6 +734,7 @@ var parseOptions = (passedOptions) => {
|
|
|
664
734
|
const notUndefinedOptions = omitUndefinedProperties(passedOptions);
|
|
665
735
|
const validations2 = getValidations(notUndefinedOptions?.validate ?? true);
|
|
666
736
|
validations2.validationsConfig();
|
|
737
|
+
validations2.knownOptions(passedOptions);
|
|
667
738
|
validations2.draftPolliHeaders(
|
|
668
739
|
// @ts-expect-error see the note above.
|
|
669
740
|
notUndefinedOptions.draft_polli_ratelimit_headers
|
|
@@ -706,6 +777,7 @@ var parseOptions = (passedOptions) => {
|
|
|
706
777
|
validations2.ip(request.ip);
|
|
707
778
|
validations2.trustProxy(request);
|
|
708
779
|
validations2.xForwardedForHeader(request);
|
|
780
|
+
validations2.forwardedHeader(request);
|
|
709
781
|
const ip = request.ip;
|
|
710
782
|
let subnet = 56;
|
|
711
783
|
if ((0, import_node_net3.isIPv6)(ip)) {
|
|
@@ -731,7 +803,9 @@ var parseOptions = (passedOptions) => {
|
|
|
731
803
|
standardHeaders,
|
|
732
804
|
// Note that this field is declared after the user's options are spread in,
|
|
733
805
|
// so that this field doesn't get overridden with an un-promisified store!
|
|
734
|
-
store: promisifyStore(
|
|
806
|
+
store: promisifyStore(
|
|
807
|
+
notUndefinedOptions.store ?? new MemoryStore(validations2)
|
|
808
|
+
),
|
|
735
809
|
// Print an error to the console if a few known misconfigurations are detected.
|
|
736
810
|
validations: validations2
|
|
737
811
|
};
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Generated by dts-bundle-generator v8.
|
|
1
|
+
// Generated by dts-bundle-generator v8.1.2
|
|
2
2
|
|
|
3
3
|
import { NextFunction, Request, RequestHandler, Response } from 'express';
|
|
4
4
|
|
|
@@ -60,6 +60,14 @@ declare const validations: {
|
|
|
60
60
|
* @returns {void}
|
|
61
61
|
*/
|
|
62
62
|
xForwardedForHeader(request: Request): void;
|
|
63
|
+
/**
|
|
64
|
+
* Alert the user if the Forwarded header is set (standardized version of X-Forwarded-For - not supported by express as of version 5.1.0)
|
|
65
|
+
*
|
|
66
|
+
* @param request {Request} - The Express request object.
|
|
67
|
+
*
|
|
68
|
+
* @returns {void}
|
|
69
|
+
*/
|
|
70
|
+
forwardedHeader(request: Request): void;
|
|
63
71
|
/**
|
|
64
72
|
* Ensures totalHits value from store is a positive integer.
|
|
65
73
|
*
|
|
@@ -124,12 +132,13 @@ declare const validations: {
|
|
|
124
132
|
* @returns {void}
|
|
125
133
|
*/
|
|
126
134
|
headersResetTime(resetTime?: Date): void;
|
|
135
|
+
knownOptions(passedOptions?: Partial<Options>): void;
|
|
127
136
|
/**
|
|
128
137
|
* Checks the options.validate setting to ensure that only recognized
|
|
129
138
|
* validations are enabled or disabled.
|
|
130
139
|
*
|
|
131
140
|
* If any unrecognized values are found, an error is logged that
|
|
132
|
-
* includes the list of supported
|
|
141
|
+
* includes the list of supported validations.
|
|
133
142
|
*/
|
|
134
143
|
validationsConfig(): void;
|
|
135
144
|
/**
|
|
@@ -141,6 +150,13 @@ declare const validations: {
|
|
|
141
150
|
ipv6Subnet(ipv6Subnet?: any): void;
|
|
142
151
|
ipv6SubnetOrKeyGenerator(options: Partial<Options>): void;
|
|
143
152
|
keyGeneratorIpFallback(keyGenerator?: ValueDeterminingMiddleware<string>): void;
|
|
153
|
+
/**
|
|
154
|
+
* Checks to see if the window duration is greater than 2^32 - 1. This is only
|
|
155
|
+
* called by the default MemoryStore, since it uses Node's setInterval method.
|
|
156
|
+
*
|
|
157
|
+
* See https://nodejs.org/api/timers.html#setintervalcallback-delay-args.
|
|
158
|
+
*/
|
|
159
|
+
windowMs(windowMs: number): void;
|
|
144
160
|
};
|
|
145
161
|
export type Validations = typeof validations;
|
|
146
162
|
/**
|
|
@@ -496,6 +512,7 @@ export type Client = {
|
|
|
496
512
|
* @public
|
|
497
513
|
*/
|
|
498
514
|
export declare class MemoryStore implements Store {
|
|
515
|
+
private validations?;
|
|
499
516
|
/**
|
|
500
517
|
* The duration of time before which all hit counts are reset (in milliseconds).
|
|
501
518
|
*/
|
|
@@ -521,6 +538,7 @@ export declare class MemoryStore implements Store {
|
|
|
521
538
|
* cannot affect other instances.
|
|
522
539
|
*/
|
|
523
540
|
localKeys: boolean;
|
|
541
|
+
constructor(validations?: Validations | undefined);
|
|
524
542
|
/**
|
|
525
543
|
* Method that initializes the store.
|
|
526
544
|
*
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Generated by dts-bundle-generator v8.
|
|
1
|
+
// Generated by dts-bundle-generator v8.1.2
|
|
2
2
|
|
|
3
3
|
import { NextFunction, Request, RequestHandler, Response } from 'express';
|
|
4
4
|
|
|
@@ -60,6 +60,14 @@ declare const validations: {
|
|
|
60
60
|
* @returns {void}
|
|
61
61
|
*/
|
|
62
62
|
xForwardedForHeader(request: Request): void;
|
|
63
|
+
/**
|
|
64
|
+
* Alert the user if the Forwarded header is set (standardized version of X-Forwarded-For - not supported by express as of version 5.1.0)
|
|
65
|
+
*
|
|
66
|
+
* @param request {Request} - The Express request object.
|
|
67
|
+
*
|
|
68
|
+
* @returns {void}
|
|
69
|
+
*/
|
|
70
|
+
forwardedHeader(request: Request): void;
|
|
63
71
|
/**
|
|
64
72
|
* Ensures totalHits value from store is a positive integer.
|
|
65
73
|
*
|
|
@@ -124,12 +132,13 @@ declare const validations: {
|
|
|
124
132
|
* @returns {void}
|
|
125
133
|
*/
|
|
126
134
|
headersResetTime(resetTime?: Date): void;
|
|
135
|
+
knownOptions(passedOptions?: Partial<Options>): void;
|
|
127
136
|
/**
|
|
128
137
|
* Checks the options.validate setting to ensure that only recognized
|
|
129
138
|
* validations are enabled or disabled.
|
|
130
139
|
*
|
|
131
140
|
* If any unrecognized values are found, an error is logged that
|
|
132
|
-
* includes the list of supported
|
|
141
|
+
* includes the list of supported validations.
|
|
133
142
|
*/
|
|
134
143
|
validationsConfig(): void;
|
|
135
144
|
/**
|
|
@@ -141,6 +150,13 @@ declare const validations: {
|
|
|
141
150
|
ipv6Subnet(ipv6Subnet?: any): void;
|
|
142
151
|
ipv6SubnetOrKeyGenerator(options: Partial<Options>): void;
|
|
143
152
|
keyGeneratorIpFallback(keyGenerator?: ValueDeterminingMiddleware<string>): void;
|
|
153
|
+
/**
|
|
154
|
+
* Checks to see if the window duration is greater than 2^32 - 1. This is only
|
|
155
|
+
* called by the default MemoryStore, since it uses Node's setInterval method.
|
|
156
|
+
*
|
|
157
|
+
* See https://nodejs.org/api/timers.html#setintervalcallback-delay-args.
|
|
158
|
+
*/
|
|
159
|
+
windowMs(windowMs: number): void;
|
|
144
160
|
};
|
|
145
161
|
export type Validations = typeof validations;
|
|
146
162
|
/**
|
|
@@ -496,6 +512,7 @@ export type Client = {
|
|
|
496
512
|
* @public
|
|
497
513
|
*/
|
|
498
514
|
export declare class MemoryStore implements Store {
|
|
515
|
+
private validations?;
|
|
499
516
|
/**
|
|
500
517
|
* The duration of time before which all hit counts are reset (in milliseconds).
|
|
501
518
|
*/
|
|
@@ -521,6 +538,7 @@ export declare class MemoryStore implements Store {
|
|
|
521
538
|
* cannot affect other instances.
|
|
522
539
|
*/
|
|
523
540
|
localKeys: boolean;
|
|
541
|
+
constructor(validations?: Validations | undefined);
|
|
524
542
|
/**
|
|
525
543
|
* Method that initializes the store.
|
|
526
544
|
*
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Generated by dts-bundle-generator v8.
|
|
1
|
+
// Generated by dts-bundle-generator v8.1.2
|
|
2
2
|
|
|
3
3
|
import { NextFunction, Request, RequestHandler, Response } from 'express';
|
|
4
4
|
|
|
@@ -60,6 +60,14 @@ declare const validations: {
|
|
|
60
60
|
* @returns {void}
|
|
61
61
|
*/
|
|
62
62
|
xForwardedForHeader(request: Request): void;
|
|
63
|
+
/**
|
|
64
|
+
* Alert the user if the Forwarded header is set (standardized version of X-Forwarded-For - not supported by express as of version 5.1.0)
|
|
65
|
+
*
|
|
66
|
+
* @param request {Request} - The Express request object.
|
|
67
|
+
*
|
|
68
|
+
* @returns {void}
|
|
69
|
+
*/
|
|
70
|
+
forwardedHeader(request: Request): void;
|
|
63
71
|
/**
|
|
64
72
|
* Ensures totalHits value from store is a positive integer.
|
|
65
73
|
*
|
|
@@ -124,12 +132,13 @@ declare const validations: {
|
|
|
124
132
|
* @returns {void}
|
|
125
133
|
*/
|
|
126
134
|
headersResetTime(resetTime?: Date): void;
|
|
135
|
+
knownOptions(passedOptions?: Partial<Options>): void;
|
|
127
136
|
/**
|
|
128
137
|
* Checks the options.validate setting to ensure that only recognized
|
|
129
138
|
* validations are enabled or disabled.
|
|
130
139
|
*
|
|
131
140
|
* If any unrecognized values are found, an error is logged that
|
|
132
|
-
* includes the list of supported
|
|
141
|
+
* includes the list of supported validations.
|
|
133
142
|
*/
|
|
134
143
|
validationsConfig(): void;
|
|
135
144
|
/**
|
|
@@ -141,6 +150,13 @@ declare const validations: {
|
|
|
141
150
|
ipv6Subnet(ipv6Subnet?: any): void;
|
|
142
151
|
ipv6SubnetOrKeyGenerator(options: Partial<Options>): void;
|
|
143
152
|
keyGeneratorIpFallback(keyGenerator?: ValueDeterminingMiddleware<string>): void;
|
|
153
|
+
/**
|
|
154
|
+
* Checks to see if the window duration is greater than 2^32 - 1. This is only
|
|
155
|
+
* called by the default MemoryStore, since it uses Node's setInterval method.
|
|
156
|
+
*
|
|
157
|
+
* See https://nodejs.org/api/timers.html#setintervalcallback-delay-args.
|
|
158
|
+
*/
|
|
159
|
+
windowMs(windowMs: number): void;
|
|
144
160
|
};
|
|
145
161
|
export type Validations = typeof validations;
|
|
146
162
|
/**
|
|
@@ -496,6 +512,7 @@ export type Client = {
|
|
|
496
512
|
* @public
|
|
497
513
|
*/
|
|
498
514
|
export declare class MemoryStore implements Store {
|
|
515
|
+
private validations?;
|
|
499
516
|
/**
|
|
500
517
|
* The duration of time before which all hit counts are reset (in milliseconds).
|
|
501
518
|
*/
|
|
@@ -521,6 +538,7 @@ export declare class MemoryStore implements Store {
|
|
|
521
538
|
* cannot affect other instances.
|
|
522
539
|
*/
|
|
523
540
|
localKeys: boolean;
|
|
541
|
+
constructor(validations?: Validations | undefined);
|
|
524
542
|
/**
|
|
525
543
|
* Method that initializes the store.
|
|
526
544
|
*
|
package/dist/index.mjs
CHANGED
|
@@ -10,7 +10,8 @@ function ipKeyGenerator(ip, ipv6Subnet = 56) {
|
|
|
10
10
|
|
|
11
11
|
// source/memory-store.ts
|
|
12
12
|
var MemoryStore = class {
|
|
13
|
-
constructor() {
|
|
13
|
+
constructor(validations2) {
|
|
14
|
+
this.validations = validations2;
|
|
14
15
|
/**
|
|
15
16
|
* These two maps store usage (requests) and reset time by key (for example, IP
|
|
16
17
|
* addresses or API keys).
|
|
@@ -36,6 +37,7 @@ var MemoryStore = class {
|
|
|
36
37
|
*/
|
|
37
38
|
init(options) {
|
|
38
39
|
this.windowMs = options.windowMs;
|
|
40
|
+
this.validations?.windowMs(this.windowMs);
|
|
39
41
|
if (this.interval) clearInterval(this.interval);
|
|
40
42
|
this.interval = setInterval(() => {
|
|
41
43
|
this.clearExpired();
|
|
@@ -208,7 +210,7 @@ var setDraft6Headers = (response, info, windowMs) => {
|
|
|
208
210
|
response.setHeader("RateLimit-Policy", `${info.limit};w=${windowSeconds}`);
|
|
209
211
|
response.setHeader("RateLimit-Limit", info.limit.toString());
|
|
210
212
|
response.setHeader("RateLimit-Remaining", info.remaining.toString());
|
|
211
|
-
if (resetSeconds)
|
|
213
|
+
if (typeof resetSeconds === "number")
|
|
212
214
|
response.setHeader("RateLimit-Reset", resetSeconds.toString());
|
|
213
215
|
};
|
|
214
216
|
var setDraft7Headers = (response, info, windowMs) => {
|
|
@@ -338,6 +340,21 @@ var validations = {
|
|
|
338
340
|
);
|
|
339
341
|
}
|
|
340
342
|
},
|
|
343
|
+
/**
|
|
344
|
+
* Alert the user if the Forwarded header is set (standardized version of X-Forwarded-For - not supported by express as of version 5.1.0)
|
|
345
|
+
*
|
|
346
|
+
* @param request {Request} - The Express request object.
|
|
347
|
+
*
|
|
348
|
+
* @returns {void}
|
|
349
|
+
*/
|
|
350
|
+
forwardedHeader(request) {
|
|
351
|
+
if (request.headers.forwarded && request.ip === request.socket?.remoteAddress) {
|
|
352
|
+
throw new ValidationError(
|
|
353
|
+
"ERR_ERL_FORWARDED_HEADER",
|
|
354
|
+
`The 'Forwarded' header (standardized X-Forwarded-For) is set but currently being ignored. Add a custom keyGenerator to use a value from this header.`
|
|
355
|
+
);
|
|
356
|
+
}
|
|
357
|
+
},
|
|
341
358
|
/**
|
|
342
359
|
* Ensures totalHits value from store is a positive integer.
|
|
343
360
|
*
|
|
@@ -475,12 +492,50 @@ var validations = {
|
|
|
475
492
|
);
|
|
476
493
|
}
|
|
477
494
|
},
|
|
495
|
+
knownOptions(passedOptions) {
|
|
496
|
+
if (!passedOptions) return;
|
|
497
|
+
const optionsMap = {
|
|
498
|
+
windowMs: true,
|
|
499
|
+
limit: true,
|
|
500
|
+
message: true,
|
|
501
|
+
statusCode: true,
|
|
502
|
+
legacyHeaders: true,
|
|
503
|
+
standardHeaders: true,
|
|
504
|
+
identifier: true,
|
|
505
|
+
requestPropertyName: true,
|
|
506
|
+
skipFailedRequests: true,
|
|
507
|
+
skipSuccessfulRequests: true,
|
|
508
|
+
keyGenerator: true,
|
|
509
|
+
ipv6Subnet: true,
|
|
510
|
+
handler: true,
|
|
511
|
+
skip: true,
|
|
512
|
+
requestWasSuccessful: true,
|
|
513
|
+
store: true,
|
|
514
|
+
validate: true,
|
|
515
|
+
headers: true,
|
|
516
|
+
max: true,
|
|
517
|
+
passOnStoreError: true
|
|
518
|
+
};
|
|
519
|
+
const validOptions = Object.keys(optionsMap).concat(
|
|
520
|
+
"draft_polli_ratelimit_headers"
|
|
521
|
+
// not a valid option anymore, but we have a more specific check for this one, so don't warn for it here
|
|
522
|
+
);
|
|
523
|
+
for (const key of Object.keys(passedOptions)) {
|
|
524
|
+
if (!validOptions.includes(key)) {
|
|
525
|
+
throw new ValidationError(
|
|
526
|
+
"ERR_ERL_UNKNOWN_OPTION",
|
|
527
|
+
`Unexpected configuration option: ${key}`
|
|
528
|
+
// todo: suggest a valid option with a short levenstein distance?
|
|
529
|
+
);
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
},
|
|
478
533
|
/**
|
|
479
534
|
* Checks the options.validate setting to ensure that only recognized
|
|
480
535
|
* validations are enabled or disabled.
|
|
481
536
|
*
|
|
482
537
|
* If any unrecognized values are found, an error is logged that
|
|
483
|
-
* includes the list of supported
|
|
538
|
+
* includes the list of supported validations.
|
|
484
539
|
*/
|
|
485
540
|
validationsConfig() {
|
|
486
541
|
const supportedValidations = Object.keys(this).filter(
|
|
@@ -551,6 +606,21 @@ var validations = {
|
|
|
551
606
|
"Custom keyGenerator appears to use request IP without calling the ipKeyGenerator helper function for IPv6 addresses. This could allow IPv6 users to bypass limits."
|
|
552
607
|
);
|
|
553
608
|
}
|
|
609
|
+
},
|
|
610
|
+
/**
|
|
611
|
+
* Checks to see if the window duration is greater than 2^32 - 1. This is only
|
|
612
|
+
* called by the default MemoryStore, since it uses Node's setInterval method.
|
|
613
|
+
*
|
|
614
|
+
* See https://nodejs.org/api/timers.html#setintervalcallback-delay-args.
|
|
615
|
+
*/
|
|
616
|
+
windowMs(windowMs) {
|
|
617
|
+
const SET_TIMEOUT_MAX = 2 ** 31 - 1;
|
|
618
|
+
if (typeof windowMs !== "number" || Number.isNaN(windowMs) || windowMs < 1 || windowMs > SET_TIMEOUT_MAX) {
|
|
619
|
+
throw new ValidationError(
|
|
620
|
+
"ERR_ERL_WINDOW_MS",
|
|
621
|
+
`Invalid windowMs value: ${windowMs}${typeof windowMs !== "number" ? ` (${typeof windowMs})` : ""}, must be a number between 1 and ${SET_TIMEOUT_MAX} when using the default MemoryStore`
|
|
622
|
+
);
|
|
623
|
+
}
|
|
554
624
|
}
|
|
555
625
|
};
|
|
556
626
|
var getValidations = (_enabled) => {
|
|
@@ -635,6 +705,7 @@ var parseOptions = (passedOptions) => {
|
|
|
635
705
|
const notUndefinedOptions = omitUndefinedProperties(passedOptions);
|
|
636
706
|
const validations2 = getValidations(notUndefinedOptions?.validate ?? true);
|
|
637
707
|
validations2.validationsConfig();
|
|
708
|
+
validations2.knownOptions(passedOptions);
|
|
638
709
|
validations2.draftPolliHeaders(
|
|
639
710
|
// @ts-expect-error see the note above.
|
|
640
711
|
notUndefinedOptions.draft_polli_ratelimit_headers
|
|
@@ -677,6 +748,7 @@ var parseOptions = (passedOptions) => {
|
|
|
677
748
|
validations2.ip(request.ip);
|
|
678
749
|
validations2.trustProxy(request);
|
|
679
750
|
validations2.xForwardedForHeader(request);
|
|
751
|
+
validations2.forwardedHeader(request);
|
|
680
752
|
const ip = request.ip;
|
|
681
753
|
let subnet = 56;
|
|
682
754
|
if (isIPv62(ip)) {
|
|
@@ -702,7 +774,9 @@ var parseOptions = (passedOptions) => {
|
|
|
702
774
|
standardHeaders,
|
|
703
775
|
// Note that this field is declared after the user's options are spread in,
|
|
704
776
|
// so that this field doesn't get overridden with an un-promisified store!
|
|
705
|
-
store: promisifyStore(
|
|
777
|
+
store: promisifyStore(
|
|
778
|
+
notUndefinedOptions.store ?? new MemoryStore(validations2)
|
|
779
|
+
),
|
|
706
780
|
// Print an error to the console if a few known misconfigurations are detected.
|
|
707
781
|
validations: validations2
|
|
708
782
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "express-rate-limit",
|
|
3
|
-
"version": "8.0
|
|
3
|
+
"version": "8.2.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",
|
|
@@ -77,29 +77,29 @@
|
|
|
77
77
|
"express": ">= 4.11"
|
|
78
78
|
},
|
|
79
79
|
"devDependencies": {
|
|
80
|
-
"@biomejs/biome": "2.
|
|
80
|
+
"@biomejs/biome": "2.3.1",
|
|
81
81
|
"@express-rate-limit/prettier": "1.1.1",
|
|
82
82
|
"@express-rate-limit/tsconfig": "1.0.2",
|
|
83
|
-
"@jest/globals": "30.0
|
|
84
|
-
"@types/express": "5.0.
|
|
83
|
+
"@jest/globals": "30.2.0",
|
|
84
|
+
"@types/express": "5.0.4",
|
|
85
85
|
"@types/jest": "30.0.0",
|
|
86
|
-
"@types/node": "24.
|
|
86
|
+
"@types/node": "24.9.1",
|
|
87
87
|
"@types/supertest": "6.0.3",
|
|
88
88
|
"del-cli": "6.0.0",
|
|
89
|
-
"dts-bundle-generator": "8.
|
|
90
|
-
"esbuild": "0.25.
|
|
89
|
+
"dts-bundle-generator": "8.1.2",
|
|
90
|
+
"esbuild": "0.25.11",
|
|
91
91
|
"express": "5.1.0",
|
|
92
92
|
"husky": "9.1.7",
|
|
93
|
-
"jest": "30.0
|
|
94
|
-
"lint-staged": "16.
|
|
95
|
-
"mintlify": "4.2.
|
|
93
|
+
"jest": "30.2.0",
|
|
94
|
+
"lint-staged": "16.2.6",
|
|
95
|
+
"mintlify": "4.2.179",
|
|
96
96
|
"npm-run-all": "4.1.5",
|
|
97
97
|
"prettier": "3.6.2",
|
|
98
98
|
"ratelimit-header-parser": "0.1.0",
|
|
99
|
-
"supertest": "7.1.
|
|
100
|
-
"ts-jest": "29.4.
|
|
99
|
+
"supertest": "7.1.4",
|
|
100
|
+
"ts-jest": "29.4.5",
|
|
101
101
|
"ts-node": "10.9.2",
|
|
102
|
-
"typescript": "5.
|
|
102
|
+
"typescript": "5.9.3"
|
|
103
103
|
},
|
|
104
104
|
"prettier": "@express-rate-limit/prettier",
|
|
105
105
|
"lint-staged": {
|