rate-limiter-flexible 2.4.2 → 3.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/README.md +2 -0
- package/lib/RateLimiterRedis.js +71 -67
- package/lib/RateLimiterStoreAbstract.js +2 -60
- package/lib/index.d.ts +2 -8
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -193,6 +193,8 @@ Specific:
|
|
|
193
193
|
* [indexKeyPrefix](https://github.com/animir/node-rate-limiter-flexible/wiki/Options#indexkeyprefix) Combined indexes of MongoDB.
|
|
194
194
|
* [timeoutMs](https://github.com/animir/node-rate-limiter-flexible/wiki/Options#timeoutms) For Cluster.
|
|
195
195
|
* [rejectIfRedisNotReady](https://github.com/animir/node-rate-limiter-flexible/wiki/Options#rejectifredisnotready)
|
|
196
|
+
* [useRedisPackage](https://github.com/animir/node-rate-limiter-flexible/wiki/Options#useredispackage)
|
|
197
|
+
* [useRedis3AndLowerPackage](https://github.com/animir/node-rate-limiter-flexible/wiki/Options#useredis3andlowerpackage)
|
|
196
198
|
|
|
197
199
|
## API
|
|
198
200
|
|
package/lib/RateLimiterRedis.js
CHANGED
|
@@ -24,14 +24,12 @@ class RateLimiterRedis extends RateLimiterStoreAbstract {
|
|
|
24
24
|
*/
|
|
25
25
|
constructor(opts) {
|
|
26
26
|
super(opts);
|
|
27
|
-
|
|
28
|
-
this.client = opts.redis;
|
|
29
|
-
} else {
|
|
30
|
-
this.client = opts.storeClient;
|
|
31
|
-
}
|
|
27
|
+
this.client = opts.storeClient;
|
|
32
28
|
|
|
33
29
|
this._rejectIfRedisNotReady = !!opts.rejectIfRedisNotReady;
|
|
34
30
|
|
|
31
|
+
this.useRedisPackage = opts.useRedisPackage;
|
|
32
|
+
this.useRedis3AndLowerPackage = opts.useRedis3AndLowerPackage;
|
|
35
33
|
if (typeof this.client.defineCommand === 'function') {
|
|
36
34
|
this.client.defineCommand("rlflxIncr", {
|
|
37
35
|
numberOfKeys: 1,
|
|
@@ -79,32 +77,39 @@ class RateLimiterRedis extends RateLimiterStoreAbstract {
|
|
|
79
77
|
return res;
|
|
80
78
|
}
|
|
81
79
|
|
|
82
|
-
_upsert(rlKey, points, msDuration, forceExpire = false) {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
80
|
+
async _upsert(rlKey, points, msDuration, forceExpire = false) {
|
|
81
|
+
if (!this._isRedisReady()) {
|
|
82
|
+
throw new Error('Redis connection is not ready');
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const secDuration = Math.floor(msDuration / 1000);
|
|
86
|
+
const multi = this.client.multi();
|
|
87
87
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
multi.set(rlKey, points);
|
|
88
|
+
if (forceExpire) {
|
|
89
|
+
if (secDuration > 0) {
|
|
90
|
+
if(!this.useRedisPackage && !this.useRedis3AndLowerPackage){
|
|
91
|
+
multi.set(rlKey, points, "EX", secDuration);
|
|
92
|
+
}else{
|
|
93
|
+
multi.set(rlKey, points, { EX: secDuration });
|
|
95
94
|
}
|
|
95
|
+
} else {
|
|
96
|
+
multi.set(rlKey, points);
|
|
97
|
+
}
|
|
96
98
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
99
|
+
if(!this.useRedisPackage && !this.useRedis3AndLowerPackage){
|
|
100
|
+
return multi.pttl(rlKey).exec(true);
|
|
101
|
+
}
|
|
102
|
+
return multi.pTTL(rlKey).exec(true);
|
|
103
|
+
}
|
|
102
104
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
105
|
+
if (secDuration > 0) {
|
|
106
|
+
if(!this.useRedisPackage && !this.useRedis3AndLowerPackage){
|
|
107
|
+
return this.client.rlflxIncr(
|
|
108
|
+
[rlKey].concat([String(points), String(secDuration)]));
|
|
109
|
+
}
|
|
110
|
+
if (this.useRedis3AndLowerPackage) {
|
|
111
|
+
return new Promise((resolve, reject) => {
|
|
112
|
+
const incrCallback = function (err, result) {
|
|
108
113
|
if (err) {
|
|
109
114
|
return reject(err);
|
|
110
115
|
}
|
|
@@ -117,56 +122,55 @@ class RateLimiterRedis extends RateLimiterStoreAbstract {
|
|
|
117
122
|
} else {
|
|
118
123
|
this.client.eval(incrTtlLuaScript, 1, rlKey, points, secDuration, incrCallback);
|
|
119
124
|
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
return resolve(res);
|
|
129
|
-
});
|
|
130
|
-
}
|
|
125
|
+
});
|
|
126
|
+
} else {
|
|
127
|
+
return this.client.eval(incrTtlLuaScript, {
|
|
128
|
+
keys: [rlKey],
|
|
129
|
+
arguments: [String(points), String(secDuration)],
|
|
130
|
+
});
|
|
131
131
|
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
_get(rlKey) {
|
|
136
|
-
return new Promise((resolve, reject) => {
|
|
137
|
-
if (!this._isRedisReady()) {
|
|
138
|
-
return reject(new Error('Redis connection is not ready'));
|
|
132
|
+
} else {
|
|
133
|
+
if(!this.useRedisPackage && !this.useRedis3AndLowerPackage){
|
|
134
|
+
return multi.incrby(rlKey, points).pttl(rlKey).exec(true);
|
|
139
135
|
}
|
|
140
136
|
|
|
141
|
-
|
|
137
|
+
return multi.incrBy(rlKey, points).pTTL(rlKey).exec(true);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
async _get(rlKey) {
|
|
142
|
+
if (!this._isRedisReady()) {
|
|
143
|
+
throw new Error('Redis connection is not ready');
|
|
144
|
+
}
|
|
145
|
+
if(!this.useRedisPackage && !this.useRedis3AndLowerPackage){
|
|
146
|
+
return this.client
|
|
142
147
|
.multi()
|
|
143
148
|
.get(rlKey)
|
|
144
149
|
.pttl(rlKey)
|
|
145
|
-
.exec(
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
if (points === null) {
|
|
151
|
-
return resolve(null)
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
resolve(res);
|
|
155
|
-
}
|
|
150
|
+
.exec()
|
|
151
|
+
.then((result) => {
|
|
152
|
+
const [[,points]] = result;
|
|
153
|
+
if (points === null) return null;
|
|
154
|
+
return result;
|
|
156
155
|
});
|
|
157
|
-
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return this.client
|
|
159
|
+
.multi()
|
|
160
|
+
.get(rlKey)
|
|
161
|
+
.pTTL(rlKey)
|
|
162
|
+
.exec(true)
|
|
163
|
+
.then((result) => {
|
|
164
|
+
const [points] = result;
|
|
165
|
+
if (points === null) return null;
|
|
166
|
+
return result;
|
|
167
|
+
});
|
|
158
168
|
}
|
|
159
169
|
|
|
160
170
|
_delete(rlKey) {
|
|
161
|
-
return
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
reject(err);
|
|
165
|
-
} else {
|
|
166
|
-
resolve(res > 0);
|
|
167
|
-
}
|
|
168
|
-
});
|
|
169
|
-
});
|
|
171
|
+
return this.client
|
|
172
|
+
.del(rlKey)
|
|
173
|
+
.then(result => result > 0);
|
|
170
174
|
}
|
|
171
175
|
}
|
|
172
176
|
|
|
@@ -16,8 +16,8 @@ module.exports = class RateLimiterStoreAbstract extends RateLimiterAbstract {
|
|
|
16
16
|
constructor(opts = {}) {
|
|
17
17
|
super(opts);
|
|
18
18
|
|
|
19
|
-
this.inMemoryBlockOnConsumed = opts.inMemoryBlockOnConsumed
|
|
20
|
-
this.inMemoryBlockDuration = opts.inMemoryBlockDuration
|
|
19
|
+
this.inMemoryBlockOnConsumed = opts.inMemoryBlockOnConsumed;
|
|
20
|
+
this.inMemoryBlockDuration = opts.inMemoryBlockDuration;
|
|
21
21
|
this.insuranceLimiter = opts.insuranceLimiter;
|
|
22
22
|
this._inMemoryBlockedKeys = new BlockedKeys();
|
|
23
23
|
}
|
|
@@ -106,64 +106,6 @@ module.exports = class RateLimiterStoreAbstract extends RateLimiterAbstract {
|
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
-
/**
|
|
110
|
-
* @deprecated Use camelCase version
|
|
111
|
-
* @returns {BlockedKeys}
|
|
112
|
-
* @private
|
|
113
|
-
*/
|
|
114
|
-
get _inmemoryBlockedKeys() {
|
|
115
|
-
return this._inMemoryBlockedKeys
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* @deprecated Use camelCase version
|
|
120
|
-
* @param rlKey
|
|
121
|
-
* @returns {number}
|
|
122
|
-
*/
|
|
123
|
-
getInmemoryBlockMsBeforeExpire(rlKey) {
|
|
124
|
-
return this.getInMemoryBlockMsBeforeExpire(rlKey)
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* @deprecated Use camelCase version
|
|
129
|
-
* @returns {number|number}
|
|
130
|
-
*/
|
|
131
|
-
get inmemoryBlockOnConsumed() {
|
|
132
|
-
return this.inMemoryBlockOnConsumed;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* @deprecated Use camelCase version
|
|
137
|
-
* @param value
|
|
138
|
-
*/
|
|
139
|
-
set inmemoryBlockOnConsumed(value) {
|
|
140
|
-
this.inMemoryBlockOnConsumed = value;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* @deprecated Use camelCase version
|
|
145
|
-
* @returns {number|number}
|
|
146
|
-
*/
|
|
147
|
-
get inmemoryBlockDuration() {
|
|
148
|
-
return this.inMemoryBlockDuration;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* @deprecated Use camelCase version
|
|
153
|
-
* @param value
|
|
154
|
-
*/
|
|
155
|
-
set inmemoryBlockDuration(value) {
|
|
156
|
-
this.inMemoryBlockDuration = value
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* @deprecated Use camelCase version
|
|
161
|
-
* @returns {number}
|
|
162
|
-
*/
|
|
163
|
-
get msInmemoryBlockDuration() {
|
|
164
|
-
return this.inMemoryBlockDuration * 1000;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
109
|
getInMemoryBlockMsBeforeExpire(rlKey) {
|
|
168
110
|
if (this.inMemoryBlockOnConsumed > 0) {
|
|
169
111
|
return this._inMemoryBlockedKeys.msBeforeExpire(rlKey);
|
package/lib/index.d.ts
CHANGED
|
@@ -231,14 +231,6 @@ interface IRateLimiterStoreOptions extends IRateLimiterOptions {
|
|
|
231
231
|
storeType?: string;
|
|
232
232
|
inMemoryBlockOnConsumed?: number;
|
|
233
233
|
inMemoryBlockDuration?: number;
|
|
234
|
-
/**
|
|
235
|
-
* @deprecated Use camelCased inMemoryBlockOnConsumed option
|
|
236
|
-
*/
|
|
237
|
-
inmemoryBlockOnConsumed?: number;
|
|
238
|
-
/**
|
|
239
|
-
* @deprecated Use camelCased inMemoryBlockOnConsumed option
|
|
240
|
-
*/
|
|
241
|
-
inmemoryBlockDuration?: number;
|
|
242
234
|
insuranceLimiter?: RateLimiterAbstract;
|
|
243
235
|
dbName?: string;
|
|
244
236
|
tableName?: string;
|
|
@@ -257,6 +249,8 @@ interface IRateLimiterMongoOptions extends IRateLimiterStoreOptions {
|
|
|
257
249
|
|
|
258
250
|
interface IRateLimiterRedisOptions extends IRateLimiterStoreOptions {
|
|
259
251
|
rejectIfRedisNotReady?: boolean;
|
|
252
|
+
useRedisPackage?: boolean;
|
|
253
|
+
useRedis3AndLowerPackage?: boolean;
|
|
260
254
|
}
|
|
261
255
|
|
|
262
256
|
interface ICallbackReady {
|
package/package.json
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rate-limiter-flexible",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Node.js rate limiter by key and protection from DDoS and Brute-Force attacks in process Memory, Redis, MongoDb, Memcached, MySQL, PostgreSQL, Cluster or PM",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
|
+
"dc:up": "docker-compose -f docker-compose.yml up -d",
|
|
8
|
+
"dc:down": "docker-compose -f docker-compose.yml down",
|
|
7
9
|
"test": "istanbul -v cover -- _mocha --recursive",
|
|
8
10
|
"debug-test": "mocha --inspect-brk lib/**/**.test.js",
|
|
9
11
|
"coveralls": "cat ./coverage/lcov.info | coveralls",
|
|
@@ -46,9 +48,11 @@
|
|
|
46
48
|
"eslint-plugin-import": "^2.7.0",
|
|
47
49
|
"eslint-plugin-node": "^6.0.1",
|
|
48
50
|
"eslint-plugin-security": "^1.4.0",
|
|
51
|
+
"ioredis": "^5.3.2",
|
|
49
52
|
"istanbul": "^0.4.5",
|
|
50
53
|
"memcached-mock": "^0.1.0",
|
|
51
|
-
"mocha": "^
|
|
54
|
+
"mocha": "^10.2.0",
|
|
55
|
+
"redis": "^4.6.8",
|
|
52
56
|
"redis-mock": "^0.48.0",
|
|
53
57
|
"sinon": "^5.0.10"
|
|
54
58
|
},
|