@prosopo/user-access-policy 3.9.0 → 3.9.1
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 +3 -3
- package/.turbo/turbo-build$colon$tsc.log +14 -14
- package/.turbo/turbo-build.log +5 -5
- package/CHANGELOG.md +5 -0
- package/dist/cjs/redis/reader/redisAggregate.cjs +22 -4
- package/dist/cjs/redis/reader/redisRulesReader.cjs +22 -27
- package/dist/redis/reader/redisAggregate.d.ts +1 -1
- package/dist/redis/reader/redisAggregate.d.ts.map +1 -1
- package/dist/redis/reader/redisAggregate.js +22 -4
- package/dist/redis/reader/redisAggregate.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 +24 -29
- package/dist/redis/reader/redisRulesReader.js.map +1 -1
- package/dist/tests/redis/redisRulesStorage.integration.test.js +31 -0
- package/dist/tests/redis/redisRulesStorage.integration.test.js.map +1 -1
- package/package.json +1 -1
- package/src/redis/reader/redisAggregate.ts +27 -1
- package/src/redis/reader/redisRulesReader.ts +42 -40
- package/src/tests/redis/redisRulesStorage.integration.test.ts +52 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @prosopo/user-access-policy@3.9.
|
|
2
|
+
> @prosopo/user-access-policy@3.9.1 build:cjs
|
|
3
3
|
> NODE_ENV=${NODE_ENV:-development}; vite build --config vite.cjs.config.ts --mode $NODE_ENV
|
|
4
4
|
|
|
5
5
|
ViteCommonJSConfig: .
|
|
@@ -56,16 +56,16 @@ rendering chunks...
|
|
|
56
56
|
[2mdist/cjs/[22m[36mapi/write/rehashRules.cjs [39m[1m[2m1.64 kB[22m[1m[22m
|
|
57
57
|
[2mdist/cjs/[22m[36mapi/read/findRuleIds.cjs [39m[1m[2m1.65 kB[22m[1m[22m
|
|
58
58
|
[2mdist/cjs/[22m[36mruleInput/policyInput.cjs [39m[1m[2m1.70 kB[22m[1m[22m
|
|
59
|
-
[2mdist/cjs/[22m[36mredis/reader/redisAggregate.cjs [39m[1m[2m1.95 kB[22m[1m[22m
|
|
60
59
|
[2mdist/cjs/[22m[36mruleInput/ruleInput.cjs [39m[1m[2m2.07 kB[22m[1m[22m
|
|
61
60
|
[2mdist/cjs/[22m[36mredis/redisClient.cjs [39m[1m[2m2.09 kB[22m[1m[22m
|
|
62
61
|
[2mdist/cjs/[22m[36mruleInput/userScopeInput.cjs [39m[1m[2m2.45 kB[22m[1m[22m
|
|
63
62
|
[2mdist/cjs/[22m[36mredis/redisRuleIndex.cjs [39m[1m[2m2.46 kB[22m[1m[22m
|
|
64
63
|
[2mdist/cjs/[22m[36mapi/rulesApiClient.cjs [39m[1m[2m2.60 kB[22m[1m[22m
|
|
64
|
+
[2mdist/cjs/[22m[36mredis/reader/redisAggregate.cjs [39m[1m[2m2.61 kB[22m[1m[22m
|
|
65
65
|
[2mdist/cjs/[22m[36mtransformRule.cjs [39m[1m[2m3.05 kB[22m[1m[22m
|
|
66
66
|
[2mdist/cjs/[22m[36mapi/write/insertRules.cjs [39m[1m[2m3.38 kB[22m[1m[22m
|
|
67
67
|
[2mdist/cjs/[22m[36mredis/redisRulesWriter.cjs [39m[1m[2m3.44 kB[22m[1m[22m
|
|
68
68
|
[2mdist/cjs/[22m[36mredis/reader/redisRulesQuery.cjs [39m[1m[2m4.34 kB[22m[1m[22m
|
|
69
69
|
[2mdist/cjs/[22m[36mapi/ruleApiRoutes.cjs [39m[1m[2m4.55 kB[22m[1m[22m
|
|
70
|
-
[2mdist/cjs/[22m[36mredis/reader/redisRulesReader.cjs [39m[1m[
|
|
70
|
+
[2mdist/cjs/[22m[36mredis/reader/redisRulesReader.cjs [39m[1m[2m6.87 kB[22m[1m[22m
|
|
71
71
|
[32m✓ built in 451ms[39m
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
|
|
2
|
-
> @prosopo/user-access-policy@3.9.
|
|
2
|
+
> @prosopo/user-access-policy@3.9.1 build:tsc
|
|
3
3
|
> tsc --build --verbose
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
1:19:54 PM - 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
|
+
1:19:54 PM - Project '../../dev/config/tsconfig.json' is up to date because newest input '../../dev/config/src/webpack/webpack.config.ts' is older than output '../../dev/config/tsconfig.tsbuildinfo'
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
1:19:54 PM - Project '../locale/tsconfig.json' is up to date because newest input '../locale/src/translationKey.ts' is older than output '../locale/tsconfig.tsbuildinfo'
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
1:19:54 PM - 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
|
+
1:19:54 PM - 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
|
+
1:19:54 PM - 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
|
+
1:19:55 PM - Project '../types/tsconfig.json' is up to date because newest input '../types/src/keyring/keyring/types.ts' is older than output '../types/tsconfig.tsbuildinfo'
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
1:19:55 PM - 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
|
+
1:19:55 PM - 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
|
+
1:19:55 PM - 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
|
+
1:19:55 PM - 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
|
+
1:19:55 PM - Project 'tsconfig.json' is out of date because output file 'tsconfig.tsbuildinfo' does not exist
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
1:19:55 PM - 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.9.
|
|
2
|
+
> @prosopo/user-access-policy@3.9.1 build
|
|
3
3
|
> npm run build:cross-env -- --mode ${NODE_ENV:-development}
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
> @prosopo/user-access-policy@3.9.
|
|
6
|
+
> @prosopo/user-access-policy@3.9.1 build:cross-env
|
|
7
7
|
> vite build --config vite.esm.config.ts --mode production
|
|
8
8
|
|
|
9
9
|
ViteEsmConfig: .
|
|
@@ -61,15 +61,15 @@ rendering chunks...
|
|
|
61
61
|
[2mdist/[22m[36mapi/read/findRuleIds.js [39m[1m[2m1.54 kB[22m[1m[22m
|
|
62
62
|
[2mdist/[22m[36mapi/write/rehashRules.js [39m[1m[2m1.54 kB[22m[1m[22m
|
|
63
63
|
[2mdist/[22m[36mruleInput/ruleInput.js [39m[1m[2m1.72 kB[22m[1m[22m
|
|
64
|
-
[2mdist/[22m[36mredis/reader/redisAggregate.js [39m[1m[2m1.80 kB[22m[1m[22m
|
|
65
64
|
[2mdist/[22m[36mredis/redisClient.js [39m[1m[2m1.90 kB[22m[1m[22m
|
|
66
65
|
[2mdist/[22m[36mredis/redisRuleIndex.js [39m[1m[2m2.01 kB[22m[1m[22m
|
|
67
66
|
[2mdist/[22m[36mruleInput/userScopeInput.js [39m[1m[2m2.22 kB[22m[1m[22m
|
|
68
67
|
[2mdist/[22m[36mapi/rulesApiClient.js [39m[1m[2m2.36 kB[22m[1m[22m
|
|
68
|
+
[2mdist/[22m[36mredis/reader/redisAggregate.js [39m[1m[2m2.46 kB[22m[1m[22m
|
|
69
69
|
[2mdist/[22m[36mtransformRule.js [39m[1m[2m2.76 kB[22m[1m[22m
|
|
70
70
|
[2mdist/[22m[36mapi/write/insertRules.js [39m[1m[2m3.22 kB[22m[1m[22m
|
|
71
71
|
[2mdist/[22m[36mredis/redisRulesWriter.js [39m[1m[2m3.22 kB[22m[1m[22m
|
|
72
72
|
[2mdist/[22m[36mredis/reader/redisRulesQuery.js [39m[1m[2m4.15 kB[22m[1m[22m
|
|
73
73
|
[2mdist/[22m[36mapi/ruleApiRoutes.js [39m[1m[2m4.33 kB[22m[1m[22m
|
|
74
|
-
[2mdist/[22m[36mredis/reader/redisRulesReader.js [39m[1m[2m6.
|
|
75
|
-
[32m✓ built in
|
|
74
|
+
[2mdist/[22m[36mredis/reader/redisRulesReader.js [39m[1m[2m6.02 kB[22m[1m[22m
|
|
75
|
+
[32m✓ built in 473ms[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# @prosopo/user-access-policy
|
|
2
2
|
|
|
3
|
+
## 3.9.1
|
|
4
|
+
### Patch Changes
|
|
5
|
+
|
|
6
|
+
- b520cd9: Paginate the greedy `findRules` RediSearch query via `FT.AGGREGATE WITHCURSOR` so the candidate set is no longer truncated at `REDIS_BATCH_SIZE` (1000). Under high-volume bot traffic, a single popular ja4 fingerprint can be carried by thousands of rules; the OR-style greedy query returned > 1000 candidates and `FT.SEARCH`'s LIMIT silently dropped the tail — block rules emitted by less-frequent detectors sat past offset 1000 and never reached the JS-side specificity sort, letting matching requests through. Aggregation cursors return the full result set, so ranking sees every candidate.
|
|
7
|
+
|
|
3
8
|
## 3.9.0
|
|
4
9
|
### Minor Changes
|
|
5
10
|
|
|
@@ -4,19 +4,36 @@ const zod = require("zod");
|
|
|
4
4
|
const redisRulesQuery = require("./redisRulesQuery.cjs");
|
|
5
5
|
const redisClient = require("../redisClient.cjs");
|
|
6
6
|
const redisRuleIndex = require("../redisRuleIndex.cjs");
|
|
7
|
-
const aggregateRedisKeys = async (client, query, logger, batchHandler) => {
|
|
7
|
+
const aggregateRedisKeys = async (client, query, logger, batchHandler, maxKeys) => {
|
|
8
8
|
const keyField = "__key";
|
|
9
9
|
const recordSchema = zod.z.object({
|
|
10
10
|
// it's a reserved name for the record key
|
|
11
11
|
[keyField]: zod.z.string()
|
|
12
12
|
});
|
|
13
13
|
const foundKeys = [];
|
|
14
|
+
let stopRequested = false;
|
|
14
15
|
const addRecordKeys = async (records) => {
|
|
16
|
+
if (stopRequested) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
15
19
|
const parsedRecords = redisClient.parseRedisRecords(records, recordSchema, logger);
|
|
16
20
|
const recordKeys = parsedRecords.map((record) => record[keyField]);
|
|
17
21
|
if (batchHandler) {
|
|
18
22
|
await batchHandler(recordKeys);
|
|
19
23
|
} else {
|
|
24
|
+
if (maxKeys !== void 0 && foundKeys.length + recordKeys.length > maxKeys) {
|
|
25
|
+
const remaining = Math.max(0, maxKeys - foundKeys.length);
|
|
26
|
+
foundKeys.push(...recordKeys.slice(0, remaining));
|
|
27
|
+
stopRequested = true;
|
|
28
|
+
logger.warn(() => ({
|
|
29
|
+
msg: "Redis aggregation candidate cap hit; truncating result set. This can suppress less-frequent rules and should be investigated.",
|
|
30
|
+
data: {
|
|
31
|
+
maxKeys,
|
|
32
|
+
query
|
|
33
|
+
}
|
|
34
|
+
}));
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
20
37
|
foundKeys.push(...recordKeys);
|
|
21
38
|
logger.debug(() => ({
|
|
22
39
|
msg: "Processed aggregation batch",
|
|
@@ -35,11 +52,12 @@ const aggregateRedisKeys = async (client, query, logger, batchHandler) => {
|
|
|
35
52
|
COUNT: redisClient.REDIS_BATCH_SIZE,
|
|
36
53
|
LOAD: `@${keyField}`
|
|
37
54
|
},
|
|
38
|
-
addRecordKeys
|
|
55
|
+
addRecordKeys,
|
|
56
|
+
() => stopRequested
|
|
39
57
|
);
|
|
40
58
|
return foundKeys;
|
|
41
59
|
};
|
|
42
|
-
const executeAggregation = async (client, query, aggregateOptions, handleBatch) => {
|
|
60
|
+
const executeAggregation = async (client, query, aggregateOptions, handleBatch, shouldStop) => {
|
|
43
61
|
const initialReply = await client.ft.aggregateWithCursor(
|
|
44
62
|
redisRuleIndex.ACCESS_RULES_REDIS_INDEX_NAME,
|
|
45
63
|
query,
|
|
@@ -47,7 +65,7 @@ const executeAggregation = async (client, query, aggregateOptions, handleBatch)
|
|
|
47
65
|
);
|
|
48
66
|
await handleBatch(initialReply.results);
|
|
49
67
|
let cursor = initialReply.cursor;
|
|
50
|
-
while (0 !== cursor) {
|
|
68
|
+
while (0 !== cursor && !shouldStop?.()) {
|
|
51
69
|
const batchReply = await client.ft.cursorRead(
|
|
52
70
|
redisRuleIndex.ACCESS_RULES_REDIS_INDEX_NAME,
|
|
53
71
|
cursor,
|
|
@@ -24,6 +24,7 @@ function _interopNamespaceDefault(e) {
|
|
|
24
24
|
return Object.freeze(n);
|
|
25
25
|
}
|
|
26
26
|
const util__namespace = /* @__PURE__ */ _interopNamespaceDefault(util);
|
|
27
|
+
const FIND_RULES_MAX_CANDIDATES = redisClient.REDIS_BATCH_SIZE * 10;
|
|
27
28
|
class RedisRulesReader {
|
|
28
29
|
constructor(client, logger) {
|
|
29
30
|
this.client = client;
|
|
@@ -53,39 +54,32 @@ class RedisRulesReader {
|
|
|
53
54
|
return [];
|
|
54
55
|
}
|
|
55
56
|
try {
|
|
56
|
-
const
|
|
57
|
-
|
|
57
|
+
const ruleKeys = await redisAggregate.aggregateRedisKeys(
|
|
58
|
+
this.client,
|
|
58
59
|
query,
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
LIMIT: {
|
|
63
|
-
from: 0,
|
|
64
|
-
size: redisClient.REDIS_BATCH_SIZE
|
|
65
|
-
}
|
|
66
|
-
}
|
|
60
|
+
this.logger,
|
|
61
|
+
void 0,
|
|
62
|
+
FIND_RULES_MAX_CANDIDATES
|
|
67
63
|
);
|
|
68
|
-
if (
|
|
69
|
-
this.logger.debug(() => ({
|
|
70
|
-
msg: "Executed search query",
|
|
71
|
-
data: {
|
|
72
|
-
inspect: util__namespace.inspect(
|
|
73
|
-
{
|
|
74
|
-
filter,
|
|
75
|
-
searchReply,
|
|
76
|
-
query
|
|
77
|
-
},
|
|
78
|
-
{ depth: null }
|
|
79
|
-
)
|
|
80
|
-
}
|
|
81
|
-
}));
|
|
82
|
-
}
|
|
83
|
-
if (searchReply.documents.length === 0) {
|
|
64
|
+
if (ruleKeys.length === 0) {
|
|
84
65
|
return [];
|
|
85
66
|
}
|
|
67
|
+
this.logger.debug(() => ({
|
|
68
|
+
msg: "Executed search query",
|
|
69
|
+
data: {
|
|
70
|
+
inspect: util__namespace.inspect(
|
|
71
|
+
{
|
|
72
|
+
filter,
|
|
73
|
+
foundCount: ruleKeys.length,
|
|
74
|
+
query
|
|
75
|
+
},
|
|
76
|
+
{ depth: null }
|
|
77
|
+
)
|
|
78
|
+
}
|
|
79
|
+
}));
|
|
86
80
|
const { records } = await redisClient.fetchRedisHashRecords(
|
|
87
81
|
this.client,
|
|
88
|
-
|
|
82
|
+
ruleKeys,
|
|
89
83
|
this.logger
|
|
90
84
|
);
|
|
91
85
|
const nonEmptyRecords = records.filter(
|
|
@@ -236,4 +230,5 @@ class DummyRedisRulesReader {
|
|
|
236
230
|
}
|
|
237
231
|
}
|
|
238
232
|
exports.DummyRedisRulesReader = DummyRedisRulesReader;
|
|
233
|
+
exports.FIND_RULES_MAX_CANDIDATES = FIND_RULES_MAX_CANDIDATES;
|
|
239
234
|
exports.RedisRulesReader = RedisRulesReader;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { Logger } from "@prosopo/logger";
|
|
2
2
|
import type { RedisClientType } from "redis";
|
|
3
|
-
export declare const aggregateRedisKeys: (client: RedisClientType, query: string, logger: Logger, batchHandler?: (keys: string[]) => Promise<void
|
|
3
|
+
export declare const aggregateRedisKeys: (client: RedisClientType, query: string, logger: Logger, batchHandler?: (keys: string[]) => Promise<void>, maxKeys?: number) => Promise<string[]>;
|
|
4
4
|
//# sourceMappingURL=redisAggregate.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redisAggregate.d.ts","sourceRoot":"","sources":["../../../src/redis/reader/redisAggregate.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAE9C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,OAAO,CAAC;AAU7C,eAAO,MAAM,kBAAkB,WACtB,eAAe,SAChB,MAAM,UACL,MAAM,iBACC,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"redisAggregate.d.ts","sourceRoot":"","sources":["../../../src/redis/reader/redisAggregate.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAE9C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,OAAO,CAAC;AAU7C,eAAO,MAAM,kBAAkB,WACtB,eAAe,SAChB,MAAM,UACL,MAAM,iBACC,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,YACtC,MAAM,KACd,OAAO,CAAC,MAAM,EAAE,CAkElB,CAAC"}
|
|
@@ -2,19 +2,36 @@ import { z } from "zod";
|
|
|
2
2
|
import { REDIS_QUERY_DIALECT } from "./redisRulesQuery.js";
|
|
3
3
|
import { parseRedisRecords, REDIS_BATCH_SIZE } from "../redisClient.js";
|
|
4
4
|
import { ACCESS_RULES_REDIS_INDEX_NAME } from "../redisRuleIndex.js";
|
|
5
|
-
const aggregateRedisKeys = async (client, query, logger, batchHandler) => {
|
|
5
|
+
const aggregateRedisKeys = async (client, query, logger, batchHandler, maxKeys) => {
|
|
6
6
|
const keyField = "__key";
|
|
7
7
|
const recordSchema = z.object({
|
|
8
8
|
// it's a reserved name for the record key
|
|
9
9
|
[keyField]: z.string()
|
|
10
10
|
});
|
|
11
11
|
const foundKeys = [];
|
|
12
|
+
let stopRequested = false;
|
|
12
13
|
const addRecordKeys = async (records) => {
|
|
14
|
+
if (stopRequested) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
13
17
|
const parsedRecords = parseRedisRecords(records, recordSchema, logger);
|
|
14
18
|
const recordKeys = parsedRecords.map((record) => record[keyField]);
|
|
15
19
|
if (batchHandler) {
|
|
16
20
|
await batchHandler(recordKeys);
|
|
17
21
|
} else {
|
|
22
|
+
if (maxKeys !== void 0 && foundKeys.length + recordKeys.length > maxKeys) {
|
|
23
|
+
const remaining = Math.max(0, maxKeys - foundKeys.length);
|
|
24
|
+
foundKeys.push(...recordKeys.slice(0, remaining));
|
|
25
|
+
stopRequested = true;
|
|
26
|
+
logger.warn(() => ({
|
|
27
|
+
msg: "Redis aggregation candidate cap hit; truncating result set. This can suppress less-frequent rules and should be investigated.",
|
|
28
|
+
data: {
|
|
29
|
+
maxKeys,
|
|
30
|
+
query
|
|
31
|
+
}
|
|
32
|
+
}));
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
18
35
|
foundKeys.push(...recordKeys);
|
|
19
36
|
logger.debug(() => ({
|
|
20
37
|
msg: "Processed aggregation batch",
|
|
@@ -33,11 +50,12 @@ const aggregateRedisKeys = async (client, query, logger, batchHandler) => {
|
|
|
33
50
|
COUNT: REDIS_BATCH_SIZE,
|
|
34
51
|
LOAD: `@${keyField}`
|
|
35
52
|
},
|
|
36
|
-
addRecordKeys
|
|
53
|
+
addRecordKeys,
|
|
54
|
+
() => stopRequested
|
|
37
55
|
);
|
|
38
56
|
return foundKeys;
|
|
39
57
|
};
|
|
40
|
-
const executeAggregation = async (client, query, aggregateOptions, handleBatch) => {
|
|
58
|
+
const executeAggregation = async (client, query, aggregateOptions, handleBatch, shouldStop) => {
|
|
41
59
|
const initialReply = await client.ft.aggregateWithCursor(
|
|
42
60
|
ACCESS_RULES_REDIS_INDEX_NAME,
|
|
43
61
|
query,
|
|
@@ -45,7 +63,7 @@ const executeAggregation = async (client, query, aggregateOptions, handleBatch)
|
|
|
45
63
|
);
|
|
46
64
|
await handleBatch(initialReply.results);
|
|
47
65
|
let cursor = initialReply.cursor;
|
|
48
|
-
while (0 !== cursor) {
|
|
66
|
+
while (0 !== cursor && !shouldStop?.()) {
|
|
49
67
|
const batchReply = await client.ft.cursorRead(
|
|
50
68
|
ACCESS_RULES_REDIS_INDEX_NAME,
|
|
51
69
|
cursor,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redisAggregate.js","sourceRoot":"","sources":["../../../src/redis/reader/redisAggregate.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,mBAAmB,EAAE,MAAM,yCAAyC,CAAC;AAC9E,OAAO,EACN,gBAAgB,EAChB,iBAAiB,GACjB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,6BAA6B,EAAE,MAAM,iCAAiC,CAAC;AAGhF,MAAM,CAAC,MAAM,kBAAkB,GAAG,KAAK,EACtC,MAAuB,EACvB,KAAa,EACb,MAAc,EACd,YAAgD,
|
|
1
|
+
{"version":3,"file":"redisAggregate.js","sourceRoot":"","sources":["../../../src/redis/reader/redisAggregate.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,6 +2,7 @@ import type { Logger } from "@prosopo/logger";
|
|
|
2
2
|
import type { RedisClientType } from "redis";
|
|
3
3
|
import type { AccessRule } from "#policy/rule.js";
|
|
4
4
|
import type { AccessRuleEntry, AccessRulesFilter, AccessRulesReader } from "#policy/rulesStorage.js";
|
|
5
|
+
export declare const FIND_RULES_MAX_CANDIDATES: number;
|
|
5
6
|
export declare class RedisRulesReader implements AccessRulesReader {
|
|
6
7
|
private readonly client;
|
|
7
8
|
private readonly logger;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redisRulesReader.d.ts","sourceRoot":"","sources":["../../../src/redis/reader/redisRulesReader.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"redisRulesReader.d.ts","sourceRoot":"","sources":["../../../src/redis/reader/redisRulesReader.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,OAAO,CAAC;AAS7C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,OAAO,KAAK,EACX,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EACjB,MAAM,yBAAyB,CAAC;AAUjC,eAAO,MAAM,yBAAyB,QAAwB,CAAC;AAE/D,qBAAa,gBAAiB,YAAW,iBAAiB;IAExD,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,MAAM;IAG1B,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAcvD,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IAazD,SAAS,CACd,MAAM,EAAE,iBAAiB,EACzB,kBAAkB,UAAQ,EAC1B,mBAAmB,UAAO,GACxB,OAAO,CAAC,UAAU,EAAE,CAAC;IA6ElB,WAAW,CAChB,MAAM,EAAE,iBAAiB,EACzB,kBAAkB,UAAQ,GACxB,OAAO,CAAC,MAAM,EAAE,CAAC;IAgDd,eAAe,CACpB,YAAY,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,GAChD,OAAO,CAAC,IAAI,CAAC;cAYA,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IA8B5E,SAAS,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE;CAGlD;AAED,qBAAa,qBAAsB,YAAW,iBAAiB;IAClD,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,MAAM;IAErC,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAWvD,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IAWzD,SAAS,CACd,MAAM,EAAE,iBAAiB,EACzB,kBAAkB,UAAQ,EAC1B,mBAAmB,UAAO,GACxB,OAAO,CAAC,UAAU,EAAE,CAAC;IAWlB,WAAW,CAChB,MAAM,EAAE,iBAAiB,EACzB,kBAAkB,UAAQ,GACxB,OAAO,CAAC,MAAM,EAAE,CAAC;IAWd,eAAe,CACpB,YAAY,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,GAChD,OAAO,CAAC,IAAI,CAAC;CAKhB"}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import * as util from "node:util";
|
|
2
2
|
import { chunkIntoBatches, executeBatchesSequentially } from "@prosopo/common";
|
|
3
|
-
import { getRulesRedisQuery
|
|
3
|
+
import { getRulesRedisQuery } from "./redisRulesQuery.js";
|
|
4
4
|
import { REDIS_BATCH_SIZE, getMissingRedisKeys, fetchRedisHashRecords, parseRedisRecords } from "../redisClient.js";
|
|
5
|
-
import { ACCESS_RULE_REDIS_KEY_PREFIX
|
|
5
|
+
import { ACCESS_RULE_REDIS_KEY_PREFIX } from "../redisRuleIndex.js";
|
|
6
6
|
import { accessRuleInput } from "../../ruleInput/ruleInput.js";
|
|
7
7
|
import { aggregateRedisKeys } from "./redisAggregate.js";
|
|
8
|
+
const FIND_RULES_MAX_CANDIDATES = REDIS_BATCH_SIZE * 10;
|
|
8
9
|
class RedisRulesReader {
|
|
9
10
|
constructor(client, logger) {
|
|
10
11
|
this.client = client;
|
|
@@ -34,39 +35,32 @@ class RedisRulesReader {
|
|
|
34
35
|
return [];
|
|
35
36
|
}
|
|
36
37
|
try {
|
|
37
|
-
const
|
|
38
|
-
|
|
38
|
+
const ruleKeys = await aggregateRedisKeys(
|
|
39
|
+
this.client,
|
|
39
40
|
query,
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
LIMIT: {
|
|
44
|
-
from: 0,
|
|
45
|
-
size: REDIS_BATCH_SIZE
|
|
46
|
-
}
|
|
47
|
-
}
|
|
41
|
+
this.logger,
|
|
42
|
+
void 0,
|
|
43
|
+
FIND_RULES_MAX_CANDIDATES
|
|
48
44
|
);
|
|
49
|
-
if (
|
|
50
|
-
this.logger.debug(() => ({
|
|
51
|
-
msg: "Executed search query",
|
|
52
|
-
data: {
|
|
53
|
-
inspect: util.inspect(
|
|
54
|
-
{
|
|
55
|
-
filter,
|
|
56
|
-
searchReply,
|
|
57
|
-
query
|
|
58
|
-
},
|
|
59
|
-
{ depth: null }
|
|
60
|
-
)
|
|
61
|
-
}
|
|
62
|
-
}));
|
|
63
|
-
}
|
|
64
|
-
if (searchReply.documents.length === 0) {
|
|
45
|
+
if (ruleKeys.length === 0) {
|
|
65
46
|
return [];
|
|
66
47
|
}
|
|
48
|
+
this.logger.debug(() => ({
|
|
49
|
+
msg: "Executed search query",
|
|
50
|
+
data: {
|
|
51
|
+
inspect: util.inspect(
|
|
52
|
+
{
|
|
53
|
+
filter,
|
|
54
|
+
foundCount: ruleKeys.length,
|
|
55
|
+
query
|
|
56
|
+
},
|
|
57
|
+
{ depth: null }
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
}));
|
|
67
61
|
const { records } = await fetchRedisHashRecords(
|
|
68
62
|
this.client,
|
|
69
|
-
|
|
63
|
+
ruleKeys,
|
|
70
64
|
this.logger
|
|
71
65
|
);
|
|
72
66
|
const nonEmptyRecords = records.filter(
|
|
@@ -218,5 +212,6 @@ class DummyRedisRulesReader {
|
|
|
218
212
|
}
|
|
219
213
|
export {
|
|
220
214
|
DummyRedisRulesReader,
|
|
215
|
+
FIND_RULES_MAX_CANDIDATES,
|
|
221
216
|
RedisRulesReader
|
|
222
217
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redisRulesReader.js","sourceRoot":"","sources":["../../../src/redis/reader/redisRulesReader.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,gBAAgB,EAAE,0BAA0B,EAAE,MAAM,iBAAiB,CAAC;AAG/E,OAAO,
|
|
1
|
+
{"version":3,"file":"redisRulesReader.js","sourceRoot":"","sources":["../../../src/redis/reader/redisRulesReader.ts"],"names":[],"mappings":"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"}
|
|
@@ -802,6 +802,37 @@ describe("redisAccessRulesStorage", () => {
|
|
|
802
802
|
});
|
|
803
803
|
expect(foundAccessRules).toEqual([]);
|
|
804
804
|
});
|
|
805
|
+
test("returns all matches when the candidate set exceeds the FT.SEARCH page size", async () => {
|
|
806
|
+
const clientId = getUniqueString();
|
|
807
|
+
const popularJa4 = `t13d1516h2_${getUniqueString()}`;
|
|
808
|
+
const targetBlockRule = {
|
|
809
|
+
type: AccessPolicyType.Block,
|
|
810
|
+
clientId: clientId,
|
|
811
|
+
ja4Hash: popularJa4,
|
|
812
|
+
coords: "[[[867,60]]]",
|
|
813
|
+
};
|
|
814
|
+
const noiseRules = Array.from({ length: 1500 }, (_, i) => ({
|
|
815
|
+
type: AccessPolicyType.Restrict,
|
|
816
|
+
clientId: clientId,
|
|
817
|
+
ja4Hash: popularJa4,
|
|
818
|
+
coords: `[[[${i % 1024},${60 + (i % 32)}]]]`,
|
|
819
|
+
description: `noise-${i}`,
|
|
820
|
+
}));
|
|
821
|
+
await insertRules([targetBlockRule, ...noiseRules]);
|
|
822
|
+
const indexRecordsCount = await getIndexRecordsCount(indexName);
|
|
823
|
+
expect(indexRecordsCount).toBe(1501);
|
|
824
|
+
const found = await accessRulesReader.findRules({
|
|
825
|
+
policyScope: { clientId: clientId },
|
|
826
|
+
policyScopeMatch: FilterScopeMatch.Greedy,
|
|
827
|
+
userScope: {
|
|
828
|
+
ja4Hash: popularJa4,
|
|
829
|
+
coords: "[[[867,60]]]",
|
|
830
|
+
},
|
|
831
|
+
userScopeMatch: FilterScopeMatch.Greedy,
|
|
832
|
+
});
|
|
833
|
+
expect(found.length).toBe(1501);
|
|
834
|
+
expect(found).toContainEqual(targetBlockRule);
|
|
835
|
+
}, 60_000);
|
|
805
836
|
test("finds rules with matchingFieldsOnly when only userId is set and all IP fields are missing", async () => {
|
|
806
837
|
const clientId = getUniqueString();
|
|
807
838
|
const userId = getUniqueString();
|