ayiin 2.0.46 → 2.0.48
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/methods/limiter.js +22 -8
- package/dist/types.d.ts +1 -1
- package/package.json +1 -1
package/dist/methods/limiter.js
CHANGED
|
@@ -63,8 +63,11 @@ class Limiter extends tools_1.default {
|
|
|
63
63
|
const userId = options.identifyUser
|
|
64
64
|
? options.identifyUser(req, res)
|
|
65
65
|
: (req.ip ?? "unknown");
|
|
66
|
+
// key storage
|
|
66
67
|
const floodKey = `${options.keyPrefix}:flood:${userId}`;
|
|
67
68
|
const levelKey = `${options.keyPrefix}:level:${userId}`;
|
|
69
|
+
const rateKey = `${options.keyPrefix}:rate:${userId}`;
|
|
70
|
+
// cek jika user terblock atau tidak
|
|
68
71
|
const blockedUntilStr = await store.get(floodKey);
|
|
69
72
|
if (blockedUntilStr) {
|
|
70
73
|
const blockedUntil = new Date(blockedUntilStr).getTime();
|
|
@@ -81,28 +84,39 @@ class Limiter extends tools_1.default {
|
|
|
81
84
|
return res.status(429).json({ success: false, error: msg });
|
|
82
85
|
}
|
|
83
86
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
const windowMs = this.toMilliseconds(options.windowMs);
|
|
87
|
+
// ambil level sekarang
|
|
88
|
+
let level = parseInt((await store.get(levelKey)) ?? "0", 10);
|
|
87
89
|
const refreshAtMs = this.toMilliseconds(options.refreshAt ?? { hours: 24 });
|
|
90
|
+
// tentukan windowMs sesuai level
|
|
91
|
+
let windowMs;
|
|
92
|
+
if (Array.isArray(options.windowMs)) {
|
|
93
|
+
const idx = Math.min(level, options.windowMs.length - 1);
|
|
94
|
+
const win = options.windowMs[idx];
|
|
95
|
+
windowMs = this.toMilliseconds(win);
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
windowMs = this.toMilliseconds(options.windowMs);
|
|
99
|
+
}
|
|
100
|
+
// hitung permintaan sekarang
|
|
101
|
+
const hits = await store.incr(rateKey);
|
|
88
102
|
if (hits === 1) {
|
|
89
103
|
await store.expire(rateKey, windowMs);
|
|
90
104
|
}
|
|
91
|
-
//
|
|
92
|
-
let level = parseInt((await store.get(levelKey)) ?? "0", 10);
|
|
93
|
-
// tentukan limit sesuai level
|
|
105
|
+
// tentukan limit sesuai level (langsung pakai level sebagai index)
|
|
94
106
|
let currentLimit;
|
|
95
107
|
if (Array.isArray(options.limit)) {
|
|
96
108
|
const limitIdx = Math.min(level, options.limit.length - 1);
|
|
97
|
-
|
|
98
|
-
currentLimit = limit;
|
|
109
|
+
currentLimit = options.limit[limitIdx];
|
|
99
110
|
}
|
|
100
111
|
else {
|
|
101
112
|
currentLimit = Number(options.limit);
|
|
102
113
|
}
|
|
114
|
+
// cek level jika permintaan melebihi limit
|
|
103
115
|
if (hits > currentLimit) {
|
|
104
116
|
level += 1;
|
|
105
117
|
await store.set(levelKey, level.toString(), refreshAtMs);
|
|
118
|
+
// reset hits untuk level baru
|
|
119
|
+
await store.set(rateKey, "0", windowMs);
|
|
106
120
|
let floodwaitMs;
|
|
107
121
|
if (Array.isArray(options.floodwaitMs)) {
|
|
108
122
|
const idx = Math.min(level - 1, options.floodwaitMs.length - 1);
|
package/dist/types.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ export interface DurationInput {
|
|
|
14
14
|
export interface RateLimiterOptions {
|
|
15
15
|
keyPrefix: string;
|
|
16
16
|
limit: number | readonly [number, ...number[]];
|
|
17
|
-
windowMs: DurationInput;
|
|
17
|
+
windowMs: DurationInput | readonly [DurationInput, ...DurationInput[]];
|
|
18
18
|
floodwaitMs: DurationInput | readonly [DurationInput, ...DurationInput[]];
|
|
19
19
|
identifyUser?: (req: Request, res: Response) => string | Response<any, Record<string, any>>;
|
|
20
20
|
store?: RateLimitStore;
|