@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.
Files changed (190) hide show
  1. package/.turbo/turbo-build$colon$cjs.log +103 -102
  2. package/.turbo/turbo-build$colon$tsc.log +24 -24
  3. package/.turbo/turbo-build.log +103 -102
  4. package/CHANGELOG.md +108 -0
  5. package/dist/api/admin/apiAdminRoutesProvider.d.ts.map +1 -1
  6. package/dist/api/admin/apiAdminRoutesProvider.js +3 -5
  7. package/dist/api/admin/apiAdminRoutesProvider.js.map +1 -1
  8. package/dist/api/admin/apiReplaceDetectorPoolEndpoint.d.ts +11 -0
  9. package/dist/api/admin/apiReplaceDetectorPoolEndpoint.d.ts.map +1 -0
  10. package/dist/api/admin/apiReplaceDetectorPoolEndpoint.js +56 -0
  11. package/dist/api/admin/apiReplaceDetectorPoolEndpoint.js.map +1 -0
  12. package/dist/api/captcha/assignDetectorBundle.d.ts +6 -0
  13. package/dist/api/captcha/assignDetectorBundle.d.ts.map +1 -0
  14. package/dist/api/captcha/assignDetectorBundle.js +51 -0
  15. package/dist/api/captcha/assignDetectorBundle.js.map +1 -0
  16. package/dist/api/captcha/assignDetectorBundle.test.d.ts +2 -0
  17. package/dist/api/captcha/assignDetectorBundle.test.d.ts.map +1 -0
  18. package/dist/api/captcha/assignDetectorBundle.test.js +71 -0
  19. package/dist/api/captcha/assignDetectorBundle.test.js.map +1 -0
  20. package/dist/api/captcha/getFrictionlessCaptchaChallenge/constants.d.ts +1 -0
  21. package/dist/api/captcha/getFrictionlessCaptchaChallenge/constants.d.ts.map +1 -1
  22. package/dist/api/captcha/getFrictionlessCaptchaChallenge/constants.js.map +1 -1
  23. package/dist/api/captcha/getFrictionlessCaptchaChallenge/decisionMachine.d.ts.map +1 -1
  24. package/dist/api/captcha/getFrictionlessCaptchaChallenge/decisionMachine.js +21 -2
  25. package/dist/api/captcha/getFrictionlessCaptchaChallenge/decisionMachine.js.map +1 -1
  26. package/dist/api/captcha/getFrictionlessCaptchaChallenge/decryptSimdReadings.d.ts +1 -1
  27. package/dist/api/captcha/getFrictionlessCaptchaChallenge/decryptSimdReadings.d.ts.map +1 -1
  28. package/dist/api/captcha/getFrictionlessCaptchaChallenge/decryptSimdReadings.js +3 -3
  29. package/dist/api/captcha/getFrictionlessCaptchaChallenge/decryptSimdReadings.js.map +1 -1
  30. package/dist/api/captcha/getFrictionlessCaptchaChallenge/handler.d.ts.map +1 -1
  31. package/dist/api/captcha/getFrictionlessCaptchaChallenge/handler.js +13 -7
  32. package/dist/api/captcha/getFrictionlessCaptchaChallenge/handler.js.map +1 -1
  33. package/dist/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.d.ts +3 -0
  34. package/dist/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.d.ts.map +1 -1
  35. package/dist/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.js +52 -18
  36. package/dist/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.js.map +1 -1
  37. package/dist/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.powFallback.test.d.ts +2 -0
  38. package/dist/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.powFallback.test.d.ts.map +1 -0
  39. package/dist/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.powFallback.test.js +86 -0
  40. package/dist/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.powFallback.test.js.map +1 -0
  41. package/dist/api/captcha/getImageCaptchaChallenge.d.ts.map +1 -1
  42. package/dist/api/captcha/getImageCaptchaChallenge.js +2 -1
  43. package/dist/api/captcha/getImageCaptchaChallenge.js.map +1 -1
  44. package/dist/api/captcha/getPoWCaptchaChallenge.d.ts.map +1 -1
  45. package/dist/api/captcha/getPoWCaptchaChallenge.js +2 -1
  46. package/dist/api/captcha/getPoWCaptchaChallenge.js.map +1 -1
  47. package/dist/api/captcha/getPuzzleCaptchaChallenge.d.ts.map +1 -1
  48. package/dist/api/captcha/getPuzzleCaptchaChallenge.js +2 -1
  49. package/dist/api/captcha/getPuzzleCaptchaChallenge.js.map +1 -1
  50. package/dist/api/captcha/submitPoWCaptchaSolution.d.ts.map +1 -1
  51. package/dist/api/captcha/submitPoWCaptchaSolution.js +1 -1
  52. package/dist/api/captcha/submitPoWCaptchaSolution.js.map +1 -1
  53. package/dist/api/captcha.d.ts.map +1 -1
  54. package/dist/api/captcha.js +6 -0
  55. package/dist/api/captcha.js.map +1 -1
  56. package/dist/api/startProviderApi.d.ts.map +1 -1
  57. package/dist/api/startProviderApi.js +21 -3
  58. package/dist/api/startProviderApi.js.map +1 -1
  59. package/dist/cjs/api/admin/apiAdminRoutesProvider.cjs +3 -5
  60. package/dist/cjs/api/admin/apiReplaceDetectorPoolEndpoint.cjs +56 -0
  61. package/dist/cjs/api/captcha/assignDetectorBundle.cjs +51 -0
  62. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/decisionMachine.cjs +21 -2
  63. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/decryptSimdReadings.cjs +3 -3
  64. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/handler.cjs +12 -6
  65. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.cjs +52 -17
  66. package/dist/cjs/api/captcha/getImageCaptchaChallenge.cjs +2 -1
  67. package/dist/cjs/api/captcha/getPoWCaptchaChallenge.cjs +2 -1
  68. package/dist/cjs/api/captcha/getPuzzleCaptchaChallenge.cjs +2 -1
  69. package/dist/cjs/api/captcha/submitPoWCaptchaSolution.cjs +1 -1
  70. package/dist/cjs/api/captcha.cjs +6 -0
  71. package/dist/cjs/api/startProviderApi.cjs +24 -5
  72. package/dist/cjs/tasks/captchaManager.cjs +76 -59
  73. package/dist/cjs/tasks/client/clientTasks.cjs +1 -29
  74. package/dist/cjs/tasks/detection/bundlePool.cjs +220 -0
  75. package/dist/cjs/tasks/detection/decodeBehavior.cjs +644 -362
  76. package/dist/cjs/tasks/detection/decodeBehavior.js +1 -1
  77. package/dist/cjs/tasks/detection/decodePayload.cjs +956 -617
  78. package/dist/cjs/tasks/detection/decodePayload.js +1 -1
  79. package/dist/cjs/tasks/detection/decodeSimd.cjs +723 -411
  80. package/dist/cjs/tasks/detection/decodeSimd.js +1 -1
  81. package/dist/cjs/tasks/detection/getBotScore.cjs +2 -2
  82. package/dist/cjs/tasks/frictionless/frictionlessTasks.cjs +35 -12
  83. package/dist/cjs/tasks/frictionless/frictionlessTasksUtils.cjs +1 -2
  84. package/dist/cjs/tasks/imgCaptcha/imgCaptchaTasks.cjs +6 -6
  85. package/dist/cjs/tasks/powCaptcha/powTasks.cjs +2 -2
  86. package/dist/cjs/tasks/puzzleCaptcha/puzzleTasks.cjs +2 -2
  87. package/dist/tasks/captchaManager.d.ts +12 -4
  88. package/dist/tasks/captchaManager.d.ts.map +1 -1
  89. package/dist/tasks/captchaManager.js +76 -59
  90. package/dist/tasks/captchaManager.js.map +1 -1
  91. package/dist/tasks/client/clientTasks.d.ts +0 -2
  92. package/dist/tasks/client/clientTasks.d.ts.map +1 -1
  93. package/dist/tasks/client/clientTasks.js +1 -29
  94. package/dist/tasks/client/clientTasks.js.map +1 -1
  95. package/dist/tasks/detection/bundlePool.d.ts +32 -0
  96. package/dist/tasks/detection/bundlePool.d.ts.map +1 -0
  97. package/dist/tasks/detection/bundlePool.js +215 -0
  98. package/dist/tasks/detection/bundlePool.js.map +1 -0
  99. package/dist/tasks/detection/bundlePool.test.d.ts +2 -0
  100. package/dist/tasks/detection/bundlePool.test.d.ts.map +1 -0
  101. package/dist/tasks/detection/bundlePool.test.js +178 -0
  102. package/dist/tasks/detection/bundlePool.test.js.map +1 -0
  103. package/dist/tasks/detection/decodeBehavior.d.ts +2 -2
  104. package/dist/tasks/detection/decodeBehavior.d.ts.map +1 -1
  105. package/dist/tasks/detection/decodeBehavior.js +1 -1
  106. package/dist/tasks/detection/decodeBehavior.js.map +1 -1
  107. package/dist/tasks/detection/decodePayload.d.ts +2 -2
  108. package/dist/tasks/detection/decodePayload.d.ts.map +1 -1
  109. package/dist/tasks/detection/decodePayload.js +1 -1
  110. package/dist/tasks/detection/decodePayload.js.map +1 -1
  111. package/dist/tasks/detection/decodeSimd.d.ts +2 -2
  112. package/dist/tasks/detection/decodeSimd.d.ts.map +1 -1
  113. package/dist/tasks/detection/decodeSimd.js +1 -1
  114. package/dist/tasks/detection/decodeSimd.js.map +1 -1
  115. package/dist/tasks/detection/getBotScore.d.ts +1 -1
  116. package/dist/tasks/detection/getBotScore.d.ts.map +1 -1
  117. package/dist/tasks/detection/getBotScore.js +3 -3
  118. package/dist/tasks/detection/getBotScore.js.map +1 -1
  119. package/dist/tasks/frictionless/frictionlessTasks.d.ts +10 -2
  120. package/dist/tasks/frictionless/frictionlessTasks.d.ts.map +1 -1
  121. package/dist/tasks/frictionless/frictionlessTasks.js +35 -12
  122. package/dist/tasks/frictionless/frictionlessTasks.js.map +1 -1
  123. package/dist/tasks/frictionless/frictionlessTasksUtils.d.ts +1 -1
  124. package/dist/tasks/frictionless/frictionlessTasksUtils.d.ts.map +1 -1
  125. package/dist/tasks/frictionless/frictionlessTasksUtils.js +1 -2
  126. package/dist/tasks/frictionless/frictionlessTasksUtils.js.map +1 -1
  127. package/dist/tasks/imgCaptcha/imgCaptchaTasks.d.ts.map +1 -1
  128. package/dist/tasks/imgCaptcha/imgCaptchaTasks.js +6 -6
  129. package/dist/tasks/imgCaptcha/imgCaptchaTasks.js.map +1 -1
  130. package/dist/tasks/powCaptcha/powTasks.d.ts.map +1 -1
  131. package/dist/tasks/powCaptcha/powTasks.js +2 -2
  132. package/dist/tasks/powCaptcha/powTasks.js.map +1 -1
  133. package/dist/tasks/puzzleCaptcha/puzzleTasks.d.ts.map +1 -1
  134. package/dist/tasks/puzzleCaptcha/puzzleTasks.js +2 -2
  135. package/dist/tasks/puzzleCaptcha/puzzleTasks.js.map +1 -1
  136. package/dist/tests/integration/maintenanceModeAdmin.integration.test.js +0 -28
  137. package/dist/tests/integration/maintenanceModeAdmin.integration.test.js.map +1 -1
  138. package/dist/tests/unit/api/admin/apiRegisterSiteKeyEndpoint.unit.test.js +1 -0
  139. package/dist/tests/unit/api/admin/apiRegisterSiteKeyEndpoint.unit.test.js.map +1 -1
  140. package/dist/tests/unit/api/adminRoutes.unit.test.js +0 -46
  141. package/dist/tests/unit/api/adminRoutes.unit.test.js.map +1 -1
  142. package/dist/tests/unit/api/captcha/getFrictionlessCaptchaChallenge/decisionMachine.unit.test.js +51 -0
  143. package/dist/tests/unit/api/captcha/getFrictionlessCaptchaChallenge/decisionMachine.unit.test.js.map +1 -1
  144. package/dist/tests/unit/api/captcha/getFrictionlessCaptchaChallenge/decryptSimdReadings.unit.test.js +12 -12
  145. package/dist/tests/unit/api/captcha/getFrictionlessCaptchaChallenge/decryptSimdReadings.unit.test.js.map +1 -1
  146. package/dist/tests/unit/api/getFrictionlessCaptchaChallenge.unit.test.js +15 -1
  147. package/dist/tests/unit/api/getFrictionlessCaptchaChallenge.unit.test.js.map +1 -1
  148. package/dist/tests/unit/tasks/captchaManager.unit.test.js +14 -30
  149. package/dist/tests/unit/tasks/captchaManager.unit.test.js.map +1 -1
  150. package/dist/tests/unit/tasks/detection/getBotScore.unit.test.js +3 -3
  151. package/dist/tests/unit/tasks/detection/getBotScore.unit.test.js.map +1 -1
  152. package/dist/tests/unit/tasks/frictionless/decryptPayload.unit.test.js +25 -7
  153. package/dist/tests/unit/tasks/frictionless/decryptPayload.unit.test.js.map +1 -1
  154. package/dist/tests/unit/tasks/frictionless/frictionlessTasks.unit.test.js +0 -1
  155. package/dist/tests/unit/tasks/frictionless/frictionlessTasks.unit.test.js.map +1 -1
  156. package/dist/tests/unit/tasks/frictionless/frictionlessTasksUtils.unit.test.js +6 -14
  157. package/dist/tests/unit/tasks/frictionless/frictionlessTasksUtils.unit.test.js.map +1 -1
  158. package/dist/tests/unit/tasks/puzzleCaptcha/puzzleTasks.unit.test.js +0 -1
  159. package/dist/tests/unit/tasks/puzzleCaptcha/puzzleTasks.unit.test.js.map +1 -1
  160. package/dist/tests/unit/tasks/writeQueueIntegration.unit.test.js +0 -2
  161. package/dist/tests/unit/tasks/writeQueueIntegration.unit.test.js.map +1 -1
  162. package/fixtures/detector-pool/bundle-0.js +15 -0
  163. package/fixtures/detector-pool/bundle-0.json +1 -0
  164. package/package.json +14 -14
  165. package/dist/api/admin/apiRemoveDetectorKeyEndpoint.d.ts +0 -23
  166. package/dist/api/admin/apiRemoveDetectorKeyEndpoint.d.ts.map +0 -1
  167. package/dist/api/admin/apiRemoveDetectorKeyEndpoint.js +0 -32
  168. package/dist/api/admin/apiRemoveDetectorKeyEndpoint.js.map +0 -1
  169. package/dist/api/admin/apiUpdateDetectorKeyEndpoint.d.ts +0 -14
  170. package/dist/api/admin/apiUpdateDetectorKeyEndpoint.d.ts.map +0 -1
  171. package/dist/api/admin/apiUpdateDetectorKeyEndpoint.js +0 -39
  172. package/dist/api/admin/apiUpdateDetectorKeyEndpoint.js.map +0 -1
  173. package/dist/cjs/api/admin/apiRemoveDetectorKeyEndpoint.cjs +0 -32
  174. package/dist/cjs/api/admin/apiUpdateDetectorKeyEndpoint.cjs +0 -39
  175. package/dist/tasks/detection/getBehavioralData.d.ts +0 -4
  176. package/dist/tasks/detection/getBehavioralData.d.ts.map +0 -1
  177. package/dist/tasks/detection/getBehavioralData.js +0 -51
  178. package/dist/tasks/detection/getBehavioralData.js.map +0 -1
  179. package/dist/tests/unit/api/admin/apiRemoveDetectorKeyEndpoint.unit.test.d.ts +0 -2
  180. package/dist/tests/unit/api/admin/apiRemoveDetectorKeyEndpoint.unit.test.d.ts.map +0 -1
  181. package/dist/tests/unit/api/admin/apiRemoveDetectorKeyEndpoint.unit.test.js +0 -57
  182. package/dist/tests/unit/api/admin/apiRemoveDetectorKeyEndpoint.unit.test.js.map +0 -1
  183. package/dist/tests/unit/api/admin/apiUpdateDetectorKeyEndpoint.unit.test.d.ts +0 -2
  184. package/dist/tests/unit/api/admin/apiUpdateDetectorKeyEndpoint.unit.test.d.ts.map +0 -1
  185. package/dist/tests/unit/api/admin/apiUpdateDetectorKeyEndpoint.unit.test.js +0 -60
  186. package/dist/tests/unit/api/admin/apiUpdateDetectorKeyEndpoint.unit.test.js.map +0 -1
  187. package/dist/tests/unit/tasks/detection/getBehavioralData.unit.test.d.ts +0 -2
  188. package/dist/tests/unit/tasks/detection/getBehavioralData.unit.test.d.ts.map +0 -1
  189. package/dist/tests/unit/tasks/detection/getBehavioralData.unit.test.js +0 -109
  190. 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 shortCircuitResponse = await require_shortCircuit.runConfiguredCaptchaTypeShortCircuit({
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
- }, res);
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 userScope = require_blacklistRequestInspector.getRequestUserScope((0, _prosopo_util.flatten)(req.headers), req.ja4, normalizedIp, user, void 0, void 0, countryCode, asn);
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 userScope = require_blacklistRequestInspector.getRequestUserScope((0, _prosopo_util.flatten)(req.headers), req.ja4, normalizedIp, user, void 0, void 0, countryCode, asn);
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 userScope = require_blacklistRequestInspector.getRequestUserScope((0, _prosopo_util.flatten)(req.headers), req.ja4, normalizedIp, user, void 0, void 0, countryCode, asn);
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,
@@ -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 active detector keys and strip the throwaway
63
- * `timestamp` field. Returns `undefined` when no key decrypts.
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 decryptKeys = [...await this.getDetectorKeys(), process.env.BOT_DECRYPTION_KEY];
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
- /** Decrypt + first-hop-wins attach. No-op on decrypt failure. */
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 readings = await this.decryptSimdReadingsForAttach(simdReadingsCiphertext);
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
- async getDetectorKeys() {
275
- return await this.db.getDetectorKeys();
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). Mirrors `decryptBehavioralData`: tries each
281
- * detector key in turn (loaded by the caller, with the env-var key as
282
- * fallback). Returns null when no key works so the caller can drop
283
- * the field rather than fail the whole request.
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, decryptKeys) {
286
- const decryptSimdReadings = (await Promise.resolve().then(() => require("./detection/decodeSimd.cjs"))).default;
287
- const validKeys = decryptKeys.filter((k) => k);
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
- for (const [keyIndex, key] of validKeys.entries()) try {
293
- return await decryptSimdReadings(encryptedData, key);
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?.debug(() => ({
296
- msg: "Failed to decrypt SIMD readings with key, trying next",
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, decryptKeys) {
311
- const decryptBehavioralData = (await Promise.resolve().then(() => require("./detection/decodeBehavior.cjs"))).default;
312
- const validKeys = decryptKeys.filter((k) => k);
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
- for (const [keyIndex, key] of validKeys.entries()) try {
318
- this.logger?.debug(() => ({
319
- msg: "Attempting to decrypt behavioral data",
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?.debug(() => ({
339
- msg: "Failed to decrypt with key, trying next",
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
- let node_crypto = require("node:crypto");
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: {