@prosopo/user-access-policy 3.12.32 → 3.13.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 +12 -10
- package/.turbo/turbo-build$colon$tsc.log +14 -14
- package/.turbo/turbo-build.log +13 -11
- package/CHANGELOG.md +91 -0
- package/dist/.export.d.ts +2 -0
- package/dist/.export.d.ts.map +1 -1
- package/dist/.export.js +3 -1
- package/dist/.export.js.map +1 -1
- package/dist/cjs/.export.cjs +11 -0
- package/dist/cjs/classifyBrowser.cjs +44 -0
- package/dist/cjs/headerMatch.cjs +122 -0
- package/dist/cjs/mongoose/mongooseRuleSchema.cjs +20 -0
- package/dist/cjs/redis/reader/redisRulesReader.cjs +8 -0
- package/dist/cjs/redis/reader/redisRulesSplitQuery.cjs +3 -1
- package/dist/cjs/redis/redisRuleIndex.cjs +20 -0
- package/dist/cjs/ruleInput/userScopeInput.cjs +6 -1
- package/dist/cjs/ruleRecord.cjs +6 -1
- package/dist/classifyBrowser.d.ts +4 -0
- package/dist/classifyBrowser.d.ts.map +1 -0
- package/dist/classifyBrowser.js +43 -0
- package/dist/classifyBrowser.js.map +1 -0
- package/dist/headerMatch.d.ts +13 -0
- package/dist/headerMatch.d.ts.map +1 -0
- package/dist/headerMatch.js +116 -0
- package/dist/headerMatch.js.map +1 -0
- package/dist/mongoose/mongooseRuleSchema.d.ts.map +1 -1
- package/dist/mongoose/mongooseRuleSchema.js +20 -0
- package/dist/mongoose/mongooseRuleSchema.js.map +1 -1
- package/dist/redis/reader/redisRulesReader.d.ts.map +1 -1
- package/dist/redis/reader/redisRulesReader.js +8 -0
- package/dist/redis/reader/redisRulesReader.js.map +1 -1
- package/dist/redis/reader/redisRulesSplitQuery.d.ts.map +1 -1
- package/dist/redis/reader/redisRulesSplitQuery.js +3 -1
- package/dist/redis/reader/redisRulesSplitQuery.js.map +1 -1
- package/dist/redis/redisRuleIndex.d.ts.map +1 -1
- package/dist/redis/redisRuleIndex.js +20 -0
- package/dist/redis/redisRuleIndex.js.map +1 -1
- package/dist/rule.d.ts +5 -0
- package/dist/rule.d.ts.map +1 -1
- package/dist/ruleInput/ruleInput.d.ts +30 -0
- package/dist/ruleInput/ruleInput.d.ts.map +1 -1
- package/dist/ruleInput/userScopeInput.d.ts +40 -0
- package/dist/ruleInput/userScopeInput.d.ts.map +1 -1
- package/dist/ruleInput/userScopeInput.js +6 -1
- package/dist/ruleInput/userScopeInput.js.map +1 -1
- package/dist/ruleRecord.d.ts +2 -2
- package/dist/ruleRecord.d.ts.map +1 -1
- package/dist/ruleRecord.js +6 -1
- package/dist/ruleRecord.js.map +1 -1
- package/dist/tests/classifyBrowser.unit.test.d.ts +2 -0
- package/dist/tests/classifyBrowser.unit.test.d.ts.map +1 -0
- package/dist/tests/classifyBrowser.unit.test.js +99 -0
- package/dist/tests/classifyBrowser.unit.test.js.map +1 -0
- package/dist/tests/headerMatch.unit.test.d.ts +2 -0
- package/dist/tests/headerMatch.unit.test.d.ts.map +1 -0
- package/dist/tests/headerMatch.unit.test.js +202 -0
- package/dist/tests/headerMatch.unit.test.js.map +1 -0
- package/dist/tests/redis/reader/redisRulesQuery.unit.test.js +3 -3
- package/dist/tests/redis/reader/redisRulesQuery.unit.test.js.map +1 -1
- package/dist/tests/redis/reader/redisRulesSplitQuery.unit.test.js +9 -0
- package/dist/tests/redis/reader/redisRulesSplitQuery.unit.test.js.map +1 -1
- package/dist/tests/transformRule.unit.test.js +5 -0
- package/dist/tests/transformRule.unit.test.js.map +1 -1
- package/package.json +14 -14
- package/src/.export.ts +17 -0
- package/src/classifyBrowser.ts +77 -0
- package/src/headerMatch.ts +180 -0
- package/src/mongoose/mongooseRuleSchema.ts +5 -0
- package/src/redis/reader/redisRulesReader.ts +10 -0
- package/src/redis/reader/redisRulesSplitQuery.ts +2 -0
- package/src/redis/redisRuleIndex.ts +14 -0
- package/src/rule.ts +14 -0
- package/src/ruleInput/userScopeInput.ts +8 -0
- package/src/ruleRecord.ts +5 -0
- package/src/tests/classifyBrowser.unit.test.ts +138 -0
- package/src/tests/headerMatch.unit.test.ts +350 -0
- package/src/tests/redis/reader/redisRulesQuery.unit.test.ts +3 -3
- package/src/tests/redis/reader/redisRulesSplitQuery.unit.test.ts +17 -0
- package/src/tests/transformRule.unit.test.ts +5 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @prosopo/user-access-policy@3.
|
|
2
|
+
> @prosopo/user-access-policy@3.13.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,7 +33,7 @@ ViteCommonJSConfig: .
|
|
|
33
33
|
[36mvite v8.1.5 [32mbuilding ssr environment for production...[36m[39m
|
|
34
34
|
Bundle build started
|
|
35
35
|
[2K
|
|
36
|
-
✓
|
|
36
|
+
✓ 40 modules transformed.
|
|
37
37
|
rendering chunks...
|
|
38
38
|
computing gzip size...
|
|
39
39
|
dist/cjs/api/accessRulesApiClient.cjs 0.00 kB │ gzip: 0.02 kB
|
|
@@ -47,32 +47,34 @@ dist/cjs/rule.cjs 0.45 kB │ gzip: 0.26 kB
|
|
|
47
47
|
dist/cjs/api/.export.cjs 0.53 kB │ gzip: 0.21 kB
|
|
48
48
|
dist/cjs/ruleInput/.export.cjs 0.57 kB │ gzip: 0.20 kB
|
|
49
49
|
dist/cjs/api/delete/deleteAllRules.cjs 0.79 kB │ gzip: 0.41 kB
|
|
50
|
-
dist/cjs/ruleRecord.cjs 0.
|
|
50
|
+
dist/cjs/ruleRecord.cjs 0.90 kB │ gzip: 0.38 kB
|
|
51
51
|
dist/cjs/_virtual/_rolldown/runtime.cjs 1.00 kB │ gzip: 0.50 kB
|
|
52
52
|
dist/cjs/api/read/getMissingIds.cjs 1.12 kB │ gzip: 0.51 kB
|
|
53
53
|
dist/cjs/api/read/fetchRules.cjs 1.22 kB │ gzip: 0.54 kB
|
|
54
54
|
dist/cjs/redis/redisRulesStorage.cjs 1.41 kB │ gzip: 0.49 kB
|
|
55
55
|
dist/cjs/api/delete/deleteRuleGroups.cjs 1.43 kB │ gzip: 0.65 kB
|
|
56
|
+
dist/cjs/classifyBrowser.cjs 1.45 kB │ gzip: 0.73 kB
|
|
56
57
|
dist/cjs/api/write/rehashRules.cjs 1.48 kB │ gzip: 0.56 kB
|
|
57
58
|
dist/cjs/api/delete/deleteRules.cjs 1.52 kB │ gzip: 0.65 kB
|
|
58
|
-
dist/cjs/mongoose/mongooseRuleSchema.cjs 1.52 kB │ gzip: 0.42 kB
|
|
59
59
|
dist/cjs/api/read/findRuleIds.cjs 1.58 kB │ gzip: 0.66 kB
|
|
60
|
-
dist/cjs
|
|
60
|
+
dist/cjs/mongoose/mongooseRuleSchema.cjs 1.79 kB │ gzip: 0.45 kB
|
|
61
61
|
dist/cjs/redis/redisClient.cjs 1.92 kB │ gzip: 0.72 kB
|
|
62
62
|
dist/cjs/classifyOs.cjs 2.04 kB │ gzip: 1.05 kB
|
|
63
63
|
dist/cjs/ruleInput/policyInput.cjs 2.09 kB │ gzip: 0.79 kB
|
|
64
64
|
dist/cjs/ruleInput/ruleInput.cjs 2.28 kB │ gzip: 0.69 kB
|
|
65
65
|
dist/cjs/matchedRule.cjs 2.29 kB │ gzip: 1.03 kB
|
|
66
|
-
dist/cjs
|
|
66
|
+
dist/cjs/.export.cjs 2.44 kB │ gzip: 0.57 kB
|
|
67
67
|
dist/cjs/api/rulesApiClient.cjs 2.53 kB │ gzip: 0.68 kB
|
|
68
68
|
dist/cjs/redis/reader/redisAggregate.cjs 2.57 kB │ gzip: 1.04 kB
|
|
69
|
+
dist/cjs/ruleInput/userScopeInput.cjs 2.67 kB │ gzip: 0.81 kB
|
|
69
70
|
dist/cjs/transformRule.cjs 2.90 kB │ gzip: 1.03 kB
|
|
70
|
-
dist/cjs/redis/redisRuleIndex.cjs 3.12 kB │ gzip: 0.82 kB
|
|
71
71
|
dist/cjs/api/write/insertRules.cjs 3.12 kB │ gzip: 1.09 kB
|
|
72
72
|
dist/cjs/redis/redisRulesWriter.cjs 3.50 kB │ gzip: 1.15 kB
|
|
73
|
+
dist/cjs/redis/redisRuleIndex.cjs 3.55 kB │ gzip: 0.85 kB
|
|
73
74
|
dist/cjs/api/ruleApiRoutes.cjs 4.14 kB │ gzip: 1.06 kB
|
|
74
75
|
dist/cjs/redis/reader/redisRulesQuery.cjs 4.76 kB │ gzip: 1.58 kB
|
|
75
|
-
dist/cjs/redis/reader/redisRulesSplitQuery.cjs 5.
|
|
76
|
-
dist/cjs/
|
|
76
|
+
dist/cjs/redis/reader/redisRulesSplitQuery.cjs 5.17 kB │ gzip: 2.17 kB
|
|
77
|
+
dist/cjs/headerMatch.cjs 5.74 kB │ gzip: 2.25 kB
|
|
78
|
+
dist/cjs/redis/reader/redisRulesReader.cjs 11.85 kB │ gzip: 2.88 kB
|
|
77
79
|
|
|
78
|
-
[32m✓ built in
|
|
80
|
+
[32m✓ built in 116ms[39m
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
|
|
2
|
-
> @prosopo/user-access-policy@3.
|
|
2
|
+
> @prosopo/user-access-policy@3.13.0 build:tsc
|
|
3
3
|
> tsc --build --verbose
|
|
4
4
|
|
|
5
|
-
1:
|
|
5
|
+
1:15:14 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
|
-
1:
|
|
18
|
+
1:15:14 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
|
-
1:
|
|
20
|
+
1:15:14 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
|
-
1:
|
|
22
|
+
1:15:14 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
|
-
1:
|
|
24
|
+
1:15:14 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
|
-
1:
|
|
26
|
+
1:15:14 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
|
-
1:
|
|
28
|
+
1:15:14 PM - Project '../types/tsconfig.json' is up to date because newest input '../types/src/types.test-d.ts' is older than output '../types/tsconfig.tsbuildinfo'
|
|
29
29
|
|
|
30
|
-
1:
|
|
30
|
+
1:15:14 PM - 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
|
-
1:
|
|
32
|
+
1:15:14 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
|
-
1:
|
|
34
|
+
1:15:14 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
|
-
1:
|
|
36
|
+
1:15:14 PM - Project '../api/tsconfig.json' is up to date because newest input '../api/src/tests/apiHarness.ts' is older than output '../api/tsconfig.tsbuildinfo'
|
|
37
37
|
|
|
38
|
-
1:
|
|
38
|
+
1:15:14 PM - Project 'tsconfig.json' is out of date because output file 'tsconfig.tsbuildinfo' does not exist
|
|
39
39
|
|
|
40
|
-
1:
|
|
40
|
+
1:15:14 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.
|
|
2
|
+
> @prosopo/user-access-policy@3.13.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.13.0 build:cross-env
|
|
7
7
|
> vite build --config vite.esm.config.ts --mode production
|
|
8
8
|
|
|
9
9
|
ViteEsmConfig: .
|
|
@@ -37,7 +37,7 @@ ViteEsmConfig: .
|
|
|
37
37
|
[36mvite v8.1.5 [32mbuilding ssr environment for production...[36m[39m
|
|
38
38
|
Bundle build started
|
|
39
39
|
[2K
|
|
40
|
-
✓
|
|
40
|
+
✓ 40 modules transformed.
|
|
41
41
|
rendering chunks...
|
|
42
42
|
computing gzip size...
|
|
43
43
|
dist/_virtual/_rolldown/runtime.js 0.04 kB │ gzip: 0.06 kB
|
|
@@ -51,32 +51,34 @@ dist/rulesStorage.js 0.29 kB │ gzip: 0.19 kB
|
|
|
51
51
|
dist/ruleInput/.export.js 0.30 kB │ gzip: 0.14 kB
|
|
52
52
|
dist/api/.export.js 0.31 kB │ gzip: 0.16 kB
|
|
53
53
|
dist/rule.js 0.36 kB │ gzip: 0.23 kB
|
|
54
|
-
dist/ruleRecord.js 0.66 kB │ gzip: 0.33 kB
|
|
55
54
|
dist/api/delete/deleteAllRules.js 0.73 kB │ gzip: 0.37 kB
|
|
56
|
-
dist
|
|
55
|
+
dist/ruleRecord.js 0.74 kB │ gzip: 0.35 kB
|
|
57
56
|
dist/api/read/getMissingIds.js 1.02 kB │ gzip: 0.48 kB
|
|
58
57
|
dist/api/read/fetchRules.js 1.07 kB │ gzip: 0.49 kB
|
|
59
58
|
dist/redis/redisRulesStorage.js 1.22 kB │ gzip: 0.45 kB
|
|
60
59
|
dist/api/delete/deleteRuleGroups.js 1.32 kB │ gzip: 0.61 kB
|
|
61
60
|
dist/api/delete/deleteRules.js 1.36 kB │ gzip: 0.58 kB
|
|
61
|
+
dist/classifyBrowser.js 1.38 kB │ gzip: 0.71 kB
|
|
62
62
|
dist/api/read/findRuleIds.js 1.39 kB │ gzip: 0.60 kB
|
|
63
63
|
dist/api/write/rehashRules.js 1.42 kB │ gzip: 0.53 kB
|
|
64
|
-
dist
|
|
64
|
+
dist/.export.js 1.43 kB │ gzip: 0.42 kB
|
|
65
|
+
dist/mongoose/mongooseRuleSchema.js 1.74 kB │ gzip: 0.43 kB
|
|
65
66
|
dist/redis/redisClient.js 1.78 kB │ gzip: 0.68 kB
|
|
66
67
|
dist/ruleInput/ruleInput.js 1.80 kB │ gzip: 0.63 kB
|
|
67
68
|
dist/ruleInput/policyInput.js 1.84 kB │ gzip: 0.73 kB
|
|
68
69
|
dist/classifyOs.js 1.98 kB │ gzip: 1.03 kB
|
|
69
|
-
dist/ruleInput/userScopeInput.js 2.09 kB │ gzip: 0.67 kB
|
|
70
70
|
dist/api/rulesApiClient.js 2.12 kB │ gzip: 0.62 kB
|
|
71
71
|
dist/matchedRule.js 2.22 kB │ gzip: 1.00 kB
|
|
72
|
+
dist/ruleInput/userScopeInput.js 2.31 kB │ gzip: 0.70 kB
|
|
72
73
|
dist/redis/reader/redisAggregate.js 2.35 kB │ gzip: 0.99 kB
|
|
73
74
|
dist/transformRule.js 2.40 kB │ gzip: 0.94 kB
|
|
74
|
-
dist/redis/redisRuleIndex.js 2.51 kB │ gzip: 0.74 kB
|
|
75
75
|
dist/api/write/insertRules.js 2.87 kB │ gzip: 1.03 kB
|
|
76
|
+
dist/redis/redisRuleIndex.js 2.87 kB │ gzip: 0.77 kB
|
|
76
77
|
dist/redis/redisRulesWriter.js 3.03 kB │ gzip: 1.07 kB
|
|
77
78
|
dist/api/ruleApiRoutes.js 3.68 kB │ gzip: 0.99 kB
|
|
78
79
|
dist/redis/reader/redisRulesQuery.js 4.53 kB │ gzip: 1.54 kB
|
|
79
|
-
dist/redis/reader/redisRulesSplitQuery.js 4.
|
|
80
|
-
dist/
|
|
80
|
+
dist/redis/reader/redisRulesSplitQuery.js 4.98 kB │ gzip: 2.14 kB
|
|
81
|
+
dist/headerMatch.js 5.51 kB │ gzip: 2.22 kB
|
|
82
|
+
dist/redis/reader/redisRulesReader.js 10.44 kB │ gzip: 2.74 kB
|
|
81
83
|
|
|
82
|
-
[32m✓ built in
|
|
84
|
+
[32m✓ built in 149ms[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,96 @@
|
|
|
1
1
|
# @prosopo/user-access-policy
|
|
2
2
|
|
|
3
|
+
## 3.13.0
|
|
4
|
+
### Minor Changes
|
|
5
|
+
|
|
6
|
+
- e22d5fb: Add an arbitrary-header match dimension to user access policies.
|
|
7
|
+
|
|
8
|
+
A `Block` or `Restrict` rule can now target a named request header with an `equals`, `contains`, `notEquals`, `notContains`, `notEqualsAny` or `notContainsAny` operator. The negated operators back the portal's allow-list mode — block unless the header matches; the `*Any` pair carries a list of accepted values in `headerValue` so an allow-list over several values of the same header fires only when the header matches none of them (separate single-value rules would each fire on the other's value and block everything). Because substring `contains` and per-rule operators can't be expressed as a Redis TAG query — and an allow-list rule must still fire on a request that omits the header — the header condition is carried on the rule as `headerName`/`headerValue`/`headerOperator` and evaluated in code against the raw request headers, while an indexed `headerMatch` sentinel makes every header rule a matching candidate for every request. Header rules contribute one point to rule specificity ranking, mirroring the other scalar dimensions.
|
|
9
|
+
|
|
10
|
+
The raw request headers are a **required** argument of `getPrioritisedAccessRule` / `CaptchaManager.getPrioritisedAccessPolicies`, with no default. A negated header operator treats a missing header as "does not match", so a lookup that quietly ran with an empty header map would fire every allow-list rule on every request. Every lookup now passes them: the request-time block middleware, the verify-path hard-block check, the `/frictionless` policy and dedup lookups, and the image / PoW / puzzle challenge endpoints.
|
|
11
|
+
|
|
12
|
+
`getPrioritisedAccessRule` now caches only the candidate fetch and ranks per request, because the header verdict depends on data that is not part of the cache key. This also closes a latent gap where `os` was never part of `hardBlockCacheKey`, so a cached ranked list could serve one operating system's verdict to a request from another.
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- 6f57ee9: chore(deps): bump yargs from 17.7.2 to 18.1.0
|
|
17
|
+
- 6f57ee9: chore(deps): bump the npm-minor-and-patch group across 1 directory with 3 updates
|
|
18
|
+
- Updated dependencies [6f57ee9]
|
|
19
|
+
- Updated dependencies [d288371]
|
|
20
|
+
- @prosopo/types@5.7.0
|
|
21
|
+
- @prosopo/util@3.3.9
|
|
22
|
+
- @prosopo/api@4.1.6
|
|
23
|
+
- @prosopo/api-route@2.6.58
|
|
24
|
+
- @prosopo/common@3.1.54
|
|
25
|
+
- @prosopo/logger@2.0.9
|
|
26
|
+
- @prosopo/redis-client@1.0.35
|
|
27
|
+
|
|
28
|
+
## 3.12.33
|
|
29
|
+
### Patch Changes
|
|
30
|
+
|
|
31
|
+
- 7fd6eb2: Add a `browser` match dimension to access rules.
|
|
32
|
+
|
|
33
|
+
Rules can now be scoped to the browser classified server-side from the request
|
|
34
|
+
User-Agent (`chrome`, `safari`, `firefox`, `edge`, `opera`, `samsung_internet`,
|
|
35
|
+
`wechat`, `facebook`, `instagram`, `ie`, `unknown`), mirroring the existing `os`
|
|
36
|
+
dimension. The classifier duplicates `@prosopo/decision-machines`' `uaClassify`
|
|
37
|
+
because the provider request path cannot depend on that package.
|
|
38
|
+
|
|
39
|
+
Also fixes `os` never getting its own probe on the Redis split-query hot path:
|
|
40
|
+
`SCALAR_USER_SCOPE_FIELDS` in `redisRulesSplitQuery` had not been updated when
|
|
41
|
+
the OS dimension landed, so an OS-only rule was reachable only via the
|
|
42
|
+
`no-user-scope` fall-through, competing for that probe's candidate budget
|
|
43
|
+
against genuine client-wide blocks.
|
|
44
|
+
|
|
45
|
+
The Redis index gains a `browser` TAG field. `createRedisIndex` hashes the index
|
|
46
|
+
definition and drops/recreates when the hash changes, so this needs no manual
|
|
47
|
+
migration — verified locally: the index came back carrying `browser` and the
|
|
48
|
+
stored hash moved to match.
|
|
49
|
+
- 89dd38a: chore(deps): batch the outstanding dependabot bumps into one upgrade
|
|
50
|
+
|
|
51
|
+
Rolls up dependabot PRs #3112, #3127-#3134 and #3159. Majors: `mongoose`
|
|
52
|
+
8 -> 9, `bson` 6 -> 7, `@noble/curves` 1 -> 2, `@polkadot/util-crypto`
|
|
53
|
+
13 -> 14, `@typegoose/auto-increment` 4 -> 5, `@babel/preset-env` 7 -> 8,
|
|
54
|
+
`@types/jsdom` 21 -> 30, `@types/bcrypt` 5 -> 6, `@actions/github` 6 -> 9,
|
|
55
|
+
`testcontainers` 11 -> 12. The rest are minor/patch.
|
|
56
|
+
|
|
57
|
+
Code changes the majors forced:
|
|
58
|
+
- `@noble/curves` v2 requires `.js` specifiers and renamed the point API,
|
|
59
|
+
so `secp256k1.ProjectivePoint.fromHex(...).toRawBytes()` becomes
|
|
60
|
+
`secp256k1.Point.fromBytes(...).toBytes()`, `RistrettoPoint` becomes
|
|
61
|
+
`ristretto255.Point`, and `abstract/utils` moves to `utils.js`.
|
|
62
|
+
- mongoose 9 drops `RootFilterQuery` (now `QueryFilter`), no longer sets
|
|
63
|
+
`background: true` on schema indexes by default, and no longer declares
|
|
64
|
+
`id` on `Document`, which un-hid a mismatch between
|
|
65
|
+
`updateDappUserCommitment`'s `Hash` parameter and the `string` `id` it
|
|
66
|
+
filters on.
|
|
67
|
+
- mongoose 9 rejects an aggregation-pipeline update (an array) unless the
|
|
68
|
+
call passes `updatePipeline: true`, so the six pipeline writes in
|
|
69
|
+
`ProviderDatabase` now opt in explicitly.
|
|
70
|
+
- mongoose 9's `castUpdate` throws on a `$setOnInsert` key inside `$set`.
|
|
71
|
+
`storeUserImageCaptchaSolution` passed its record straight in as the
|
|
72
|
+
update, and mongoose's `moveImmutableProperties` mutates that object on
|
|
73
|
+
an upsert -- adding the very `$setOnInsert` key the record then carried
|
|
74
|
+
into `CentralDbStreamer.streamImageRecord`. Image records stopped
|
|
75
|
+
reaching the central DB (the streamer is fire-and-forget, so it only
|
|
76
|
+
logged) and signup verification returned 500. The update is now an
|
|
77
|
+
explicit `$set` over a shallow copy.
|
|
78
|
+
- `@prosopo/database` moves from mongodb 6.20 to 7.5 to match the driver
|
|
79
|
+
mongoose 9 pulls, so bson 7 is the only copy resolvable in the package.
|
|
80
|
+
- `vitest`/`@vitest/coverage-v8` go to 4.1.11 alongside dependabot's
|
|
81
|
+
`@vitest/spy` bump; leaving them at 4.1.10 installed a second copy of
|
|
82
|
+
`@vitest/spy` and broke type inference in the provider test utils.
|
|
83
|
+
- Updated dependencies [89dd38a]
|
|
84
|
+
- Updated dependencies [80f73c1]
|
|
85
|
+
- Updated dependencies [8a670d3]
|
|
86
|
+
- @prosopo/api@4.1.5
|
|
87
|
+
- @prosopo/api-route@2.6.57
|
|
88
|
+
- @prosopo/common@3.1.53
|
|
89
|
+
- @prosopo/logger@2.0.8
|
|
90
|
+
- @prosopo/redis-client@1.0.34
|
|
91
|
+
- @prosopo/types@5.6.0
|
|
92
|
+
- @prosopo/util@3.3.8
|
|
93
|
+
|
|
3
94
|
## 3.12.32
|
|
4
95
|
### Patch Changes
|
|
5
96
|
|
package/dist/.export.d.ts
CHANGED
|
@@ -3,6 +3,8 @@ export { makeAccessRuleHash, transformAccessRuleRecordIntoRule, transformAccessR
|
|
|
3
3
|
export { type AccessRule, type AccessPolicy, type PolicyScope, type UserScope, AccessPolicyType, } from "./rule.js";
|
|
4
4
|
export { describeMatchedRule } from "./matchedRule.js";
|
|
5
5
|
export { classifyOs, OS_NAMES, type OsName } from "./classifyOs.js";
|
|
6
|
+
export { classifyBrowser, BROWSER_NAMES, type BrowserName, } from "./classifyBrowser.js";
|
|
7
|
+
export { HEADER_OPERATORS, type HeaderOperator, HEADER_RULE_MARKER, isHeaderOperator, evaluateHeaderCondition, accessRuleHeaderMatches, encodeHeaderValueList, decodeHeaderValueList, } from "./headerMatch.js";
|
|
6
8
|
export { type AccessRulesFilter, type AccessRulesStorage, type AccessRuleEntry, FilterScopeMatch, } from "./rulesStorage.js";
|
|
7
9
|
export { type AccessRuleRecord, type UserScopeRecord, type UserScopeRecordField, userScopeRecordFields, getUserScopeRecordFromAccessRuleRecord, } from "./ruleRecord.js";
|
|
8
10
|
//# sourceMappingURL=.export.d.ts.map
|
package/dist/.export.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":".export.d.ts","sourceRoot":"","sources":["../src/.export.ts"],"names":[],"mappings":"AAcA,cAAc,wBAAwB,CAAC;AAEvC,OAAO,EACN,kBAAkB,EAClB,iCAAiC,EACjC,6BAA6B,GAC7B,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACN,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,gBAAgB,GAChB,MAAM,WAAW,CAAC;AAEnB,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEpE,OAAO,EACN,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,gBAAgB,GAChB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACN,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,oBAAoB,EACzB,qBAAqB,EACrB,sCAAsC,GACtC,MAAM,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":".export.d.ts","sourceRoot":"","sources":["../src/.export.ts"],"names":[],"mappings":"AAcA,cAAc,wBAAwB,CAAC;AAEvC,OAAO,EACN,kBAAkB,EAClB,iCAAiC,EACjC,6BAA6B,GAC7B,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACN,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,gBAAgB,GAChB,MAAM,WAAW,CAAC;AAEnB,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEpE,OAAO,EACN,eAAe,EACf,aAAa,EACb,KAAK,WAAW,GAChB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACN,gBAAgB,EAChB,KAAK,cAAc,EACnB,kBAAkB,EAClB,gBAAgB,EAChB,uBAAuB,EACvB,uBAAuB,EACvB,qBAAqB,EACrB,qBAAqB,GACrB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACN,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,gBAAgB,GAChB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACN,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,oBAAoB,EACzB,qBAAqB,EACrB,sCAAsC,GACtC,MAAM,iBAAiB,CAAC"}
|
package/dist/.export.js
CHANGED
|
@@ -8,4 +8,6 @@ import { makeAccessRuleHash, transformAccessRuleIntoRecord, transformAccessRuleR
|
|
|
8
8
|
import { getUserScopeRecordFromAccessRuleRecord, userScopeRecordFields } from "./ruleRecord.js";
|
|
9
9
|
import { describeMatchedRule } from "./matchedRule.js";
|
|
10
10
|
import { OS_NAMES, classifyOs } from "./classifyOs.js";
|
|
11
|
-
|
|
11
|
+
import { BROWSER_NAMES, classifyBrowser } from "./classifyBrowser.js";
|
|
12
|
+
import { HEADER_OPERATORS, HEADER_RULE_MARKER, accessRuleHeaderMatches, decodeHeaderValueList, encodeHeaderValueList, evaluateHeaderCondition, isHeaderOperator } from "./headerMatch.js";
|
|
13
|
+
export { AccessPolicyType, BROWSER_NAMES, FilterScopeMatch, HEADER_OPERATORS, HEADER_RULE_MARKER, OS_NAMES, accessPolicyInput, accessRuleHeaderMatches, accessRuleInput, classifyBrowser, classifyOs, decodeHeaderValueList, describeMatchedRule, encodeHeaderValueList, evaluateHeaderCondition, getUserScopeRecordFromAccessRuleRecord, isHeaderOperator, makeAccessRuleHash, policyScopeInput, transformAccessRuleIntoRecord, transformAccessRuleRecordIntoRule, userScopeInput, userScopeRecordFields };
|
package/dist/.export.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":".export.js","sourceRoot":"","sources":["../src/.export.ts"],"names":[],"mappings":"AAcA,cAAc,wBAAwB,CAAC;AAEvC,OAAO,EACN,kBAAkB,EAClB,iCAAiC,EACjC,6BAA6B,GAC7B,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAKN,gBAAgB,GAChB,MAAM,WAAW,CAAC;AAEnB,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAe,MAAM,iBAAiB,CAAC;AAEpE,OAAO,EAIN,gBAAgB,GAChB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAIN,qBAAqB,EACrB,sCAAsC,GACtC,MAAM,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":".export.js","sourceRoot":"","sources":["../src/.export.ts"],"names":[],"mappings":"AAcA,cAAc,wBAAwB,CAAC;AAEvC,OAAO,EACN,kBAAkB,EAClB,iCAAiC,EACjC,6BAA6B,GAC7B,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAKN,gBAAgB,GAChB,MAAM,WAAW,CAAC;AAEnB,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAe,MAAM,iBAAiB,CAAC;AAEpE,OAAO,EACN,eAAe,EACf,aAAa,GAEb,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACN,gBAAgB,EAEhB,kBAAkB,EAClB,gBAAgB,EAChB,uBAAuB,EACvB,uBAAuB,EACvB,qBAAqB,EACrB,qBAAqB,GACrB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAIN,gBAAgB,GAChB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAIN,qBAAqB,EACrB,sCAAsC,GACtC,MAAM,iBAAiB,CAAC"}
|
package/dist/cjs/.export.cjs
CHANGED
|
@@ -8,14 +8,25 @@ const require_transformRule = require("./transformRule.cjs");
|
|
|
8
8
|
const require_ruleRecord = require("./ruleRecord.cjs");
|
|
9
9
|
const require_matchedRule = require("./matchedRule.cjs");
|
|
10
10
|
const require_classifyOs = require("./classifyOs.cjs");
|
|
11
|
+
const require_classifyBrowser = require("./classifyBrowser.cjs");
|
|
12
|
+
const require_headerMatch = require("./headerMatch.cjs");
|
|
11
13
|
exports.AccessPolicyType = require_rule.AccessPolicyType;
|
|
14
|
+
exports.BROWSER_NAMES = require_classifyBrowser.BROWSER_NAMES;
|
|
12
15
|
exports.FilterScopeMatch = require_rulesStorage.FilterScopeMatch;
|
|
16
|
+
exports.HEADER_OPERATORS = require_headerMatch.HEADER_OPERATORS;
|
|
17
|
+
exports.HEADER_RULE_MARKER = require_headerMatch.HEADER_RULE_MARKER;
|
|
13
18
|
exports.OS_NAMES = require_classifyOs.OS_NAMES;
|
|
14
19
|
exports.accessPolicyInput = require_ruleInput_policyInput.accessPolicyInput;
|
|
20
|
+
exports.accessRuleHeaderMatches = require_headerMatch.accessRuleHeaderMatches;
|
|
15
21
|
exports.accessRuleInput = require_ruleInput_ruleInput.accessRuleInput;
|
|
22
|
+
exports.classifyBrowser = require_classifyBrowser.classifyBrowser;
|
|
16
23
|
exports.classifyOs = require_classifyOs.classifyOs;
|
|
24
|
+
exports.decodeHeaderValueList = require_headerMatch.decodeHeaderValueList;
|
|
17
25
|
exports.describeMatchedRule = require_matchedRule.describeMatchedRule;
|
|
26
|
+
exports.encodeHeaderValueList = require_headerMatch.encodeHeaderValueList;
|
|
27
|
+
exports.evaluateHeaderCondition = require_headerMatch.evaluateHeaderCondition;
|
|
18
28
|
exports.getUserScopeRecordFromAccessRuleRecord = require_ruleRecord.getUserScopeRecordFromAccessRuleRecord;
|
|
29
|
+
exports.isHeaderOperator = require_headerMatch.isHeaderOperator;
|
|
19
30
|
exports.makeAccessRuleHash = require_transformRule.makeAccessRuleHash;
|
|
20
31
|
exports.policyScopeInput = require_ruleInput_policyInput.policyScopeInput;
|
|
21
32
|
exports.transformAccessRuleIntoRecord = require_transformRule.transformAccessRuleIntoRecord;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
//#region src/classifyBrowser.ts
|
|
3
|
+
/**
|
|
4
|
+
* Kept in step with `@prosopo/decision-machines`' `uaClassify` — as `classifyOs`
|
|
5
|
+
* is — but defined here because the provider request path cannot depend on that
|
|
6
|
+
* package.
|
|
7
|
+
*/
|
|
8
|
+
var BROWSER_NAMES = [
|
|
9
|
+
"chrome",
|
|
10
|
+
"safari",
|
|
11
|
+
"firefox",
|
|
12
|
+
"edge",
|
|
13
|
+
"opera",
|
|
14
|
+
"samsung_internet",
|
|
15
|
+
"wechat",
|
|
16
|
+
"facebook",
|
|
17
|
+
"instagram",
|
|
18
|
+
"ie",
|
|
19
|
+
"unknown"
|
|
20
|
+
];
|
|
21
|
+
/**
|
|
22
|
+
* Branch order is load-bearing: every browser below Chrome also carries a
|
|
23
|
+
* `chrome/` token, and Safari's signature appears in nearly every WebKit UA.
|
|
24
|
+
*
|
|
25
|
+
* Reads the User-Agent rather than the `sec-ch-ua` client hint because a client
|
|
26
|
+
* can simply omit client hints, but stripping the UA breaks far more.
|
|
27
|
+
*/
|
|
28
|
+
var classifyBrowser = (userAgent) => {
|
|
29
|
+
const ua = (userAgent || "").toLowerCase();
|
|
30
|
+
if (/\bedg(?:e|a|ios)?\//.test(ua)) return "edge";
|
|
31
|
+
if (/samsungbrowser/.test(ua)) return "samsung_internet";
|
|
32
|
+
if (/\bopr\/|opera/.test(ua)) return "opera";
|
|
33
|
+
if (/micromessenger/.test(ua)) return "wechat";
|
|
34
|
+
if (/fban|fbav|fbios/.test(ua)) return "facebook";
|
|
35
|
+
if (/instagram/.test(ua)) return "instagram";
|
|
36
|
+
if (/firefox|fxios/.test(ua)) return "firefox";
|
|
37
|
+
if (/msie|trident/.test(ua)) return "ie";
|
|
38
|
+
if (/\bchrome\/|\bcrios\//.test(ua)) return "chrome";
|
|
39
|
+
if (/safari\//.test(ua)) return "safari";
|
|
40
|
+
return "unknown";
|
|
41
|
+
};
|
|
42
|
+
//#endregion
|
|
43
|
+
exports.BROWSER_NAMES = BROWSER_NAMES;
|
|
44
|
+
exports.classifyBrowser = classifyBrowser;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
//#region src/headerMatch.ts
|
|
3
|
+
/**
|
|
4
|
+
* Operators for an access rule's arbitrary-header condition.
|
|
5
|
+
*
|
|
6
|
+
* `equals` / `contains` are the deny-list operators (block when the request's
|
|
7
|
+
* header matches). `notEquals` / `notContains` are their allow-list negations
|
|
8
|
+
* (block when the request's header does NOT match — including when the header
|
|
9
|
+
* is absent), so an allow-list card that says "only let requests with header X
|
|
10
|
+
* through" desugars to `notEquals` / `notContains` Block rules, exactly the way
|
|
11
|
+
* the OS allow-list desugars to Block rules on the complement.
|
|
12
|
+
*
|
|
13
|
+
* `notEqualsAny` / `notContainsAny` are the multi-value form of those two: the
|
|
14
|
+
* rule's `headerValue` holds a list (see `encodeHeaderValueList`) and the rule
|
|
15
|
+
* blocks unless the request's header matches *one of* the listed values. They
|
|
16
|
+
* exist because an allow-list over several values of the SAME header cannot be
|
|
17
|
+
* expressed as several single-value rules — each rule fires independently, so
|
|
18
|
+
* `notEquals ios` + `notEquals android` blocks both an iOS and an Android
|
|
19
|
+
* request. One rule holding both values is the only way to get the "any of"
|
|
20
|
+
* semantics the allow-list needs.
|
|
21
|
+
*/
|
|
22
|
+
var HEADER_OPERATORS = [
|
|
23
|
+
"equals",
|
|
24
|
+
"contains",
|
|
25
|
+
"notEquals",
|
|
26
|
+
"notContains",
|
|
27
|
+
"notEqualsAny",
|
|
28
|
+
"notContainsAny"
|
|
29
|
+
];
|
|
30
|
+
var isHeaderOperator = (value) => value !== void 0 && HEADER_OPERATORS.includes(value);
|
|
31
|
+
/**
|
|
32
|
+
* Sentinel value carried both on every request's user scope (see
|
|
33
|
+
* `getRequestUserScope`) and on every header-restriction rule. Header rules
|
|
34
|
+
* match on data (`headerName` / `headerValue` / `headerOperator`) that Redis
|
|
35
|
+
* cannot evaluate — substring `contains` and per-rule operators aren't
|
|
36
|
+
* expressible as a TAG query, and an allow-list rule must still fire on a
|
|
37
|
+
* request that OMITS the target header, so candidate selection can't key off
|
|
38
|
+
* header presence. Redis returns header rules via the reader's
|
|
39
|
+
* `no-user-scope` fall-through probe (they constrain none of the indexed
|
|
40
|
+
* scope dimensions); this marker is what keeps them candidates through the
|
|
41
|
+
* JS-side `ruleApplies` scalar check, which would otherwise drop a rule
|
|
42
|
+
* carrying a scope field the request lacks. The concrete condition is then
|
|
43
|
+
* checked by `accessRuleHeaderMatches`.
|
|
44
|
+
*/
|
|
45
|
+
var HEADER_RULE_MARKER = "1";
|
|
46
|
+
/**
|
|
47
|
+
* Encode the value list carried by a multi-value operator (`notEqualsAny` /
|
|
48
|
+
* `notContainsAny`) into the single `headerValue` string an access rule can
|
|
49
|
+
* store. JSON rather than a delimiter because header values are arbitrary
|
|
50
|
+
* text — any separator we picked could legitimately occur inside a value.
|
|
51
|
+
*/
|
|
52
|
+
var encodeHeaderValueList = (values) => JSON.stringify(values);
|
|
53
|
+
/**
|
|
54
|
+
* Inverse of {@link encodeHeaderValueList}, tolerant of rules written by hand
|
|
55
|
+
* (e.g. via the access-policy CLI) that carry a single literal value instead of
|
|
56
|
+
* an encoded list.
|
|
57
|
+
*
|
|
58
|
+
* Returns `undefined` for a value that looks list-encoded but isn't usable — an
|
|
59
|
+
* empty list, a non-array, non-string members, or malformed JSON. Callers treat
|
|
60
|
+
* that as a malformed rule and decline to fire it, so a garbled list can't
|
|
61
|
+
* silently block all traffic.
|
|
62
|
+
*/
|
|
63
|
+
var decodeHeaderValueList = (value) => {
|
|
64
|
+
if (!value.trimStart().startsWith("[")) return [value];
|
|
65
|
+
let parsed;
|
|
66
|
+
try {
|
|
67
|
+
parsed = JSON.parse(value);
|
|
68
|
+
} catch {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (!Array.isArray(parsed) || parsed.length === 0 || !parsed.every((entry) => typeof entry === "string")) return;
|
|
72
|
+
return parsed;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Evaluate a single header condition against a request's headers. Returns
|
|
76
|
+
* `true` when the condition is satisfied — i.e. when a Block rule carrying it
|
|
77
|
+
* should fire for this request.
|
|
78
|
+
*
|
|
79
|
+
* `headers` is expected to be keyed by lower-cased header name (HTTP header
|
|
80
|
+
* names are case-insensitive); `headerName` is lower-cased here defensively.
|
|
81
|
+
* The negated operators treat an absent header as "not matching the value",
|
|
82
|
+
* which is what makes an allow-list block a request that drops the header.
|
|
83
|
+
*/
|
|
84
|
+
var evaluateHeaderCondition = (headerName, operator, value, headers) => {
|
|
85
|
+
const actual = headers[headerName.toLowerCase()];
|
|
86
|
+
switch (operator) {
|
|
87
|
+
case "equals": return actual !== void 0 && actual === value;
|
|
88
|
+
case "contains": return actual?.includes(value) ?? false;
|
|
89
|
+
case "notEquals": return actual === void 0 || actual !== value;
|
|
90
|
+
case "notContains": return actual === void 0 || !actual.includes(value);
|
|
91
|
+
case "notEqualsAny": {
|
|
92
|
+
const values = decodeHeaderValueList(value);
|
|
93
|
+
if (values === void 0) return false;
|
|
94
|
+
return actual === void 0 || !values.includes(actual);
|
|
95
|
+
}
|
|
96
|
+
case "notContainsAny": {
|
|
97
|
+
const values = decodeHeaderValueList(value);
|
|
98
|
+
if (values === void 0) return false;
|
|
99
|
+
return actual === void 0 || !values.some((candidate) => actual.includes(candidate));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
/**
|
|
104
|
+
* Whether a rule's header condition (if any) is satisfied by the request's
|
|
105
|
+
* headers. A rule with no `headerName` carries no header constraint, so it is
|
|
106
|
+
* treated as satisfied and the rule's other dimensions decide the match. A
|
|
107
|
+
* rule with a `headerName` but an unrecognised operator is malformed and never
|
|
108
|
+
* matches (fail-safe: a garbled rule must not silently block traffic).
|
|
109
|
+
*/
|
|
110
|
+
var accessRuleHeaderMatches = (rule, headers) => {
|
|
111
|
+
if (rule.headerName === void 0) return true;
|
|
112
|
+
if (!isHeaderOperator(rule.headerOperator)) return false;
|
|
113
|
+
return evaluateHeaderCondition(rule.headerName, rule.headerOperator, rule.headerValue ?? "", headers);
|
|
114
|
+
};
|
|
115
|
+
//#endregion
|
|
116
|
+
exports.HEADER_OPERATORS = HEADER_OPERATORS;
|
|
117
|
+
exports.HEADER_RULE_MARKER = HEADER_RULE_MARKER;
|
|
118
|
+
exports.accessRuleHeaderMatches = accessRuleHeaderMatches;
|
|
119
|
+
exports.decodeHeaderValueList = decodeHeaderValueList;
|
|
120
|
+
exports.encodeHeaderValueList = encodeHeaderValueList;
|
|
121
|
+
exports.evaluateHeaderCondition = evaluateHeaderCondition;
|
|
122
|
+
exports.isHeaderOperator = isHeaderOperator;
|
|
@@ -36,6 +36,26 @@ var userAttributesSchema = {
|
|
|
36
36
|
os: {
|
|
37
37
|
type: String,
|
|
38
38
|
required: false
|
|
39
|
+
},
|
|
40
|
+
browser: {
|
|
41
|
+
type: String,
|
|
42
|
+
required: false
|
|
43
|
+
},
|
|
44
|
+
headerMatch: {
|
|
45
|
+
type: String,
|
|
46
|
+
required: false
|
|
47
|
+
},
|
|
48
|
+
headerName: {
|
|
49
|
+
type: String,
|
|
50
|
+
required: false
|
|
51
|
+
},
|
|
52
|
+
headerValue: {
|
|
53
|
+
type: String,
|
|
54
|
+
required: false
|
|
55
|
+
},
|
|
56
|
+
headerOperator: {
|
|
57
|
+
type: String,
|
|
58
|
+
required: false
|
|
39
59
|
}
|
|
40
60
|
};
|
|
41
61
|
var userIpSchema = {
|
|
@@ -25,6 +25,8 @@ var SPECIFICITY_EXPR = [
|
|
|
25
25
|
"exists(@countryCode)",
|
|
26
26
|
"exists(@asn)",
|
|
27
27
|
"exists(@os)",
|
|
28
|
+
"exists(@browser)",
|
|
29
|
+
"exists(@headerMatch)",
|
|
28
30
|
"exists(@numericIp)",
|
|
29
31
|
"exists(@numericIpMaskMin)"
|
|
30
32
|
].join(" + ");
|
|
@@ -52,6 +54,11 @@ var RULE_LOAD_FIELDS = [
|
|
|
52
54
|
"@countryCode",
|
|
53
55
|
"@asn",
|
|
54
56
|
"@os",
|
|
57
|
+
"@browser",
|
|
58
|
+
"@headerMatch",
|
|
59
|
+
"@headerName",
|
|
60
|
+
"@headerValue",
|
|
61
|
+
"@headerOperator",
|
|
55
62
|
"@numericIp",
|
|
56
63
|
"@numericIpMaskMin",
|
|
57
64
|
"@numericIpMaskMax"
|
|
@@ -68,6 +75,7 @@ var readerSpecificity = (rule) => {
|
|
|
68
75
|
if (rule.countryCode !== void 0) score++;
|
|
69
76
|
if (rule.asn !== void 0) score++;
|
|
70
77
|
if (rule.os !== void 0) score++;
|
|
78
|
+
if (rule.browser !== void 0) score++;
|
|
71
79
|
if (rule.numericIp !== void 0) score++;
|
|
72
80
|
if (rule.numericIpMaskMin !== void 0) score++;
|
|
73
81
|
return score;
|
|
@@ -54,6 +54,26 @@ var userAttributesRedisSchema = {
|
|
|
54
54
|
os: {
|
|
55
55
|
type: _redis_search.SCHEMA_FIELD_TYPE.TAG,
|
|
56
56
|
INDEXMISSING: true
|
|
57
|
+
},
|
|
58
|
+
browser: {
|
|
59
|
+
type: _redis_search.SCHEMA_FIELD_TYPE.TAG,
|
|
60
|
+
INDEXMISSING: true
|
|
61
|
+
},
|
|
62
|
+
headerMatch: {
|
|
63
|
+
type: _redis_search.SCHEMA_FIELD_TYPE.TAG,
|
|
64
|
+
INDEXMISSING: true
|
|
65
|
+
},
|
|
66
|
+
headerName: {
|
|
67
|
+
type: _redis_search.SCHEMA_FIELD_TYPE.TAG,
|
|
68
|
+
INDEXMISSING: true
|
|
69
|
+
},
|
|
70
|
+
headerValue: {
|
|
71
|
+
type: _redis_search.SCHEMA_FIELD_TYPE.TAG,
|
|
72
|
+
INDEXMISSING: true
|
|
73
|
+
},
|
|
74
|
+
headerOperator: {
|
|
75
|
+
type: _redis_search.SCHEMA_FIELD_TYPE.TAG,
|
|
76
|
+
INDEXMISSING: true
|
|
57
77
|
}
|
|
58
78
|
};
|
|
59
79
|
var userScopeRedisSchema = {
|
|
@@ -15,7 +15,12 @@ var userAttributesSchema = zod.z.object({
|
|
|
15
15
|
coords: zod.z.coerce.string().optional(),
|
|
16
16
|
countryCode: zod.z.coerce.string().optional(),
|
|
17
17
|
asn: zod.z.coerce.number().int().nonnegative().optional(),
|
|
18
|
-
os: zod.z.coerce.string().optional()
|
|
18
|
+
os: zod.z.coerce.string().optional(),
|
|
19
|
+
browser: zod.z.coerce.string().optional(),
|
|
20
|
+
headerMatch: zod.z.coerce.string().optional(),
|
|
21
|
+
headerName: zod.z.coerce.string().optional(),
|
|
22
|
+
headerValue: zod.z.coerce.string().optional(),
|
|
23
|
+
headerOperator: zod.z.coerce.string().optional()
|
|
19
24
|
});
|
|
20
25
|
var userAttributesInput = zod.z.object({
|
|
21
26
|
...userAttributesSchema.shape,
|
package/dist/cjs/ruleRecord.cjs
CHANGED
|
@@ -9,7 +9,12 @@ var userAttributesRecordFields = [
|
|
|
9
9
|
"coords",
|
|
10
10
|
"countryCode",
|
|
11
11
|
"asn",
|
|
12
|
-
"os"
|
|
12
|
+
"os",
|
|
13
|
+
"browser",
|
|
14
|
+
"headerMatch",
|
|
15
|
+
"headerName",
|
|
16
|
+
"headerValue",
|
|
17
|
+
"headerOperator"
|
|
13
18
|
];
|
|
14
19
|
var userIpRecordFields = ["ip", "ipMask"];
|
|
15
20
|
var userScopeRecordFields = [...userAttributesRecordFields, ...userIpRecordFields];
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare const BROWSER_NAMES: readonly ["chrome", "safari", "firefox", "edge", "opera", "samsung_internet", "wechat", "facebook", "instagram", "ie", "unknown"];
|
|
2
|
+
export type BrowserName = (typeof BROWSER_NAMES)[number];
|
|
3
|
+
export declare const classifyBrowser: (userAgent: string | undefined) => BrowserName;
|
|
4
|
+
//# sourceMappingURL=classifyBrowser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"classifyBrowser.d.ts","sourceRoot":"","sources":["../src/classifyBrowser.ts"],"names":[],"mappings":"AAmBA,eAAO,MAAM,aAAa,mIAYhB,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AASzD,eAAO,MAAM,eAAe,cAAe,MAAM,GAAG,SAAS,KAAG,WAkC/D,CAAC"}
|