@prosopo/provider 5.12.3 → 5.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.
@@ -1,5 +1,5 @@
1
1
 
2
- > @prosopo/provider@5.12.3 build:cjs
2
+ > @prosopo/provider@5.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: .
@@ -32,6 +32,7 @@ ViteCommonJSConfig: .
32
32
  {
33
33
  externals: [
34
34
  '@prosopo/api-route',
35
+ The plugin "vite-tsconfig-paths" is detected. Vite now supports tsconfig paths resolution natively via the resolve.tsconfigPaths option. You can remove the plugin and set resolve.tsconfigPaths: true in your Vite config instead.
35
36
  '@prosopo/logger',
36
37
  '@prosopo/util',
37
38
  '@prosopo/api-express-router',
@@ -55,7 +56,6 @@ ViteCommonJSConfig: .
55
56
  '@prosopo/web-bot-auth'
56
57
  ]
57
58
  }
58
- The plugin "vite-tsconfig-paths" is detected. Vite now supports tsconfig paths resolution natively via the resolve.tsconfigPaths option. You can remove the plugin and set resolve.tsconfigPaths: true in your Vite config instead.
59
59
  vite v8.1.5 building ssr environment for production...
60
60
  Bundle build started
61
61
  
@@ -104,7 +104,6 @@ dist/cjs/tasks/puzzle/backgroundBuffer.cjs 1
104
104
  dist/cjs/utils/clientMetaData.cjs 1.48 kB │ gzip: 0.72 kB
105
105
  dist/cjs/tasks/detection/assignSecret.cjs 1.48 kB │ gzip: 0.75 kB
106
106
  dist/cjs/api/assetDocument.cjs 1.50 kB │ gzip: 0.81 kB
107
- dist/cjs/compositeIpAddress.cjs 1.55 kB │ gzip: 0.57 kB
108
107
  dist/cjs/api/admin/apiGetAllDecisionMachinesEndpoint.cjs 1.59 kB │ gzip: 0.60 kB
109
108
  dist/cjs/schedulers/updateSpamEmailDomains.cjs 1.64 kB │ gzip: 0.62 kB
110
109
  dist/cjs/utils/honeypot/encoders.cjs 1.66 kB │ gzip: 0.67 kB
@@ -137,6 +136,7 @@ dist/cjs/api/public.cjs 2
137
136
  dist/cjs/api/captcha/maintenanceModeResponses.cjs 2.91 kB │ gzip: 0.77 kB
138
137
  dist/cjs/api/captcha/submitImageCaptchaSolution.cjs 2.93 kB │ gzip: 1.03 kB
139
138
  dist/cjs/tasks/detection/getBotScore.cjs 3.37 kB │ gzip: 1.33 kB
139
+ dist/cjs/compositeIpAddress.cjs 3.39 kB │ gzip: 1.36 kB
140
140
  dist/cjs/api/captcha/assetSealFormat.cjs 3.59 kB │ gzip: 1.37 kB
141
141
  dist/cjs/api/captcha/assignDetectorBundle.cjs 3.63 kB │ gzip: 1.37 kB
142
142
  dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.cjs 3.66 kB │ gzip: 1.35 kB
@@ -153,7 +153,7 @@ dist/cjs/tasks/puzzle/puzzleRenderer.cjs 4
153
153
  dist/cjs/api/captcha.cjs 4.51 kB │ gzip: 1.40 kB
154
154
  dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/accessPolicy.cjs 4.56 kB │ gzip: 1.07 kB
155
155
  dist/cjs/tasks/dnsEvent/enrichDnsEvent.cjs 4.84 kB │ gzip: 1.74 kB
156
- dist/cjs/index.cjs 4.95 kB │ gzip: 1.03 kB
156
+ dist/cjs/index.cjs 5.02 kB │ gzip: 1.05 kB
157
157
  dist/cjs/tasks/tasks.cjs 5.07 kB │ gzip: 1.57 kB
158
158
  dist/cjs/tasks/detection/decoderPool.cjs 5.47 kB │ gzip: 2.06 kB
159
159
  dist/cjs/util/usageCounters.cjs 5.72 kB │ gzip: 2.03 kB
@@ -174,12 +174,12 @@ dist/cjs/api/blacklistRequestInspector.cjs 13
174
174
  dist/cjs/api/verify.cjs 16.79 kB │ gzip: 2.93 kB
175
175
  dist/cjs/tasks/frictionless/frictionlessTasks.cjs 18.37 kB │ gzip: 4.89 kB
176
176
  dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/handler.cjs 20.05 kB │ gzip: 4.59 kB
177
- dist/cjs/tasks/captchaManager.cjs 23.94 kB │ gzip: 7.10 kB
178
177
  dist/cjs/tasks/puzzleCaptcha/puzzleTasks.cjs 24.12 kB │ gzip: 5.17 kB
179
- dist/cjs/tasks/powCaptcha/powTasks.cjs 24.99 kB │ gzip: 6.02 kB
178
+ dist/cjs/tasks/captchaManager.cjs 24.62 kB │ gzip: 7.42 kB
179
+ dist/cjs/tasks/powCaptcha/powTasks.cjs 25.55 kB │ gzip: 6.16 kB
180
180
  dist/cjs/tasks/imgCaptcha/imgCaptchaTasks.cjs 27.94 kB │ gzip: 6.36 kB
181
181
 
182
- ✓ built in 147ms
182
+ ✓ built in 191ms
183
183
  [copy-plugin] copying /home/runner/work/captcha/captcha/packages/provider/src/tasks/detection/decodeBehavior.js to /home/runner/work/captcha/captcha/packages/provider/dist/cjs/tasks/detection/decodeBehavior.js
