@prosopo/provider 4.15.14 → 4.15.16

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 +63 -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,7 +1,10 @@
1
- "use strict";
2
- Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const validatePuzzleSolution = (finalX, finalY, targetX, targetY, tolerance) => {
4
- const distance = Math.sqrt((finalX - targetX) ** 2 + (finalY - targetY) ** 2);
5
- return distance <= tolerance;
1
+ //#region src/tasks/puzzleCaptcha/puzzleTasksUtils.ts
2
+ /**
3
+ * Validate that the puzzle solution is within tolerance of the target.
4
+ * Uses Euclidean distance.
5
+ */
6
+ var validatePuzzleSolution = (finalX, finalY, targetX, targetY, tolerance) => {
7
+ return Math.sqrt((finalX - targetX) ** 2 + (finalY - targetY) ** 2) <= tolerance;
6
8
  };
9
+ //#endregion
7
10
  exports.validatePuzzleSolution = validatePuzzleSolution;
@@ -1,146 +1,138 @@
1
- "use strict";
2
- Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const util = require("@prosopo/util");
4
- const dns = require("../../utils/dns.cjs");
1
+ const require_dns = require("../../utils/dns.cjs");
2
+ let _prosopo_util = require("@prosopo/util");
3
+ //#region src/tasks/spam/checkSpamEmail.ts
4
+ /**
5
+ * Extracts the domain from a URL or returns the input if it's already a domain
6
+ */
5
7
  function extractDomain(urlOrDomain) {
6
- try {
7
- const url = new URL(
8
- urlOrDomain.startsWith("http") ? urlOrDomain : `https://${urlOrDomain}`
9
- );
10
- return url.hostname;
11
- } catch {
12
- return urlOrDomain;
13
- }
8
+ try {
9
+ return new URL(urlOrDomain.startsWith("http") ? urlOrDomain : `https://${urlOrDomain}`).hostname;
10
+ } catch {
11
+ return urlOrDomain;
12
+ }
14
13
  }
14
+ /**
15
+ * Checks if an email domain is spam by checking against a spam list,
16
+ * performing DNS/redirect/TLS-related checks.
17
+ */
15
18
  async function checkSpamEmail(email, db, config, logger) {
16
- const normalizedDomain = util.extractDomainFromEmail(email);
17
- if (!normalizedDomain) {
18
- return true;
19
- }
20
- try {
21
- const record = await db.getSpamEmailDomain(normalizedDomain);
22
- if (record !== null && record !== void 0) {
23
- return true;
24
- }
25
- } catch (error) {
26
- logger.warn(() => ({
27
- msg: "Failed to check spam email domain",
28
- error
29
- }));
30
- return false;
31
- }
32
- const domainValidation = util.validateDomainForOutboundRequest(normalizedDomain);
33
- if (!domainValidation.isValid) {
34
- logger.warn(() => ({
35
- msg: "Email domain failed SSRF validation, rejecting",
36
- domain: normalizedDomain,
37
- reason: domainValidation.reason
38
- }));
39
- return true;
40
- }
41
- let dnsCheckResult = null;
42
- try {
43
- dnsCheckResult = await dns.runDnsChecks(normalizedDomain, {
44
- dnsServers: config?.dnsServers
45
- });
46
- } catch (error) {
47
- logger.warn(() => ({
48
- msg: "Failed to run DNS checks",
49
- error,
50
- domain: normalizedDomain
51
- }));
52
- return false;
53
- }
54
- if (dnsCheckResult.redirectResult.tlsError) {
55
- logger.info(() => ({
56
- msg: "Email domain apex has TLS error — observed, not treated as spam",
57
- domain: normalizedDomain
58
- }));
59
- }
60
- if (dnsCheckResult.redirectResult.redirectUrl) {
61
- const redirectUrl = dnsCheckResult.redirectResult.redirectUrl;
62
- const redirectDomain = extractDomain(redirectUrl).toLowerCase().trim();
63
- logger.info(() => ({
64
- msg: "Email domain has HTTP redirect",
65
- domain: normalizedDomain,
66
- redirectDomain
67
- }));
68
- try {
69
- const record = await db.getSpamEmailDomain(redirectDomain);
70
- if (record !== null && record !== void 0) {
71
- return true;
72
- }
73
- } catch (error) {
74
- logger.warn(() => ({
75
- msg: "Failed to check spam email domain for redirect",
76
- error,
77
- redirectDomain
78
- }));
79
- return false;
80
- }
81
- } else if (dnsCheckResult.cnameResult && dnsCheckResult.cnameResult.length > 0) {
82
- const firstCname = dnsCheckResult.cnameResult[0];
83
- if (!firstCname) {
84
- logger.warn(() => ({
85
- msg: "CNAME result array has undefined element",
86
- domain: normalizedDomain
87
- }));
88
- return false;
89
- }
90
- const cnameDomain = firstCname.replace(/\.$/, "").toLowerCase().trim();
91
- logger.info(() => ({
92
- msg: "Email domain has CNAME",
93
- domain: normalizedDomain,
94
- cnameDomain
95
- }));
96
- try {
97
- const record = await db.getSpamEmailDomain(cnameDomain);
98
- if (record !== null && record !== void 0) {
99
- return true;
100
- }
101
- } catch (error) {
102
- logger.warn(() => ({
103
- msg: "Failed to check spam email domain for CNAME",
104
- error,
105
- cnameDomain
106
- }));
107
- return false;
108
- }
109
- } else if (dnsCheckResult.mxRecordResult && dnsCheckResult.mxRecordResult.length > 0) {
110
- const firstMxRecord = dnsCheckResult.mxRecordResult[0];
111
- if (!firstMxRecord || !firstMxRecord.exchange) {
112
- logger.warn(() => ({
113
- msg: "MX record result array has undefined element or exchange",
114
- domain: normalizedDomain
115
- }));
116
- return false;
117
- }
118
- const mxDomain = firstMxRecord.exchange.replace(/\.$/, "").toLowerCase().trim();
119
- logger.info(() => ({
120
- msg: "Email domain has MX record",
121
- domain: normalizedDomain,
122
- mxDomain,
123
- priority: firstMxRecord.priority
124
- }));
125
- try {
126
- const record = await db.getSpamEmailDomain(mxDomain);
127
- if (record !== null && record !== void 0) {
128
- logger.warn(() => ({
129
- msg: "Email domain MX record points to spam domain",
130
- domain: normalizedDomain,
131
- mxDomain
132
- }));
133
- return true;
134
- }
135
- } catch (error) {
136
- logger.warn(() => ({
137
- msg: "Failed to check spam email domain for MX record",
138
- error,
139
- mxDomain
140
- }));
141
- return false;
142
- }
143
- }
144
- return false;
19
+ const normalizedDomain = (0, _prosopo_util.extractDomainFromEmail)(email);
20
+ if (!normalizedDomain) return true;
21
+ try {
22
+ const record = await db.getSpamEmailDomain(normalizedDomain);
23
+ if (record !== null && record !== void 0) return true;
24
+ } catch (error) {
25
+ logger.warn(() => ({
26
+ msg: "Failed to check spam email domain",
27
+ error
28
+ }));
29
+ return false;
30
+ }
31
+ const domainValidation = (0, _prosopo_util.validateDomainForOutboundRequest)(normalizedDomain);
32
+ if (!domainValidation.isValid) {
33
+ logger.warn(() => ({
34
+ msg: "Email domain failed SSRF validation, rejecting",
35
+ domain: normalizedDomain,
36
+ reason: domainValidation.reason
37
+ }));
38
+ return true;
39
+ }
40
+ let dnsCheckResult = null;
41
+ try {
42
+ dnsCheckResult = await require_dns.runDnsChecks(normalizedDomain, { dnsServers: config?.dnsServers });
43
+ } catch (error) {
44
+ logger.warn(() => ({
45
+ msg: "Failed to run DNS checks",
46
+ error,
47
+ domain: normalizedDomain
48
+ }));
49
+ return false;
50
+ }
51
+ if (dnsCheckResult.redirectResult.tlsError) logger.info(() => ({
52
+ msg: "Email domain apex has TLS error — observed, not treated as spam",
53
+ domain: normalizedDomain
54
+ }));
55
+ if (dnsCheckResult.redirectResult.redirectUrl) {
56
+ const redirectUrl = dnsCheckResult.redirectResult.redirectUrl;
57
+ const redirectDomain = extractDomain(redirectUrl).toLowerCase().trim();
58
+ logger.info(() => ({
59
+ msg: "Email domain has HTTP redirect",
60
+ domain: normalizedDomain,
61
+ redirectDomain
62
+ }));
63
+ try {
64
+ const record = await db.getSpamEmailDomain(redirectDomain);
65
+ if (record !== null && record !== void 0) return true;
66
+ } catch (error) {
67
+ logger.warn(() => ({
68
+ msg: "Failed to check spam email domain for redirect",
69
+ error,
70
+ redirectDomain
71
+ }));
72
+ return false;
73
+ }
74
+ } else if (dnsCheckResult.cnameResult && dnsCheckResult.cnameResult.length > 0) {
75
+ const firstCname = dnsCheckResult.cnameResult[0];
76
+ if (!firstCname) {
77
+ logger.warn(() => ({
78
+ msg: "CNAME result array has undefined element",
79
+ domain: normalizedDomain
80
+ }));
81
+ return false;
82
+ }
83
+ const cnameDomain = firstCname.replace(/\.$/, "").toLowerCase().trim();
84
+ logger.info(() => ({
85
+ msg: "Email domain has CNAME",
86
+ domain: normalizedDomain,
87
+ cnameDomain
88
+ }));
89
+ try {
90
+ const record = await db.getSpamEmailDomain(cnameDomain);
91
+ if (record !== null && record !== void 0) return true;
92
+ } catch (error) {
93
+ logger.warn(() => ({
94
+ msg: "Failed to check spam email domain for CNAME",
95
+ error,
96
+ cnameDomain
97
+ }));
98
+ return false;
99
+ }
100
+ } else if (dnsCheckResult.mxRecordResult && dnsCheckResult.mxRecordResult.length > 0) {
101
+ const firstMxRecord = dnsCheckResult.mxRecordResult[0];
102
+ if (!firstMxRecord || !firstMxRecord.exchange) {
103
+ logger.warn(() => ({
104
+ msg: "MX record result array has undefined element or exchange",
105
+ domain: normalizedDomain
106
+ }));
107
+ return false;
108
+ }
109
+ const mxDomain = firstMxRecord.exchange.replace(/\.$/, "").toLowerCase().trim();
110
+ logger.info(() => ({
111
+ msg: "Email domain has MX record",
112
+ domain: normalizedDomain,
113
+ mxDomain,
114
+ priority: firstMxRecord.priority
115
+ }));
116
+ try {
117
+ const record = await db.getSpamEmailDomain(mxDomain);
118
+ if (record !== null && record !== void 0) {
119
+ logger.warn(() => ({
120
+ msg: "Email domain MX record points to spam domain",
121
+ domain: normalizedDomain,
122
+ mxDomain
123
+ }));
124
+ return true;
125
+ }
126
+ } catch (error) {
127
+ logger.warn(() => ({
128
+ msg: "Failed to check spam email domain for MX record",
129
+ error,
130
+ mxDomain
131
+ }));
132
+ return false;
133
+ }
134
+ }
135
+ return false;
145
136
  }
137
+ //#endregion
146
138
  exports.checkSpamEmail = checkSpamEmail;
@@ -1,81 +1,123 @@
1
- "use strict";
2
- Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const types = require("@prosopo/types");
4
- const isDatacenterAllowlisted = (ipInfo, allowlist) => {
5
- if (!allowlist || allowlist.length === 0) {
6
- return false;
7
- }
8
- const candidates = [];
9
- for (const value of [
10
- ipInfo.datacenterName,
11
- ipInfo.providerName,
12
- ipInfo.asnOrganization
13
- ]) {
14
- if (typeof value !== "string") continue;
15
- const trimmed = value.trim().toLowerCase();
16
- if (trimmed) candidates.push(trimmed);
17
- }
18
- if (candidates.length === 0) {
19
- return false;
20
- }
21
- const normalisedAllowlist = allowlist.map(
22
- (entry) => entry.trim().toLowerCase()
23
- );
24
- return candidates.some((c) => normalisedAllowlist.includes(c));
1
+ let _prosopo_types = require("@prosopo/types");
2
+ //#region src/tasks/spam/checkTrafficFilter.ts
3
+ var matchesDatacenterNameList = (ipInfo, list) => {
4
+ if (!list || list.length === 0) return false;
5
+ const candidates = [];
6
+ for (const value of [
7
+ ipInfo.datacenterName,
8
+ ipInfo.providerName,
9
+ ipInfo.asnOrganization
10
+ ]) {
11
+ if (typeof value !== "string") continue;
12
+ const trimmed = value.trim().toLowerCase();
13
+ if (trimmed) candidates.push(trimmed);
14
+ }
15
+ if (candidates.length === 0) return false;
16
+ const normalisedList = list.map((entry) => entry.trim().toLowerCase());
17
+ return candidates.some((c) => normalisedList.includes(c));
25
18
  };
26
- const evaluateIpInfo = (ipInfo, trafficFilter, isDnsExtra = false) => {
27
- if (!ipInfo || !ipInfo.isValid) {
28
- return { isBlocked: false };
29
- }
30
- if (trafficFilter.blockVpn && ipInfo.isVPN) {
31
- return { isBlocked: true, reason: types.ResultReason.VPN_BLOCKED };
32
- }
33
- if (trafficFilter.blockProxy && ipInfo.isProxy) {
34
- return { isBlocked: true, reason: types.ResultReason.PROXY_BLOCKED };
35
- }
36
- if (trafficFilter.blockTor && ipInfo.isTor) {
37
- return { isBlocked: true, reason: types.ResultReason.TOR_BLOCKED };
38
- }
39
- if ((trafficFilter.blockAbuser ?? true) && ipInfo.isAbuser) {
40
- const threshold = trafficFilter.abuserScoreThreshold ?? types.trafficFilterAbuserScoreThresholdDefault;
41
- const maxScore = Math.max(
42
- ipInfo.abuserScore ?? 0,
43
- ipInfo.companyAbuserScore ?? 0
44
- );
45
- if (maxScore >= threshold) {
46
- return { isBlocked: true, reason: types.ResultReason.ABUSER_BLOCKED };
47
- }
48
- }
49
- const datacenterSuppressedByCategory = ipInfo.isVPN && !trafficFilter.blockVpn || ipInfo.isProxy && !trafficFilter.blockProxy || ipInfo.isTor && !trafficFilter.blockTor || ipInfo.isCrawler && !trafficFilter.blockCrawler;
50
- if (trafficFilter.blockDatacenter && ipInfo.isDatacenter && ipInfo.providerType !== "isp" && !datacenterSuppressedByCategory && !isDatacenterAllowlisted(ipInfo, trafficFilter.datacenterNameAllowlist)) {
51
- return { isBlocked: true, reason: types.ResultReason.DATACENTER_BLOCKED };
52
- }
53
- if (trafficFilter.blockMobile && ipInfo.isMobile) {
54
- return { isBlocked: true, reason: types.ResultReason.MOBILE_BLOCKED };
55
- }
56
- if (trafficFilter.blockSatellite && ipInfo.isSatellite) {
57
- return { isBlocked: true, reason: types.ResultReason.SATELLITE_BLOCKED };
58
- }
59
- if (!isDnsExtra && trafficFilter.blockCrawler && ipInfo.isCrawler) {
60
- return { isBlocked: true, reason: types.ResultReason.CRAWLER_BLOCKED };
61
- }
62
- return { isBlocked: false };
19
+ var isDatacenterAllowlisted = (ipInfo, allowlist) => matchesDatacenterNameList(ipInfo, allowlist);
20
+ var isDatacenterDenylisted = (ipInfo, denylist) => matchesDatacenterNameList(ipInfo, denylist);
21
+ var evaluateIpInfo = (ipInfo, trafficFilter, isDnsExtra = false) => {
22
+ if (!ipInfo || !ipInfo.isValid) return { isBlocked: false };
23
+ if (trafficFilter.blockVpn && ipInfo.isVPN) return {
24
+ isBlocked: true,
25
+ reason: _prosopo_types.ResultReason.VPN_BLOCKED
26
+ };
27
+ if (trafficFilter.blockProxy && ipInfo.isProxy) return {
28
+ isBlocked: true,
29
+ reason: _prosopo_types.ResultReason.PROXY_BLOCKED
30
+ };
31
+ if (trafficFilter.blockTor && ipInfo.isTor) return {
32
+ isBlocked: true,
33
+ reason: _prosopo_types.ResultReason.TOR_BLOCKED
34
+ };
35
+ if ((trafficFilter.blockAbuser ?? true) && ipInfo.isAbuser) {
36
+ const threshold = trafficFilter.abuserScoreThreshold ?? _prosopo_types.trafficFilterAbuserScoreThresholdDefault;
37
+ if (Math.max(ipInfo.abuserScore ?? 0, ipInfo.companyAbuserScore ?? 0) >= threshold) return {
38
+ isBlocked: true,
39
+ reason: _prosopo_types.ResultReason.ABUSER_BLOCKED
40
+ };
41
+ }
42
+ const datacenterSuppressedByCategory = ipInfo.isVPN && !trafficFilter.blockVpn || ipInfo.isProxy && !trafficFilter.blockProxy || ipInfo.isTor && !trafficFilter.blockTor || ipInfo.isCrawler && !trafficFilter.blockCrawler;
43
+ if (trafficFilter.blockDatacenter && ipInfo.isDatacenter) {
44
+ if (isDatacenterDenylisted(ipInfo, trafficFilter.datacenterNameDenylist)) return {
45
+ isBlocked: true,
46
+ reason: _prosopo_types.ResultReason.DATACENTER_BLOCKED
47
+ };
48
+ if (ipInfo.providerType !== "isp" && !datacenterSuppressedByCategory && !isDatacenterAllowlisted(ipInfo, trafficFilter.datacenterNameAllowlist)) return {
49
+ isBlocked: true,
50
+ reason: _prosopo_types.ResultReason.DATACENTER_BLOCKED
51
+ };
52
+ }
53
+ if (trafficFilter.blockMobile && ipInfo.isMobile) return {
54
+ isBlocked: true,
55
+ reason: _prosopo_types.ResultReason.MOBILE_BLOCKED
56
+ };
57
+ if (trafficFilter.blockSatellite && ipInfo.isSatellite) return {
58
+ isBlocked: true,
59
+ reason: _prosopo_types.ResultReason.SATELLITE_BLOCKED
60
+ };
61
+ if (!isDnsExtra && trafficFilter.blockCrawler && ipInfo.isCrawler) return {
62
+ isBlocked: true,
63
+ reason: _prosopo_types.ResultReason.CRAWLER_BLOCKED
64
+ };
65
+ return { isBlocked: false };
63
66
  };
64
- const checkTrafficFilter = (ipInfo, trafficFilter, extraIpInfos, dnsPathValid) => {
65
- const primary = evaluateIpInfo(ipInfo, trafficFilter);
66
- if (primary.isBlocked) {
67
- return primary;
68
- }
69
- if (trafficFilter.skipExtrasOnValidDnsPath && dnsPathValid === true) {
70
- return { isBlocked: false };
71
- }
72
- for (const extra of extraIpInfos ?? []) {
73
- const result = evaluateIpInfo(extra, trafficFilter, true);
74
- if (result.isBlocked) {
75
- return result;
76
- }
77
- }
78
- return { isBlocked: false };
67
+ /**
68
+ * Checks whether a request should be blocked based on traffic filter
69
+ * settings and the request's already-resolved IP info (attached to
70
+ * `req.ipInfo` by `ipInfoMiddleware`). Each filter (VPN, proxy, Tor,
71
+ * abuser, etc.) is evaluated independently. A missing or invalid
72
+ * `ipInfo` falls back to "not blocked" so an outage in the upstream
73
+ * service can't block all traffic.
74
+ *
75
+ * Cross-filter rule: the datacenter rule is suppressed when the IP
76
+ * carries a more specific category the operator has left unblocked —
77
+ * VPN, proxy, Tor, or crawler. All four legitimately sit on datacenter
78
+ * infrastructure, so "block datacenters" (a scraping rule) shouldn't
79
+ * catch them out the back door. Applies to primary and DNS extras.
80
+ *
81
+ * Extras-only rule: the crawler check is skipped on DNS extras. Public
82
+ * DNS resolvers share IP space with search crawlers.
83
+ *
84
+ * The datacenter rule also honours `datacenterNameAllowlist`: consumer
85
+ * relays route through datacenter ranges and are reported as
86
+ * `is_datacenter=true` by upstream but the exiting users are real humans.
87
+ * Operators can list the datacenter, provider, or ASN organisation names
88
+ * they want to allow through — see `isDatacenterAllowlisted`.
89
+ *
90
+ * The datacenter rule also short-circuits when upstream classifies the
91
+ * provider as an ISP (`providerType === "isp"`). Consumer ISPs like
92
+ * Afrihost, Comcast, or BT are sometimes flagged `is_datacenter=true` by
93
+ * upstream heuristics — usually because part of the ASN hosts B2B or
94
+ * hosting services — but the eyeball ranges behind those ASNs carry
95
+ * ordinary end-users. The ISP categorisation is stronger evidence of
96
+ * consumer traffic than the datacenter boolean.
97
+ *
98
+ * The ISP short-circuit and the allowlist are both overridden by
99
+ * `datacenterNameDenylist`: if the IP's `datacenterName`, `providerName`,
100
+ * or `asnOrganization` matches a denylist entry, the block fires. This
101
+ * lets operators opt named providers (for example IP-leasing platforms
102
+ * whose ranges are announced from carrier ASNs but exit as proxy pools)
103
+ * back into the datacenter rule.
104
+ *
105
+ * When `trafficFilter.skipExtrasOnValidDnsPath` is on and the catcher
106
+ * confirmed the DNS path matched the connection path (`pathValid: true`),
107
+ * the extras evaluation is skipped. This stops public-DoH resolver IPs
108
+ * from tripping the datacenter rule for ordinary users.
109
+ */
110
+ var checkTrafficFilter = (ipInfo, trafficFilter, extraIpInfos, dnsPathValid) => {
111
+ const primary = evaluateIpInfo(ipInfo, trafficFilter);
112
+ if (primary.isBlocked) return primary;
113
+ if (trafficFilter.skipExtrasOnValidDnsPath && dnsPathValid === true) return { isBlocked: false };
114
+ for (const extra of extraIpInfos ?? []) {
115
+ const result = evaluateIpInfo(extra, trafficFilter, true);
116
+ if (result.isBlocked) return result;
117
+ }
118
+ return { isBlocked: false };
79
119
  };
120
+ //#endregion
80
121
  exports.checkTrafficFilter = checkTrafficFilter;
81
122
  exports.isDatacenterAllowlisted = isDatacenterAllowlisted;
123
+ exports.isDatacenterDenylisted = isDatacenterDenylisted;