@prosopo/provider 4.15.14 → 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 (232) 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 +49 -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/spam/checkTrafficFilter.unit.test.js +140 -0
  219. package/dist/tests/unit/tasks/spam/checkTrafficFilter.unit.test.js.map +1 -1
  220. package/dist/tests/unit/testUtils/mockProviderEnv.d.ts +7 -7
  221. package/dist/util/usageCounters.js +220 -212
  222. package/dist/util.d.ts.map +1 -1
  223. package/dist/util.js +327 -364
  224. package/dist/util.js.map +1 -1
  225. package/dist/utils/devicePlatform.js +15 -9
  226. package/dist/utils/dns.js +64 -77
  227. package/dist/utils/hashUserAgent.js +14 -7
  228. package/dist/utils/hashUserIp.js +14 -6
  229. package/dist/utils/honeypot/encoders.js +74 -80
  230. package/dist/utils/honeypot/phraseBank.js +49 -44
  231. package/dist/utils/normalizeRequestIp.js +34 -26
  232. package/package.json +24 -24
@@ -1,391 +1,303 @@
1
- "use strict";
2
- Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const node_crypto = require("node:crypto");
4
- const types = require("@prosopo/types");
5
- const userAccessPolicy = require("@prosopo/user-access-policy");
6
- const compositeIpAddress = require("../compositeIpAddress.cjs");
7
- const hardBlockVerdictCache = require("./hardBlockVerdictCache.cjs");
8
- const metrics = require("./metrics.cjs");
9
- const getRequestUserScope = (requestHeaders, ja4, ip, user, headHash, coords, countryCode, asn) => {
10
- const userAgent = requestHeaders["user-agent"] ? requestHeaders["user-agent"].toString() : void 0;
11
- return {
12
- ...user && { userId: user },
13
- ...ja4 && { ja4Hash: ja4 },
14
- ...userAgent && { userAgent },
15
- ...ip && { ip },
16
- ...headHash && { headHash },
17
- ...coords && { coords },
18
- ...countryCode && { countryCode },
19
- ...typeof asn === "number" && { asn },
20
- // Always populated (even "unknown") — derived from the request UA, not
21
- // trusted from a client hint. Present unconditionally so an OS
22
- // allow-list (block everything not on the list) still matches requests
23
- // whose UA we can't classify.
24
- os: userAccessPolicy.classifyOs(userAgent)
25
- };
1
+ const require_compositeIpAddress = require("../compositeIpAddress.cjs");
2
+ const require_hardBlockVerdictCache = require("./hardBlockVerdictCache.cjs");
3
+ const require_metrics = require("./metrics.cjs");
4
+ let _prosopo_types = require("@prosopo/types");
5
+ let node_crypto = require("node:crypto");
6
+ let _prosopo_user_access_policy = require("@prosopo/user-access-policy");
7
+ //#region src/api/blacklistRequestInspector.ts
8
+ var getRequestUserScope = (requestHeaders, ja4, ip, user, headHash, coords, countryCode, asn) => {
9
+ const userAgent = requestHeaders["user-agent"] ? requestHeaders["user-agent"].toString() : void 0;
10
+ return {
11
+ ...user && { userId: user },
12
+ ...ja4 && { ja4Hash: ja4 },
13
+ ...userAgent && { userAgent },
14
+ ...ip && { ip },
15
+ ...headHash && { headHash },
16
+ ...coords && { coords },
17
+ ...countryCode && { countryCode },
18
+ ...typeof asn === "number" && { asn },
19
+ os: (0, _prosopo_user_access_policy.classifyOs)(userAgent)
20
+ };
26
21
  };
27
- const SCALAR_USER_SCOPE_FIELDS = [
28
- "userId",
29
- "ja4Hash",
30
- "headersHash",
31
- "userAgentHash",
32
- "headHash",
33
- "coords",
34
- "countryCode",
35
- "asn",
36
- "os"
22
+ var SCALAR_USER_SCOPE_FIELDS = [
23
+ "userId",
24
+ "ja4Hash",
25
+ "headersHash",
26
+ "userAgentHash",
27
+ "headHash",
28
+ "coords",
29
+ "countryCode",
30
+ "asn",
31
+ "os"
37
32
  ];
38
- const deriveRuleType = (rule) => {
39
- const fields = [];
40
- for (const f of SCALAR_USER_SCOPE_FIELDS) {
41
- if (rule[f] !== void 0) {
42
- fields.push(f);
43
- }
44
- }
45
- if (rule.numericIp !== void 0) {
46
- fields.push("ip");
47
- } else if (rule.numericIpMaskMin !== void 0 && rule.numericIpMaskMax !== void 0) {
48
- fields.push("ipMask");
49
- }
50
- return fields;
33
+ var deriveRuleType = (rule) => {
34
+ const fields = [];
35
+ for (const f of SCALAR_USER_SCOPE_FIELDS) if (rule[f] !== void 0) fields.push(f);
36
+ if (rule.numericIp !== void 0) fields.push("ip");
37
+ else if (rule.numericIpMaskMin !== void 0 && rule.numericIpMaskMax !== void 0) fields.push("ipMask");
38
+ return fields;
51
39
  };
52
- const sanitizeRequestHeaders = (headers) => {
53
- const out = {};
54
- for (const [k, v] of Object.entries(headers)) {
55
- if (typeof v === "string") {
56
- out[k] = v;
57
- } else if (Array.isArray(v)) {
58
- out[k] = v.map((x) => String(x)).join(", ");
59
- }
60
- }
61
- return out;
40
+ var sanitizeRequestHeaders = (headers) => {
41
+ const out = {};
42
+ for (const [k, v] of Object.entries(headers)) if (typeof v === "string") out[k] = v;
43
+ else if (Array.isArray(v)) out[k] = v.map((x) => String(x)).join(", ");
44
+ return out;
62
45
  };
63
- const ruleHasIpConstraint = (rule) => rule.numericIp !== void 0 || rule.numericIpMaskMin !== void 0 && rule.numericIpMaskMax !== void 0;
64
- const ruleIpMatchesRequest = (rule, requestIp) => {
65
- if (!ruleHasIpConstraint(rule)) {
66
- return true;
67
- }
68
- if (requestIp === void 0) {
69
- return false;
70
- }
71
- if (rule.numericIp !== void 0) {
72
- return requestIp === rule.numericIp;
73
- }
74
- return requestIp >= rule.numericIpMaskMin && requestIp <= rule.numericIpMaskMax;
46
+ var ruleHasIpConstraint = (rule) => rule.numericIp !== void 0 || rule.numericIpMaskMin !== void 0 && rule.numericIpMaskMax !== void 0;
47
+ var ruleIpMatchesRequest = (rule, requestIp) => {
48
+ if (!ruleHasIpConstraint(rule)) return true;
49
+ if (requestIp === void 0) return false;
50
+ if (rule.numericIp !== void 0) return requestIp === rule.numericIp;
51
+ return requestIp >= rule.numericIpMaskMin && requestIp <= rule.numericIpMaskMax;
75
52
  };
76
- const ruleApplies = (rule, request, requestClientId) => {
77
- if (rule.clientId !== void 0 && rule.clientId !== requestClientId) {
78
- return false;
79
- }
80
- for (const field of SCALAR_USER_SCOPE_FIELDS) {
81
- const ruleValue = rule[field];
82
- if (ruleValue === void 0) {
83
- continue;
84
- }
85
- if (ruleValue !== request[field]) {
86
- return false;
87
- }
88
- }
89
- return ruleIpMatchesRequest(rule, request.numericIp);
53
+ var ruleApplies = (rule, request, requestClientId) => {
54
+ if (rule.clientId !== void 0 && rule.clientId !== requestClientId) return false;
55
+ for (const field of SCALAR_USER_SCOPE_FIELDS) {
56
+ const ruleValue = rule[field];
57
+ if (ruleValue === void 0) continue;
58
+ if (ruleValue !== request[field]) return false;
59
+ }
60
+ return ruleIpMatchesRequest(rule, request.numericIp);
90
61
  };
91
- const ruleSpecificity = (rule, requestClientId) => {
92
- let score = 0;
93
- if (rule.clientId !== void 0 && rule.clientId === requestClientId) {
94
- score += 1;
95
- }
96
- for (const field of SCALAR_USER_SCOPE_FIELDS) {
97
- if (rule[field] !== void 0) {
98
- score += 1;
99
- }
100
- }
101
- if (ruleHasIpConstraint(rule)) {
102
- score += 1;
103
- }
104
- return score;
62
+ var ruleSpecificity = (rule, requestClientId) => {
63
+ let score = 0;
64
+ if (rule.clientId !== void 0 && rule.clientId === requestClientId) score += 1;
65
+ for (const field of SCALAR_USER_SCOPE_FIELDS) if (rule[field] !== void 0) score += 1;
66
+ if (ruleHasIpConstraint(rule)) score += 1;
67
+ return score;
105
68
  };
106
- const CAPTCHA_TYPE_HARSHNESS = {
107
- [types.CaptchaType.image]: 30,
108
- [types.CaptchaType.puzzle]: 20,
109
- [types.CaptchaType.pow]: 10,
110
- // Frictionless isn't a routing target for Restrict rules but include it
111
- // so the Record is total over CaptchaType — keeps the type-checker honest
112
- // if the enum grows. Restrict-with-frictionless wouldn't make operational
113
- // sense and ranks at the bottom of the captcha tiers if it ever appears.
114
- [types.CaptchaType.frictionless]: 0
69
+ var CAPTCHA_TYPE_HARSHNESS = {
70
+ [_prosopo_types.CaptchaType.image]: 30,
71
+ [_prosopo_types.CaptchaType.puzzle]: 20,
72
+ [_prosopo_types.CaptchaType.pow]: 10,
73
+ [_prosopo_types.CaptchaType.frictionless]: 0
115
74
  };
116
- const ruleHarshness = (rule) => {
117
- if (rule.type === userAccessPolicy.AccessPolicyType.Block) {
118
- return Number.MAX_SAFE_INTEGER;
119
- }
120
- if (rule.captchaType === void 0) {
121
- return 0;
122
- }
123
- const base = CAPTCHA_TYPE_HARSHNESS[rule.captchaType];
124
- const rounds = rule.solvedImagesCount ?? 0;
125
- return base + rounds;
75
+ var ruleHarshness = (rule) => {
76
+ if (rule.type === _prosopo_user_access_policy.AccessPolicyType.Block) return Number.MAX_SAFE_INTEGER;
77
+ if (rule.captchaType === void 0) return 0;
78
+ return CAPTCHA_TYPE_HARSHNESS[rule.captchaType] + (rule.solvedImagesCount ?? 0);
126
79
  };
127
- const rankCandidateRules = (rules, request, requestClientId) => rules.filter((rule) => ruleApplies(rule, request, requestClientId)).sort((a, b) => {
128
- const specDelta = ruleSpecificity(b, requestClientId) - ruleSpecificity(a, requestClientId);
129
- if (specDelta !== 0) {
130
- return specDelta;
131
- }
132
- return ruleHarshness(b) - ruleHarshness(a);
80
+ /**
81
+ * Rank the candidate rules a single Redis query returned. A rule "applies" iff
82
+ * every populated field on the rule equals the corresponding request field
83
+ * (IP fields use range semantics).
84
+ *
85
+ * Ordering: specificity DESC primary, harshness DESC as the equal-specificity
86
+ * tiebreaker (issue #3713). The most specific applicable rule wins; on tie,
87
+ * the harshest matching rule wins — Block > Restrict[image, rounds DESC] >
88
+ * Restrict[puzzle] > Restrict[pow]. Client-scoped rules outrank global rules
89
+ * of equal user-scope specificity.
90
+ */
91
+ var rankCandidateRules = (rules, request, requestClientId) => rules.filter((rule) => ruleApplies(rule, request, requestClientId)).sort((a, b) => {
92
+ const specDelta = ruleSpecificity(b, requestClientId) - ruleSpecificity(a, requestClientId);
93
+ if (specDelta !== 0) return specDelta;
94
+ return ruleHarshness(b) - ruleHarshness(a);
133
95
  });
134
- const verdictCache = new hardBlockVerdictCache.HardBlockVerdictCache();
135
- const getVerdictCache = () => verdictCache;
136
- const REQUEST_MEMO_SYMBOL = Symbol.for("prosopo.accessRuleRequestMemo");
137
- const getOrCreateRequestMemo = (requestMemoHost) => {
138
- let memo = requestMemoHost[REQUEST_MEMO_SYMBOL];
139
- if (memo === void 0) {
140
- memo = /* @__PURE__ */ new Map();
141
- requestMemoHost[REQUEST_MEMO_SYMBOL] = memo;
142
- }
143
- return memo;
96
+ /**
97
+ * Fetch the access rules that apply to a request, most specific first.
98
+ *
99
+ * Evolution of this lookup:
100
+ *
101
+ * - Original: 2 × (2^n − 1) `FT.SEARCH` round trips, one per non-empty
102
+ * subset of the populated user-scope fields × {clientId, undefined}.
103
+ * n=6 fields ⇒ 126 RTTs per request.
104
+ * - #2657 (greedy): one OR-of-fields `FT.SEARCH`, JS-side rank picks
105
+ * the most-specific. 1 RTT but pulled hundreds of irrelevant hashes
106
+ * every request.
107
+ * - #2689 / 3.6.38: greedy + FT.AGGREGATE+CURSOR to defeat the silent
108
+ * 1000-cap truncation. Tipped CPU into 125% peg in production.
109
+ * - 3.6.38.1 hotfix: reverted to greedy + FT.SEARCH (this file's old
110
+ * shape with the truncation bug back).
111
+ * - Now (this fix): strict-match query so every returned candidate
112
+ * actually applies, with specificity ranked server-side via
113
+ * FT.AGGREGATE+APPLY+SORTBY+LIMIT in the storage layer. Node receives
114
+ * at most 20 already-ranked rules — no JS sort needed for
115
+ * correctness, but `rankCandidateRules` is kept as defence so any
116
+ * mismatch between the Redis-side score and the JS semantics surfaces
117
+ * as ordering rather than letting traffic through.
118
+ */
119
+ var verdictCache = new require_hardBlockVerdictCache.HardBlockVerdictCache();
120
+ var getVerdictCache = () => verdictCache;
121
+ var REQUEST_MEMO_SYMBOL = Symbol.for("prosopo.accessRuleRequestMemo");
122
+ var getOrCreateRequestMemo = (requestMemoHost) => {
123
+ let memo = requestMemoHost[REQUEST_MEMO_SYMBOL];
124
+ if (memo === void 0) {
125
+ memo = /* @__PURE__ */ new Map();
126
+ requestMemoHost[REQUEST_MEMO_SYMBOL] = memo;
127
+ }
128
+ return memo;
144
129
  };
145
- const getPrioritisedAccessRule = async (userAccessRulesStorage, userScope, clientId, options) => {
146
- const parsedUserScope = userAccessPolicy.userScopeInput.parse(userScope);
147
- const blockOnly = options?.blockOnly ?? false;
148
- const skipCache = options?.skipCache ?? false;
149
- const requestMemoHost = options?.requestMemoHost;
150
- const cacheKey = hardBlockVerdictCache.hardBlockCacheKey(clientId, parsedUserScope, blockOnly);
151
- const requestMemo = requestMemoHost ? getOrCreateRequestMemo(requestMemoHost) : void 0;
152
- if (requestMemo !== void 0) {
153
- const memoHit = requestMemo.get(cacheKey);
154
- if (memoHit !== void 0) {
155
- return memoHit;
156
- }
157
- }
158
- const filter = {
159
- ...clientId && {
160
- policyScope: {
161
- clientId
162
- }
163
- },
164
- policyScopeMatch: userAccessPolicy.FilterScopeMatch.Greedy,
165
- userScope: parsedUserScope,
166
- userScopeMatch: userAccessPolicy.FilterScopeMatch.Greedy,
167
- ...blockOnly && { blockOnly: true }
168
- };
169
- const compute = async () => {
170
- const candidates = await userAccessRulesStorage.findRules(
171
- filter,
172
- true,
173
- // matchingFieldsOnly — engages the split-query hot path
174
- true
175
- );
176
- return rankCandidateRules(candidates, parsedUserScope, clientId);
177
- };
178
- let ranked;
179
- if (skipCache) {
180
- ranked = await compute();
181
- } else {
182
- ranked = await verdictCache.getOrCompute(cacheKey, compute);
183
- }
184
- requestMemo?.set(cacheKey, ranked);
185
- return ranked;
130
+ var getPrioritisedAccessRule = async (userAccessRulesStorage, userScope, clientId, options) => {
131
+ const parsedUserScope = _prosopo_user_access_policy.userScopeInput.parse(userScope);
132
+ const blockOnly = options?.blockOnly ?? false;
133
+ const skipCache = options?.skipCache ?? false;
134
+ const requestMemoHost = options?.requestMemoHost;
135
+ const cacheKey = require_hardBlockVerdictCache.hardBlockCacheKey(clientId, parsedUserScope, blockOnly);
136
+ const requestMemo = requestMemoHost ? getOrCreateRequestMemo(requestMemoHost) : void 0;
137
+ if (requestMemo !== void 0) {
138
+ const memoHit = requestMemo.get(cacheKey);
139
+ if (memoHit !== void 0) return memoHit;
140
+ }
141
+ const filter = {
142
+ ...clientId && { policyScope: { clientId } },
143
+ policyScopeMatch: _prosopo_user_access_policy.FilterScopeMatch.Greedy,
144
+ userScope: parsedUserScope,
145
+ userScopeMatch: _prosopo_user_access_policy.FilterScopeMatch.Greedy,
146
+ ...blockOnly && { blockOnly: true }
147
+ };
148
+ const compute = async () => {
149
+ return rankCandidateRules(await userAccessRulesStorage.findRules(filter, true, true), parsedUserScope, clientId);
150
+ };
151
+ let ranked;
152
+ if (skipCache) ranked = await compute();
153
+ else ranked = await verdictCache.getOrCompute(cacheKey, compute);
154
+ requestMemo?.set(cacheKey, ranked);
155
+ return ranked;
186
156
  };
187
- class BlacklistRequestInspector {
188
- constructor(userAccessRulesStorage, environmentReadinessWaiter, db) {
189
- this.userAccessRulesStorage = userAccessRulesStorage;
190
- this.environmentReadinessWaiter = environmentReadinessWaiter;
191
- this.db = db;
192
- }
193
- async abortRequestForBlockedUsers(request, res, next) {
194
- const rawIp = request.ip || "";
195
- request.logger.debug(() => ({
196
- data: { ja4: request.ja4 }
197
- }));
198
- const shouldAbortRequest = await this.shouldAbortRequest(
199
- request.url,
200
- rawIp,
201
- request.ja4,
202
- request.headers,
203
- request.body,
204
- request.logger,
205
- request.ipInfo,
206
- // Share the per-request memo so a downstream captcha task
207
- // hitting checkForHardBlock in the same request reuses this
208
- // lookup rather than re-querying Redis.
209
- request
210
- );
211
- if (shouldAbortRequest) {
212
- res.status(403).json({ error: "Forbidden" });
213
- return;
214
- }
215
- next();
216
- }
217
- async shouldAbortRequest(requestedRoute, rawIp, ja4, requestHeaders, requestBody, logger, ipInfo, requestMemoHost) {
218
- if (this.isApiUnrelatedRoute(requestedRoute)) {
219
- return false;
220
- }
221
- if (!rawIp) {
222
- logger.info(() => ({
223
- data: {
224
- requestedRoute,
225
- requestHeaders,
226
- requestBody
227
- },
228
- msg: "Request without IP"
229
- }));
230
- metrics.recordBlockedRequest("no_ip");
231
- return true;
232
- }
233
- await this.environmentReadinessWaiter();
234
- try {
235
- const { userId, clientId } = this.extractIdsFromRequest(
236
- requestHeaders,
237
- requestBody
238
- );
239
- const countryCode = ipInfo?.isValid ? ipInfo.countryCode : void 0;
240
- const asn = ipInfo?.isValid ? ipInfo.asnNumber : void 0;
241
- const accessPolicies = await getPrioritisedAccessRule(
242
- this.userAccessRulesStorage,
243
- getRequestUserScope(
244
- requestHeaders,
245
- ja4,
246
- rawIp,
247
- userId,
248
- void 0,
249
- // headHash
250
- void 0,
251
- // coords
252
- countryCode,
253
- asn
254
- ),
255
- clientId,
256
- // Request-time middleware only ever fires on Block policies
257
- // (Restrict rules flow through and let the captcha-creation
258
- // path decorate the response). Restrict the Redis-side
259
- // candidate pool so the SERVER_SIDE_RANK_TOP_N cap can't
260
- // crowd out hard-block rules in clients with dense Restrict
261
- // rule populations.
262
- { blockOnly: true, requestMemoHost }
263
- );
264
- const enforceable = (accessPolicies ?? []).filter(
265
- (p) => !p.deferToVerify
266
- );
267
- if (enforceable.length === 0 || !enforceable[0]) {
268
- return false;
269
- }
270
- const accessPolicy = enforceable[0];
271
- const isBlock = userAccessPolicy.AccessPolicyType.Block === accessPolicy.type;
272
- if (isBlock) {
273
- metrics.recordBlockedRequest("access_policy");
274
- this.recordBlockDecision(
275
- accessPolicy,
276
- {
277
- userId,
278
- clientId,
279
- rawIp,
280
- ja4,
281
- requestHeaders,
282
- ipInfo,
283
- countryCode,
284
- asn
285
- },
286
- logger
287
- );
288
- }
289
- return isBlock;
290
- } catch (err) {
291
- logger.error(() => ({
292
- err,
293
- msg: "Block Middleware Error"
294
- }));
295
- metrics.recordBlockedRequest("error");
296
- return true;
297
- }
298
- }
299
- /**
300
- * Emit a structured log line and (if a DB is wired) persist a synthetic
301
- * Session record for the request we're about to block (403). Fire-and-forget on
302
- * the Mongo side — the structured log line is the source of truth and
303
- * the 403 response is never delayed by a persistence failure.
304
- *
305
- * Carries the matched rule's identity (hash + ruleType + description)
306
- * so the Traffic page can surface "what's blocking traffic for this
307
- * site" without re-reading the rules collection.
308
- */
309
- recordBlockDecision(accessPolicy, ctx, logger) {
310
- const ruleHash = userAccessPolicy.makeAccessRuleHash(accessPolicy);
311
- const ruleType = deriveRuleType(accessPolicy);
312
- const ruleDescription = accessPolicy.description;
313
- const userAgent = typeof ctx.requestHeaders["user-agent"] === "string" ? ctx.requestHeaders["user-agent"] : void 0;
314
- logger.info(() => ({
315
- msg: "Access policy block",
316
- data: {
317
- ruleHash,
318
- ruleType,
319
- ruleDescription,
320
- policyType: accessPolicy.type,
321
- clientId: ctx.clientId,
322
- userScope: {
323
- userId: ctx.userId,
324
- ja4: ctx.ja4,
325
- ip: ctx.rawIp,
326
- userAgent,
327
- countryCode: ctx.countryCode,
328
- asn: ctx.asn,
329
- os: userAccessPolicy.classifyOs(userAgent)
330
- }
331
- }
332
- }));
333
- if (!this.db) {
334
- return;
335
- }
336
- const ipAddress = ctx.rawIp ? compositeIpAddress.getCompositeIpAddress(ctx.rawIp) : void 0;
337
- if (!ipAddress) {
338
- return;
339
- }
340
- const headers = sanitizeRequestHeaders(ctx.requestHeaders);
341
- const session = {
342
- sessionId: `blocked-${node_crypto.randomUUID()}`,
343
- createdAt: /* @__PURE__ */ new Date(),
344
- // Sentinel values for schema-required fields the blocked request
345
- // never reached the point of populating.
346
- token: "",
347
- score: 1,
348
- threshold: 0,
349
- scoreComponents: { baseScore: 1 },
350
- captchaType: types.CaptchaType.frictionless,
351
- webView: false,
352
- iFrame: false,
353
- decryptedHeadHash: "",
354
- // Real data the inspector did collect.
355
- siteKey: ctx.clientId,
356
- ipAddress,
357
- ipInfo: ctx.ipInfo,
358
- headers,
359
- reason: types.FrictionlessReason.ACCESS_POLICY_BLOCK,
360
- result: {
361
- status: types.CaptchaStatus.disapproved,
362
- reason: types.ResultReason.ACCESS_POLICY_BLOCK
363
- },
364
- // Rule identity — the whole point of writing this record.
365
- ruleHash,
366
- ruleType,
367
- ruleDescription
368
- // blocked + deleted are stamped inside storeBlockedSession so
369
- // the synthetic record is unmistakably a block-middleware
370
- // artefact and can never be picked up by the captcha flow.
371
- };
372
- void this.db.storeBlockedSession(session);
373
- }
374
- isApiUnrelatedRoute(url) {
375
- return !url.includes(types.ApiPrefix);
376
- }
377
- extractIdsFromRequest(requestHeaders, requestBody) {
378
- const userId = this.getObjectValue(requestHeaders, "Prosopo-User") || this.getObjectValue(requestBody, "user");
379
- const clientId = this.getObjectValue(requestHeaders, "Prosopo-Site-Key") || this.getObjectValue(requestBody, "dapp");
380
- return {
381
- userId: "string" === typeof userId ? userId : void 0,
382
- clientId: "string" === typeof clientId ? clientId : void 0
383
- };
384
- }
385
- getObjectValue(object, key) {
386
- return object[key];
387
- }
388
- }
157
+ var BlacklistRequestInspector = class {
158
+ constructor(userAccessRulesStorage, environmentReadinessWaiter, db) {
159
+ this.userAccessRulesStorage = userAccessRulesStorage;
160
+ this.environmentReadinessWaiter = environmentReadinessWaiter;
161
+ this.db = db;
162
+ }
163
+ async abortRequestForBlockedUsers(request, res, next) {
164
+ const rawIp = request.ip || "";
165
+ request.logger.debug(() => ({ data: { ja4: request.ja4 } }));
166
+ if (await this.shouldAbortRequest(request.url, rawIp, request.ja4, request.headers, request.body, request.logger, request.ipInfo, request)) {
167
+ res.status(403).json({ error: "Forbidden" });
168
+ return;
169
+ }
170
+ next();
171
+ }
172
+ async shouldAbortRequest(requestedRoute, rawIp, ja4, requestHeaders, requestBody, logger, ipInfo, requestMemoHost) {
173
+ if (this.isApiUnrelatedRoute(requestedRoute)) return false;
174
+ if (!rawIp) {
175
+ logger.info(() => ({
176
+ data: {
177
+ requestedRoute,
178
+ requestHeaders,
179
+ requestBody
180
+ },
181
+ msg: "Request without IP"
182
+ }));
183
+ require_metrics.recordBlockedRequest("no_ip");
184
+ return true;
185
+ }
186
+ await this.environmentReadinessWaiter();
187
+ try {
188
+ const { userId, clientId } = this.extractIdsFromRequest(requestHeaders, requestBody);
189
+ const countryCode = ipInfo?.isValid ? ipInfo.countryCode : void 0;
190
+ const asn = ipInfo?.isValid ? ipInfo.asnNumber : void 0;
191
+ const enforceable = (await getPrioritisedAccessRule(this.userAccessRulesStorage, getRequestUserScope(requestHeaders, ja4, rawIp, userId, void 0, void 0, countryCode, asn), clientId, {
192
+ blockOnly: true,
193
+ requestMemoHost
194
+ }) ?? []).filter((p) => !p.deferToVerify);
195
+ if (enforceable.length === 0 || !enforceable[0]) return false;
196
+ const accessPolicy = enforceable[0];
197
+ const isBlock = _prosopo_user_access_policy.AccessPolicyType.Block === accessPolicy.type;
198
+ if (isBlock) {
199
+ require_metrics.recordBlockedRequest("access_policy");
200
+ this.recordBlockDecision(accessPolicy, {
201
+ userId,
202
+ clientId,
203
+ rawIp,
204
+ ja4,
205
+ requestHeaders,
206
+ ipInfo,
207
+ countryCode,
208
+ asn
209
+ }, logger);
210
+ }
211
+ return isBlock;
212
+ } catch (err) {
213
+ logger.error(() => ({
214
+ err,
215
+ msg: "Block Middleware Error"
216
+ }));
217
+ require_metrics.recordBlockedRequest("error");
218
+ return true;
219
+ }
220
+ }
221
+ /**
222
+ * Emit a structured log line and (if a DB is wired) persist a synthetic
223
+ * Session record for the request we're about to block (403). Fire-and-forget on
224
+ * the Mongo side — the structured log line is the source of truth and
225
+ * the 403 response is never delayed by a persistence failure.
226
+ *
227
+ * Carries the matched rule's identity (hash + ruleType + description)
228
+ * so the Traffic page can surface "what's blocking traffic for this
229
+ * site" without re-reading the rules collection.
230
+ */
231
+ recordBlockDecision(accessPolicy, ctx, logger) {
232
+ const ruleHash = (0, _prosopo_user_access_policy.makeAccessRuleHash)(accessPolicy);
233
+ const ruleType = deriveRuleType(accessPolicy);
234
+ const ruleDescription = accessPolicy.description;
235
+ const userAgent = typeof ctx.requestHeaders["user-agent"] === "string" ? ctx.requestHeaders["user-agent"] : void 0;
236
+ logger.info(() => ({
237
+ msg: "Access policy block",
238
+ data: {
239
+ ruleHash,
240
+ ruleType,
241
+ ruleDescription,
242
+ policyType: accessPolicy.type,
243
+ clientId: ctx.clientId,
244
+ userScope: {
245
+ userId: ctx.userId,
246
+ ja4: ctx.ja4,
247
+ ip: ctx.rawIp,
248
+ userAgent,
249
+ countryCode: ctx.countryCode,
250
+ asn: ctx.asn,
251
+ os: (0, _prosopo_user_access_policy.classifyOs)(userAgent)
252
+ }
253
+ }
254
+ }));
255
+ if (!this.db) return;
256
+ const ipAddress = ctx.rawIp ? require_compositeIpAddress.getCompositeIpAddress(ctx.rawIp) : void 0;
257
+ if (!ipAddress) return;
258
+ const headers = sanitizeRequestHeaders(ctx.requestHeaders);
259
+ const session = {
260
+ sessionId: `blocked-${(0, node_crypto.randomUUID)()}`,
261
+ createdAt: /* @__PURE__ */ new Date(),
262
+ token: "",
263
+ score: 1,
264
+ threshold: 0,
265
+ scoreComponents: { baseScore: 1 },
266
+ captchaType: _prosopo_types.CaptchaType.frictionless,
267
+ webView: false,
268
+ iFrame: false,
269
+ decryptedHeadHash: "",
270
+ siteKey: ctx.clientId,
271
+ ipAddress,
272
+ ipInfo: ctx.ipInfo,
273
+ headers,
274
+ reason: _prosopo_types.FrictionlessReason.ACCESS_POLICY_BLOCK,
275
+ result: {
276
+ status: _prosopo_types.CaptchaStatus.disapproved,
277
+ reason: _prosopo_types.ResultReason.ACCESS_POLICY_BLOCK
278
+ },
279
+ ruleHash,
280
+ ruleType,
281
+ ruleDescription
282
+ };
283
+ this.db.storeBlockedSession(session);
284
+ }
285
+ isApiUnrelatedRoute(url) {
286
+ return !url.includes(_prosopo_types.ApiPrefix);
287
+ }
288
+ extractIdsFromRequest(requestHeaders, requestBody) {
289
+ const userId = this.getObjectValue(requestHeaders, "Prosopo-User") || this.getObjectValue(requestBody, "user");
290
+ const clientId = this.getObjectValue(requestHeaders, "Prosopo-Site-Key") || this.getObjectValue(requestBody, "dapp");
291
+ return {
292
+ userId: "string" === typeof userId ? userId : void 0,
293
+ clientId: "string" === typeof clientId ? clientId : void 0
294
+ };
295
+ }
296
+ getObjectValue(object, key) {
297
+ return object[key];
298
+ }
299
+ };
300
+ //#endregion
389
301
  exports.BlacklistRequestInspector = BlacklistRequestInspector;
390
302
  exports.getPrioritisedAccessRule = getPrioritisedAccessRule;
391
303
  exports.getRequestUserScope = getRequestUserScope;