@prosopo/provider 5.13.4 → 5.15.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 +30 -30
- package/.turbo/turbo-build$colon$tsc.log +27 -30
- package/.turbo/turbo-build.log +30 -33
- package/CHANGELOG.md +233 -0
- package/LICENSE +201 -0
- package/dist/api/adminAuthOptions.d.ts +4 -0
- package/dist/api/adminAuthOptions.d.ts.map +1 -0
- package/dist/api/adminAuthOptions.js +34 -0
- package/dist/api/adminAuthOptions.js.map +1 -0
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/constants.d.ts +2 -1
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/constants.d.ts.map +1 -1
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/constants.js +11 -2
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/constants.js.map +1 -1
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/handler.d.ts.map +1 -1
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/handler.js +16 -11
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/handler.js.map +1 -1
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/refreshLineage.d.ts +5 -0
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/refreshLineage.d.ts.map +1 -0
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/refreshLineage.js +20 -0
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/refreshLineage.js.map +1 -0
- package/dist/api/captcha/getPuzzleCaptchaChallenge.d.ts.map +1 -1
- package/dist/api/captcha/getPuzzleCaptchaChallenge.js +24 -0
- package/dist/api/captcha/getPuzzleCaptchaChallenge.js.map +1 -1
- package/dist/api/captcha/submitPoWCaptchaSolution.d.ts +4 -11
- package/dist/api/captcha/submitPoWCaptchaSolution.d.ts.map +1 -1
- package/dist/api/captcha/submitPoWCaptchaSolution.js +12 -17
- package/dist/api/captcha/submitPoWCaptchaSolution.js.map +1 -1
- package/dist/api/detectorPoolBodyParser.d.ts +4 -0
- package/dist/api/detectorPoolBodyParser.d.ts.map +1 -0
- package/dist/api/detectorPoolBodyParser.js +31 -0
- package/dist/api/detectorPoolBodyParser.js.map +1 -0
- package/dist/api/domainMiddleware.d.ts.map +1 -1
- package/dist/api/domainMiddleware.js +5 -1
- package/dist/api/domainMiddleware.js.map +1 -1
- package/dist/api/metrics.d.ts +2 -1
- package/dist/api/metrics.d.ts.map +1 -1
- package/dist/api/metrics.js +46 -4
- package/dist/api/metrics.js.map +1 -1
- package/dist/api/rawTlsSignalsMiddleware.d.ts +14 -1
- package/dist/api/rawTlsSignalsMiddleware.d.ts.map +1 -1
- package/dist/api/rawTlsSignalsMiddleware.js +111 -23
- package/dist/api/rawTlsSignalsMiddleware.js.map +1 -1
- package/dist/api/startProviderApi.d.ts.map +1 -1
- package/dist/api/startProviderApi.js +8 -5
- package/dist/api/startProviderApi.js.map +1 -1
- package/dist/api/verify.d.ts.map +1 -1
- package/dist/api/verify.js +50 -8
- package/dist/api/verify.js.map +1 -1
- package/dist/cjs/api/adminAuthOptions.cjs +35 -0
- package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/constants.cjs +10 -0
- package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/handler.cjs +14 -8
- package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/refreshLineage.cjs +20 -0
- package/dist/cjs/api/captcha/getPuzzleCaptchaChallenge.cjs +24 -0
- package/dist/cjs/api/captcha/submitPoWCaptchaSolution.cjs +10 -15
- package/dist/cjs/api/detectorPoolBodyParser.cjs +33 -0
- package/dist/cjs/api/domainMiddleware.cjs +5 -1
- package/dist/cjs/api/metrics.cjs +46 -3
- package/dist/cjs/api/rawTlsSignalsMiddleware.cjs +111 -22
- package/dist/cjs/api/startProviderApi.cjs +8 -5
- package/dist/cjs/api/verify.cjs +50 -8
- package/dist/cjs/compositeIpAddress.cjs +21 -7
- package/dist/cjs/tasks/captchaManager.cjs +15 -0
- package/dist/cjs/tasks/captchaTypeSelection.cjs +23 -2
- package/dist/cjs/tasks/client/clientTasks.cjs +25 -4
- package/dist/cjs/tasks/dataset/datasetTasksUtils.cjs +1 -1
- package/dist/cjs/tasks/frictionless/frictionlessTasks.cjs +26 -23
- package/dist/cjs/tasks/imgCaptcha/imgCaptchaTasks.cjs +4 -11
- package/dist/cjs/tasks/powCaptcha/powTasks.cjs +7 -11
- package/dist/cjs/tasks/powCaptcha/powTasksUtils.cjs +2 -0
- package/dist/cjs/tasks/puzzle/backgroundBuffer.cjs +3 -3
- package/dist/cjs/tasks/puzzle/nativeBackground.cjs +12 -5
- package/dist/cjs/tasks/puzzle/puzzleRenderer.cjs +4 -3
- package/dist/cjs/tasks/puzzleCaptcha/puzzleTasks.cjs +2 -9
- package/dist/cjs/utils/tarpitPadding.cjs +81 -10
- package/dist/compositeIpAddress.d.ts.map +1 -1
- package/dist/compositeIpAddress.js +21 -7
- package/dist/compositeIpAddress.js.map +1 -1
- package/dist/tasks/captchaManager.d.ts.map +1 -1
- package/dist/tasks/captchaManager.js +16 -1
- package/dist/tasks/captchaManager.js.map +1 -1
- package/dist/tasks/captchaTypeSelection.d.ts +3 -1
- package/dist/tasks/captchaTypeSelection.d.ts.map +1 -1
- package/dist/tasks/captchaTypeSelection.js +23 -3
- package/dist/tasks/captchaTypeSelection.js.map +1 -1
- package/dist/tasks/client/clientTasks.d.ts +1 -0
- package/dist/tasks/client/clientTasks.d.ts.map +1 -1
- package/dist/tasks/client/clientTasks.js +25 -5
- package/dist/tasks/client/clientTasks.js.map +1 -1
- package/dist/tasks/dataset/datasetTasksUtils.js +1 -1
- package/dist/tasks/dataset/datasetTasksUtils.js.map +1 -1
- package/dist/tasks/frictionless/frictionlessTasks.d.ts +3 -1
- package/dist/tasks/frictionless/frictionlessTasks.d.ts.map +1 -1
- package/dist/tasks/frictionless/frictionlessTasks.js +28 -25
- package/dist/tasks/frictionless/frictionlessTasks.js.map +1 -1
- package/dist/tasks/frictionless/routingMachine.d.ts +1 -2
- package/dist/tasks/frictionless/routingMachine.d.ts.map +1 -1
- package/dist/tasks/frictionless/routingMachine.js.map +1 -1
- package/dist/tasks/imgCaptcha/imgCaptchaTasks.d.ts.map +1 -1
- package/dist/tasks/imgCaptcha/imgCaptchaTasks.js +4 -11
- package/dist/tasks/imgCaptcha/imgCaptchaTasks.js.map +1 -1
- package/dist/tasks/powCaptcha/powTasks.d.ts.map +1 -1
- package/dist/tasks/powCaptcha/powTasks.js +8 -12
- package/dist/tasks/powCaptcha/powTasks.js.map +1 -1
- package/dist/tasks/powCaptcha/powTasksUtils.d.ts +1 -0
- package/dist/tasks/powCaptcha/powTasksUtils.d.ts.map +1 -1
- package/dist/tasks/powCaptcha/powTasksUtils.js +2 -1
- package/dist/tasks/powCaptcha/powTasksUtils.js.map +1 -1
- package/dist/tasks/puzzle/backgroundBuffer.d.ts +3 -2
- package/dist/tasks/puzzle/backgroundBuffer.d.ts.map +1 -1
- package/dist/tasks/puzzle/backgroundBuffer.js +3 -3
- package/dist/tasks/puzzle/backgroundBuffer.js.map +1 -1
- package/dist/tasks/puzzle/nativeBackground.d.ts +5 -1
- package/dist/tasks/puzzle/nativeBackground.d.ts.map +1 -1
- package/dist/tasks/puzzle/nativeBackground.js +12 -5
- package/dist/tasks/puzzle/nativeBackground.js.map +1 -1
- package/dist/tasks/puzzle/puzzleRenderer.d.ts +2 -0
- package/dist/tasks/puzzle/puzzleRenderer.d.ts.map +1 -1
- package/dist/tasks/puzzle/puzzleRenderer.js +4 -3
- package/dist/tasks/puzzle/puzzleRenderer.js.map +1 -1
- package/dist/tasks/puzzleCaptcha/puzzleTasks.d.ts.map +1 -1
- package/dist/tasks/puzzleCaptcha/puzzleTasks.js +2 -9
- package/dist/tasks/puzzleCaptcha/puzzleTasks.js.map +1 -1
- package/dist/tests/integration/clientSettingsPersistence.integration.test.js +2 -0
- package/dist/tests/integration/clientSettingsPersistence.integration.test.js.map +1 -1
- package/dist/tests/unit/api/adminAuthOptions.unit.test.d.ts +2 -0
- package/dist/tests/unit/api/adminAuthOptions.unit.test.d.ts.map +1 -0
- package/dist/tests/unit/api/adminAuthOptions.unit.test.js +38 -0
- package/dist/tests/unit/api/adminAuthOptions.unit.test.js.map +1 -0
- package/dist/tests/unit/api/captcha/getFrictionlessCaptchaChallenge/constants.unit.test.js +35 -2
- package/dist/tests/unit/api/captcha/getFrictionlessCaptchaChallenge/constants.unit.test.js.map +1 -1
- package/dist/tests/unit/api/captcha/getFrictionlessCaptchaChallenge/refreshLineage.unit.test.d.ts +2 -0
- package/dist/tests/unit/api/captcha/getFrictionlessCaptchaChallenge/refreshLineage.unit.test.d.ts.map +1 -0
- package/dist/tests/unit/api/captcha/getFrictionlessCaptchaChallenge/refreshLineage.unit.test.js +45 -0
- package/dist/tests/unit/api/captcha/getFrictionlessCaptchaChallenge/refreshLineage.unit.test.js.map +1 -0
- package/dist/tests/unit/api/captcha/submitPoWCaptchaSolution.escalation.unit.test.js +15 -1
- package/dist/tests/unit/api/captcha/submitPoWCaptchaSolution.escalation.unit.test.js.map +1 -1
- package/dist/tests/unit/api/detectorPoolBodyParser.unit.test.d.ts +2 -0
- package/dist/tests/unit/api/detectorPoolBodyParser.unit.test.d.ts.map +1 -0
- package/dist/tests/unit/api/detectorPoolBodyParser.unit.test.js +64 -0
- package/dist/tests/unit/api/detectorPoolBodyParser.unit.test.js.map +1 -0
- package/dist/tests/unit/api/domainMiddlewareErrorBody.unit.test.d.ts +2 -0
- package/dist/tests/unit/api/domainMiddlewareErrorBody.unit.test.d.ts.map +1 -0
- package/dist/tests/unit/api/domainMiddlewareErrorBody.unit.test.js +67 -0
- package/dist/tests/unit/api/domainMiddlewareErrorBody.unit.test.js.map +1 -0
- package/dist/tests/unit/api/getFrictionlessCaptchaChallenge.unit.test.js +174 -23
- package/dist/tests/unit/api/getFrictionlessCaptchaChallenge.unit.test.js.map +1 -1
- package/dist/tests/unit/api/metricsAccess.unit.test.d.ts +2 -0
- package/dist/tests/unit/api/metricsAccess.unit.test.d.ts.map +1 -0
- package/dist/tests/unit/api/metricsAccess.unit.test.js +87 -0
- package/dist/tests/unit/api/metricsAccess.unit.test.js.map +1 -0
- package/dist/tests/unit/api/public.unit.test.js +4 -1
- package/dist/tests/unit/api/public.unit.test.js.map +1 -1
- package/dist/tests/unit/api/rawTlsSignalsMiddleware.unit.test.js +96 -1
- package/dist/tests/unit/api/rawTlsSignalsMiddleware.unit.test.js.map +1 -1
- package/dist/tests/unit/api/validateAddress.unit.test.js +1 -1
- package/dist/tests/unit/api/validateAddress.unit.test.js.map +1 -1
- package/dist/tests/unit/api/verifyBadDappSignature.unit.test.d.ts +2 -0
- package/dist/tests/unit/api/verifyBadDappSignature.unit.test.d.ts.map +1 -0
- package/dist/tests/unit/api/verifyBadDappSignature.unit.test.js +96 -0
- package/dist/tests/unit/api/verifyBadDappSignature.unit.test.js.map +1 -0
- package/dist/tests/unit/api/verifyMalformedToken.unit.test.d.ts +2 -0
- package/dist/tests/unit/api/verifyMalformedToken.unit.test.d.ts.map +1 -0
- package/dist/tests/unit/api/verifyMalformedToken.unit.test.js +89 -0
- package/dist/tests/unit/api/verifyMalformedToken.unit.test.js.map +1 -0
- package/dist/tests/unit/compositeIpAddress.unit.test.js +12 -3
- package/dist/tests/unit/compositeIpAddress.unit.test.js.map +1 -1
- package/dist/tests/unit/tasks/captchaManager.unit.test.js +51 -0
- package/dist/tests/unit/tasks/captchaManager.unit.test.js.map +1 -1
- package/dist/tests/unit/tasks/captchaTypeSelection.unit.test.js +20 -1
- package/dist/tests/unit/tasks/captchaTypeSelection.unit.test.js.map +1 -1
- package/dist/tests/unit/tasks/client/clientTasks.unit.test.js +33 -1
- package/dist/tests/unit/tasks/client/clientTasks.unit.test.js.map +1 -1
- package/dist/tests/unit/tasks/dataset/datasetTasksUtils.unit.test.js +14 -1
- package/dist/tests/unit/tasks/dataset/datasetTasksUtils.unit.test.js.map +1 -1
- package/dist/tests/unit/tasks/frictionless/allowedCaptchaTypes.unit.test.d.ts +2 -0
- package/dist/tests/unit/tasks/frictionless/allowedCaptchaTypes.unit.test.d.ts.map +1 -0
- package/dist/tests/unit/tasks/frictionless/allowedCaptchaTypes.unit.test.js +94 -0
- package/dist/tests/unit/tasks/frictionless/allowedCaptchaTypes.unit.test.js.map +1 -0
- package/dist/tests/unit/tasks/frictionless/refreshSwitch.unit.test.d.ts +2 -0
- package/dist/tests/unit/tasks/frictionless/refreshSwitch.unit.test.d.ts.map +1 -0
- package/dist/tests/unit/tasks/frictionless/refreshSwitch.unit.test.js +103 -0
- package/dist/tests/unit/tasks/frictionless/refreshSwitch.unit.test.js.map +1 -0
- package/dist/tests/unit/tasks/powCaptcha/powTasksUtils.unit.test.js +23 -1
- package/dist/tests/unit/tasks/powCaptcha/powTasksUtils.unit.test.js.map +1 -1
- package/dist/tests/unit/tasks/puzzle/backgroundBuffer.unit.test.js +1 -4
- package/dist/tests/unit/tasks/puzzle/backgroundBuffer.unit.test.js.map +1 -1
- package/dist/tests/unit/tasks/puzzle/nativeBackground.unit.test.js +10 -3
- package/dist/tests/unit/tasks/puzzle/nativeBackground.unit.test.js.map +1 -1
- package/dist/tests/unit/tasks/puzzle/puzzleRenderer.unit.test.d.ts +2 -0
- package/dist/tests/unit/tasks/puzzle/puzzleRenderer.unit.test.d.ts.map +1 -0
- package/dist/tests/unit/tasks/puzzle/puzzleRenderer.unit.test.js +35 -0
- package/dist/tests/unit/tasks/puzzle/puzzleRenderer.unit.test.js.map +1 -0
- package/dist/tests/unit/tasks/puzzleDifficultyDeviceCap.unit.test.d.ts +2 -0
- package/dist/tests/unit/tasks/puzzleDifficultyDeviceCap.unit.test.d.ts.map +1 -0
- package/dist/tests/unit/tasks/puzzleDifficultyDeviceCap.unit.test.js +49 -0
- package/dist/tests/unit/tasks/puzzleDifficultyDeviceCap.unit.test.js.map +1 -0
- package/dist/tests/unit/testUtils/mockProviderEnv.d.ts +17 -14
- package/dist/tests/unit/testUtils/mockProviderEnv.d.ts.map +1 -1
- package/dist/tests/unit/testUtils/mockProviderEnv.js.map +1 -1
- package/dist/tests/unit/utils/tarpitPadding.unit.test.js +118 -36
- package/dist/tests/unit/utils/tarpitPadding.unit.test.js.map +1 -1
- package/dist/utils/tarpitPadding.d.ts.map +1 -1
- package/dist/utils/tarpitPadding.js +81 -10
- package/dist/utils/tarpitPadding.js.map +1 -1
- package/package.json +105 -103
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,238 @@
|
|
|
1
1
|
# @prosopo/provider
|
|
2
2
|
|
|
3
|
+
## 5.15.0
|
|
4
|
+
### Minor Changes
|
|
5
|
+
|
|
6
|
+
- 1c13037: Add `captchaTypeFeatureFlags` to site settings, starting with `puzzle`. Setting
|
|
7
|
+
`puzzle: false` stops a site being served the puzzle captcha by any path: its
|
|
8
|
+
configured `captchaType`, `frictionlessTypes`, access policies, the traffic
|
|
9
|
+
filter, routing machines, PoW escalation, and puzzle sessions that already
|
|
10
|
+
exist. A site pinned to puzzle gets an image captcha instead (or PoW if image is
|
|
11
|
+
also off). The field is optional and has no stored default, so sites that never
|
|
12
|
+
set it behave exactly as before. The flag is meant for Prosopo staff, not site
|
|
13
|
+
owners.
|
|
14
|
+
- f961dab: Store everything needed to redraw a puzzle, so the portal can show the exact challenge a user was served.
|
|
15
|
+
|
|
16
|
+
Until now a puzzle record kept the target, the origin and the accuracy required (`tolerance`), and
|
|
17
|
+
nothing else. The things that decide what the puzzle actually looked like — how many decoy shapes were
|
|
18
|
+
scattered on it, how dark they were, how big the piece was, and which background was used — were
|
|
19
|
+
picked per challenge and then thrown away. So you could see that someone failed by 11px and had no way
|
|
20
|
+
to know whether they had been handed an easy puzzle or a nasty one.
|
|
21
|
+
|
|
22
|
+
Puzzle records now carry a `render` object with all of it: the difficulty ladder level, the piece size,
|
|
23
|
+
the frame geometry, the five render settings, and the two 128-bit seeds that regenerate the imagery.
|
|
24
|
+
Given those, the portal reproduces the background and the piece byte for byte.
|
|
25
|
+
|
|
26
|
+
To make that possible the renderer had to become reproducible. `renderPuzzle` and `createBackground`
|
|
27
|
+
now take an optional seed and report the one they used, instead of generating one internally and
|
|
28
|
+
discarding it; the background pool hands out each image together with its seed. Default behaviour is
|
|
29
|
+
unchanged — omit the seed and you still get a fresh random one.
|
|
30
|
+
|
|
31
|
+
The ladder level is new on the session too (`puzzleLevel`), because it was computed when the puzzle
|
|
32
|
+
was escalated and never written down anywhere. It is absent when the ladder did not choose the
|
|
33
|
+
puzzle — a site-configured puzzle or a traffic-filter override has no level.
|
|
34
|
+
|
|
35
|
+
The record is patched after the imagery is produced rather than written with the rest of the record,
|
|
36
|
+
because the piece size and the seeds only exist once the render has run, and the target has to be
|
|
37
|
+
durable before it is expressed in pixels. If that patch fails it is logged and ignored: losing a
|
|
38
|
+
diagnostic must not cost the user their solve. Records written before this change, and any challenge
|
|
39
|
+
whose render threw, simply have no `render`.
|
|
40
|
+
|
|
41
|
+
**The seeds are secret.** `puzzle-assets/src/prng.ts` explains why: they regenerate the clean
|
|
42
|
+
background, and a clean background can be diffed against the composite to read the target position
|
|
43
|
+
straight off. They were previously barred from leaving the provider entirely. They may now sit on the
|
|
44
|
+
captcha record, and nowhere else — not in a response, not in a log, not on the session. Anything that
|
|
45
|
+
exposes a puzzle record to a caller has to drop `render.backgroundSeed` and `render.renderSeed`, and
|
|
46
|
+
must not serve them at all while the challenge is still live. The comment in `prng.ts` now says so.
|
|
47
|
+
|
|
48
|
+
Test coverage. Three guards, each confirmed to fail when the thing it protects is broken:
|
|
49
|
+
`renderReplay.unit.test.ts` re-renders from the stored fields and asserts the bytes match, with one
|
|
50
|
+
case per field asserting that changing *only* that field changes the output — so a record missing a
|
|
51
|
+
field cannot pass; `puzzleRenderer.unit.test.ts` replays through the same entry points the portal would
|
|
52
|
+
use, which catches a background paired with the wrong seed; and `schemas.test.ts` asserts every
|
|
53
|
+
sub-field survives a strict-mode mongoose write, since a field absent from the schema is dropped
|
|
54
|
+
silently and would store nothing at all.
|
|
55
|
+
- 1ce9482: Cap automatic puzzle escalation one rung lower on touch devices than on pointer devices.
|
|
56
|
+
|
|
57
|
+
The puzzle's `tolerance` is an absolute CSS-pixel target and the widget renders into a fixed 300x200 container on every device, so a difficulty level asks the same placement accuracy of a fingertip as it does of a mouse.
|
|
58
|
+
|
|
59
|
+
`MAX_AUTO_ESCALATION_LEVEL_TOUCH` and `resolveMaxEscalationLevel(siteMaxLevel, isTouch)` are new in `@prosopo/captcha-severity`. The resolver takes the stricter of the site's own `puzzleMaxDifficulty` and the device ceiling, so a site set to 3 or 4 cannot out-vote the touch ceiling and a site pinned to 0 is not raised by it.
|
|
60
|
+
|
|
61
|
+
The provider now calls it from both places a puzzle difficulty is chosen: `sendCaptcha`, which reads `routingContext.platform.isMobile`, and the post-PoW escalation in `submitPoWCaptchaSolution`, which derives the platform from the originating session. That second path previously ignored the site's `puzzleMaxDifficulty` entirely and always clamped to the global ceiling; it now respects both caps.
|
|
62
|
+
|
|
63
|
+
Desktop behaviour is unchanged, and L4 stays unreachable by automatic escalation on either device.
|
|
64
|
+
- dcb691b: Add a refresh control to the puzzle captcha.
|
|
65
|
+
|
|
66
|
+
A user who can't solve the puzzle they were given can now ask for a different one, from a button in the puzzle's header. The replacement comes through a new frictionless session, like a wrong answer already does.
|
|
67
|
+
|
|
68
|
+
The widget tells the provider which session was refreshed (`refreshOf`). The provider then records `refreshOf`, `refreshCount` and `refreshedAfterMs` on the new session, so refresh behaviour can be scored later. After three refreshes in a row it serves an image challenge instead, with reason `PUZZLE_REFRESH_LIMIT`. It only does this if the site has image enabled. The switch only goes from puzzle to image, so a client that lies about its refreshes can only make its own challenge harder. A client that leaves the field out gets a normal session, the same as reloading the page.
|
|
69
|
+
|
|
70
|
+
The image widget's reload button now reports itself as a refresh too. That way a user who was moved onto image isn't sent back to the puzzle by their next reload.
|
|
71
|
+
|
|
72
|
+
### Patch Changes
|
|
73
|
+
|
|
74
|
+
- 7d57d2a: A proof-of-work solve is checked against the address the challenge was issued to, and a mismatch sends the user to an image captcha instead of approving them. That check compared the whole IPv4 address, so it fired for anyone whose address moved between asking for the challenge and solving it — which is normal behaviour on mobile and on carrier NAT, where the low octet gets reassigned mid-session. One EE subscriber was seen moving one address along in four seconds.
|
|
75
|
+
|
|
76
|
+
It now compares the /24, so a reassignment inside the same pool reads as the same place on the network. IPv6 already worked this way on the /64, for the same reason, and is unchanged. A solve arriving from a genuinely different network is still caught and still escalates, so the point of the check survives.
|
|
77
|
+
|
|
78
|
+
Unit tests cover a low-octet reassignment, both ends of a /24, two different /24s, and a pair of adjacent addresses that straddle the /24 boundary.
|
|
79
|
+
- 2118584: Trim the comments on the puzzle difficulty device ceiling. No behaviour change.
|
|
80
|
+
- 80b7780: Post-PoW routing now receives the widget mode from the originating session and whether the submitted click coords were all (0,0), so a routing rule can escalate visible-mode solves that carry no real click position.
|
|
81
|
+
- dd4c27c: Store the whole-SYN fields the tcp-probe sidecar now reports.
|
|
82
|
+
|
|
83
|
+
The sidecar's handshake record grew from 80 to 104 bytes and the tail was reordered (prosopo/Protect#1167). chaddy was updated to read both layouts and to forward the new fields as their own headers (prosopo/chaddy#16, #17); this is the provider side of that, so the values have somewhere to land instead of being dropped at the middleware.
|
|
84
|
+
|
|
85
|
+
Twelve new fields on `Session`, all optional: `tcpOptsKinds`, `tcpOptsPresent`, `tcpOptsCount`, `tcpTsval`, `tcpTsecr`, `tcpFlags`, `tcpDataOffsetResv`, `tcpUrgPtr`, `ipIdent`, `ipTotalLen`, `ipFragFlags`, `ipTos`. They are surfaced on the decision-machine input the same way the existing TCP fields are, so routing and verify rules can read them.
|
|
86
|
+
|
|
87
|
+
`tcpOptsKinds` is stored decoded — the IANA kind number of each TCP option in wire order, `[2, 4, 8, 1, 3]` on an ordinary Linux SYN. The probe emits it packed into a u64, and a u64 reaches 2^64 while a JS number is exact only to 2^53, so the packed form could not be held without rounding; the rounding would land in the low bytes, which are the option kinds themselves. The array holds the same information and is queryable per position. It also replaces the old `tcpOptsOrder`, which packed 4 bits per option and so could not tell MSS from TCP Fast Open, or Window Scale from MD5, and could not represent MPTCP at all.
|
|
88
|
+
|
|
89
|
+
`tcpOptsFlags` and `tcpOptsOrder` are kept and still read. A pronode running an older chaddy still sends them, and years of rows hold them, so removing them would both lose the rollout window and break any routing rule already reading them. They go undefined on new sessions once the fleet is rolled.
|
|
90
|
+
|
|
91
|
+
`tcpTsval` and `tcpTsecr` are written only when the Timestamps option was actually on the SYN. A TSval of 0 is legal and a TSecr of 0 is expected, so neither can use zero to mean absent.
|
|
92
|
+
|
|
93
|
+
Six places named every one of these fields by hand — the middleware's copy onto the request, the session write, and four task files building the decision-machine bag. They now all go through one list, with a compile-time check that every field of `RawTlsSignals` is on it. That is not tidying: the Session projection comment in `@prosopo/types-database` records a field being missed in exactly this way, after which the rules reading it got `undefined` and silently never fired against real traffic.
|
|
94
|
+
|
|
95
|
+
Separately, the provider compose no longer defaults the sidecar to `prosopo/tcp-probe:latest`. The probe's reply is a bare fixed-size struct with no version in it, so the image tag is the only statement of which layout a host serves, and publishing `:latest` would change that on every pronode at the next pull with nobody running a deploy. The default is now the `0.1.1` both Protect inventories already pin.
|
|
96
|
+
|
|
97
|
+
Tests: the new headers all parse; a packed value above 2^53 decodes without losing its low bytes; the kind pairs the old encoding aliased stay distinct; a trailing end-of-option-list terminates the list rather than appearing in it; an all-zero packed value reads as absent rather than as an empty list; malformed and out-of-range values are ignored; the legacy header pair is still read; and a zero is kept rather than dropped, since `ipIdent` 0 and `tcpTsecr` 0 are real readings.
|
|
98
|
+
- Updated dependencies [1c13037]
|
|
99
|
+
- Updated dependencies [f961dab]
|
|
100
|
+
- Updated dependencies [a17e8eb]
|
|
101
|
+
- Updated dependencies [7d57d2a]
|
|
102
|
+
- Updated dependencies [2118584]
|
|
103
|
+
- Updated dependencies [1ce9482]
|
|
104
|
+
- Updated dependencies [6e2eb55]
|
|
105
|
+
- Updated dependencies [dcb691b]
|
|
106
|
+
- Updated dependencies [80b7780]
|
|
107
|
+
- Updated dependencies [dd4c27c]
|
|
108
|
+
- @prosopo/types@5.13.0
|
|
109
|
+
- @prosopo/types-database@5.8.0
|
|
110
|
+
- @prosopo/puzzle-assets@0.2.0
|
|
111
|
+
- @prosopo/util@3.3.14
|
|
112
|
+
- @prosopo/captcha-severity@1.2.0
|
|
113
|
+
- @prosopo/api@4.4.0
|
|
114
|
+
- @prosopo/locale@3.7.0
|
|
115
|
+
- @prosopo/api-express-router@3.2.1
|
|
116
|
+
- @prosopo/common@3.1.62
|
|
117
|
+
- @prosopo/database@4.1.4
|
|
118
|
+
- @prosopo/datasets@3.2.1
|
|
119
|
+
- @prosopo/env@3.6.69
|
|
120
|
+
- @prosopo/ipinfo@0.4.14
|
|
121
|
+
- @prosopo/keyring@2.10.1
|
|
122
|
+
- @prosopo/load-balancer@2.11.5
|
|
123
|
+
- @prosopo/types-env@2.11.15
|
|
124
|
+
- @prosopo/user-access-policy@3.14.15
|
|
125
|
+
- @prosopo/api-route@2.6.63
|
|
126
|
+
- @prosopo/logger@2.1.3
|
|
127
|
+
- @prosopo/redis-client@1.0.40
|
|
128
|
+
- @prosopo/util-crypto@13.6.0
|
|
129
|
+
- @prosopo/web-bot-auth@0.1.3
|
|
130
|
+
|
|
131
|
+
## 5.14.0
|
|
132
|
+
### Minor Changes
|
|
133
|
+
|
|
134
|
+
- ede4352: Admin tokens can now be bound to one provider and used only once. `jwtVerify` takes optional checks for the `aud` claim and for the longest allowed lifetime, and the provider's admin check uses them. A token that names an audience must name this provider: its host, `https://` plus its host, or one of the values in `PROSOPO_ADMIN_JWT_AUDIENCE`. A token that carries a `jti` is accepted once per provider process. Tokens may live at most one hour (`PROSOPO_ADMIN_JWT_MAX_LIFETIME_SECONDS`).
|
|
135
|
+
|
|
136
|
+
Migration: tokens without `aud` or `jti` are still accepted, so current callers keep working. Callers should add both, for example `pair.jwtIssue({ expiresIn }, { aud: provider.url, jti: randomUUID() })`, minting one token per provider and per request. Callers that reuse one token for several requests to the same provider must mint a new one per request before they add `jti`. Once every caller sends `aud`, set `PROSOPO_ADMIN_JWT_REQUIRE_AUDIENCE=true` to refuse tokens without it.
|
|
137
|
+
- e62661c: `/metrics` is no longer open to everyone by default. Without `PROSOPO_METRICS_TOKEN`, only direct requests from loopback or private addresses are served, such as a scraper on the docker network. Requests relayed by a reverse proxy (they carry `X-Forwarded-For`, `Forwarded` or `X-Real-IP`) get 403. With `PROSOPO_METRICS_TOKEN` set, any caller with `Authorization: Bearer <token>` is served, as before. The token is now compared in constant time. Set `PROSOPO_METRICS_PUBLIC=true` to keep the old open endpoint. A scraper that reaches the provider through a proxy or from a public address needs either the token or that flag.
|
|
138
|
+
|
|
139
|
+
### Patch Changes
|
|
140
|
+
|
|
141
|
+
- fc79e06: The provider now only accepts a detector-pool upload of up to 128 MB from a caller with a valid admin token. Before, the large upload limit applied to anyone who sent a request to that path, because the body was read and parsed before the admin check and the rate limits ran, so unauthenticated requests could make the provider buffer and parse up to 128 MB each. Other requests to that path now get the normal 1 MB limit and are then refused by the admin check.
|
|
142
|
+
- 382f96b: Allowed-domain patterns that contain `*` are now matched without a regular expression. A pattern such as `*a*a*a*a*a*a*a*a*a*b` used to take tens of seconds to check against a long hostname, blocking the provider for every other request while it ran. Matching now takes time proportional to the pattern and hostname lengths, with the same results as before.
|
|
143
|
+
- 9ed0afd: 401 responses no longer include server internals. The admin auth check returned the whole error object, which included the request's i18n instance with its settings and file paths (about 16 KB per response), or whatever a failing check had thrown. It now returns `{ error: { code: 401, key, message } }`, the same shape as other API errors. The domain check returned unexpected errors, such as database errors, in the response body. It now returns a fixed message and logs the error.
|
|
144
|
+
- 3fe7b19: Check the number of unsolved captchas in a dataset against the configured minimum, instead of checking the number of solved ones twice.
|
|
145
|
+
|
|
146
|
+
The unsolved check compared the solved count with `unsolved.count`, so a dataset where every captcha was solved passed even when unsolved captchas were required. It now counts the captchas without a solution. Production sets `unsolved.count` to 0, so its behaviour does not change.
|
|
147
|
+
- b1becee: Stop padding the `/frictionless` response. The tarpit pads the challenge, and that endpoint does not serve one.
|
|
148
|
+
|
|
149
|
+
`GetFrictionlessCaptchaResponse` is `{captchaType, sessionId, dns_url}` — a session envelope. The widget then fetches the challenge from `/captcha/pow`, `/captcha/image` or `/captcha/puzzle`, and each of those resolves its own traffic-filter verdict and pads there, which is where the original feature put it.
|
|
150
|
+
|
|
151
|
+
Padding the envelope as well charged a tarpitted session twice. Measured on one site over 6h: 418 of 868 padded responses (48%, 1.48 GB of 3.09 GB) were `/frictionless`, roughly one per padded challenge.
|
|
152
|
+
|
|
153
|
+
This restores the frictionless handler to its pre-tarpit state, so it also reverts the hoist that extended envelope padding to reused sessions and pinned-captcha-type sites. Nothing is lost from the feature: each of those sessions still fetches a challenge from a typed endpoint, which pads it.
|
|
154
|
+
|
|
155
|
+
Kept from the same work: `padBytes` on the Mongoose traffic-category schema, without which the setting could not persist at all, and the padding writer's handling of a fieldless or non-object body.
|
|
156
|
+
- 3e1053b: Pad the challenge on the two frictionless paths that return early: a reused session, and a site pinned to a concrete captcha type.
|
|
157
|
+
|
|
158
|
+
`applyTrafficFilterAtRequestTime` ran after both short-circuits, so neither resolved a verdict and neither response was padded. On a site whose traffic is mostly returning visitors that is most of the traffic — on Twickets, session reuse is 11–18% of decisions and rose to ~16% after their proxy pool consolidated onto fewer IPs.
|
|
159
|
+
|
|
160
|
+
The verdict now resolves once, before both, and the pad is attached from it. No extra work: the call is synchronous and reads `req.ipInfo`, which `ipInfoMiddleware` already populates for every request.
|
|
161
|
+
|
|
162
|
+
The pad is read live on every request rather than stored on the session, unlike `captchaType`, `powDifficulty` and `puzzleTolerance`. Those are frozen because they are part of the issued challenge — the PoW string was minted at that difficulty — so re-deriving them mid-session would invalidate work already handed out. Nothing verifies the pad, so it has no such constraint, and reading it live means a newly-configured pad applies on the next request instead of only after every live session has expired.
|
|
163
|
+
|
|
164
|
+
A reused session keeps its cached captcha type, and a pinned site keeps serving the type it pinned. Making a category's `captchaType` override win over a site-level pin is a larger behaviour change and is left on prosopo/captcha#3463.
|
|
165
|
+
|
|
166
|
+
Blocking was never affected by any of this: `resolveTrafficFilterCheck` runs at submit time from the site's current settings and a fresh IP lookup, so a blocked category was always rejected regardless of how the challenge was issued.
|
|
167
|
+
|
|
168
|
+
Tests: the pad is attached on a reused session without evicting it or changing its cached type, and on a site pinned to each of pow / image / puzzle without changing which challenge is sent.
|
|
169
|
+
- df06006: Stream the traffic-filter tarpit padding with backpressure, and spread it across the response body instead of a single leading field.
|
|
170
|
+
|
|
171
|
+
The padding is written in 64 KiB chunks that wait for the socket to drain, and is abandoned if the connection goes away, so provider memory stays flat while a padded response is in flight however slowly it is read.
|
|
172
|
+
|
|
173
|
+
It is also split into several members with generated keys, one before each real field, rather than one `pad` member at the front. The body is the same size and parses the same way; no consumer reads these fields.
|
|
174
|
+
- 06784d0: Translation keys are now a typed union built from the English catalogue, so calling the translator with a key that does not exist fails to compile. Error classes only pass a message to the translator when it is a real catalogue key, and free-text messages are shown as they are.
|
|
175
|
+
- 7e9cd1e: The verify endpoints (image, PoW, puzzle and authenticated session) now answer 400 `GENERAL.INVALID_SIGNATURE` when the `dappSignature` is not hex, is the wrong length, or does not match the site key. Before, the error from the signature check fell into each handler's catch-all and came back as a 500. Anyone could call these endpoints and push up the provider's 500 rate, which made it look unhealthy and skewed the error-rate metrics. Real server faults later in the handlers still return 500.
|
|
176
|
+
- f7cfa1c: Return 400, not 500, when a verify request carries an undecodable token.
|
|
177
|
+
|
|
178
|
+
Every verify endpoint (image, PoW, puzzle and authenticated-session) decodes
|
|
179
|
+
the hex `ProcaptchaToken` inside a `try` whose `catch` answers
|
|
180
|
+
`API.BAD_REQUEST` with HTTP 500. The body schema only checks that the token is
|
|
181
|
+
a bounded `0x`-prefixed string, so a value like `0x1234` passes validation and
|
|
182
|
+
then fails to decode into a `ProcaptchaToken` SCALE struct — a bad-input case,
|
|
183
|
+
not a server fault.
|
|
184
|
+
|
|
185
|
+
The endpoints are unauthenticated, so any caller could make the provider
|
|
186
|
+
answer 500 at will. That mis-signals provider health and inflates the
|
|
187
|
+
error-rate metrics that alerting and the http_requests_total status label feed
|
|
188
|
+
from, without leaking anything (the response body is unchanged).
|
|
189
|
+
|
|
190
|
+
Decoding now goes through a helper that maps a decode failure to a 400
|
|
191
|
+
`CAPTCHA.PARSE_ERROR`, matching the existing 400 the same endpoints already
|
|
192
|
+
return for a non-hex token. Genuine server errors later in each handler still
|
|
193
|
+
surface as 500.
|
|
194
|
+
- Updated dependencies [ede4352]
|
|
195
|
+
- Updated dependencies [f53ddb2]
|
|
196
|
+
- Updated dependencies [97d65fa]
|
|
197
|
+
- Updated dependencies [08daf16]
|
|
198
|
+
- Updated dependencies [1144e04]
|
|
199
|
+
- Updated dependencies [de6bb08]
|
|
200
|
+
- Updated dependencies [2145922]
|
|
201
|
+
- Updated dependencies [b017dfb]
|
|
202
|
+
- Updated dependencies [8ed0eb8]
|
|
203
|
+
- Updated dependencies [9ed0afd]
|
|
204
|
+
- Updated dependencies [70fcefd]
|
|
205
|
+
- Updated dependencies [06784d0]
|
|
206
|
+
- Updated dependencies [06784d0]
|
|
207
|
+
- Updated dependencies [8d7ba8c]
|
|
208
|
+
- Updated dependencies [995e954]
|
|
209
|
+
- Updated dependencies [97a799e]
|
|
210
|
+
- Updated dependencies [9fc1e8a]
|
|
211
|
+
- Updated dependencies [4461043]
|
|
212
|
+
- Updated dependencies [92edebd]
|
|
213
|
+
- Updated dependencies [54a07f3]
|
|
214
|
+
- Updated dependencies [b75e9b7]
|
|
215
|
+
- Updated dependencies [6d5b7f5]
|
|
216
|
+
- @prosopo/util-crypto@13.6.0
|
|
217
|
+
- @prosopo/keyring@2.10.0
|
|
218
|
+
- @prosopo/types@5.12.0
|
|
219
|
+
- @prosopo/api-express-router@3.2.0
|
|
220
|
+
- @prosopo/database@4.1.3
|
|
221
|
+
- @prosopo/datasets@3.2.0
|
|
222
|
+
- @prosopo/util@3.3.13
|
|
223
|
+
- @prosopo/locale@3.6.2
|
|
224
|
+
- @prosopo/load-balancer@2.11.4
|
|
225
|
+
- @prosopo/common@3.1.61
|
|
226
|
+
- @prosopo/types-database@5.7.3
|
|
227
|
+
- @prosopo/env@3.6.68
|
|
228
|
+
- @prosopo/user-access-policy@3.14.14
|
|
229
|
+
- @prosopo/types-env@2.11.14
|
|
230
|
+
- @prosopo/api@4.3.8
|
|
231
|
+
- @prosopo/ipinfo@0.4.13
|
|
232
|
+
- @prosopo/logger@2.1.2
|
|
233
|
+
- @prosopo/api-route@2.6.62
|
|
234
|
+
- @prosopo/redis-client@1.0.39
|
|
235
|
+
|
|
3
236
|
## 5.13.4
|
|
4
237
|
### Patch Changes
|
|
5
238
|
|
package/LICENSE
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work
|
|
38
|
+
(an example is provided in the Appendix below).
|
|
39
|
+
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
+
the Work and Derivative Works thereof.
|
|
47
|
+
|
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
|
49
|
+
the original version of the Work and any modifications or additions
|
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
+
|
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
64
|
+
subsequently incorporated within the Work.
|
|
65
|
+
|
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
|
72
|
+
|
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
+
where such license applies only to those patent claims licensable
|
|
79
|
+
by such Contributor that are necessarily infringed by their
|
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
+
institute patent litigation against any entity (including a
|
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
+
or contributory patent infringement, then any patent licenses
|
|
86
|
+
granted to You under this License for that Work shall terminate
|
|
87
|
+
as of the date such litigation is filed.
|
|
88
|
+
|
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
+
modifications, and in Source or Object form, provided that You
|
|
92
|
+
meet the following conditions:
|
|
93
|
+
|
|
94
|
+
(a) You must give any other recipients of the Work or
|
|
95
|
+
Derivative Works a copy of this License; and
|
|
96
|
+
|
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
|
98
|
+
stating that You changed the files; and
|
|
99
|
+
|
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
|
102
|
+
attribution notices from the Source form of the Work,
|
|
103
|
+
excluding those notices that do not pertain to any part of
|
|
104
|
+
the Derivative Works; and
|
|
105
|
+
|
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
|
108
|
+
include a readable copy of the attribution notices contained
|
|
109
|
+
within such NOTICE file, excluding those notices that do not
|
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
|
111
|
+
of the following places: within a NOTICE text file distributed
|
|
112
|
+
as part of the Derivative Works; within the Source form or
|
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
|
114
|
+
within a display generated by the Derivative Works, if and
|
|
115
|
+
wherever such third-party notices normally appear. The contents
|
|
116
|
+
of the NOTICE file are for informational purposes only and
|
|
117
|
+
do not modify the License. You may add Your own attribution
|
|
118
|
+
notices within Derivative Works that You distribute, alongside
|
|
119
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
120
|
+
that such additional attribution notices cannot be construed
|
|
121
|
+
as modifying the License.
|
|
122
|
+
|
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
|
124
|
+
may provide additional or different license terms and conditions
|
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
+
the conditions stated in this License.
|
|
129
|
+
|
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
+
this License, without any additional terms or conditions.
|
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
+
the terms of any separate license agreement you may have executed
|
|
136
|
+
with Licensor regarding such Contributions.
|
|
137
|
+
|
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
+
except as required for reasonable and customary use in describing the
|
|
141
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
142
|
+
|
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
|
151
|
+
risks associated with Your exercise of permissions under this License.
|
|
152
|
+
|
|
153
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
154
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
155
|
+
unless required by applicable law (such as deliberate and grossly
|
|
156
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
157
|
+
liable to You for damages, including any direct, indirect, special,
|
|
158
|
+
incidental, or consequential damages of any character arising as a
|
|
159
|
+
result of this License or out of the use or inability to use the
|
|
160
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
161
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
162
|
+
other commercial damages or losses), even if such Contributor
|
|
163
|
+
has been advised of the possibility of such damages.
|
|
164
|
+
|
|
165
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
166
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
167
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
168
|
+
or other liability obligations and/or rights consistent with this
|
|
169
|
+
License. However, in accepting such obligations, You may act only
|
|
170
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
171
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
172
|
+
defend, and hold each Contributor harmless for any liability
|
|
173
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
174
|
+
of your accepting any such warranty or additional liability.
|
|
175
|
+
|
|
176
|
+
END OF TERMS AND CONDITIONS
|
|
177
|
+
|
|
178
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
179
|
+
|
|
180
|
+
To apply the Apache License to your work, attach the following
|
|
181
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
182
|
+
replaced with your own identifying information. (Don't include
|
|
183
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
184
|
+
comment syntax for the file format. We also recommend that a
|
|
185
|
+
file or class name and description of purpose be included on the
|
|
186
|
+
same "printed page" as the copyright notice for easier
|
|
187
|
+
identification within third-party archives.
|
|
188
|
+
|
|
189
|
+
Copyright 2022 PROSOPO LIMITED
|
|
190
|
+
|
|
191
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
|
+
you may not use this file except in compliance with the License.
|
|
193
|
+
You may obtain a copy of the License at
|
|
194
|
+
|
|
195
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
196
|
+
|
|
197
|
+
Unless required by applicable law or agreed to in writing, software
|
|
198
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
199
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
200
|
+
See the License for the specific language governing permissions and
|
|
201
|
+
limitations under the License.
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type AuthMiddlewareOptions } from "@prosopo/api-express-router";
|
|
2
|
+
export declare const DEFAULT_ADMIN_JWT_MAX_LIFETIME_SECONDS = 3600;
|
|
3
|
+
export declare const adminAuthOptions: (vars: Record<string, string | undefined>, host: string | undefined) => AuthMiddlewareOptions;
|
|
4
|
+
//# sourceMappingURL=adminAuthOptions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adminAuthOptions.d.ts","sourceRoot":"","sources":["../../src/api/adminAuthOptions.ts"],"names":[],"mappings":"AAcA,OAAO,EACN,KAAK,qBAAqB,EAE1B,MAAM,6BAA6B,CAAC;AAGrC,eAAO,MAAM,sCAAsC,OAAO,CAAC;AAmB3D,eAAO,MAAM,gBAAgB,SACtB,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,QAClC,MAAM,GAAG,SAAS,KACtB,qBAyBF,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { createMemoryJwtReplayGuard } from "@prosopo/api-express-router";
|
|
2
|
+
//#region src/api/adminAuthOptions.ts
|
|
3
|
+
/** Longest admin token lifetime (exp - iat) accepted by default, in seconds. */
|
|
4
|
+
var DEFAULT_ADMIN_JWT_MAX_LIFETIME_SECONDS = 3600;
|
|
5
|
+
var parseList = (value) => (value ?? "").split(",").map((entry) => entry.trim()).filter((entry) => entry.length > 0);
|
|
6
|
+
/**
|
|
7
|
+
* Admin JWT checks for this provider.
|
|
8
|
+
*
|
|
9
|
+
* - Audience: a token carrying `aud` must name this provider. The accepted
|
|
10
|
+
* values come from PROSOPO_ADMIN_JWT_AUDIENCE (comma separated), else from
|
|
11
|
+
* the provider host as both `host` and `https://host`. Tokens without `aud`
|
|
12
|
+
* are still accepted until PROSOPO_ADMIN_JWT_REQUIRE_AUDIENCE=true.
|
|
13
|
+
* - Replay: a token carrying `jti` is accepted once per process.
|
|
14
|
+
* - Lifetime: exp - iat may not exceed PROSOPO_ADMIN_JWT_MAX_LIFETIME_SECONDS
|
|
15
|
+
* (default one hour).
|
|
16
|
+
*/
|
|
17
|
+
var adminAuthOptions = (vars, host) => {
|
|
18
|
+
const configured = parseList(vars.PROSOPO_ADMIN_JWT_AUDIENCE);
|
|
19
|
+
const requireAudience = vars.PROSOPO_ADMIN_JWT_REQUIRE_AUDIENCE === "true";
|
|
20
|
+
const derived = host ? [host, `https://${host}`] : [];
|
|
21
|
+
const candidates = configured.length > 0 ? configured : derived;
|
|
22
|
+
const audience = candidates.length > 0 || requireAudience ? candidates : void 0;
|
|
23
|
+
const maxLifetime = Number.parseInt(vars.PROSOPO_ADMIN_JWT_MAX_LIFETIME_SECONDS ?? "", 10);
|
|
24
|
+
return {
|
|
25
|
+
verify: {
|
|
26
|
+
audience,
|
|
27
|
+
requireAudience,
|
|
28
|
+
maxLifetimeSeconds: Number.isFinite(maxLifetime) && maxLifetime > 0 ? maxLifetime : DEFAULT_ADMIN_JWT_MAX_LIFETIME_SECONDS
|
|
29
|
+
},
|
|
30
|
+
replayGuard: createMemoryJwtReplayGuard()
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
//#endregion
|
|
34
|
+
export { DEFAULT_ADMIN_JWT_MAX_LIFETIME_SECONDS, adminAuthOptions };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adminAuthOptions.js","sourceRoot":"","sources":["../../src/api/adminAuthOptions.ts"],"names":[],"mappings":"AAcA,OAAO,EAEN,0BAA0B,GAC1B,MAAM,6BAA6B,CAAC;AAGrC,MAAM,CAAC,MAAM,sCAAsC,GAAG,IAAI,CAAC;AAE3D,MAAM,SAAS,GAAG,CAAC,KAAyB,EAAY,EAAE,CACzD,CAAC,KAAK,IAAI,EAAE,CAAC;KACX,KAAK,CAAC,GAAG,CAAC;KACV,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;KAC5B,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAavC,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC/B,IAAwC,EACxC,IAAwB,EACA,EAAE;IAC1B,MAAM,UAAU,GAAG,SAAS,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;IAC9D,MAAM,eAAe,GAAG,IAAI,CAAC,kCAAkC,KAAK,MAAM,CAAC;IAC3E,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,WAAW,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACtD,MAAM,UAAU,GAAG,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC;IAEhE,MAAM,QAAQ,GACb,UAAU,CAAC,MAAM,GAAG,CAAC,IAAI,eAAe,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC;IAEnE,MAAM,WAAW,GAAG,MAAM,CAAC,QAAQ,CAClC,IAAI,CAAC,sCAAsC,IAAI,EAAE,EACjD,EAAE,CACF,CAAC;IAEF,OAAO;QACN,MAAM,EAAE;YACP,QAAQ;YACR,eAAe;YACf,kBAAkB,EACjB,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,WAAW,GAAG,CAAC;gBAC9C,CAAC,CAAC,WAAW;gBACb,CAAC,CAAC,sCAAsC;SAC1C;QACD,WAAW,EAAE,0BAA0B,EAAE;KACzC,CAAC;AACH,CAAC,CAAC"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { type IFrictionlessThreshold } from "@prosopo/types";
|
|
1
|
+
import { type IFrictionlessThreshold, type IFrictionlessTypes, type IUserSettings } from "@prosopo/types";
|
|
2
2
|
export declare const DEFAULT_FRICTIONLESS_THRESHOLD = 0.5;
|
|
3
3
|
export declare const resolveScoreLadder: (configured: IFrictionlessThreshold | number | undefined) => {
|
|
4
4
|
botThreshold: number;
|
|
5
5
|
botImageThreshold: number;
|
|
6
6
|
};
|
|
7
|
+
export declare const resolveSiteAllowedCaptchaTypes: (settings: Pick<Partial<IUserSettings>, "captchaType" | "frictionlessTypes" | "captchaTypeFeatureFlags">) => IFrictionlessTypes;
|
|
7
8
|
export declare const DECRYPTION_FAILED_IMAGE_ROUNDS = 3;
|
|
8
9
|
export declare const MISSING_TOKEN_IMAGE_ROUNDS = 3;
|
|
9
10
|
export declare const MISSING_HEAD_HASH_IMAGE_ROUNDS = 2;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../src/api/captcha/getFrictionlessCaptchaChallenge/constants.ts"],"names":[],"mappings":"AAcA,OAAO,
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../src/api/captcha/getFrictionlessCaptchaChallenge/constants.ts"],"names":[],"mappings":"AAcA,OAAO,EAEN,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAIlB,MAAM,gBAAgB,CAAC;AAExB,eAAO,MAAM,8BAA8B,MACR,CAAC;AAOpC,eAAO,MAAM,kBAAkB,eAClB,sBAAsB,GAAG,MAAM,GAAG,SAAS,KACrD;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,iBAAiB,EAAE,MAAM,CAAA;CAMnD,CAAC;AAOF,eAAO,MAAM,8BAA8B,aAChC,IAAI,CACb,OAAO,CAAC,aAAa,CAAC,EACtB,aAAa,GAAG,mBAAmB,GAAG,yBAAyB,CAC/D,KACC,kBAOA,CAAC;AAWJ,eAAO,MAAM,8BAA8B,IAAI,CAAC;AAOhD,eAAO,MAAM,0BAA0B,IAAI,CAAC;AAM5C,eAAO,MAAM,8BAA8B,IAAI,CAAC;AAQhD,eAAO,MAAM,+BAA+B,IAAI,CAAC;AAUjD,eAAO,MAAM,+BAA+B,SACrC,MAAM,sBACQ,MAAM,EAAE,GAAG,SAAS,KACtC,MAEwE,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { resolveFrictionlessThreshold } from "@prosopo/types";
|
|
1
|
+
import { CaptchaType, resolveAllowedCaptchaTypes, resolveFrictionlessThreshold } from "@prosopo/types";
|
|
2
2
|
/**
|
|
3
3
|
* A client record's configured ladder, in the terms the decision machine
|
|
4
4
|
* compares against. Thin rename over `resolveFrictionlessThreshold`, which
|
|
@@ -12,6 +12,15 @@ var resolveScoreLadder = (configured) => {
|
|
|
12
12
|
};
|
|
13
13
|
};
|
|
14
14
|
/**
|
|
15
|
+
* The types any session minted by /frictionless may be. The owner's
|
|
16
|
+
* `frictionlessTypes` only governs the frictionless flow, so a site pinned to
|
|
17
|
+
* a concrete `captchaType` is held to the feature flags alone.
|
|
18
|
+
*/
|
|
19
|
+
var resolveSiteAllowedCaptchaTypes = (settings) => resolveAllowedCaptchaTypes({
|
|
20
|
+
captchaTypeFeatureFlags: settings.captchaTypeFeatureFlags,
|
|
21
|
+
...(!settings.captchaType || settings.captchaType === CaptchaType.frictionless) && { frictionlessTypes: settings.frictionlessTypes }
|
|
22
|
+
});
|
|
23
|
+
/**
|
|
15
24
|
* Size an image challenge by how much was actually found. `base` is the
|
|
16
25
|
* sitekey's ordinary image round count; each triggered signal adds a round,
|
|
17
26
|
* capped by `MAX_DETECTOR_EXTRA_IMAGE_ROUNDS`. A session with nothing
|
|
@@ -21,4 +30,4 @@ var resolveScoreLadder = (configured) => {
|
|
|
21
30
|
*/
|
|
22
31
|
var getRoundsFromTriggeredDetectors = (base, triggeredDetectors) => base + Math.min(triggeredDetectors?.length ?? 0, 6);
|
|
23
32
|
//#endregion
|
|
24
|
-
export { getRoundsFromTriggeredDetectors, resolveScoreLadder };
|
|
33
|
+
export { getRoundsFromTriggeredDetectors, resolveScoreLadder, resolveSiteAllowedCaptchaTypes };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../../src/api/captcha/getFrictionlessCaptchaChallenge/constants.ts"],"names":[],"mappings":"AAcA,OAAO,
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../../src/api/captcha/getFrictionlessCaptchaChallenge/constants.ts"],"names":[],"mappings":"AAcA,OAAO,EACN,WAAW,EAIX,kCAAkC,EAClC,0BAA0B,EAC1B,4BAA4B,GAC5B,MAAM,gBAAgB,CAAC;AAExB,MAAM,CAAC,MAAM,8BAA8B,GAC1C,kCAAkC,CAAC;AAOpC,MAAM,CAAC,MAAM,kBAAkB,GAAG,CACjC,UAAuD,EACD,EAAE;IACxD,MAAM,MAAM,GAAG,4BAA4B,CAAC,UAAU,CAAC,CAAC;IACxD,OAAO;QACN,YAAY,EAAE,MAAM,CAAC,2BAA2B;QAChD,iBAAiB,EAAE,MAAM,CAAC,0BAA0B;KACpD,CAAC;AACH,CAAC,CAAC;AAOF,MAAM,CAAC,MAAM,8BAA8B,GAAG,CAC7C,QAGC,EACoB,EAAE,CACvB,0BAA0B,CAAC;IAC1B,uBAAuB,EAAE,QAAQ,CAAC,uBAAuB;IACzD,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW;QACzB,QAAQ,CAAC,WAAW,KAAK,WAAW,CAAC,YAAY,CAAC,IAAI;QACtD,iBAAiB,EAAE,QAAQ,CAAC,iBAAiB;KAC7C,CAAC;CACF,CAAC,CAAC;AAWJ,MAAM,CAAC,MAAM,8BAA8B,GAAG,CAAC,CAAC;AAOhD,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,CAAC;AAM5C,MAAM,CAAC,MAAM,8BAA8B,GAAG,CAAC,CAAC;AAQhD,MAAM,CAAC,MAAM,+BAA+B,GAAG,CAAC,CAAC;AAUjD,MAAM,CAAC,MAAM,+BAA+B,GAAG,CAC9C,IAAY,EACZ,kBAAwC,EAC/B,EAAE,CACX,IAAI;IACJ,IAAI,CAAC,GAAG,CAAC,kBAAkB,EAAE,MAAM,IAAI,CAAC,EAAE,+BAA+B,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../../src/api/captcha/getFrictionlessCaptchaChallenge/handler.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAEN,KAAK,kBAAkB,EACvB,MAAM,6BAA6B,CAAC;AAGrC,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAG/D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../../src/api/captcha/getFrictionlessCaptchaChallenge/handler.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAEN,KAAK,kBAAkB,EACvB,MAAM,6BAA6B,CAAC;AAGrC,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAG/D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;8BA4CtD,mBAAmB,0BACA,kBAAkB,WAGpC,OAAO,GAAG,gBAAgB,OAC1B,QAAQ,QACP,YAAY;AAPpB,wBAu5BG"}
|