184
184
  [copy-plugin] copying /home/runner/work/captcha/captcha/packages/provider/src/tasks/detection/decodePayload.js to /home/runner/work/captcha/captcha/packages/provider/dist/cjs/tasks/detection/decodePayload.js
185
185
  [copy-plugin] copying /home/runner/work/captcha/captcha/packages/provider/src/tasks/detection/decodeSimd.js to /home/runner/work/captcha/captcha/packages/provider/dist/cjs/tasks/detection/decodeSimd.js
@@ -1,8 +1,8 @@
1
1
 
2
- > @prosopo/provider@5.12.3 build:tsc
2
+ > @prosopo/provider@5.13.0 build:tsc
3
3
  > tsc --build --verbose
4
4
 
5
- 10:41:07 PM - Projects in this build:
5
+ 9:06:33 AM - Projects in this build:
6
6
  * ../../dev/config/tsconfig.json
7
7
  * ../util/tsconfig.json
8
8
  * ../logger/tsconfig.json
@@ -28,53 +28,53 @@
28
28
  * ../web-bot-auth/tsconfig.json
29
29
  * tsconfig.json
30
30
 
31
- 10:41:07 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'
31
+ 9:06:33 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'
32
32
 
33
- 10:41:07 PM - Project '../util/tsconfig.json' is up to date because newest input '../util/src/url.ts' is older than output '../util/tsconfig.tsbuildinfo'
33
+ 9:06:33 AM - Project '../util/tsconfig.json' is up to date because newest input '../util/src/url.ts' is older than output '../util/tsconfig.tsbuildinfo'
34
34
 
35
- 10:41:07 PM - Project '../logger/tsconfig.json' is up to date because newest input '../logger/src/tests/loggerBrowser.unit.test.ts' is older than output '../logger/tsconfig.tsbuildinfo'
35
+ 9:06:33 AM - Project '../logger/tsconfig.json' is up to date because newest input '../logger/src/index.ts' is older than output '../logger/tsconfig.tsbuildinfo'
36
36
 
37
- 10:41:07 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'
37
+ 9:06:33 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'
38
38
 
39
- 10:41:07 PM - Project '../locale/tsconfig.json' is up to date because newest input '../locale/src/process.ts' is older than output '../locale/tsconfig.tsbuildinfo'
39
+ 9:06:33 AM - Project '../locale/tsconfig.json' is up to date because newest input '../locale/src/translationKey.ts' is older than output '../locale/tsconfig.tsbuildinfo'
40
40
 
41
- 10:41:07 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'
41
+ 9:06:33 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'
42
42
 
43
- 10:41:07 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'
43
+ 9:06:33 AM - Project '../types/tsconfig.json' is up to date because newest input '../types/src/types.test-d.ts' is older than output '../types/tsconfig.tsbuildinfo'
44
44
 
45
- 10:41:07 PM - Project '../common/tsconfig.json' is up to date because newest input '../common/src/tests/utils/objectUtils.unit.test.ts' is older than output '../common/tsconfig.tsbuildinfo'
45
+ 9:06:33 AM - Project '../common/tsconfig.json' is up to date because newest input '../common/src/error.ts' is older than output '../common/tsconfig.tsbuildinfo'
46
46
 
47
- 10:41:07 PM - Project '../ipinfo/tsconfig.json' is up to date because newest input '../ipinfo/src/index.ts' is older than output '../ipinfo/tsconfig.tsbuildinfo'
47
+ 9:06:33 AM - Project '../ipinfo/tsconfig.json' is up to date because newest input '../ipinfo/src/types.ts' is older than output '../ipinfo/tsconfig.tsbuildinfo'
48
48
 
49
- 10:41:07 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'
49
+ 9:06:33 AM - Project '../redis-client/tsconfig.json' is up to date because newest input '../redis-client/src/redisClient.ts' is older than output '../redis-client/tsconfig.tsbuildinfo'
50
50
 
51
- 10:41:07 PM - Project '../api/tsconfig.json' is up to date because newest input '../api/src/index.ts' is older than output '../api/tsconfig.tsbuildinfo'
51
+ 9:06:33 AM - Project '../api/tsconfig.json' is up to date because newest input '../api/src/index.ts' is older than output '../api/tsconfig.tsbuildinfo'
52
52
 
53
- 10:41:07 PM - Project '../user-access-policy/tsconfig.json' is up to date because newest input '../user-access-policy/src/transformRule.ts' is older than output '../user-access-policy/tsconfig.tsbuildinfo'
53
+ 9:06:33 AM - Project '../user-access-policy/tsconfig.json' is up to date because newest input '../user-access-policy/src/transformRule.ts' is older than output '../user-access-policy/tsconfig.tsbuildinfo'
54
54
 
55
- 10:41:07 PM - Project '../types-database/tsconfig.json' is up to date because newest input '../types-database/src/index.ts' is older than output '../types-database/tsconfig.tsbuildinfo'
55
+ 9:06:33 AM - Project '../types-database/tsconfig.json' is up to date because newest input '../types-database/src/index.ts' is older than output '../types-database/tsconfig.tsbuildinfo'
56
56
 
57
- 10:41:07 PM - Project '../database/tsconfig.json' is up to date because newest input '../database/src/tests/unit/captchaLabel.unit.test.ts' is older than output '../database/tsconfig.tsbuildinfo'
57
+ 9:06:33 AM - Project '../database/tsconfig.json' is up to date because newest input '../database/src/tests/unit/captchaLabel.unit.test.ts' is older than output '../database/tsconfig.tsbuildinfo'
58
58
 
