@prosopo/user-access-policy 3.12.6 → 3.12.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/.turbo/turbo-build$colon$cjs.log +3 -3
- package/.turbo/turbo-build$colon$tsc.log +14 -14
- package/.turbo/turbo-build.log +6 -6
- package/CHANGELOG.md +29 -0
- package/dist/cjs/ruleInput/policyInput.cjs +21 -1
- package/dist/cjs/ruleInput/ruleInput.cjs +1 -1
- package/dist/cjs/transformRule.cjs +1 -1
- package/dist/ruleInput/policyInput.d.ts +52 -1
- package/dist/ruleInput/policyInput.d.ts.map +1 -1
- package/dist/ruleInput/policyInput.js +21 -1
- package/dist/ruleInput/policyInput.js.map +1 -1
- package/dist/ruleInput/ruleInput.d.ts.map +1 -1
- package/dist/ruleInput/ruleInput.js +2 -2
- package/dist/ruleInput/ruleInput.js.map +1 -1
- package/dist/tests/policyInput.unit.test.js +50 -1
- package/dist/tests/policyInput.unit.test.js.map +1 -1
- package/dist/tests/redis/redisRulesStorage.integration.test.js +21 -0
- package/dist/tests/redis/redisRulesStorage.integration.test.js.map +1 -1
- package/dist/transformRule.js +2 -2
- package/dist/transformRule.js.map +1 -1
- package/package.json +3 -3
- package/src/ruleInput/policyInput.ts +45 -2
- package/src/ruleInput/ruleInput.ts +10 -3
- package/src/tests/policyInput.unit.test.ts +69 -1
- package/src/tests/redis/redisRulesStorage.integration.test.ts +47 -0
- package/src/transformRule.ts +2 -2
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @prosopo/user-access-policy@3.12.
|
|
2
|
+
> @prosopo/user-access-policy@3.12.8 build:cjs
|
|
3
3
|
> NODE_ENV=${NODE_ENV:-development}; vite build --config vite.cjs.config.ts --mode $NODE_ENV
|
|
4
4
|
|
|
5
5
|
ViteCommonJSConfig: .
|
|
@@ -58,11 +58,11 @@ rendering chunks...
|
|
|
58
58
|
[2mdist/cjs/[22m[36mapi/read/findRuleIds.cjs [39m[1m[2m 1.65 kB[22m[1m[22m
|
|
59
59
|
[2mdist/cjs/[22m[36mredis/redisClient.cjs [39m[1m[2m 2.09 kB[22m[1m[22m
|
|
60
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
61
|
[2mdist/cjs/[22m[36mapi/rulesApiClient.cjs [39m[1m[2m 2.60 kB[22m[1m[22m
|
|
63
62
|
[2mdist/cjs/[22m[36mredis/reader/redisRulesSplitQuery.cjs [39m[1m[2m 2.66 kB[22m[1m[22m
|
|
64
63
|
[2mdist/cjs/[22m[36mruleInput/userScopeInput.cjs [39m[1m[2m 2.67 kB[22m[1m[22m
|
|
65
64
|
[2mdist/cjs/[22m[36mredis/reader/redisAggregate.cjs [39m[1m[2m 2.98 kB[22m[1m[22m
|
|
65
|
+
[2mdist/cjs/[22m[36mruleInput/policyInput.cjs [39m[1m[2m 2.99 kB[22m[1m[22m
|
|
66
66
|
[2mdist/cjs/[22m[36mtransformRule.cjs [39m[1m[2m 3.05 kB[22m[1m[22m
|
|
67
67
|
[2mdist/cjs/[22m[36mredis/redisRuleIndex.cjs [39m[1m[2m 3.07 kB[22m[1m[22m
|
|
68
68
|
[2mdist/cjs/[22m[36mapi/write/insertRules.cjs [39m[1m[2m 3.38 kB[22m[1m[22m
|
|
@@ -70,4 +70,4 @@ rendering chunks...
|
|
|
70
70
|
[2mdist/cjs/[22m[36mapi/ruleApiRoutes.cjs [39m[1m[2m 4.55 kB[22m[1m[22m
|
|
71
71
|
[2mdist/cjs/[22m[36mredis/reader/redisRulesQuery.cjs [39m[1m[2m 4.60 kB[22m[1m[22m
|
|
72
72
|
[2mdist/cjs/[22m[36mredis/reader/redisRulesReader.cjs [39m[1m[2m17.15 kB[22m[1m[22m
|
|
73
|
-
[32m✓ built in
|
|
73
|
+
[32m✓ built in 529ms[39m
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
|
|
2
|
-
> @prosopo/user-access-policy@3.12.
|
|
2
|
+
> @prosopo/user-access-policy@3.12.8 build:tsc
|
|
3
3
|
> tsc --build --verbose
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
9:05:22 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
|
+
9:05:23 AM - 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
|
+
9:05:23 AM - 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
|
+
9:05:23 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
|
+
9:05:23 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
|
+
9:05:23 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
|
+
9:05:23 AM - Project '../types/tsconfig.json' is up to date because newest input '../types/src/procaptcha/api.ts' is older than output '../types/tsconfig.tsbuildinfo'
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
9:05:23 AM - Project '../common/tsconfig.json' is up to date because newest input '../common/src/utils/batches.ts' is older than output '../common/tsconfig.tsbuildinfo'
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
9:05:23 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
|
+
9:05:23 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
|
+
9:05:23 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
|
+
9:05:23 AM - Project 'tsconfig.json' is out of date because output file 'tsconfig.tsbuildinfo' does not exist
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
9:05:23 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.12.
|
|
2
|
+
> @prosopo/user-access-policy@3.12.8 build
|
|
3
3
|
> npm run build:cross-env -- --mode ${NODE_ENV:-development}
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
> @prosopo/user-access-policy@3.12.
|
|
6
|
+
> @prosopo/user-access-policy@3.12.8 build:cross-env
|
|
7
7
|
> vite build --config vite.esm.config.ts --mode production
|
|
8
8
|
|
|
9
9
|
ViteEsmConfig: .
|
|
@@ -60,18 +60,18 @@ rendering chunks...
|
|
|
60
60
|
[2mdist/[22m[36mapi/delete/deleteRuleGroups.js [39m[1m[2m 1.44 kB[22m[1m[22m
|
|
61
61
|
[2mdist/[22m[36mapi/read/findRuleIds.js [39m[1m[2m 1.54 kB[22m[1m[22m
|
|
62
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.
|
|
63
|
+
[2mdist/[22m[36mruleInput/ruleInput.js [39m[1m[2m 1.77 kB[22m[1m[22m
|
|
64
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
65
|
[2mdist/[22m[36mapi/rulesApiClient.js [39m[1m[2m 2.36 kB[22m[1m[22m
|
|
67
66
|
[2mdist/[22m[36mruleInput/userScopeInput.js [39m[1m[2m 2.44 kB[22m[1m[22m
|
|
68
67
|
[2mdist/[22m[36mredis/reader/redisRulesSplitQuery.js [39m[1m[2m 2.55 kB[22m[1m[22m
|
|
69
68
|
[2mdist/[22m[36mredis/redisRuleIndex.js [39m[1m[2m 2.58 kB[22m[1m[22m
|
|
70
|
-
[2mdist/[22m[
|
|
69
|
+
[2mdist/[22m[36mruleInput/policyInput.js [39m[1m[2m 2.77 kB[22m[1m[22m
|
|
70
|
+
[2mdist/[22m[36mtransformRule.js [39m[1m[2m 2.77 kB[22m[1m[22m
|
|
71
71
|
[2mdist/[22m[36mredis/reader/redisAggregate.js [39m[1m[2m 2.77 kB[22m[1m[22m
|
|
72
72
|
[2mdist/[22m[36mapi/write/insertRules.js [39m[1m[2m 3.22 kB[22m[1m[22m
|
|
73
73
|
[2mdist/[22m[36mredis/redisRulesWriter.js [39m[1m[2m 3.47 kB[22m[1m[22m
|
|
74
74
|
[2mdist/[22m[36mapi/ruleApiRoutes.js [39m[1m[2m 4.33 kB[22m[1m[22m
|
|
75
75
|
[2mdist/[22m[36mredis/reader/redisRulesQuery.js [39m[1m[2m 4.45 kB[22m[1m[22m
|
|
76
76
|
[2mdist/[22m[36mredis/reader/redisRulesReader.js [39m[1m[2m16.17 kB[22m[1m[22m
|
|
77
|
-
[32m✓ built in
|
|
77
|
+
[32m✓ built in 532ms[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,34 @@
|
|
|
1
1
|
# @prosopo/user-access-policy
|
|
2
2
|
|
|
3
|
+
## 3.12.8
|
|
4
|
+
### Patch Changes
|
|
5
|
+
|
|
6
|
+
- c61dfb5: fix(access-policy): reject Block+captchaType at schema level; add follow-up test coverage
|
|
7
|
+
|
|
8
|
+
**Fix.** The `sanitizeAccessPolicy` helper silently strips `captchaType` and `solvedImagesCount` from Block policies at write time, which meant operators writing e.g. `--block --ip X --captchaType image` got a rule that actually blocked EVERY captcha type for that IP — not just image. Same root cause as the Block+deferToVerify request-time 400 bug (see #2885). Rejecting at input surfaces the mismatch loudly with a message that points the operator at Restrict:
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
Block policies cannot pin a captchaType — Block always applies to every
|
|
12
|
+
captcha type. Use a Restrict policy if you want to narrow the effect to
|
|
13
|
+
one captcha type.
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
`accessPolicyInput` now has a `superRefine` that rejects Block+captchaType and Block+solvedImagesCount. The read path still accepts the legacy shape (records written before the refinement landed can still be parsed by the reader). The `addUserAccessPolicy` script was updated to only emit those fields for Restrict, so its `--block` path no longer 400s.
|
|
17
|
+
|
|
18
|
+
**Follow-up tests added** — closing the gaps flagged in the previous session:
|
|
19
|
+
|
|
20
|
+
- **Coord threading lands on the puzzle record** (`puzzleTasks.unit.test.ts`) — extends the verify-puzzle-solution suite to encode a real salt with `(158, 42)`, submit, and assert `coords[0][0] === [158, 42]` on the persisted record. Guards against a regression that drops the salt decode or writes `[0, 0]` — the whole point of the puzzle DM threading PR (#2873).
|
|
21
|
+
- **DM deny reason lands on the pow commitment** (`powTasks.unit.test.ts`) — pow's existing "should deny when decision machine returns deny" test only asserted `verified:false`; now also asserts the DM's reason string is persisted on the commitment.
|
|
22
|
+
- **checkForHardBlock wins over DM deny at verify** (`puzzleTasks.unit.test.ts`) — stubs `checkForHardBlock` to match, stubs the DM to also deny with a distinguishable reason, asserts the commitment carries `ACCESS_POLICY_BLOCK` and that the DM was never consulted. Locks in the ordering that the audit trail depends on.
|
|
23
|
+
- **Rule expiry** (`redisRulesStorage.integration.test.ts`) — inserts a rule with a 2 s TTL, waits past expiry, asserts the Redis hash is gone and the RediSearch index no longer counts it. The existing "inserts time limited rule" test only verified the TTL was set, not that expired rules stop matching.
|
|
24
|
+
|
|
25
|
+
## 3.12.7
|
|
26
|
+
### Patch Changes
|
|
27
|
+
|
|
28
|
+
- Updated dependencies [a0cb39e]
|
|
29
|
+
- @prosopo/types@4.9.12
|
|
30
|
+
- @prosopo/api@3.5.19
|
|
31
|
+
|
|
3
32
|
## 3.12.6
|
|
4
33
|
### Patch Changes
|
|
5
34
|
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
3
3
|
const types = require("@prosopo/types");
|
|
4
4
|
const zod = require("zod");
|
|
5
5
|
const rule = require("../rule.cjs");
|
|
6
|
-
const
|
|
6
|
+
const accessPolicyInputShape = zod.z.object({
|
|
7
7
|
type: zod.z.nativeEnum(rule.AccessPolicyType),
|
|
8
8
|
captchaType: types.CaptchaTypeSchema.optional(),
|
|
9
9
|
description: zod.z.coerce.string().optional(),
|
|
@@ -22,6 +22,25 @@ const accessPolicyInput = zod.z.object({
|
|
|
22
22
|
// round-trip to the JS boolean the matcher expects.
|
|
23
23
|
deferToVerify: zod.z.preprocess((v) => typeof v === "string" ? v === "true" : v, zod.z.boolean()).optional()
|
|
24
24
|
});
|
|
25
|
+
const accessPolicyInput = accessPolicyInputShape.superRefine(
|
|
26
|
+
(policy, ctx) => {
|
|
27
|
+
if (policy.type !== rule.AccessPolicyType.Block) return;
|
|
28
|
+
if (policy.captchaType !== void 0) {
|
|
29
|
+
ctx.addIssue({
|
|
30
|
+
code: zod.z.ZodIssueCode.custom,
|
|
31
|
+
path: ["captchaType"],
|
|
32
|
+
message: "Block policies cannot pin a captchaType — Block always applies to every captcha type. Use a Restrict policy if you want to narrow the effect to one captcha type."
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
if (policy.solvedImagesCount !== void 0) {
|
|
36
|
+
ctx.addIssue({
|
|
37
|
+
code: zod.z.ZodIssueCode.custom,
|
|
38
|
+
path: ["solvedImagesCount"],
|
|
39
|
+
message: "Block policies cannot set solvedImagesCount — the field only applies to Restrict policies that adjust image-captcha rounds."
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
);
|
|
25
44
|
const sanitizeAccessPolicy = (policy) => {
|
|
26
45
|
if (policy.type === rule.AccessPolicyType.Block) {
|
|
27
46
|
const { captchaType, solvedImagesCount, ...blockPolicy } = policy;
|
|
@@ -41,5 +60,6 @@ const policyScopeInput = zod.z.object({
|
|
|
41
60
|
)
|
|
42
61
|
});
|
|
43
62
|
exports.accessPolicyInput = accessPolicyInput;
|
|
63
|
+
exports.accessPolicyInputShape = accessPolicyInputShape;
|
|
44
64
|
exports.policyScopeInput = policyScopeInput;
|
|
45
65
|
exports.sanitizeAccessPolicy = sanitizeAccessPolicy;
|
|
@@ -15,7 +15,7 @@ const ruleGroupInput = zod.z.object({
|
|
|
15
15
|
return ruleGroup;
|
|
16
16
|
});
|
|
17
17
|
const accessRuleInput = zod.z.object({
|
|
18
|
-
...policyInput.
|
|
18
|
+
...policyInput.accessPolicyInputShape.shape,
|
|
19
19
|
...policyInput.policyScopeInput.shape
|
|
20
20
|
}).and(userScopeInput.userScopeInput).and(ruleGroupInput).transform((ruleInput) => ruleInput);
|
|
21
21
|
const ruleEntryInput = zod.z.object({
|
|
@@ -23,7 +23,7 @@ const transformAccessRuleRecordIntoRule = (ruleRecord) => (
|
|
|
23
23
|
);
|
|
24
24
|
const transformAccessRuleIntoRecord = (rule) => accessRuleToRecordScheme.parse(rule);
|
|
25
25
|
const accessRuleToRecordScheme = zod.z.object({
|
|
26
|
-
...policyInput.
|
|
26
|
+
...policyInput.accessPolicyInputShape.shape,
|
|
27
27
|
...policyInput.policyScopeInput.shape,
|
|
28
28
|
...userScopeInput.userScopeSchema.shape,
|
|
29
29
|
groupId: zod.z.coerce.string().optional()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { type AccessPolicy, AccessPolicyType } from "#policy/rule.js";
|
|
3
|
-
export declare const
|
|
3
|
+
export declare const accessPolicyInputShape: z.ZodObject<{
|
|
4
4
|
type: z.ZodNativeEnum<typeof AccessPolicyType>;
|
|
5
5
|
captchaType: z.ZodOptional<z.ZodNativeEnum<typeof import("@prosopo/types").CaptchaType>>;
|
|
6
6
|
description: z.ZodOptional<z.ZodString>;
|
|
@@ -31,6 +31,57 @@ export declare const accessPolicyInput: z.ZodObject<{
|
|
|
31
31
|
frictionlessScore?: number | undefined;
|
|
32
32
|
deferToVerify?: unknown;
|
|
33
33
|
}>;
|
|
34
|
+
export declare const accessPolicyInput: z.ZodEffects<z.ZodObject<{
|
|
35
|
+
type: z.ZodNativeEnum<typeof AccessPolicyType>;
|
|
36
|
+
captchaType: z.ZodOptional<z.ZodNativeEnum<typeof import("@prosopo/types").CaptchaType>>;
|
|
37
|
+
description: z.ZodOptional<z.ZodString>;
|
|
38
|
+
solvedImagesCount: z.ZodOptional<z.ZodNumber>;
|
|
39
|
+
imageThreshold: z.ZodOptional<z.ZodNumber>;
|
|
40
|
+
powDifficulty: z.ZodOptional<z.ZodNumber>;
|
|
41
|
+
unsolvedImagesCount: z.ZodOptional<z.ZodNumber>;
|
|
42
|
+
frictionlessScore: z.ZodOptional<z.ZodNumber>;
|
|
43
|
+
deferToVerify: z.ZodOptional<z.ZodEffects<z.ZodBoolean, boolean, unknown>>;
|
|
44
|
+
}, "strip", z.ZodTypeAny, {
|
|
45
|
+
type: AccessPolicyType;
|
|
46
|
+
captchaType?: import("@prosopo/types").CaptchaType | undefined;
|
|
47
|
+
description?: string | undefined;
|
|
48
|
+
solvedImagesCount?: number | undefined;
|
|
49
|
+
imageThreshold?: number | undefined;
|
|
50
|
+
powDifficulty?: number | undefined;
|
|
51
|
+
unsolvedImagesCount?: number | undefined;
|
|
52
|
+
frictionlessScore?: number | undefined;
|
|
53
|
+
deferToVerify?: boolean | undefined;
|
|
54
|
+
}, {
|
|
55
|
+
type: AccessPolicyType;
|
|
56
|
+
captchaType?: import("@prosopo/types").CaptchaType | undefined;
|
|
57
|
+
description?: string | undefined;
|
|
58
|
+
solvedImagesCount?: number | undefined;
|
|
59
|
+
imageThreshold?: number | undefined;
|
|
60
|
+
powDifficulty?: number | undefined;
|
|
61
|
+
unsolvedImagesCount?: number | undefined;
|
|
62
|
+
frictionlessScore?: number | undefined;
|
|
63
|
+
deferToVerify?: unknown;
|
|
64
|
+
}>, {
|
|
65
|
+
type: AccessPolicyType;
|
|
66
|
+
captchaType?: import("@prosopo/types").CaptchaType | undefined;
|
|
67
|
+
description?: string | undefined;
|
|
68
|
+
solvedImagesCount?: number | undefined;
|
|
69
|
+
imageThreshold?: number | undefined;
|
|
70
|
+
powDifficulty?: number | undefined;
|
|
71
|
+
unsolvedImagesCount?: number | undefined;
|
|
72
|
+
frictionlessScore?: number | undefined;
|
|
73
|
+
deferToVerify?: boolean | undefined;
|
|
74
|
+
}, {
|
|
75
|
+
type: AccessPolicyType;
|
|
76
|
+
captchaType?: import("@prosopo/types").CaptchaType | undefined;
|
|
77
|
+
description?: string | undefined;
|
|
78
|
+
solvedImagesCount?: number | undefined;
|
|
79
|
+
imageThreshold?: number | undefined;
|
|
80
|
+
powDifficulty?: number | undefined;
|
|
81
|
+
unsolvedImagesCount?: number | undefined;
|
|
82
|
+
frictionlessScore?: number | undefined;
|
|
83
|
+
deferToVerify?: unknown;
|
|
84
|
+
}>;
|
|
34
85
|
export declare const sanitizeAccessPolicy: (policy: AccessPolicy) => AccessPolicy;
|
|
35
86
|
export declare const policyScopeInput: z.ZodObject<{
|
|
36
87
|
clientId: z.ZodEffects<z.ZodOptional<z.ZodString>, string | undefined, unknown>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"policyInput.d.ts","sourceRoot":"","sources":["../../src/ruleInput/policyInput.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EACN,KAAK,YAAY,EACjB,gBAAgB,EAGhB,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"policyInput.d.ts","sourceRoot":"","sources":["../../src/ruleInput/policyInput.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EACN,KAAK,YAAY,EACjB,gBAAgB,EAGhB,MAAM,iBAAiB,CAAC;AAwBzB,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoBD,CAAC;AAEnC,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoB7B,CAAC;AAOF,eAAO,MAAM,oBAAoB,WAAY,YAAY,KAAG,YAM3D,CAAC;AAOF,eAAO,MAAM,gBAAgB;;;;;;EAUI,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { CaptchaTypeSchema } from "@prosopo/types";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { AccessPolicyType, GLOBAL_CLIENT_SCOPE_SENTINEL } from "../rule.js";
|
|
4
|
-
const
|
|
4
|
+
const accessPolicyInputShape = z.object({
|
|
5
5
|
type: z.nativeEnum(AccessPolicyType),
|
|
6
6
|
captchaType: CaptchaTypeSchema.optional(),
|
|
7
7
|
description: z.coerce.string().optional(),
|
|
@@ -20,6 +20,25 @@ const accessPolicyInput = z.object({
|
|
|
20
20
|
// round-trip to the JS boolean the matcher expects.
|
|
21
21
|
deferToVerify: z.preprocess((v) => typeof v === "string" ? v === "true" : v, z.boolean()).optional()
|
|
22
22
|
});
|
|
23
|
+
const accessPolicyInput = accessPolicyInputShape.superRefine(
|
|
24
|
+
(policy, ctx) => {
|
|
25
|
+
if (policy.type !== AccessPolicyType.Block) return;
|
|
26
|
+
if (policy.captchaType !== void 0) {
|
|
27
|
+
ctx.addIssue({
|
|
28
|
+
code: z.ZodIssueCode.custom,
|
|
29
|
+
path: ["captchaType"],
|
|
30
|
+
message: "Block policies cannot pin a captchaType — Block always applies to every captcha type. Use a Restrict policy if you want to narrow the effect to one captcha type."
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
if (policy.solvedImagesCount !== void 0) {
|
|
34
|
+
ctx.addIssue({
|
|
35
|
+
code: z.ZodIssueCode.custom,
|
|
36
|
+
path: ["solvedImagesCount"],
|
|
37
|
+
message: "Block policies cannot set solvedImagesCount — the field only applies to Restrict policies that adjust image-captcha rounds."
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
);
|
|
23
42
|
const sanitizeAccessPolicy = (policy) => {
|
|
24
43
|
if (policy.type === AccessPolicyType.Block) {
|
|
25
44
|
const { captchaType, solvedImagesCount, ...blockPolicy } = policy;
|
|
@@ -40,6 +59,7 @@ const policyScopeInput = z.object({
|
|
|
40
59
|
});
|
|
41
60
|
export {
|
|
42
61
|
accessPolicyInput,
|
|
62
|
+
accessPolicyInputShape,
|
|
43
63
|
policyScopeInput,
|
|
44
64
|
sanitizeAccessPolicy
|
|
45
65
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"policyInput.js","sourceRoot":"","sources":["../../src/ruleInput/policyInput.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAEN,gBAAgB,EAChB,4BAA4B,GAE5B,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"policyInput.js","sourceRoot":"","sources":["../../src/ruleInput/policyInput.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAEN,gBAAgB,EAChB,4BAA4B,GAE5B,MAAM,iBAAiB,CAAC;AAwBzB,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9C,IAAI,EAAE,CAAC,CAAC,UAAU,CAAC,gBAAgB,CAAC;IACpC,WAAW,EAAE,iBAAiB,CAAC,QAAQ,EAAE;IACzC,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAEzC,iBAAiB,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAE/C,cAAc,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAE5C,aAAa,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAE3C,mBAAmB,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAEjD,iBAAiB,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAI/C,aAAa,EAAE,CAAC;SACd,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;SAC1E,QAAQ,EAAE;CACoB,CAAC,CAAC;AAEnC,MAAM,CAAC,MAAM,iBAAiB,GAAG,sBAAsB,CAAC,WAAW,CAClE,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE;IACf,IAAI,MAAM,CAAC,IAAI,KAAK,gBAAgB,CAAC,KAAK;QAAE,OAAO;IACnD,IAAI,MAAM,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;QACtC,GAAG,CAAC,QAAQ,CAAC;YACZ,IAAI,EAAE,CAAC,CAAC,YAAY,CAAC,MAAM;YAC3B,IAAI,EAAE,CAAC,aAAa,CAAC;YACrB,OAAO,EACN,mKAAmK;SACpK,CAAC,CAAC;IACJ,CAAC;IACD,IAAI,MAAM,CAAC,iBAAiB,KAAK,SAAS,EAAE,CAAC;QAC5C,GAAG,CAAC,QAAQ,CAAC;YACZ,IAAI,EAAE,CAAC,CAAC,YAAY,CAAC,MAAM;YAC3B,IAAI,EAAE,CAAC,mBAAmB,CAAC;YAC3B,OAAO,EACN,6HAA6H;SAC9H,CAAC,CAAC;IACJ,CAAC;AACF,CAAC,CACD,CAAC;AAOF,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,MAAoB,EAAgB,EAAE;IAC1E,IAAI,MAAM,CAAC,IAAI,KAAK,gBAAgB,CAAC,KAAK,EAAE,CAAC;QAC5C,MAAM,EAAE,WAAW,EAAE,iBAAiB,EAAE,GAAG,WAAW,EAAE,GAAG,MAAM,CAAC;QAClE,OAAO,WAAW,CAAC;IACpB,CAAC;IACD,OAAO,MAAM,CAAC;AACf,CAAC,CAAC;AAOF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IAMxC,QAAQ,EAAE,CAAC,CAAC,UAAU,CACrB,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,4BAA4B,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,EAC3D,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAC5B;CAC8B,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ruleInput.d.ts","sourceRoot":"","sources":["../../src/ruleInput/ruleInput.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,KAAK,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACtC,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC7E,OAAO,EACN,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,gBAAgB,EAChB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,KAAK,cAAc,EAAkB,MAAM,qBAAqB,CAAC;AAE1E,KAAK,cAAc,GAAG;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,YAAY,GACzC,WAAW,GACX,cAAc,GACd,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"ruleInput.d.ts","sourceRoot":"","sources":["../../src/ruleInput/ruleInput.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,KAAK,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACtC,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC7E,OAAO,EACN,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,gBAAgB,EAChB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,KAAK,cAAc,EAAkB,MAAM,qBAAqB,CAAC;AAE1E,KAAK,cAAc,GAAG;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,YAAY,GACzC,WAAW,GACX,cAAc,GACd,cAAc,CAAC;AA6BhB,eAAO,MAAM,eAAe,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,OAAO,CAOL,CAAC;AAEnE,eAAO,MAAM,cAAc,EAAE,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC,UAAU,EAAE,OAAO,CAIrC,CAAC;AAEvC,MAAM,MAAM,sBAAsB,GAAG,iBAAiB,GAAG;IACxD,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B,YAAY,CAAC,EAAE,WAAW,EAAE,CAAC;CAC7B,CAAC;AAQF,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAYS,CAAC;AAE7C,eAAO,MAAM,6BAA6B,gBAC5B,sBAAsB,KACjC,iBAAiB,EAiBnB,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { FilterScopeMatch } from "../rulesStorage.js";
|
|
3
|
-
import { policyScopeInput,
|
|
3
|
+
import { policyScopeInput, accessPolicyInputShape } from "./policyInput.js";
|
|
4
4
|
import { userScopeInput } from "./userScopeInput.js";
|
|
5
5
|
const ruleGroupInput = z.object({
|
|
6
6
|
groupId: z.coerce.string().optional(),
|
|
@@ -13,7 +13,7 @@ const ruleGroupInput = z.object({
|
|
|
13
13
|
return ruleGroup;
|
|
14
14
|
});
|
|
15
15
|
const accessRuleInput = z.object({
|
|
16
|
-
...
|
|
16
|
+
...accessPolicyInputShape.shape,
|
|
17
17
|
...policyScopeInput.shape
|
|
18
18
|
}).and(userScopeInput).and(ruleGroupInput).transform((ruleInput) => ruleInput);
|
|
19
19
|
const ruleEntryInput = z.object({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ruleInput.js","sourceRoot":"","sources":["../../src/ruleInput/ruleInput.ts"],"names":[],"mappings":"AAeA,OAAO,EAAgB,CAAC,EAAE,MAAM,KAAK,CAAC;AAEtC,OAAO,EAGN,gBAAgB,GAChB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"ruleInput.js","sourceRoot":"","sources":["../../src/ruleInput/ruleInput.ts"],"names":[],"mappings":"AAeA,OAAO,EAAgB,CAAC,EAAE,MAAM,KAAK,CAAC;AAEtC,OAAO,EAGN,gBAAgB,GAChB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAC5E,OAAO,EAAuB,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAY1E,MAAM,cAAc,GAAG,CAAC;KACtB,MAAM,CAAC;IACP,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACrC,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACP,CAAC;KACnC,SAAS,CAAC,CAAC,cAA8B,EAAE,EAAE;IAC7C,MAAM,EAAE,WAAW,EAAE,GAAG,SAAS,EAAE,GAAG,cAAc,CAAC;IAErD,IAAI,QAAQ,KAAK,OAAO,WAAW,EAAE,CAAC;QACrC,SAAS,CAAC,OAAO,GAAG,WAAW,CAAC;IACjC,CAAC;IAED,OAAO,SAAS,CAAC;AAClB,CAAC,CAAC,CAAC;AAcJ,MAAM,CAAC,MAAM,eAAe,GAA+C,CAAC;KAC1E,MAAM,CAAC;IACP,GAAG,sBAAsB,CAAC,KAAK;IAC/B,GAAG,gBAAgB,CAAC,KAAK;CACzB,CAAC;KACD,GAAG,CAAC,cAAc,CAAC;KACnB,GAAG,CAAC,cAAc,CAAC;KACnB,SAAS,CAAC,CAAC,SAA0B,EAAc,EAAE,CAAC,SAAS,CAAC,CAAC;AAEnE,MAAM,CAAC,MAAM,cAAc,GAC1B,CAAC,CAAC,MAAM,CAAC;IACR,IAAI,EAAE,eAAe;IACrB,oBAAoB,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACf,CAAC,CAAC;AAavC,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9C,WAAW,EAAE,gBAAgB,CAAC,QAAQ,EAAE;IACxC,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,QAAQ,EAAE;IAClD,gBAAgB,EAAE,CAAC;SACjB,UAAU,CAAC,gBAAgB,CAAC;SAC5B,OAAO,CAAC,gBAAgB,CAAC,KAAK,CAAC;IACjC,SAAS,EAAE,cAAc,CAAC,QAAQ,EAAE;IACpC,cAAc,EAAE,CAAC;SACf,UAAU,CAAC,gBAAgB,CAAC;SAC5B,OAAO,CAAC,gBAAgB,CAAC,KAAK,CAAC;IACjC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC9B,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;CACS,CAAC,CAAC;AAE7C,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAC5C,WAAmC,EACb,EAAE;IACxB,MAAM,EAAE,YAAY,EAAE,WAAW,EAAE,GAAG,UAAU,EAAE,GAAG,WAAW,CAAC;IAEjE,MAAM,eAAe,GAAG,YAAY,IAAI,EAAE,CAAC;IAE3C,IAAI,WAAW,EAAE,CAAC;QACjB,eAAe,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACnC,CAAC;IAED,IAAI,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChC,OAAO,eAAe,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;YAC5C,GAAG,UAAU;YACb,WAAW;SACX,CAAC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,CAAC,UAAU,CAAC,CAAC;AACrB,CAAC,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { CaptchaType } from "@prosopo/types";
|
|
2
2
|
import { describe, expect, it } from "vitest";
|
|
3
3
|
import { AccessPolicyType } from "#policy/rule.js";
|
|
4
|
-
import { sanitizeAccessPolicy } from "#policy/ruleInput/policyInput.js";
|
|
4
|
+
import { accessPolicyInput, sanitizeAccessPolicy, } from "#policy/ruleInput/policyInput.js";
|
|
5
5
|
describe("sanitizeAccessPolicy", () => {
|
|
6
6
|
describe("block policies", () => {
|
|
7
7
|
it("should remove captchaType from block policies", () => {
|
|
@@ -113,4 +113,53 @@ describe("sanitizeAccessPolicy", () => {
|
|
|
113
113
|
});
|
|
114
114
|
});
|
|
115
115
|
});
|
|
116
|
+
describe("accessPolicyInput refinement", () => {
|
|
117
|
+
it("rejects Block + captchaType with a clear message pointing at Restrict", () => {
|
|
118
|
+
const result = accessPolicyInput.safeParse({
|
|
119
|
+
type: AccessPolicyType.Block,
|
|
120
|
+
captchaType: CaptchaType.image,
|
|
121
|
+
});
|
|
122
|
+
expect(result.success).toBe(false);
|
|
123
|
+
if (!result.success) {
|
|
124
|
+
const issue = result.error.issues.find((i) => i.path.includes("captchaType"));
|
|
125
|
+
expect(issue).toBeDefined();
|
|
126
|
+
expect(issue?.message).toMatch(/Block policies cannot pin a captchaType/);
|
|
127
|
+
expect(issue?.message).toMatch(/Restrict policy/);
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
it("rejects Block + solvedImagesCount", () => {
|
|
131
|
+
const result = accessPolicyInput.safeParse({
|
|
132
|
+
type: AccessPolicyType.Block,
|
|
133
|
+
solvedImagesCount: 3,
|
|
134
|
+
});
|
|
135
|
+
expect(result.success).toBe(false);
|
|
136
|
+
if (!result.success) {
|
|
137
|
+
const issue = result.error.issues.find((i) => i.path.includes("solvedImagesCount"));
|
|
138
|
+
expect(issue).toBeDefined();
|
|
139
|
+
expect(issue?.message).toMatch(/Block policies cannot set solvedImagesCount/);
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
it("accepts Block without the disallowed fields", () => {
|
|
143
|
+
const result = accessPolicyInput.safeParse({
|
|
144
|
+
type: AccessPolicyType.Block,
|
|
145
|
+
description: "clean block",
|
|
146
|
+
});
|
|
147
|
+
expect(result.success).toBe(true);
|
|
148
|
+
});
|
|
149
|
+
it("accepts Block + deferToVerify (deferToVerify is orthogonal to the type-pin restriction)", () => {
|
|
150
|
+
const result = accessPolicyInput.safeParse({
|
|
151
|
+
type: AccessPolicyType.Block,
|
|
152
|
+
deferToVerify: true,
|
|
153
|
+
});
|
|
154
|
+
expect(result.success).toBe(true);
|
|
155
|
+
});
|
|
156
|
+
it("accepts Restrict + captchaType + solvedImagesCount (these are Restrict's whole point)", () => {
|
|
157
|
+
const result = accessPolicyInput.safeParse({
|
|
158
|
+
type: AccessPolicyType.Restrict,
|
|
159
|
+
captchaType: CaptchaType.image,
|
|
160
|
+
solvedImagesCount: 5,
|
|
161
|
+
});
|
|
162
|
+
expect(result.success).toBe(true);
|
|
163
|
+
});
|
|
164
|
+
});
|
|
116
165
|
//# sourceMappingURL=policyInput.unit.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"policyInput.unit.test.js","sourceRoot":"","sources":["../../src/tests/policyInput.unit.test.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,
|
|
1
|
+
{"version":3,"file":"policyInput.unit.test.js","sourceRoot":"","sources":["../../src/tests/policyInput.unit.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -95,6 +95,27 @@ describe("redisAccessRulesStorage", () => {
|
|
|
95
95
|
expect(recordExpirySeconds).toBeLessThanOrEqual(expirationTimestampInSeconds);
|
|
96
96
|
expect(indexRecordsCount).toBe(1);
|
|
97
97
|
});
|
|
98
|
+
test("expired rule is no longer returned by the reader after its TTL fires", async () => {
|
|
99
|
+
const accessRule = {
|
|
100
|
+
type: AccessPolicyType.Block,
|
|
101
|
+
clientId: `expiring-${getUniqueString()}`,
|
|
102
|
+
};
|
|
103
|
+
const ruleKey = getAccessRuleRedisKey(accessRule);
|
|
104
|
+
const expirationTimestampInSeconds = Math.floor(Date.now() / 1000) + 2;
|
|
105
|
+
await accessRulesWriter.insertRules([
|
|
106
|
+
{
|
|
107
|
+
rule: accessRule,
|
|
108
|
+
expiresUnixTimestamp: expirationTimestampInSeconds,
|
|
109
|
+
},
|
|
110
|
+
]);
|
|
111
|
+
const initialRecord = await redisClient.hGetAll(ruleKey);
|
|
112
|
+
expect(initialRecord).toEqual(accessRule);
|
|
113
|
+
await new Promise((resolve) => setTimeout(resolve, 3500));
|
|
114
|
+
const expiredRecord = await redisClient.hGetAll(ruleKey);
|
|
115
|
+
expect(expiredRecord).toEqual({});
|
|
116
|
+
const indexRecordsCount = await getIndexRecordsCount(indexName);
|
|
117
|
+
expect(indexRecordsCount).toBe(0);
|
|
118
|
+
}, 10_000);
|
|
98
119
|
test("deletes rules", async () => {
|
|
99
120
|
const johnAccessRule = {
|
|
100
121
|
type: AccessPolicyType.Block,
|