diff --git a/types/express-rate-limit/express-rate-limit-tests.ts b/types/express-rate-limit/express-rate-limit-tests.ts index aa5c51a016..4b94ef6b05 100644 --- a/types/express-rate-limit/express-rate-limit-tests.ts +++ b/types/express-rate-limit/express-rate-limit-tests.ts @@ -3,7 +3,19 @@ import RateLimit = require("express-rate-limit"); const apiLimiter = new RateLimit({ windowMs: 15 * 60 * 1000, // 15 minutes max: 100, - delayMs: 0 // disabled + headers: false, + skipFailedRequests: false, + skipSuccessfulRequests: true, +}); + +const apiLimiterWithMaxFn = new RateLimit({ + windowMs: 15 * 60 * 1000, + max: () => 5, +}); + +const apiLimiterWithMaxPromiseFn = new RateLimit({ + windowMs: 15 * 60 * 1000, + max: () => Promise.resolve(5), }); const apiLimiterWithMessageObject = new RateLimit({ @@ -17,8 +29,6 @@ const apiLimiterWithMessageObject = new RateLimit({ const createAccountLimiter = new RateLimit({ windowMs: 60 * 60 * 1000, // 1 hour window - delayAfter: 1, // begin slowing down responses after the first request - delayMs: 3 * 1000, // slow down subsequent responses by 3 seconds per request max: 5, // start blocking after 5 requests message: "Too many accounts created from this IP, please try again after an hour", handler: (req, _, next) => next(new Error(`TooManyRequests: ${req.ip}`)) diff --git a/types/express-rate-limit/index.d.ts b/types/express-rate-limit/index.d.ts index b3f074f28d..9d3459e21b 100644 --- a/types/express-rate-limit/index.d.ts +++ b/types/express-rate-limit/index.d.ts @@ -1,6 +1,8 @@ -// Type definitions for express-rate-limit 2.9 +// Type definitions for express-rate-limit 3.3 // Project: https://github.com/nfriedly/express-rate-limit -// Definitions by: Cyril Schumacher , makepost +// Definitions by: Cyril Schumacher +// makepost +// Jeremy Forsythe // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped // TypeScript Version: 2.2 @@ -21,19 +23,80 @@ declare namespace RateLimit { [key: string]: any; } + type MaxValueFn = () => number | Promise; + interface Options { - delayAfter?: number; - delayMs?: number; + /** + * The funciton to handle requests once `max` is exceeded. It receives the request and response objects. + * The "next" param is available if you need to pass to the next middleware. The `req.rateLimit` object + * has `limit`, `current`, and `remaining` number of requests, and if the store provides it, a `resetTime` + * Date object. + * Default: `(req, res, next) => res.status(options.statusCode).send(options.message)` + */ handler?(req: express.Request, res: express.Response, next: express.NextFunction): any; + + /** + * Enable headers for request limit (`X-RateLimit-Limit`) and current usage (`X-RateLimit-Remaining`) on all + * responses andtime to wait before retrying (`Retry-After`) when `max` is exceeded. Defaults to `true`. + */ headers?: boolean; + + /** + * Function used to generate keys. Defaults to using `req.ip`. + * Default: `(req, res) => req.ip` + */ keyGenerator?(req: express.Request, res: express.Response): string; - max?: number; + + /** + * Max number of connections during `windowMs` before sending a 429 response. May be a `number` or + * a function that returns a `number` or a `Promise`. Defaults to `5`. Set to `0` to disable. + */ + max?: number | MaxValueFn; + + /** + * Error message sent to user when `max` is exceeded. May be a `string`, JSON object, or any other value + * that Express's `req.send()` supports. Defaults to `'Too many requests, please try again later.'`. + */ message?: string | Buffer | Message; - skip?(req: express.Request, res: express.Response): boolean; - skipFailedRequests?: boolean; - statusCode?: number; - store?: Store; + + /** + * Function that is called the first time `max` is exceeded. The `req.rateLimit` object has `limit`, `current`, + * and `remaining` number of requests and, if the store provides it, a `resetTime` Date object. Default is + * an empty function. + * Default: `(req, res, opts) => {}` + */ onLimitReached?(req: express.Request, res: express.Response, optionsUsed: Options): void; + + /** + * Function used to skip requests. Returning `true` from the function will skip limiting for that request. Defaults to + * always `false` (count all requests). + * Default: `(req, res) => false` + */ + skip?(req: express.Request, res: express.Response): boolean; + + /** + * When set to `true`, failed requests (status >= 400, request canceled or errored) won't be counted. Defaults to `false`. + */ + skipFailedRequests?: boolean; + + /** + * When set to `true`, successful requests (status < 400) won't be counted. Defaults to `false`. + */ + skipSuccessfulRequests?: boolean; + + /** + * HTTP status code returned when `max` is exceeded. Defaults to `429`. + */ + statusCode?: number; + + /** + * The storage to use when persisting rate limit attempts. + */ + store?: Store; + + /** + * How long in milliseconds to keep records of requests in memory. Defaults to `60000` (1 minute). + */ windowMs?: number; } } diff --git a/types/express-rate-limit/v2/express-rate-limit-tests.ts b/types/express-rate-limit/v2/express-rate-limit-tests.ts new file mode 100644 index 0000000000..aa5c51a016 --- /dev/null +++ b/types/express-rate-limit/v2/express-rate-limit-tests.ts @@ -0,0 +1,39 @@ +import RateLimit = require("express-rate-limit"); + +const apiLimiter = new RateLimit({ + windowMs: 15 * 60 * 1000, // 15 minutes + max: 100, + delayMs: 0 // disabled +}); + +const apiLimiterWithMessageObject = new RateLimit({ + windowMs: 15 * 60 * 1000, // 15 minutes + max: 100, + message: { + status: 429, + message: 'To many requests, try again later' + } +}); + +const createAccountLimiter = new RateLimit({ + windowMs: 60 * 60 * 1000, // 1 hour window + delayAfter: 1, // begin slowing down responses after the first request + delayMs: 3 * 1000, // slow down subsequent responses by 3 seconds per request + max: 5, // start blocking after 5 requests + message: "Too many accounts created from this IP, please try again after an hour", + handler: (req, _, next) => next(new Error(`TooManyRequests: ${req.ip}`)) +}); + +const callbackWithFewerParams = new RateLimit({ + handler: (req, res) => res.status(429).json(`TooManyRequests: ${req.ip}`) +}); + +class SomeStore implements RateLimit.Store { + incr(key: string, cb: RateLimit.StoreIncrementCallback) { } + decrement(key: string) { } + resetKey(key: string) { } +} + +const limiterWithStore = new RateLimit({ + store: new SomeStore() +}); diff --git a/types/express-rate-limit/v2/index.d.ts b/types/express-rate-limit/v2/index.d.ts new file mode 100644 index 0000000000..b3f074f28d --- /dev/null +++ b/types/express-rate-limit/v2/index.d.ts @@ -0,0 +1,42 @@ +// Type definitions for express-rate-limit 2.9 +// Project: https://github.com/nfriedly/express-rate-limit +// Definitions by: Cyril Schumacher , makepost +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +// TypeScript Version: 2.2 + +import express = require("express"); + +declare namespace RateLimit { + type StoreIncrementCallback = (err?: {}, hits?: number) => void; + + interface Store { + incr(key: string, cb: StoreIncrementCallback): void; + decrement(key: string): void; + resetKey(key: string): void; + } + + interface Message { + status: number; + message: string; + [key: string]: any; + } + + interface Options { + delayAfter?: number; + delayMs?: number; + handler?(req: express.Request, res: express.Response, next: express.NextFunction): any; + headers?: boolean; + keyGenerator?(req: express.Request, res: express.Response): string; + max?: number; + message?: string | Buffer | Message; + skip?(req: express.Request, res: express.Response): boolean; + skipFailedRequests?: boolean; + statusCode?: number; + store?: Store; + onLimitReached?(req: express.Request, res: express.Response, optionsUsed: Options): void; + windowMs?: number; + } +} + +declare var RateLimit: new (options: RateLimit.Options) => express.RequestHandler; +export = RateLimit; diff --git a/types/express-rate-limit/v2/tsconfig.json b/types/express-rate-limit/v2/tsconfig.json new file mode 100644 index 0000000000..0e9b4d2ad4 --- /dev/null +++ b/types/express-rate-limit/v2/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "module": "commonjs", + "lib": [ + "es6" + ], + "noImplicitAny": true, + "noImplicitThis": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "baseUrl": "../../", + "typeRoots": [ + "../../" + ], + "paths": { + "express-rate-limit": ["express-rate-limit/v2"] + }, + "types": [], + "noEmit": true, + "forceConsistentCasingInFileNames": true + }, + "files": [ + "index.d.ts", + "express-rate-limit-tests.ts" + ] +} diff --git a/types/express-rate-limit/v2/tslint.json b/types/express-rate-limit/v2/tslint.json new file mode 100644 index 0000000000..3db14f85ea --- /dev/null +++ b/types/express-rate-limit/v2/tslint.json @@ -0,0 +1 @@ +{ "extends": "dtslint/dt.json" }