59
- 10:41:07 PM - Project '../keyring/tsconfig.json' is up to date because newest input '../keyring/src/index.ts' is older than output '../keyring/tsconfig.tsbuildinfo'
59
+ 9:06:33 AM - Project '../keyring/tsconfig.json' is up to date because newest input '../keyring/src/index.ts' is older than output '../keyring/tsconfig.tsbuildinfo'
60
60
 
61
- 10:41:07 PM - Project '../types-env/tsconfig.json' is up to date because newest input '../types-env/src/index.ts' is older than output '../types-env/tsconfig.tsbuildinfo'
61
+ 9:06:33 AM - Project '../types-env/tsconfig.json' is up to date because newest input '../types-env/src/index.ts' is older than output '../types-env/tsconfig.tsbuildinfo'
62
62
 
63
- 10:41:07 PM - Project '../env/tsconfig.json' is up to date because newest input '../env/src/index.ts' is older than output '../env/tsconfig.tsbuildinfo'
63
+ 9:06:33 AM - Project '../env/tsconfig.json' is up to date because newest input '../env/src/env.ts' is older than output '../env/tsconfig.tsbuildinfo'
64
64
 
65
- 10:41:07 PM - Project '../api-express-router/tsconfig.json' is up to date because newest input '../api-express-router/src/middlewares/requestLoggerMiddleware.ts' is older than output '../api-express-router/tsconfig.tsbuildinfo'
65
+ 9:06:33 AM - Project '../api-express-router/tsconfig.json' is up to date because newest input '../api-express-router/src/tests/unit/testDoubles.ts' is older than output '../api-express-router/tsconfig.tsbuildinfo'
66
66
 
67
- 10:41:07 PM - Project '../captcha-severity/tsconfig.json' is up to date because newest input '../captcha-severity/src/index.test.ts' is older than output '../captcha-severity/tsconfig.tsbuildinfo'
67
+ 9:06:33 AM - Project '../captcha-severity/tsconfig.json' is up to date because newest input '../captcha-severity/src/index.test.ts' is older than output '../captcha-severity/tsconfig.tsbuildinfo'
68
68
 
69
- 10:41:07 PM - Project '../datasets/tsconfig.json' is up to date because newest input '../datasets/src/tests/captcha.unit.test.ts' is older than output '../datasets/tsconfig.tsbuildinfo'
69
+ 9:06:33 AM - Project '../datasets/tsconfig.json' is up to date because newest input '../datasets/src/index.ts' is older than output '../datasets/tsconfig.tsbuildinfo'
70
70
 
71
- 10:41:07 PM - Project '../load-balancer/tsconfig.json' is up to date because newest input '../load-balancer/src/balancer.ts' is older than output '../load-balancer/tsconfig.tsbuildinfo'
71
+ 9:06:33 AM - Project '../load-balancer/tsconfig.json' is up to date because newest input '../load-balancer/src/balancer.ts' is older than output '../load-balancer/tsconfig.tsbuildinfo'
72
72
 
73
- 10:41:07 PM - Project '../puzzle-assets/tsconfig.json' is up to date because newest input '../puzzle-assets/src/background.ts' is older than output '../puzzle-assets/tsconfig.tsbuildinfo'
73
+ 9:06:33 AM - Project '../puzzle-assets/tsconfig.json' is up to date because newest input '../puzzle-assets/src/background.ts' is older than output '../puzzle-assets/tsconfig.tsbuildinfo'
74
74
 
75
- 10:41:07 PM - Project '../web-bot-auth/tsconfig.json' is up to date because newest input '../web-bot-auth/src/base64.ts' is older than output '../web-bot-auth/tsconfig.tsbuildinfo'
75
+ 9:06:33 AM - Project '../web-bot-auth/tsconfig.json' is up to date because newest input '../web-bot-auth/src/base64.ts' is older than output '../web-bot-auth/tsconfig.tsbuildinfo'
76
76
 
77
- 10:41:07 PM - Project 'tsconfig.json' is out of date because output file 'tsconfig.tsbuildinfo' does not exist
77
+ 9:06:33 AM - Project 'tsconfig.json' is out of date because output file 'tsconfig.tsbuildinfo' does not exist
78
78
 
79
- 10:41:07 PM - Building project '/home/runner/work/captcha/captcha/packages/provider/tsconfig.json'...
79
+ 9:06:33 AM - Building project '/home/runner/work/captcha/captcha/packages/provider/tsconfig.json'...
80
80
 
@@ -1,9 +1,9 @@
1
1
 
2
- > @prosopo/provider@5.12.3 build
2
+ > @prosopo/provider@5.13.0 build
3
3
  > npm run build:cross-env -- --mode ${NODE_ENV:-development}
4
4
 
5
5
 
6
- > @prosopo/provider@5.12.3 build:cross-env
6
+ > @prosopo/provider@5.13.0 build:cross-env
7
7
  > vite build --config vite.esm.config.ts --mode production
8
8
 
9
9
  ViteEsmConfig: .
@@ -106,7 +106,6 @@ dist/api/admin/apiRemoveAllDecisionMachinesEndpoint.js 1.27 k
106
106
  dist/api/admin/apiRemoveDecisionMachineEndpoint.js 1.29 kB │ gzip: 0.51 kB
107
107
  dist/tasks/dataset/datasetTasksUtils.js 1.30 kB │ gzip: 0.48 kB
108
108
  dist/api/assetDocument.js 1.36 kB │ gzip: 0.75 kB
109
- dist/compositeIpAddress.js 1.36 kB │ gzip: 0.55 kB
110
109
  dist/tasks/detection/assignSecret.js 1.42 kB │ gzip: 0.74 kB
111
110
  dist/utils/clientMetaData.js 1.42 kB │ gzip: 0.72 kB
