@prosopo/user-access-policy 3.11.2 → 3.12.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/.turbo/turbo-build$colon$cjs.log +38 -37
- package/.turbo/turbo-build$colon$tsc.log +14 -14
- package/.turbo/turbo-build.log +39 -38
- package/CHANGELOG.md +30 -0
- package/dist/api/delete/deleteRules.d.ts +2 -2
- package/dist/api/delete/deleteRules.d.ts.map +1 -1
- package/dist/api/delete/deleteRules.js.map +1 -1
- package/dist/api/read/findRuleIds.d.ts +1 -1
- package/dist/api/read/findRuleIds.d.ts.map +1 -1
- package/dist/api/read/findRuleIds.js.map +1 -1
- package/dist/cjs/redis/reader/redisRulesQuery.cjs +3 -2
- package/dist/cjs/redis/reader/redisRulesReader.cjs +101 -1
- package/dist/cjs/redis/reader/redisRulesSplitQuery.cjs +78 -0
- package/dist/cjs/redis/redisRuleIndex.cjs +3 -1
- package/dist/cjs/redis/redisRulesWriter.cjs +17 -6
- package/dist/cjs/rule.cjs +2 -0
- package/dist/cjs/ruleInput/policyInput.cjs +9 -1
- package/dist/redis/reader/redisRulesQuery.d.ts.map +1 -1
- package/dist/redis/reader/redisRulesQuery.js +4 -3
- package/dist/redis/reader/redisRulesQuery.js.map +1 -1
- package/dist/redis/reader/redisRulesReader.d.ts +1 -0
- package/dist/redis/reader/redisRulesReader.d.ts.map +1 -1
- package/dist/redis/reader/redisRulesReader.js +101 -1
- package/dist/redis/reader/redisRulesReader.js.map +1 -1
- package/dist/redis/reader/redisRulesSplitQuery.d.ts +8 -0
- package/dist/redis/reader/redisRulesSplitQuery.d.ts.map +1 -0
- package/dist/redis/reader/redisRulesSplitQuery.js +78 -0
- package/dist/redis/reader/redisRulesSplitQuery.js.map +1 -0
- package/dist/redis/redisRuleIndex.d.ts +1 -0
- package/dist/redis/redisRuleIndex.d.ts.map +1 -1
- package/dist/redis/redisRuleIndex.js +2 -0
- package/dist/redis/redisRuleIndex.js.map +1 -1
- package/dist/redis/redisRulesWriter.d.ts +1 -1
- package/dist/redis/redisRulesWriter.d.ts.map +1 -1
- package/dist/redis/redisRulesWriter.js +14 -3
- package/dist/redis/redisRulesWriter.js.map +1 -1
- package/dist/rule.d.ts +1 -0
- package/dist/rule.d.ts.map +1 -1
- package/dist/rule.js +3 -1
- package/dist/rule.js.map +1 -1
- package/dist/ruleInput/policyInput.d.ts +2 -2
- package/dist/ruleInput/policyInput.d.ts.map +1 -1
- package/dist/ruleInput/policyInput.js +10 -2
- package/dist/ruleInput/policyInput.js.map +1 -1
- package/dist/ruleInput/ruleInput.d.ts +6 -6
- package/dist/ruleInput/ruleInput.d.ts.map +1 -1
- package/dist/ruleInput/ruleInput.js.map +1 -1
- package/dist/tests/redis/reader/redisRulesSplitQuery.unit.test.d.ts +2 -0
- package/dist/tests/redis/reader/redisRulesSplitQuery.unit.test.d.ts.map +1 -0
- package/dist/tests/redis/reader/redisRulesSplitQuery.unit.test.js +79 -0
- package/dist/tests/redis/reader/redisRulesSplitQuery.unit.test.js.map +1 -0
- package/dist/tests/redis/redisRulesReaderLoad.benchmark.integration.test.d.ts +2 -0
- package/dist/tests/redis/redisRulesReaderLoad.benchmark.integration.test.d.ts.map +1 -0
- package/dist/tests/redis/redisRulesReaderLoad.benchmark.integration.test.js +288 -0
- package/dist/tests/redis/redisRulesReaderLoad.benchmark.integration.test.js.map +1 -0
- package/package.json +3 -3
- package/src/api/delete/deleteRules.ts +7 -1
- package/src/api/read/findRuleIds.ts +3 -1
- package/src/redis/reader/redisRulesQuery.ts +12 -2
- package/src/redis/reader/redisRulesReader.ts +145 -7
- package/src/redis/reader/redisRulesSplitQuery.ts +170 -0
- package/src/redis/redisRuleIndex.ts +6 -0
- package/src/redis/redisRulesWriter.ts +19 -5
- package/src/rule.ts +12 -0
- package/src/ruleInput/policyInput.ts +17 -3
- package/src/ruleInput/ruleInput.ts +7 -1
- package/src/tests/redis/reader/redisRulesSplitQuery.unit.test.ts +132 -0
- package/src/tests/redis/redisRulesReaderLoad.benchmark.integration.test.ts +516 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @prosopo/user-access-policy@3.
|
|
2
|
+
> @prosopo/user-access-policy@3.12.0 build:cjs
|
|
3
3
|
> NODE_ENV=${NODE_ENV:-development}; vite build --config vite.cjs.config.ts --mode $NODE_ENV
|
|
4
4
|
|
|
5
5
|
ViteCommonJSConfig: .
|
|
@@ -33,40 +33,41 @@ ViteCommonJSConfig: .
|
|
|
33
33
|
Bundle build started
|
|
34
34
|
transforming...
|
|
35
35
|
Build end
|
|
36
|
-
[32m✓[39m
|
|
36
|
+
[32m✓[39m 35 modules transformed.
|
|
37
37
|
rendering chunks...
|
|
38
|
-
[2mdist/cjs/[22m[36mapi/delete/.export.cjs
|
|
39
|
-
[2mdist/cjs/[22m[36mapi/read/.export.cjs
|
|
40
|
-
[2mdist/cjs/[22m[36mapi/write/.export.cjs
|
|
41
|
-
[2mdist/cjs/[22m[36mmongoose/.export.cjs
|
|
42
|
-
[2mdist/cjs/[22m[36mrulesStorage.cjs
|
|
43
|
-
[2mdist/cjs/[22m[
|
|
44
|
-
[2mdist/cjs/[22m[
|
|
45
|
-
[2mdist/cjs/[22m[36mruleInput/.export.cjs
|
|
46
|
-
[2mdist/cjs/[22m[36mapi/.export.cjs
|
|
47
|
-
[2mdist/cjs/[22m[36mclassifyOs.cjs
|
|
48
|
-
[2mdist/cjs/[22m[36mapi/delete/deleteAllRules.cjs
|
|
49
|
-
[2mdist/cjs/[22m[36mruleRecord.cjs
|
|
50
|
-
[2mdist/cjs/[22m[36mapi/read/getMissingIds.cjs
|
|
51
|
-
[2mdist/cjs/[22m[36mapi/read/fetchRules.cjs
|
|
52
|
-
[2mdist/cjs/[22m[36mredis/redisRulesStorage.cjs
|
|
53
|
-
[2mdist/cjs/[22m[36m.export.cjs
|
|
54
|
-
[2mdist/cjs/[22m[36mapi/delete/deleteRules.cjs
|
|
55
|
-
[2mdist/cjs/[22m[36mmongoose/mongooseRuleSchema.cjs
|
|
56
|
-
[2mdist/cjs/[22m[36mapi/delete/deleteRuleGroups.cjs
|
|
57
|
-
[2mdist/cjs/[22m[36mapi/write/rehashRules.cjs
|
|
58
|
-
[2mdist/cjs/[22m[36mapi/read/findRuleIds.cjs
|
|
59
|
-
[2mdist/cjs/[22m[
|
|
60
|
-
[2mdist/cjs/[22m[
|
|
61
|
-
[2mdist/cjs/[22m[36mruleInput/
|
|
62
|
-
[2mdist/cjs/[22m[
|
|
63
|
-
[2mdist/cjs/[22m[
|
|
64
|
-
[2mdist/cjs/[22m[
|
|
65
|
-
[2mdist/cjs/[22m[
|
|
66
|
-
[2mdist/cjs/[22m[36mtransformRule.cjs
|
|
67
|
-
[2mdist/cjs/[22m[
|
|
68
|
-
[2mdist/cjs/[22m[
|
|
69
|
-
[2mdist/cjs/[22m[36mredis/
|
|
70
|
-
[2mdist/cjs/[22m[36mapi/ruleApiRoutes.cjs
|
|
71
|
-
[2mdist/cjs/[22m[36mredis/reader/
|
|
72
|
-
[
|
|
38
|
+
[2mdist/cjs/[22m[36mapi/delete/.export.cjs [39m[1m[2m 0.01 kB[22m[1m[22m
|
|
39
|
+
[2mdist/cjs/[22m[36mapi/read/.export.cjs [39m[1m[2m 0.01 kB[22m[1m[22m
|
|
40
|
+
[2mdist/cjs/[22m[36mapi/write/.export.cjs [39m[1m[2m 0.01 kB[22m[1m[22m
|
|
41
|
+
[2mdist/cjs/[22m[36mmongoose/.export.cjs [39m[1m[2m 0.23 kB[22m[1m[22m
|
|
42
|
+
[2mdist/cjs/[22m[36mrulesStorage.cjs [39m[1m[2m 0.34 kB[22m[1m[22m
|
|
43
|
+
[2mdist/cjs/[22m[36mredis/.export.cjs [39m[1m[2m 0.36 kB[22m[1m[22m
|
|
44
|
+
[2mdist/cjs/[22m[36mrule.cjs [39m[1m[2m 0.46 kB[22m[1m[22m
|
|
45
|
+
[2mdist/cjs/[22m[36mruleInput/.export.cjs [39m[1m[2m 0.46 kB[22m[1m[22m
|
|
46
|
+
[2mdist/cjs/[22m[36mapi/.export.cjs [39m[1m[2m 0.57 kB[22m[1m[22m
|
|
47
|
+
[2mdist/cjs/[22m[36mclassifyOs.cjs [39m[1m[2m 0.62 kB[22m[1m[22m
|
|
48
|
+
[2mdist/cjs/[22m[36mapi/delete/deleteAllRules.cjs [39m[1m[2m 0.77 kB[22m[1m[22m
|
|
49
|
+
[2mdist/cjs/[22m[36mruleRecord.cjs [39m[1m[2m 0.84 kB[22m[1m[22m
|
|
50
|
+
[2mdist/cjs/[22m[36mapi/read/getMissingIds.cjs [39m[1m[2m 1.15 kB[22m[1m[22m
|
|
51
|
+
[2mdist/cjs/[22m[36mapi/read/fetchRules.cjs [39m[1m[2m 1.22 kB[22m[1m[22m
|
|
52
|
+
[2mdist/cjs/[22m[36mredis/redisRulesStorage.cjs [39m[1m[2m 1.35 kB[22m[1m[22m
|
|
53
|
+
[2mdist/cjs/[22m[36m.export.cjs [39m[1m[2m 1.37 kB[22m[1m[22m
|
|
54
|
+
[2mdist/cjs/[22m[36mapi/delete/deleteRules.cjs [39m[1m[2m 1.51 kB[22m[1m[22m
|
|
55
|
+
[2mdist/cjs/[22m[36mmongoose/mongooseRuleSchema.cjs [39m[1m[2m 1.52 kB[22m[1m[22m
|
|
56
|
+
[2mdist/cjs/[22m[36mapi/delete/deleteRuleGroups.cjs [39m[1m[2m 1.57 kB[22m[1m[22m
|
|
57
|
+
[2mdist/cjs/[22m[36mapi/write/rehashRules.cjs [39m[1m[2m 1.64 kB[22m[1m[22m
|
|
58
|
+
[2mdist/cjs/[22m[36mapi/read/findRuleIds.cjs [39m[1m[2m 1.65 kB[22m[1m[22m
|
|
59
|
+
[2mdist/cjs/[22m[36mredis/redisClient.cjs [39m[1m[2m 2.09 kB[22m[1m[22m
|
|
60
|
+
[2mdist/cjs/[22m[36mruleInput/ruleInput.cjs [39m[1m[2m 2.11 kB[22m[1m[22m
|
|
61
|
+
[2mdist/cjs/[22m[36mruleInput/policyInput.cjs [39m[1m[2m 2.14 kB[22m[1m[22m
|
|
62
|
+
[2mdist/cjs/[22m[36mredis/reader/redisRulesSplitQuery.cjs [39m[1m[2m 2.43 kB[22m[1m[22m
|
|
63
|
+
[2mdist/cjs/[22m[36mapi/rulesApiClient.cjs [39m[1m[2m 2.60 kB[22m[1m[22m
|
|
64
|
+
[2mdist/cjs/[22m[36mredis/reader/redisAggregate.cjs [39m[1m[2m 2.61 kB[22m[1m[22m
|
|
65
|
+
[2mdist/cjs/[22m[36mruleInput/userScopeInput.cjs [39m[1m[2m 2.67 kB[22m[1m[22m
|
|
66
|
+
[2mdist/cjs/[22m[36mtransformRule.cjs [39m[1m[2m 3.05 kB[22m[1m[22m
|
|
67
|
+
[2mdist/cjs/[22m[36mredis/redisRuleIndex.cjs [39m[1m[2m 3.07 kB[22m[1m[22m
|
|
68
|
+
[2mdist/cjs/[22m[36mapi/write/insertRules.cjs [39m[1m[2m 3.38 kB[22m[1m[22m
|
|
69
|
+
[2mdist/cjs/[22m[36mredis/redisRulesWriter.cjs [39m[1m[2m 3.68 kB[22m[1m[22m
|
|
70
|
+
[2mdist/cjs/[22m[36mapi/ruleApiRoutes.cjs [39m[1m[2m 4.55 kB[22m[1m[22m
|
|
71
|
+
[2mdist/cjs/[22m[36mredis/reader/redisRulesQuery.cjs [39m[1m[2m 4.60 kB[22m[1m[22m
|
|
72
|
+
[2mdist/cjs/[22m[36mredis/reader/redisRulesReader.cjs [39m[1m[2m15.32 kB[22m[1m[22m
|
|
73
|
+
[32m✓ built in 540ms[39m
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
|
|
2
|
-
> @prosopo/user-access-policy@3.
|
|
2
|
+
> @prosopo/user-access-policy@3.12.0 build:tsc
|
|
3
3
|
> tsc --build --verbose
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
11:41:51 AM - Projects in this build:
|
|
6
6
|
* ../../dev/config/tsconfig.json
|
|
7
7
|
* ../locale/tsconfig.json
|
|
8
8
|
* ../util/tsconfig.json
|
|
@@ -15,27 +15,27 @@
|
|
|
15
15
|
* ../api/tsconfig.json
|
|
16
16
|
* tsconfig.json
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
11:41:52 AM - Project '../../dev/config/tsconfig.json' is up to date because newest input '../../dev/config/src/vite/NodejsPolarsNativeFilePlugin.ts' is older than output '../../dev/config/tsconfig.tsbuildinfo'
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
11:41:52 AM - Project '../locale/tsconfig.json' is up to date because newest input '../locale/src/useTranslation.ts' is older than output '../locale/tsconfig.tsbuildinfo'
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
11:41:52 AM - Project '../util/tsconfig.json' is up to date because newest input '../util/src/url.ts' is older than output '../util/tsconfig.tsbuildinfo'
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
11:41:52 AM - Project '../logger/tsconfig.json' is up to date because newest input '../logger/src/index.ts' is older than output '../logger/tsconfig.tsbuildinfo'
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
11:41:52 AM - Project '../util-crypto/tsconfig.json' is up to date because newest input '../util-crypto/src/types.ts' is older than output '../util-crypto/tsconfig.tsbuildinfo'
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
11:41:52 AM - Project '../types/tsconfig.json' is up to date because newest input '../types/src/provider/api.ts' is older than output '../types/tsconfig.tsbuildinfo'
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
11:41:52 AM - Project '../common/tsconfig.json' is up to date because newest input '../common/src/index.ts' is older than output '../common/tsconfig.tsbuildinfo'
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
11:41:52 AM - Project '../api-route/tsconfig.json' is up to date because newest input '../api-route/src/apiRoutes.ts' is older than output '../api-route/tsconfig.tsbuildinfo'
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
11:41:52 AM - Project '../redis-client/tsconfig.json' is up to date because newest input '../redis-client/src/index.ts' is older than output '../redis-client/tsconfig.tsbuildinfo'
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
11:41:52 AM - Project '../api/tsconfig.json' is up to date because newest input '../api/src/index.ts' is older than output '../api/tsconfig.tsbuildinfo'
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
11:41:52 AM - Project 'tsconfig.json' is out of date because output file 'tsconfig.tsbuildinfo' does not exist
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
11:41:52 AM - Building project '/home/runner/work/captcha/captcha/packages/user-access-policy/tsconfig.json'...
|
|
41
41
|
|
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
|
|
2
|
-
> @prosopo/user-access-policy@3.
|
|
2
|
+
> @prosopo/user-access-policy@3.12.0 build
|
|
3
3
|
> npm run build:cross-env -- --mode ${NODE_ENV:-development}
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
> @prosopo/user-access-policy@3.
|
|
6
|
+
> @prosopo/user-access-policy@3.12.0 build:cross-env
|
|
7
7
|
> vite build --config vite.esm.config.ts --mode production
|
|
8
8
|
|
|
9
9
|
ViteEsmConfig: .
|
|
@@ -37,40 +37,41 @@ ViteEsmConfig: .
|
|
|
37
37
|
Bundle build started
|
|
38
38
|
transforming...
|
|
39
39
|
Build end
|
|
40
|
-
[32m✓[39m
|
|
40
|
+
[32m✓[39m 35 modules transformed.
|
|
41
41
|
rendering chunks...
|
|
42
|
-
[2mdist/[22m[36mapi/delete/.export.js
|
|
43
|
-
[2mdist/[22m[36mapi/read/.export.js
|
|
44
|
-
[2mdist/[22m[36mapi/write/.export.js
|
|
45
|
-
[2mdist/[22m[36mmongoose/.export.js
|
|
46
|
-
[2mdist/[22m[36mredis/.export.js
|
|
47
|
-
[2mdist/[22m[36mrulesStorage.js
|
|
48
|
-
[2mdist/[22m[
|
|
49
|
-
[2mdist/[22m[
|
|
50
|
-
[2mdist/[22m[36mapi/.export.js
|
|
51
|
-
[2mdist/[22m[36mclassifyOs.js
|
|
52
|
-
[2mdist/[22m[36mruleRecord.js
|
|
53
|
-
[2mdist/[22m[36mapi/delete/deleteAllRules.js
|
|
54
|
-
[2mdist/[22m[36m.export.js
|
|
55
|
-
[2mdist/[22m[36mapi/read/getMissingIds.js
|
|
56
|
-
[2mdist/[22m[36mapi/read/fetchRules.js
|
|
57
|
-
[2mdist/[22m[36mredis/redisRulesStorage.js
|
|
58
|
-
[2mdist/[22m[36mmongoose/mongooseRuleSchema.js
|
|
59
|
-
[2mdist/[22m[36mapi/delete/deleteRules.js
|
|
60
|
-
[2mdist/[22m[36mapi/delete/deleteRuleGroups.js
|
|
61
|
-
[2mdist/[22m[
|
|
62
|
-
[2mdist/[22m[36mapi/
|
|
63
|
-
[2mdist/[22m[
|
|
64
|
-
[2mdist/[22m[
|
|
65
|
-
[2mdist/[22m[
|
|
66
|
-
[2mdist/[22m[
|
|
67
|
-
[2mdist/[22m[
|
|
68
|
-
[2mdist/[22m[
|
|
69
|
-
[2mdist/[22m[36mredis/
|
|
70
|
-
[2mdist/[22m[
|
|
71
|
-
[2mdist/[22m[
|
|
72
|
-
[2mdist/[22m[
|
|
73
|
-
[2mdist/[22m[36mredis/
|
|
74
|
-
[2mdist/[22m[36mapi/ruleApiRoutes.js
|
|
75
|
-
[2mdist/[22m[36mredis/reader/
|
|
76
|
-
[
|
|
42
|
+
[2mdist/[22m[36mapi/delete/.export.js [39m[1m[2m 0.00 kB[22m[1m[22m
|
|
43
|
+
[2mdist/[22m[36mapi/read/.export.js [39m[1m[2m 0.00 kB[22m[1m[22m
|
|
44
|
+
[2mdist/[22m[36mapi/write/.export.js [39m[1m[2m 0.00 kB[22m[1m[22m
|
|
45
|
+
[2mdist/[22m[36mmongoose/.export.js [39m[1m[2m 0.11 kB[22m[1m[22m
|
|
46
|
+
[2mdist/[22m[36mredis/.export.js [39m[1m[2m 0.20 kB[22m[1m[22m
|
|
47
|
+
[2mdist/[22m[36mrulesStorage.js [39m[1m[2m 0.23 kB[22m[1m[22m
|
|
48
|
+
[2mdist/[22m[36mruleInput/.export.js [39m[1m[2m 0.27 kB[22m[1m[22m
|
|
49
|
+
[2mdist/[22m[36mrule.js [39m[1m[2m 0.32 kB[22m[1m[22m
|
|
50
|
+
[2mdist/[22m[36mapi/.export.js [39m[1m[2m 0.37 kB[22m[1m[22m
|
|
51
|
+
[2mdist/[22m[36mclassifyOs.js [39m[1m[2m 0.51 kB[22m[1m[22m
|
|
52
|
+
[2mdist/[22m[36mruleRecord.js [39m[1m[2m 0.62 kB[22m[1m[22m
|
|
53
|
+
[2mdist/[22m[36mapi/delete/deleteAllRules.js [39m[1m[2m 0.67 kB[22m[1m[22m
|
|
54
|
+
[2mdist/[22m[36m.export.js [39m[1m[2m 0.93 kB[22m[1m[22m
|
|
55
|
+
[2mdist/[22m[36mapi/read/getMissingIds.js [39m[1m[2m 1.01 kB[22m[1m[22m
|
|
56
|
+
[2mdist/[22m[36mapi/read/fetchRules.js [39m[1m[2m 1.08 kB[22m[1m[22m
|
|
57
|
+
[2mdist/[22m[36mredis/redisRulesStorage.js [39m[1m[2m 1.21 kB[22m[1m[22m
|
|
58
|
+
[2mdist/[22m[36mmongoose/mongooseRuleSchema.js [39m[1m[2m 1.41 kB[22m[1m[22m
|
|
59
|
+
[2mdist/[22m[36mapi/delete/deleteRules.js [39m[1m[2m 1.44 kB[22m[1m[22m
|
|
60
|
+
[2mdist/[22m[36mapi/delete/deleteRuleGroups.js [39m[1m[2m 1.44 kB[22m[1m[22m
|
|
61
|
+
[2mdist/[22m[36mapi/read/findRuleIds.js [39m[1m[2m 1.54 kB[22m[1m[22m
|
|
62
|
+
[2mdist/[22m[36mapi/write/rehashRules.js [39m[1m[2m 1.54 kB[22m[1m[22m
|
|
63
|
+
[2mdist/[22m[36mruleInput/ruleInput.js [39m[1m[2m 1.76 kB[22m[1m[22m
|
|
64
|
+
[2mdist/[22m[36mredis/redisClient.js [39m[1m[2m 1.90 kB[22m[1m[22m
|
|
65
|
+
[2mdist/[22m[36mruleInput/policyInput.js [39m[1m[2m 1.96 kB[22m[1m[22m
|
|
66
|
+
[2mdist/[22m[36mredis/reader/redisRulesSplitQuery.js [39m[1m[2m 2.35 kB[22m[1m[22m
|
|
67
|
+
[2mdist/[22m[36mapi/rulesApiClient.js [39m[1m[2m 2.36 kB[22m[1m[22m
|
|
68
|
+
[2mdist/[22m[36mruleInput/userScopeInput.js [39m[1m[2m 2.44 kB[22m[1m[22m
|
|
69
|
+
[2mdist/[22m[36mredis/reader/redisAggregate.js [39m[1m[2m 2.46 kB[22m[1m[22m
|
|
70
|
+
[2mdist/[22m[36mredis/redisRuleIndex.js [39m[1m[2m 2.58 kB[22m[1m[22m
|
|
71
|
+
[2mdist/[22m[36mtransformRule.js [39m[1m[2m 2.76 kB[22m[1m[22m
|
|
72
|
+
[2mdist/[22m[36mapi/write/insertRules.js [39m[1m[2m 3.22 kB[22m[1m[22m
|
|
73
|
+
[2mdist/[22m[36mredis/redisRulesWriter.js [39m[1m[2m 3.47 kB[22m[1m[22m
|
|
74
|
+
[2mdist/[22m[36mapi/ruleApiRoutes.js [39m[1m[2m 4.33 kB[22m[1m[22m
|
|
75
|
+
[2mdist/[22m[36mredis/reader/redisRulesQuery.js [39m[1m[2m 4.45 kB[22m[1m[22m
|
|
76
|
+
[2mdist/[22m[36mredis/reader/redisRulesReader.js [39m[1m[2m14.33 kB[22m[1m[22m
|
|
77
|
+
[32m✓ built in 569ms[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# @prosopo/user-access-policy
|
|
2
2
|
|
|
3
|
+
## 3.12.0
|
|
4
|
+
### Minor Changes
|
|
5
|
+
|
|
6
|
+
- 7d7e767: perf(access-rules): split-query hot path + verdict cache with LRU and singleflight
|
|
7
|
+
|
|
8
|
+
Reworks the block-lookup Redis path so per-request latency is bounded by matching-rules-per-request rather than total rules in the tenant. Rule populations in the 10k+ range no longer degrade tail latency.
|
|
9
|
+
|
|
10
|
+
Key changes:
|
|
11
|
+
|
|
12
|
+
- **Split-query read path**: `redisRulesSplitQuery.ts` builds one FT sub-query per populated request field (numericIp exact + CIDR, ja4Hash, userId, headHash, coords, countryCode, asn), each hitting a discriminating posting-list index instead of a single wide FT.AGGREGATE that scaled linearly in total rule count.
|
|
13
|
+
- **`clientId="global"` sentinel**: writer stamps the sentinel on rules with no clientId so queries probe `@clientId:{X|global|ismissing}` instead of the expensive `ismissing()` set-difference walk. Transition-safe — legacy rules match via the ismissing branch until a rehash migrates them.
|
|
14
|
+
- **HardBlockVerdictCache**: bounded LRU + TTL (10 s / 50k entries) with real LRU move-to-tail on hit and **singleflight `getOrCompute`** dedupe of concurrent misses — the wave-1 stampede fix for the frontend retry-loop shape.
|
|
15
|
+
- **Request-scoped memo**: attached to `req` so blockMiddleware + downstream in-request checks share one Redis round-trip.
|
|
16
|
+
|
|
17
|
+
Measured impact under 100-concurrent × 10-wave retry storm against a 19.3k-rule population: wave-1 p99 drops from 23 ms → 3 ms, throughput jumps from 28.5k → 61.5k req/s per process, 50 identical concurrent misses collapse to 1 storage call.
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- Updated dependencies [b3f351b]
|
|
22
|
+
- Updated dependencies [17bc76e]
|
|
23
|
+
- @prosopo/types@4.9.6
|
|
24
|
+
- @prosopo/api@3.5.13
|
|
25
|
+
|
|
26
|
+
## 3.11.3
|
|
27
|
+
### Patch Changes
|
|
28
|
+
|
|
29
|
+
- Updated dependencies [6cb3218]
|
|
30
|
+
- @prosopo/types@4.9.5
|
|
31
|
+
- @prosopo/api@3.5.12
|
|
32
|
+
|
|
3
33
|
## 3.11.2
|
|
4
34
|
### Patch Changes
|
|
5
35
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { type ApiEndpoint, type ApiEndpointResponse } from "@prosopo/api-route";
|
|
2
2
|
import type { Logger } from "@prosopo/logger";
|
|
3
|
-
import { type ZodType } from "zod";
|
|
3
|
+
import { type ZodType, z } from "zod";
|
|
4
4
|
import { type AccessRulesFilterInput } from "#policy/ruleInput/ruleInput.js";
|
|
5
5
|
import type { AccessRulesStorage } from "#policy/rulesStorage.js";
|
|
6
|
-
type DeleteRulesSchema = ZodType<AccessRulesFilterInput[]>;
|
|
6
|
+
type DeleteRulesSchema = ZodType<AccessRulesFilterInput[], z.ZodTypeDef, unknown>;
|
|
7
7
|
export declare class DeleteRulesEndpoint implements ApiEndpoint<DeleteRulesSchema> {
|
|
8
8
|
private readonly accessRulesStorage;
|
|
9
9
|
private readonly logger;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deleteRules.d.ts","sourceRoot":"","sources":["../../../src/api/delete/deleteRules.ts"],"names":[],"mappings":"AAcA,OAAO,EACN,KAAK,WAAW,EAChB,KAAK,mBAAmB,EAExB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,KAAK,OAAO,
|
|
1
|
+
{"version":3,"file":"deleteRules.d.ts","sourceRoot":"","sources":["../../../src/api/delete/deleteRules.ts"],"names":[],"mappings":"AAcA,OAAO,EACN,KAAK,WAAW,EAChB,KAAK,mBAAmB,EAExB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,KAAK,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACtC,OAAO,EACN,KAAK,sBAAsB,EAG3B,MAAM,gCAAgC,CAAC;AACxC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAIlE,KAAK,iBAAiB,GAAG,OAAO,CAC/B,sBAAsB,EAAE,EACxB,CAAC,CAAC,UAAU,EACZ,OAAO,CACP,CAAC;AAEF,qBAAa,mBAAoB,YAAW,WAAW,CAAC,iBAAiB,CAAC;IAExE,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IACnC,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,kBAAkB,EAAE,kBAAkB,EACtC,MAAM,EAAE,MAAM;IAGzB,oBAAoB,IAAI,iBAAiB;IAI1C,cAAc,CACnB,IAAI,EAAE,sBAAsB,EAAE,EAC9B,MAAM,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,mBAAmB,CAAC;CAoC/B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deleteRules.js","sourceRoot":"","sources":["../../../src/api/delete/deleteRules.ts"],"names":[],"mappings":"AAcA,OAAO,EAGN,yBAAyB,GACzB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,0BAA0B,EAAE,MAAM,iBAAiB,CAAC;AAE7D,OAAO,EAAgB,CAAC,EAAE,MAAM,KAAK,CAAC;AACtC,OAAO,EAEN,sBAAsB,EACtB,6BAA6B,GAC7B,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"deleteRules.js","sourceRoot":"","sources":["../../../src/api/delete/deleteRules.ts"],"names":[],"mappings":"AAcA,OAAO,EAGN,yBAAyB,GACzB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,0BAA0B,EAAE,MAAM,iBAAiB,CAAC;AAE7D,OAAO,EAAgB,CAAC,EAAE,MAAM,KAAK,CAAC;AACtC,OAAO,EAEN,sBAAsB,EACtB,6BAA6B,GAC7B,MAAM,gCAAgC,CAAC;AAWxC,MAAM,OAAO,mBAAmB;IAC/B,YACkB,kBAAsC,EACtC,MAAc;QADd,uBAAkB,GAAlB,kBAAkB,CAAoB;QACtC,WAAM,GAAN,MAAM,CAAQ;IAC7B,CAAC;IAEG,oBAAoB;QAC1B,OAAO,CAAC,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;IACxC,CAAC;IAED,KAAK,CAAC,cAAc,CACnB,IAA8B,EAC9B,MAAe;QAEf,MAAM,GAAG,GAAG,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC;QAClC,IAAI,YAAY,GAAG,CAAC,CAAC;QAErB,KAAK,MAAM,gBAAgB,IAAI,IAAI,EAAE,CAAC;YACrC,MAAM,WAAW,GAAG,6BAA6B,CAAC,gBAAgB,CAAC,CAAC;YAEpE,MAAM,0BAA0B,CAAC,WAAW,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE;gBAClE,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;gBAGtE,MAAM,aAAa,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;gBAE5C,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAC9B,MAAM,IAAI,CAAC,kBAAkB,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC;oBAEzD,YAAY,IAAI,aAAa,CAAC,MAAM,CAAC;oBAErC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;wBACf,GAAG,EAAE,wBAAwB;wBAC7B,IAAI,EAAE;4BACL,gBAAgB;4BAChB,aAAa;yBACb;qBACD,CAAC,CAAC,CAAC;gBACL,CAAC;YACF,CAAC,CAAC,CAAC;QACJ,CAAC;QAED,OAAO;YACN,MAAM,EAAE,yBAAyB,CAAC,OAAO;YACzC,IAAI,EAAE;gBACL,aAAa,EAAE,YAAY;aAC3B;SACD,CAAC;IACH,CAAC;CACD"}
|
|
@@ -3,7 +3,7 @@ import type { Logger } from "@prosopo/logger";
|
|
|
3
3
|
import { type ZodType, z } from "zod";
|
|
4
4
|
import { type AccessRulesFilterInput } from "#policy/ruleInput/ruleInput.js";
|
|
5
5
|
import type { AccessRulesStorage } from "#policy/rulesStorage.js";
|
|
6
|
-
type FindRulesSchema = ZodType<AccessRulesFilterInput[]>;
|
|
6
|
+
type FindRulesSchema = ZodType<AccessRulesFilterInput[], z.ZodTypeDef, unknown>;
|
|
7
7
|
export type RuleIdsResponse = {
|
|
8
8
|
ruleIds: string[];
|
|
9
9
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"findRuleIds.d.ts","sourceRoot":"","sources":["../../../src/api/read/findRuleIds.ts"],"names":[],"mappings":"AAcA,OAAO,EACN,KAAK,WAAW,EAChB,KAAK,mBAAmB,EAExB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,KAAK,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACtC,OAAO,EACN,KAAK,sBAAsB,EAG3B,MAAM,gCAAgC,CAAC;AACxC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"findRuleIds.d.ts","sourceRoot":"","sources":["../../../src/api/read/findRuleIds.ts"],"names":[],"mappings":"AAcA,OAAO,EACN,KAAK,WAAW,EAChB,KAAK,mBAAmB,EAExB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,KAAK,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACtC,OAAO,EACN,KAAK,sBAAsB,EAG3B,MAAM,gCAAgC,CAAC;AACxC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAIlE,KAAK,eAAe,GAAG,OAAO,CAAC,sBAAsB,EAAE,EAAE,CAAC,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;AAEhF,MAAM,MAAM,eAAe,GAAG;IAC7B,OAAO,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC;AAEF,eAAO,MAAM,eAAe;;;;;;EAE4C,CAAC;AAEzE,MAAM,MAAM,uBAAuB,GAAG,mBAAmB,GAAG;IAC3D,IAAI,CAAC,EAAE,eAAe,CAAC;CACvB,CAAC;AAEF,qBAAa,mBAAoB,YAAW,WAAW,CAAC,eAAe,CAAC;IAEtE,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IACnC,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,kBAAkB,EAAE,kBAAkB,EACtC,MAAM,EAAE,MAAM;IAGzB,oBAAoB,IAAI,eAAe;IAIxC,cAAc,CACnB,IAAI,EAAE,sBAAsB,EAAE,EAC9B,MAAM,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,uBAAuB,CAAC;CAsCnC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"findRuleIds.js","sourceRoot":"","sources":["../../../src/api/read/findRuleIds.ts"],"names":[],"mappings":"AAcA,OAAO,EAGN,yBAAyB,GACzB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAgB,0BAA0B,EAAE,MAAM,iBAAiB,CAAC;AAE3E,OAAO,EAAgB,CAAC,EAAE,MAAM,KAAK,CAAC;AACtC,OAAO,EAEN,sBAAsB,EACtB,6BAA6B,GAC7B,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"findRuleIds.js","sourceRoot":"","sources":["../../../src/api/read/findRuleIds.ts"],"names":[],"mappings":"AAcA,OAAO,EAGN,yBAAyB,GACzB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAgB,0BAA0B,EAAE,MAAM,iBAAiB,CAAC;AAE3E,OAAO,EAAgB,CAAC,EAAE,MAAM,KAAK,CAAC;AACtC,OAAO,EAEN,sBAAsB,EACtB,6BAA6B,GAC7B,MAAM,gCAAgC,CAAC;AAWxC,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IACvC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE;CACQ,CAAoC,CAAC;AAMzE,MAAM,OAAO,mBAAmB;IAC/B,YACkB,kBAAsC,EACtC,MAAc;QADd,uBAAkB,GAAlB,kBAAkB,CAAoB;QACtC,WAAM,GAAN,MAAM,CAAQ;IAC7B,CAAC;IAEG,oBAAoB;QAC1B,OAAO,CAAC,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;IACxC,CAAC;IAED,KAAK,CAAC,cAAc,CACnB,IAA8B,EAC9B,MAAe;QAEf,MAAM,GAAG,GAAG,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC;QAClC,MAAM,aAAa,GAAG,MAAM,0BAA0B,CACrD,IAAI,EACJ,KAAK,EAAE,gBAAgB,EAAE,EAAE;YAC1B,MAAM,WAAW,GAAG,6BAA6B,CAAC,gBAAgB,CAAC,CAAC;YAEpE,MAAM,OAAO,GAAG,MAAM,0BAA0B,CAC/C,WAAW,EACX,CAAC,UAAU,EAAE,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC,WAAW,CAAC,UAAU,CAAC,CAC/D,CAAC;YAEF,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC;QACvB,CAAC,CACD,CAAC;QAEF,MAAM,OAAO,GAAG,aAAa,CAAC,IAAI,EAAE,CAAC;QAGrC,MAAM,aAAa,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;QAE5C,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;YACf,GAAG,EAAE,sBAAsB;YAC3B,IAAI,EAAE;gBACL,eAAe,EAAE,OAAO,CAAC,MAAM;gBAC/B,gBAAgB,EAAE,aAAa,CAAC,MAAM;gBACtC,aAAa,EAAE,IAAI;gBACnB,QAAQ,EAAE,aAAa;aACvB;SACD,CAAC,CAAC,CAAC;QAEJ,OAAO;YACN,MAAM,EAAE,yBAAyB,CAAC,OAAO;YACzC,IAAI,EAAE;gBACL,OAAO,EAAE,aAAa;aACtB;SACD,CAAC;IACH,CAAC;CACD"}
|
|
@@ -87,12 +87,13 @@ const getUserScopeFieldQuery = (fieldName, fieldValue, scopeMatch, fullScope) =>
|
|
|
87
87
|
const queryValue = FIELDS_REQUIRING_ESCAPE.has(fieldName) ? escapeTagValue(stringValue) : stringValue;
|
|
88
88
|
return `@${fieldName}:{${queryValue}}`;
|
|
89
89
|
};
|
|
90
|
+
const GLOBAL_MATCH_CLAUSE_INNER = `@clientId:{${rule.GLOBAL_CLIENT_SCOPE_SENTINEL}} | ismissing(@clientId)`;
|
|
90
91
|
const getPolicyScopeQuery = (policyScope, scopeMatch) => {
|
|
91
92
|
const clientId = policyScope?.clientId;
|
|
92
93
|
if ("string" === typeof clientId) {
|
|
93
|
-
return rulesStorage.FilterScopeMatch.Exact === scopeMatch ? `@clientId:{${clientId}}` : `( @clientId:{${clientId}} |
|
|
94
|
+
return rulesStorage.FilterScopeMatch.Exact === scopeMatch ? `@clientId:{${clientId}}` : `( @clientId:{${clientId}} | ${GLOBAL_MATCH_CLAUSE_INNER} )`;
|
|
94
95
|
}
|
|
95
|
-
return rulesStorage.FilterScopeMatch.Exact === scopeMatch ?
|
|
96
|
+
return rulesStorage.FilterScopeMatch.Exact === scopeMatch ? `( ${GLOBAL_MATCH_CLAUSE_INNER} )` : "";
|
|
96
97
|
};
|
|
97
98
|
const getRulesRedisQuery = (filter, matchingFieldsOnly) => {
|
|
98
99
|
const { policyScope, userScope } = filter;
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
3
3
|
const util = require("node:util");
|
|
4
4
|
const common = require("@prosopo/common");
|
|
5
5
|
const redisRulesQuery = require("./redisRulesQuery.cjs");
|
|
6
|
+
const redisRulesSplitQuery = require("./redisRulesSplitQuery.cjs");
|
|
6
7
|
const redisClient = require("../redisClient.cjs");
|
|
7
8
|
const redisRuleIndex = require("../redisRuleIndex.cjs");
|
|
8
9
|
const rule = require("../../rule.cjs");
|
|
@@ -27,6 +28,7 @@ function _interopNamespaceDefault(e) {
|
|
|
27
28
|
const util__namespace = /* @__PURE__ */ _interopNamespaceDefault(util);
|
|
28
29
|
const SERVER_SIDE_RANK_TOP_N = 20;
|
|
29
30
|
const GREEDY_MAX_CANDIDATES = redisClient.REDIS_BATCH_SIZE * 10;
|
|
31
|
+
const SPLIT_MAX_CANDIDATES_PER_SUB = 500;
|
|
30
32
|
const SPECIFICITY_EXPR = [
|
|
31
33
|
"exists(@clientId)",
|
|
32
34
|
"exists(@userId)",
|
|
@@ -94,14 +96,112 @@ class RedisRulesReader {
|
|
|
94
96
|
}
|
|
95
97
|
async findRules(filter, matchingFieldsOnly = false, skipEmptyUserScopes = true) {
|
|
96
98
|
const query = redisRulesQuery.getRulesRedisQuery(filter, matchingFieldsOnly);
|
|
97
|
-
if (skipEmptyUserScopes && query
|
|
99
|
+
if (skipEmptyUserScopes && // Sentinel query shape emitted by getPolicyScopeQuery when the
|
|
100
|
+
// caller passed neither a userScope nor a clientId — i.e. an
|
|
101
|
+
// empty filter that would otherwise resolve to "all global
|
|
102
|
+
// rules". Guard so an accidentally-empty filter can't return
|
|
103
|
+
// the full global rule set. The exact literal must stay in
|
|
104
|
+
// sync with GLOBAL_MATCH_CLAUSE_INNER over there.
|
|
105
|
+
query === "( @clientId:{global} | ismissing(@clientId) )") {
|
|
98
106
|
return [];
|
|
99
107
|
}
|
|
108
|
+
if (matchingFieldsOnly && filter.blockOnly && filter.userScope !== void 0) {
|
|
109
|
+
return this.findBlockRulesSplit(filter);
|
|
110
|
+
}
|
|
100
111
|
if (matchingFieldsOnly) {
|
|
101
112
|
return this.findRulesRanked(filter, query);
|
|
102
113
|
}
|
|
103
114
|
return this.findRulesGreedy(filter, query);
|
|
104
115
|
}
|
|
116
|
+
// Union candidate keys from each split sub-query, de-dupe, HGETALL,
|
|
117
|
+
// parse, hand back to `getPrioritisedAccessRule` for JS-side ranking.
|
|
118
|
+
// Ranking stays in JS because rankCandidateRules already encodes the
|
|
119
|
+
// strict "every populated rule field matches request" semantics —
|
|
120
|
+
// FT can't express that shape cheaply and the previous server-side
|
|
121
|
+
// APPLY / SORTBY imposed the linear-per-rule cost we're eliminating.
|
|
122
|
+
async findBlockRulesSplit(filter) {
|
|
123
|
+
const userScope = filter.userScope;
|
|
124
|
+
if (userScope === void 0) {
|
|
125
|
+
return [];
|
|
126
|
+
}
|
|
127
|
+
const clientId = filter.policyScope?.clientId;
|
|
128
|
+
const subQueries = redisRulesSplitQuery.buildScopedBlockSubQueries(userScope, clientId);
|
|
129
|
+
try {
|
|
130
|
+
const keyLists = await Promise.all(
|
|
131
|
+
subQueries.map(
|
|
132
|
+
(sub) => redisAggregate.aggregateRedisKeys(
|
|
133
|
+
this.client,
|
|
134
|
+
sub.query,
|
|
135
|
+
this.logger,
|
|
136
|
+
void 0,
|
|
137
|
+
// Per-sub-query cap. Each probe hits a discriminating
|
|
138
|
+
// index (e.g. numericIp posting list), so the natural
|
|
139
|
+
// cardinality is tiny — this cap only fires on
|
|
140
|
+
// pathological rule-set shapes and mirrors
|
|
141
|
+
// SPLIT_MAX_CANDIDATES_PER_SUB below.
|
|
142
|
+
SPLIT_MAX_CANDIDATES_PER_SUB
|
|
143
|
+
).catch((err) => {
|
|
144
|
+
this.logger.error(() => ({
|
|
145
|
+
err,
|
|
146
|
+
data: {
|
|
147
|
+
inspect: util__namespace.inspect(
|
|
148
|
+
{ subKind: sub.kind, query: sub.query },
|
|
149
|
+
{ depth: null }
|
|
150
|
+
)
|
|
151
|
+
},
|
|
152
|
+
msg: "failed to execute split block sub-query"
|
|
153
|
+
}));
|
|
154
|
+
return [];
|
|
155
|
+
})
|
|
156
|
+
)
|
|
157
|
+
);
|
|
158
|
+
const uniqueKeys = /* @__PURE__ */ new Set();
|
|
159
|
+
for (const list of keyLists) {
|
|
160
|
+
for (const key of list) {
|
|
161
|
+
uniqueKeys.add(key);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
if (uniqueKeys.size === 0) {
|
|
165
|
+
return [];
|
|
166
|
+
}
|
|
167
|
+
const ruleKeys = [...uniqueKeys];
|
|
168
|
+
this.logger.debug(() => ({
|
|
169
|
+
msg: "Executed split block sub-queries",
|
|
170
|
+
data: {
|
|
171
|
+
inspect: util__namespace.inspect(
|
|
172
|
+
{
|
|
173
|
+
subQueryCount: subQueries.length,
|
|
174
|
+
uniqueCandidates: ruleKeys.length,
|
|
175
|
+
perSubQueryCounts: keyLists.map((l, i) => ({
|
|
176
|
+
kind: subQueries[i]?.kind,
|
|
177
|
+
found: l.length
|
|
178
|
+
})),
|
|
179
|
+
filter
|
|
180
|
+
},
|
|
181
|
+
{ depth: null }
|
|
182
|
+
)
|
|
183
|
+
}
|
|
184
|
+
}));
|
|
185
|
+
const { records } = await redisClient.fetchRedisHashRecords(
|
|
186
|
+
this.client,
|
|
187
|
+
ruleKeys,
|
|
188
|
+
this.logger
|
|
189
|
+
);
|
|
190
|
+
const nonEmptyRecords = records.filter(
|
|
191
|
+
(record) => Object.keys(record).length > 0
|
|
192
|
+
);
|
|
193
|
+
return redisClient.parseRedisRecords(nonEmptyRecords, ruleInput.accessRuleInput, this.logger);
|
|
194
|
+
} catch (e) {
|
|
195
|
+
this.logger.error(() => ({
|
|
196
|
+
err: e,
|
|
197
|
+
data: {
|
|
198
|
+
inspect: util__namespace.inspect({ filter }, { depth: null })
|
|
199
|
+
},
|
|
200
|
+
msg: "failed to execute split block query set"
|
|
201
|
+
}));
|
|
202
|
+
return [];
|
|
203
|
+
}
|
|
204
|
+
}
|
|
105
205
|
async findRulesRanked(filter, query) {
|
|
106
206
|
try {
|
|
107
207
|
const reply = await this.client.ft.aggregate(
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const rule = require("../../rule.cjs");
|
|
4
|
+
const escapeTagValue = (value) => value.replace(/([,.<>{}\[\]"':;!@#$%^&*()\-+=~|/\\])/g, "\\$1");
|
|
5
|
+
const FIELDS_REQUIRING_ESCAPE = /* @__PURE__ */ new Set([
|
|
6
|
+
"coords"
|
|
7
|
+
]);
|
|
8
|
+
const NUMERIC_FIELDS = /* @__PURE__ */ new Set(["asn"]);
|
|
9
|
+
const SCALAR_USER_SCOPE_FIELDS = [
|
|
10
|
+
"userId",
|
|
11
|
+
"ja4Hash",
|
|
12
|
+
"headersHash",
|
|
13
|
+
"userAgentHash",
|
|
14
|
+
"headHash",
|
|
15
|
+
"coords",
|
|
16
|
+
"countryCode",
|
|
17
|
+
"asn"
|
|
18
|
+
];
|
|
19
|
+
const ALL_USER_SCOPE_FIELDS = [
|
|
20
|
+
...SCALAR_USER_SCOPE_FIELDS,
|
|
21
|
+
"numericIp",
|
|
22
|
+
"numericIpMaskMin",
|
|
23
|
+
"numericIpMaskMax"
|
|
24
|
+
];
|
|
25
|
+
const GLOBAL_SCOPE_INNER = `@clientId:{${rule.GLOBAL_CLIENT_SCOPE_SENTINEL}} | ismissing(@clientId)`;
|
|
26
|
+
const buildScopeClause = (clientId) => {
|
|
27
|
+
if (clientId === void 0) {
|
|
28
|
+
return `( ${GLOBAL_SCOPE_INNER} )`;
|
|
29
|
+
}
|
|
30
|
+
return `( @clientId:{${clientId}} | ${GLOBAL_SCOPE_INNER} )`;
|
|
31
|
+
};
|
|
32
|
+
const buildFieldClause = (field, value) => {
|
|
33
|
+
if (value === void 0) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
const stringValue = String(value);
|
|
37
|
+
if (NUMERIC_FIELDS.has(field)) {
|
|
38
|
+
return `@${field}:[${stringValue} ${stringValue}]`;
|
|
39
|
+
}
|
|
40
|
+
const queryValue = FIELDS_REQUIRING_ESCAPE.has(field) ? escapeTagValue(stringValue) : stringValue;
|
|
41
|
+
return `@${field}:{${queryValue}}`;
|
|
42
|
+
};
|
|
43
|
+
const buildScopedBlockSubQueries = (userScope, clientId) => {
|
|
44
|
+
const typeClause = `@type:{${rule.AccessPolicyType.Block}}`;
|
|
45
|
+
const scopeClause = buildScopeClause(clientId);
|
|
46
|
+
const prefix = `${typeClause} ${scopeClause}`;
|
|
47
|
+
const subQueries = [];
|
|
48
|
+
for (const field of SCALAR_USER_SCOPE_FIELDS) {
|
|
49
|
+
const clause = buildFieldClause(field, userScope[field]);
|
|
50
|
+
if (clause === null) {
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
subQueries.push({
|
|
54
|
+
kind: `field:${field}`,
|
|
55
|
+
query: `${prefix} ${clause}`
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
const requestIp = userScope.numericIp;
|
|
59
|
+
if (requestIp !== void 0) {
|
|
60
|
+
subQueries.push({
|
|
61
|
+
kind: "ip:exact",
|
|
62
|
+
query: `${prefix} @numericIp:[${requestIp} ${requestIp}]`
|
|
63
|
+
});
|
|
64
|
+
subQueries.push({
|
|
65
|
+
kind: "ip:mask",
|
|
66
|
+
query: `${prefix} @numericIpMaskMin:[-inf ${requestIp}] @numericIpMaskMax:[${requestIp} +inf]`
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
const noScopeIsmissing = ALL_USER_SCOPE_FIELDS.map(
|
|
70
|
+
(field) => `ismissing(@${field})`
|
|
71
|
+
).join(" ");
|
|
72
|
+
subQueries.push({
|
|
73
|
+
kind: "no-user-scope",
|
|
74
|
+
query: `${prefix} ${noScopeIsmissing}`
|
|
75
|
+
});
|
|
76
|
+
return subQueries;
|
|
77
|
+
};
|
|
78
|
+
exports.buildScopedBlockSubQueries = buildScopedBlockSubQueries;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const search = require("@redis/search");
|
|
4
4
|
const transformRule = require("../transformRule.cjs");
|
|
5
|
+
const rule = require("../rule.cjs");
|
|
5
6
|
const userIpRedisSchema = {
|
|
6
7
|
numericIpMaskMin: { type: search.SCHEMA_FIELD_TYPE.NUMERIC, INDEXMISSING: true },
|
|
7
8
|
numericIpMaskMax: { type: search.SCHEMA_FIELD_TYPE.NUMERIC, INDEXMISSING: true },
|
|
@@ -50,7 +51,8 @@ const accessRulesRedisIndex = {
|
|
|
50
51
|
PREFIX: [ACCESS_RULE_REDIS_KEY_PREFIX]
|
|
51
52
|
}
|
|
52
53
|
};
|
|
53
|
-
const getAccessRuleRedisKey = (
|
|
54
|
+
const getAccessRuleRedisKey = (rule2) => ACCESS_RULE_REDIS_KEY_PREFIX + transformRule.makeAccessRuleHash(rule2);
|
|
55
|
+
exports.GLOBAL_CLIENT_SCOPE_SENTINEL = rule.GLOBAL_CLIENT_SCOPE_SENTINEL;
|
|
54
56
|
exports.ACCESS_RULES_REDIS_INDEX_NAME = ACCESS_RULES_REDIS_INDEX_NAME;
|
|
55
57
|
exports.ACCESS_RULE_REDIS_KEY_PREFIX = ACCESS_RULE_REDIS_KEY_PREFIX;
|
|
56
58
|
exports.accessRuleRedisSchema = accessRuleRedisSchema;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const common = require("@prosopo/common");
|
|
4
4
|
const redisClient = require("./redisClient.cjs");
|
|
5
|
+
const rule = require("../rule.cjs");
|
|
5
6
|
const redisRuleIndex = require("./redisRuleIndex.cjs");
|
|
6
7
|
class RedisRulesWriter {
|
|
7
8
|
constructor(client, logger) {
|
|
@@ -51,9 +52,9 @@ class RedisRulesWriter {
|
|
|
51
52
|
async insertRuleEntries(ruleEntries) {
|
|
52
53
|
const queries = this.client.multi();
|
|
53
54
|
const ruleKeys = ruleEntries.map((ruleEntry) => {
|
|
54
|
-
const { rule, expiresUnixTimestamp } = ruleEntry;
|
|
55
|
-
const ruleKey = redisRuleIndex.getAccessRuleRedisKey(
|
|
56
|
-
const ruleValue = getRedisRuleValue(
|
|
55
|
+
const { rule: rule2, expiresUnixTimestamp } = ruleEntry;
|
|
56
|
+
const ruleKey = redisRuleIndex.getAccessRuleRedisKey(rule2);
|
|
57
|
+
const ruleValue = getRedisRuleValue(rule2);
|
|
57
58
|
queries.hSet(ruleKey, ruleValue);
|
|
58
59
|
if (expiresUnixTimestamp) {
|
|
59
60
|
const MILLISECOND_THRESHOLD = 1e10;
|
|
@@ -70,9 +71,19 @@ class RedisRulesWriter {
|
|
|
70
71
|
return ruleKeys;
|
|
71
72
|
}
|
|
72
73
|
}
|
|
73
|
-
const getRedisRuleValue = (rule) =>
|
|
74
|
-
|
|
75
|
-
)
|
|
74
|
+
const getRedisRuleValue = (rule$1) => {
|
|
75
|
+
const record = {};
|
|
76
|
+
for (const [key, value] of Object.entries(rule$1)) {
|
|
77
|
+
if (value === void 0) {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
record[key] = String(value);
|
|
81
|
+
}
|
|
82
|
+
if (record.clientId === void 0) {
|
|
83
|
+
record.clientId = rule.GLOBAL_CLIENT_SCOPE_SENTINEL;
|
|
84
|
+
}
|
|
85
|
+
return record;
|
|
86
|
+
};
|
|
76
87
|
class DummyRedisRulesWriter {
|
|
77
88
|
constructor(logger) {
|
|
78
89
|
this.logger = logger;
|