@prosopo/provider 5.15.0 → 5.16.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 +50 -32
- package/.turbo/turbo-build$colon$tsc.log +36 -30
- package/.turbo/turbo-build.log +51 -33
- package/CHANGELOG.md +65 -0
- package/dist/api/admin/apiToggleMaintenanceModeEndpoint.d.ts +4 -0
- package/dist/api/admin/apiToggleMaintenanceModeEndpoint.d.ts.map +1 -1
- package/dist/api/admin/apiToggleMaintenanceModeEndpoint.js +63 -3
- package/dist/api/admin/apiToggleMaintenanceModeEndpoint.js.map +1 -1
- package/dist/api/blacklistRequestInspector.js +2 -2
- package/dist/api/captcha/getAudioCaptchaChallenge.d.ts +5 -0
- package/dist/api/captcha/getAudioCaptchaChallenge.d.ts.map +1 -0
- package/dist/api/captcha/getAudioCaptchaChallenge.js +37 -0
- package/dist/api/captcha/getAudioCaptchaChallenge.js.map +1 -0
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/decisionMachine.js +1 -1
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/handler.d.ts.map +1 -1
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/handler.js +11 -7
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/handler.js.map +1 -1
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.d.ts.map +1 -1
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.js +1 -0
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.js.map +1 -1
- package/dist/api/captcha/getIconOrderCaptchaChallenge.d.ts +5 -0
- package/dist/api/captcha/getIconOrderCaptchaChallenge.d.ts.map +1 -0
- package/dist/api/captcha/getIconOrderCaptchaChallenge.js +37 -0
- package/dist/api/captcha/getIconOrderCaptchaChallenge.js.map +1 -0
- package/dist/api/captcha/getImageCaptchaChallenge.js +2 -2
- package/dist/api/captcha/getPoWCaptchaChallenge.js +4 -4
- package/dist/api/captcha/getPuzzleCaptchaChallenge.d.ts +1 -3
- package/dist/api/captcha/getPuzzleCaptchaChallenge.d.ts.map +1 -1
- package/dist/api/captcha/getPuzzleCaptchaChallenge.js +52 -169
- package/dist/api/captcha/getPuzzleCaptchaChallenge.js.map +1 -1
- package/dist/api/captcha/interactiveCaptchaChallenge.d.ts +42 -0
- package/dist/api/captcha/interactiveCaptchaChallenge.d.ts.map +1 -0
- package/dist/api/captcha/interactiveCaptchaChallenge.js +154 -0
- package/dist/api/captcha/interactiveCaptchaChallenge.js.map +1 -0
- package/dist/api/captcha/interactiveCaptchaSolution.d.ts +14 -0
- package/dist/api/captcha/interactiveCaptchaSolution.d.ts.map +1 -0
- package/dist/api/captcha/interactiveCaptchaSolution.js +77 -0
- package/dist/api/captcha/interactiveCaptchaSolution.js.map +1 -0
- package/dist/api/captcha/maintenanceModeResponses.d.ts +4 -2
- package/dist/api/captcha/maintenanceModeResponses.d.ts.map +1 -1
- package/dist/api/captcha/maintenanceModeResponses.js +28 -1
- package/dist/api/captcha/maintenanceModeResponses.js.map +1 -1
- package/dist/api/captcha/submitAudioCaptchaSolution.d.ts +4 -0
- package/dist/api/captcha/submitAudioCaptchaSolution.d.ts.map +1 -0
- package/dist/api/captcha/submitAudioCaptchaSolution.js +11 -0
- package/dist/api/captcha/submitAudioCaptchaSolution.js.map +1 -0
- package/dist/api/captcha/submitIconOrderCaptchaSolution.d.ts +4 -0
- package/dist/api/captcha/submitIconOrderCaptchaSolution.d.ts.map +1 -0
- package/dist/api/captcha/submitIconOrderCaptchaSolution.js +11 -0
- package/dist/api/captcha/submitIconOrderCaptchaSolution.js.map +1 -0
- package/dist/api/captcha/submitPoWCaptchaSolution.js +2 -2
- package/dist/api/captcha/submitPuzzleCaptchaSolution.d.ts +1 -3
- package/dist/api/captcha/submitPuzzleCaptchaSolution.d.ts.map +1 -1
- package/dist/api/captcha/submitPuzzleCaptchaSolution.js +6 -73
- package/dist/api/captcha/submitPuzzleCaptchaSolution.js.map +1 -1
- package/dist/api/captcha/trafficFilterRequestTime.d.ts +4 -1
- package/dist/api/captcha/trafficFilterRequestTime.d.ts.map +1 -1
- package/dist/api/captcha/trafficFilterRequestTime.js +3 -0
- package/dist/api/captcha/trafficFilterRequestTime.js.map +1 -1
- package/dist/api/captcha.d.ts.map +1 -1
- package/dist/api/captcha.js +8 -0
- package/dist/api/captcha.js.map +1 -1
- package/dist/api/domainMiddleware.js +1 -1
- package/dist/api/ja4Middleware.js +1 -1
- package/dist/api/startProviderApi.js +1 -1
- package/dist/api/verify.d.ts.map +1 -1
- package/dist/api/verify.js +153 -96
- package/dist/api/verify.js.map +1 -1
- package/dist/cjs/api/admin/apiToggleMaintenanceModeEndpoint.cjs +65 -2
- package/dist/cjs/api/blacklistRequestInspector.cjs +2 -2
- package/dist/cjs/api/captcha/getAudioCaptchaChallenge.cjs +37 -0
- package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/decisionMachine.cjs +1 -1
- package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/handler.cjs +11 -7
- package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.cjs +1 -0
- package/dist/cjs/api/captcha/getIconOrderCaptchaChallenge.cjs +37 -0
- package/dist/cjs/api/captcha/getImageCaptchaChallenge.cjs +2 -2
- package/dist/cjs/api/captcha/getPoWCaptchaChallenge.cjs +4 -4
- package/dist/cjs/api/captcha/getPuzzleCaptchaChallenge.cjs +51 -168
- package/dist/cjs/api/captcha/interactiveCaptchaChallenge.cjs +154 -0
- package/dist/cjs/api/captcha/interactiveCaptchaSolution.cjs +77 -0
- package/dist/cjs/api/captcha/maintenanceModeResponses.cjs +29 -0
- package/dist/cjs/api/captcha/submitAudioCaptchaSolution.cjs +11 -0
- package/dist/cjs/api/captcha/submitIconOrderCaptchaSolution.cjs +11 -0
- package/dist/cjs/api/captcha/submitPoWCaptchaSolution.cjs +2 -2
- package/dist/cjs/api/captcha/submitPuzzleCaptchaSolution.cjs +6 -73
- package/dist/cjs/api/captcha/trafficFilterRequestTime.cjs +3 -0
- package/dist/cjs/api/captcha.cjs +8 -0
- package/dist/cjs/api/domainMiddleware.cjs +1 -1
- package/dist/cjs/api/ja4Middleware.cjs +1 -1
- package/dist/cjs/api/startProviderApi.cjs +1 -1
- package/dist/cjs/api/verify.cjs +152 -95
- package/dist/cjs/index.cjs +1 -1
- package/dist/cjs/tasks/audio/audioBuffer.cjs +72 -0
- package/dist/cjs/tasks/audio/audioRenderer.cjs +32 -0
- package/dist/cjs/tasks/audioAlternative.cjs +23 -0
- package/dist/cjs/tasks/audioCaptcha/audioTasks.cjs +65 -0
- package/dist/cjs/tasks/audioCaptcha/audioTasksUtils.cjs +19 -0
- package/dist/cjs/tasks/captchaManager.cjs +14 -2
- package/dist/cjs/tasks/captchaTypeSelection.cjs +10 -3
- package/dist/cjs/tasks/client/clientTasks.cjs +2 -2
- package/dist/cjs/tasks/frictionless/frictionlessTasks.cjs +26 -6
- package/dist/cjs/tasks/iconOrder/iconOrderRenderer.cjs +42 -0
- package/dist/cjs/tasks/iconOrderCaptcha/iconOrderTasks.cjs +69 -0
- package/dist/cjs/tasks/imgCaptcha/imgCaptchaTasks.cjs +8 -8
- package/dist/cjs/tasks/interactiveCaptcha/interactiveCaptchaManager.cjs +423 -0
- package/dist/cjs/tasks/powCaptcha/powTasks.cjs +8 -8
- package/dist/cjs/tasks/powCaptcha/powTasksUtils.cjs +1 -1
- package/dist/cjs/tasks/puzzleCaptcha/puzzleTasks.cjs +40 -486
- package/dist/cjs/tasks/spam/checkTrafficFilter.cjs +18 -1
- package/dist/cjs/tasks/tasks.cjs +6 -0
- package/dist/cjs/util.cjs +1 -1
- package/dist/index.js +2 -2
- package/dist/tasks/audio/audioBuffer.d.ts +23 -0
- package/dist/tasks/audio/audioBuffer.d.ts.map +1 -0
- package/dist/tasks/audio/audioBuffer.js +70 -0
- package/dist/tasks/audio/audioBuffer.js.map +1 -0
- package/dist/tasks/audio/audioRenderer.d.ts +11 -0
- package/dist/tasks/audio/audioRenderer.d.ts.map +1 -0
- package/dist/tasks/audio/audioRenderer.js +31 -0
- package/dist/tasks/audio/audioRenderer.js.map +1 -0
- package/dist/tasks/audioAlternative.d.ts +8 -0
- package/dist/tasks/audioAlternative.d.ts.map +1 -0
- package/dist/tasks/audioAlternative.js +20 -0
- package/dist/tasks/audioAlternative.js.map +1 -0
- package/dist/tasks/audioCaptcha/audioTasks.d.ts +19 -0
- package/dist/tasks/audioCaptcha/audioTasks.d.ts.map +1 -0
- package/dist/tasks/audioCaptcha/audioTasks.js +65 -0
- package/dist/tasks/audioCaptcha/audioTasks.js.map +1 -0
- package/dist/tasks/audioCaptcha/audioTasksUtils.d.ts +3 -0
- package/dist/tasks/audioCaptcha/audioTasksUtils.d.ts.map +1 -0
- package/dist/tasks/audioCaptcha/audioTasksUtils.js +18 -0
- package/dist/tasks/audioCaptcha/audioTasksUtils.js.map +1 -0
- package/dist/tasks/captchaManager.d.ts +9 -3
- package/dist/tasks/captchaManager.d.ts.map +1 -1
- package/dist/tasks/captchaManager.js +15 -3
- package/dist/tasks/captchaManager.js.map +1 -1
- package/dist/tasks/captchaTypeSelection.d.ts +1 -1
- package/dist/tasks/captchaTypeSelection.d.ts.map +1 -1
- package/dist/tasks/captchaTypeSelection.js +11 -4
- package/dist/tasks/captchaTypeSelection.js.map +1 -1
- package/dist/tasks/client/clientTasks.js +2 -2
- package/dist/tasks/frictionless/frictionlessTasks.d.ts +3 -0
- package/dist/tasks/frictionless/frictionlessTasks.d.ts.map +1 -1
- package/dist/tasks/frictionless/frictionlessTasks.js +26 -6
- package/dist/tasks/frictionless/frictionlessTasks.js.map +1 -1
- package/dist/tasks/iconOrder/iconOrderRenderer.d.ts +12 -0
- package/dist/tasks/iconOrder/iconOrderRenderer.d.ts.map +1 -0
- package/dist/tasks/iconOrder/iconOrderRenderer.js +40 -0
- package/dist/tasks/iconOrder/iconOrderRenderer.js.map +1 -0
- package/dist/tasks/iconOrderCaptcha/iconOrderTasks.d.ts +22 -0
- package/dist/tasks/iconOrderCaptcha/iconOrderTasks.d.ts.map +1 -0
- package/dist/tasks/iconOrderCaptcha/iconOrderTasks.js +69 -0
- package/dist/tasks/iconOrderCaptcha/iconOrderTasks.js.map +1 -0
- package/dist/tasks/imgCaptcha/imgCaptchaTasks.js +8 -8
- package/dist/tasks/interactiveCaptcha/interactiveCaptchaManager.d.ts +52 -0
- package/dist/tasks/interactiveCaptcha/interactiveCaptchaManager.d.ts.map +1 -0
- package/dist/tasks/interactiveCaptcha/interactiveCaptchaManager.js +423 -0
- package/dist/tasks/interactiveCaptcha/interactiveCaptchaManager.js.map +1 -0
- package/dist/tasks/powCaptcha/powTasks.js +8 -8
- package/dist/tasks/powCaptcha/powTasksUtils.js +1 -1
- package/dist/tasks/puzzleCaptcha/puzzleTasks.d.ts +14 -16
- package/dist/tasks/puzzleCaptcha/puzzleTasks.d.ts.map +1 -1
- package/dist/tasks/puzzleCaptcha/puzzleTasks.js +41 -487
- package/dist/tasks/puzzleCaptcha/puzzleTasks.js.map +1 -1
- package/dist/tasks/spam/checkTrafficFilter.d.ts +4 -1
- package/dist/tasks/spam/checkTrafficFilter.d.ts.map +1 -1
- package/dist/tasks/spam/checkTrafficFilter.js +18 -1
- package/dist/tasks/spam/checkTrafficFilter.js.map +1 -1
- package/dist/tasks/tasks.d.ts +4 -0
- package/dist/tasks/tasks.d.ts.map +1 -1
- package/dist/tasks/tasks.js +6 -0
- package/dist/tasks/tasks.js.map +1 -1
- package/dist/tests/integration/api/admin/apiRegisterSiteKeyEndpoint.integration.test.js +7 -3
- package/dist/tests/integration/api/admin/apiRegisterSiteKeyEndpoint.integration.test.js.map +1 -1
- package/dist/tests/integration/clientSettingsPersistence.integration.test.js +43 -3
- package/dist/tests/integration/clientSettingsPersistence.integration.test.js.map +1 -1
- package/dist/tests/unit/api/admin/apiRegisterSiteKeyEndpoint.unit.test.js +4 -2
- package/dist/tests/unit/api/admin/apiRegisterSiteKeyEndpoint.unit.test.js.map +1 -1
- package/dist/tests/unit/api/admin/apiToggleMaintenanceModeEndpoint.unit.test.js +76 -1
- package/dist/tests/unit/api/admin/apiToggleMaintenanceModeEndpoint.unit.test.js.map +1 -1
- package/dist/tests/unit/api/captcha/getFrictionlessCaptchaChallenge/constants.unit.test.js +27 -8
- package/dist/tests/unit/api/captcha/getFrictionlessCaptchaChallenge/constants.unit.test.js.map +1 -1
- package/dist/tests/unit/api/captcha/maintenanceModeShortCircuit.unit.test.js +20 -0
- package/dist/tests/unit/api/captcha/maintenanceModeShortCircuit.unit.test.js.map +1 -1
- package/dist/tests/unit/api/getFrictionlessCaptchaChallenge.unit.test.js +28 -2
- package/dist/tests/unit/api/getFrictionlessCaptchaChallenge.unit.test.js.map +1 -1
- package/dist/tests/unit/tasks/audio/audioBuffer.unit.test.d.ts +2 -0
- package/dist/tests/unit/tasks/audio/audioBuffer.unit.test.d.ts.map +1 -0
- package/dist/tests/unit/tasks/audio/audioBuffer.unit.test.js +105 -0
- package/dist/tests/unit/tasks/audio/audioBuffer.unit.test.js.map +1 -0
- package/dist/tests/unit/tasks/audioAlternative.unit.test.d.ts +2 -0
- package/dist/tests/unit/tasks/audioAlternative.unit.test.d.ts.map +1 -0
- package/dist/tests/unit/tasks/audioAlternative.unit.test.js +76 -0
- package/dist/tests/unit/tasks/audioAlternative.unit.test.js.map +1 -0
- package/dist/tests/unit/tasks/audioCaptcha/audioTasks.unit.test.d.ts +2 -0
- package/dist/tests/unit/tasks/audioCaptcha/audioTasks.unit.test.d.ts.map +1 -0
- package/dist/tests/unit/tasks/audioCaptcha/audioTasks.unit.test.js +259 -0
- package/dist/tests/unit/tasks/audioCaptcha/audioTasks.unit.test.js.map +1 -0
- package/dist/tests/unit/tasks/audioCaptcha/audioTasksUtils.unit.test.d.ts +2 -0
- package/dist/tests/unit/tasks/audioCaptcha/audioTasksUtils.unit.test.d.ts.map +1 -0
- package/dist/tests/unit/tasks/audioCaptcha/audioTasksUtils.unit.test.js +52 -0
- package/dist/tests/unit/tasks/audioCaptcha/audioTasksUtils.unit.test.js.map +1 -0
- package/dist/tests/unit/tasks/captchaManager.unit.test.js +120 -2
- package/dist/tests/unit/tasks/captchaManager.unit.test.js.map +1 -1
- package/dist/tests/unit/tasks/captchaTypeSelection.unit.test.js +48 -5
- package/dist/tests/unit/tasks/captchaTypeSelection.unit.test.js.map +1 -1
- package/dist/tests/unit/tasks/frictionless/allowedCaptchaTypes.unit.test.js +29 -0
- package/dist/tests/unit/tasks/frictionless/allowedCaptchaTypes.unit.test.js.map +1 -1
- package/dist/tests/unit/tasks/frictionless/frictionlessTasks.unit.test.js +31 -0
- package/dist/tests/unit/tasks/frictionless/frictionlessTasks.unit.test.js.map +1 -1
- package/dist/tests/unit/tasks/frictionless/refreshSwitch.unit.test.js +1 -1
- package/dist/tests/unit/tasks/frictionless/refreshSwitch.unit.test.js.map +1 -1
- package/dist/tests/unit/tasks/frictionless/routerPuzzleOverrides.unit.test.js +28 -0
- package/dist/tests/unit/tasks/frictionless/routerPuzzleOverrides.unit.test.js.map +1 -1
- package/dist/tests/unit/tasks/iconOrder/iconOrderRenderer.unit.test.d.ts +2 -0
- package/dist/tests/unit/tasks/iconOrder/iconOrderRenderer.unit.test.d.ts.map +1 -0
- package/dist/tests/unit/tasks/iconOrder/iconOrderRenderer.unit.test.js +60 -0
- package/dist/tests/unit/tasks/iconOrder/iconOrderRenderer.unit.test.js.map +1 -0
- package/dist/tests/unit/tasks/iconOrderCaptcha/iconOrderTasks.unit.test.d.ts +2 -0
- package/dist/tests/unit/tasks/iconOrderCaptcha/iconOrderTasks.unit.test.d.ts.map +1 -0
- package/dist/tests/unit/tasks/iconOrderCaptcha/iconOrderTasks.unit.test.js +225 -0
- package/dist/tests/unit/tasks/iconOrderCaptcha/iconOrderTasks.unit.test.js.map +1 -0
- package/dist/util.js +1 -1
- package/package.json +19 -17
|
@@ -1,144 +1,51 @@
|
|
|
1
|
-
import { validateAddr, validateSiteKey } from "../validateAddress.js";
|
|
2
|
-
import { recordCaptchaIssueError, recordCaptchaIssued } from "../metrics.js";
|
|
3
|
-
import { getCompositeIpAddress } from "../../compositeIpAddress.js";
|
|
4
|
-
import { getRequestUserScope, normalizeHeadersForMatching } from "../blacklistRequestInspector.js";
|
|
5
1
|
import { renderPuzzleImages, resolvePuzzlePieceSize, resolvePuzzleRenderSettings } from "../../tasks/puzzle/puzzleRenderer.js";
|
|
6
|
-
import {
|
|
7
|
-
import { getMaintenanceMode } from "../admin/apiToggleMaintenanceModeEndpoint.js";
|
|
8
|
-
import { isReservedTestSiteKey } from "../testSiteKey.js";
|
|
9
|
-
import { normalizeRequestIp } from "../../utils/normalizeRequestIp.js";
|
|
2
|
+
import { interactiveChallengeHandler } from "./interactiveCaptchaChallenge.js";
|
|
10
3
|
import { buildPuzzleMaintenanceResponse } from "./maintenanceModeResponses.js";
|
|
11
|
-
import {
|
|
12
|
-
import { summariseRequestBody } from "../requestBodySummary.js";
|
|
13
|
-
import { ProsopoApiError } from "@prosopo/common";
|
|
14
|
-
import { ApiParams, CaptchaType, GetPuzzleCaptchaChallengeRequestBody, SimdReadingsStage } from "@prosopo/types";
|
|
15
|
-
import { flatten } from "@prosopo/util";
|
|
4
|
+
import { ApiParams, CaptchaType } from "@prosopo/types";
|
|
16
5
|
import { DEFAULT_GEOMETRY } from "@prosopo/puzzle-assets";
|
|
17
6
|
//#region src/api/captcha/getPuzzleCaptchaChallenge.ts
|
|
18
|
-
var
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
7
|
+
var issuePuzzleChallenge = async ({ tasks, user, dapp, origin, clientSettings, sessionRecord, trafficVerdict, provenance }) => {
|
|
8
|
+
const challengeVerdict = trafficVerdict.kind === "challenge" ? trafficVerdict : void 0;
|
|
9
|
+
const tolerance = challengeVerdict?.puzzleTolerance ?? sessionRecord?.puzzleTolerance ?? clientSettings?.settings?.puzzleTolerance;
|
|
10
|
+
const routedPuzzleSettings = challengeVerdict?.puzzleSettings ?? sessionRecord?.puzzle;
|
|
11
|
+
const effectivePuzzleSettings = resolvePuzzleRenderSettings(clientSettings?.settings?.puzzle, routedPuzzleSettings);
|
|
12
|
+
const effectivePieceSize = resolvePuzzlePieceSize(clientSettings?.settings?.puzzle, routedPuzzleSettings);
|
|
13
|
+
const challenge = await tasks.puzzleCaptchaManager.getPuzzleCaptchaChallenge(user, dapp, origin, tolerance);
|
|
14
|
+
await tasks.db.storePuzzleCaptchaRecord(challenge.challenge, {
|
|
15
|
+
requestedAtTimestamp: challenge.requestedAtTimestamp,
|
|
16
|
+
userAccount: user,
|
|
17
|
+
dappAccount: dapp
|
|
18
|
+
}, challenge.targetX, challenge.targetY, challenge.originX, challenge.originY, challenge.tolerance, challenge.providerSignature, provenance.ipAddress, provenance.headers, provenance.ja4, provenance.sessionId, provenance.ipInfo);
|
|
19
|
+
const images = await renderPuzzleImages({
|
|
20
|
+
targetX: challenge.targetX,
|
|
21
|
+
targetY: challenge.targetY
|
|
22
|
+
}, effectivePuzzleSettings, effectivePieceSize);
|
|
23
|
+
await tasks.db.updatePuzzleCaptchaRecord(challenge.challenge, { render: {
|
|
24
|
+
...sessionRecord?.puzzleLevel !== void 0 && { level: sessionRecord.puzzleLevel },
|
|
25
|
+
pieceSize: images.pieceSize,
|
|
26
|
+
geometry: {
|
|
27
|
+
width: DEFAULT_GEOMETRY.width,
|
|
28
|
+
height: DEFAULT_GEOMETRY.height,
|
|
29
|
+
notchSize: DEFAULT_GEOMETRY.notchSize
|
|
30
|
+
},
|
|
31
|
+
settings: {
|
|
32
|
+
decoyCount: effectivePuzzleSettings.decoyCount,
|
|
33
|
+
decoyEdgeDarkness: effectivePuzzleSettings.decoyEdgeDarkness,
|
|
34
|
+
decoyBodyBrightness: effectivePuzzleSettings.decoyBodyBrightness,
|
|
35
|
+
holeDarken: effectivePuzzleSettings.holeDarken,
|
|
36
|
+
decoyHoleDarken: effectivePuzzleSettings.decoyHoleDarken
|
|
37
|
+
},
|
|
38
|
+
backgroundSeed: images.backgroundSeed,
|
|
39
|
+
renderSeed: images.renderSeed
|
|
40
|
+
} }).catch((updateErr) => {
|
|
41
|
+
tasks.logger.warn(() => ({
|
|
42
|
+
err: updateErr,
|
|
43
|
+
msg: "Failed to patch puzzle render inputs onto the challenge record"
|
|
30
44
|
}));
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
if (getMaintenanceMode()) {
|
|
36
|
-
req.logger.info(() => ({
|
|
37
|
-
msg: "Maintenance mode active - returning dummy puzzle challenge",
|
|
38
|
-
data: {
|
|
39
|
-
dapp,
|
|
40
|
-
user,
|
|
41
|
-
sessionId
|
|
42
|
-
}
|
|
43
|
-
}));
|
|
44
|
-
return res.json(await buildPuzzleMaintenanceResponse(user, dapp));
|
|
45
|
-
}
|
|
46
|
-
if (isReservedTestSiteKey(dapp)) {
|
|
47
|
-
req.logger.warn(() => ({
|
|
48
|
-
msg: "Reserved TEST site key - returning dummy puzzle challenge",
|
|
49
|
-
data: {
|
|
50
|
-
dapp,
|
|
51
|
-
user,
|
|
52
|
-
sessionId
|
|
53
|
-
}
|
|
54
|
-
}));
|
|
55
|
-
return res.json(await buildPuzzleMaintenanceResponse(user, dapp));
|
|
56
|
-
}
|
|
57
|
-
const tasks = new Tasks(env, req.logger);
|
|
58
|
-
try {
|
|
59
|
-
const clientSettings = await tasks.db.getClientRecord(dapp);
|
|
60
|
-
if (!clientSettings) return next(new ProsopoApiError("API.SITE_KEY_NOT_REGISTERED", {
|
|
61
|
-
context: {
|
|
62
|
-
code: 400,
|
|
63
|
-
siteKey: dapp
|
|
64
|
-
},
|
|
65
|
-
i18n: req.i18n,
|
|
66
|
-
logger: req.logger
|
|
67
|
-
}));
|
|
68
|
-
const normalizedIp = normalizeRequestIp(req.ip, req.logger);
|
|
69
|
-
if (!normalizedIp) req.logger.warn(() => ({ msg: "Request missing IP; geoblocking will be skipped" }));
|
|
70
|
-
const countryCode = req.ipInfo && "isValid" in req.ipInfo && req.ipInfo.isValid ? req.ipInfo.countryCode : void 0;
|
|
71
|
-
const asn = req.ipInfo && "isValid" in req.ipInfo && req.ipInfo.isValid ? req.ipInfo.asnNumber : void 0;
|
|
72
|
-
const sessionRecord = sessionId ? await tasks.db.getSessionRecordBySessionId(sessionId) : void 0;
|
|
73
|
-
const userScope = getRequestUserScope(flatten(req.headers), req.ja4, normalizedIp, user, sessionRecord?.decryptedHeadHash, void 0, countryCode, asn);
|
|
74
|
-
const userAccessPolicy = (await tasks.puzzleCaptchaManager.getPrioritisedAccessPolicies(userAccessRulesStorage, dapp, userScope, normalizeHeadersForMatching(req.headers))).find((p) => !p.deferToVerify);
|
|
75
|
-
const { valid, reason, sessionId: validSessionId } = await tasks.puzzleCaptchaManager.isValidRequest(clientSettings, CaptchaType.puzzle, env, sessionId, userAccessPolicy, normalizedIp);
|
|
76
|
-
if (!valid) return next(new ProsopoApiError(reason || "API.BAD_REQUEST", {
|
|
77
|
-
context: {
|
|
78
|
-
code: 400,
|
|
79
|
-
siteKey: dapp,
|
|
80
|
-
user
|
|
81
|
-
},
|
|
82
|
-
i18n: req.i18n,
|
|
83
|
-
logger: req.logger
|
|
84
|
-
}));
|
|
85
|
-
const origin = req.headers.origin;
|
|
86
|
-
if (!origin) return next(new ProsopoApiError("API.BAD_REQUEST", {
|
|
87
|
-
context: {
|
|
88
|
-
error: "Origin header not found",
|
|
89
|
-
code: 400,
|
|
90
|
-
siteKey: dapp,
|
|
91
|
-
user
|
|
92
|
-
},
|
|
93
|
-
i18n: req.i18n,
|
|
94
|
-
logger: req.logger
|
|
95
|
-
}));
|
|
96
|
-
const trafficVerdict = applyTrafficFilterAtRequestTime(req.ipInfo, clientSettings.settings?.trafficFilter, req.logger);
|
|
97
|
-
const tolerance = (trafficVerdict.kind === "challenge" ? trafficVerdict.puzzleTolerance : void 0) ?? sessionRecord?.puzzleTolerance ?? clientSettings?.settings?.puzzleTolerance;
|
|
98
|
-
const routedPuzzleSettings = (trafficVerdict.kind === "challenge" ? trafficVerdict.puzzleSettings : void 0) ?? sessionRecord?.puzzle;
|
|
99
|
-
const effectivePuzzleSettings = resolvePuzzleRenderSettings(clientSettings?.settings?.puzzle, routedPuzzleSettings);
|
|
100
|
-
const effectivePieceSize = resolvePuzzlePieceSize(clientSettings?.settings?.puzzle, routedPuzzleSettings);
|
|
101
|
-
const challenge = await tasks.puzzleCaptchaManager.getPuzzleCaptchaChallenge(user, dapp, origin, tolerance);
|
|
102
|
-
if (validSessionId && simdReadings) await tasks.frictionlessManager.decryptAndAttachSimdReadingsIfAbsent(validSessionId, simdReadings, SimdReadingsStage.challenge).catch((updateErr) => {
|
|
103
|
-
req.logger.warn(() => ({
|
|
104
|
-
err: updateErr,
|
|
105
|
-
msg: "Failed to patch session with SIMD readings on puzzle challenge"
|
|
106
|
-
}));
|
|
107
|
-
});
|
|
108
|
-
await tasks.db.storePuzzleCaptchaRecord(challenge.challenge, {
|
|
109
|
-
requestedAtTimestamp: challenge.requestedAtTimestamp,
|
|
110
|
-
userAccount: user,
|
|
111
|
-
dappAccount: dapp
|
|
112
|
-
}, challenge.targetX, challenge.targetY, challenge.originX, challenge.originY, challenge.tolerance, challenge.providerSignature, getCompositeIpAddress(normalizedIp), flatten(req.headers), req.ja4, validSessionId, req.ipInfo);
|
|
113
|
-
const images = await renderPuzzleImages({
|
|
114
|
-
targetX: challenge.targetX,
|
|
115
|
-
targetY: challenge.targetY
|
|
116
|
-
}, effectivePuzzleSettings, effectivePieceSize);
|
|
117
|
-
await tasks.db.updatePuzzleCaptchaRecord(challenge.challenge, { render: {
|
|
118
|
-
...sessionRecord?.puzzleLevel !== void 0 && { level: sessionRecord.puzzleLevel },
|
|
119
|
-
pieceSize: images.pieceSize,
|
|
120
|
-
geometry: {
|
|
121
|
-
width: DEFAULT_GEOMETRY.width,
|
|
122
|
-
height: DEFAULT_GEOMETRY.height,
|
|
123
|
-
notchSize: DEFAULT_GEOMETRY.notchSize
|
|
124
|
-
},
|
|
125
|
-
settings: {
|
|
126
|
-
decoyCount: effectivePuzzleSettings.decoyCount,
|
|
127
|
-
decoyEdgeDarkness: effectivePuzzleSettings.decoyEdgeDarkness,
|
|
128
|
-
decoyBodyBrightness: effectivePuzzleSettings.decoyBodyBrightness,
|
|
129
|
-
holeDarken: effectivePuzzleSettings.holeDarken,
|
|
130
|
-
decoyHoleDarken: effectivePuzzleSettings.decoyHoleDarken
|
|
131
|
-
},
|
|
132
|
-
backgroundSeed: images.backgroundSeed,
|
|
133
|
-
renderSeed: images.renderSeed
|
|
134
|
-
} }).catch((updateErr) => {
|
|
135
|
-
req.logger.warn(() => ({
|
|
136
|
-
err: updateErr,
|
|
137
|
-
msg: "Failed to patch puzzle render inputs onto the challenge record"
|
|
138
|
-
}));
|
|
139
|
-
});
|
|
140
|
-
const padBytes = trafficVerdict.padBytes;
|
|
141
|
-
const getPuzzleCaptchaResponse = {
|
|
45
|
+
});
|
|
46
|
+
return {
|
|
47
|
+
logData: { tolerance: challenge.tolerance },
|
|
48
|
+
response: {
|
|
142
49
|
[ApiParams.status]: "ok",
|
|
143
50
|
[ApiParams.challenge]: challenge.challenge,
|
|
144
51
|
[ApiParams.background]: images.background,
|
|
@@ -148,39 +55,15 @@ var getPuzzleCaptchaChallenge_default = (env, userAccessRulesStorage) => async (
|
|
|
148
55
|
[ApiParams.originY]: challenge.originY,
|
|
149
56
|
[ApiParams.timestamp]: challenge.requestedAtTimestamp.toString(),
|
|
150
57
|
[ApiParams.signature]: { [ApiParams.provider]: { [ApiParams.challenge]: challenge.providerSignature } }
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
msg: "Puzzle captcha challenge issued",
|
|
154
|
-
data: {
|
|
155
|
-
captchaType: CaptchaType.puzzle,
|
|
156
|
-
challenge: challenge.challenge,
|
|
157
|
-
tolerance: challenge.tolerance,
|
|
158
|
-
user,
|
|
159
|
-
dapp,
|
|
160
|
-
session: sessionId
|
|
161
|
-
}
|
|
162
|
-
}));
|
|
163
|
-
res.locals.padBytes = padBytes;
|
|
164
|
-
recordCaptchaIssued(CaptchaType.puzzle);
|
|
165
|
-
return res.json(getPuzzleCaptchaResponse);
|
|
166
|
-
} catch (err) {
|
|
167
|
-
recordCaptchaIssueError(CaptchaType.puzzle);
|
|
168
|
-
req.logger.error(() => ({
|
|
169
|
-
err,
|
|
170
|
-
body: summariseRequestBody(req),
|
|
171
|
-
msg: "Error in puzzle captcha challenge request"
|
|
172
|
-
}));
|
|
173
|
-
return next(new ProsopoApiError("API.BAD_REQUEST", {
|
|
174
|
-
context: {
|
|
175
|
-
code: 500,
|
|
176
|
-
siteKey: req.body.dapp,
|
|
177
|
-
user: req.body.user,
|
|
178
|
-
error: err
|
|
179
|
-
},
|
|
180
|
-
i18n: req.i18n,
|
|
181
|
-
logger: req.logger
|
|
182
|
-
}));
|
|
183
|
-
}
|
|
58
|
+
}
|
|
59
|
+
};
|
|
184
60
|
};
|
|
61
|
+
var getPuzzleCaptchaChallenge_default = (env, userAccessRulesStorage) => interactiveChallengeHandler(env, userAccessRulesStorage, {
|
|
62
|
+
captchaType: CaptchaType.puzzle,
|
|
63
|
+
label: "puzzle",
|
|
64
|
+
manager: (tasks) => tasks.puzzleCaptchaManager,
|
|
65
|
+
maintenanceResponse: buildPuzzleMaintenanceResponse,
|
|
66
|
+
issue: issuePuzzleChallenge
|
|
67
|
+
});
|
|
185
68
|
//#endregion
|
|
186
69
|
export { getPuzzleCaptchaChallenge_default as default };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getPuzzleCaptchaChallenge.js","sourceRoot":"","sources":["../../../src/api/captcha/getPuzzleCaptchaChallenge.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"getPuzzleCaptchaChallenge.js","sourceRoot":"","sources":["../../../src/api/captcha/getPuzzleCaptchaChallenge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { type ApiResponse, type CaptchaType, type CompositeIpAddress, type IPInfoResponse, type PoWChallengeId, type RequestHeaders } from "@prosopo/types";
|
|
2
|
+
import type { ClientRecord, ProjectedSession } from "@prosopo/types-database";
|
|
3
|
+
import type { ProviderEnvironment } from "@prosopo/types-env";
|
|
4
|
+
import type { AccessRulesStorage } from "@prosopo/user-access-policy";
|
|
5
|
+
import type { NextFunction, Request, Response } from "express";
|
|
6
|
+
import type { AugmentedRequest } from "../../express.js";
|
|
7
|
+
import type { CaptchaManager } from "../../tasks/captchaManager.js";
|
|
8
|
+
import { Tasks } from "../../tasks/index.js";
|
|
9
|
+
import { type RequestTimeTrafficVerdict } from "./trafficFilterRequestTime.js";
|
|
10
|
+
export interface ChallengeIssueContext {
|
|
11
|
+
tasks: Tasks;
|
|
12
|
+
user: string;
|
|
13
|
+
dapp: string;
|
|
14
|
+
origin: string;
|
|
15
|
+
clientSettings: ClientRecord;
|
|
16
|
+
sessionRecord: ProjectedSession | undefined;
|
|
17
|
+
trafficVerdict: RequestTimeTrafficVerdict;
|
|
18
|
+
provenance: {
|
|
19
|
+
ipAddress: CompositeIpAddress;
|
|
20
|
+
headers: RequestHeaders;
|
|
21
|
+
ja4: string;
|
|
22
|
+
sessionId?: string;
|
|
23
|
+
ipInfo?: IPInfoResponse;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
type ChallengeResponse = ApiResponse & {
|
|
27
|
+
challenge: PoWChallengeId;
|
|
28
|
+
};
|
|
29
|
+
export interface IssuedChallenge<TResponse> {
|
|
30
|
+
response: TResponse;
|
|
31
|
+
logData: Readonly<Record<string, number>>;
|
|
32
|
+
}
|
|
33
|
+
export interface InteractiveChallengeSpec<TResponse extends ChallengeResponse> {
|
|
34
|
+
captchaType: CaptchaType.puzzle | CaptchaType.iconOrder | CaptchaType.audio;
|
|
35
|
+
label: string;
|
|
36
|
+
manager: (tasks: Tasks) => CaptchaManager;
|
|
37
|
+
maintenanceResponse: (user: string, dapp: string) => Promise<TResponse>;
|
|
38
|
+
issue: (context: ChallengeIssueContext) => Promise<IssuedChallenge<TResponse>>;
|
|
39
|
+
}
|
|
40
|
+
export declare const interactiveChallengeHandler: <TResponse extends ChallengeResponse>(env: ProviderEnvironment, userAccessRulesStorage: AccessRulesStorage, spec: InteractiveChallengeSpec<TResponse>) => (req: Request & AugmentedRequest, res: Response, next: NextFunction) => Promise<void | Response<any, Record<string, any>>>;
|
|
41
|
+
export {};
|
|
42
|
+
//# sourceMappingURL=interactiveCaptchaChallenge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interactiveCaptchaChallenge.d.ts","sourceRoot":"","sources":["../../../src/api/captcha/interactiveCaptchaChallenge.ts"],"names":[],"mappings":"AAcA,OAAO,EACN,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,kBAAkB,EAGvB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,cAAc,EAEnB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC9E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAEtE,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE/D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AACpE,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAW7C,OAAO,EACN,KAAK,yBAAyB,EAE9B,MAAM,+BAA+B,CAAC;AAGvC,MAAM,WAAW,qBAAqB;IACrC,KAAK,EAAE,KAAK,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,YAAY,CAAC;IAC7B,aAAa,EAAE,gBAAgB,GAAG,SAAS,CAAC;IAC5C,cAAc,EAAE,yBAAyB,CAAC;IAE1C,UAAU,EAAE;QACX,SAAS,EAAE,kBAAkB,CAAC;QAC9B,OAAO,EAAE,cAAc,CAAC;QACxB,GAAG,EAAE,MAAM,CAAC;QACZ,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,MAAM,CAAC,EAAE,cAAc,CAAC;KACxB,CAAC;CACF;AAED,KAAK,iBAAiB,GAAG,WAAW,GAAG;IAAE,SAAS,EAAE,cAAc,CAAA;CAAE,CAAC;AAErE,MAAM,WAAW,eAAe,CAAC,SAAS;IACzC,QAAQ,EAAE,SAAS,CAAC;IAEpB,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAC1C;AAED,MAAM,WAAW,wBAAwB,CAAC,SAAS,SAAS,iBAAiB;IAC5E,WAAW,EAAE,WAAW,CAAC,MAAM,GAAG,WAAW,CAAC,SAAS,GAAG,WAAW,CAAC,KAAK,CAAC;IAE5E,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,cAAc,CAAC;IAC1C,mBAAmB,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IAExE,KAAK,EAAE,CACN,OAAO,EAAE,qBAAqB,KAC1B,OAAO,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC,CAAC;CACzC;AAMD,eAAO,MAAM,2BAA2B,GACtC,SAAS,SAAS,iBAAiB,OAC9B,mBAAmB,0BACA,kBAAkB,QACpC,wBAAwB,CAAC,SAAS,CAAC,WAGpC,OAAO,GAAG,gBAAgB,OAC1B,QAAQ,QACP,YAAY,uDAoOlB,CAAC"}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { getCompositeIpAddress } from "../../compositeIpAddress.js";
|
|
2
|
+
import { recordCaptchaIssueError, recordCaptchaIssued } from "../metrics.js";
|
|
3
|
+
import { getRequestUserScope, normalizeHeadersForMatching } from "../blacklistRequestInspector.js";
|
|
4
|
+
import { validateAddr, validateSiteKey } from "../validateAddress.js";
|
|
5
|
+
import { Tasks } from "../../tasks/tasks.js";
|
|
6
|
+
import { getMaintenanceMode } from "../admin/apiToggleMaintenanceModeEndpoint.js";
|
|
7
|
+
import { isReservedTestSiteKey } from "../testSiteKey.js";
|
|
8
|
+
import { normalizeRequestIp } from "../../utils/normalizeRequestIp.js";
|
|
9
|
+
import { summariseRequestBody } from "../requestBodySummary.js";
|
|
10
|
+
import { applyTrafficFilterAtRequestTime } from "./trafficFilterRequestTime.js";
|
|
11
|
+
import { ProsopoApiError } from "@prosopo/common";
|
|
12
|
+
import { GetPuzzleCaptchaChallengeRequestBody, SimdReadingsStage } from "@prosopo/types";
|
|
13
|
+
import { flatten } from "@prosopo/util";
|
|
14
|
+
//#region src/api/captcha/interactiveCaptchaChallenge.ts
|
|
15
|
+
var capitalise = (text) => text.charAt(0).toUpperCase() + text.slice(1);
|
|
16
|
+
/** Request handling shared by the challenge endpoints of the interactive types. */
|
|
17
|
+
var interactiveChallengeHandler = (env, userAccessRulesStorage, spec) => async (req, res, next) => {
|
|
18
|
+
const { captchaType, label } = spec;
|
|
19
|
+
let parsed;
|
|
20
|
+
try {
|
|
21
|
+
parsed = GetPuzzleCaptchaChallengeRequestBody.parse(req.body);
|
|
22
|
+
} catch (err) {
|
|
23
|
+
return next(new ProsopoApiError("CAPTCHA.PARSE_ERROR", {
|
|
24
|
+
context: {
|
|
25
|
+
code: 400,
|
|
26
|
+
error: err
|
|
27
|
+
},
|
|
28
|
+
i18n: req.i18n,
|
|
29
|
+
logger: req.logger
|
|
30
|
+
}));
|
|
31
|
+
}
|
|
32
|
+
const { user, dapp, sessionId, simdReadings } = parsed;
|
|
33
|
+
validateSiteKey(dapp);
|
|
34
|
+
validateAddr(user);
|
|
35
|
+
if (getMaintenanceMode()) {
|
|
36
|
+
req.logger.info(() => ({
|
|
37
|
+
msg: `Maintenance mode active - returning dummy ${label} challenge`,
|
|
38
|
+
data: {
|
|
39
|
+
dapp,
|
|
40
|
+
user,
|
|
41
|
+
sessionId
|
|
42
|
+
}
|
|
43
|
+
}));
|
|
44
|
+
return res.json(await spec.maintenanceResponse(user, dapp));
|
|
45
|
+
}
|
|
46
|
+
if (isReservedTestSiteKey(dapp)) {
|
|
47
|
+
req.logger.warn(() => ({
|
|
48
|
+
msg: `Reserved TEST site key - returning dummy ${label} challenge`,
|
|
49
|
+
data: {
|
|
50
|
+
dapp,
|
|
51
|
+
user,
|
|
52
|
+
sessionId
|
|
53
|
+
}
|
|
54
|
+
}));
|
|
55
|
+
return res.json(await spec.maintenanceResponse(user, dapp));
|
|
56
|
+
}
|
|
57
|
+
const tasks = new Tasks(env, req.logger);
|
|
58
|
+
const manager = spec.manager(tasks);
|
|
59
|
+
try {
|
|
60
|
+
const clientSettings = await tasks.db.getClientRecord(dapp);
|
|
61
|
+
if (!clientSettings) return next(new ProsopoApiError("API.SITE_KEY_NOT_REGISTERED", {
|
|
62
|
+
context: {
|
|
63
|
+
code: 400,
|
|
64
|
+
siteKey: dapp
|
|
65
|
+
},
|
|
66
|
+
i18n: req.i18n,
|
|
67
|
+
logger: req.logger
|
|
68
|
+
}));
|
|
69
|
+
const normalizedIp = normalizeRequestIp(req.ip, req.logger);
|
|
70
|
+
if (!normalizedIp) req.logger.warn(() => ({ msg: "Request missing IP; geoblocking will be skipped" }));
|
|
71
|
+
const countryCode = req.ipInfo && "isValid" in req.ipInfo && req.ipInfo.isValid ? req.ipInfo.countryCode : void 0;
|
|
72
|
+
const asn = req.ipInfo && "isValid" in req.ipInfo && req.ipInfo.isValid ? req.ipInfo.asnNumber : void 0;
|
|
73
|
+
const sessionRecord = sessionId ? await tasks.db.getSessionRecordBySessionId(sessionId) : void 0;
|
|
74
|
+
const userScope = getRequestUserScope(flatten(req.headers), req.ja4, normalizedIp, user, sessionRecord?.decryptedHeadHash, void 0, countryCode, asn);
|
|
75
|
+
const userAccessPolicy = (await manager.getPrioritisedAccessPolicies(userAccessRulesStorage, dapp, userScope, normalizeHeadersForMatching(req.headers))).find((p) => !p.deferToVerify);
|
|
76
|
+
const { valid, reason, sessionId: validSessionId } = await manager.isValidRequest(clientSettings, captchaType, env, sessionId, userAccessPolicy, normalizedIp);
|
|
77
|
+
if (!valid) return next(new ProsopoApiError(reason || "API.BAD_REQUEST", {
|
|
78
|
+
context: {
|
|
79
|
+
code: 400,
|
|
80
|
+
siteKey: dapp,
|
|
81
|
+
user
|
|
82
|
+
},
|
|
83
|
+
i18n: req.i18n,
|
|
84
|
+
logger: req.logger
|
|
85
|
+
}));
|
|
86
|
+
const origin = req.headers.origin;
|
|
87
|
+
if (!origin) return next(new ProsopoApiError("API.BAD_REQUEST", {
|
|
88
|
+
context: {
|
|
89
|
+
error: "Origin header not found",
|
|
90
|
+
code: 400,
|
|
91
|
+
siteKey: dapp,
|
|
92
|
+
user
|
|
93
|
+
},
|
|
94
|
+
i18n: req.i18n,
|
|
95
|
+
logger: req.logger
|
|
96
|
+
}));
|
|
97
|
+
const trafficVerdict = applyTrafficFilterAtRequestTime(req.ipInfo, clientSettings.settings?.trafficFilter, req.logger);
|
|
98
|
+
if (validSessionId && simdReadings) await tasks.frictionlessManager.decryptAndAttachSimdReadingsIfAbsent(validSessionId, simdReadings, SimdReadingsStage.challenge).catch((updateErr) => {
|
|
99
|
+
req.logger.warn(() => ({
|
|
100
|
+
err: updateErr,
|
|
101
|
+
msg: `Failed to patch session with SIMD readings on ${label} challenge`
|
|
102
|
+
}));
|
|
103
|
+
});
|
|
104
|
+
const { response, logData } = await spec.issue({
|
|
105
|
+
tasks,
|
|
106
|
+
user,
|
|
107
|
+
dapp,
|
|
108
|
+
origin,
|
|
109
|
+
clientSettings,
|
|
110
|
+
sessionRecord,
|
|
111
|
+
trafficVerdict,
|
|
112
|
+
provenance: {
|
|
113
|
+
ipAddress: getCompositeIpAddress(normalizedIp),
|
|
114
|
+
headers: flatten(req.headers),
|
|
115
|
+
ja4: req.ja4,
|
|
116
|
+
sessionId: validSessionId,
|
|
117
|
+
ipInfo: req.ipInfo
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
req.logger.info(() => ({
|
|
121
|
+
msg: `${capitalise(label)} captcha challenge issued`,
|
|
122
|
+
data: {
|
|
123
|
+
captchaType,
|
|
124
|
+
challenge: response.challenge,
|
|
125
|
+
...logData,
|
|
126
|
+
user,
|
|
127
|
+
dapp,
|
|
128
|
+
session: sessionId
|
|
129
|
+
}
|
|
130
|
+
}));
|
|
131
|
+
res.locals.padBytes = trafficVerdict.padBytes;
|
|
132
|
+
recordCaptchaIssued(captchaType);
|
|
133
|
+
return res.json(response);
|
|
134
|
+
} catch (err) {
|
|
135
|
+
recordCaptchaIssueError(captchaType);
|
|
136
|
+
req.logger.error(() => ({
|
|
137
|
+
err,
|
|
138
|
+
body: summariseRequestBody(req),
|
|
139
|
+
msg: `Error in ${label} captcha challenge request`
|
|
140
|
+
}));
|
|
141
|
+
return next(new ProsopoApiError("API.BAD_REQUEST", {
|
|
142
|
+
context: {
|
|
143
|
+
code: 500,
|
|
144
|
+
siteKey: req.body.dapp,
|
|
145
|
+
user: req.body.user,
|
|
146
|
+
error: err
|
|
147
|
+
},
|
|
148
|
+
i18n: req.i18n,
|
|
149
|
+
logger: req.logger
|
|
150
|
+
}));
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
//#endregion
|
|
154
|
+
export { interactiveChallengeHandler };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interactiveCaptchaChallenge.js","sourceRoot":"","sources":["../../../src/api/captcha/interactiveCaptchaChallenge.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAIN,oCAAoC,EAKpC,iBAAiB,GACjB,MAAM,gBAAgB,CAAC;AAIxB,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAExC,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AAGpE,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAC7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AACvE,OAAO,EAAE,kBAAkB,EAAE,MAAM,8CAA8C,CAAC;AAClF,OAAO,EACN,mBAAmB,EACnB,2BAA2B,GAC3B,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAC7E,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,EAEN,+BAA+B,GAC/B,MAAM,+BAA+B,CAAC;AAyCvC,MAAM,UAAU,GAAG,CAAC,IAAY,EAAU,EAAE,CAC3C,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAG9C,MAAM,CAAC,MAAM,2BAA2B,GACvC,CACC,GAAwB,EACxB,sBAA0C,EAC1C,IAAyC,EACxC,EAAE,CACJ,KAAK,EACJ,GAA+B,EAC/B,GAAa,EACb,IAAkB,EACjB,EAAE;IACH,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC;IACpC,IAAI,MAAsD,CAAC;IAE3D,IAAI,CAAC;QACJ,MAAM,GAAG,oCAAoC,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC/D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACd,OAAO,IAAI,CACV,IAAI,eAAe,CAAC,qBAAqB,EAAE;YAC1C,OAAO,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE;YAClC,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,MAAM,EAAE,GAAG,CAAC,MAAM;SAClB,CAAC,CACF,CAAC;IACH,CAAC;IAED,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,EAAE,GAAG,MAAM,CAAC;IAEvD,eAAe,CAAC,IAAI,CAAC,CAAC;IACtB,YAAY,CAAC,IAAI,CAAC,CAAC;IAKnB,IAAI,kBAAkB,EAAE,EAAE,CAAC;QAC1B,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;YACtB,GAAG,EAAE,6CAA6C,KAAK,YAAY;YACnE,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE;SAC/B,CAAC,CAAC,CAAC;QACJ,OAAO,GAAG,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,mBAAmB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;IAC7D,CAAC;IAMD,IAAI,qBAAqB,CAAC,IAAI,CAAC,EAAE,CAAC;QACjC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;YACtB,GAAG,EAAE,4CAA4C,KAAK,YAAY;YAClE,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE;SAC/B,CAAC,CAAC,CAAC;QACJ,OAAO,GAAG,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,mBAAmB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;IAC7D,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACzC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAEpC,IAAI,CAAC;QACJ,MAAM,cAAc,GAAG,MAAM,KAAK,CAAC,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;QAE5D,IAAI,CAAC,cAAc,EAAE,CAAC;YACrB,OAAO,IAAI,CACV,IAAI,eAAe,CAAC,6BAA6B,EAAE;gBAClD,OAAO,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE;gBACrC,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,MAAM,EAAE,GAAG,CAAC,MAAM;aAClB,CAAC,CACF,CAAC;QACH,CAAC;QAED,MAAM,YAAY,GAAG,kBAAkB,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;QAC5D,IAAI,CAAC,YAAY,EAAE,CAAC;YACnB,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;gBACtB,GAAG,EAAE,iDAAiD;aACtD,CAAC,CAAC,CAAC;QACL,CAAC;QAGD,MAAM,WAAW,GAChB,GAAG,CAAC,MAAM,IAAI,SAAS,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO;YAC1D,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW;YACxB,CAAC,CAAC,SAAS,CAAC;QACd,MAAM,GAAG,GACR,GAAG,CAAC,MAAM,IAAI,SAAS,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO;YAC1D,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS;YACtB,CAAC,CAAC,SAAS,CAAC;QAId,MAAM,aAAa,GAAG,SAAS;YAC9B,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC,2BAA2B,CAAC,SAAS,CAAC;YACvD,CAAC,CAAC,SAAS,CAAC;QAEb,MAAM,SAAS,GAAG,mBAAmB,CACpC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EACpB,GAAG,CAAC,GAAG,EACP,YAAY,EACZ,IAAI,EACJ,aAAa,EAAE,iBAAiB,EAChC,SAAS,EACT,WAAW,EACX,GAAG,CACH,CAAC;QAGF,MAAM,gBAAgB,GAAG,CACxB,MAAM,OAAO,CAAC,4BAA4B,CACzC,sBAAsB,EACtB,IAAI,EACJ,SAAS,EACT,2BAA2B,CAAC,GAAG,CAAC,OAAO,CAAC,CACxC,CACD,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;QAEhC,MAAM,EACL,KAAK,EACL,MAAM,EACN,SAAS,EAAE,cAAc,GACzB,GAAG,MAAM,OAAO,CAAC,cAAc,CAC/B,cAAc,EACd,WAAW,EACX,GAAG,EACH,SAAS,EACT,gBAAgB,EAChB,YAAY,CACZ,CAAC;QAEF,IAAI,CAAC,KAAK,EAAE,CAAC;YACZ,OAAO,IAAI,CACV,IAAI,eAAe,CAAC,MAAM,IAAI,iBAAiB,EAAE;gBAChD,OAAO,EAAE;oBACR,IAAI,EAAE,GAAG;oBACT,OAAO,EAAE,IAAI;oBACb,IAAI;iBACJ;gBACD,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,MAAM,EAAE,GAAG,CAAC,MAAM;aAClB,CAAC,CACF,CAAC;QACH,CAAC;QAED,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC;QAElC,IAAI,CAAC,MAAM,EAAE,CAAC;YACb,OAAO,IAAI,CACV,IAAI,eAAe,CAAC,iBAAiB,EAAE;gBACtC,OAAO,EAAE;oBACR,KAAK,EAAE,yBAAyB;oBAChC,IAAI,EAAE,GAAG;oBACT,OAAO,EAAE,IAAI;oBACb,IAAI;iBACJ;gBACD,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,MAAM,EAAE,GAAG,CAAC,MAAM;aAClB,CAAC,CACF,CAAC;QACH,CAAC;QAMD,MAAM,cAAc,GAAG,+BAA+B,CACrD,GAAG,CAAC,MAAM,EACV,cAAc,CAAC,QAAQ,EAAE,aAAa,EACtC,GAAG,CAAC,MAAM,CACV,CAAC;QAEF,IAAI,cAAc,IAAI,YAAY,EAAE,CAAC;YACpC,MAAM,KAAK,CAAC,mBAAmB;iBAC7B,oCAAoC,CACpC,cAAc,EACd,YAAY,EACZ,iBAAiB,CAAC,SAAS,CAC3B;iBACA,KAAK,CAAC,CAAC,SAAS,EAAE,EAAE;gBACpB,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;oBACtB,GAAG,EAAE,SAAS;oBACd,GAAG,EAAE,iDAAiD,KAAK,YAAY;iBACvE,CAAC,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;QACL,CAAC;QAED,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC;YAC9C,KAAK;YACL,IAAI;YACJ,IAAI;YACJ,MAAM;YACN,cAAc;YACd,aAAa;YACb,cAAc;YACd,UAAU,EAAE;gBACX,SAAS,EAAE,qBAAqB,CAAC,YAAY,CAAC;gBAC9C,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC;gBAC7B,GAAG,EAAE,GAAG,CAAC,GAAG;gBACZ,SAAS,EAAE,cAAc;gBAIzB,MAAM,EAAE,GAAG,CAAC,MAAM;aAClB;SACD,CAAC,CAAC;QAEH,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;YACtB,GAAG,EAAE,GAAG,UAAU,CAAC,KAAK,CAAC,2BAA2B;YACpD,IAAI,EAAE;gBACL,WAAW;gBACX,SAAS,EAAE,QAAQ,CAAC,SAAS;gBAC7B,GAAG,OAAO;gBACV,IAAI;gBACJ,IAAI;gBACJ,OAAO,EAAE,SAAS;aAClB;SACD,CAAC,CAAC,CAAC;QACJ,GAAG,CAAC,MAAM,CAAC,QAAQ,GAAG,cAAc,CAAC,QAAQ,CAAC;QAC9C,mBAAmB,CAAC,WAAW,CAAC,CAAC;QACjC,OAAO,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC3B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACd,uBAAuB,CAAC,WAAW,CAAC,CAAC;QACrC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC;YACvB,GAAG;YACH,IAAI,EAAE,oBAAoB,CAAC,GAAG,CAAC;YAC/B,GAAG,EAAE,YAAY,KAAK,4BAA4B;SAClD,CAAC,CAAC,CAAC;QACJ,OAAO,IAAI,CACV,IAAI,eAAe,CAAC,iBAAiB,EAAE;YACtC,OAAO,EAAE;gBACR,IAAI,EAAE,GAAG;gBACT,OAAO,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI;gBACtB,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI;gBACnB,KAAK,EAAE,GAAG;aACV;YACD,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,MAAM,EAAE,GAAG,CAAC,MAAM;SAClB,CAAC,CACF,CAAC;IACH,CAAC;AACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ProviderEnvironment } from "@prosopo/types-env";
|
|
2
|
+
import type { NextFunction, Request, Response } from "express";
|
|
3
|
+
import type { AugmentedRequest } from "../../express.js";
|
|
4
|
+
import { Tasks } from "../../tasks/tasks.js";
|
|
5
|
+
export interface InteractiveSolutionSpec<TBody> {
|
|
6
|
+
label: string;
|
|
7
|
+
parse: (body: unknown) => TBody;
|
|
8
|
+
verify: (tasks: Tasks, body: TBody, submitWindowMs: number, req: Request & AugmentedRequest) => Promise<boolean>;
|
|
9
|
+
}
|
|
10
|
+
export declare const interactiveSolutionHandler: <TBody extends {
|
|
11
|
+
dapp: string;
|
|
12
|
+
user: string;
|
|
13
|
+
}>(env: ProviderEnvironment, spec: InteractiveSolutionSpec<TBody>) => (req: Request & AugmentedRequest, res: Response, next: NextFunction) => Promise<void | Response<any, Record<string, any>>>;
|
|
14
|
+
//# sourceMappingURL=interactiveCaptchaSolution.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interactiveCaptchaSolution.d.ts","sourceRoot":"","sources":["../../../src/api/captcha/interactiveCaptchaSolution.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAM7C,MAAM,WAAW,uBAAuB,CAAC,KAAK;IAE7C,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,KAAK,CAAC;IAEhC,MAAM,EAAE,CACP,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,KAAK,EACX,cAAc,EAAE,MAAM,EACtB,GAAG,EAAE,OAAO,GAAG,gBAAgB,KAC3B,OAAO,CAAC,OAAO,CAAC,CAAC;CACtB;AAGD,eAAO,MAAM,0BAA0B,GACrC,KAAK,SAAS;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,OACvC,mBAAmB,QAClB,uBAAuB,CAAC,KAAK,CAAC,WAG/B,OAAO,GAAG,gBAAgB,OAC1B,QAAQ,QACP,YAAY,uDA8FlB,CAAC"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { validateAddr, validateSiteKey } from "../validateAddress.js";
|
|
2
|
+
import { Tasks } from "../../tasks/tasks.js";
|
|
3
|
+
import { getMaintenanceMode } from "../admin/apiToggleMaintenanceModeEndpoint.js";
|
|
4
|
+
import { resolveTestSiteKeyVerdict } from "../testSiteKey.js";
|
|
5
|
+
import { summariseRequestBody } from "../requestBodySummary.js";
|
|
6
|
+
import { ProsopoApiError } from "@prosopo/common";
|
|
7
|
+
//#region src/api/captcha/interactiveCaptchaSolution.ts
|
|
8
|
+
/** Request handling shared by the solution endpoints of the interactive types. */
|
|
9
|
+
var interactiveSolutionHandler = (env, spec) => async (req, res, next) => {
|
|
10
|
+
if (getMaintenanceMode()) {
|
|
11
|
+
req.logger.info(() => ({ msg: "Maintenance mode active - returning verified" }));
|
|
12
|
+
return res.json({
|
|
13
|
+
status: "ok",
|
|
14
|
+
verified: true
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
let parsed;
|
|
18
|
+
const tasks = new Tasks(env, req.logger);
|
|
19
|
+
try {
|
|
20
|
+
parsed = spec.parse(req.body);
|
|
21
|
+
} catch (err) {
|
|
22
|
+
return next(new ProsopoApiError("CAPTCHA.PARSE_ERROR", {
|
|
23
|
+
context: {
|
|
24
|
+
code: 400,
|
|
25
|
+
error: err,
|
|
26
|
+
body: summariseRequestBody(req)
|
|
27
|
+
},
|
|
28
|
+
i18n: req.i18n,
|
|
29
|
+
logger: req.logger
|
|
30
|
+
}));
|
|
31
|
+
}
|
|
32
|
+
const { dapp, user } = parsed;
|
|
33
|
+
validateSiteKey(dapp);
|
|
34
|
+
validateAddr(user);
|
|
35
|
+
const testVerdict = resolveTestSiteKeyVerdict(dapp, req.logger);
|
|
36
|
+
if (testVerdict !== null) {
|
|
37
|
+
const response = {
|
|
38
|
+
status: "ok",
|
|
39
|
+
verified: testVerdict
|
|
40
|
+
};
|
|
41
|
+
return res.json(response);
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
const clientRecord = await tasks.db.getClientRecord(dapp);
|
|
45
|
+
if (!clientRecord) return next(new ProsopoApiError("API.SITE_KEY_NOT_REGISTERED", {
|
|
46
|
+
context: {
|
|
47
|
+
code: 400,
|
|
48
|
+
siteKey: dapp
|
|
49
|
+
},
|
|
50
|
+
i18n: req.i18n,
|
|
51
|
+
logger: req.logger
|
|
52
|
+
}));
|
|
53
|
+
const submitWindowMs = clientRecord.settings.solutionTimeout ?? clientRecord.settings.verifiedTimeout;
|
|
54
|
+
const response = {
|
|
55
|
+
status: "ok",
|
|
56
|
+
verified: await spec.verify(tasks, parsed, submitWindowMs, req)
|
|
57
|
+
};
|
|
58
|
+
return res.json(response);
|
|
59
|
+
} catch (err) {
|
|
60
|
+
req.logger.error(() => ({
|
|
61
|
+
err,
|
|
62
|
+
body: summariseRequestBody(req),
|
|
63
|
+
msg: `Error in ${spec.label} captcha solution submission`
|
|
64
|
+
}));
|
|
65
|
+
return next(new ProsopoApiError("API.BAD_REQUEST", {
|
|
66
|
+
context: {
|
|
67
|
+
code: 500,
|
|
68
|
+
siteKey: req.body.dapp,
|
|
69
|
+
error: err
|
|
70
|
+
},
|
|
71
|
+
i18n: req.i18n,
|
|
72
|
+
logger: req.logger
|
|
73
|
+
}));
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
//#endregion
|
|
77
|
+
export { interactiveSolutionHandler };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interactiveCaptchaSolution.js","sourceRoot":"","sources":["../../../src/api/captcha/interactiveCaptchaSolution.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { type CaptchaResponseBody, type CaptchaType, type GetFrictionlessCaptchaResponse, type GetPowCaptchaResponse, type GetPuzzleCaptchaResponse, type VerificationResponse } from "@prosopo/types";
|
|
1
|
+
import { type CaptchaResponseBody, type CaptchaType, type GetAudioCaptchaResponse, type GetFrictionlessCaptchaResponse, type GetIconOrderCaptchaResponse, type GetPowCaptchaResponse, type GetPuzzleCaptchaResponse, type VerificationResponse } from "@prosopo/types";
|
|
2
2
|
export declare const MAINTENANCE_VERIFY_SCORE = 0;
|
|
3
3
|
export declare const buildMaintenanceVerificationResponse: (translate: (key: string) => string) => VerificationResponse;
|
|
4
|
-
export declare const buildFrictionlessMaintenanceResponse: (captchaType: CaptchaType.pow | CaptchaType.image | CaptchaType.puzzle, host: string | undefined) => GetFrictionlessCaptchaResponse;
|
|
4
|
+
export declare const buildFrictionlessMaintenanceResponse: (captchaType: CaptchaType.pow | CaptchaType.image | CaptchaType.puzzle | CaptchaType.iconOrder, host: string | undefined) => GetFrictionlessCaptchaResponse;
|
|
5
5
|
export declare const buildPowMaintenanceResponse: (user: string, dapp: string) => GetPowCaptchaResponse;
|
|
6
6
|
export declare const buildImageMaintenanceResponse: () => CaptchaResponseBody;
|
|
7
7
|
export declare const buildPuzzleMaintenanceResponse: (user: string, dapp: string) => Promise<GetPuzzleCaptchaResponse>;
|
|
8
|
+
export declare const buildAudioMaintenanceResponse: (user: string, dapp: string) => Promise<GetAudioCaptchaResponse>;
|
|
9
|
+
export declare const buildIconOrderMaintenanceResponse: (user: string, dapp: string) => Promise<GetIconOrderCaptchaResponse>;
|
|
8
10
|
//# sourceMappingURL=maintenanceModeResponses.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"maintenanceModeResponses.d.ts","sourceRoot":"","sources":["../../../src/api/captcha/maintenanceModeResponses.ts"],"names":[],"mappings":"AAeA,OAAO,EAEN,KAAK,mBAAmB,EACxB,KAAK,WAAW,EAChB,KAAK,8BAA8B,EACnC,KAAK,qBAAqB,EAC1B,KAAK,wBAAwB,EAG7B,KAAK,oBAAoB,EACzB,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"maintenanceModeResponses.d.ts","sourceRoot":"","sources":["../../../src/api/captcha/maintenanceModeResponses.ts"],"names":[],"mappings":"AAeA,OAAO,EAEN,KAAK,mBAAmB,EACxB,KAAK,WAAW,EAChB,KAAK,uBAAuB,EAC5B,KAAK,8BAA8B,EACnC,KAAK,2BAA2B,EAChC,KAAK,qBAAqB,EAC1B,KAAK,wBAAwB,EAG7B,KAAK,oBAAoB,EACzB,MAAM,gBAAgB,CAAC;AAyBxB,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAiB1C,eAAO,MAAM,oCAAoC,cACrC,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,KAChC,oBAID,CAAC;AAEH,eAAO,MAAM,oCAAoC,gBAE7C,WAAW,CAAC,GAAG,GACf,WAAW,CAAC,KAAK,GACjB,WAAW,CAAC,MAAM,GAClB,WAAW,CAAC,SAAS,QAClB,MAAM,GAAG,SAAS,KACtB,8BAID,CAAC;AAEH,eAAO,MAAM,2BAA2B,SACjC,MAAM,QACN,MAAM,KACV,qBAWF,CAAC;AAOF,eAAO,MAAM,6BAA6B,QAAO,mBAQ/C,CAAC;AAMH,eAAO,MAAM,8BAA8B,SACpC,MAAM,QACN,MAAM,KACV,OAAO,CAAC,wBAAwB,CAgBlC,CAAC;AAIF,eAAO,MAAM,6BAA6B,SACnC,MAAM,QACN,MAAM,KACV,OAAO,CAAC,uBAAuB,CAajC,CAAC;AAIF,eAAO,MAAM,iCAAiC,SACvC,MAAM,QACN,MAAM,KACV,OAAO,CAAC,2BAA2B,CAcrC,CAAC"}
|