112
111
  dist/api/admin/apiGetAllDecisionMachinesEndpoint.js 1.48 kB │ gzip: 0.57 kB
@@ -141,7 +140,8 @@ dist/api/captcha/submitPuzzleCaptchaSolution.js 2.55 k
141
140
  dist/api/forwardVerify.js 2.59 kB │ gzip: 1.10 kB
142
141
  dist/api/captcha/submitImageCaptchaSolution.js 2.59 kB │ gzip: 1.00 kB
143
142
  dist/api/admin/apiAdminRoutesProvider.js 2.78 kB │ gzip: 0.55 kB
144
- dist/index.js 2.92 kB │ gzip: 0.80 kB
143
+ dist/index.js 2.95 kB │ gzip: 0.81 kB
144
+ dist/compositeIpAddress.js 3.15 kB │ gzip: 1.34 kB
145
145
  dist/tasks/detection/getBotScore.js 3.29 kB │ gzip: 1.32 kB
146
146
  dist/api/captcha/assetSealFormat.js 3.38 kB │ gzip: 1.34 kB
147
147
  dist/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.js 3.39 kB │ gzip: 1.32 kB
@@ -179,11 +179,11 @@ dist/api/verify.js 15.12 k
179
179
  dist/tasks/frictionless/frictionlessTasks.js 17.80 kB │ gzip: 4.86 kB
180
180
  dist/api/captcha/getFrictionlessCaptchaChallenge/handler.js 18.54 kB │ gzip: 4.48 kB
181
181
  dist/tasks/puzzleCaptcha/puzzleTasks.js 22.71 kB │ gzip: 5.12 kB
182
- dist/tasks/captchaManager.js 23.44 kB │ gzip: 7.03 kB
183
- dist/tasks/powCaptcha/powTasks.js 23.61 kB │ gzip: 5.97 kB
182
+ dist/tasks/captchaManager.js 24.12 kB │ gzip: 7.34 kB
183
+ dist/tasks/powCaptcha/powTasks.js 24.13 kB │ gzip: 6.12 kB
184
184
  dist/tasks/imgCaptcha/imgCaptchaTasks.js 26.42 kB │ gzip: 6.30 kB
185
185
 
186
- ✓ built in 150ms
186
+ ✓ built in 484ms
187
187
  [copy-plugin] copying /home/runner/work/captcha/captcha/packages/provider/src/tasks/detection/decodeBehavior.js to /home/runner/work/captcha/captcha/packages/provider/dist/tasks/detection/decodeBehavior.js
188
188
  [copy-plugin] copying /home/runner/work/captcha/captcha/packages/provider/src/tasks/detection/decodePayload.js to /home/runner/work/captcha/captcha/packages/provider/dist/tasks/detection/decodePayload.js
189
189
  [copy-plugin] copying /home/runner/work/captcha/captcha/packages/provider/src/tasks/detection/decodeSimd.js to /home/runner/work/captcha/captcha/packages/provider/dist/tasks/detection/decodeSimd.js
package/CHANGELOG.md CHANGED
@@ -1,5 +1,59 @@
1
1
  # @prosopo/provider
2
2
 
3
+ ## 5.13.0
4
+ ### Minor Changes
5
+
6
+ - 85a1bb9: Seal captcha image paths into opaque URLs, opened by a CDN edge script.
7
+
8
+ An image URL used to say which image it was: `https://cdn.example.net/dataset/images/abc.webp`. Signed URLs already stop a harvested URL being refetched forever, but the path stays in plain sight, and the path is a stable identifier for the image behind it — which makes it a usable key for caching answers between sessions.
9
+
10
+ The path is now AES-256-GCM sealed, with an expiry, into an opaque blob drawn fresh every time:
11
+
12
+ ```
13
+ https://cdn.example.net/s/AgHk1n...Qx9.webp
14
+ ```
15
+
16
+ The edge script opens it, puts the canonical path back on the request, and the CDN serves the one object that path names. The same image therefore has a different URL in every session, with nothing in the URL to group those together, and there is still only one cached copy and one stored object.
17
+
18
+ Sealing happens strictly below `item.data`. The item hash, the captchaId and the datasetId are untouched, so nothing about the dataset or how a solution is verified changes.
19
+
20
+ The provider seals with `node:crypto`, because `AssetsResolver.resolveAsset` is synchronous and every WebCrypto call returns a promise; the edge opens with WebCrypto, because that is what its runtime has. The wire format, the validation and the base64url alphabet live in one module both ends import, and a test seals with one end and opens with the other so the two cannot drift.
21
+
22
+ Inert unless its key is configured, since a sealed URL is unservable until the matching edge script is live. Configured, it takes precedence over the signed resolver; leaving the signing key in place keeps that as the fallback for any zone not yet moved over. More than one key opens at a time, so keys can be rotated without a flag day. `npm run -w @prosopo/provider build:edge` emits the edge script as a single file. Rollout order, environment variables and rotation are documented for operators outside this repository.
23
+
24
+ Test coverage: 51 unit tests over the wire format, the sealer, the resolver and the edge handler — round trip, tamper, truncation, expiry at the boundary, swapped key id, rotation across two live keys, path traversal and prefix confinement, URL shape and per-call uniqueness, passthrough of requests that are not sealed, idempotency when the handler runs at both hooks, and the provider-seals/edge-opens interop.
25
+
26
+ ### Patch Changes
27
+
28
+ - 4c9b84b: Escalate a PoW solve to an image captcha when it arrives from a different address than the challenge.
29
+
30
+ A PoW challenge is bound to the user account and the site key and to nothing about where the request came from, so a solved challenge can be carried to any host that wants a free pass. The issuing address is already on the record, so binding to it costs nothing: `verifyPowCaptchaSolution` now compares it against the address submitting the solve and escalates when they differ, under a new `IP_CHANGED` reason.
31
+
32
+ Escalation, not denial. A phone handing off between towers mid-solve is a real user and should pay a picture rather than be turned away. For the same reason IPv6 is judged on the /64 alone — the interface identifier in the low 64 bits rotates by design under RFC 8981, several times a day on one unchanged connection — and an address we could not read counts as unchanged.
33
+
34
+ Only applies where a session is linked, since escalation carries the originating session's risk profile forward. Missing coordinates still takes precedence as the reported reason when both fire.
35
+ - 2cca36e: Report a bot score of zero to Pro and Enterprise instead of dropping the field.
36
+
37
+ `canClientSeeScore` tested `score && tier && tier !== Tier.Free`. A session with nothing wrong with it scores 0, which is falsy, so `score` was omitted from the siteverify response for exactly those users: a paying customer got a score for every suspicious visitor and no score at all for their cleanest ones, which reads as "no score available" rather than "no risk".
38
+
39
+ Invisible in production today because `Math.random() * 0.3` is added to every score, making an exact 0 all but impossible. Removing that noise — captcha-private#4433, where this was found — is what would have exposed it.
40
+
41
+ The function also returned `number | boolean | undefined` from its `&&` chain; it now returns `boolean`.
42
+ - Updated dependencies [4c9b84b]
43
+ - Updated dependencies [f13bea8]
44
+ - @prosopo/types@5.10.1
45
+ - @prosopo/load-balancer@2.11.0
46
+ - @prosopo/api@4.3.4
47
+ - @prosopo/api-express-router@3.1.94
48
+ - @prosopo/database@4.0.40
49
+ - @prosopo/datasets@3.1.90
50
+ - @prosopo/env@3.6.63
51
+ - @prosopo/ipinfo@0.4.9
52
+ - @prosopo/keyring@2.9.96
53
+ - @prosopo/types-database@5.6.4
54
+ - @prosopo/types-env@2.11.9
55
+ - @prosopo/user-access-policy@3.14.10
56
+
3
57
  ## 5.12.3
