@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,475 +1,349 @@
1
- import { ProsopoApiError } from "@prosopo/common";
2
- import { GetFrictionlessCaptchaChallengeRequestBody, ModeEnum, CaptchaType, ApiParams } from "@prosopo/types";
3
- import { AccessPolicyType } from "@prosopo/user-access-policy";
4
- import { sanitisePageUrl, isProtectDeployment, flatten } from "@prosopo/util";
1
+ import { buildDnsEventUrl } from "../../dnsEventUrl.js";
5
2
  import { getCompositeIpAddress } from "../../../compositeIpAddress.js";
6
- import "../../../tasks/index.js";
3
+ import { recordBotScore, recordDetectorTriggered, recordFrictionlessDecision } from "../../metrics.js";
4
+ import { getRequestUserScope } from "../../blacklistRequestInspector.js";
5
+ import { Tasks } from "../../../tasks/tasks.js";
6
+ import { getMaintenanceMode } from "../../admin/apiToggleMaintenanceModeEndpoint.js";
7
7
  import { derivePlatform } from "../../../utils/devicePlatform.js";
8
8
  import { hashUserAgent } from "../../../utils/hashUserAgent.js";
9
9
  import { hashUserIp } from "../../../utils/hashUserIp.js";
10
10
  import { normalizeRequestIp } from "../../../utils/normalizeRequestIp.js";
11
- import { getMaintenanceMode } from "../../admin/apiToggleMaintenanceModeEndpoint.js";
12
- import { getRequestUserScope } from "../../blacklistRequestInspector.js";
13
- import { buildDnsEventUrl } from "../../dnsEventUrl.js";
14
- import { recordFrictionlessDecision, recordBotScore, recordDetectorTriggered } from "../../metrics.js";
15
11
  import { isReservedTestSiteKey } from "../../testSiteKey.js";
16
12
  import { buildFrictionlessMaintenanceResponse } from "../maintenanceModeResponses.js";
13
+ import { attachHoneypot } from "./honeypotResponse.js";
17
14
  import { handleAccessPolicy } from "./accessPolicy.js";
18
- import { DEFAULT_FRICTIONLESS_THRESHOLD } from "./constants.js";
15
+ import "./constants.js";
19
16
  import { runDecisionMachine } from "./decisionMachine.js";
20
17
  import { decryptIncomingSimdReadings } from "./decryptSimdReadings.js";
21
- import { attachHoneypot } from "./honeypotResponse.js";
22
18
  import { resolveSessionDedup } from "./sessionDedup.js";
23
19
  import { runConfiguredCaptchaTypeShortCircuit } from "./shortCircuit.js";
