@prosopo/provider 4.15.13 → 4.15.15

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 (236) hide show
  1. package/.turbo/turbo-build$colon$cjs.log +106 -106
  2. package/.turbo/turbo-build$colon$tsc.log +24 -24
  3. package/.turbo/turbo-build.log +107 -104
  4. package/CHANGELOG.md +78 -0
  5. package/dist/_virtual/_rolldown/runtime.js +3 -0
  6. package/dist/api/admin/apiAdminRoutesProvider.js +27 -46
  7. package/dist/api/admin/apiClearAllCountersEndpoint.js +62 -57
  8. package/dist/api/admin/apiDnsEventEndpoint.js +79 -92
  9. package/dist/api/admin/apiGetAllDecisionMachinesEndpoint.js +43 -45
  10. package/dist/api/admin/apiGetDecisionMachineEndpoint.js +40 -40
  11. package/dist/api/admin/apiRegisterSiteKeyEndpoint.js +23 -22
  12. package/dist/api/admin/apiRegisterSiteKeysEndpoint.js +26 -30
  13. package/dist/api/admin/apiRemoveAllDecisionMachinesEndpoint.js +35 -37
  14. package/dist/api/admin/apiRemoveDecisionMachineEndpoint.js +40 -40
  15. package/dist/api/admin/apiRemoveDetectorKeyEndpoint.d.ts.map +1 -1
  16. package/dist/api/admin/apiRemoveDetectorKeyEndpoint.js +29 -31
  17. package/dist/api/admin/apiRemoveSiteKeyEndpoint.js +33 -29
  18. package/dist/api/admin/apiRemoveSiteKeysEndpoint.js +32 -31
  19. package/dist/api/admin/apiToggleMaintenanceModeEndpoint.js +43 -35
  20. package/dist/api/admin/apiUpdateDecisionMachineEndpoint.js +43 -63
  21. package/dist/api/admin/apiUpdateDetectorKeyEndpoint.js +36 -35
  22. package/dist/api/admin/createApiAdminRoutesProvider.js +6 -8
  23. package/dist/api/blacklistRequestInspector.js +285 -377
  24. package/dist/api/block.js +17 -30
  25. package/dist/api/captcha/checkSpamEmail.js +88 -98
  26. package/dist/api/captcha/contextAwareValidation.js +21 -15
  27. package/dist/api/captcha/getFrictionlessCaptchaChallenge/accessPolicy.js +126 -140
  28. package/dist/api/captcha/getFrictionlessCaptchaChallenge/constants.js +11 -12
  29. package/dist/api/captcha/getFrictionlessCaptchaChallenge/decisionMachine.js +236 -299
  30. package/dist/api/captcha/getFrictionlessCaptchaChallenge/decryptSimdReadings.js +10 -13
  31. package/dist/api/captcha/getFrictionlessCaptchaChallenge/handler.js +336 -462
  32. package/dist/api/captcha/getFrictionlessCaptchaChallenge/honeypotResponse.js +17 -14
  33. package/dist/api/captcha/getFrictionlessCaptchaChallenge/sessionDedup.js +27 -27
  34. package/dist/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.js +42 -63
  35. package/dist/api/captcha/getFrictionlessCaptchaChallenge.js +2 -4
  36. package/dist/api/captcha/getImageCaptchaChallenge.js +136 -207
  37. package/dist/api/captcha/getPoWCaptchaChallenge.js +128 -198
  38. package/dist/api/captcha/getPuzzleCaptchaChallenge.js +132 -201
  39. package/dist/api/captcha/maintenanceModeResponses.js +38 -47
  40. package/dist/api/captcha/submitImageCaptchaSolution.js +75 -101
  41. package/dist/api/captcha/submitPoWCaptchaSolution.js +137 -207
  42. package/dist/api/captcha/submitPuzzleCaptchaSolution.js +73 -105
  43. package/dist/api/captcha.js +76 -58
  44. package/dist/api/dnsEventUrl.js +20 -22
  45. package/dist/api/domainMiddleware.js +104 -115
  46. package/dist/api/forwardVerify.js +62 -48
  47. package/dist/api/handshakeTimingMiddleware.js +43 -62
  48. package/dist/api/hardBlockVerdictCache.js +114 -117
  49. package/dist/api/headerCheckMiddleware.js +34 -34
  50. package/dist/api/ignoreMiddleware.js +13 -15
  51. package/dist/api/ipInfoMiddleware.js +17 -19
  52. package/dist/api/ja4.js +149 -188
  53. package/dist/api/ja4Middleware.js +39 -54
  54. package/dist/api/metrics.js +245 -257
  55. package/dist/api/public.js +52 -54
  56. package/dist/api/robotsMiddleware.js +10 -10
  57. package/dist/api/startProviderApi.js +205 -232
  58. package/dist/api/testSiteKey.js +16 -16
  59. package/dist/api/validateAddress.js +23 -21
  60. package/dist/api/verify.js +334 -377
  61. package/dist/cjs/_virtual/_rolldown/runtime.cjs +23 -0
  62. package/dist/cjs/api/admin/apiAdminRoutesProvider.cjs +40 -59
  63. package/dist/cjs/api/admin/apiClearAllCountersEndpoint.cjs +63 -58
  64. package/dist/cjs/api/admin/apiDnsEventEndpoint.cjs +82 -93
  65. package/dist/cjs/api/admin/apiGetAllDecisionMachinesEndpoint.cjs +46 -48
  66. package/dist/cjs/api/admin/apiGetDecisionMachineEndpoint.cjs +41 -41
  67. package/dist/cjs/api/admin/apiRegisterSiteKeyEndpoint.cjs +25 -24
  68. package/dist/cjs/api/admin/apiRegisterSiteKeysEndpoint.cjs +28 -32
  69. package/dist/cjs/api/admin/apiRemoveAllDecisionMachinesEndpoint.cjs +38 -40
  70. package/dist/cjs/api/admin/apiRemoveDecisionMachineEndpoint.cjs +41 -41
  71. package/dist/cjs/api/admin/apiRemoveDetectorKeyEndpoint.cjs +31 -33
  72. package/dist/cjs/api/admin/apiRemoveSiteKeyEndpoint.cjs +35 -31
  73. package/dist/cjs/api/admin/apiRemoveSiteKeysEndpoint.cjs +34 -33
  74. package/dist/cjs/api/admin/apiToggleMaintenanceModeEndpoint.cjs +45 -35
  75. package/dist/cjs/api/admin/apiUpdateDecisionMachineEndpoint.cjs +45 -65
  76. package/dist/cjs/api/admin/apiUpdateDetectorKeyEndpoint.cjs +38 -37
  77. package/dist/cjs/api/admin/createApiAdminRoutesProvider.cjs +7 -8
  78. package/dist/cjs/api/blacklistRequestInspector.cjs +288 -376
  79. package/dist/cjs/api/block.cjs +18 -30
  80. package/dist/cjs/api/captcha/checkSpamEmail.cjs +90 -100
  81. package/dist/cjs/api/captcha/contextAwareValidation.cjs +21 -14
  82. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/accessPolicy.cjs +125 -140
  83. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/constants.cjs +10 -10
  84. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/decisionMachine.cjs +238 -301
  85. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/decryptSimdReadings.cjs +9 -12
  86. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/handler.cjs +349 -473
  87. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/honeypotResponse.cjs +18 -14
  88. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/sessionDedup.cjs +26 -26
  89. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.cjs +42 -63
  90. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge.cjs +2 -3
  91. package/dist/cjs/api/captcha/getImageCaptchaChallenge.cjs +138 -208
  92. package/dist/cjs/api/captcha/getPoWCaptchaChallenge.cjs +131 -200
  93. package/dist/cjs/api/captcha/getPuzzleCaptchaChallenge.cjs +135 -203
  94. package/dist/cjs/api/captcha/maintenanceModeResponses.cjs +38 -44
  95. package/dist/cjs/api/captcha/submitImageCaptchaSolution.cjs +77 -102
  96. package/dist/cjs/api/captcha/submitPoWCaptchaSolution.cjs +140 -209
  97. package/dist/cjs/api/captcha/submitPuzzleCaptchaSolution.cjs +76 -107
  98. package/dist/cjs/api/captcha.cjs +79 -58
  99. package/dist/cjs/api/dnsEventUrl.cjs +20 -21
  100. package/dist/cjs/api/domainMiddleware.cjs +106 -117
  101. package/dist/cjs/api/forwardVerify.cjs +63 -49
  102. package/dist/cjs/api/handshakeTimingMiddleware.cjs +43 -61
  103. package/dist/cjs/api/hardBlockVerdictCache.cjs +114 -114
  104. package/dist/cjs/api/headerCheckMiddleware.cjs +34 -34
  105. package/dist/cjs/api/ignoreMiddleware.cjs +12 -14
  106. package/dist/cjs/api/ipInfoMiddleware.cjs +16 -18
  107. package/dist/cjs/api/ja4.cjs +149 -187
  108. package/dist/cjs/api/ja4Middleware.cjs +40 -53
  109. package/dist/cjs/api/metrics.cjs +229 -228
  110. package/dist/cjs/api/public.cjs +57 -57
  111. package/dist/cjs/api/robotsMiddleware.cjs +9 -9
  112. package/dist/cjs/api/startProviderApi.cjs +219 -237
  113. package/dist/cjs/api/testSiteKey.cjs +15 -14
  114. package/dist/cjs/api/validateAddress.cjs +24 -21
  115. package/dist/cjs/api/verify.cjs +338 -379
  116. package/dist/cjs/compositeIpAddress.cjs +40 -47
  117. package/dist/cjs/index.cjs +65 -71
  118. package/dist/cjs/pairs.cjs +31 -35
  119. package/dist/cjs/rules/lang.cjs +10 -14
  120. package/dist/cjs/schedulers/captchaScheduler.cjs +26 -32
  121. package/dist/cjs/schedulers/getClientList.cjs +35 -33
  122. package/dist/cjs/schedulers/setClientEntropy.cjs +35 -33
  123. package/dist/cjs/schedulers/updateSpamEmailDomains.cjs +39 -43
  124. package/dist/cjs/services/ipComparison.cjs +122 -119
  125. package/dist/cjs/tasks/captchaManager.cjs +407 -486
  126. package/dist/cjs/tasks/client/clientTasks.cjs +347 -470
  127. package/dist/cjs/tasks/dataset/datasetTasks.cjs +25 -29
  128. package/dist/cjs/tasks/dataset/datasetTasksUtils.cjs +16 -32
  129. package/dist/cjs/tasks/decisionMachine/decisionMachineRunner.cjs +220 -307
  130. package/dist/cjs/tasks/detection/decodeBehavior.cjs +408 -317
  131. package/dist/cjs/tasks/detection/decodePayload.cjs +686 -468
  132. package/dist/cjs/tasks/detection/decodeSimd.cjs +462 -304
  133. package/dist/cjs/tasks/detection/getBotScore.cjs +37 -43
  134. package/dist/cjs/tasks/dnsEvent/enrichDnsEvent.cjs +88 -71
  135. package/dist/cjs/tasks/frictionless/frictionlessTasks.cjs +348 -486
  136. package/dist/cjs/tasks/frictionless/frictionlessTasksUtils.cjs +13 -30
  137. package/dist/cjs/tasks/frictionless/routingMachine.cjs +71 -55
  138. package/dist/cjs/tasks/imgCaptcha/imgCaptchaTasks.cjs +555 -806
  139. package/dist/cjs/tasks/imgCaptcha/imgCaptchaTasksUtils.cjs +22 -23
  140. package/dist/cjs/tasks/index.cjs +2 -4
  141. package/dist/cjs/tasks/powCaptcha/powTasks.cjs +491 -687
  142. package/dist/cjs/tasks/powCaptcha/powTasksUtils.cjs +17 -29
  143. package/dist/cjs/tasks/puzzleCaptcha/puzzleTasks.cjs +422 -591
  144. package/dist/cjs/tasks/puzzleCaptcha/puzzleTasksUtils.cjs +8 -5
  145. package/dist/cjs/tasks/spam/checkSpamEmail.cjs +133 -141
  146. package/dist/cjs/tasks/spam/checkTrafficFilter.cjs +118 -76
  147. package/dist/cjs/tasks/spam/evaluateEmailSpamRules.cjs +75 -84
  148. package/dist/cjs/tasks/spam/updateSpamEmailDomains.cjs +40 -56
  149. package/dist/cjs/tasks/tasks.cjs +107 -158
  150. package/dist/cjs/util/usageCounters.cjs +220 -211
  151. package/dist/cjs/util.cjs +329 -359
  152. package/dist/cjs/utils/devicePlatform.cjs +14 -8
  153. package/dist/cjs/utils/dns.cjs +68 -93
  154. package/dist/cjs/utils/hashUserAgent.cjs +14 -7
  155. package/dist/cjs/utils/hashUserIp.cjs +14 -6
  156. package/dist/cjs/utils/honeypot/encoders.cjs +74 -80
  157. package/dist/cjs/utils/honeypot/phraseBank.cjs +51 -44
  158. package/dist/cjs/utils/normalizeRequestIp.cjs +33 -25
  159. package/dist/compositeIpAddress.js +38 -46
  160. package/dist/index.js +12 -56
  161. package/dist/pairs.js +31 -37
  162. package/dist/rules/lang.js +11 -15
  163. package/dist/schedulers/captchaScheduler.js +25 -31
  164. package/dist/schedulers/getClientList.js +34 -32
  165. package/dist/schedulers/setClientEntropy.js +34 -32
  166. package/dist/schedulers/updateSpamEmailDomains.js +38 -42
  167. package/dist/services/ipComparison.js +122 -119
  168. package/dist/tasks/captchaManager.js +403 -483
  169. package/dist/tasks/client/clientTasks.js +343 -467
  170. package/dist/tasks/dataset/datasetTasks.js +24 -28
  171. package/dist/tasks/dataset/datasetTasksUtils.js +15 -31
  172. package/dist/tasks/decisionMachine/decisionMachineRunner.js +217 -306
  173. package/dist/tasks/detection/getBotScore.js +37 -43
  174. package/dist/tasks/dnsEvent/enrichDnsEvent.d.ts.map +1 -1
  175. package/dist/tasks/dnsEvent/enrichDnsEvent.js +88 -74
  176. package/dist/tasks/dnsEvent/enrichDnsEvent.js.map +1 -1
  177. package/dist/tasks/frictionless/frictionlessTasks.js +342 -479
  178. package/dist/tasks/frictionless/frictionlessTasksUtils.js +14 -32
  179. package/dist/tasks/frictionless/routingMachine.js +72 -56
  180. package/dist/tasks/imgCaptcha/imgCaptchaTasks.js +550 -801
  181. package/dist/tasks/imgCaptcha/imgCaptchaTasksUtils.js +21 -22
  182. package/dist/tasks/index.js +1 -3
  183. package/dist/tasks/powCaptcha/powTasks.d.ts.map +1 -1
  184. package/dist/tasks/powCaptcha/powTasks.js +486 -682
  185. package/dist/tasks/powCaptcha/powTasks.js.map +1 -1
  186. package/dist/tasks/powCaptcha/powTasksUtils.js +15 -28
  187. package/dist/tasks/puzzleCaptcha/puzzleTasks.d.ts.map +1 -1
  188. package/dist/tasks/puzzleCaptcha/puzzleTasks.js +417 -586
  189. package/dist/tasks/puzzleCaptcha/puzzleTasks.js.map +1 -1
  190. package/dist/tasks/puzzleCaptcha/puzzleTasksUtils.js +9 -6
  191. package/dist/tasks/spam/checkSpamEmail.js +133 -141
  192. package/dist/tasks/spam/checkTrafficFilter.d.ts +1 -0
  193. package/dist/tasks/spam/checkTrafficFilter.d.ts.map +1 -1
  194. package/dist/tasks/spam/checkTrafficFilter.js +117 -77
  195. package/dist/tasks/spam/checkTrafficFilter.js.map +1 -1
  196. package/dist/tasks/spam/evaluateEmailSpamRules.js +75 -86
  197. package/dist/tasks/spam/updateSpamEmailDomains.js +36 -54
  198. package/dist/tasks/tasks.js +98 -150
  199. package/dist/tests/integration/api/blacklistRequestInspector.integration.test.js +4 -1
  200. package/dist/tests/integration/api/blacklistRequestInspector.integration.test.js.map +1 -1
  201. package/dist/tests/unit/api/block.unit.test.js +8 -4
  202. package/dist/tests/unit/api/block.unit.test.js.map +1 -1
  203. package/dist/tests/unit/api/captcha/maintenanceModeShortCircuit.unit.test.js +8 -6
  204. package/dist/tests/unit/api/captcha/maintenanceModeShortCircuit.unit.test.js.map +1 -1
  205. package/dist/tests/unit/api/forwardVerify.unit.test.js +3 -1
  206. package/dist/tests/unit/api/forwardVerify.unit.test.js.map +1 -1
  207. package/dist/tests/unit/api/getFrictionlessCaptchaChallenge.unit.test.js +15 -7
  208. package/dist/tests/unit/api/getFrictionlessCaptchaChallenge.unit.test.js.map +1 -1
  209. package/dist/tests/unit/schedulers/captchaScheduler.unit.test.js +24 -18
  210. package/dist/tests/unit/schedulers/captchaScheduler.unit.test.js.map +1 -1
  211. package/dist/tests/unit/schedulers/getClientList.unit.test.js +19 -13
  212. package/dist/tests/unit/schedulers/getClientList.unit.test.js.map +1 -1
  213. package/dist/tests/unit/schedulers/setClientEntropy.unit.test.js +19 -13
  214. package/dist/tests/unit/schedulers/setClientEntropy.unit.test.js.map +1 -1
  215. package/dist/tests/unit/tasks/client/clientTasks.unit.test.js.map +1 -1
  216. package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasksUtils.unit.test.js +22 -16
  217. package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasksUtils.unit.test.js.map +1 -1
  218. package/dist/tests/unit/tasks/powCaptcha/powTasks.unit.test.js +6 -0
  219. package/dist/tests/unit/tasks/powCaptcha/powTasks.unit.test.js.map +1 -1
  220. package/dist/tests/unit/tasks/puzzleCaptcha/puzzleTasks.unit.test.js +60 -1
  221. package/dist/tests/unit/tasks/puzzleCaptcha/puzzleTasks.unit.test.js.map +1 -1
  222. package/dist/tests/unit/tasks/spam/checkTrafficFilter.unit.test.js +140 -0
  223. package/dist/tests/unit/tasks/spam/checkTrafficFilter.unit.test.js.map +1 -1
  224. package/dist/tests/unit/testUtils/mockProviderEnv.d.ts +7 -7
  225. package/dist/util/usageCounters.js +220 -212
  226. package/dist/util.d.ts.map +1 -1
  227. package/dist/util.js +327 -364
  228. package/dist/util.js.map +1 -1
  229. package/dist/utils/devicePlatform.js +15 -9
  230. package/dist/utils/dns.js +64 -77
  231. package/dist/utils/hashUserAgent.js +14 -7
  232. package/dist/utils/hashUserIp.js +14 -6
  233. package/dist/utils/honeypot/encoders.js +74 -80
  234. package/dist/utils/honeypot/phraseBank.js +49 -44
  235. package/dist/utils/normalizeRequestIp.js +34 -26
  236. package/package.json +24 -24