4
58
  ### Patch Changes
5
59
 
@@ -38,9 +38,53 @@ var getIpAddressFromComposite = (compositeIpAddress) => {
38
38
  }
39
39
  };
40
40
  var getBigInt = (number) => BigInt(number || 0n);
41
+ /**
42
+ * Mongo hands these back as Decimal128 rather than the `number | bigint` the
43
+ * type promises, and `BigInt(Decimal128)` throws. Route through the string
44
+ * form, and report a value we cannot read as absent rather than throwing.
45
+ */
46
+ var readPart = (value) => {
47
+ if (value === void 0 || value === null) return void 0;
48
+ try {
49
+ return BigInt(value.toString());
50
+ } catch {
51
+ return;
52
+ }
53
+ };
54
+ /**
55
+ * The value `getCompositeIpAddress` returns when it could not read an
56
+ * address at all. 0.0.0.0 is not a client address, so nothing legitimate is
57
+ * being swallowed by treating it as "we don't know".
58
+ */
59
+ var isUnknownIp = (ip) => ip.type === _prosopo_types.IpAddressType.v4 && readPart(ip.lower) === 0n;
60
+ /**
61
+ * Do two observations of a client come from the same place on the network?
62
+ *
63
+ * v4 is compared exactly. v6 is compared on the /64 prefix alone — the
64
+ * interface identifier in the low 64 bits is designed to rotate (RFC 8981
65
+ * privacy extensions), often several times a day on one unchanged connection,
66
+ * so comparing it would call an ordinary phone a different host.
67
+ *
68
+ * A value we do not actually have counts as the same — one that will not
69
+ * parse, or the all-zero v4 `getCompositeIpAddress` returns when handed an
70
+ * address it could not read. This answer gates extra friction for a real
71
+ * user, and a gap in what we recorded is not evidence against them.
72
+ */
73
+ var isSameIpOrigin = (a, b) => {
74
+ if (isUnknownIp(a) || isUnknownIp(b)) return true;
75
+ if (a.type !== b.type) return false;
76
+ const compare = (left, right) => {
77
+ const leftPart = readPart(left);
78
+ const rightPart = readPart(right);
79
+ if (leftPart === void 0 || rightPart === void 0) return true;
80
+ return leftPart === rightPart;
81
+ };
82
+ return a.type === _prosopo_types.IpAddressType.v6 ? compare(a.upper, b.upper) : compare(a.lower, b.lower);
83
+ };
41
84
  var never = () => {
42
85
  throw new Error("Unhandled type");
43
86
  };
44
87
  //#endregion
45
88
  exports.getCompositeIpAddress = getCompositeIpAddress;
46
89
  exports.getIpAddressFromComposite = getIpAddressFromComposite;
90
+ exports.isSameIpOrigin = isSameIpOrigin;
@@ -50,6 +50,7 @@ exports.getVerdictCache = require_blacklistRequestInspector.getVerdictCache;
50
50
  exports.handshakeTimingMiddleware = require_handshakeTimingMiddleware.handshakeTimingMiddleware;
51
51
  exports.headerCheckMiddleware = require_headerCheckMiddleware.headerCheckMiddleware;
52
52
  exports.ignoreMiddleware = require_ignoreMiddleware.ignoreMiddleware;
53
+ exports.isSameIpOrigin = require_compositeIpAddress.isSameIpOrigin;
53
54
  exports.isTlsAvailable = require_startProviderApi.isTlsAvailable;
54
55
  exports.ja4Middleware = require_ja4Middleware.ja4Middleware;
