@prosopo/provider 4.15.16 → 5.0.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 +103 -102
- package/.turbo/turbo-build$colon$tsc.log +24 -24
- package/.turbo/turbo-build.log +103 -102
- package/CHANGELOG.md +108 -0
- package/dist/api/admin/apiAdminRoutesProvider.d.ts.map +1 -1
- package/dist/api/admin/apiAdminRoutesProvider.js +3 -5
- package/dist/api/admin/apiAdminRoutesProvider.js.map +1 -1
- package/dist/api/admin/apiReplaceDetectorPoolEndpoint.d.ts +11 -0
- package/dist/api/admin/apiReplaceDetectorPoolEndpoint.d.ts.map +1 -0
- package/dist/api/admin/apiReplaceDetectorPoolEndpoint.js +56 -0
- package/dist/api/admin/apiReplaceDetectorPoolEndpoint.js.map +1 -0
- package/dist/api/captcha/assignDetectorBundle.d.ts +6 -0
- package/dist/api/captcha/assignDetectorBundle.d.ts.map +1 -0
- package/dist/api/captcha/assignDetectorBundle.js +51 -0
- package/dist/api/captcha/assignDetectorBundle.js.map +1 -0
- package/dist/api/captcha/assignDetectorBundle.test.d.ts +2 -0
- package/dist/api/captcha/assignDetectorBundle.test.d.ts.map +1 -0
- package/dist/api/captcha/assignDetectorBundle.test.js +71 -0
- package/dist/api/captcha/assignDetectorBundle.test.js.map +1 -0
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/constants.d.ts +1 -0
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/constants.d.ts.map +1 -1
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/constants.js.map +1 -1
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/decisionMachine.d.ts.map +1 -1
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/decisionMachine.js +21 -2
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/decisionMachine.js.map +1 -1
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/decryptSimdReadings.d.ts +1 -1
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/decryptSimdReadings.d.ts.map +1 -1
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/decryptSimdReadings.js +3 -3
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/decryptSimdReadings.js.map +1 -1
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/handler.d.ts.map +1 -1
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/handler.js +13 -7
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/handler.js.map +1 -1
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.d.ts +3 -0
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.d.ts.map +1 -1
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.js +52 -18
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.js.map +1 -1
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.powFallback.test.d.ts +2 -0
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.powFallback.test.d.ts.map +1 -0
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.powFallback.test.js +86 -0
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.powFallback.test.js.map +1 -0
- package/dist/api/captcha/getImageCaptchaChallenge.d.ts.map +1 -1
- package/dist/api/captcha/getImageCaptchaChallenge.js +2 -1
- package/dist/api/captcha/getImageCaptchaChallenge.js.map +1 -1
- package/dist/api/captcha/getPoWCaptchaChallenge.d.ts.map +1 -1
- package/dist/api/captcha/getPoWCaptchaChallenge.js +2 -1
- package/dist/api/captcha/getPoWCaptchaChallenge.js.map +1 -1
- package/dist/api/captcha/getPuzzleCaptchaChallenge.d.ts.map +1 -1
- package/dist/api/captcha/getPuzzleCaptchaChallenge.js +2 -1
- package/dist/api/captcha/getPuzzleCaptchaChallenge.js.map +1 -1
- package/dist/api/captcha/submitPoWCaptchaSolution.d.ts.map +1 -1
- package/dist/api/captcha/submitPoWCaptchaSolution.js +1 -1
- package/dist/api/captcha/submitPoWCaptchaSolution.js.map +1 -1
- package/dist/api/captcha.d.ts.map +1 -1
- package/dist/api/captcha.js +6 -0
- package/dist/api/captcha.js.map +1 -1
- package/dist/api/startProviderApi.d.ts.map +1 -1
- package/dist/api/startProviderApi.js +21 -3
- package/dist/api/startProviderApi.js.map +1 -1
- package/dist/cjs/api/admin/apiAdminRoutesProvider.cjs +3 -5
- package/dist/cjs/api/admin/apiReplaceDetectorPoolEndpoint.cjs +56 -0
- package/dist/cjs/api/captcha/assignDetectorBundle.cjs +51 -0
- package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/decisionMachine.cjs +21 -2
- package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/decryptSimdReadings.cjs +3 -3
- package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/handler.cjs +12 -6
- package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.cjs +52 -17
- package/dist/cjs/api/captcha/getImageCaptchaChallenge.cjs +2 -1
- package/dist/cjs/api/captcha/getPoWCaptchaChallenge.cjs +2 -1
- package/dist/cjs/api/captcha/getPuzzleCaptchaChallenge.cjs +2 -1
- package/dist/cjs/api/captcha/submitPoWCaptchaSolution.cjs +1 -1
- package/dist/cjs/api/captcha.cjs +6 -0
- package/dist/cjs/api/startProviderApi.cjs +24 -5
- package/dist/cjs/tasks/captchaManager.cjs +76 -59
- package/dist/cjs/tasks/client/clientTasks.cjs +1 -29
- package/dist/cjs/tasks/detection/bundlePool.cjs +220 -0
- package/dist/cjs/tasks/detection/decodeBehavior.cjs +644 -362
- package/dist/cjs/tasks/detection/decodeBehavior.js +1 -1
- package/dist/cjs/tasks/detection/decodePayload.cjs +956 -617
- package/dist/cjs/tasks/detection/decodePayload.js +1 -1
- package/dist/cjs/tasks/detection/decodeSimd.cjs +723 -411
- package/dist/cjs/tasks/detection/decodeSimd.js +1 -1
- package/dist/cjs/tasks/detection/getBotScore.cjs +2 -2
- package/dist/cjs/tasks/frictionless/frictionlessTasks.cjs +35 -12
- package/dist/cjs/tasks/frictionless/frictionlessTasksUtils.cjs +1 -2
- package/dist/cjs/tasks/imgCaptcha/imgCaptchaTasks.cjs +6 -6
- package/dist/cjs/tasks/powCaptcha/powTasks.cjs +2 -2
- package/dist/cjs/tasks/puzzleCaptcha/puzzleTasks.cjs +2 -2
- package/dist/tasks/captchaManager.d.ts +12 -4
- package/dist/tasks/captchaManager.d.ts.map +1 -1
- package/dist/tasks/captchaManager.js +76 -59
- package/dist/tasks/captchaManager.js.map +1 -1
- package/dist/tasks/client/clientTasks.d.ts +0 -2
- package/dist/tasks/client/clientTasks.d.ts.map +1 -1
- package/dist/tasks/client/clientTasks.js +1 -29
- package/dist/tasks/client/clientTasks.js.map +1 -1
- package/dist/tasks/detection/bundlePool.d.ts +32 -0
- package/dist/tasks/detection/bundlePool.d.ts.map +1 -0
- package/dist/tasks/detection/bundlePool.js +215 -0
- package/dist/tasks/detection/bundlePool.js.map +1 -0
- package/dist/tasks/detection/bundlePool.test.d.ts +2 -0
- package/dist/tasks/detection/bundlePool.test.d.ts.map +1 -0
- package/dist/tasks/detection/bundlePool.test.js +178 -0
- package/dist/tasks/detection/bundlePool.test.js.map +1 -0
- package/dist/tasks/detection/decodeBehavior.d.ts +2 -2
- package/dist/tasks/detection/decodeBehavior.d.ts.map +1 -1
- package/dist/tasks/detection/decodeBehavior.js +1 -1
- package/dist/tasks/detection/decodeBehavior.js.map +1 -1
- package/dist/tasks/detection/decodePayload.d.ts +2 -2
- package/dist/tasks/detection/decodePayload.d.ts.map +1 -1
- package/dist/tasks/detection/decodePayload.js +1 -1
- package/dist/tasks/detection/decodePayload.js.map +1 -1
- package/dist/tasks/detection/decodeSimd.d.ts +2 -2
- package/dist/tasks/detection/decodeSimd.d.ts.map +1 -1
- package/dist/tasks/detection/decodeSimd.js +1 -1
- package/dist/tasks/detection/decodeSimd.js.map +1 -1
- package/dist/tasks/detection/getBotScore.d.ts +1 -1
- package/dist/tasks/detection/getBotScore.d.ts.map +1 -1
- package/dist/tasks/detection/getBotScore.js +3 -3
- package/dist/tasks/detection/getBotScore.js.map +1 -1
- package/dist/tasks/frictionless/frictionlessTasks.d.ts +10 -2
- package/dist/tasks/frictionless/frictionlessTasks.d.ts.map +1 -1
- package/dist/tasks/frictionless/frictionlessTasks.js +35 -12
- package/dist/tasks/frictionless/frictionlessTasks.js.map +1 -1
- package/dist/tasks/frictionless/frictionlessTasksUtils.d.ts +1 -1
- package/dist/tasks/frictionless/frictionlessTasksUtils.d.ts.map +1 -1
- package/dist/tasks/frictionless/frictionlessTasksUtils.js +1 -2
- package/dist/tasks/frictionless/frictionlessTasksUtils.js.map +1 -1
- package/dist/tasks/imgCaptcha/imgCaptchaTasks.d.ts.map +1 -1
- package/dist/tasks/imgCaptcha/imgCaptchaTasks.js +6 -6
- 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 +2 -2
- package/dist/tasks/powCaptcha/powTasks.js.map +1 -1
- package/dist/tasks/puzzleCaptcha/puzzleTasks.d.ts.map +1 -1
- package/dist/tasks/puzzleCaptcha/puzzleTasks.js +2 -2
- package/dist/tasks/puzzleCaptcha/puzzleTasks.js.map +1 -1
- package/dist/tests/integration/maintenanceModeAdmin.integration.test.js +0 -28
- package/dist/tests/integration/maintenanceModeAdmin.integration.test.js.map +1 -1
- package/dist/tests/unit/api/admin/apiRegisterSiteKeyEndpoint.unit.test.js +1 -0
- package/dist/tests/unit/api/admin/apiRegisterSiteKeyEndpoint.unit.test.js.map +1 -1
- package/dist/tests/unit/api/adminRoutes.unit.test.js +0 -46
- package/dist/tests/unit/api/adminRoutes.unit.test.js.map +1 -1
- package/dist/tests/unit/api/captcha/getFrictionlessCaptchaChallenge/decisionMachine.unit.test.js +51 -0
- package/dist/tests/unit/api/captcha/getFrictionlessCaptchaChallenge/decisionMachine.unit.test.js.map +1 -1
- package/dist/tests/unit/api/captcha/getFrictionlessCaptchaChallenge/decryptSimdReadings.unit.test.js +12 -12
- package/dist/tests/unit/api/captcha/getFrictionlessCaptchaChallenge/decryptSimdReadings.unit.test.js.map +1 -1
- package/dist/tests/unit/api/getFrictionlessCaptchaChallenge.unit.test.js +15 -1
- package/dist/tests/unit/api/getFrictionlessCaptchaChallenge.unit.test.js.map +1 -1
- package/dist/tests/unit/tasks/captchaManager.unit.test.js +14 -30
- package/dist/tests/unit/tasks/captchaManager.unit.test.js.map +1 -1
- package/dist/tests/unit/tasks/detection/getBotScore.unit.test.js +3 -3
- package/dist/tests/unit/tasks/detection/getBotScore.unit.test.js.map +1 -1
- package/dist/tests/unit/tasks/frictionless/decryptPayload.unit.test.js +25 -7
- package/dist/tests/unit/tasks/frictionless/decryptPayload.unit.test.js.map +1 -1
- package/dist/tests/unit/tasks/frictionless/frictionlessTasks.unit.test.js +0 -1
- package/dist/tests/unit/tasks/frictionless/frictionlessTasks.unit.test.js.map +1 -1
- package/dist/tests/unit/tasks/frictionless/frictionlessTasksUtils.unit.test.js +6 -14
- package/dist/tests/unit/tasks/frictionless/frictionlessTasksUtils.unit.test.js.map +1 -1
- package/dist/tests/unit/tasks/puzzleCaptcha/puzzleTasks.unit.test.js +0 -1
- package/dist/tests/unit/tasks/puzzleCaptcha/puzzleTasks.unit.test.js.map +1 -1
- package/dist/tests/unit/tasks/writeQueueIntegration.unit.test.js +0 -2
- package/dist/tests/unit/tasks/writeQueueIntegration.unit.test.js.map +1 -1
- package/fixtures/detector-pool/bundle-0.js +15 -0
- package/fixtures/detector-pool/bundle-0.json +1 -0
- package/package.json +14 -14
- package/dist/api/admin/apiRemoveDetectorKeyEndpoint.d.ts +0 -23
- package/dist/api/admin/apiRemoveDetectorKeyEndpoint.d.ts.map +0 -1
- package/dist/api/admin/apiRemoveDetectorKeyEndpoint.js +0 -32
- package/dist/api/admin/apiRemoveDetectorKeyEndpoint.js.map +0 -1
- package/dist/api/admin/apiUpdateDetectorKeyEndpoint.d.ts +0 -14
- package/dist/api/admin/apiUpdateDetectorKeyEndpoint.d.ts.map +0 -1
- package/dist/api/admin/apiUpdateDetectorKeyEndpoint.js +0 -39
- package/dist/api/admin/apiUpdateDetectorKeyEndpoint.js.map +0 -1
- package/dist/cjs/api/admin/apiRemoveDetectorKeyEndpoint.cjs +0 -32
- package/dist/cjs/api/admin/apiUpdateDetectorKeyEndpoint.cjs +0 -39
- package/dist/tasks/detection/getBehavioralData.d.ts +0 -4
- package/dist/tasks/detection/getBehavioralData.d.ts.map +0 -1
- package/dist/tasks/detection/getBehavioralData.js +0 -51
- package/dist/tasks/detection/getBehavioralData.js.map +0 -1
- package/dist/tests/unit/api/admin/apiRemoveDetectorKeyEndpoint.unit.test.d.ts +0 -2
- package/dist/tests/unit/api/admin/apiRemoveDetectorKeyEndpoint.unit.test.d.ts.map +0 -1
- package/dist/tests/unit/api/admin/apiRemoveDetectorKeyEndpoint.unit.test.js +0 -57
- package/dist/tests/unit/api/admin/apiRemoveDetectorKeyEndpoint.unit.test.js.map +0 -1
- package/dist/tests/unit/api/admin/apiUpdateDetectorKeyEndpoint.unit.test.d.ts +0 -2
- package/dist/tests/unit/api/admin/apiUpdateDetectorKeyEndpoint.unit.test.d.ts.map +0 -1
- package/dist/tests/unit/api/admin/apiUpdateDetectorKeyEndpoint.unit.test.js +0 -60
- package/dist/tests/unit/api/admin/apiUpdateDetectorKeyEndpoint.unit.test.js.map +0 -1
- package/dist/tests/unit/tasks/detection/getBehavioralData.unit.test.d.ts +0 -2
- package/dist/tests/unit/tasks/detection/getBehavioralData.unit.test.d.ts.map +0 -1
- package/dist/tests/unit/tasks/detection/getBehavioralData.unit.test.js +0 -109
- package/dist/tests/unit/tasks/detection/getBehavioralData.unit.test.js.map +0 -1
|
@@ -34,7 +34,7 @@ var handler_default = (env, userAccessRulesStorage) => async (req, res, next) =>
|
|
|
34
34
|
}
|
|
35
35
|
}));
|
|
36
36
|
});
|
|
37
|
-
const { token, headHash, dapp, user, mode, simdReadings, currentUrl: reportedCurrentUrl, iframeUrl: reportedIframeUrl } = _prosopo_types.GetFrictionlessCaptchaChallengeRequestBody.parse(req.body);
|
|
37
|
+
const { token, headHash, dapp, user, mode, simdReadings, detectorSessionId, detectorUnavailable, currentUrl: reportedCurrentUrl, iframeUrl: reportedIframeUrl } = _prosopo_types.GetFrictionlessCaptchaChallengeRequestBody.parse(req.body);
|
|
38
38
|
const currentUrl = (0, _prosopo_util.sanitisePageUrl)(reportedCurrentUrl);
|
|
39
39
|
const iframeUrl = (0, _prosopo_util.sanitisePageUrl)(reportedIframeUrl);
|
|
40
40
|
const isProtect = (0, _prosopo_util.isProtectDeployment)(currentUrl, iframeUrl);
|
|
@@ -76,7 +76,7 @@ var handler_default = (env, userAccessRulesStorage) => async (req, res, next) =>
|
|
|
76
76
|
const tasks = new require_tasks.Tasks(env, req.logger);
|
|
77
77
|
const userSitekeyIpHash = require_hashUserIp.hashUserIp(user, normalizedIp, dapp);
|
|
78
78
|
const [decodedSimdReadings, { existingToken, dedup }, clientRecord] = await Promise.all([
|
|
79
|
-
require_decryptSimdReadings.decryptIncomingSimdReadings(tasks.frictionlessManager, simdReadings),
|
|
79
|
+
require_decryptSimdReadings.decryptIncomingSimdReadings(tasks.frictionlessManager, simdReadings, detectorSessionId),
|
|
80
80
|
require_sessionDedup.resolveSessionDedup(tasks, token, userSitekeyIpHash, req.logger),
|
|
81
81
|
tasks.db.getClientRecord(dapp)
|
|
82
82
|
]);
|
|
@@ -182,7 +182,7 @@ var handler_default = (env, userAccessRulesStorage) => async (req, res, next) =>
|
|
|
182
182
|
const flatHeaders = (0, _prosopo_util.flatten)(req.headers);
|
|
183
183
|
const countryCode = req.ipInfo && "isValid" in req.ipInfo && req.ipInfo.isValid ? req.ipInfo.countryCode : void 0;
|
|
184
184
|
const asn = req.ipInfo && "isValid" in req.ipInfo && req.ipInfo.isValid ? req.ipInfo.asnNumber : void 0;
|
|
185
|
-
const
|
|
185
|
+
const shortCircuitInput = {
|
|
186
186
|
tasks,
|
|
187
187
|
env,
|
|
188
188
|
clientRecord,
|
|
@@ -193,19 +193,24 @@ var handler_default = (env, userAccessRulesStorage) => async (req, res, next) =>
|
|
|
193
193
|
flatHeaders,
|
|
194
194
|
sessionMode,
|
|
195
195
|
userSitekeyIpHash,
|
|
196
|
+
requestId: req.requestId,
|
|
196
197
|
logger: req.logger,
|
|
198
|
+
detectorUnavailable: detectorUnavailable ?? false,
|
|
197
199
|
...req.tcpToChelloUs !== void 0 && { tcpToChelloUs: req.tcpToChelloUs },
|
|
198
200
|
...req.chelloToHandshakeUs !== void 0 && { chelloToHandshakeUs: req.chelloToHandshakeUs }
|
|
199
|
-
}
|
|
201
|
+
};
|
|
202
|
+
const shortCircuitResponse = await require_shortCircuit.runConfiguredCaptchaTypeShortCircuit(shortCircuitInput, res);
|
|
200
203
|
if (shortCircuitResponse) return shortCircuitResponse;
|
|
204
|
+
const noDetectorResponse = await require_shortCircuit.runNoDetectorPowFallback(shortCircuitInput, res);
|
|
205
|
+
if (noDetectorResponse) return noDetectorResponse;
|
|
201
206
|
const lScore = tasks.frictionlessManager.checkLangRules(req.headers["accept-language"] || "");
|
|
202
207
|
const userScope = require_blacklistRequestInspector.getRequestUserScope((0, _prosopo_util.flatten)(req.headers), req.ja4, normalizedIp, user, void 0, void 0, countryCode, asn);
|
|
203
208
|
const [decryptedPayload, validation, accessPolicies] = await Promise.all([
|
|
204
|
-
tasks.frictionlessManager.decryptPayload(token, headHash),
|
|
209
|
+
tasks.frictionlessManager.decryptPayload(token, headHash, detectorSessionId),
|
|
205
210
|
tasks.frictionlessManager.isValidRequest(clientRecord, _prosopo_types.CaptchaType.frictionless, env),
|
|
206
211
|
tasks.frictionlessManager.getPrioritisedAccessPolicies(userAccessRulesStorage, dapp, userScope)
|
|
207
212
|
]);
|
|
208
|
-
const { baseBotScore: rawBaseBotScore, timestamp: rawTimestamp, userId: rawUserId, userAgent: rawUserAgent, webView, iFrame, decryptedHeadHash, decryptionFailed: rawDecryptionFailed, triggeredDetectors, shadowDomPenalty, entropyMathRandomFingerprint, entropyCryptoFingerprint, entropyWallClockOffsetMs, entropyMathRandomFirst } = decryptedPayload;
|
|
213
|
+
const { baseBotScore: rawBaseBotScore, timestamp: rawTimestamp, userId: rawUserId, userAgent: rawUserAgent, webView, iFrame, decryptedHeadHash, decryptionFailed: rawDecryptionFailed, triggeredDetectors, shadowDomPenalty, entropyMathRandomFingerprint, entropyCryptoFingerprint, entropyWallClockOffsetMs, entropyMathRandomFirst, bundleId } = decryptedPayload;
|
|
209
214
|
const detectorOverride = process.env.PROSOPO_TEST_FRICTIONLESS_DETECTOR_OVERRIDE === "1";
|
|
210
215
|
const baseBotScore = detectorOverride ? 0 : rawBaseBotScore;
|
|
211
216
|
const timestamp = detectorOverride ? Date.now() : rawTimestamp;
|
|
@@ -259,6 +264,7 @@ var handler_default = (env, userAccessRulesStorage) => async (req, res, next) =>
|
|
|
259
264
|
ipInfo: req.ipInfo,
|
|
260
265
|
headers: flatHeaders,
|
|
261
266
|
mode: sessionMode,
|
|
267
|
+
...bundleId && { bundleId },
|
|
262
268
|
...decodedSimdReadings && { simdReadings: decodedSimdReadings },
|
|
263
269
|
...entropyMathRandomFingerprint !== void 0 && { entropyMathRandomFingerprint },
|
|
264
270
|
...entropyCryptoFingerprint !== void 0 && { entropyCryptoFingerprint },
|
|
@@ -1,27 +1,61 @@
|
|
|
1
|
+
const require_bundlePool = require("../../../tasks/detection/bundlePool.cjs");
|
|
1
2
|
const require_honeypotResponse = require("./honeypotResponse.cjs");
|
|
2
3
|
require("./constants.cjs");
|
|
3
4
|
let _prosopo_types = require("@prosopo/types");
|
|
5
|
+
let uuid = require("uuid");
|
|
4
6
|
//#region src/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.ts
|
|
7
|
+
var buildBypassSessionParams = (input) => ({
|
|
8
|
+
token: input.token || `nodetector-${(0, uuid.v4)()}`,
|
|
9
|
+
score: 0,
|
|
10
|
+
threshold: input.clientRecord.settings?.frictionlessThreshold ?? .5,
|
|
11
|
+
scoreComponents: { baseScore: 0 },
|
|
12
|
+
ipAddress: input.ipAddress,
|
|
13
|
+
webView: false,
|
|
14
|
+
iFrame: false,
|
|
15
|
+
decryptedHeadHash: "",
|
|
16
|
+
siteKey: input.dapp,
|
|
17
|
+
ipInfo: input.ipInfo,
|
|
18
|
+
headers: input.flatHeaders,
|
|
19
|
+
mode: input.sessionMode,
|
|
20
|
+
userSitekeyIpHash: input.userSitekeyIpHash,
|
|
21
|
+
...input.tcpToChelloUs !== void 0 && { tcpToChelloUs: input.tcpToChelloUs },
|
|
22
|
+
...input.chelloToHandshakeUs !== void 0 && { chelloToHandshakeUs: input.chelloToHandshakeUs }
|
|
23
|
+
});
|
|
24
|
+
/**
|
|
25
|
+
* Universal "no detector ⇒ PoW" fallback. The detector lives only in the
|
|
26
|
+
* provider-served pool bundles; when none is available for this request there
|
|
27
|
+
* is no way to run (or decrypt) frictionless detection, so the provider serves
|
|
28
|
+
* a real PoW challenge rather than the request failing or silently passing.
|
|
29
|
+
*
|
|
30
|
+
* Fires when EITHER:
|
|
31
|
+
* - the pool is empty (missing dir, empty dir, or all bundles failed to
|
|
32
|
+
* load) — no provider has a bundle to assign; or
|
|
33
|
+
* - the client reported `detectorUnavailable` (it couldn't fetch/run a
|
|
34
|
+
* bundle this session) — even if the pool itself is populated.
|
|
35
|
+
*
|
|
36
|
+
* Returns null (proceed with normal scored detection) only when the pool has at
|
|
37
|
+
* least one bundle AND the client ran one.
|
|
38
|
+
*/
|
|
39
|
+
var runNoDetectorPowFallback = async (input, res) => {
|
|
40
|
+
const pool = require_bundlePool.getDetectorBundlePool();
|
|
41
|
+
const poolEmpty = !pool || pool.size() === 0;
|
|
42
|
+
if (!poolEmpty && !input.detectorUnavailable) return null;
|
|
43
|
+
const reason = poolEmpty ? "empty_detector_pool_pow_fallback" : "client_detector_unavailable_pow_fallback";
|
|
44
|
+
input.logger.warn(() => ({
|
|
45
|
+
msg: "Frictionless decision",
|
|
46
|
+
data: {
|
|
47
|
+
requestId: input.requestId,
|
|
48
|
+
decision: reason,
|
|
49
|
+
captchaType: _prosopo_types.CaptchaType.pow
|
|
50
|
+
}
|
|
51
|
+
}));
|
|
52
|
+
require_honeypotResponse.attachHoneypot(res, input.clientRecord);
|
|
53
|
+
return res.json(await input.tasks.frictionlessManager.sendPowCaptcha(buildBypassSessionParams(input)));
|
|
54
|
+
};
|
|
5
55
|
var runConfiguredCaptchaTypeShortCircuit = async (input, res) => {
|
|
6
56
|
const configuredType = input.clientRecord.settings?.captchaType;
|
|
7
57
|
if (!configuredType || configuredType === _prosopo_types.CaptchaType.frictionless) return null;
|
|
8
|
-
const sessionParams =
|
|
9
|
-
token: input.token,
|
|
10
|
-
score: 0,
|
|
11
|
-
threshold: input.clientRecord.settings?.frictionlessThreshold ?? .5,
|
|
12
|
-
scoreComponents: { baseScore: 0 },
|
|
13
|
-
ipAddress: input.ipAddress,
|
|
14
|
-
webView: false,
|
|
15
|
-
iFrame: false,
|
|
16
|
-
decryptedHeadHash: "",
|
|
17
|
-
siteKey: input.dapp,
|
|
18
|
-
ipInfo: input.ipInfo,
|
|
19
|
-
headers: input.flatHeaders,
|
|
20
|
-
mode: input.sessionMode,
|
|
21
|
-
userSitekeyIpHash: input.userSitekeyIpHash,
|
|
22
|
-
...input.tcpToChelloUs !== void 0 && { tcpToChelloUs: input.tcpToChelloUs },
|
|
23
|
-
...input.chelloToHandshakeUs !== void 0 && { chelloToHandshakeUs: input.chelloToHandshakeUs }
|
|
24
|
-
};
|
|
58
|
+
const sessionParams = buildBypassSessionParams(input);
|
|
25
59
|
input.logger.info(() => ({
|
|
26
60
|
msg: "Frictionless decision",
|
|
27
61
|
data: {
|
|
@@ -42,3 +76,4 @@ var runConfiguredCaptchaTypeShortCircuit = async (input, res) => {
|
|
|
42
76
|
};
|
|
43
77
|
//#endregion
|
|
44
78
|
exports.runConfiguredCaptchaTypeShortCircuit = runConfiguredCaptchaTypeShortCircuit;
|
|
79
|
+
exports.runNoDetectorPowFallback = runNoDetectorPowFallback;
|
|
@@ -70,7 +70,8 @@ var getImageCaptchaChallenge_default = (env, userAccessRulesStorage) => async (r
|
|
|
70
70
|
}));
|
|
71
71
|
const countryCode = req.ipInfo && "isValid" in req.ipInfo && req.ipInfo.isValid ? req.ipInfo.countryCode : void 0;
|
|
72
72
|
const asn = req.ipInfo && "isValid" in req.ipInfo && req.ipInfo.isValid ? req.ipInfo.asnNumber : void 0;
|
|
73
|
-
const
|
|
73
|
+
const sessionRecord = sessionId ? await tasks.db.getSessionRecordBySessionId(sessionId) : void 0;
|
|
74
|
+
const userScope = require_blacklistRequestInspector.getRequestUserScope((0, _prosopo_util.flatten)(req.headers), req.ja4, normalizedIp, user, sessionRecord?.decryptedHeadHash, void 0, countryCode, asn);
|
|
74
75
|
const userAccessPolicy = (await tasks.imgCaptchaManager.getPrioritisedAccessPolicies(userAccessRulesStorage, dapp, userScope)).find((p) => !p.deferToVerify);
|
|
75
76
|
const { valid, reason, sessionId: validSessionId, solvedImagesCount } = await tasks.imgCaptchaManager.isValidRequest(clientRecord, _prosopo_types.CaptchaType.image, env, sessionId, userAccessPolicy, normalizedIp);
|
|
76
77
|
if (!valid) return next(new _prosopo_common.ProsopoApiError(reason || "API.BAD_REQUEST", {
|
|
@@ -53,7 +53,8 @@ var getPoWCaptchaChallenge_default = (env, userAccessRulesStorage) => async (req
|
|
|
53
53
|
if (!normalizedIp) req.logger.warn(() => ({ msg: "Request missing IP; geoblocking will be skipped" }));
|
|
54
54
|
const countryCode = req.ipInfo && "isValid" in req.ipInfo && req.ipInfo.isValid ? req.ipInfo.countryCode : void 0;
|
|
55
55
|
const asn = req.ipInfo && "isValid" in req.ipInfo && req.ipInfo.isValid ? req.ipInfo.asnNumber : void 0;
|
|
56
|
-
const
|
|
56
|
+
const sessionRecord = sessionId ? await tasks.db.getSessionRecordBySessionId(sessionId) : void 0;
|
|
57
|
+
const userScope = require_blacklistRequestInspector.getRequestUserScope((0, _prosopo_util.flatten)(req.headers), req.ja4, normalizedIp, user, sessionRecord?.decryptedHeadHash, void 0, countryCode, asn);
|
|
57
58
|
const userAccessPolicy = (await tasks.powCaptchaManager.getPrioritisedAccessPolicies(userAccessRulesStorage, dapp, userScope)).find((p) => !p.deferToVerify);
|
|
58
59
|
const { valid, reason, sessionId: validSessionId, powDifficulty } = await tasks.powCaptchaManager.isValidRequest(clientSettings, _prosopo_types.CaptchaType.pow, env, sessionId, userAccessPolicy, normalizedIp);
|
|
59
60
|
if (!valid) return next(new _prosopo_common.ProsopoApiError(reason || "API.BAD_REQUEST", {
|
|
@@ -53,7 +53,8 @@ var getPuzzleCaptchaChallenge_default = (env, userAccessRulesStorage) => async (
|
|
|
53
53
|
if (!normalizedIp) req.logger.warn(() => ({ msg: "Request missing IP; geoblocking will be skipped" }));
|
|
54
54
|
const countryCode = req.ipInfo && "isValid" in req.ipInfo && req.ipInfo.isValid ? req.ipInfo.countryCode : void 0;
|
|
55
55
|
const asn = req.ipInfo && "isValid" in req.ipInfo && req.ipInfo.isValid ? req.ipInfo.asnNumber : void 0;
|
|
56
|
-
const
|
|
56
|
+
const sessionRecord = sessionId ? await tasks.db.getSessionRecordBySessionId(sessionId) : void 0;
|
|
57
|
+
const userScope = require_blacklistRequestInspector.getRequestUserScope((0, _prosopo_util.flatten)(req.headers), req.ja4, normalizedIp, user, sessionRecord?.decryptedHeadHash, void 0, countryCode, asn);
|
|
57
58
|
const userAccessPolicy = (await tasks.puzzleCaptchaManager.getPrioritisedAccessPolicies(userAccessRulesStorage, dapp, userScope)).find((p) => !p.deferToVerify);
|
|
58
59
|
const { valid, reason, sessionId: validSessionId } = await tasks.puzzleCaptchaManager.isValidRequest(clientSettings, _prosopo_types.CaptchaType.puzzle, env, sessionId, userAccessPolicy, normalizedIp);
|
|
59
60
|
if (!valid) return next(new _prosopo_common.ProsopoApiError(reason || "API.BAD_REQUEST", {
|
|
@@ -131,7 +131,7 @@ var buildEscalation = async (tasks, result, challenge, handshakeTiming) => {
|
|
|
131
131
|
if (!originSession) return void 0;
|
|
132
132
|
const routed = result.routingOutput;
|
|
133
133
|
const selectionReason = routed.reason ?? originSession.reason;
|
|
134
|
-
const newSession = await tasks.frictionlessManager.createSession(originSession.token, originSession.score, originSession.threshold, originSession.scoreComponents, originSession.ipAddress, routed.captchaType, originSession.siteKey ?? powRecord.dappAccount, routed.captchaType === _prosopo_types.CaptchaType.image ? routed.solvedImagesCount ?? originSession.solvedImagesCount : void 0, void 0, originSession.userSitekeyIpHash, originSession.webView, originSession.iFrame, originSession.decryptedHeadHash, selectionReason, void 0, void 0, originSession.ipInfo, originSession.headers, originSession.mode, originSession.simdReadings, originSession.entropyMathRandomFingerprint, originSession.entropyCryptoFingerprint, originSession.entropyWallClockOffsetMs, originSession.entropyMathRandomFirst, originSession.currentUrl, handshakeTiming?.tcpToChelloUs, handshakeTiming?.chelloToHandshakeUs, true, originSession.iframeUrl, originSession.isProtect);
|
|
134
|
+
const newSession = await tasks.frictionlessManager.createSession(originSession.token, originSession.score, originSession.threshold, originSession.scoreComponents, originSession.ipAddress, routed.captchaType, originSession.siteKey ?? powRecord.dappAccount, routed.captchaType === _prosopo_types.CaptchaType.image ? routed.solvedImagesCount ?? originSession.solvedImagesCount : void 0, void 0, originSession.userSitekeyIpHash, originSession.webView, originSession.iFrame, originSession.decryptedHeadHash, selectionReason, void 0, void 0, originSession.ipInfo, originSession.headers, originSession.mode, originSession.simdReadings, originSession.entropyMathRandomFingerprint, originSession.entropyCryptoFingerprint, originSession.entropyWallClockOffsetMs, originSession.entropyMathRandomFirst, originSession.bundleId, originSession.currentUrl, handshakeTiming?.tcpToChelloUs, handshakeTiming?.chelloToHandshakeUs, true, originSession.iframeUrl, originSession.isProtect);
|
|
135
135
|
if (tasks.writeQueue) await tasks.writeQueue.cacheSessionEscalation(powRecord.sessionId, newSession.sessionId);
|
|
136
136
|
return {
|
|
137
137
|
captchaType: routed.captchaType,
|
package/dist/cjs/api/captcha.cjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const require_runtime = require("../_virtual/_rolldown/runtime.cjs");
|
|
2
|
+
const require_assignDetectorBundle = require("./captcha/assignDetectorBundle.cjs");
|
|
2
3
|
const require_checkSpamEmail = require("./captcha/checkSpamEmail.cjs");
|
|
3
4
|
const require_handler = require("./captcha/getFrictionlessCaptchaChallenge/handler.cjs");
|
|
4
5
|
const require_getImageCaptchaChallenge = require("./captcha/getImageCaptchaChallenge.cjs");
|
|
@@ -65,6 +66,11 @@ function prosopoRouter(env) {
|
|
|
65
66
|
*/
|
|
66
67
|
router.post(_prosopo_types.ClientApiPaths.GetFrictionlessCaptchaChallenge, asyncHandler(require_handler.default(env, userAccessRulesStorage)));
|
|
67
68
|
/**
|
|
69
|
+
* Assigns a precomputed detector bundle for this session (or signals the
|
|
70
|
+
* bundled fallback when no pool is loaded).
|
|
71
|
+
*/
|
|
72
|
+
router.post(_prosopo_types.ClientApiPaths.AssignDetectorBundle, (req, res, next) => require_assignDetectorBundle.default(env)(req, res, next));
|
|
73
|
+
/**
|
|
68
74
|
* Supplies a Puzzle challenge to a Dapp User
|
|
69
75
|
*/
|
|
70
76
|
router.post(_prosopo_types.ClientApiPaths.GetPuzzleCaptchaChallenge, asyncHandler(require_getPuzzleCaptchaChallenge.default(env, userAccessRulesStorage)));
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const require_runtime = require("../_virtual/_rolldown/runtime.cjs");
|
|
2
2
|
const require_metrics = require("./metrics.cjs");
|
|
3
3
|
const require_blacklistRequestInspector = require("./blacklistRequestInspector.cjs");
|
|
4
|
+
const require_bundlePool = require("../tasks/detection/bundlePool.cjs");
|
|
4
5
|
const require_block = require("./block.cjs");
|
|
5
6
|
const require_captcha = require("./captcha.cjs");
|
|
6
7
|
const require_verify = require("./verify.cjs");
|
|
@@ -15,15 +16,15 @@ const require_ipInfoMiddleware = require("./ipInfoMiddleware.cjs");
|
|
|
15
16
|
const require_robotsMiddleware = require("./robotsMiddleware.cjs");
|
|
16
17
|
let _prosopo_logger = require("@prosopo/logger");
|
|
17
18
|
let _prosopo_types = require("@prosopo/types");
|
|
18
|
-
let node_https = require("node:https");
|
|
19
|
-
node_https = require_runtime.__toESM(node_https, 1);
|
|
20
19
|
let node_fs = require("node:fs");
|
|
21
20
|
node_fs = require_runtime.__toESM(node_fs, 1);
|
|
21
|
+
let node_path = require("node:path");
|
|
22
|
+
node_path = require_runtime.__toESM(node_path, 1);
|
|
23
|
+
let node_https = require("node:https");
|
|
24
|
+
node_https = require_runtime.__toESM(node_https, 1);
|
|
22
25
|
let _prosopo_api_express_router = require("@prosopo/api-express-router");
|
|
23
26
|
let express = require("express");
|
|
24
27
|
express = require_runtime.__toESM(express, 1);
|
|
25
|
-
let node_path = require("node:path");
|
|
26
|
-
node_path = require_runtime.__toESM(node_path, 1);
|
|
27
28
|
let node_url = require("node:url");
|
|
28
29
|
let _prosopo_locale = require("@prosopo/locale");
|
|
29
30
|
let _prosopo_user_access_policy_api = require("@prosopo/user-access-policy/api");
|
|
@@ -32,6 +33,12 @@ cors = require_runtime.__toESM(cors, 1);
|
|
|
32
33
|
let express_rate_limit = require("express-rate-limit");
|
|
33
34
|
express_rate_limit = require_runtime.__toESM(express_rate_limit, 1);
|
|
34
35
|
//#region src/api/startProviderApi.ts
|
|
36
|
+
/**
|
|
37
|
+
* Body-size ceiling for the detector-pool push. ~830 KB/bundle × 100 bundles
|
|
38
|
+
* ≈ 86 MB encoded; 128 MB leaves headroom without approaching the 512 MiB V8
|
|
39
|
+
* string limit that ultimately bounds a single-body push at ~620 bundles.
|
|
40
|
+
*/
|
|
41
|
+
var DETECTOR_POOL_BODY_LIMIT = "128mb";
|
|
35
42
|
var __dirname$1 = node_path.default.dirname((0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href));
|
|
36
43
|
var certPath = node_path.default.resolve(__dirname$1, "../../../../certs");
|
|
37
44
|
var keyPath = node_path.default.join(certPath, "server.key");
|
|
@@ -48,7 +55,7 @@ var isTlsAvailable = () => {
|
|
|
48
55
|
* @returns Array of ClientApiPaths excluding verify and spam routes
|
|
49
56
|
*/
|
|
50
57
|
var getClientApiPathsExpectingProsopoHeaders = () => {
|
|
51
|
-
return Object.values(_prosopo_types.ClientApiPaths).filter((path) => path.indexOf("verify") === -1 && path.indexOf("spam") === -1);
|
|
58
|
+
return Object.values(_prosopo_types.ClientApiPaths).filter((path) => path.indexOf("verify") === -1 && path.indexOf("spam") === -1 && path.indexOf("detector/assign") === -1);
|
|
52
59
|
};
|
|
53
60
|
/**
|
|
54
61
|
* Extract authenticated user address from JWT for rate limiting
|
|
@@ -95,6 +102,17 @@ var getUserFromJWT = (req) => {
|
|
|
95
102
|
*/
|
|
96
103
|
async function startProviderApi(env, admin = false, port) {
|
|
97
104
|
env.logger.info(() => ({ msg: "Starting Prosopo API" }));
|
|
105
|
+
const detectorPoolDir = process.env.PROSOPO_DETECTOR_POOL_DIR ?? "/app/data/detector-pool";
|
|
106
|
+
require_bundlePool.initDetectorBundlePool(detectorPoolDir, {
|
|
107
|
+
info: (msg, data) => env.logger.info(() => ({
|
|
108
|
+
msg,
|
|
109
|
+
data
|
|
110
|
+
})),
|
|
111
|
+
warn: (msg, data) => env.logger.warn(() => ({
|
|
112
|
+
msg,
|
|
113
|
+
data
|
|
114
|
+
}))
|
|
115
|
+
}, process.env.PROSOPO_DETECTOR_POOL_RELEASE);
|
|
98
116
|
const apiApp = (0, express.default)();
|
|
99
117
|
const apiPort = port || env.config.server?.port;
|
|
100
118
|
const apiEndpointAdapter = (0, _prosopo_api_express_router.createApiExpressDefaultEndpointAdapter)((0, _prosopo_logger.parseLogLevel)(env.config.logLevel));
|
|
@@ -129,6 +147,7 @@ async function startProviderApi(env, admin = false, port) {
|
|
|
129
147
|
],
|
|
130
148
|
maxAge: 86400
|
|
131
149
|
}));
|
|
150
|
+
apiApp.use(_prosopo_types.AdminApiPaths.ReplaceDetectorPool, express.default.json({ limit: DETECTOR_POOL_BODY_LIMIT }));
|
|
132
151
|
apiApp.use(express.default.json({ limit: "1mb" }));
|
|
133
152
|
apiApp.use(require_public.publicRouter(env));
|
|
134
153
|
apiApp.use(require_metrics.metricsMiddleware());
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const require_compositeIpAddress = require("../compositeIpAddress.cjs");
|
|
2
2
|
const require_blacklistRequestInspector = require("../api/blacklistRequestInspector.cjs");
|
|
3
|
+
const require_bundlePool = require("./detection/bundlePool.cjs");
|
|
3
4
|
const require_checkTrafficFilter = require("./spam/checkTrafficFilter.cjs");
|
|
4
5
|
const require_enrichDnsEvent = require("./dnsEvent/enrichDnsEvent.cjs");
|
|
5
6
|
const require_checkSpamEmail = require("./spam/checkSpamEmail.cjs");
|
|
@@ -59,19 +60,24 @@ var CaptchaManager = class CaptchaManager {
|
|
|
59
60
|
this.scheduleMongoSessionUpdate(sessionId, updates, streamToCentral);
|
|
60
61
|
}
|
|
61
62
|
/**
|
|
62
|
-
* Decrypt with the
|
|
63
|
-
* `timestamp` field. Returns `undefined` when no
|
|
63
|
+
* Decrypt with the session's detector pool bundle and strip the throwaway
|
|
64
|
+
* `timestamp` field. Returns `undefined` when no bundle is resolved or
|
|
65
|
+
* decryption fails.
|
|
64
66
|
*/
|
|
65
|
-
async decryptSimdReadingsForAttach(simdReadingsCiphertext) {
|
|
66
|
-
const
|
|
67
|
-
const decrypted = await this.decryptSimdReadings(simdReadingsCiphertext, decryptKeys);
|
|
67
|
+
async decryptSimdReadingsForAttach(simdReadingsCiphertext, bundle) {
|
|
68
|
+
const decrypted = await this.decryptSimdReadings(simdReadingsCiphertext, bundle);
|
|
68
69
|
if (!decrypted) return void 0;
|
|
69
70
|
const { timestamp: _ignored, ...readings } = decrypted;
|
|
70
71
|
return readings;
|
|
71
72
|
}
|
|
72
|
-
/**
|
|
73
|
+
/**
|
|
74
|
+
* Decrypt + first-hop-wins attach. Resolves the session's detector pool
|
|
75
|
+
* bundle (promoted onto the session record at frictionless time) to decrypt.
|
|
76
|
+
* No-op on decrypt failure / no bundle.
|
|
77
|
+
*/
|
|
73
78
|
async decryptAndAttachSimdReadingsIfAbsent(sessionId, simdReadingsCiphertext, stage) {
|
|
74
|
-
const
|
|
79
|
+
const bundle = await this.resolveBundleBySessionId(sessionId);
|
|
80
|
+
const readings = await this.decryptSimdReadingsForAttach(simdReadingsCiphertext, bundle);
|
|
75
81
|
if (!readings) return;
|
|
76
82
|
await this.recordSessionSimdReadingsIfAbsentWithCache(sessionId, readings, stage);
|
|
77
83
|
}
|
|
@@ -271,62 +277,81 @@ var CaptchaManager = class CaptchaManager {
|
|
|
271
277
|
async getPrioritisedAccessPolicies(userAccessRulesStorage, clientId, userScope, options) {
|
|
272
278
|
return require_blacklistRequestInspector.getPrioritisedAccessRule(userAccessRulesStorage, userScope, clientId, options);
|
|
273
279
|
}
|
|
274
|
-
|
|
275
|
-
|
|
280
|
+
/**
|
|
281
|
+
* Resolve a detector pool bundle's decryption material from a `bundleId`
|
|
282
|
+
* (in-memory pool lookup). Returns undefined when the id is absent or the
|
|
283
|
+
* bundle is no longer in the pool.
|
|
284
|
+
*/
|
|
285
|
+
resolveBundleById(bundleId) {
|
|
286
|
+
const bundle = bundleId ? require_bundlePool.getDetectorBundlePool()?.get(bundleId) : void 0;
|
|
287
|
+
return bundle ? {
|
|
288
|
+
key: bundle.privateKey,
|
|
289
|
+
innerConfig: bundle.innerConfig
|
|
290
|
+
} : void 0;
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Resolve the detector pool bundle for a session via its short-lived
|
|
294
|
+
* `detectorSessionId → bundleId` Redis binding (used at the frictionless hop,
|
|
295
|
+
* before the binding is promoted onto the durable session record). Returns
|
|
296
|
+
* the bundleId too so the caller can promote it onto the session.
|
|
297
|
+
*/
|
|
298
|
+
async resolveBundleByDetectorSession(detectorSessionId) {
|
|
299
|
+
if (!detectorSessionId || !this.writeQueue) return void 0;
|
|
300
|
+
const bundleId = await this.writeQueue.getDetectorBundle(detectorSessionId);
|
|
301
|
+
const decrypt = this.resolveBundleById(bundleId);
|
|
302
|
+
return bundleId && decrypt ? {
|
|
303
|
+
...decrypt,
|
|
304
|
+
bundleId
|
|
305
|
+
} : void 0;
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Resolve the detector pool bundle for a session via the `bundleId` promoted
|
|
309
|
+
* onto its durable session record (used at later hops — SIMD attach,
|
|
310
|
+
* PoW/puzzle/image solution submit — after the Redis binding has expired).
|
|
311
|
+
* Cache-first (Redis), Mongo fallback.
|
|
312
|
+
*/
|
|
313
|
+
async resolveBundleBySessionId(sessionId) {
|
|
314
|
+
if (!sessionId) return void 0;
|
|
315
|
+
const cached = this.writeQueue ? await this.writeQueue.getCachedSession(sessionId) : void 0;
|
|
316
|
+
const bundleId = (typeof cached?.bundleId === "string" ? cached.bundleId : void 0) ?? (await this.db.getSessionRecordBySessionId(sessionId))?.bundleId;
|
|
317
|
+
return this.resolveBundleById(bundleId);
|
|
276
318
|
}
|
|
277
319
|
/**
|
|
278
320
|
* Decrypt the catcher's WASM SIMD CPU fingerprint readings via the
|
|
279
321
|
* obfuscated `decodeSimd.js` bundle (source lives in the private
|
|
280
|
-
* @prosopo/catcher repo).
|
|
281
|
-
*
|
|
282
|
-
*
|
|
283
|
-
* the field rather than fail the
|
|
322
|
+
* @prosopo/catcher repo). The detector lives only in provider-served pool
|
|
323
|
+
* bundles, so decryption uses that session's single bundle (RSA key + inner
|
|
324
|
+
* cipher) — there is no key pool. Returns null when no bundle is resolved or
|
|
325
|
+
* decryption fails, so the caller can drop the field rather than fail the
|
|
326
|
+
* whole request.
|
|
284
327
|
*/
|
|
285
|
-
async decryptSimdReadings(encryptedData,
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
if (validKeys.length === 0) {
|
|
289
|
-
this.logger?.error(() => ({ msg: "No decryption keys provided for SIMD readings" }));
|
|
328
|
+
async decryptSimdReadings(encryptedData, bundle) {
|
|
329
|
+
if (!bundle) {
|
|
330
|
+
this.logger?.warn(() => ({ msg: "No detector bundle resolved for SIMD readings — dropping field" }));
|
|
290
331
|
return null;
|
|
291
332
|
}
|
|
292
|
-
|
|
293
|
-
|
|
333
|
+
const decryptSimdReadings = (await Promise.resolve().then(() => require("./detection/decodeSimd.cjs"))).default;
|
|
334
|
+
try {
|
|
335
|
+
return await decryptSimdReadings(encryptedData, bundle.key, bundle.innerConfig);
|
|
294
336
|
} catch (err) {
|
|
295
|
-
this.logger?.
|
|
296
|
-
msg: "Failed to decrypt SIMD readings with
|
|
297
|
-
data: {
|
|
298
|
-
keyIndex: keyIndex + 1,
|
|
299
|
-
totalKeys: validKeys.length,
|
|
300
|
-
err
|
|
301
|
-
}
|
|
337
|
+
this.logger?.warn(() => ({
|
|
338
|
+
msg: "Failed to decrypt SIMD readings with the session's bundle",
|
|
339
|
+
data: { err }
|
|
302
340
|
}));
|
|
341
|
+
return null;
|
|
303
342
|
}
|
|
304
|
-
this.logger?.warn(() => ({
|
|
305
|
-
msg: "Failed to decrypt SIMD readings with all available keys",
|
|
306
|
-
data: { totalKeysAttempted: validKeys.length }
|
|
307
|
-
}));
|
|
308
|
-
return null;
|
|
309
343
|
}
|
|
310
|
-
async decryptBehavioralData(encryptedData,
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
if (validKeys.length === 0) {
|
|
314
|
-
this.logger?.error(() => ({ msg: "No decryption keys provided for behavioral data" }));
|
|
344
|
+
async decryptBehavioralData(encryptedData, bundle) {
|
|
345
|
+
if (!bundle) {
|
|
346
|
+
this.logger?.warn(() => ({ msg: "No detector bundle resolved for behavioral data — dropping field" }));
|
|
315
347
|
return null;
|
|
316
348
|
}
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
data: {
|
|
321
|
-
keyIndex: keyIndex + 1,
|
|
322
|
-
totalKeys: validKeys.length
|
|
323
|
-
}
|
|
324
|
-
}));
|
|
325
|
-
const result = await decryptBehavioralData(encryptedData, key);
|
|
349
|
+
const decryptBehavioralData = (await Promise.resolve().then(() => require("./detection/decodeBehavior.cjs"))).default;
|
|
350
|
+
try {
|
|
351
|
+
const result = await decryptBehavioralData(encryptedData, bundle.key, bundle.innerConfig);
|
|
326
352
|
this.logger?.info(() => ({
|
|
327
353
|
msg: "Behavioral data decrypted successfully",
|
|
328
354
|
data: {
|
|
329
|
-
keyIndex: keyIndex + 1,
|
|
330
355
|
c1Length: result.collector1?.length || 0,
|
|
331
356
|
c2Length: result.collector2?.length || 0,
|
|
332
357
|
c3Length: result.collector3?.length || 0,
|
|
@@ -335,20 +360,12 @@ var CaptchaManager = class CaptchaManager {
|
|
|
335
360
|
}));
|
|
336
361
|
return result;
|
|
337
362
|
} catch (error) {
|
|
338
|
-
this.logger?.
|
|
339
|
-
msg: "Failed to decrypt with
|
|
340
|
-
data: {
|
|
341
|
-
keyIndex: keyIndex + 1,
|
|
342
|
-
totalKeys: validKeys.length,
|
|
343
|
-
err: error
|
|
344
|
-
}
|
|
363
|
+
this.logger?.warn(() => ({
|
|
364
|
+
msg: "Failed to decrypt behavioral data with the session's bundle",
|
|
365
|
+
data: { err: error }
|
|
345
366
|
}));
|
|
367
|
+
return null;
|
|
346
368
|
}
|
|
347
|
-
this.logger?.error(() => ({
|
|
348
|
-
msg: "Failed to decrypt behavioral data with all available keys",
|
|
349
|
-
data: { totalKeysAttempted: validKeys.length }
|
|
350
|
-
}));
|
|
351
|
-
return null;
|
|
352
369
|
}
|
|
353
370
|
/**
|
|
354
371
|
* Checks if a user should be hard blocked based on access policies
|
|
@@ -2,23 +2,10 @@ const require_validateAddress = require("../../api/validateAddress.cjs");
|
|
|
2
2
|
let _prosopo_common = require("@prosopo/common");
|
|
3
3
|
let _prosopo_database = require("@prosopo/database");
|
|
4
4
|
let _prosopo_types = require("@prosopo/types");
|
|
5
|
-
|
|
5
|
+
require("node:crypto");
|
|
6
6
|
let _prosopo_util = require("@prosopo/util");
|
|
7
7
|
//#region src/tasks/client/clientTasks.ts
|
|
8
8
|
var SAMPLE_SIZE = 75;
|
|
9
|
-
var isValidPrivateKey = (privateKeyString) => {
|
|
10
|
-
const privateKey = Buffer.from(privateKeyString, "base64").toString("ascii");
|
|
11
|
-
try {
|
|
12
|
-
(0, node_crypto.createPrivateKey)({
|
|
13
|
-
key: privateKey,
|
|
14
|
-
format: "pem",
|
|
15
|
-
type: "pkcs8"
|
|
16
|
-
});
|
|
17
|
-
return true;
|
|
18
|
-
} catch (error) {
|
|
19
|
-
return false;
|
|
20
|
-
}
|
|
21
|
-
};
|
|
22
9
|
var ClientTaskManager = class {
|
|
23
10
|
constructor(config, logger, db) {
|
|
24
11
|
this.config = config;
|
|
@@ -196,21 +183,6 @@ var ClientTaskManager = class {
|
|
|
196
183
|
}
|
|
197
184
|
await this.providerDB.removeClientRecords(accounts);
|
|
198
185
|
}
|
|
199
|
-
async updateDetectorKey(detectorKey) {
|
|
200
|
-
if (!isValidPrivateKey(detectorKey)) throw new _prosopo_common.ProsopoApiError("INVALID_DETECTOR_KEY", {
|
|
201
|
-
context: { detectorKey },
|
|
202
|
-
logger: this.logger
|
|
203
|
-
});
|
|
204
|
-
await this.providerDB.storeDetectorKey(detectorKey);
|
|
205
|
-
return await this.providerDB.getDetectorKeys();
|
|
206
|
-
}
|
|
207
|
-
async removeDetectorKey(detectorKey, expirationInSeconds) {
|
|
208
|
-
if (!isValidPrivateKey(detectorKey)) throw new _prosopo_common.ProsopoApiError("INVALID_DETECTOR_KEY", {
|
|
209
|
-
context: { detectorKey },
|
|
210
|
-
logger: this.logger
|
|
211
|
-
});
|
|
212
|
-
await this.providerDB.removeDetectorKey(detectorKey, expirationInSeconds);
|
|
213
|
-
}
|
|
214
186
|
async updateDecisionMachine(scope, runtime, source, dappAccount, language, name, version, captchaType, kind) {
|
|
215
187
|
if (scope === _prosopo_types.DecisionMachineScope.Dapp && !dappAccount) throw new _prosopo_common.ProsopoApiError("API.BAD_REQUEST", {
|
|
216
188
|
context: {
|