@prosopo/provider 4.8.1 → 4.9.0

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 (69) hide show
  1. package/.turbo/turbo-build$colon$cjs.log +15 -14
  2. package/.turbo/turbo-build$colon$tsc.log +24 -24
  3. package/.turbo/turbo-build.log +16 -15
  4. package/CHANGELOG.md +25 -0
  5. package/dist/api/admin/apiAdminRoutesProvider.d.ts.map +1 -1
  6. package/dist/api/admin/apiAdminRoutesProvider.js +4 -1
  7. package/dist/api/admin/apiAdminRoutesProvider.js.map +1 -1
  8. package/dist/api/admin/apiDnsEventEndpoint.d.ts +4 -1
  9. package/dist/api/admin/apiDnsEventEndpoint.d.ts.map +1 -1
  10. package/dist/api/admin/apiDnsEventEndpoint.js +31 -1
  11. package/dist/api/admin/apiDnsEventEndpoint.js.map +1 -1
  12. package/dist/cjs/api/admin/apiAdminRoutesProvider.cjs +4 -1
  13. package/dist/cjs/api/admin/apiDnsEventEndpoint.cjs +31 -1
  14. package/dist/cjs/pairs.cjs +14 -0
  15. package/dist/cjs/tasks/captchaManager.cjs +9 -2
  16. package/dist/cjs/tasks/dnsEvent/enrichDnsEvent.cjs +62 -0
  17. package/dist/cjs/tasks/imgCaptcha/imgCaptchaTasks.cjs +66 -33
  18. package/dist/cjs/tasks/powCaptcha/powTasks.cjs +42 -15
  19. package/dist/cjs/tasks/puzzleCaptcha/puzzleTasks.cjs +42 -15
  20. package/dist/cjs/tasks/spam/checkTrafficFilter.cjs +19 -2
  21. package/dist/cjs/tasks/tasks.cjs +1 -0
  22. package/dist/cjs/util/usageCounters.cjs +18 -1
  23. package/dist/cjs/util.cjs +11 -1
  24. package/dist/pairs.d.ts +4 -0
  25. package/dist/pairs.d.ts.map +1 -1
  26. package/dist/pairs.js +15 -1
  27. package/dist/pairs.js.map +1 -1
  28. package/dist/tasks/captchaManager.d.ts +2 -2
  29. package/dist/tasks/captchaManager.d.ts.map +1 -1
  30. package/dist/tasks/captchaManager.js +9 -2
  31. package/dist/tasks/captchaManager.js.map +1 -1
  32. package/dist/tasks/dnsEvent/enrichDnsEvent.d.ts +8 -0
  33. package/dist/tasks/dnsEvent/enrichDnsEvent.d.ts.map +1 -0
  34. package/dist/tasks/dnsEvent/enrichDnsEvent.js +62 -0
  35. package/dist/tasks/dnsEvent/enrichDnsEvent.js.map +1 -0
  36. package/dist/tasks/imgCaptcha/imgCaptchaTasks.d.ts.map +1 -1
  37. package/dist/tasks/imgCaptcha/imgCaptchaTasks.js +67 -34
  38. package/dist/tasks/imgCaptcha/imgCaptchaTasks.js.map +1 -1
  39. package/dist/tasks/powCaptcha/powTasks.d.ts.map +1 -1
  40. package/dist/tasks/powCaptcha/powTasks.js +42 -15
  41. package/dist/tasks/powCaptcha/powTasks.js.map +1 -1
  42. package/dist/tasks/puzzleCaptcha/puzzleTasks.d.ts.map +1 -1
  43. package/dist/tasks/puzzleCaptcha/puzzleTasks.js +42 -15
  44. package/dist/tasks/puzzleCaptcha/puzzleTasks.js.map +1 -1
  45. package/dist/tasks/spam/checkTrafficFilter.d.ts +1 -1
  46. package/dist/tasks/spam/checkTrafficFilter.d.ts.map +1 -1
  47. package/dist/tasks/spam/checkTrafficFilter.js +19 -2
  48. package/dist/tasks/spam/checkTrafficFilter.js.map +1 -1
  49. package/dist/tasks/tasks.d.ts +1 -0
  50. package/dist/tasks/tasks.d.ts.map +1 -1
  51. package/dist/tasks/tasks.js +1 -0
  52. package/dist/tasks/tasks.js.map +1 -1
  53. package/dist/tests/unit/pairs.unit.test.js +79 -1
  54. package/dist/tests/unit/pairs.unit.test.js.map +1 -1
  55. package/dist/tests/unit/tasks/dnsEvent/enrichDnsEvent.unit.test.d.ts +2 -0
  56. package/dist/tests/unit/tasks/dnsEvent/enrichDnsEvent.unit.test.d.ts.map +1 -0
  57. package/dist/tests/unit/tasks/dnsEvent/enrichDnsEvent.unit.test.js +94 -0
  58. package/dist/tests/unit/tasks/dnsEvent/enrichDnsEvent.unit.test.js.map +1 -0
  59. package/dist/tests/unit/tasks/spam/checkTrafficFilter.unit.test.js +68 -0
  60. package/dist/tests/unit/tasks/spam/checkTrafficFilter.unit.test.js.map +1 -1
  61. package/dist/util/usageCounters.d.ts +1 -1
  62. package/dist/util/usageCounters.d.ts.map +1 -1
  63. package/dist/util/usageCounters.js +18 -1
  64. package/dist/util/usageCounters.js.map +1 -1
  65. package/dist/util.d.ts +1 -1
  66. package/dist/util.d.ts.map +1 -1
  67. package/dist/util.js +11 -1
  68. package/dist/util.js.map +1 -1
  69. package/package.json +13 -12
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const enrichDnsEvent = async (dnsEvent, ipInfoService, primaryIp) => {
4
+ if (!dnsEvent) {
5
+ return void 0;
6
+ }
7
+ const enriched = {
8
+ peerIp: dnsEvent.peerIp,
9
+ resolverIp: dnsEvent.resolverIp,
10
+ pathValid: dnsEvent.pathValid
11
+ };
12
+ const lookups = [];
13
+ const kinds = [];
14
+ if (dnsEvent.peerIp && dnsEvent.peerIp !== primaryIp) {
15
+ lookups.push(ipInfoService.lookup(dnsEvent.peerIp));
16
+ kinds.push("peer");
17
+ }
18
+ if (dnsEvent.resolverIp && dnsEvent.resolverIp !== primaryIp) {
19
+ lookups.push(ipInfoService.lookup(dnsEvent.resolverIp));
20
+ kinds.push("resolver");
21
+ }
22
+ if (lookups.length === 0) {
23
+ return enriched;
24
+ }
25
+ const results = await Promise.all(lookups);
26
+ kinds.forEach((k, i) => {
27
+ const info = results[i];
28
+ if (!info) return;
29
+ if (k === "peer") enriched.peerIpInfo = info;
30
+ else enriched.resolverIpInfo = info;
31
+ });
32
+ return enriched;
33
+ };
34
+ const getIpInfoAsn = (info) => info?.isValid ? info.asnNumber : void 0;
35
+ const extraIpInfosFromEnrichedDnsEvent = (enriched) => {
36
+ if (!enriched) return [];
37
+ const out = [];
38
+ if (enriched.peerIpInfo) out.push(enriched.peerIpInfo);
39
+ if (enriched.resolverIpInfo) out.push(enriched.resolverIpInfo);
40
+ return out;
41
+ };
42
+ const computeDnsAsymmetry = (enriched, clientIpInfo) => {
43
+ if (!enriched) return 0;
44
+ let score = 0;
45
+ if (enriched.pathValid === false) score += 0.3;
46
+ if (enriched.resolverIpInfo?.isValid) {
47
+ if (enriched.resolverIpInfo.isDatacenter) score += 0.3;
48
+ if (enriched.resolverIpInfo.isAbuser) score += 0.2;
49
+ }
50
+ if (enriched.peerIpInfo?.isValid) {
51
+ if (enriched.peerIpInfo.isDatacenter) score += 0.2;
52
+ if (enriched.peerIpInfo.isAbuser) score += 0.2;
53
+ }
54
+ if (clientIpInfo?.isValid && clientIpInfo.providerType === "isp" && enriched.resolverIpInfo?.isValid && enriched.resolverIpInfo.isDatacenter) {
55
+ score += 0.2;
56
+ }
57
+ return Math.min(score, 1);
58
+ };
59
+ exports.computeDnsAsymmetry = computeDnsAsymmetry;
60
+ exports.enrichDnsEvent = enrichDnsEvent;
61
+ exports.extraIpInfosFromEnrichedDnsEvent = extraIpInfosFromEnrichedDnsEvent;
62
+ exports.getIpInfoAsn = getIpInfoAsn;
@@ -13,6 +13,7 @@ const util = require("../../util.cjs");
13
13
  const usageCounters = require("../../util/usageCounters.cjs");
