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