55
56
  exports.migrateFrictionlessLadder = require_frictionlessLadder.migrateFrictionlessLadder;
@@ -564,8 +564,22 @@ var CaptchaManager = class CaptchaManager {
564
564
  const ipInfo = currentIp ? await env.ipInfoService.lookup(currentIp) : recordIpInfo;
565
565
  return require_checkTrafficFilter.checkTrafficFilter(ipInfo, effective, require_enrichDnsEvent.extraIpInfosFromEnrichedDnsEvent(enrichedDnsEvent), enrichedDnsEvent?.pathValid);
566
566
  }
567
+ /**
568
+ * Does this client's tier entitle it to the bot score, and is there one?
569
+ *
570
+ * `score !== undefined`, not `score`: a session with nothing wrong with it
571
+ * scores 0, and a truthiness test dropped the field for exactly those
572
+ * users — a paying customer reading `score` got a present field for
573
+ * every suspicious visitor and a missing one for their cleanest. It has
574
+ * been invisible because `Math.random() * 0.3` makes an exact 0 all but
575
+ * impossible; taking that noise out (see captcha-private#4433) is what
576
+ * would expose it.
577
+ *
578
+ * Returning `boolean` rather than the old `number | boolean | undefined`,
579
+ * which came from `&&`-chaining the score and the tier.
580
+ */
567
581
  static canClientSeeScore(tier, score) {
568
- return score && tier && tier !== _prosopo_types.Tier.Free;
582
+ return score !== void 0 && tier !== _prosopo_types.Tier.Free;
569
583
  }
570
584
  };
571
585
  //#endregion
