fix: plugin/antibrute: was not considering parallel requests
Massimo Melina committed
May 1, 2022 at 20:18 UTC
d7ae2fcf21899338197252f29d69e2b2d388ea9b
1 file changed
+21
-19
plugins/antibrute/plugin.js
+21
-19
@@ -1,33 +1,35 @@
1
-exports.version = 1
1
+exports.version = 2
2
exports.description = "Introduce increasing delays between login attempts."
3
-exports.apiRequired = 1
3
+exports.apiRequired = 3 // log
4
5
-// these settings will grant 4 attempts in first minute, 2 in second minute, and 1 from the third one on
6
-const INCREMENT = 5_000
7
-const CAP = 60_000
5
+exports.config = {
6
+ increment: { type: 'number', min: 1, defaultValue: 5, md: 6, helperText: "Seconds to add to the delay for each login attempt" },
7
+ max: { type: 'number', min: 1, defaultValue: 60, md: 6, helperText: "Max seconds to delay before next login is allowed" },
8
+}
9
10
const byIp = {}
11
12
exports.init = api => {
13
const LOGIN_URI = api.const.API_URI + 'loginSrp1'
13
- return ({
14
+ const { getOrSet } = api.require('./misc')
15
+ return {
16
async middleware(ctx) {
17
if (ctx.path !== LOGIN_URI) return
16
- const k = ctx.ip
18
+ const { ip } = ctx
19
const now = Date.now()
18
- const rec = byIp[k]
19
- if (rec) {
20
- const wait = rec.when - now
21
- if (wait > 0) {
22
- console.log('plugin antibrute is delaying', k, 'for', Math.round(wait / 1000))
23
- await new Promise(resolve => setTimeout(resolve, wait))
24
- }
20
+ const rec = getOrSet(byIp, ip, () => ({ delay: 0, next: now }))
21
+ const wait = rec.next - now
22
+ const max = api.getConfig('max') * 1000
23
+ const inc = api.getConfig('increment') * 1000
24
+ rec.delay = Math.min(max, rec.delay + inc)
25
+ rec.next += rec.delay
26
+ clearTimeout(rec.timer)
27
+ if (wait > 0) {
28
+ api.log('delaying', ip, 'for', Math.round(wait / 1000))
29
ctx.set('x-anti-brute-force', wait)
30
+ await new Promise(resolve => setTimeout(resolve, wait))
31
}
27
- const delay = Math.min(CAP, (rec?.delay || 0) + INCREMENT)
28
- byIp[k] = { delay, when: now + delay }
29
- setTimeout(() => delete byIp[k], delay * 10) // no memory leak
32
+ rec.timer = setTimeout(() => delete byIp[ip], rec.delay * 10) // no memory leak
33
}
31
- })
34
+ }
35
}
33
-