@@ -1,486 +1,349 @@
1
- import { SimdReadingsStage, CaptchaType, ApiParams } from "@prosopo/types";
2
- import { FrictionlessReason } from "@prosopo/types";
3
- import { v4 } from "uuid";
1
+ import { buildAllWindowIncrements } from "../../util/usageCounters.js";
2
+ import { DecisionMachineRunner } from "../decisionMachine/decisionMachineRunner.js";
4
3
  import { buildDnsEventUrl } from "../../api/dnsEventUrl.js";
5
4
  import { checkLangRules } from "../../rules/lang.js";
6
- import { buildAllWindowIncrements } from "../../util/usageCounters.js";
7
5
  import { CaptchaManager } from "../captchaManager.js";
8
- import { DecisionMachineRunner } from "../decisionMachine/decisionMachineRunner.js";
9
6
  import { getBotScore } from "../detection/getBotScore.js";
10
7
  import { applyRouter } from "./routingMachine.js";
11
- const DEFAULT_MAX_TIMESTAMP_AGE = 60 * 10 * 1e3;
12
- const getSessionIDPrefix = (host) => {
13
- return host ? host.replace(".prosopo.io", "") : "local";
8
+ import { ApiParams, CaptchaType, FrictionlessReason as FrictionlessReason$1, SimdReadingsStage } from "@prosopo/types";
9
+ import { v4 } from "uuid";
10
+ //#region src/tasks/frictionless/frictionlessTasks.ts
11
+ var DEFAULT_MAX_TIMESTAMP_AGE = 600 * 1e3;
12
+ var getSessionIDPrefix = (host) => {
13
+ return host ? host.replace(".prosopo.io", "") : "local";
14
14
  };
15
- class FrictionlessManager extends CaptchaManager {
16
- constructor(db, pair, config, logger, writeQueue, decisionMachineRunner, usageCounters) {
17
- super(db, pair, config, logger, writeQueue);
18
- this.config = config;
19
- this.decisionMachineRunner = decisionMachineRunner ?? new DecisionMachineRunner(db);
20
- this.usageCounters = usageCounters ?? null;
21
- }
22
- /**
23
- * Provide the routing-machine context for this request. When set, the
24
- * frictionless flow's send*Captcha calls will (a) invoke the routing
25
- * machine to potentially override the baseline captcha type, and (b) emit
26
- * fire-and-forget served-counter writes after the session is created.
27
- *
28
- * Not called on maintenance-mode or configured-captchaType short-circuit
29
- * paths — those skip routing entirely.
30
- */
31
- setRoutingContext(ctx) {
32
- this.routingContext = ctx;
33
- }
34
- /**
35
- * Evaluate the configured routing machine against an arbitrary baseline +
36
- * context, without going through `sendCaptcha`. Used by the dedup
37
- * short-circuit to ask "if we reused this cached session, would the
38
- * current routing machine still pick the same captchaType?" — if not,
39
- * the cached session is evicted and the request falls through into the
40
- * normal decision-machine flow (which will run the router again with
41
- * fully-derived inputs).
42
- *
43
- * Returns the supplied baseline on any failure (no machine, machine
44
- * throws, counter fetch failure, etc.), matching applyRouter's contract.
45
- */
46
- async applyRoutingMachine(baseline, ctx) {
47
- return applyRouter(
48
- this.decisionMachineRunner,
49
- this.usageCounters,
50
- baseline,
51
- ctx,
52
- this.logger
53
- );
54
- }
55
- setSessionParams(params) {
56
- this.sessionParams = {
57
- token: params.token,
58
- score: params.score,
59
- threshold: params.threshold,
60
- scoreComponents: params.scoreComponents,
61
- ipAddress: params.ipAddress,
62
- webView: params.webView ?? false,
63
- iFrame: params.iFrame ?? false,
64
- decryptedHeadHash: params.decryptedHeadHash,
65
- siteKey: params.siteKey,
66
- currentUrl: params.currentUrl,
67
- iframeUrl: params.iframeUrl,
68
- isProtect: params.isProtect,
69
- ipInfo: params.ipInfo,
70
- headers: params.headers,
71
- mode: params.mode,
72
- simdReadings: params.simdReadings,
73
- entropyMathRandomFingerprint: params.entropyMathRandomFingerprint,
74
- entropyCryptoFingerprint: params.entropyCryptoFingerprint,
75
- entropyWallClockOffsetMs: params.entropyWallClockOffsetMs,
76
- entropyMathRandomFirst: params.entropyMathRandomFirst,
77
- tcpToChelloUs: params.tcpToChelloUs,
78
- chelloToHandshakeUs: params.chelloToHandshakeUs
79
- };
80
- }
81
- updateScore(score, scoreComponents) {
82
- if (this.sessionParams) {
83
- this.sessionParams.score = score;
84
- this.sessionParams.scoreComponents = scoreComponents;
85
- }
86
- }
87
- checkLangRules(acceptLanguage) {
88
- return checkLangRules(this.config, acceptLanguage);
89
- }
90
- async createSession(token, score, threshold, scoreComponents, ipAddress, captchaType, siteKey, solvedImagesCount, powDifficulty, userSitekeyIpHash, webView = false, iFrame = false, decryptedHeadHash = "", reason, blocked, deleted, ipInfo, headers, mode, simdReadings, entropyMathRandomFingerprint, entropyCryptoFingerprint, entropyWallClockOffsetMs, entropyMathRandomFirst, currentUrl, tcpToChelloUs, chelloToHandshakeUs, isEscalation, iframeUrl, isProtect) {
91
- const sessionRecord = {
92
- sessionId: `${getSessionIDPrefix(this.config.host)}-${v4()}`,
93
- createdAt: /* @__PURE__ */ new Date(),
94
- token,
95
- score,
96
- threshold,
97
- scoreComponents,
98
- ipAddress,
99
- captchaType,
100
- mode,
101
- solvedImagesCount,
102
- powDifficulty,
103
- userSitekeyIpHash,
104
- webView,
105
- iFrame,
106
- // Only persist the escalation flag when it's actually true —
107
- // avoids polluting analytics with `false` on every plain
108
- // frictionless session.
109
- ...isEscalation && { isEscalation: true },
110
- decryptedHeadHash,
111
- reason,
112
- siteKey,
113
- currentUrl,
114
- iframeUrl,
115
- // Same rationale as isEscalation above: only persist the flag
116
- // when it's actually true so non-Protect sessions stay slim and
117
- // the sparse index on {isProtect, createdAt} carries only the
118
- // Protect subset.
119
- ...isProtect && { isProtect: true },
120
- blocked,
121
- deleted,
122
- ipInfo,
123
- headers,
124
- simdReadings,
125
- // Tag the arrival stage when the readings actually came in on
126
- // this hop. Absence of readings → absence of stage.
127
- ...simdReadings && {
128
- simdReadingsStage: SimdReadingsStage.frictionless
129
- },
130
- entropyMathRandomFingerprint,
131
- entropyCryptoFingerprint,
132
- entropyWallClockOffsetMs,
133
- entropyMathRandomFirst,
134
- tcpToChelloUs,
135
- chelloToHandshakeUs
136
- };
137
- await this.db.storeSessionRecord(sessionRecord);
138
- if (this.writeQueue) {
139
- const cacheData = sessionRecord;
140
- const cachePromises = [
141
- this.writeQueue.cacheSession(sessionRecord.sessionId, cacheData)
142
- ];
143
- if (userSitekeyIpHash) {
144
- cachePromises.push(
145
- this.writeQueue.cacheSessionByHash(
146
- userSitekeyIpHash,
147
- sessionRecord.sessionId
148
- )
149
- );
150
- }
151
- await Promise.all(cachePromises).catch(() => {
152
- });
153
- }
154
- return sessionRecord;
155
- }
156
- async sendImageCaptcha(params) {
157
- return this.sendCaptcha(CaptchaType.image, params);
158
- }
159
- async sendPowCaptcha(params) {
160
- return this.sendCaptcha(CaptchaType.pow, params);
161
- }
162
- async sendPuzzleCaptcha(params) {
163
- return this.sendCaptcha(CaptchaType.puzzle, params);
164
- }
165
- // Shared body for the three concrete `send*Captcha` helpers. Each helper is
166
- // kept as its own thin wrapper so call-sites read clearly, but session
167
- // validation and the createSession invocation only live in one place.
168
- async sendCaptcha(captchaType, params) {
169
- const effectiveParams = { ...this.sessionParams, ...params };
170
- if (!effectiveParams.token || effectiveParams.score === void 0 || effectiveParams.threshold === void 0 || !effectiveParams.scoreComponents || !effectiveParams.ipAddress || effectiveParams.siteKey === void 0) {
171
- throw new Error(
172
- `Session parameters must be set before sending a ${captchaType} captcha`
173
- );
174
- }
175
- const baseline = {
176
- captchaType,
177
- solvedImagesCount: captchaType === CaptchaType.image ? effectiveParams.solvedImagesCount : void 0,
178
- powDifficulty: captchaType === CaptchaType.pow ? effectiveParams.powDifficulty : void 0
179
- };
180
- const routed = this.routingContext ? await applyRouter(
181
- this.decisionMachineRunner,
182
- this.usageCounters,
183
- baseline,
184
- this.routingContext,
185
- this.logger
186
- ) : baseline;
187
- const finalCaptchaType = routed.captchaType;
188
- const finalSolvedImagesCount = finalCaptchaType === CaptchaType.image ? routed.solvedImagesCount ?? effectiveParams.solvedImagesCount : void 0;
189
- const finalPowDifficulty = finalCaptchaType === CaptchaType.pow ? routed.powDifficulty ?? effectiveParams.powDifficulty : void 0;
190
- const blocked = finalCaptchaType === CaptchaType.image ? effectiveParams.blocked : void 0;
191
- const sessionRecord = await this.createSession(
192
- effectiveParams.token,
193
- effectiveParams.score,
194
- effectiveParams.threshold,
195
- effectiveParams.scoreComponents,
196
- effectiveParams.ipAddress,
197
- finalCaptchaType,
198
- effectiveParams.siteKey,
199
- finalSolvedImagesCount,
200
- finalPowDifficulty,
201
- effectiveParams.userSitekeyIpHash,
202
- effectiveParams.webView ?? false,
203
- effectiveParams.iFrame ?? false,
204
- effectiveParams.decryptedHeadHash,
205
- effectiveParams.reason,
206
- blocked,
207
- void 0,
208
- effectiveParams.ipInfo,
209
- effectiveParams.headers,
210
- effectiveParams.mode,
211
- effectiveParams.simdReadings,
212
- effectiveParams.entropyMathRandomFingerprint,
213
- effectiveParams.entropyCryptoFingerprint,
214
- effectiveParams.entropyWallClockOffsetMs,
215
- effectiveParams.entropyMathRandomFirst,
216
- effectiveParams.currentUrl,
217
- effectiveParams.tcpToChelloUs,
218
- effectiveParams.chelloToHandshakeUs,
219
- void 0,
220
- effectiveParams.iframeUrl,
221
- effectiveParams.isProtect
222
- );
223
- if (this.routingContext && this.usageCounters) {
224
- this.usageCounters.incrManyAsync(
225
- this.routingContext.dappAccount,
226
- buildAllWindowIncrements(
227
- "served",
228
- finalCaptchaType,
229
- this.routingContext.ip,
230
- this.routingContext.userAccount
231
- )
232
- );
233
- }
234
- return {
235
- [ApiParams.captchaType]: finalCaptchaType,
236
- [ApiParams.sessionId]: sessionRecord.sessionId,
237
- [ApiParams.status]: "ok",
238
- dns_url: buildDnsEventUrl(sessionRecord.sessionId)
239
- };
240
- }
241
- async registerBlockedSession(params) {
242
- const effectiveParams = { ...this.sessionParams, ...params };
243
- if (!effectiveParams.token || effectiveParams.score === void 0 || effectiveParams.threshold === void 0 || !effectiveParams.scoreComponents || !effectiveParams.ipAddress || effectiveParams.siteKey === void 0) {
244
- throw new Error(
245
- "Session parameters must be set before calling registerBlockedSession"
246
- );
247
- }
248
- await this.createSession(
249
- effectiveParams.token,
250
- effectiveParams.score,
251
- effectiveParams.threshold,
252
- effectiveParams.scoreComponents,
253
- effectiveParams.ipAddress,
254
- CaptchaType.image,
255
- effectiveParams.siteKey,
256
- effectiveParams.solvedImagesCount,
257
- void 0,
258
- effectiveParams.userSitekeyIpHash,
259
- effectiveParams.webView ?? false,
260
- effectiveParams.iFrame ?? false,
261
- effectiveParams.decryptedHeadHash,
262
- effectiveParams.reason,
263
- true,
264
- true,
265
- effectiveParams.ipInfo,
266
- effectiveParams.headers,
267
- effectiveParams.mode,
268
- effectiveParams.simdReadings,
269
- effectiveParams.entropyMathRandomFingerprint,
270
- effectiveParams.entropyCryptoFingerprint,
271
- effectiveParams.entropyWallClockOffsetMs,
272
- effectiveParams.entropyMathRandomFirst,
273
- effectiveParams.currentUrl,
274
- effectiveParams.tcpToChelloUs,
275
- effectiveParams.chelloToHandshakeUs,
276
- void 0,
277
- effectiveParams.iframeUrl,
278
- effectiveParams.isProtect
279
- );
280
- }
281
- scoreIncreaseAccessPolicy(accessPolicy, baseBotScore, botScore, scoreComponents) {
282
- const accessPolicyPenalty = accessPolicy?.frictionlessScore || this.config.penalties.PENALTY_ACCESS_RULE;
283
- botScore += accessPolicyPenalty;
284
- return {
285
- score: botScore,
286
- scoreComponents: {
287
- ...scoreComponents,
288
- accessPolicy: accessPolicyPenalty
289
- }
290
- };
291
- }
292
- scoreIncreaseWebView(baseBotScore, botScore, scoreComponents) {
293
- this.logger.debug(() => ({
294
- msg: "WebView detected"
295
- }));
296
- botScore += this.config.penalties.PENALTY_WEBVIEW;
297
- return {
298
- score: botScore,
299
- scoreComponents: {
300
- ...scoreComponents,
301
- webView: this.config.penalties.PENALTY_WEBVIEW
302
- }
303
- };
304
- }
305
- scoreIncreaseTimestamp(timestamp, baseBotScore, botScore, scoreComponents) {
306
- this.logger.info(() => ({
307
- msg: "Timestamp is older than 10 minutes",
308
- data: { timestamp: new Date(timestamp) }
309
- }));
310
- botScore += this.config.penalties.PENALTY_OLD_TIMESTAMP;
311
- return {
312
- score: botScore,
313
- scoreComponents: {
314
- ...scoreComponents,
315
- timeout: this.config.penalties.PENALTY_OLD_TIMESTAMP
316
- }
317
- };
318
- }
319
- static timestampTooOld(timestamp) {
320
- const now = Date.now();
321
- const diff = now - timestamp;
322
- return diff > DEFAULT_MAX_TIMESTAMP_AGE;
323
- }
324
- /**
325
- * Redacts a key for logging purposes by showing only the first 5, middle 10, and last 5 characters
326
- * @param key - The key to redact
327
- * @returns Redacted key string or empty string if key is falsy
328
- */
329
- redactKeyForLogging(key) {
330
- if (!key) return "";
331
- const start = key.slice(0, 5);
332
- const middle = key.slice(
333
- Math.floor(key.length / 2) - 5,
334
- Math.floor(key.length / 2) + 5
335
- );
336
- const end = key.slice(-5);
337
- return `${start}...${middle}...${end}`;
338
- }
339
- async decryptPayload(token, headHash) {
340
- const decryptKeys = [
341
- // Process DB keys first, then env var key last as env key will likely be invalid
342
- ...await this.getDetectorKeys(),
343
- process.env.BOT_DECRYPTION_KEY
344
- ].filter((k) => k);
345
- this.logger.debug(() => {
346
- const loggedKeys = decryptKeys.map(
347
- (key) => this.redactKeyForLogging(key)
348
- );
349
- return {
350
- msg: "Decrypting score",
351
- data: {
352
- keysLength: decryptKeys.length,
353
- keys: loggedKeys
354
- }
355
- };
356
- });
357
- let baseBotScore;
358
- let timestamp;
359
- let userId;
360
- let userAgent;
361
- let webView;
362
- let iFrame;
363
- let decryptedHeadHash = "";
364
- let decryptionFailed = false;
365
- let triggeredDetectors;
366
- let shadowDomPenalty;
367
- let entropyMathRandomFingerprint;
368
- let entropyCryptoFingerprint;
369
- let entropyWallClockOffsetMs;
370
- let entropyMathRandomFirst;
371
- for (const [keyIndex, key] of decryptKeys.entries()) {
372
- try {
373
- this.logger.info(() => ({
374
- msg: "Attempting to decrypt score",
375
- data: {
376
- key: this.redactKeyForLogging(key)
377
- }
378
- }));
379
- const decrypted = await getBotScore(token, headHash, key);
380
- decryptedHeadHash = decrypted.decryptedHeadHash || "";
381
- const s = decrypted.baseBotScore;
382
- const t = decrypted.timestamp;
383
- const a = decrypted.userId;
384
- const u = decrypted.userAgent;
385
- const w = decrypted.isWebView;
386
- const i = decrypted.isIframe;
387
- const td = decrypted.triggeredDetectors;
388
- const sd = decrypted.shadowDomPenalty;
389
- const ef = decrypted.entropyMathRandomFingerprint;
390
- const ec = decrypted.entropyCryptoFingerprint;
391
- const eo = decrypted.entropyWallClockOffsetMs;
392
- const em = decrypted.entropyMathRandomFirst;
393
- this.logger.debug(() => ({
394
- msg: "Successfully decrypted score",
395
- data: {
396
- key: this.redactKeyForLogging(key),
397
- baseBotScore: s,
398
- timestamp: t,
399
- userId: a,
400
- userAgent: u,
401
- webView: w,
402
- iFrame: i,
403
- triggeredDetectors: td,
404
- shadowDomPenalty: sd,
405
- entropyMathRandomFingerprint: ef,
406
- entropyCryptoFingerprint: ec,
407
- entropyWallClockOffsetMs: eo,
408
- entropyMathRandomFirst: em
409
- }
410
- }));
411
- baseBotScore = s;
412
- timestamp = t;
413
- userId = a;
414
- userAgent = u;
415
- webView = w;
416
- iFrame = i;
417
- triggeredDetectors = td;
418
- shadowDomPenalty = sd;
419
- entropyMathRandomFingerprint = ef;
420
- entropyCryptoFingerprint = ec;
421
- entropyWallClockOffsetMs = eo;
422
- entropyMathRandomFirst = em;
423
- break;
424
- } catch (err) {
425
- if (keyIndex === decryptKeys.length - 1) {
426
- this.logger.warn(() => ({
427
- msg: "Error decrypting score: no more keys to try"
428
- }));
429
- baseBotScore = 1;
430
- timestamp = 0;
431
- decryptedHeadHash = "";
432
- decryptionFailed = true;
433
- }
434
- }
435
- }
436
- const baseBotScoreUndefined = baseBotScore === void 0 || Number.isNaN(baseBotScore);
437
- const timestampUndefined = timestamp === void 0 || Number.isNaN(timestamp);
438
- const undefinedCount = Number(baseBotScoreUndefined) + Number(timestampUndefined);
439
- if (undefinedCount > 0) {
440
- this.logger.error(() => ({
441
- msg: "Error decrypting score: baseBotScore or timestamp is undefined"
442
- }));
443
- baseBotScore = 1;
444
- timestamp = 0;
445
- decryptedHeadHash = "";
446
- decryptionFailed = true;
447
- }
448
- this.logger.info(() => ({
449
- msg: "decryptPayload result",
450
- data: {
451
- baseBotScore,
452
- timestamp,
453
- userId,
454
- userAgent,
455
- webView,
456
- iFrame,
457
- decryptedHeadHash,
458
- decryptionFailed,
459
- shadowDomPenalty
460
- }
461
- }));
462
- return {
463
- baseBotScore: Number(baseBotScore),
464
- timestamp: Number(timestamp),
465
- userId,
466
- userAgent,
467
- webView: webView || false,
468
- iFrame: iFrame || false,
469
- decryptedHeadHash,
470
- decryptionFailed,
471
- triggeredDetectors,
472
- shadowDomPenalty,
473
- entropyMathRandomFingerprint,
474
- entropyCryptoFingerprint,
475
- entropyWallClockOffsetMs,
476
- entropyMathRandomFirst
477
- };
478
- }
479
- async getClientContextEntropy(siteKey, contextType) {
480
- return this.db.getClientContextEntropy(siteKey, contextType);
481
- }
482
- }
483
- export {
484
- FrictionlessManager,
485
- FrictionlessReason
15
+ var FrictionlessManager = class extends CaptchaManager {
16
+ constructor(db, pair, config, logger, writeQueue, decisionMachineRunner, usageCounters) {
17
+ super(db, pair, config, logger, writeQueue);
18
+ this.config = config;
19
+ this.decisionMachineRunner = decisionMachineRunner ?? new DecisionMachineRunner(db);
20
+ this.usageCounters = usageCounters ?? null;
21
+ }
22
+ /**
23
+ * Provide the routing-machine context for this request. When set, the
24
+ * frictionless flow's send*Captcha calls will (a) invoke the routing
25
+ * machine to potentially override the baseline captcha type, and (b) emit
26
+ * fire-and-forget served-counter writes after the session is created.
27
+ *
28
+ * Not called on maintenance-mode or configured-captchaType short-circuit
29
+ * paths — those skip routing entirely.
30
+ */
31
+ setRoutingContext(ctx) {
32
+ this.routingContext = ctx;
33
+ }
34
+ /**
35
+ * Evaluate the configured routing machine against an arbitrary baseline +
36
+ * context, without going through `sendCaptcha`. Used by the dedup
37
+ * short-circuit to ask "if we reused this cached session, would the
38
+ * current routing machine still pick the same captchaType?" — if not,
39
+ * the cached session is evicted and the request falls through into the
40
+ * normal decision-machine flow (which will run the router again with
41
+ * fully-derived inputs).
42
+ *
43
+ * Returns the supplied baseline on any failure (no machine, machine
44
+ * throws, counter fetch failure, etc.), matching applyRouter's contract.
45
+ */
46
+ async applyRoutingMachine(baseline, ctx) {
47
+ return applyRouter(this.decisionMachineRunner, this.usageCounters, baseline, ctx, this.logger);
48
+ }
49
+ setSessionParams(params) {
50
+ this.sessionParams = {
51
+ token: params.token,
52
+ score: params.score,
53
+ threshold: params.threshold,
54
+ scoreComponents: params.scoreComponents,
55
+ ipAddress: params.ipAddress,
56
+ webView: params.webView ?? false,
57
+ iFrame: params.iFrame ?? false,
58
+ decryptedHeadHash: params.decryptedHeadHash,
59
+ siteKey: params.siteKey,
60
+ currentUrl: params.currentUrl,
61
+ iframeUrl: params.iframeUrl,
62
+ isProtect: params.isProtect,
63
+ ipInfo: params.ipInfo,
64
+ headers: params.headers,
65
+ mode: params.mode,
66
+ simdReadings: params.simdReadings,
67
+ entropyMathRandomFingerprint: params.entropyMathRandomFingerprint,
68
+ entropyCryptoFingerprint: params.entropyCryptoFingerprint,
69
+ entropyWallClockOffsetMs: params.entropyWallClockOffsetMs,
70
+ entropyMathRandomFirst: params.entropyMathRandomFirst,
71
+ tcpToChelloUs: params.tcpToChelloUs,
72
+ chelloToHandshakeUs: params.chelloToHandshakeUs
73
+ };
74
+ }
75
+ updateScore(score, scoreComponents) {
76
+ if (this.sessionParams) {
77
+ this.sessionParams.score = score;
78
+ this.sessionParams.scoreComponents = scoreComponents;
79
+ }
80
+ }
81
+ checkLangRules(acceptLanguage) {
82
+ return checkLangRules(this.config, acceptLanguage);
83
+ }
84
+ async createSession(token, score, threshold, scoreComponents, ipAddress, captchaType, siteKey, solvedImagesCount, powDifficulty, userSitekeyIpHash, webView = false, iFrame = false, decryptedHeadHash = "", reason, blocked, deleted, ipInfo, headers, mode, simdReadings, entropyMathRandomFingerprint, entropyCryptoFingerprint, entropyWallClockOffsetMs, entropyMathRandomFirst, currentUrl, tcpToChelloUs, chelloToHandshakeUs, isEscalation, iframeUrl, isProtect) {
85
+ const sessionRecord = {
86
+ sessionId: `${getSessionIDPrefix(this.config.host)}-${v4()}`,
87
+ createdAt: /* @__PURE__ */ new Date(),
88
+ token,
89
+ score,
90
+ threshold,
91
+ scoreComponents,
92
+ ipAddress,
93
+ captchaType,
94
+ mode,
95
+ solvedImagesCount,
96
+ powDifficulty,
97
+ userSitekeyIpHash,
98
+ webView,
99
+ iFrame,
100
+ ...isEscalation && { isEscalation: true },
101
+ decryptedHeadHash,
102
+ reason,
103
+ siteKey,
104
+ currentUrl,
105
+ iframeUrl,
106
+ ...isProtect && { isProtect: true },
107
+ blocked,
108
+ deleted,
109
+ ipInfo,
110
+ headers,
111
+ simdReadings,
112
+ ...simdReadings && { simdReadingsStage: SimdReadingsStage.frictionless },
113
+ entropyMathRandomFingerprint,
114
+ entropyCryptoFingerprint,
115
+ entropyWallClockOffsetMs,
116
+ entropyMathRandomFirst,
117
+ tcpToChelloUs,
118
+ chelloToHandshakeUs
119
+ };
120
+ await this.db.storeSessionRecord(sessionRecord);
121
+ if (this.writeQueue) {
122
+ const cacheData = sessionRecord;
123
+ const cachePromises = [this.writeQueue.cacheSession(sessionRecord.sessionId, cacheData)];
124
+ if (userSitekeyIpHash) cachePromises.push(this.writeQueue.cacheSessionByHash(userSitekeyIpHash, sessionRecord.sessionId));
125
+ await Promise.all(cachePromises).catch(() => {});
126
+ }
127
+ return sessionRecord;
128
+ }
129
+ async sendImageCaptcha(params) {
130
+ return this.sendCaptcha(CaptchaType.image, params);
131
+ }
132
+ async sendPowCaptcha(params) {
133
+ return this.sendCaptcha(CaptchaType.pow, params);
134
+ }
135
+ async sendPuzzleCaptcha(params) {
136
+ return this.sendCaptcha(CaptchaType.puzzle, params);
137
+ }
138
+ async sendCaptcha(captchaType, params) {
139
+ const effectiveParams = {
140
+ ...this.sessionParams,
141
+ ...params
142
+ };
143
+ if (!effectiveParams.token || effectiveParams.score === void 0 || effectiveParams.threshold === void 0 || !effectiveParams.scoreComponents || !effectiveParams.ipAddress || effectiveParams.siteKey === void 0) throw new Error(`Session parameters must be set before sending a ${captchaType} captcha`);
144
+ const baseline = {
145
+ captchaType,
146
+ solvedImagesCount: captchaType === CaptchaType.image ? effectiveParams.solvedImagesCount : void 0,
147
+ powDifficulty: captchaType === CaptchaType.pow ? effectiveParams.powDifficulty : void 0
148
+ };
149
+ const routed = this.routingContext ? await applyRouter(this.decisionMachineRunner, this.usageCounters, baseline, this.routingContext, this.logger) : baseline;
150
+ const finalCaptchaType = routed.captchaType;
151
+ const finalSolvedImagesCount = finalCaptchaType === CaptchaType.image ? routed.solvedImagesCount ?? effectiveParams.solvedImagesCount : void 0;
152
+ const finalPowDifficulty = finalCaptchaType === CaptchaType.pow ? routed.powDifficulty ?? effectiveParams.powDifficulty : void 0;
153
+ const blocked = finalCaptchaType === CaptchaType.image ? effectiveParams.blocked : void 0;
154
+ const sessionRecord = await this.createSession(effectiveParams.token, effectiveParams.score, effectiveParams.threshold, effectiveParams.scoreComponents, effectiveParams.ipAddress, finalCaptchaType, effectiveParams.siteKey, finalSolvedImagesCount, finalPowDifficulty, effectiveParams.userSitekeyIpHash, effectiveParams.webView ?? false, effectiveParams.iFrame ?? false, effectiveParams.decryptedHeadHash, effectiveParams.reason, blocked, void 0, effectiveParams.ipInfo, effectiveParams.headers, effectiveParams.mode, effectiveParams.simdReadings, effectiveParams.entropyMathRandomFingerprint, effectiveParams.entropyCryptoFingerprint, effectiveParams.entropyWallClockOffsetMs, effectiveParams.entropyMathRandomFirst, effectiveParams.currentUrl, effectiveParams.tcpToChelloUs, effectiveParams.chelloToHandshakeUs, void 0, effectiveParams.iframeUrl, effectiveParams.isProtect);
155
+ if (this.routingContext && this.usageCounters) this.usageCounters.incrManyAsync(this.routingContext.dappAccount, buildAllWindowIncrements("served", finalCaptchaType, this.routingContext.ip, this.routingContext.userAccount));
156
+ return {
157
+ [ApiParams.captchaType]: finalCaptchaType,
158
+ [ApiParams.sessionId]: sessionRecord.sessionId,
159
+ [ApiParams.status]: "ok",
160
+ dns_url: buildDnsEventUrl(sessionRecord.sessionId)
161
+ };
162
+ }
163
+ async registerBlockedSession(params) {
164
+ const effectiveParams = {
165
+ ...this.sessionParams,
166
+ ...params
167
+ };
168
+ if (!effectiveParams.token || effectiveParams.score === void 0 || effectiveParams.threshold === void 0 || !effectiveParams.scoreComponents || !effectiveParams.ipAddress || effectiveParams.siteKey === void 0) throw new Error("Session parameters must be set before calling registerBlockedSession");
169
+ await this.createSession(effectiveParams.token, effectiveParams.score, effectiveParams.threshold, effectiveParams.scoreComponents, effectiveParams.ipAddress, CaptchaType.image, effectiveParams.siteKey, effectiveParams.solvedImagesCount, void 0, effectiveParams.userSitekeyIpHash, effectiveParams.webView ?? false, effectiveParams.iFrame ?? false, effectiveParams.decryptedHeadHash, effectiveParams.reason, true, true, effectiveParams.ipInfo, effectiveParams.headers, effectiveParams.mode, effectiveParams.simdReadings, effectiveParams.entropyMathRandomFingerprint, effectiveParams.entropyCryptoFingerprint, effectiveParams.entropyWallClockOffsetMs, effectiveParams.entropyMathRandomFirst, effectiveParams.currentUrl, effectiveParams.tcpToChelloUs, effectiveParams.chelloToHandshakeUs, void 0, effectiveParams.iframeUrl, effectiveParams.isProtect);
170
+ }
171
+ scoreIncreaseAccessPolicy(accessPolicy, baseBotScore, botScore, scoreComponents) {
172
+ const accessPolicyPenalty = accessPolicy?.frictionlessScore || this.config.penalties.PENALTY_ACCESS_RULE;
173
+ botScore += accessPolicyPenalty;
174
+ return {
175
+ score: botScore,
176
+ scoreComponents: {
177
+ ...scoreComponents,
178
+ accessPolicy: accessPolicyPenalty
179
+ }
180
+ };
181
+ }
182
+ scoreIncreaseWebView(baseBotScore, botScore, scoreComponents) {
183
+ this.logger.debug(() => ({ msg: "WebView detected" }));
184
+ botScore += this.config.penalties.PENALTY_WEBVIEW;
185
+ return {
186
+ score: botScore,
187
+ scoreComponents: {
188
+ ...scoreComponents,
189
+ webView: this.config.penalties.PENALTY_WEBVIEW
190
+ }
191
+ };
192
+ }
193
+ scoreIncreaseTimestamp(timestamp, baseBotScore, botScore, scoreComponents) {
194
+ this.logger.info(() => ({
195
+ msg: "Timestamp is older than 10 minutes",
196
+ data: { timestamp: new Date(timestamp) }
197
+ }));
198
+ botScore += this.config.penalties.PENALTY_OLD_TIMESTAMP;
199
+ return {
200
+ score: botScore,
201
+ scoreComponents: {
202
+ ...scoreComponents,
203
+ timeout: this.config.penalties.PENALTY_OLD_TIMESTAMP
204
+ }
205
+ };
206
+ }
207
+ static timestampTooOld(timestamp) {
208
+ return Date.now() - timestamp > DEFAULT_MAX_TIMESTAMP_AGE;
209
+ }
210
+ /**
211
+ * Redacts a key for logging purposes by showing only the first 5, middle 10, and last 5 characters
212
+ * @param key - The key to redact
213
+ * @returns Redacted key string or empty string if key is falsy
214
+ */
215
+ redactKeyForLogging(key) {
216
+ if (!key) return "";
217
+ return `${key.slice(0, 5)}...${key.slice(Math.floor(key.length / 2) - 5, Math.floor(key.length / 2) + 5)}...${key.slice(-5)}`;
218
+ }
219
+ async decryptPayload(token, headHash) {
220
+ const decryptKeys = [...await this.getDetectorKeys(), process.env.BOT_DECRYPTION_KEY].filter((k) => k);
221
+ this.logger.debug(() => {
222
+ const loggedKeys = decryptKeys.map((key) => this.redactKeyForLogging(key));
223
+ return {
224
+ msg: "Decrypting score",
225
+ data: {
226
+ keysLength: decryptKeys.length,
227
+ keys: loggedKeys
228
+ }
229
+ };
230
+ });
231
+ let baseBotScore;
232
+ let timestamp;
233
+ let userId;
234
+ let userAgent;
235
+ let webView;
236
+ let iFrame;
237
+ let decryptedHeadHash = "";
238
+ let decryptionFailed = false;
239
+ let triggeredDetectors;
240
+ let shadowDomPenalty;
241
+ let entropyMathRandomFingerprint;
242
+ let entropyCryptoFingerprint;
243
+ let entropyWallClockOffsetMs;
244
+ let entropyMathRandomFirst;
245
+ for (const [keyIndex, key] of decryptKeys.entries()) try {
246
+ this.logger.info(() => ({
247
+ msg: "Attempting to decrypt score",
248
+ data: { key: this.redactKeyForLogging(key) }
249
+ }));
250
+ const decrypted = await getBotScore(token, headHash, key);
251
+ decryptedHeadHash = decrypted.decryptedHeadHash || "";
252
+ const s = decrypted.baseBotScore;
253
+ const t = decrypted.timestamp;
254
+ const a = decrypted.userId;
255
+ const u = decrypted.userAgent;
256
+ const w = decrypted.isWebView;
257
+ const i = decrypted.isIframe;
258
+ const td = decrypted.triggeredDetectors;
259
+ const sd = decrypted.shadowDomPenalty;
260
+ const ef = decrypted.entropyMathRandomFingerprint;
261
+ const ec = decrypted.entropyCryptoFingerprint;
262
+ const eo = decrypted.entropyWallClockOffsetMs;
263
+ const em = decrypted.entropyMathRandomFirst;
264
+ this.logger.debug(() => ({
265
+ msg: "Successfully decrypted score",
266
+ data: {
267
+ key: this.redactKeyForLogging(key),
268
+ baseBotScore: s,
269
+ timestamp: t,
270
+ userId: a,
271
+ userAgent: u,
272
+ webView: w,
273
+ iFrame: i,
274
+ triggeredDetectors: td,
275
+ shadowDomPenalty: sd,
276
+ entropyMathRandomFingerprint: ef,
277
+ entropyCryptoFingerprint: ec,
278
+ entropyWallClockOffsetMs: eo,
279
+ entropyMathRandomFirst: em
280
+ }
281
+ }));
282
+ baseBotScore = s;
283
+ timestamp = t;
284
+ userId = a;
285
+ userAgent = u;
286
+ webView = w;
287
+ iFrame = i;
288
+ triggeredDetectors = td;
289
+ shadowDomPenalty = sd;
290
+ entropyMathRandomFingerprint = ef;
291
+ entropyCryptoFingerprint = ec;
292
+ entropyWallClockOffsetMs = eo;
293
+ entropyMathRandomFirst = em;
294
+ break;
295
+ } catch (err) {
296
+ if (keyIndex === decryptKeys.length - 1) {
297
+ this.logger.warn(() => ({ msg: "Error decrypting score: no more keys to try" }));
298
+ baseBotScore = 1;
299
+ timestamp = 0;
300
+ decryptedHeadHash = "";
301
+ decryptionFailed = true;
302
+ }
303
+ }
304
+ const baseBotScoreUndefined = baseBotScore === void 0 || Number.isNaN(baseBotScore);
305
+ const timestampUndefined = timestamp === void 0 || Number.isNaN(timestamp);
306
+ if (Number(baseBotScoreUndefined) + Number(timestampUndefined) > 0) {
307
+ this.logger.error(() => ({ msg: "Error decrypting score: baseBotScore or timestamp is undefined" }));
308
+ baseBotScore = 1;
309
+ timestamp = 0;
310
+ decryptedHeadHash = "";
311
+ decryptionFailed = true;
312
+ }
313
+ this.logger.info(() => ({
314
+ msg: "decryptPayload result",
315
+ data: {
316
+ baseBotScore,
317
+ timestamp,
318
+ userId,
319
+ userAgent,
320
+ webView,
321
+ iFrame,
322
+ decryptedHeadHash,
323
+ decryptionFailed,
324
+ shadowDomPenalty
325
+ }
326
+ }));
327
+ return {
328
+ baseBotScore: Number(baseBotScore),
329
+ timestamp: Number(timestamp),
330
+ userId,
331
+ userAgent,
332
+ webView: webView || false,
333
+ iFrame: iFrame || false,
334
+ decryptedHeadHash,
335
+ decryptionFailed,
336
+ triggeredDetectors,
337
+ shadowDomPenalty,
338
+ entropyMathRandomFingerprint,
339
+ entropyCryptoFingerprint,
340
+ entropyWallClockOffsetMs,
341
+ entropyMathRandomFirst
342
+ };
343
+ }
344
+ async getClientContextEntropy(siteKey, contextType) {
345
+ return this.db.getClientContextEntropy(siteKey, contextType);
346
+ }
486
347
  };
348
+ //#endregion
349
+ export { FrictionlessManager, FrictionlessReason$1 as FrictionlessReason };