@@ -190,14 +190,24 @@ var PowCaptchaManager = class extends require_captchaManager.CaptchaManager {
190
190
  await Promise.all(writePromises);
191
191
  if (!correct) return { verified: correct };
192
192
  const escalateForMissingCoords = !coords && Boolean(challengeRecord.sessionId);
193
+ const solveIp = require_compositeIpAddress.getCompositeIpAddress(ipAddress);
194
+ const escalateForIpChange = Boolean(challengeRecord.sessionId) && !require_compositeIpAddress.isSameIpOrigin(challengeRecord.ipAddress, solveIp);
195
+ if (escalateForIpChange) this.logger.info(() => ({
196
+ msg: "PoW solve arrived from a different address than the challenge",
197
+ data: {
198
+ challenge,
199
+ issuedType: challengeRecord.ipAddress.type,
200
+ solvedType: solveIp.type
201
+ }
202
+ }));
193
203
  let routingOutput = this.postPowContext ? await this.runPostPowRouting({
194
204
  challengeRecord,
195
205
  challengeSplit,
196
206
  behavioralDataPacked: decryptedBehavioralDataPacked
197
207
  }) : void 0;
198
- if (escalateForMissingCoords && routingOutput?.captchaType !== _prosopo_types.CaptchaType.image && routingOutput?.captchaType !== _prosopo_types.CaptchaType.puzzle) routingOutput = {
208
+ if ((escalateForMissingCoords || escalateForIpChange) && routingOutput?.captchaType !== _prosopo_types.CaptchaType.image && routingOutput?.captchaType !== _prosopo_types.CaptchaType.puzzle) routingOutput = {
199
209
  captchaType: _prosopo_types.CaptchaType.image,
200
- reason: _prosopo_types.FrictionlessReason.MISSING_COORDINATES
210
+ reason: escalateForMissingCoords ? _prosopo_types.FrictionlessReason.MISSING_COORDINATES : _prosopo_types.FrictionlessReason.IP_CHANGED
201
211
  };
202
212
  return {
203
213
  verified: correct,
@@ -2,4 +2,5 @@ import type { IPAddress } from "@prosopo/types";
2
2
  import { type CompositeIpAddress } from "@prosopo/types";
3
3
  export declare const getCompositeIpAddress: (ip: string | IPAddress) => CompositeIpAddress;
4
4
  export declare const getIpAddressFromComposite: (compositeIpAddress: CompositeIpAddress) => IPAddress;
5
+ export declare const isSameIpOrigin: (a: CompositeIpAddress, b: CompositeIpAddress) => boolean;
5
6
  //# sourceMappingURL=compositeIpAddress.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"compositeIpAddress.d.ts","sourceRoot":"","sources":["../src/compositeIpAddress.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,KAAK,kBAAkB,EAAiB,MAAM,gBAAgB,CAAC;AAOxE,eAAO,MAAM,qBAAqB,OAC7B,MAAM,GAAG,SAAS,KACpB,kBAaF,CAAC;AAuBF,eAAO,MAAM,yBAAyB,uBACjB,kBAAkB,KACpC,SAaF,CAAC"}
1
+ {"version":3,"file":"compositeIpAddress.d.ts","sourceRoot":"","sources":["../src/compositeIpAddress.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,KAAK,kBAAkB,EAAiB,MAAM,gBAAgB,CAAC;AAOxE,eAAO,MAAM,qBAAqB,OAC7B,MAAM,GAAG,SAAS,KACpB,kBAaF,CAAC;AAuBF,eAAO,MAAM,yBAAyB,uBACjB,kBAAkB,KACpC,SAaF,CAAC;AAuCF,eAAO,MAAM,cAAc,MACvB,kBAAkB,KAClB,kBAAkB,KACnB,OAiBF,CAAC"}
@@ -38,8 +38,51 @@ var getIpAddressFromComposite = (compositeIpAddress) => {
38
38
  }
39
39
  };
40
40
  var getBigInt = (number) => BigInt(number || 0n);
41
+ /**
42
+ * Mongo hands these back as Decimal128 rather than the `number | bigint` the
43
+ * type promises, and `BigInt(Decimal128)` throws. Route through the string
44
+ * form, and report a value we cannot read as absent rather than throwing.
45
+ */
46
+ var readPart = (value) => {
47
+ if (value === void 0 || value === null) return void 0;
48
+ try {
49
+ return BigInt(value.toString());
50
+ } catch {
51
+ return;
52
+ }
53
+ };
54
+ /**
55
+ * The value `getCompositeIpAddress` returns when it could not read an
56
+ * address at all. 0.0.0.0 is not a client address, so nothing legitimate is
57
+ * being swallowed by treating it as "we don't know".
58
+ */
59
+ var isUnknownIp = (ip) => ip.type === IpAddressType.v4 && readPart(ip.lower) === 0n;
60
+ /**
61
+ * Do two observations of a client come from the same place on the network?
62
+ *
63
+ * v4 is compared exactly. v6 is compared on the /64 prefix alone — the
64
+ * interface identifier in the low 64 bits is designed to rotate (RFC 8981
65
+ * privacy extensions), often several times a day on one unchanged connection,
66
+ * so comparing it would call an ordinary phone a different host.
67
+ *
68
+ * A value we do not actually have counts as the same — one that will not
69
+ * parse, or the all-zero v4 `getCompositeIpAddress` returns when handed an
70
+ * address it could not read. This answer gates extra friction for a real
71
+ * user, and a gap in what we recorded is not evidence against them.
72
+ */
73
+ var isSameIpOrigin = (a, b) => {
74
+ if (isUnknownIp(a) || isUnknownIp(b)) return true;
75
+ if (a.type !== b.type) return false;
76
+ const compare = (left, right) => {
77
+ const leftPart = readPart(left);
78
+ const rightPart = readPart(right);
79
+ if (leftPart === void 0 || rightPart === void 0) return true;
80
+ return leftPart === rightPart;
81
+ };
82
+ return a.type === IpAddressType.v6 ? compare(a.upper, b.upper) : compare(a.lower, b.lower);
83
+ };
41
84
  var never = () => {
42
85
  throw new Error("Unhandled type");
43
86
  };
44
87
  //#endregion
45
- export { getCompositeIpAddress, getIpAddressFromComposite };
88
+ export { getCompositeIpAddress, getIpAddressFromComposite, isSameIpOrigin };
@@ -1 +1 @@
1
- {"version":3,"file":"compositeIpAddress.js","sourceRoot":"","sources":["../src/compositeIpAddress.ts"],"names":[],"mappings":"AAeA,OAAO,EAA2B,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACxE,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEhD,MAAM,QAAQ,GAAG,GAAG,CAAC;AACrB,MAAM,aAAa,GAAG,CAAC,EAAE,IAAI,QAAQ,CAAC,GAAG,EAAE,CAAC;AAE5C,MAAM,CAAC,MAAM,qBAAqB,GAAG,CACpC,EAAsB,EACD,EAAE;IACvB,IAAI,SAAoB,CAAC;IAEzB,IAAI,CAAC;QACJ,SAAS,GAAG,QAAQ,KAAK,OAAO,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5D,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACZ,OAAO;YACN,KAAK,EAAE,EAAE;YACT,IAAI,EAAE,aAAa,CAAC,EAAE;SACtB,CAAC;IACH,CAAC;IAED,OAAO,yBAAyB,CAAC,SAAS,CAAC,CAAC;AAC7C,CAAC,CAAC;AAEF,MAAM,yBAAyB,GAAG,CACjC,SAAoB,EACC,EAAE;IACvB,MAAM,SAAS,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC;IAErC,IAAI,SAAS,YAAY,QAAQ,EAAE,CAAC;QACnC,OAAO;YACN,KAAK,EAAE,SAAS;YAChB,IAAI,EAAE,aAAa,CAAC,EAAE;SACtB,CAAC;IACH,CAAC;IAED,SAA4B,CAAC;IAE7B,OAAO;QACN,KAAK,EAAE,SAAS,GAAG,aAAa;QAChC,KAAK,EAAE,SAAS,IAAI,QAAQ;QAC5B,IAAI,EAAE,aAAa,CAAC,EAAE;KACtB,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,yBAAyB,GAAG,CACxC,kBAAsC,EAC1B,EAAE;IACd,QAAQ,kBAAkB,CAAC,IAAI,EAAE,CAAC;QACjC,KAAK,aAAa,CAAC,EAAE;YACpB,OAAO,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC;QACjE,KAAK,aAAa,CAAC,EAAE;YACpB,OAAO,QAAQ,CAAC,UAAU,CACzB,CAAC,SAAS,CAAC,kBAAkB,CAAC,KAAK,CAAC,IAAI,QAAQ,CAAC;gBAChD,CAAC,SAAS,CAAC,kBAAkB,CAAC,KAAK,CAAC,GAAG,aAAa,CAAC,CACtD,CAAC;QACH;YACC,KAAK,EAAE,CAAC;YACR,OAAO,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;IACjC,CAAC;AACF,CAAC,CAAC;AAEF,MAAM,SAAS,GAAG,CAAC,MAAmC,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;AAEhF,MAAM,KAAK,GAAG,GAAU,EAAE;IACzB,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAC;AACnC,CAAC,CAAC"}
1
+ {"version":3,"file":"compositeIpAddress.js","sourceRoot":"","sources":["../src/compositeIpAddress.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import "./_virtual/_rolldown/runtime.js";
2
- import { getCompositeIpAddress, getIpAddressFromComposite } from "./compositeIpAddress.js";
2
+ import { getCompositeIpAddress, getIpAddressFromComposite, isSameIpOrigin } from "./compositeIpAddress.js";
3
3
  import { BlacklistRequestInspector, getPrioritisedAccessRule, getRequestUserScope, getVerdictCache, normalizeHeadersForMatching, rankCandidateRules } from "./api/blacklistRequestInspector.js";
4
4
  import { FrictionlessReason } from "./tasks/frictionless/frictionlessTasks.js";
5
5
  import { compareIPs } from "./services/ipComparison.js";
@@ -22,4 +22,4 @@ import { migrateFrictionlessLadder, runFrictionlessLadderMigration } from "./mig
22
22
  import { storeCaptchasExternally } from "./schedulers/captchaScheduler.js";
23
23
  import { getClientList } from "./schedulers/getClientList.js";
24
24
  import { updateSpamEmailDomainsScheduler } from "./schedulers/updateSpamEmailDomains.js";
25
- export { BlacklistRequestInspector, DEFAULT_JA4, FrictionlessReason, Tasks, asyncHandler, blockMiddleware, checkIfTaskIsRunning, compareIPs, createApiAdminRoutesProvider, deepValidateIpAddress, domainMiddleware, encodeStringAddress, evaluateIpValidationRules, getClientApiPathsExpectingProsopoHeaders, getClientList, getCompositeIpAddress, getHandshakeTiming, getIPAddress, getIPAddressFromBigInt, getIpAddressFromComposite, getJA4, getPrioritisedAccessRule, getRequestUserScope, getUserFromJWT, getVerdictCache, handshakeTimingMiddleware, headerCheckMiddleware, ignoreMiddleware, isTlsAvailable, ja4Middleware, migrateFrictionlessLadder, normalizeHeadersForMatching, prosopoRouter, prosopoVerifyRouter, publicRouter, rankCandidateRules, robotsMiddleware, runFrictionlessLadderMigration, shuffleArray, startProviderApi, storeCaptchasExternally, updateSpamEmailDomains, updateSpamEmailDomainsScheduler, validateIpAddress };
25
+ export { BlacklistRequestInspector, DEFAULT_JA4, FrictionlessReason, Tasks, asyncHandler, blockMiddleware, checkIfTaskIsRunning, compareIPs, createApiAdminRoutesProvider, deepValidateIpAddress, domainMiddleware, encodeStringAddress, evaluateIpValidationRules, getClientApiPathsExpectingProsopoHeaders, getClientList, getCompositeIpAddress, getHandshakeTiming, getIPAddress, getIPAddressFromBigInt, getIpAddressFromComposite, getJA4, getPrioritisedAccessRule, getRequestUserScope, getUserFromJWT, getVerdictCache, handshakeTimingMiddleware, headerCheckMiddleware, ignoreMiddleware, isSameIpOrigin, isTlsAvailable, ja4Middleware, migrateFrictionlessLadder, normalizeHeadersForMatching, prosopoRouter, prosopoVerifyRouter, publicRouter, rankCandidateRules, robotsMiddleware, runFrictionlessLadderMigration, shuffleArray, startProviderApi, storeCaptchasExternally, updateSpamEmailDomains, updateSpamEmailDomainsScheduler, validateIpAddress };
@@ -71,6 +71,6 @@ export declare class CaptchaManager {
71
71
  checkForHardBlock(userAccessRulesStorage: AccessRulesStorage, challengeRecord: PoWCaptchaRecord | PuzzleCaptchaRecord | UserCommitment, userAccount: string, headers: RequestHeaders, coords?: [number, number][][], countryCode?: string, asn?: number): Promise<AccessRule | undefined>;
72
72
  checkSpamEmail(email: string): Promise<boolean>;
73
73
  resolveTrafficFilterCheck(env: ProviderEnvironment, recordIpInfo: IPInfoResponse | undefined, trafficFilter: Partial<ITrafficFilter> | undefined, currentIp?: string, enrichedDnsEvent?: EnrichedDnsEvent): Promise<TrafficCheckResult>;
74
- static canClientSeeScore(tier: Tier, score?: number): boolean | 0 | undefined;
74
+ static canClientSeeScore(tier: Tier, score?: number): boolean;
75
75
  }
76
76
  //# sourceMappingURL=captchaManager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"captchaManager.d.ts","sourceRoot":"","sources":["../../src/tasks/captchaManager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"captchaManager.d.ts","sourceRoot":"","sources":["../../src/tasks/captchaManager.ts"],"names":[],"mappings":"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"}
@@ -563,8 +563,22 @@ var CaptchaManager = class CaptchaManager {
563
563
  };
564
564
  return checkTrafficFilter(currentIp ? await env.ipInfoService.lookup(currentIp) : recordIpInfo, effective, extraIpInfosFromEnrichedDnsEvent(enrichedDnsEvent), enrichedDnsEvent?.pathValid);
565
565
  }
566
+ /**
567
+ * Does this client's tier entitle it to the bot score, and is there one?
568
+ *
569
+ * `score !== undefined`, not `score`: a session with nothing wrong with it
570
+ * scores 0, and a truthiness test dropped the field for exactly those
571
+ * users — a paying customer reading `score` got a present field for
572
+ * every suspicious visitor and a missing one for their cleanest. It has
573
+ * been invisible because `Math.random() * 0.3` makes an exact 0 all but
574
+ * impossible; taking that noise out (see captcha-private#4433) is what
575
+ * would expose it.
576
+ *
577
+ * Returning `boolean` rather than the old `number | boolean | undefined`,
578
+ * which came from `&&`-chaining the score and the tier.
579
+ */
566
580
  static canClientSeeScore(tier, score) {
567
- return score && tier && tier !== Tier.Free;
581
+ return score !== void 0 && tier !== Tier.Free;
568
582
  }
569
583
  };
570
584
  //#endregion