24
- import { Tasks } from "../../../tasks/tasks.js";
25
- const getFrictionlessCaptchaChallenge = (env, userAccessRulesStorage) => async (req, res, next) => {
26
- try {
27
- res.on("finish", () => {
28
- req.logger.info(() => ({
29
- msg: "Frictionless response finished",
30
- data: {
31
- status: res.statusCode,
32
- path: req.path,
33
- method: req.method
34
- }
35
- }));
36
- });
37
- const {
38
- token,
39
- headHash,
40
- dapp,
41
- user,
42
- mode,
43
- simdReadings,
44
- currentUrl: reportedCurrentUrl,
45
- iframeUrl: reportedIframeUrl
46
- } = GetFrictionlessCaptchaChallengeRequestBody.parse(req.body);
47
- const currentUrl = sanitisePageUrl(reportedCurrentUrl);
48
- const iframeUrl = sanitisePageUrl(reportedIframeUrl);
49
- const isProtect = isProtectDeployment(currentUrl, iframeUrl);
50
- const normalizedIp = normalizeRequestIp(req.ip, req.logger);
51
- const sessionMode = mode === ModeEnum.invisible ? ModeEnum.invisible : void 0;
52
- req.logger.info(() => ({
53
- msg: "Frictionless handler entry",
54
- data: {
55
- token,
56
- user,
57
- dapp,
58
- normalizedIp,
59
- ja4: req.ja4,
60
- path: req.path,
61
- method: req.method,
62
- ...sessionMode && { mode: sessionMode }
63
- }
64
- }));
65
- if (getMaintenanceMode()) {
66
- req.logger.info(() => ({
67
- msg: "Maintenance mode active - returning dummy PoW captcha session",
68
- data: { dapp, user }
69
- }));
70
- return res.json(
71
- buildFrictionlessMaintenanceResponse(
72
- CaptchaType.pow,
73
- env.config.host
74
- )
75
- );
76
- }
77
- if (isReservedTestSiteKey(dapp)) {
78
- req.logger.warn(() => ({
79
- msg: "Reserved TEST site key - returning invisible PoW session",
80
- data: { dapp, user }
81
- }));
82
- return res.json(
83
- buildFrictionlessMaintenanceResponse(
84
- CaptchaType.pow,
85
- env.config.host
86
- )
87
- );
88
- }
89
- const tasks = new Tasks(env, req.logger);
90
- const userSitekeyIpHash = hashUserIp(user, normalizedIp, dapp);
91
- const [decodedSimdReadings, { existingToken, dedup }, clientRecord] = await Promise.all([
92
- decryptIncomingSimdReadings(tasks.frictionlessManager, simdReadings),
93
- resolveSessionDedup(tasks, token, userSitekeyIpHash, req.logger),
94
- tasks.db.getClientRecord(dapp)
95
- ]);
96
- if (existingToken) {
97
- req.logger.info(() => ({
98
- token: existingToken,
99
- msg: "Token has already been used"
100
- }));
101
- return next(
102
- new ProsopoApiError("API.BAD_REQUEST", {
103
- context: { code: 400, siteKey: dapp, user },
104
- i18n: req.i18n,
105
- logger: req.logger
106
- })
107
- );
108
- }
109
- if (!clientRecord) {
110
- return next(
111
- new ProsopoApiError("API.SITE_KEY_NOT_REGISTERED", {
112
- context: { code: 400, siteKey: dapp },
113
- i18n: req.i18n,
114
- logger: req.logger
115
- })
116
- );
117
- }
118
- if (dedup) {
119
- const dedupCountryCode = req.ipInfo && "isValid" in req.ipInfo && req.ipInfo.isValid ? req.ipInfo.countryCode : void 0;
120
- const dedupAsn = req.ipInfo && "isValid" in req.ipInfo && req.ipInfo.isValid ? req.ipInfo.asnNumber : void 0;
121
- const dedupIsMobile = req.ipInfo && "isValid" in req.ipInfo && req.ipInfo.isValid ? req.ipInfo.isMobile : void 0;
122
- const dedupFlatHeaders = flatten(req.headers);
123
- const dedupUserAgent = String(req.headers["user-agent"] ?? "");
124
- const dedupUserScope = getRequestUserScope(
125
- dedupFlatHeaders,
126
- req.ja4,
127
- normalizedIp,
128
- user,
129
- void 0,
130
- void 0,
131
- dedupCountryCode,
132
- dedupAsn
133
- );
134
- const dedupAccessPolicy = (await tasks.frictionlessManager.getPrioritisedAccessPolicies(
135
- userAccessRulesStorage,
136
- dapp,
137
- dedupUserScope
138
- )).find((p) => !p.deferToVerify);
139
- const dedupConflictsWithPolicy = dedupAccessPolicy !== void 0 && (dedupAccessPolicy.type === AccessPolicyType.Block || dedupAccessPolicy.captchaType !== void 0 && dedupAccessPolicy.captchaType !== dedup.captchaType);
140
- const cachedCaptchaType = dedup.captchaType;
141
- const dedupRouted = normalizedIp ? await tasks.frictionlessManager.applyRoutingMachine(
142
- {
143
- captchaType: cachedCaptchaType,
144
- ...dedup.session.solvedImagesCount !== void 0 && {
145
- solvedImagesCount: dedup.session.solvedImagesCount
146
- },
147
- ...dedup.session.powDifficulty !== void 0 && {
148
- powDifficulty: dedup.session.powDifficulty
149
- }
150
- },
151
- {
152
- dappAccount: dapp,
153
- userAccount: user,
154
- ip: normalizedIp,
155
- ...dedupCountryCode && { countryCode: dedupCountryCode },
156
- score: dedup.session.score,
157
- platform: derivePlatform(
158
- dedupUserAgent,
159
- dedup.session.webView,
160
- {
161
- ...typeof dedupIsMobile === "boolean" && {
162
- isMobile: dedupIsMobile
163
- }
164
- }
165
- ),
166
- raw: {
167
- headers: dedupFlatHeaders,
168
- userAgent: dedupUserAgent,
169
- ...req.ja4 && { ja4: req.ja4 },
170
- // Timing values are per-connection so they come from
171
- // the current request even in the dedup replay path —
172
- // dedup.session was created on a different TCP conn.
173
- ...req.tcpToChelloUs !== void 0 && {
174
- tcpToChelloUs: req.tcpToChelloUs
175
- },
176
- ...req.chelloToHandshakeUs !== void 0 && {
177
- chelloToHandshakeUs: req.chelloToHandshakeUs
178
- },
179
- // currentUrl / iframeUrl use the cached session's
180
- // values to match the rest of the dedup routing input
181
- // (score, webView, captchaType are all pulled from
182
- // dedup).
183
- ...dedup.session.currentUrl && {
184
- currentUrl: dedup.session.currentUrl
185
- },
186
- ...dedup.session.iframeUrl && {
187
- iframeUrl: dedup.session.iframeUrl
188
- }
189
- }
190
- }
191
- ) : { captchaType: cachedCaptchaType };
192
- const dedupConflictsWithRouting = dedupRouted.captchaType !== cachedCaptchaType;
193
- if (dedupConflictsWithPolicy || dedupConflictsWithRouting) {
194
- req.logger.info(() => ({
195
- msg: "Evicting reused session: cached captchaType conflicts with access policy or routing machine",
196
- data: {
197
- userSitekeyIpHash,
198
- sessionId: dedup.sessionId,
199
- cachedCaptchaType: dedup.captchaType,
200
- ...dedupConflictsWithPolicy && {
201
- policyType: dedupAccessPolicy?.type,
202
- policyCaptchaType: dedupAccessPolicy?.captchaType
203
- },
204
- ...dedupConflictsWithRouting && {
205
- routedCaptchaType: dedupRouted.captchaType
206
- }
207
- }
208
- }));
209
- await tasks.db.checkAndRemoveSession(dedup.sessionId);
210
- await Promise.all([
211
- tasks.writeQueue?.invalidateCachedSession(dedup.sessionId) ?? Promise.resolve(),
212
- tasks.writeQueue?.invalidateCachedSessionByHash(
213
- userSitekeyIpHash
214
- ) ?? Promise.resolve()
215
- ]);
216
- } else {
217
- req.logger.info(() => ({
218
- msg: "Reusing existing session for user-IP-sitekey combination",
219
- data: {
220
- userSitekeyIpHash,
221
- sessionId: dedup.sessionId,
222
- captchaType: dedup.captchaType
223
- }
224
- }));
225
- req.logger.info(() => ({
226
- msg: "Frictionless decision",
227
- data: {
228
- decision: "reuse_session",
229
- captchaType: dedup.captchaType,
230
- sessionId: dedup.sessionId
231
- }
232
- }));
233
- recordFrictionlessDecision("reuse_session");
234
- attachHoneypot(res, clientRecord);
235
- return res.json({
236
- [ApiParams.captchaType]: dedup.captchaType,
237
- [ApiParams.sessionId]: dedup.sessionId,
238
- [ApiParams.status]: "ok",
239
- dns_url: buildDnsEventUrl(dedup.sessionId)
240
- });
241
- }
242
- }
243
- const ipAddress = getCompositeIpAddress(normalizedIp);
244
- const flatHeaders = flatten(req.headers);
245
- const countryCode = req.ipInfo && "isValid" in req.ipInfo && req.ipInfo.isValid ? req.ipInfo.countryCode : void 0;
246
- const asn = req.ipInfo && "isValid" in req.ipInfo && req.ipInfo.isValid ? req.ipInfo.asnNumber : void 0;
247
- const shortCircuitResponse = await runConfiguredCaptchaTypeShortCircuit(
248
- {
249
- tasks,
250
- env,
251
- clientRecord,
252
- token,
253
- dapp,
254
- ipAddress,
255
- ipInfo: req.ipInfo,
256
- flatHeaders,
257
- sessionMode,
258
- userSitekeyIpHash,
259
- logger: req.logger,
260
- ...req.tcpToChelloUs !== void 0 && {
261
- tcpToChelloUs: req.tcpToChelloUs
262
- },
263
- ...req.chelloToHandshakeUs !== void 0 && {
264
- chelloToHandshakeUs: req.chelloToHandshakeUs
265
- }
266
- },
267
- res
268
- );
269
- if (shortCircuitResponse) return shortCircuitResponse;
270
- const lScore = tasks.frictionlessManager.checkLangRules(
271
- req.headers["accept-language"] || ""
272
- );
273
- const userScope = getRequestUserScope(
274
- flatten(req.headers),
275
- req.ja4,
276
- normalizedIp,
277
- user,
278
- void 0,
279
- void 0,
280
- countryCode,
281
- asn
282
- );
283
- const [decryptedPayload, validation, accessPolicies] = await Promise.all([
284
- tasks.frictionlessManager.decryptPayload(token, headHash),
285
- tasks.frictionlessManager.isValidRequest(
286
- clientRecord,
287
- CaptchaType.frictionless,
288
- env
289
- ),
290
- tasks.frictionlessManager.getPrioritisedAccessPolicies(
291
- userAccessRulesStorage,
292
- dapp,
293
- userScope
294
- )
295
- ]);
296
- const {
297
- baseBotScore: rawBaseBotScore,
298
- timestamp: rawTimestamp,
299
- userId: rawUserId,
300
- userAgent: rawUserAgent,
301
- webView,
302
- iFrame,
303
- decryptedHeadHash,
304
- decryptionFailed: rawDecryptionFailed,
305
- triggeredDetectors,
306
- shadowDomPenalty,
307
- entropyMathRandomFingerprint,
308
- entropyCryptoFingerprint,
309
- entropyWallClockOffsetMs,
310
- entropyMathRandomFirst
311
- } = decryptedPayload;
312
- const detectorOverride = process.env.PROSOPO_TEST_FRICTIONLESS_DETECTOR_OVERRIDE === "1";
313
- const baseBotScore = detectorOverride ? 0 : rawBaseBotScore;
314
- const timestamp = detectorOverride ? Date.now() : rawTimestamp;
315
- const userId = detectorOverride ? req.headers["prosopo-user"] : rawUserId;
316
- const userAgent = detectorOverride ? hashUserAgent(req.headers["user-agent"] ?? "") : rawUserAgent;
317
- const decryptionFailed = detectorOverride ? false : rawDecryptionFailed;
318
- req.logger.debug(() => ({
319
- msg: "Decrypted payload",
320
- data: {
321
- baseBotScore,
322
- timestamp,
323
- userId,
324
- userAgent,
325
- webView,
326
- ...detectorOverride && { detectorOverride: true }
327
- }
328
- }));
329
- let botScore = baseBotScore + lScore;
330
- const { valid, reason } = validation;
331
- if (!valid) {
332
- return next(
333
- new ProsopoApiError(reason || "API.BAD_REQUEST", {
334
- context: { code: 400, siteKey: dapp, user },
335
- i18n: req.i18n,
336
- logger: req.logger
337
- })
338
- );
339
- }
340
- recordBotScore(botScore);
341
- if (triggeredDetectors && triggeredDetectors.length > 0) {
342
- recordDetectorTriggered(triggeredDetectors);
343
- }
344
- const botThreshold = clientRecord.settings?.frictionlessThreshold || DEFAULT_FRICTIONLESS_THRESHOLD;
345
- let scoreComponents = {
346
- baseScore: baseBotScore,
347
- ...lScore && { lScore },
348
- ...triggeredDetectors && triggeredDetectors.length > 0 && { triggeredDetectors },
349
- ...shadowDomPenalty !== void 0 && { shadowDomPenalty }
350
- };
351
- tasks.frictionlessManager.setSessionParams({
352
- token,
353
- score: botScore,
354
- threshold: botThreshold,
355
- scoreComponents,
356
- ipAddress,
357
- webView,
358
- iFrame,
359
- decryptedHeadHash,
360
- siteKey: dapp,
361
- ...currentUrl && { currentUrl },
362
- ...iframeUrl && { iframeUrl },
363
- ...isProtect && { isProtect: true },
364
- ipInfo: req.ipInfo,
365
- headers: flatHeaders,
366
- mode: sessionMode,
367
- ...decodedSimdReadings && { simdReadings: decodedSimdReadings },
368
- ...entropyMathRandomFingerprint !== void 0 && {
369
- entropyMathRandomFingerprint
370
- },
371
- ...entropyCryptoFingerprint !== void 0 && {
372
- entropyCryptoFingerprint
373
- },
374
- ...entropyWallClockOffsetMs !== void 0 && {
375
- entropyWallClockOffsetMs
376
- },
377
- ...entropyMathRandomFirst !== void 0 && {
378
- entropyMathRandomFirst
379
- },
380
- ...req.tcpToChelloUs !== void 0 && {
381
- tcpToChelloUs: req.tcpToChelloUs
382
- },
383
- ...req.chelloToHandshakeUs !== void 0 && {
384
- chelloToHandshakeUs: req.chelloToHandshakeUs
385
- }
386
- });
387
- const ipInfoMobile = req.ipInfo && "isValid" in req.ipInfo && req.ipInfo.isValid ? req.ipInfo.isMobile : void 0;
388
- const safeUserAgent = userAgent ?? "";
389
- tasks.frictionlessManager.setRoutingContext({
390
- dappAccount: dapp,
391
- userAccount: user,
392
- ip: normalizedIp,
393
- countryCode,
394
- score: botScore,
395
- platform: derivePlatform(safeUserAgent, webView, {
396
- ...typeof ipInfoMobile === "boolean" && { isMobile: ipInfoMobile }
397
- }),
398
- raw: {
399
- headers: flatHeaders,
400
- userAgent: safeUserAgent,
401
- ...req.ja4 && { ja4: req.ja4 },
402
- ...req.tcpToChelloUs !== void 0 && {
403
- tcpToChelloUs: req.tcpToChelloUs
404
- },
405
- ...req.chelloToHandshakeUs !== void 0 && {
406
- chelloToHandshakeUs: req.chelloToHandshakeUs
407
- },
408
- ...currentUrl && { currentUrl },
409
- ...iframeUrl && { iframeUrl }
410
- }
411
- });
412
- const userAccessPolicy = accessPolicies.find((p) => !p.deferToVerify);
413
- const accessPolicyOutcome = await handleAccessPolicy(
414
- {
415
- tasks,
416
- clientRecord,
417
- userAccessPolicy,
418
- baseBotScore,
419
- botScore,
420
- scoreComponents,
421
- userSitekeyIpHash,
422
- dapp,
423
- ipInfo: req.ipInfo,
424
- flatHeaders,
425
- logger: req.logger,
426
- userScope
427
- },
428
- res
429
- );
430
- if (accessPolicyOutcome.handled) return accessPolicyOutcome.response;
431
- botScore = accessPolicyOutcome.botScore;
432
- scoreComponents = accessPolicyOutcome.scoreComponents;
433
- return await runDecisionMachine(
434
- {
435
- tasks,
436
- env,
437
- clientRecord,
438
- dapp,
439
- user,
440
- userSitekeyIpHash,
441
- flatHeaders,
442
- ipInfo: req.ipInfo,
443
- timestamp,
444
- decryptionFailed,
445
- userAgent,
446
- userId,
447
- webView,
448
- decryptedHeadHash,
449
- baseBotScore,
450
- botScore,
451
- scoreComponents,
452
- token,
453
- botThreshold,
454
- currentUrl,
455
- iframeUrl
456
- },
457
- { req, res, next }
458
- );
459
- } catch (err) {
460
- req.logger.error(() => ({
461
- err,
462
- msg: "Error in frictionless captcha challenge"
463
- }));
464
- return next(
465
- new ProsopoApiError("API.BAD_REQUEST", {
466
- context: { code: 400, error: err },
467
- i18n: req.i18n,
468
- logger: req.logger
469
- })
470
- );
471
- }
472
- };
473
- export {
474
- getFrictionlessCaptchaChallenge as default
20
+ import { ProsopoApiError } from "@prosopo/common";
21
+ import { ApiParams, CaptchaType, GetFrictionlessCaptchaChallengeRequestBody, ModeEnum } from "@prosopo/types";
22
+ import { flatten, isProtectDeployment, sanitisePageUrl } from "@prosopo/util";
23
+ import { AccessPolicyType } from "@prosopo/user-access-policy";
24
+ //#region src/api/captcha/getFrictionlessCaptchaChallenge/handler.ts
25
+ var handler_default = (env, userAccessRulesStorage) => async (req, res, next) => {
26
+ try {
27
+ res.on("finish", () => {
28
+ req.logger.info(() => ({
29
+ msg: "Frictionless response finished",
30
+ data: {
31
+ status: res.statusCode,
32
+ path: req.path,
33
+ method: req.method
34
+ }
35
+ }));
36
+ });
37
+ const { token, headHash, dapp, user, mode, simdReadings, currentUrl: reportedCurrentUrl, iframeUrl: reportedIframeUrl } = GetFrictionlessCaptchaChallengeRequestBody.parse(req.body);
38
+ const currentUrl = sanitisePageUrl(reportedCurrentUrl);
39
+ const iframeUrl = sanitisePageUrl(reportedIframeUrl);
40
+ const isProtect = isProtectDeployment(currentUrl, iframeUrl);
41
+ const normalizedIp = normalizeRequestIp(req.ip, req.logger);
42
+ const sessionMode = mode === ModeEnum.invisible ? ModeEnum.invisible : void 0;
43
+ req.logger.info(() => ({
44
+ msg: "Frictionless handler entry",
45
+ data: {
46
+ token,
47
+ user,
48
+ dapp,
49
+ normalizedIp,
50
+ ja4: req.ja4,
51
+ path: req.path,
52
+ method: req.method,
53
+ ...sessionMode && { mode: sessionMode }
54
+ }
55
+ }));
56
+ if (getMaintenanceMode()) {
57
+ req.logger.info(() => ({
58
+ msg: "Maintenance mode active - returning dummy PoW captcha session",
59
+ data: {
60
+ dapp,
61
+ user
62
+ }
63
+ }));
64
+ return res.json(buildFrictionlessMaintenanceResponse(CaptchaType.pow, env.config.host));
65
+ }
66
+ if (isReservedTestSiteKey(dapp)) {
67
+ req.logger.warn(() => ({
68
+ msg: "Reserved TEST site key - returning invisible PoW session",
69
+ data: {
70
+ dapp,
71
+ user
72
+ }
73
+ }));
74
+ return res.json(buildFrictionlessMaintenanceResponse(CaptchaType.pow, env.config.host));
75
+ }
76
+ const tasks = new Tasks(env, req.logger);
77
+ const userSitekeyIpHash = hashUserIp(user, normalizedIp, dapp);
78
+ const [decodedSimdReadings, { existingToken, dedup }, clientRecord] = await Promise.all([
79
+ decryptIncomingSimdReadings(tasks.frictionlessManager, simdReadings),
80
+ resolveSessionDedup(tasks, token, userSitekeyIpHash, req.logger),
81
+ tasks.db.getClientRecord(dapp)
82
+ ]);
83
+ if (existingToken) {
84
+ req.logger.info(() => ({
85
+ token: existingToken,
86
+ msg: "Token has already been used"
87
+ }));
88
+ return next(new ProsopoApiError("API.BAD_REQUEST", {
89
+ context: {
90
+ code: 400,
91
+ siteKey: dapp,
92
+ user
93
+ },
94
+ i18n: req.i18n,
95
+ logger: req.logger
96
+ }));
97
+ }
98
+ if (!clientRecord) return next(new ProsopoApiError("API.SITE_KEY_NOT_REGISTERED", {
99
+ context: {
100
+ code: 400,
101
+ siteKey: dapp
102
+ },
103
+ i18n: req.i18n,
104
+ logger: req.logger
105
+ }));
106
+ if (dedup) {
107
+ const dedupCountryCode = req.ipInfo && "isValid" in req.ipInfo && req.ipInfo.isValid ? req.ipInfo.countryCode : void 0;
108
+ const dedupAsn = req.ipInfo && "isValid" in req.ipInfo && req.ipInfo.isValid ? req.ipInfo.asnNumber : void 0;
109
+ const dedupIsMobile = req.ipInfo && "isValid" in req.ipInfo && req.ipInfo.isValid ? req.ipInfo.isMobile : void 0;
110
+ const dedupFlatHeaders = flatten(req.headers);
111
+ const dedupUserAgent = String(req.headers["user-agent"] ?? "");
112
+ const dedupUserScope = getRequestUserScope(dedupFlatHeaders, req.ja4, normalizedIp, user, void 0, void 0, dedupCountryCode, dedupAsn);
113
+ const dedupAccessPolicy = (await tasks.frictionlessManager.getPrioritisedAccessPolicies(userAccessRulesStorage, dapp, dedupUserScope)).find((p) => !p.deferToVerify);
114
+ const dedupConflictsWithPolicy = dedupAccessPolicy !== void 0 && (dedupAccessPolicy.type === AccessPolicyType.Block || dedupAccessPolicy.captchaType !== void 0 && dedupAccessPolicy.captchaType !== dedup.captchaType);
115
+ const cachedCaptchaType = dedup.captchaType;
116
+ const dedupRouted = normalizedIp ? await tasks.frictionlessManager.applyRoutingMachine({
117
+ captchaType: cachedCaptchaType,
118
+ ...dedup.session.solvedImagesCount !== void 0 && { solvedImagesCount: dedup.session.solvedImagesCount },
119
+ ...dedup.session.powDifficulty !== void 0 && { powDifficulty: dedup.session.powDifficulty }
120
+ }, {
121
+ dappAccount: dapp,
122
+ userAccount: user,
123
+ ip: normalizedIp,
124
+ ...dedupCountryCode && { countryCode: dedupCountryCode },
125
+ score: dedup.session.score,
126
+ platform: derivePlatform(dedupUserAgent, dedup.session.webView, { ...typeof dedupIsMobile === "boolean" && { isMobile: dedupIsMobile } }),
127
+ raw: {
128
+ headers: dedupFlatHeaders,
129
+ userAgent: dedupUserAgent,
130
+ ...req.ja4 && { ja4: req.ja4 },
131
+ ...req.tcpToChelloUs !== void 0 && { tcpToChelloUs: req.tcpToChelloUs },
132
+ ...req.chelloToHandshakeUs !== void 0 && { chelloToHandshakeUs: req.chelloToHandshakeUs },
133
+ ...dedup.session.currentUrl && { currentUrl: dedup.session.currentUrl },
134
+ ...dedup.session.iframeUrl && { iframeUrl: dedup.session.iframeUrl }
135
+ }
136
+ }) : { captchaType: cachedCaptchaType };
137
+ const dedupConflictsWithRouting = dedupRouted.captchaType !== cachedCaptchaType;
138
+ if (dedupConflictsWithPolicy || dedupConflictsWithRouting) {
139
+ req.logger.info(() => ({
140
+ msg: "Evicting reused session: cached captchaType conflicts with access policy or routing machine",
141
+ data: {
142
+ userSitekeyIpHash,
143
+ sessionId: dedup.sessionId,
144
+ cachedCaptchaType: dedup.captchaType,
145
+ ...dedupConflictsWithPolicy && {
146
+ policyType: dedupAccessPolicy?.type,
147
+ policyCaptchaType: dedupAccessPolicy?.captchaType
148
+ },
149
+ ...dedupConflictsWithRouting && { routedCaptchaType: dedupRouted.captchaType }
150
+ }
151
+ }));
152
+ await tasks.db.checkAndRemoveSession(dedup.sessionId);
153
+ await Promise.all([tasks.writeQueue?.invalidateCachedSession(dedup.sessionId) ?? Promise.resolve(), tasks.writeQueue?.invalidateCachedSessionByHash(userSitekeyIpHash) ?? Promise.resolve()]);
154
+ } else {
155
+ req.logger.info(() => ({
156
+ msg: "Reusing existing session for user-IP-sitekey combination",
157
+ data: {
158
+ userSitekeyIpHash,
159
+ sessionId: dedup.sessionId,
160
+ captchaType: dedup.captchaType
161
+ }
162
+ }));
163
+ req.logger.info(() => ({
164
+ msg: "Frictionless decision",
165
+ data: {
166
+ decision: "reuse_session",
167
+ captchaType: dedup.captchaType,
168
+ sessionId: dedup.sessionId
169
+ }
170
+ }));
171
+ recordFrictionlessDecision("reuse_session");
172
+ attachHoneypot(res, clientRecord);
173
+ return res.json({
174
+ [ApiParams.captchaType]: dedup.captchaType,
175
+ [ApiParams.sessionId]: dedup.sessionId,
176
+ [ApiParams.status]: "ok",
177
+ dns_url: buildDnsEventUrl(dedup.sessionId)
178
+ });
179
+ }
180
+ }
181
+ const ipAddress = getCompositeIpAddress(normalizedIp);
182
+ const flatHeaders = flatten(req.headers);
183
+ const countryCode = req.ipInfo && "isValid" in req.ipInfo && req.ipInfo.isValid ? req.ipInfo.countryCode : void 0;
184
+ const asn = req.ipInfo && "isValid" in req.ipInfo && req.ipInfo.isValid ? req.ipInfo.asnNumber : void 0;
185
+ const shortCircuitResponse = await runConfiguredCaptchaTypeShortCircuit({
186
+ tasks,
187
+ env,
188
+ clientRecord,
189
+ token,
190
+ dapp,
191
+ ipAddress,
192
+ ipInfo: req.ipInfo,
193
+ flatHeaders,
194
+ sessionMode,
195
+ userSitekeyIpHash,
196
+ logger: req.logger,
197
+ ...req.tcpToChelloUs !== void 0 && { tcpToChelloUs: req.tcpToChelloUs },
198
+ ...req.chelloToHandshakeUs !== void 0 && { chelloToHandshakeUs: req.chelloToHandshakeUs }
199
+ }, res);
200
+ if (shortCircuitResponse) return shortCircuitResponse;
201
+ const lScore = tasks.frictionlessManager.checkLangRules(req.headers["accept-language"] || "");
202
+ const userScope = getRequestUserScope(flatten(req.headers), req.ja4, normalizedIp, user, void 0, void 0, countryCode, asn);
203
+ const [decryptedPayload, validation, accessPolicies] = await Promise.all([
204
+ tasks.frictionlessManager.decryptPayload(token, headHash),
205
+ tasks.frictionlessManager.isValidRequest(clientRecord, CaptchaType.frictionless, env),
206
+ tasks.frictionlessManager.getPrioritisedAccessPolicies(userAccessRulesStorage, dapp, userScope)
207
+ ]);
208
+ const { baseBotScore: rawBaseBotScore, timestamp: rawTimestamp, userId: rawUserId, userAgent: rawUserAgent, webView, iFrame, decryptedHeadHash, decryptionFailed: rawDecryptionFailed, triggeredDetectors, shadowDomPenalty, entropyMathRandomFingerprint, entropyCryptoFingerprint, entropyWallClockOffsetMs, entropyMathRandomFirst } = decryptedPayload;
209
+ const detectorOverride = process.env.PROSOPO_TEST_FRICTIONLESS_DETECTOR_OVERRIDE === "1";
210
+ const baseBotScore = detectorOverride ? 0 : rawBaseBotScore;
211
+ const timestamp = detectorOverride ? Date.now() : rawTimestamp;
212
+ const userId = detectorOverride ? req.headers["prosopo-user"] : rawUserId;
213
+ const userAgent = detectorOverride ? hashUserAgent(req.headers["user-agent"] ?? "") : rawUserAgent;
214
+ const decryptionFailed = detectorOverride ? false : rawDecryptionFailed;
215
+ req.logger.debug(() => ({
216
+ msg: "Decrypted payload",
217
+ data: {
218
+ baseBotScore,
219
+ timestamp,
220
+ userId,
221
+ userAgent,
222
+ webView,
223
+ ...detectorOverride && { detectorOverride: true }
224
+ }
225
+ }));
226
+ let botScore = baseBotScore + lScore;
227
+ const { valid, reason } = validation;
228
+ if (!valid) return next(new ProsopoApiError(reason || "API.BAD_REQUEST", {
229
+ context: {
230
+ code: 400,
231
+ siteKey: dapp,
232
+ user
233
+ },
234
+ i18n: req.i18n,
235
+ logger: req.logger
236
+ }));
237
+ recordBotScore(botScore);
238
+ if (triggeredDetectors && triggeredDetectors.length > 0) recordDetectorTriggered(triggeredDetectors);
239
+ const botThreshold = clientRecord.settings?.frictionlessThreshold || .5;
240
+ let scoreComponents = {
241
+ baseScore: baseBotScore,
242
+ ...lScore && { lScore },
243
+ ...triggeredDetectors && triggeredDetectors.length > 0 && { triggeredDetectors },
244
+ ...shadowDomPenalty !== void 0 && { shadowDomPenalty }
245
+ };
246
+ tasks.frictionlessManager.setSessionParams({
247
+ token,
248
+ score: botScore,
249
+ threshold: botThreshold,
250
+ scoreComponents,
251
+ ipAddress,
252
+ webView,
253
+ iFrame,
254
+ decryptedHeadHash,
255
+ siteKey: dapp,
256
+ ...currentUrl && { currentUrl },
257
+ ...iframeUrl && { iframeUrl },
258
+ ...isProtect && { isProtect: true },
259
+ ipInfo: req.ipInfo,
260
+ headers: flatHeaders,
261
+ mode: sessionMode,
262
+ ...decodedSimdReadings && { simdReadings: decodedSimdReadings },
263
+ ...entropyMathRandomFingerprint !== void 0 && { entropyMathRandomFingerprint },
264
+ ...entropyCryptoFingerprint !== void 0 && { entropyCryptoFingerprint },
265
+ ...entropyWallClockOffsetMs !== void 0 && { entropyWallClockOffsetMs },
266
+ ...entropyMathRandomFirst !== void 0 && { entropyMathRandomFirst },
267
+ ...req.tcpToChelloUs !== void 0 && { tcpToChelloUs: req.tcpToChelloUs },
268
+ ...req.chelloToHandshakeUs !== void 0 && { chelloToHandshakeUs: req.chelloToHandshakeUs }
269
+ });
270
+ const ipInfoMobile = req.ipInfo && "isValid" in req.ipInfo && req.ipInfo.isValid ? req.ipInfo.isMobile : void 0;
271
+ const safeUserAgent = userAgent ?? "";
272
+ tasks.frictionlessManager.setRoutingContext({
273
+ dappAccount: dapp,
274
+ userAccount: user,
275
+ ip: normalizedIp,
276
+ countryCode,
277
+ score: botScore,
278
+ platform: derivePlatform(safeUserAgent, webView, { ...typeof ipInfoMobile === "boolean" && { isMobile: ipInfoMobile } }),
279
+ raw: {
280
+ headers: flatHeaders,
281
+ userAgent: safeUserAgent,
282
+ ...req.ja4 && { ja4: req.ja4 },
283
+ ...req.tcpToChelloUs !== void 0 && { tcpToChelloUs: req.tcpToChelloUs },
284
+ ...req.chelloToHandshakeUs !== void 0 && { chelloToHandshakeUs: req.chelloToHandshakeUs },
285
+ ...currentUrl && { currentUrl },
286
+ ...iframeUrl && { iframeUrl }
287
+ }
288
+ });
289
+ const accessPolicyOutcome = await handleAccessPolicy({
290
+ tasks,
291
+ clientRecord,
292
+ userAccessPolicy: accessPolicies.find((p) => !p.deferToVerify),
293
+ baseBotScore,
294
+ botScore,
295
+ scoreComponents,
296
+ userSitekeyIpHash,
297
+ dapp,
298
+ ipInfo: req.ipInfo,
299
+ flatHeaders,
300
+ logger: req.logger,
301
+ userScope
302
+ }, res);
303
+ if (accessPolicyOutcome.handled) return accessPolicyOutcome.response;
304
+ botScore = accessPolicyOutcome.botScore;
305
+ scoreComponents = accessPolicyOutcome.scoreComponents;
306
+ return await runDecisionMachine({
307
+ tasks,
308
+ env,
309
+ clientRecord,
310
+ dapp,
311
+ user,
312
+ userSitekeyIpHash,
313
+ flatHeaders,
314
+ ipInfo: req.ipInfo,
315
+ timestamp,
316
+ decryptionFailed,
317
+ userAgent,
318
+ userId,
319
+ webView,
320
+ decryptedHeadHash,
321
+ baseBotScore,
322
+ botScore,
323
+ scoreComponents,
324
+ token,
325
+ botThreshold,
326
+ currentUrl,
327
+ iframeUrl
328
+ }, {
329
+ req,
330
+ res,
331
+ next
332
+ });
333
+ } catch (err) {
334
+ req.logger.error(() => ({
335
+ err,
336
+ msg: "Error in frictionless captcha challenge"
337
+ }));
338
+ return next(new ProsopoApiError("API.BAD_REQUEST", {
339
+ context: {
340
+ code: 400,
341
+ error: err
342
+ },
343
+ i18n: req.i18n,
344
+ logger: req.logger
345
+ }));
346
+ }
475
347
  };
348
+ //#endregion
349
+ export { handler_default as default };