nestjs-rate-limiter
Advanced tools
Comparing version 2.4.0 to 2.5.0
@@ -20,3 +20,3 @@ "use strict"; | ||
storeType: undefined, | ||
dbName: undefined, | ||
dbName: 'rate-limiter', | ||
tableName: undefined, | ||
@@ -23,0 +23,0 @@ tableCreated: undefined, |
@@ -9,2 +9,3 @@ import { Reflector } from '@nestjs/core'; | ||
private rateLimiters; | ||
private spesificOptions; | ||
private queueLimiter; | ||
@@ -11,0 +12,0 @@ constructor(options: RateLimiterOptions, reflector: Reflector); |
@@ -40,2 +40,4 @@ "use strict"; | ||
const default_options_1 = require("./default-options"); | ||
const env = require("dotenv"); | ||
env.config(); | ||
let RateLimiterInterceptor = class RateLimiterInterceptor { | ||
@@ -46,13 +48,16 @@ constructor(options, reflector) { | ||
this.rateLimiters = new Map(); | ||
this.options = Object.assign(Object.assign({}, default_options_1.defaultRateLimiterOptions), this.options); | ||
this.options.execEvenlyMinDelayMs = (this.options.duration * 1000) / this.options.points; | ||
} | ||
getRateLimiter(keyPrefix, options) { | ||
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
this.options = Object.assign(Object.assign({}, this.options), options); | ||
this.options = Object.assign(Object.assign({}, default_options_1.defaultRateLimiterOptions), this.options); | ||
this.spesificOptions = null; | ||
this.spesificOptions = options; | ||
let rateLimiter = this.rateLimiters.get(keyPrefix); | ||
const limiterOptions = Object.assign(Object.assign(Object.assign({}, this.options), options), { keyPrefix }); | ||
const libraryArguments = __rest(limiterOptions, []); | ||
if (libraryArguments.execEvenlyMinDelayMs === undefined) | ||
libraryArguments.execEvenlyMinDelayMs = (this.options.duration * 1000) / this.options.points; | ||
if (!rateLimiter) { | ||
switch (this.options.type) { | ||
switch (((_a = this.spesificOptions) === null || _a === void 0 ? void 0 : _a.type) || this.options.type) { | ||
case 'Memory': | ||
@@ -71,12 +76,12 @@ rateLimiter = new rate_limiter_flexible_1.RateLimiterMemory(libraryArguments); | ||
case 'Postgres': | ||
if (this.options.storeType === undefined) | ||
this.options.storeType = this.options.storeClient.constructor.name; | ||
if (this.options.dbName === undefined) | ||
this.options.dbName = 'rate-limiter'; | ||
if (this.options.tableName === undefined) | ||
this.options.tableName = this.options.keyPrefix; | ||
if (this.options.tableCreated === undefined) | ||
this.options.tableCreated = false; | ||
if (this.options.clearExpiredByTimeout === undefined) | ||
this.options.clearExpiredByTimeout = true; | ||
if (libraryArguments.storeType === undefined) | ||
libraryArguments.storeType = this.options.storeClient.constructor.name; | ||
libraryArguments.tableName = ((_b = this.spesificOptions) === null || _b === void 0 ? void 0 : _b.tableName) || this.options.tableName; | ||
if (libraryArguments.tableName === undefined) { | ||
libraryArguments.tableName = ((_c = this.spesificOptions) === null || _c === void 0 ? void 0 : _c.keyPrefix) || this.options.keyPrefix; | ||
} | ||
if (libraryArguments.tableCreated === undefined) | ||
libraryArguments.tableCreated = false; | ||
if (libraryArguments.clearExpiredByTimeout === undefined) | ||
libraryArguments.clearExpiredByTimeout = true; | ||
rateLimiter = yield new Promise((resolve, reject) => { | ||
@@ -95,12 +100,12 @@ const limiter = new rate_limiter_flexible_1.RateLimiterPostgres(libraryArguments, (err) => { | ||
case 'MySQL': | ||
if (this.options.storeType === undefined) | ||
this.options.storeType = this.options.storeClient.constructor.name; | ||
if (this.options.dbName === undefined) | ||
this.options.dbName = 'rate-limiter'; | ||
if (this.options.tableName === undefined) | ||
this.options.tableName = this.options.keyPrefix; | ||
if (this.options.tableCreated === undefined) | ||
this.options.tableCreated = false; | ||
if (this.options.clearExpiredByTimeout === undefined) | ||
this.options.clearExpiredByTimeout = true; | ||
if (libraryArguments.storeType === undefined) | ||
libraryArguments.storeType = this.options.storeClient.constructor.name; | ||
libraryArguments.tableName = ((_d = this.spesificOptions) === null || _d === void 0 ? void 0 : _d.tableName) || this.options.tableName; | ||
if (libraryArguments.tableName === undefined) { | ||
libraryArguments.tableName = ((_e = this.spesificOptions) === null || _e === void 0 ? void 0 : _e.keyPrefix) || this.options.keyPrefix; | ||
} | ||
if (libraryArguments.tableCreated === undefined) | ||
libraryArguments.tableCreated = false; | ||
if (libraryArguments.clearExpiredByTimeout === undefined) | ||
libraryArguments.clearExpiredByTimeout = true; | ||
rateLimiter = yield new Promise((resolve, reject) => { | ||
@@ -119,8 +124,8 @@ const limiter = new rate_limiter_flexible_1.RateLimiterMySQL(libraryArguments, (err) => { | ||
case 'Mongo': | ||
if (this.options.storeType === undefined) | ||
this.options.storeType = this.options.storeClient.constructor.name; | ||
if (this.options.dbName === undefined) | ||
this.options.dbName = 'rate-limiter'; | ||
if (this.options.tableName === undefined) | ||
this.options.tableName = this.options.keyPrefix; | ||
if (libraryArguments.storeType === undefined) | ||
libraryArguments.storeType = this.options.storeClient.constructor.name; | ||
libraryArguments.tableName = ((_f = this.spesificOptions) === null || _f === void 0 ? void 0 : _f.tableName) || this.options.tableName; | ||
if (libraryArguments.tableName === undefined) { | ||
libraryArguments.tableName = ((_g = this.spesificOptions) === null || _g === void 0 ? void 0 : _g.keyPrefix) || this.options.keyPrefix; | ||
} | ||
rateLimiter = new rate_limiter_flexible_1.RateLimiterMongo(libraryArguments); | ||
@@ -134,5 +139,5 @@ common_1.Logger.log(`Rate Limiter started with ${keyPrefix} key prefix`, 'RateLimiterMongo'); | ||
} | ||
if (this.options.queueEnabled) { | ||
if (((_h = this.spesificOptions) === null || _h === void 0 ? void 0 : _h.queueEnabled) || this.options.queueEnabled) { | ||
this.queueLimiter = new rate_limiter_flexible_1.RateLimiterQueue(rateLimiter, { | ||
maxQueueSize: this.options.maxQueueSize | ||
maxQueueSize: ((_j = this.spesificOptions) === null || _j === void 0 ? void 0 : _j.maxQueueSize) || this.options.maxQueueSize | ||
}); | ||
@@ -142,4 +147,4 @@ } | ||
limiter: rateLimiter, | ||
whiteList: this.options.whiteList, | ||
blackList: this.options.blackList, | ||
whiteList: ((_k = this.spesificOptions) === null || _k === void 0 ? void 0 : _k.whiteList) || this.options.whiteList, | ||
blackList: ((_l = this.spesificOptions) === null || _l === void 0 ? void 0 : _l.blackList) || this.options.blackList, | ||
runActionAnyway: false | ||
@@ -151,6 +156,9 @@ }); | ||
intercept(context, next) { | ||
var _a, _b, _c; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
let points = this.options.points; | ||
let pointsConsumed = this.options.pointsConsumed; | ||
let keyPrefix = this.options.keyPrefix; | ||
if (process.env.RATE_LIMITER === '0') | ||
return next.handle(); | ||
let points = ((_a = this.spesificOptions) === null || _a === void 0 ? void 0 : _a.points) || this.options.points; | ||
let pointsConsumed = ((_b = this.spesificOptions) === null || _b === void 0 ? void 0 : _b.pointsConsumed) || this.options.pointsConsumed; | ||
let keyPrefix = ((_c = this.spesificOptions) === null || _c === void 0 ? void 0 : _c.keyPrefix) || this.options.keyPrefix; | ||
const reflectedOptions = this.reflector.get('rateLimit', context.getHandler()); | ||
@@ -178,4 +186,4 @@ if (reflectedOptions) { | ||
const key = request.ip.replace(/^.*:/, ''); | ||
const process = yield this.responseHandler(response, key, rateLimiter, points, pointsConsumed, next); | ||
return process; | ||
const operation = yield this.responseHandler(response, key, rateLimiter, points, pointsConsumed, next); | ||
return operation; | ||
}); | ||
@@ -204,6 +212,7 @@ } | ||
responseHandler(response, key, rateLimiter, points, pointsConsumed, next) { | ||
var _a, _b, _c, _d; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
if (this.options.for === 'Fastify' || this.options.for === 'FastifyGraphql') { | ||
try { | ||
if (this.options.queueEnabled) | ||
if (((_a = this.spesificOptions) === null || _a === void 0 ? void 0 : _a.queueEnabled) || this.options.queueEnabled) | ||
yield this.queueLimiter.removeTokens(1); | ||
@@ -224,3 +233,3 @@ else { | ||
error: 'Too Many Requests', | ||
message: this.options.errorMessage | ||
message: ((_b = this.spesificOptions) === null || _b === void 0 ? void 0 : _b.errorMessage) || this.options.errorMessage | ||
}); | ||
@@ -231,3 +240,3 @@ } | ||
try { | ||
if (this.options.queueEnabled) | ||
if (((_c = this.spesificOptions) === null || _c === void 0 ? void 0 : _c.queueEnabled) || this.options.queueEnabled) | ||
yield this.queueLimiter.removeTokens(1); | ||
@@ -248,3 +257,3 @@ else { | ||
error: 'Too Many Requests', | ||
message: this.options.errorMessage | ||
message: ((_d = this.spesificOptions) === null || _d === void 0 ? void 0 : _d.errorMessage) || this.options.errorMessage | ||
}); | ||
@@ -251,0 +260,0 @@ } |
{ | ||
"name": "nestjs-rate-limiter", | ||
"version": "2.4.0", | ||
"version": "2.5.0", | ||
"description": "Highly configurable rate limiter library", | ||
@@ -36,2 +36,3 @@ "repository": { | ||
"dependencies": { | ||
"dotenv": "^8.2.0", | ||
"rate-limiter-flexible": "2.1.10" | ||
@@ -42,2 +43,3 @@ }, | ||
"@nestjs/core": "latest", | ||
"@types/node": "^14.11.1", | ||
"prettier": "^2.1.1", | ||
@@ -44,0 +46,0 @@ "reflect-metadata": "0.1.13", |
@@ -199,6 +199,7 @@ <p align="center"> | ||
# Options | ||
# Options | ||
- #### for | ||
#### for | ||
<code> Default: 'Express'</code> | ||
<br> | ||
<code> Type: 'Express' | 'Fastify' | 'Microservice' | 'ExpressGraphql' | 'FastifyGraphql'</code> | ||
@@ -209,4 +210,5 @@ <br> | ||
- #### type | ||
#### type | ||
<code> Default: 'Memory'</code> | ||
<br> | ||
<code> Type: 'Memory' | 'Redis' | 'Memcache' | 'Postgres' | 'MySQL' | 'Mongo'</code> | ||
@@ -216,4 +218,5 @@ <br> | ||
Here you define where the limiter data will be stored. Each option plays a different role in limiter performance, to see that please check [benchmarks](https://github.com/ozkanonur/nestjs-rate-limiter#benchmarks). | ||
- #### keyPrefix | ||
#### keyPrefix | ||
<code> Default: 'global'</code> | ||
<br> | ||
<code> Type: string</code> | ||
@@ -227,4 +230,5 @@ <br> | ||
Note: for some limiters it should correspond to Storage requirements for tables or collections name, as keyPrefix may be used as their name. | ||
- #### points | ||
#### points | ||
<code> Default: 4</code> | ||
<br> | ||
<code> Type: number</code> | ||
@@ -234,4 +238,5 @@ <br> | ||
Maximum number of points can be consumed over duration | ||
- #### pointsConsumed | ||
#### pointsConsumed | ||
<code> Default: 1</code> | ||
<br> | ||
<code> Type: number</code> | ||
@@ -243,4 +248,5 @@ <br> | ||
For instance if you have a limit of 100 points per 60 seconds, and pointsConsumed is set to 10, the user will effectively be able to make 10 requests per 60 seconds. | ||
- #### inmemoryBlockOnConsumed | ||
#### inmemoryBlockOnConsumed | ||
<code> Default: 0</code> | ||
<br> | ||
<code> Type: number</code> | ||
@@ -254,4 +260,5 @@ <br> | ||
It blocks a key in memory for msBeforeNext milliseconds from the last consume result, if inmemoryBlockDuration is not set. This helps to avoid extra requests. It is not necessary to increment counter on store, if all points are consumed already. | ||
- #### duration | ||
#### duration | ||
<code> Default: 1</code> | ||
<br> | ||
<code> Type: number</code> | ||
@@ -263,4 +270,5 @@ <br> | ||
Keys never expire, if duration is 0. | ||
- #### blockDuration | ||
#### blockDuration | ||
<code> Default: 0</code> | ||
<br> | ||
<code> Type: number</code> | ||
@@ -270,4 +278,5 @@ <br> | ||
If positive number and consumed more than points in current duration, block for blockDuration seconds. | ||
- #### inmemoryBlockDuration | ||
#### inmemoryBlockDuration | ||
<code> Default: 0</code> | ||
<br> | ||
<code> Type: number</code> | ||
@@ -279,4 +288,5 @@ <br> | ||
Block key for inmemoryBlockDuration seconds, if inmemoryBlockOnConsumed or more points are consumed. Set it the same as blockDuration option for distributed application to have consistent result on all processes. | ||
- #### queueEnabled | ||
#### queueEnabled | ||
<code> Default: false</code> | ||
<br> | ||
<code> Type: boolean</code> | ||
@@ -286,4 +296,5 @@ <br> | ||
It activates the queue mechanism, and holds the incoming requests for <code>duration</code> value. | ||
- #### whiteList | ||
#### whiteList | ||
<code> Default: []</code> | ||
<br> | ||
<code> Type: string[]</code> | ||
@@ -293,4 +304,5 @@ <br> | ||
If the IP is white listed, consume resolved no matter how many points consumed. | ||
- #### blackList | ||
#### blackList | ||
<code> Default: []</code> | ||
<br> | ||
<code> Type: string[]</code> | ||
@@ -300,11 +312,14 @@ <br> | ||
If the IP is black listed, consume rejected anytime. Blacklisted IPs are blocked on code level not in store/memory. Think of it as of requests filter. | ||
- #### storeClient | ||
#### storeClient | ||
<code> Default: undefined</code> | ||
<br> | ||
<code> Type: any</code> | ||
<br> | ||
Required for Redis, Memcached, MongoDB, MySQL, PostgreSQL, etc | ||
Required for Redis, Memcached, MongoDB, MySQL, PostgreSQL, etc. | ||
Have to be redis, ioredis, memcached, mongodb, pg, mysql2, mysql or any other related pool or connection. | ||
- #### insuranceLimiter | ||
#### insuranceLimiter | ||
<code> Default: undefined</code> | ||
<br> | ||
<code> Type: any</code> | ||
@@ -320,4 +335,5 @@ <br> | ||
Note: insuranceLimiter automatically setup blockDuration and execEvenly to same values as in parent to avoid unexpected behaviour | ||
- #### storeType | ||
#### storeType | ||
<code> Default: storeClient.constructor.name</code> | ||
<br> | ||
<code> Type: any</code> | ||
@@ -328,4 +344,5 @@ <br> | ||
It is required only for Knex and have to be set to 'knex' | ||
- #### dbName | ||
#### dbName | ||
<code> Default for MySQL, Postgres & Mongo: 'rate-limiter'</code> | ||
<br> | ||
<code> Type: string</code> | ||
@@ -336,4 +353,5 @@ <br> | ||
- #### tableName | ||
#### tableName | ||
<code> Default: equals to 'keyPrefix' option</code> | ||
<br> | ||
<code> Type: string</code> | ||
@@ -345,4 +363,5 @@ <br> | ||
By default, limiter creates a table for each unique keyPrefix. tableName option sets table/collection name where values should be stor | ||
- #### tableCreated | ||
#### tableCreated | ||
<code> Default: false</code> | ||
<br> | ||
<code> Type: boolean</code> | ||
@@ -353,4 +372,5 @@ <br> | ||
- #### clearExpiredByTimeout | ||
#### clearExpiredByTimeout | ||
<code> Default for MySQL and PostgreSQL: true</code> | ||
<br> | ||
<code> Type: boolean</code> | ||
@@ -360,4 +380,5 @@ <br> | ||
Rate limiter deletes data expired more than 1 hour ago every 5 minutes. | ||
- #### execEvenly | ||
#### execEvenly | ||
<code> Default: false</code> | ||
<br> | ||
<code> Type: boolean</code> | ||
@@ -369,4 +390,5 @@ <br> | ||
Note: it isn't recommended to use it for long duration and few points, as it may delay action for too long with default execEvenlyMinDelayMs. | ||
- #### execEvenlyMinDelayMs | ||
#### execEvenlyMinDelayMs | ||
<code> Default: duration * 1000 / points</code> | ||
<br> | ||
<code> Type: number</code> | ||
@@ -376,4 +398,5 @@ <br> | ||
Sets minimum delay in milliseconds, when action is delayed with execEvenly | ||
- #### indexKeyPrefix | ||
#### indexKeyPrefix | ||
<code> Default: {}</code> | ||
<br> | ||
<code> Type: {}</code> | ||
@@ -383,4 +406,5 @@ <br> | ||
Object which is used to create combined index by {...indexKeyPrefix, key: 1} attributes. | ||
- #### maxQueueSize | ||
#### maxQueueSize | ||
<code> Default: 100</code> | ||
<br> | ||
<code> Type: number</code> | ||
@@ -390,4 +414,5 @@ <br> | ||
Determines the maximum number of requests in the queue and returns <code>429</code> as response to requests that over of the maxQueueSize. | ||
- #### errorMessage | ||
#### errorMessage | ||
<code> Default: 'Rate limit exceeded'</code> | ||
<br> | ||
<code> Type: string</code> | ||
@@ -394,0 +419,0 @@ <br> |
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
40855
448
423
2
8
1
+ Addeddotenv@^8.2.0
+ Addeddotenv@8.6.0(transitive)