14
14
  const captchaManager = require("../captchaManager.cjs");
15
15
  const decisionMachineRunner = require("../decisionMachine/decisionMachineRunner.cjs");
16
+ const enrichDnsEvent = require("../dnsEvent/enrichDnsEvent.cjs");
16
17
  require("../frictionless/frictionlessTasks.cjs");
17
18
  const frictionlessTasksUtils = require("../frictionless/frictionlessTasksUtils.cjs");
18
19
  const evaluateEmailSpamRules = require("../spam/evaluateEmailSpamRules.cjs");
@@ -174,8 +175,13 @@ class ImgCaptchaManager extends captchaManager.CaptchaManager {
174
175
  );
175
176
  if (pendingRequest) {
176
177
  const { storedCaptchas, receivedCaptchas, captchaIds } = await this.validateReceivedCaptchasAgainstStoredCaptchas(captchas);
177
- const flat = receivedCaptchas.map((c) => util$2.extractData(c.salt));
178
- const pairs$1 = flat.map((list) => pairs.constructPairList(list));
178
+ const rawFlat = receivedCaptchas.map((c) => util$2.extractData(c.salt));
179
+ const { checkbox: checkboxCoordPair, flat } = pairs.peelCheckboxPrefix(
180
+ rawFlat,
181
+ receivedCaptchas.map((c) => c.solution.length)
182
+ );
183
+ const shapePairs = flat.map((list) => pairs.constructPairList(list));
184
+ const pairs$1 = checkboxCoordPair ? [[checkboxCoordPair], ...shapePairs] : shapePairs;
179
185
  const { tree, commitmentId } = imgCaptchaTasksUtils.buildTreeAndGetCommitmentId(receivedCaptchas);
180
186
  const datasetId = util$2.at(storedCaptchas, 0).datasetId;
181
187
  if (!datasetId) {
@@ -555,17 +561,34 @@ class ImgCaptchaManager extends captchaManager.CaptchaManager {
555
561
  failStatus = types.ResultReason.SPAM_EMAIL_RULE;
556
562
  }
557
563
  }
564
+ const sessionRecord = solution.sessionId ? await this.db.getSessionRecordBySessionId(solution.sessionId) : void 0;
565
+ const enrichedDnsEvent = await enrichDnsEvent.enrichDnsEvent(
566
+ sessionRecord?.dnsEvent,
567
+ env.ipInfoService,
568
+ ip ?? solution.ipInfo?.ip
569
+ );
558
570
  if (!failStatus) {
559
571
  const check = await this.resolveTrafficFilterCheck(
560
572
  env,
561
573
  solution.ipInfo,
562
574
  trafficFilter,
563
- ip
575
+ ip,
576
+ enrichedDnsEvent
564
577
  );
565
578
  if (check.isBlocked) {
566
579
  this.logger.info(() => ({
567
580
  msg: "Traffic filter rejected request",
568
- data: { commitmentId, dapp, ip, reason: check.reason }
581
+ data: {
582
+ commitmentId,
583
+ dapp,
584
+ ip,
585
+ reason: check.reason,
586
+ dnsPeerIp: enrichedDnsEvent?.peerIp,
587
+ dnsResolverIp: enrichedDnsEvent?.resolverIp,
588
+ dnsPeerAsn: enrichDnsEvent.getIpInfoAsn(enrichedDnsEvent?.peerIpInfo),
589
+ dnsResolverAsn: enrichDnsEvent.getIpInfoAsn(enrichedDnsEvent?.resolverIpInfo),
590
+ dnsPathValid: enrichedDnsEvent?.pathValid
591
+ }
569
592
  }));
570
593
  commitmentUpdates.result = {
571
594
  status: types.CaptchaStatus.disapproved,
@@ -588,7 +611,8 @@ class ImgCaptchaManager extends captchaManager.CaptchaManager {
588
611
  solutionIpAddress,
589
612
  this.logger,
590
613
  env.ipInfoService,
591
- ipValidationRules
614
+ ipValidationRules,
615
+ enrichedDnsEvent?.peerIp
592
616
  );
593
617
  if (!ipValidation.isValid) {
594
618
  this.logger.error(() => ({
@@ -614,40 +638,48 @@ class ImgCaptchaManager extends captchaManager.CaptchaManager {
614
638
  "solved",
615
639
  types.CaptchaType.image,
616
640
  ipValue,
617
- solution.userAccount
641
+ solution.userAccount,
642
+ enrichedDnsEvent?.peerIp
618
643
  )
619
644
  );
620
645
  }
621
646
  let score;
622
- if (solution.sessionId) {
623
- const sessionRecord = await this.db.getSessionRecordBySessionId(
624
- solution.sessionId
647
+ if (sessionRecord) {
648
+ const dnsAsymmetry = enrichDnsEvent.computeDnsAsymmetry(
649
+ enrichedDnsEvent,
650
+ solution.ipInfo
625
651
  );
626
- if (sessionRecord) {
627
- score = frictionlessTasksUtils.computeFrictionlessScore(sessionRecord?.scoreComponents);
652
+ if (dnsAsymmetry > 0) {
653
+ sessionRecord.scoreComponents = {
654
+ ...sessionRecord.scoreComponents,
655
+ dnsAsymmetry
656
+ };
657
+ }
658
+ score = frictionlessTasksUtils.computeFrictionlessScore(sessionRecord?.scoreComponents);
659
+ this.logger.info(() => ({
660
+ data: {
661
+ scoreComponents: sessionRecord?.scoreComponents,
662
+ score,
663
+ dnsPeerAsn: enrichDnsEvent.getIpInfoAsn(enrichedDnsEvent?.peerIpInfo),
664
+ dnsResolverAsn: enrichDnsEvent.getIpInfoAsn(enrichedDnsEvent?.resolverIpInfo)
665
+ }
666
+ }));
667
+ if (!failStatus && disallowWebView === true && (sessionRecord.webView === true || (sessionRecord.scoreComponents.webView || 0) > 0)) {
628
668
  this.logger.info(() => ({
629
- data: {
630
- scoreComponents: sessionRecord?.scoreComponents,
631
- score
632
- }
669
+ msg: "Disallowing webview access - user not verified"
670
+ }));
671
+ commitmentUpdates.result = {
672
+ status: types.CaptchaStatus.disapproved,
673
+ reason: types.ResultReason.DISALLOWED_WEBVIEW
674
+ };
675
+ failStatus = types.ResultReason.DISALLOWED_WEBVIEW;
676
+ isApproved = false;
677
+ failureStatus = types.ResultReason.DISALLOWED_WEBVIEW;
678
+ }
679
+ if (contextAwareEnabled && sessionRecord.reason === types.FrictionlessReason.CONTEXT_AWARE_VALIDATION_FAILED) {
680
+ this.logger.info(() => ({
681
+ msg: "Context aware validation failed"
633
682
  }));
634
- if (!failStatus && disallowWebView === true && (sessionRecord.webView === true || (sessionRecord.scoreComponents.webView || 0) > 0)) {
635
- this.logger.info(() => ({
636
- msg: "Disallowing webview access - user not verified"
637
- }));
638
- commitmentUpdates.result = {
639
- status: types.CaptchaStatus.disapproved,
640
- reason: types.ResultReason.DISALLOWED_WEBVIEW
641
- };
642
- failStatus = types.ResultReason.DISALLOWED_WEBVIEW;
643
- isApproved = false;
644
- failureStatus = types.ResultReason.DISALLOWED_WEBVIEW;
645
- }
646
- if (contextAwareEnabled && sessionRecord.reason === types.FrictionlessReason.CONTEXT_AWARE_VALIDATION_FAILED) {
647
- this.logger.info(() => ({
648
- msg: "Context aware validation failed"
649
- }));
650
- }
651
683
  }
652
684
  }
653
685
  if (isApproved) {
@@ -657,7 +689,8 @@ class ImgCaptchaManager extends captchaManager.CaptchaManager {
657
689
  captchaResult: "passed",
658
690
  headers: solution.headers,
659
691
  captchaType: types.CaptchaType.image,
660
- countryCode: solution.ipInfo?.isValid ? solution.ipInfo.countryCode : void 0
692
+ countryCode: solution.ipInfo?.isValid ? solution.ipInfo.countryCode : void 0,
693
+ dnsEvent: enrichedDnsEvent
661
694
  };
662
695
  try {
663
696
  const decision = await this.decisionMachineRunner.decide(
@@ -9,6 +9,7 @@ const util$2 = require("../../util.cjs");
9
9
  const usageCounters = require("../../util/usageCounters.cjs");
10
10
  const captchaManager = require("../captchaManager.cjs");
11
11
  const decisionMachineRunner = require("../decisionMachine/decisionMachineRunner.cjs");
12
+ const enrichDnsEvent = require("../dnsEvent/enrichDnsEvent.cjs");
12
13
  const frictionlessTasksUtils = require("../frictionless/frictionlessTasksUtils.cjs");
13
14
  const routingMachine = require("../frictionless/routingMachine.cjs");
14
15
  const evaluateEmailSpamRules = require("../spam/evaluateEmailSpamRules.cjs");
@@ -434,17 +435,34 @@ class PowCaptchaManager extends captchaManager.CaptchaManager {
434
435
  failReason = "API.SPAM_EMAIL_RULE";
435
436
  }
436
437
  }
438
+ const sessionRecord = challengeRecord.sessionId ? await this.db.getSessionRecordBySessionId(challengeRecord.sessionId) : void 0;
439
+ const enrichedDnsEvent = await enrichDnsEvent.enrichDnsEvent(
440
+ sessionRecord?.dnsEvent,
441
+ env.ipInfoService,
442
+ ip ?? challengeRecord.ipInfo?.ip
443
+ );
437
444
  if (!failResult) {
438
445
  const check = await this.resolveTrafficFilterCheck(
439
446
  env,
440
447
  challengeRecord.ipInfo,
441
448
  trafficFilter,
442
- ip
449
+ ip,
450
+ enrichedDnsEvent
443
451
  );
444
452
  if (check.isBlocked) {
445
453
  this.logger.info(() => ({
446
454
  msg: "Traffic filter rejected request in PoW verification",
447
- data: { challenge, dappAccount, ip, reason: check.reason }
455
+ data: {
456
+ challenge,
457
+ dappAccount,
458
+ ip,
459
+ reason: check.reason,
460
+ dnsPeerIp: enrichedDnsEvent?.peerIp,
461
+ dnsResolverIp: enrichedDnsEvent?.resolverIp,
462
+ dnsPeerAsn: enrichDnsEvent.getIpInfoAsn(enrichedDnsEvent?.peerIpInfo),
463
+ dnsResolverAsn: enrichDnsEvent.getIpInfoAsn(enrichedDnsEvent?.resolverIpInfo),
464
+ dnsPathValid: enrichedDnsEvent?.pathValid
465
+ }
448
466
  }));
449
467
  failResult = {
450
468
  status: types.CaptchaStatus.disapproved,
@@ -469,7 +487,8 @@ class PowCaptchaManager extends captchaManager.CaptchaManager {
469
487
  challengeIpAddress,
470
488
  this.logger,
471
489
  env.ipInfoService,
472
- ipValidationRules
490
+ ipValidationRules,
491
+ enrichedDnsEvent?.peerIp
473
492
  );
474
493
  if (!ipValidation.isValid) {
475
494
  this.logger.error(() => ({
@@ -490,19 +509,26 @@ class PowCaptchaManager extends captchaManager.CaptchaManager {
490
509
  }
491
510
  }
492
511
  let score;
493
- if (challengeRecord.sessionId) {
494
- const sessionRecord = await this.db.getSessionRecordBySessionId(
495
- challengeRecord.sessionId
512
+ if (sessionRecord) {
513
+ const dnsAsymmetry = enrichDnsEvent.computeDnsAsymmetry(
514
+ enrichedDnsEvent,
515
+ challengeRecord.ipInfo
496
516
  );
497
- if (sessionRecord) {
498
- score = frictionlessTasksUtils.computeFrictionlessScore(sessionRecord?.scoreComponents);
499
- this.logger.info(() => ({
500
- data: {
501
- scoreComponents: { ...sessionRecord?.scoreComponents || {} },
502
- score
503
- }
504
- }));
517
+ if (dnsAsymmetry > 0) {
518
+ sessionRecord.scoreComponents = {
519
+ ...sessionRecord.scoreComponents,
520
+ dnsAsymmetry
521
+ };
505
522
  }
523
+ score = frictionlessTasksUtils.computeFrictionlessScore(sessionRecord?.scoreComponents);
524
+ this.logger.info(() => ({
525
+ data: {
526
+ scoreComponents: { ...sessionRecord?.scoreComponents || {} },
527
+ score,
528
+ dnsPeerAsn: enrichDnsEvent.getIpInfoAsn(enrichedDnsEvent?.peerIpInfo),
529
+ dnsResolverAsn: enrichDnsEvent.getIpInfoAsn(enrichedDnsEvent?.resolverIpInfo)
530
+ }
531
+ }));
506
532
  }
507
533
  if (!failResult) {
508
534
  try {
@@ -514,7 +540,8 @@ class PowCaptchaManager extends captchaManager.CaptchaManager {
514
540
  captchaType: types.CaptchaType.pow,
515
541
  behavioralDataPacked: challengeRecord.behavioralDataPacked,
516
542
  deviceCapability: challengeRecord.deviceCapability,
517
- countryCode: challengeRecord.ipInfo?.isValid ? challengeRecord.ipInfo.countryCode : void 0
543
+ countryCode: challengeRecord.ipInfo?.isValid ? challengeRecord.ipInfo.countryCode : void 0,
544
+ dnsEvent: enrichedDnsEvent
518
545
  };
519
546
  const decision = await this.decisionMachineRunner.decide(
520
547
  decisionInput,
@@ -9,6 +9,7 @@ const util$2 = require("../../util.cjs");
9
9
  const usageCounters = require("../../util/usageCounters.cjs");
10
10
  const captchaManager = require("../captchaManager.cjs");
11
11
  const decisionMachineRunner = require("../decisionMachine/decisionMachineRunner.cjs");
12
+ const enrichDnsEvent = require("../dnsEvent/enrichDnsEvent.cjs");
12
13
  const frictionlessTasksUtils = require("../frictionless/frictionlessTasksUtils.cjs");
13
14
  const powTasksUtils = require("../powCaptcha/powTasksUtils.cjs");
14
15
  const puzzleTasksUtils = require("./puzzleTasksUtils.cjs");
@@ -365,17 +366,34 @@ class PuzzleCaptchaManager extends captchaManager.CaptchaManager {
365
366
  }));
366
367
  }
367
368
  }
369
+ const sessionRecord = challengeRecord.sessionId ? await this.db.getSessionRecordBySessionId(challengeRecord.sessionId) : void 0;
370
+ const enrichedDnsEvent = await enrichDnsEvent.enrichDnsEvent(
371
+ sessionRecord?.dnsEvent,
372
+ env.ipInfoService,
373
+ ip ?? challengeRecord.ipInfo?.ip
374
+ );
368
375
  {
369
376
  const check = await this.resolveTrafficFilterCheck(
370
377
  env,
371
378
  challengeRecord.ipInfo,
372
379
  trafficFilter,
373
- ip
380
+ ip,
381
+ enrichedDnsEvent
374
382
  );
375
383
  if (check.isBlocked) {
376
384
  this.logger.info(() => ({
377
385
  msg: "Traffic filter rejected request in puzzle verification",
378
- data: { challenge, dappAccount, ip, reason: check.reason }
386
+ data: {
387
+ challenge,
388
+ dappAccount,
389
+ ip,
390
+ reason: check.reason,
391
+ dnsPeerIp: enrichedDnsEvent?.peerIp,
392
+ dnsResolverIp: enrichedDnsEvent?.resolverIp,
393
+ dnsPeerAsn: enrichDnsEvent.getIpInfoAsn(enrichedDnsEvent?.peerIpInfo),
394
+ dnsResolverAsn: enrichDnsEvent.getIpInfoAsn(enrichedDnsEvent?.resolverIpInfo),
395
+ dnsPathValid: enrichedDnsEvent?.pathValid
396
+ }
379
397
  }));
380
398
  const blockedResult = {
381
399
  status: types.CaptchaStatus.disapproved,
@@ -413,7 +431,8 @@ class PuzzleCaptchaManager extends captchaManager.CaptchaManager {
413
431
  challengeIpAddress,
414
432
  this.logger,
415
433
  env.ipInfoService,
416
- ipValidationRules
434
+ ipValidationRules,
435
+ enrichedDnsEvent?.peerIp
417
436
  );
418
437
  if (!ipValidation.isValid) {
419
438
  this.logger.error(() => ({
@@ -443,19 +462,26 @@ class PuzzleCaptchaManager extends captchaManager.CaptchaManager {
443
462
  }
444
463
  }
445
464
  let score;
446
- if (challengeRecord.sessionId) {
447
- const sessionRecord = await this.db.getSessionRecordBySessionId(
448
- challengeRecord.sessionId
465
+ if (sessionRecord) {
466
+ const dnsAsymmetry = enrichDnsEvent.computeDnsAsymmetry(
467
+ enrichedDnsEvent,
468
+ challengeRecord.ipInfo
449
469
  );
450
- if (sessionRecord) {
451
- score = frictionlessTasksUtils.computeFrictionlessScore(sessionRecord?.scoreComponents);
452
- this.logger.info(() => ({
453
- data: {
454
- scoreComponents: { ...sessionRecord?.scoreComponents || {} },
455
- score
456
- }
457
- }));
470
+ if (dnsAsymmetry > 0) {
471
+ sessionRecord.scoreComponents = {
472
+ ...sessionRecord.scoreComponents,
473
+ dnsAsymmetry
474
+ };
458
475
  }
476
+ score = frictionlessTasksUtils.computeFrictionlessScore(sessionRecord?.scoreComponents);
477
+ this.logger.info(() => ({
478
+ data: {
479
+ scoreComponents: { ...sessionRecord?.scoreComponents || {} },
480
+ score,
481
+ dnsPeerAsn: enrichDnsEvent.getIpInfoAsn(enrichedDnsEvent?.peerIpInfo),
482
+ dnsResolverAsn: enrichDnsEvent.getIpInfoAsn(enrichedDnsEvent?.resolverIpInfo)
483
+ }
484
+ }));
459
485
  }
460
486
  try {
461
487
  const decisionInput = {
@@ -466,7 +492,8 @@ class PuzzleCaptchaManager extends captchaManager.CaptchaManager {
466
492
  captchaType: types.CaptchaType.puzzle,
467
493
  behavioralDataPacked: challengeRecord.behavioralDataPacked,
468
494
  deviceCapability: challengeRecord.deviceCapability,
469
- countryCode: challengeRecord.ipInfo?.isValid ? challengeRecord.ipInfo.countryCode : void 0
495
+ countryCode: challengeRecord.ipInfo?.isValid ? challengeRecord.ipInfo.countryCode : void 0,
496
+ dnsEvent: enrichedDnsEvent
470
497
  };
471
498
  const decision = await this.decisionMachineRunner.decide(
472
499
  decisionInput,
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const types = require("@prosopo/types");
4
- const checkTrafficFilter = (ipInfo, trafficFilter) => {
4
+ const evaluateIpInfo = (ipInfo, trafficFilter, options) => {
5
5
  if (!ipInfo || !ipInfo.isValid) {
6
6
  return { isBlocked: false };
7
7
  }
@@ -24,7 +24,7 @@ const checkTrafficFilter = (ipInfo, trafficFilter) => {
24
24
  return { isBlocked: true, reason: types.ResultReason.ABUSER_BLOCKED };
25
25
  }
26
26
  }
27
- if (trafficFilter.blockDatacenter && ipInfo.isDatacenter && !(ipInfo.isVPN && !trafficFilter.blockVpn)) {
27
+ if (trafficFilter.blockDatacenter && ipInfo.isDatacenter && !(options.suppressVpnDatacenterInteraction && ipInfo.isVPN && !trafficFilter.blockVpn)) {
28
28
  return { isBlocked: true, reason: types.ResultReason.DATACENTER_BLOCKED };
29
29
  }
30
30
  if (trafficFilter.blockMobile && ipInfo.isMobile) {
@@ -38,4 +38,21 @@ const checkTrafficFilter = (ipInfo, trafficFilter) => {
38
38
  }
39
39
  return { isBlocked: false };
40
40
  };
41
+ const checkTrafficFilter = (ipInfo, trafficFilter, extraIpInfos) => {
42
+ const primary = evaluateIpInfo(ipInfo, trafficFilter, {
43
+ suppressVpnDatacenterInteraction: true
44
+ });
45
+ if (primary.isBlocked) {
46
+ return primary;
47
+ }
48
+ for (const extra of extraIpInfos ?? []) {
49
+ const result = evaluateIpInfo(extra, trafficFilter, {
50
+ suppressVpnDatacenterInteraction: false
51
+ });
52
+ if (result.isBlocked) {
53
+ return result;
54
+ }
55
+ }
56
+ return { isBlocked: false };
57
+ };
41
58
  exports.checkTrafficFilter = checkTrafficFilter;
@@ -15,6 +15,7 @@ let globalWriteQueue = null;
15
15
  let flushStarted = false;
16
16
  class Tasks {
17
17
  constructor(env, logger$1) {
18
+ this.env = env;
18
19
  this.config = env.config;
19
20
  this.db = env.getDb();
20
21
  this.captchaConfig = env.config.captchas;
@@ -160,7 +160,7 @@ class UsageCounters {
160
160
  }
161
161
  }
162
162
  }
163
- const buildAllWindowIncrements = (kind, captchaType, ip, userAccount) => {
163
+ const buildAllWindowIncrements = (kind, captchaType, ip, userAccount, peerIp) => {
164
164
  const out = [];
165
165
  for (const window of [
166
166
  "1m",
@@ -177,6 +177,12 @@ const buildAllWindowIncrements = (kind, captchaType, ip, userAccount) => {
177
177
  value: userAccount
178
178
  }
179
179
  );
180
+ if (peerIp && peerIp !== ip) {
181
+ out.push({
182
+ spec: { kind, captchaType, dimension: "peerIp", window },
183
+ value: peerIp
184
+ });
185
+ }
180
186
  if (captchaType !== "any") {
181
187
  out.push(
182
188
  {
@@ -193,6 +199,17 @@ const buildAllWindowIncrements = (kind, captchaType, ip, userAccount) => {
193
199
  value: userAccount
194
200
  }
195
201
  );
202
+ if (peerIp && peerIp !== ip) {
203
+ out.push({
204
+ spec: {
205
+ kind,
206
+ captchaType: "any",
207
+ dimension: "peerIp",
208
+ window
209
+ },
210
+ value: peerIp
211
+ });
212
+ }
196
213
  }
197
214
  }
198
215
  return out;
package/dist/cjs/util.cjs CHANGED
@@ -224,7 +224,17 @@ const evaluateIpValidationRules = (comparison, rules, logger) => {
224
224
  shouldFlag
225
225
  };
226
226
  };
227
- const deepValidateIpAddress = async (ip, challengeIpAddress, logger, ipInfoService, ipValidationRules) => {
227
+ const deepValidateIpAddress = async (ip, challengeIpAddress, logger, ipInfoService, ipValidationRules, dnsPeerIp) => {
228
+ if (ipValidationRules?.forceConsistentIp === true && dnsPeerIp && dnsPeerIp !== ip) {
229
+ logger.info(() => ({
230
+ msg: "IP validation failed - dnsEvent.peerIp does not match client IP",
231
+ data: { clientIp: ip, dnsPeerIp }
232
+ }));
233
+ return {
234
+ isValid: false,
235
+ errorMessage: `Client IP ${ip} does not match dnsEvent.peerIp ${dnsPeerIp}`
236
+ };
237
+ }
228
238
  const standardValidation = validateIpAddress(ip, challengeIpAddress, logger);
229
239
  if (!standardValidation.isValid) {
230
240
  if (standardValidation.errorMessage?.includes("Invalid IP address")) {
package/dist/pairs.d.ts CHANGED
@@ -1,3 +1,7 @@
1
1
  export declare const constructPairList: (list: number[]) => [number, number][];
2
+ export declare const peelCheckboxPrefix: (flat: number[][], solutionLengths: number[]) => {
3
+ checkbox?: [number, number];
4
+ flat: number[][];
5
+ };
2
6
  export declare const containsIdenticalPairs: (pairsLists: [number, number][][]) => boolean;
3
7
  //# sourceMappingURL=pairs.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"pairs.d.ts","sourceRoot":"","sources":["../src/pairs.ts"],"names":[],"mappings":"AAmBA,eAAO,MAAM,iBAAiB,SAAU,MAAM,EAAE,KAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAWlE,CAAC;AAMF,eAAO,MAAM,sBAAsB,eAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,EAAE,YActE,CAAC"}
1
+ {"version":3,"file":"pairs.d.ts","sourceRoot":"","sources":["../src/pairs.ts"],"names":[],"mappings":"AAmBA,eAAO,MAAM,iBAAiB,SAAU,MAAM,EAAE,KAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAWlE,CAAC;AAEF,eAAO,MAAM,kBAAkB,SACxB,MAAM,EAAE,EAAE,mBACC,MAAM,EAAE,KACvB;IAAE,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,EAAE,CAAA;CAYjD,CAAC;AAMF,eAAO,MAAM,sBAAsB,eAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,EAAE,YActE,CAAC"}
package/dist/pairs.js CHANGED
@@ -9,6 +9,19 @@ const constructPairList = (list) => {
9
9
  }
10
10
  return pairList;
11
11
  };
12
+ const peelCheckboxPrefix = (flat, solutionLengths) => {
13
+ const firstFlat = flat[0];
14
+ const firstLen = solutionLengths[0];
15
+ if (firstFlat === void 0 || firstLen === void 0) {
16
+ return { flat };
17
+ }
18
+ if (firstFlat.length === 2 * firstLen + 2) {
19
+ const checkbox = [at(firstFlat, 0), at(firstFlat, 1)];
20
+ const stripped = [firstFlat.slice(2), ...flat.slice(1)];
21
+ return { checkbox, flat: stripped };
22
+ }
23
+ return { flat };
24
+ };
12
25
  const containsIdenticalPairs = (pairsLists) => {
13
26
  const set = /* @__PURE__ */ new Set();
14
27
  for (const pairList of pairsLists) {
@@ -23,5 +36,6 @@ const containsIdenticalPairs = (pairsLists) => {
23
36
  };
24
37
  export {
25
38
  constructPairList,
26
- containsIdenticalPairs
39
+ containsIdenticalPairs,
40
+ peelCheckboxPrefix
27
41
  };
package/dist/pairs.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"pairs.js","sourceRoot":"","sources":["../src/pairs.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,EAAE,EAAE,MAAM,eAAe,CAAC;AAKnC,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,IAAc,EAAsB,EAAE;IAEvE,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IACzC,CAAC;IAED,MAAM,QAAQ,GAAuB,EAAE,CAAC;IACxC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACzC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/C,CAAC;IACD,OAAO,QAAQ,CAAC;AACjB,CAAC,CAAC;AAMF,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,UAAgC,EAAE,EAAE;IAC1E,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAC;IAE9B,KAAK,MAAM,QAAQ,IAAI,UAAU,EAAE,CAAC;QACnC,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;YAC7B,MAAM,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;YACtB,MAAM,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;YACtB,MAAM,WAAW,GAAG,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAChC,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACtB,CAAC;IACF,CAAC;IAGD,OAAO,GAAG,CAAC,IAAI,KAAK,UAAU,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;AACzD,CAAC,CAAC"}
1
+ {"version":3,"file":"pairs.js","sourceRoot":"","sources":["../src/pairs.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,EAAE,EAAE,MAAM,eAAe,CAAC;AAKnC,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,IAAc,EAAsB,EAAE;IAEvE,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IACzC,CAAC;IAED,MAAM,QAAQ,GAAuB,EAAE,CAAC;IACxC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACzC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/C,CAAC;IACD,OAAO,QAAQ,CAAC;AACjB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CACjC,IAAgB,EAChB,eAAyB,EAC2B,EAAE;IACtD,MAAM,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IAC1B,MAAM,QAAQ,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC;IACpC,IAAI,SAAS,KAAK,SAAS,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QACvD,OAAO,EAAE,IAAI,EAAE,CAAC;IACjB,CAAC;IACD,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,GAAG,QAAQ,GAAG,CAAC,EAAE,CAAC;QAC3C,MAAM,QAAQ,GAAqB,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC;QACxE,MAAM,QAAQ,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QACxD,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IACrC,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,CAAC;AACjB,CAAC,CAAC;AAMF,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,UAAgC,EAAE,EAAE;IAC1E,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAC;IAE9B,KAAK,MAAM,QAAQ,IAAI,UAAU,EAAE,CAAC;QACnC,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;YAC7B,MAAM,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;YACtB,MAAM,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;YACtB,MAAM,WAAW,GAAG,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAChC,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACtB,CAAC;IACF,CAAC;IAGD,OAAO,GAAG,CAAC,IAAI,KAAK,UAAU,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;AACzD,CAAC,CAAC"}
@@ -1,7 +1,7 @@
1
1
  import type { RedisWriteQueue } from "@prosopo/database";
2
2
  import type { TranslationKey } from "@prosopo/locale";
3
3
  import { type Logger } from "@prosopo/logger";
4
- import { type CaptchaType, type IPInfoResponse, type ITrafficFilter, type KeyringPair, type ProsopoConfigOutput, type RequestHeaders, type Session, type SimdReadingsStage, Tier, type UserCommitment } from "@prosopo/types";
4
+ import { type CaptchaType, type EnrichedDnsEvent, type IPInfoResponse, type ITrafficFilter, type KeyringPair, type ProsopoConfigOutput, type RequestHeaders, type Session, type SimdReadingsStage, Tier, type UserCommitment } from "@prosopo/types";
5
5
  import type { ClientRecord, IProviderDatabase, IUserDataSlim, PoWCaptchaRecord, PuzzleCaptchaRecord } from "@prosopo/types-database";
6
6
  import type { ProviderEnvironment } from "@prosopo/types-env";
7
7
  import { type AccessPolicy, type AccessRulesStorage, type UserScope, type UserScopeRecord } from "@prosopo/user-access-policy";
@@ -46,7 +46,7 @@ export declare class CaptchaManager {
46
46
  decryptBehavioralData(encryptedData: string, decryptKeys: (string | undefined)[]): Promise<BehavioralDataResult | null>;
47
47
  checkForHardBlock(userAccessRulesStorage: AccessRulesStorage, challengeRecord: PoWCaptchaRecord | PuzzleCaptchaRecord | UserCommitment, userAccount: string, headers: RequestHeaders, coords?: [number, number][][], countryCode?: string, asn?: number): Promise<AccessPolicy | undefined>;
48
48
  checkSpamEmail(email: string): Promise<boolean>;
49
- resolveTrafficFilterCheck(env: ProviderEnvironment, recordIpInfo: IPInfoResponse | undefined, trafficFilter: Partial<ITrafficFilter> | undefined, currentIp?: string): Promise<TrafficCheckResult>;
49
+ resolveTrafficFilterCheck(env: ProviderEnvironment, recordIpInfo: IPInfoResponse | undefined, trafficFilter: Partial<ITrafficFilter> | undefined, currentIp?: string, enrichedDnsEvent?: EnrichedDnsEvent): Promise<TrafficCheckResult>;
50
50
  static canClientSeeScore(tier: Tier, score?: number): boolean | 0 | undefined;
51
51
  }
52
52
  //# sourceMappingURL=captchaManager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"captchaManager.d.ts","sourceRoot":"","sources":["../../src/tasks/captchaManager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"captchaManager.d.ts","sourceRoot":"","sources":["../../src/tasks/captchaManager.ts"],"names":[],"mappings":"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"}
@@ -3,6 +3,7 @@ import { ResultReason, Tier, ApiParams } from "@prosopo/types";
3
3
  import { AccessPolicyType } from "@prosopo/user-access-policy";
4
4
  import { getPrioritisedAccessRule, getRequestUserScope } from "../api/blacklistRequestInspector.js";
5
5
  import { getIpAddressFromComposite } from "../compositeIpAddress.js";
6
+ import { extraIpInfosFromEnrichedDnsEvent } from "./dnsEvent/enrichDnsEvent.js";
6
7
  import { checkSpamEmail } from "./spam/checkSpamEmail.js";
7
8
  import { checkTrafficFilter } from "./spam/checkTrafficFilter.js";
8
9
  const findHardBlockPolicy = (accessPolicies) => {
@@ -397,6 +398,8 @@ class CaptchaManager {
397
398
  * - If the dapp's server passed up the end user's current IP via the
398
399
  * verify call, look that up fresh — it's the "now" IP for filtering
399
400
  * and may differ from the IP that originally requested the captcha.
401
+ * - When the session carries a `dnsEvent`, its `peerIp` and `resolverIp`
402
+ * are enriched and passed alongside the primary IP.
400
403
  * - `blockAbuser` defaults to true so abusive networks are always
401
404
  * blocked even when the site hasn't configured a trafficFilter.
402
405
  * - Returns `{ isBlocked: false }` if every filter flag is off, without
@@ -406,14 +409,18 @@ class CaptchaManager {
406
409
  * updates record / session state differently); this helper just returns
407
410
  * the verdict.
408
411
  */
409
- async resolveTrafficFilterCheck(env, recordIpInfo, trafficFilter, currentIp) {
412
+ async resolveTrafficFilterCheck(env, recordIpInfo, trafficFilter, currentIp, enrichedDnsEvent) {
410
413
  const effective = { blockAbuser: true, ...trafficFilter };
411
414
  const hasAny = Object.values(effective).some((v) => v);
412
415
  if (!hasAny) {
413
416
  return { isBlocked: false };
414
417
  }
415
418
  const ipInfo = currentIp ? await env.ipInfoService.lookup(currentIp) : recordIpInfo;
416
- return checkTrafficFilter(ipInfo, effective);
419
+ return checkTrafficFilter(
420
+ ipInfo,
421
+ effective,
422
+ extraIpInfosFromEnrichedDnsEvent(enrichedDnsEvent)
423
+ );
417
424
  }
418
425
  static canClientSeeScore(tier, score) {
419
426
  return score && tier && tier !== Tier.Free;