nestjs-shield 1.0.1 → 1.1.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 +1 -1
- package/dist/storage/redis.storage.js +22 -12
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -37,7 +37,7 @@ Or from GitHub Packages (published as `@yassinos-coder/nestjs-shield`) — first
|
|
|
37
37
|
GITHUB_TOKEN=ghp_xxx npm install @yassinos-coder/nestjs-shield
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
-
Node ≥ 18, NestJS 9 / 10 / 11.
|
|
40
|
+
Node ≥ 18, NestJS 9 / 10 / 11 / 12. NestJS 12 applications require Node ≥ 20.
|
|
41
41
|
|
|
42
42
|
## Quick start
|
|
43
43
|
|
|
@@ -111,6 +111,19 @@ local ttl = redis.call('PTTL', key)
|
|
|
111
111
|
if ttl < 0 then ttl = 0 end
|
|
112
112
|
return { count, ttl }
|
|
113
113
|
`;
|
|
114
|
+
const BURST_INCREMENT_LUA = `
|
|
115
|
+
local count = redis.call('INCR', KEYS[1])
|
|
116
|
+
redis.call('PEXPIRE', KEYS[1], ARGV[1])
|
|
117
|
+
return count
|
|
118
|
+
`;
|
|
119
|
+
const BURST_DECREMENT_LUA = `
|
|
120
|
+
local count = tonumber(redis.call('GET', KEYS[1]) or '0')
|
|
121
|
+
if count <= 1 then
|
|
122
|
+
redis.call('DEL', KEYS[1])
|
|
123
|
+
return 0
|
|
124
|
+
end
|
|
125
|
+
return redis.call('DECR', KEYS[1])
|
|
126
|
+
`;
|
|
114
127
|
const SLIDING_COUNTER_LUA = `
|
|
115
128
|
local cur = KEYS[1]
|
|
116
129
|
local prev = KEYS[2]
|
|
@@ -166,11 +179,9 @@ class RedisStorage {
|
|
|
166
179
|
}
|
|
167
180
|
async fixedWindow(key, ttlMs, limit) {
|
|
168
181
|
const k = this.k(key);
|
|
169
|
-
const
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
const ttl = await this.client.pttl(k);
|
|
173
|
-
return { count, allowed: count <= limit, resetMs: Math.max(0, ttl), limit };
|
|
182
|
+
const res = (await this.runScript('shieldIncrement', INCREMENT_LUA, [k], [1, ttlMs]));
|
|
183
|
+
const count = Number(res[0]);
|
|
184
|
+
return { count, allowed: count <= limit, resetMs: Math.max(0, Number(res[1])), limit };
|
|
174
185
|
}
|
|
175
186
|
async slidingWindowCounter(key, ttlMs, limit) {
|
|
176
187
|
const now = Date.now();
|
|
@@ -225,16 +236,13 @@ class RedisStorage {
|
|
|
225
236
|
}
|
|
226
237
|
async incrementConcurrent(key) {
|
|
227
238
|
const k = this.k(`burst:${key}`);
|
|
228
|
-
const next = await this.
|
|
229
|
-
|
|
230
|
-
return next;
|
|
239
|
+
const next = await this.runScript('shieldBurstIncrement', BURST_INCREMENT_LUA, [k], [60_000]);
|
|
240
|
+
return Number(next);
|
|
231
241
|
}
|
|
232
242
|
async decrementConcurrent(key) {
|
|
233
243
|
const k = this.k(`burst:${key}`);
|
|
234
|
-
const next = await this.
|
|
235
|
-
|
|
236
|
-
await this.client.del(k);
|
|
237
|
-
return Math.max(0, next);
|
|
244
|
+
const next = await this.runScript('shieldBurstDecrement', BURST_DECREMENT_LUA, [k], []);
|
|
245
|
+
return Math.max(0, Number(next));
|
|
238
246
|
}
|
|
239
247
|
k(key) {
|
|
240
248
|
return this.prefix ? `${this.prefix}:${key}` : key;
|
|
@@ -255,6 +263,8 @@ class RedisStorage {
|
|
|
255
263
|
this.client.defineCommand('shieldSlidingLog', { numberOfKeys: 1, lua: SLIDING_LOG_LUA });
|
|
256
264
|
this.client.defineCommand('shieldSlidingCounter', { numberOfKeys: 2, lua: SLIDING_COUNTER_LUA });
|
|
257
265
|
this.client.defineCommand('shieldIncrement', { numberOfKeys: 1, lua: INCREMENT_LUA });
|
|
266
|
+
this.client.defineCommand('shieldBurstIncrement', { numberOfKeys: 1, lua: BURST_INCREMENT_LUA });
|
|
267
|
+
this.client.defineCommand('shieldBurstDecrement', { numberOfKeys: 1, lua: BURST_DECREMENT_LUA });
|
|
258
268
|
this.commandsDefined = true;
|
|
259
269
|
}
|
|
260
270
|
catch {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nestjs-shield",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Layered API protection for NestJS: rate limiting, IP allow/block lists, auto-ban, slow-down, UA filtering, burst caps, payload limits. Pluggable storage (memory/Redis).",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -51,8 +51,8 @@
|
|
|
51
51
|
"node": ">=18"
|
|
52
52
|
},
|
|
53
53
|
"peerDependencies": {
|
|
54
|
-
"@nestjs/common": "^9.0.0 || ^10.0.0 || ^11.0.0",
|
|
55
|
-
"@nestjs/core": "^9.0.0 || ^10.0.0 || ^11.0.0",
|
|
54
|
+
"@nestjs/common": "^9.0.0 || ^10.0.0 || ^11.0.0 || ^12.0.0",
|
|
55
|
+
"@nestjs/core": "^9.0.0 || ^10.0.0 || ^11.0.0 || ^12.0.0",
|
|
56
56
|
"reflect-metadata": "^0.1.13 || ^0.2.0",
|
|
57
57
|
"rxjs": "^7.0.0"
|
|
58
58
|
},
|
|
@@ -65,9 +65,9 @@
|
|
|
65
65
|
"ipaddr.js": "^2.2.0"
|
|
66
66
|
},
|
|
67
67
|
"devDependencies": {
|
|
68
|
-
"@nestjs/common": "^
|
|
69
|
-
"@nestjs/core": "^
|
|
70
|
-
"@types/node": "^
|
|
68
|
+
"@nestjs/common": "^12.0.1",
|
|
69
|
+
"@nestjs/core": "^12.0.1",
|
|
70
|
+
"@types/node": "^22.0.0",
|
|
71
71
|
"ioredis": "^5.4.1",
|
|
72
72
|
"reflect-metadata": "^0.2.2",
|
|
73
73
|
"rimraf": "^5.0.7",
|