ac-ratelimiter 2.0.6 → 2.0.8
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/.github/CODEOWNERS +9 -0
- package/.github/workflows/node.js.yml +6 -3
- package/CHANGELOG.md +18 -0
- package/Makefile +2 -2
- package/SECURITY.md +22 -0
- package/index.js +19 -19
- package/package.json +11 -8
- package/test/test.js +1 -3
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Code Owners
|
|
2
|
+
#
|
|
3
|
+
# This file defines who is responsible for code in this repository.
|
|
4
|
+
# Reviews from code owners are automatically requested for pull requests.
|
|
5
|
+
#
|
|
6
|
+
# More info: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners
|
|
7
|
+
|
|
8
|
+
# Default owner for everything in the repo
|
|
9
|
+
* @AdmiralCloud/ac-maintainer-backend
|
|
@@ -5,18 +5,21 @@ name: Node.js CI
|
|
|
5
5
|
|
|
6
6
|
on:
|
|
7
7
|
push:
|
|
8
|
-
branches: [ master
|
|
8
|
+
branches: [ master ]
|
|
9
9
|
pull_request:
|
|
10
|
-
branches: [ master
|
|
10
|
+
branches: [ master ]
|
|
11
11
|
|
|
12
12
|
jobs:
|
|
13
13
|
build:
|
|
14
14
|
|
|
15
|
+
permissions:
|
|
16
|
+
contents: read
|
|
17
|
+
|
|
15
18
|
runs-on: ubuntu-latest
|
|
16
19
|
|
|
17
20
|
strategy:
|
|
18
21
|
matrix:
|
|
19
|
-
node-version: [
|
|
22
|
+
node-version: [20.x, 22.x]
|
|
20
23
|
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
|
21
24
|
redis-version: [6]
|
|
22
25
|
|
package/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,22 @@
|
|
|
1
1
|
|
|
2
|
+
## [2.0.8](https://github.com/admiralcloud/ac-ratelimiter/compare/v2.0.7..v2.0.8) (2026-02-24 18:53:30)
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
### Bug Fix
|
|
6
|
+
|
|
7
|
+
* **Misc:** Package updates | MP | [2c1f50da711acab29e7e5c18c19a3be427c33100](https://github.com/admiralcloud/ac-ratelimiter/commit/2c1f50da711acab29e7e5c18c19a3be427c33100)
|
|
8
|
+
Package updates incl ESLint 9 -> 10 and lint fixes
|
|
9
|
+
Related issues:
|
|
10
|
+
|
|
11
|
+
## [2.0.7](https://github.com/admiralcloud/ac-ratelimiter/compare/v2.0.6..v2.0.7) (2026-02-03 08:30:54)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Bug Fix
|
|
15
|
+
|
|
16
|
+
* **Limiter:** Package updates | MP | [a4259bd5791eacaf62347bdb24029b67aa956647](https://github.com/admiralcloud/ac-ratelimiter/commit/a4259bd5791eacaf62347bdb24029b67aa956647)
|
|
17
|
+
Package updates
|
|
18
|
+
Related issues:
|
|
19
|
+
|
|
2
20
|
## [2.0.6](https://github.com/admiralcloud/ac-ratelimiter/compare/v2.0.5..v2.0.6) (2025-09-19 05:24:50)
|
|
3
21
|
|
|
4
22
|
|
package/Makefile
CHANGED
|
@@ -2,10 +2,10 @@ MOCHA_OPTS= --slow 0 -A
|
|
|
2
2
|
REPORTER = spec
|
|
3
3
|
|
|
4
4
|
lint-fix:
|
|
5
|
-
./node_modules/.bin/eslint --fix
|
|
5
|
+
./node_modules/.bin/eslint --fix
|
|
6
6
|
|
|
7
7
|
lint-check:
|
|
8
|
-
./node_modules/.bin/eslint
|
|
8
|
+
./node_modules/.bin/eslint
|
|
9
9
|
|
|
10
10
|
commit:
|
|
11
11
|
@node ./node_modules/ac-semantic-release/lib/commit.js
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Supported Versions
|
|
4
|
+
|
|
5
|
+
We only provide security updates for the latest version of this project.
|
|
6
|
+
|
|
7
|
+
If you are using an older version, please upgrade to the latest release to receive security fixes.
|
|
8
|
+
|
|
9
|
+
## Reporting a Vulnerability
|
|
10
|
+
|
|
11
|
+
If you discover a security vulnerability, please report it by creating a GitHub issue in this repository.
|
|
12
|
+
|
|
13
|
+
Please include the following information:
|
|
14
|
+
|
|
15
|
+
- Description of the vulnerability
|
|
16
|
+
- Steps to reproduce the issue
|
|
17
|
+
- Potential impact
|
|
18
|
+
- Any suggested fixes (if you have them)
|
|
19
|
+
|
|
20
|
+
We will review your report and respond as soon as possible.
|
|
21
|
+
|
|
22
|
+
Thank you for helping keep AdmiralCloud and our users safe!
|
package/index.js
CHANGED
|
@@ -34,14 +34,14 @@ class RateLimiter {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
whichStorage() {
|
|
37
|
-
if (this.redisInstance) return 'Redis'
|
|
38
|
-
else return 'NodeCache'
|
|
37
|
+
if (this.redisInstance) { return 'Redis' }
|
|
38
|
+
else { return 'NodeCache' }
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
// private
|
|
42
42
|
prepareRedisKey({ ip, controller = 'controller', action = 'action', clientId = 'clientId', identifier = 'identifier', redisKey }) {
|
|
43
43
|
let rateLimiterKey = redisKey || (this.environment + ':rateLimiter:' + clientId + ':' + ip + ':' + controller + ':' + action)
|
|
44
|
-
if (identifier) rateLimiterKey += ':' + identifier
|
|
44
|
+
if (identifier) { rateLimiterKey += ':' + identifier }
|
|
45
45
|
return rateLimiterKey
|
|
46
46
|
}
|
|
47
47
|
|
|
@@ -60,7 +60,7 @@ class RateLimiter {
|
|
|
60
60
|
rateLimitCounter
|
|
61
61
|
}) {
|
|
62
62
|
|
|
63
|
-
if (this.ignorePrivateIps && acts.isSpecialIP(ip)) return
|
|
63
|
+
if (this.ignorePrivateIps && acts.isSpecialIP(ip)) { return }
|
|
64
64
|
|
|
65
65
|
const logIdentifier = typeof identifier === 'string' && identifier.replace(/(\w{1,4})-(\w{1,4})/g, 'xxxx')
|
|
66
66
|
const knownIP = this.knownIPs.find(({ knownIP }) => knownIP === ip)
|
|
@@ -81,21 +81,21 @@ class RateLimiter {
|
|
|
81
81
|
|
|
82
82
|
const rateLogger = ({ type, rateLimitCounter, currentLimit }) => {
|
|
83
83
|
this.logger.warn('-'.repeat(80))
|
|
84
|
-
if (debugMode) this.logger.warn('DEBUG MODE - DEBUG MODE - DEBUG MODE')
|
|
84
|
+
if (debugMode) { this.logger.warn('DEBUG MODE - DEBUG MODE - DEBUG MODE') }
|
|
85
85
|
this.logger.warn('%s | %s | %s | %s | Counter %s/%s', 'ACRateLimiter'.padEnd(15), type.padEnd(12), currentRoute.padEnd(32), (ip + ' ' + (knownIP?.name || '')).padEnd(16), rateLimitCounter, currentLimit)
|
|
86
|
-
if (logIdentifier) this.logger.warn('%s | Identifier: %s', ' '.padEnd(15), logIdentifier)
|
|
86
|
+
if (logIdentifier) { this.logger.warn('%s | Identifier: %s', ' '.padEnd(15), logIdentifier) }
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
let settings = this.routes.find(item => {
|
|
90
|
-
if (ip && clientId && currentRoute && item.ip === ip && item.clientId === clientId && item.route === currentRoute ) return item
|
|
91
|
-
else if (ip && currentRoute && item.ip === ip && item.route === currentRoute && !item.clientId ) return item
|
|
92
|
-
else if (clientId && currentRoute && item.clientId === clientId && item.route === currentRoute && !item.ip) return item
|
|
93
|
-
else if (currentRoute && item.route === currentRoute && !item.clientId && !item.ip) return item
|
|
90
|
+
if (ip && clientId && currentRoute && item.ip === ip && item.clientId === clientId && item.route === currentRoute ) { return item }
|
|
91
|
+
else if (ip && currentRoute && item.ip === ip && item.route === currentRoute && !item.clientId ) { return item }
|
|
92
|
+
else if (clientId && currentRoute && item.clientId === clientId && item.route === currentRoute && !item.ip) { return item }
|
|
93
|
+
else if (currentRoute && item.route === currentRoute && !item.clientId && !item.ip) { return item }
|
|
94
94
|
})
|
|
95
95
|
if (!settings) {
|
|
96
96
|
// check fallback route
|
|
97
97
|
settings = this.routes.find(item => {
|
|
98
|
-
if (item.route === fallbackRoute && !item.clientId && !item.ip) return item
|
|
98
|
+
if (item.route === fallbackRoute && !item.clientId && !item.ip) { return item }
|
|
99
99
|
})
|
|
100
100
|
}
|
|
101
101
|
|
|
@@ -110,8 +110,8 @@ class RateLimiter {
|
|
|
110
110
|
props.forEach(prop => {
|
|
111
111
|
if (!Number.isFinite(current[prop])) {
|
|
112
112
|
// use from setting
|
|
113
|
-
if (Number.isFinite(settings?.[prop])) current[prop] = settings[prop]
|
|
114
|
-
else current[prop] = this.limits[prop]
|
|
113
|
+
if (Number.isFinite(settings?.[prop])) { current[prop] = settings[prop] }
|
|
114
|
+
else { current[prop] = this.limits[prop] }
|
|
115
115
|
}
|
|
116
116
|
})
|
|
117
117
|
|
|
@@ -143,7 +143,7 @@ class RateLimiter {
|
|
|
143
143
|
}
|
|
144
144
|
|
|
145
145
|
if (debugMode) {
|
|
146
|
-
console.
|
|
146
|
+
console.warn('Route %s | Current Counter %s | Throttle %s | Limit %s | Delay %s | Expires %s', currentRoute, rateLimitCounter, current.throttleLimit, current.limit, current.delay, current.expires)
|
|
147
147
|
}
|
|
148
148
|
|
|
149
149
|
if (rateLimitCounter > current.limit) {
|
|
@@ -159,7 +159,7 @@ class RateLimiter {
|
|
|
159
159
|
rateLogger({ type: 'Final Throttling', rateLimitCounter, currentLimit: current.limit })
|
|
160
160
|
await setTimeout(current.expires * 1000)
|
|
161
161
|
// do not "taint" process time when deliberately throttline
|
|
162
|
-
if (req._startTime) req._startTime += current.expires * 1000
|
|
162
|
+
if (req._startTime) { req._startTime += current.expires * 1000 }
|
|
163
163
|
throw new ACError('finalThrottlingActive_requestsIsDelayed', 900, { counter: rateLimitCounter, expires: current.expires })
|
|
164
164
|
}
|
|
165
165
|
else if (current.throttleLimit && rateLimitCounter > current.throttleLimit) {
|
|
@@ -169,15 +169,15 @@ class RateLimiter {
|
|
|
169
169
|
}
|
|
170
170
|
await setTimeout(current.delay)
|
|
171
171
|
// do not "taint" process time when deliberately throttline
|
|
172
|
-
if (req._startTime) req._startTime += current.delay
|
|
172
|
+
if (req._startTime) { req._startTime += current.delay }
|
|
173
173
|
throw new ACError('throttlingActive_requestsIsDelayed', 900, { counter: rateLimitCounter, expires: current.expires })
|
|
174
174
|
}
|
|
175
175
|
}
|
|
176
176
|
|
|
177
177
|
async updateLimiter({ routes, knownIPs, ignorePrivateIps }) {
|
|
178
|
-
if (Array.isArray(routes)) this.routes = routes
|
|
179
|
-
if (Array.isArray(knownIPs)) this.knownIPs = knownIPs
|
|
180
|
-
if (typeof ignorePrivateIps === 'boolean') this.ignorePrivateIps = ignorePrivateIps
|
|
178
|
+
if (Array.isArray(routes)) { this.routes = routes }
|
|
179
|
+
if (Array.isArray(knownIPs)) { this.knownIPs = knownIPs }
|
|
180
|
+
if (typeof ignorePrivateIps === 'boolean') { this.ignorePrivateIps = ignorePrivateIps }
|
|
181
181
|
}
|
|
182
182
|
|
|
183
183
|
async resetLimiter() {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ac-ratelimiter",
|
|
3
3
|
"description": "Simple ratelimiter for express",
|
|
4
|
-
"version": "2.0.
|
|
4
|
+
"version": "2.0.8",
|
|
5
5
|
"author": "Mark Poepping (www.admiralcloud.com)",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -9,16 +9,17 @@
|
|
|
9
9
|
},
|
|
10
10
|
"homepage": "https://www.admiralcloud.com",
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"ac-custom-error": "^
|
|
13
|
-
"ac-ip": "^4.1.
|
|
12
|
+
"ac-custom-error": "^2.0.1",
|
|
13
|
+
"ac-ip": "^4.1.10",
|
|
14
14
|
"node-cache": "^5.1.2"
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
17
|
-
"ac-semantic-release": "^0.4.
|
|
17
|
+
"ac-semantic-release": "^0.4.10",
|
|
18
18
|
"chai": "^4.5.0",
|
|
19
|
-
"eslint": "
|
|
20
|
-
"
|
|
21
|
-
"
|
|
19
|
+
"eslint": "10.0.2",
|
|
20
|
+
"globals": "^17.3.0",
|
|
21
|
+
"ioredis": "^5.9.3",
|
|
22
|
+
"mocha": "^11.7.5"
|
|
22
23
|
},
|
|
23
24
|
"scripts": {
|
|
24
25
|
"test": "./node_modules/.bin/mocha --slow 1000 --colors --bail ./test/test.js || :",
|
|
@@ -29,7 +30,9 @@
|
|
|
29
30
|
"node": ">=18.0.0"
|
|
30
31
|
},
|
|
31
32
|
"resolutions": {
|
|
32
|
-
"mocha/chokidar/braces": "^3.0.3"
|
|
33
|
+
"mocha/chokidar/braces": "^3.0.3",
|
|
34
|
+
"mocha/diff": "^8.0.3",
|
|
35
|
+
"minimatch": "^10.2.1"
|
|
33
36
|
},
|
|
34
37
|
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
|
|
35
38
|
}
|
package/test/test.js
CHANGED
|
@@ -45,7 +45,6 @@ describe('Use NodeCache', () => {
|
|
|
45
45
|
await ratelimiter.limiter(req, options)
|
|
46
46
|
}
|
|
47
47
|
catch(e) {
|
|
48
|
-
console.log(45, e)
|
|
49
48
|
expect(e).to.have.property('message', 'finalThrottlingActive_requestsIsDelayed')
|
|
50
49
|
expect(e).to.have.property('code', 900)
|
|
51
50
|
}
|
|
@@ -354,8 +353,7 @@ describe('Use Redis', () => {
|
|
|
354
353
|
it('should trigger immediately', async() => {
|
|
355
354
|
req.determinedIP = '4.1.4.1'
|
|
356
355
|
try {
|
|
357
|
-
|
|
358
|
-
console.log(304, x)
|
|
356
|
+
await ratelimiterRedis.limiter(req, options)
|
|
359
357
|
}
|
|
360
358
|
catch(e) {
|
|
361
359
|
expect(e).to.be.an('error')
|