@slicedearth/whoisleuth-cli 1.43.0 → 1.47.4

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 (153) hide show
  1. package/DISCLOSURE +7 -3
  2. package/NOTICE +5 -4
  3. package/README.md +67 -10
  4. package/bin/whoisleuth.mjs +22 -9
  5. package/cli/arguments.mjs +256 -9
  6. package/cli/artifact-structure.mjs +1833 -0
  7. package/cli/artifact-verify.mjs +242 -49
  8. package/cli/bounded-json.mjs +1 -0
  9. package/cli/bulk-checkpoint.mjs +67 -31
  10. package/cli/bulk-command-runner.mjs +16 -6
  11. package/cli/bulk.mjs +18 -7
  12. package/cli/case-pack.mjs +819 -34
  13. package/cli/command-reference.mjs +48 -24
  14. package/cli/completion.mjs +50 -11
  15. package/cli/config-profile.mjs +15 -12
  16. package/cli/ct-event-intake.mjs +32 -2
  17. package/cli/discovery-observation-snapshot.mjs +8 -14
  18. package/cli/discovery-scan-command-runner.mjs +18 -6
  19. package/cli/discovery-snapshot.mjs +8 -15
  20. package/cli/discovery-workflow.mjs +2 -3
  21. package/cli/doctor.mjs +2 -2
  22. package/cli/domain-control-monitor.mjs +21 -15
  23. package/cli/domain-control-observations.mjs +25 -2
  24. package/cli/errors.mjs +7 -1
  25. package/cli/evidence-command-runner.mjs +17 -11
  26. package/cli/evidence-signing.mjs +73 -45
  27. package/cli/export-evidence.mjs +11 -4
  28. package/cli/formatters/html.mjs +3 -3
  29. package/cli/formatters/json.mjs +12 -4
  30. package/cli/formatters/terminal.mjs +4 -1
  31. package/cli/http.mjs +2 -1
  32. package/cli/input.mjs +57 -0
  33. package/cli/interchange-report.mjs +226 -0
  34. package/cli/investigation-manifest.mjs +16 -17
  35. package/cli/investigation-run.mjs +71 -23
  36. package/cli/local-mmdb-review.mjs +45 -14
  37. package/cli/lookup-command-runner.mjs +2 -2
  38. package/cli/lookup-diff.mjs +9 -0
  39. package/cli/lookup-reconcile.mjs +1 -1
  40. package/cli/mail-review.mjs +5 -5
  41. package/cli/manual.mjs +1 -1
  42. package/cli/network-command-runner.mjs +78 -0
  43. package/cli/offline-evidence-review.mjs +28 -8
  44. package/cli/page-compare.mjs +8 -5
  45. package/cli/registry-cohort.mjs +385 -61
  46. package/cli/registry-fixture-scaffold.mjs +4 -3
  47. package/cli/registry-support.mjs +2 -1
  48. package/cli/retained-artifact-diff.mjs +376 -0
  49. package/cli/risk-calibration.mjs +7 -5
  50. package/cli/runner.mjs +150 -177
  51. package/cli/saved-lookup.mjs +26 -3
  52. package/cli/sharing-review.mjs +12 -6
  53. package/docs/cli-reference.md +467 -74
  54. package/docs/cli.md +25 -5
  55. package/frontend/src/lib/analysis/acquisition-decision-packet.js +4 -4
  56. package/frontend/src/lib/analysis/acquisition-due-diligence.js +1 -1
  57. package/frontend/src/lib/analysis/artifact-integrity.js +42 -0
  58. package/frontend/src/lib/analysis/brand-profile-model.js +33 -7
  59. package/frontend/src/lib/analysis/bulk-domain-comparison.js +25 -5
  60. package/frontend/src/lib/analysis/bulk-mail-exposure.js +66 -15
  61. package/frontend/src/lib/analysis/bulk-retry-plan.js +1 -1
  62. package/frontend/src/lib/analysis/bulk-review-export.js +7 -6
  63. package/frontend/src/lib/analysis/bulk-review-model.js +3 -2
  64. package/frontend/src/lib/analysis/bulk-session-model.js +192 -26
  65. package/frontend/src/lib/analysis/bulk-sort.js +4 -0
  66. package/frontend/src/lib/analysis/case-brand-profile-references.js +85 -0
  67. package/frontend/src/lib/analysis/case-evidence-model.js +9 -1
  68. package/frontend/src/lib/analysis/case-investigation-branch-model.js +134 -0
  69. package/frontend/src/lib/analysis/case-migration-model.js +83 -31
  70. package/frontend/src/lib/analysis/case-record-contracts.js +4 -2
  71. package/frontend/src/lib/analysis/case-record-core.js +1 -1
  72. package/frontend/src/lib/analysis/case-record-model.js +2 -0
  73. package/frontend/src/lib/analysis/case-record-operations.js +43 -13
  74. package/frontend/src/lib/analysis/case-report.js +39 -6
  75. package/frontend/src/lib/analysis/case-response-model.js +66 -7
  76. package/frontend/src/lib/analysis/case-response-packet.js +15 -5
  77. package/frontend/src/lib/analysis/comparison-ledger-bulk.js +366 -0
  78. package/frontend/src/lib/analysis/comparison-ledger-contract.js +241 -0
  79. package/frontend/src/lib/analysis/comparison-ledger-json.js +79 -0
  80. package/frontend/src/lib/analysis/comparison-ledger-serialization.js +51 -0
  81. package/frontend/src/lib/analysis/domain-control-manifest-core.js +145 -0
  82. package/frontend/src/lib/analysis/domain-control-records.js +88 -0
  83. package/frontend/src/lib/analysis/external-findings-import.js +70 -6
  84. package/frontend/src/lib/analysis/investigation-capsule.js +47 -13
  85. package/frontend/src/lib/analysis/investigation-guide.js +52 -10
  86. package/frontend/src/lib/analysis/investigation-template-model.js +9 -6
  87. package/frontend/src/lib/analysis/lookup-asset-graph.js +8 -8
  88. package/frontend/src/lib/analysis/lookup-claim-passport.js +236 -0
  89. package/frontend/src/lib/analysis/lookup-claim-readiness.js +280 -0
  90. package/frontend/src/lib/analysis/lookup-decision-support.js +63 -8
  91. package/frontend/src/lib/analysis/lookup-presentation.js +70 -14
  92. package/frontend/src/lib/analysis/lookup-source-refresh.js +36 -63
  93. package/frontend/src/lib/analysis/opaque-reference-id.js +9 -0
  94. package/frontend/src/lib/analysis/utils.js +27 -4
  95. package/frontend/src/lib/analysis/visualization-matrix.js +71 -28
  96. package/frontend/src/lib/analysis/visualization-models.js +63 -94
  97. package/frontend/src/lib/analysis/visualization-time-series.js +53 -12
  98. package/frontend/src/lib/analysis/website-snapshot-model.js +6 -0
  99. package/frontend/src/lib/analysis/workspace-archive-crypto.js +1 -4
  100. package/frontend/src/lib/analysis/workspace-archive.js +105 -19
  101. package/lib/application-version.mjs +3 -0
  102. package/lib/availability.mjs +14 -12
  103. package/lib/bounded-file.mjs +82 -0
  104. package/lib/bounded-json-response.mjs +170 -0
  105. package/lib/bounded-json.mjs +249 -0
  106. package/lib/browser-library-profile.mjs +167 -38
  107. package/lib/certificate-extension-profile.mjs +2 -1
  108. package/lib/cryptographic-assurance.mjs +155 -0
  109. package/lib/ct-search.mjs +87 -47
  110. package/lib/dns-intelligence.mjs +3 -2
  111. package/lib/dns-resolver-selection.mjs +6 -4
  112. package/lib/dnssec-chain-validation.mjs +1053 -0
  113. package/lib/dnssec-evidence-validation.mjs +10 -3
  114. package/lib/domain-change-packet.mjs +7 -5
  115. package/lib/domain-control-manifest.mjs +17 -129
  116. package/lib/domain-posture.mjs +7 -4
  117. package/lib/evidence-export.mjs +751 -78
  118. package/lib/evidence-report-markdown.mjs +3 -0
  119. package/lib/evidence-report.mjs +5 -0
  120. package/lib/favicon.mjs +8 -5
  121. package/lib/http-evidence-bounds.mjs +3 -0
  122. package/lib/http-intelligence.mjs +2 -5
  123. package/lib/interchange-fidelity-registry.mjs +122 -0
  124. package/lib/local-geoip-evidence.mjs +2 -1
  125. package/lib/lookup-cache.mjs +5 -1
  126. package/lib/lookup-network-evidence-bounds.mjs +9 -0
  127. package/lib/lookup-response-contract.mjs +691 -3
  128. package/lib/lookup.mjs +2 -2
  129. package/lib/observation.mjs +7 -6
  130. package/lib/outbound-identity.mjs +2 -3
  131. package/lib/perceptual-hash.mjs +12 -4
  132. package/lib/portable-generator.mjs +21 -0
  133. package/lib/provider-policy-admission.mjs +9 -4
  134. package/lib/rdap-normalization.mjs +18 -5
  135. package/lib/rdap-registrar.mjs +5 -1
  136. package/lib/rdap-transport.mjs +6 -6
  137. package/lib/registry-capabilities.mjs +3 -0
  138. package/lib/registry-capability-catalogue.mjs +12 -2
  139. package/lib/registry-comparison.mjs +28 -11
  140. package/lib/risk-calibration-summary.mjs +338 -0
  141. package/lib/rpki-evidence.mjs +9 -8
  142. package/lib/safe-fetch.mjs +96 -42
  143. package/lib/security-txt.mjs +26 -3
  144. package/lib/service-binding-dns.mjs +6 -1
  145. package/lib/smtp-transport-review.mjs +784 -0
  146. package/lib/sslbl-certificates.generated.mjs +136 -134
  147. package/lib/threat-intelligence-runtime.mjs +4 -13
  148. package/lib/threat-intelligence-types.mjs +18 -1
  149. package/lib/tls-intelligence.mjs +11 -5
  150. package/lib/tlsa-evidence.mjs +37 -7
  151. package/lib/website-technology.mjs +2 -6
  152. package/package.json +1 -1
  153. package/third-party-notices.txt +95 -5817
@@ -1,4 +1,6 @@
1
1
  import { Buffer } from 'node:buffer';
2
+ import { classifyQuery } from "../lib/classify.mjs";
3
+ import { scanBoundedJson } from "../lib/bounded-json.mjs";
2
4
  import { CliUsageError } from "./arguments.mjs";
3
5
  const MAX_SAVED_LOOKUP_INPUT_BYTES = 8 * 1024 * 1024;
4
6
  const MAX_SAVED_LOOKUP_STRING_LENGTH = 1024;
@@ -46,9 +48,21 @@ function parseSavedLookupDocument(text, options = {}) {
46
48
  if (Buffer.byteLength(text, 'utf8') > MAX_SAVED_LOOKUP_INPUT_BYTES) {
47
49
  throw new CliUsageError(`${label} is limited to ${MAX_SAVED_LOOKUP_INPUT_BYTES} bytes.`);
48
50
  }
51
+ const normalized = text.replace(/^\uFEFF/, '');
52
+ try {
53
+ scanBoundedJson(normalized);
54
+ }
55
+ catch (cause) {
56
+ const detail = cause instanceof Error ? cause.message : '';
57
+ if (detail === 'Artefact input is not valid JSON.') {
58
+ throw new CliUsageError(`${label} must be valid JSON.`);
59
+ }
60
+ const boundedDetail = detail.replace(/^Artefact JSON /u, '');
61
+ throw new CliUsageError(boundedDetail ? `${label} ${boundedDetail}` : `${label} must be valid JSON.`);
62
+ }
49
63
  let parsed;
50
64
  try {
51
- parsed = JSON.parse(text.replace(/^\uFEFF/, ''));
65
+ parsed = JSON.parse(normalized);
52
66
  }
53
67
  catch {
54
68
  throw new CliUsageError(`${label} must be valid JSON.`);
@@ -64,8 +78,17 @@ function parseSavedLookupDocument(text, options = {}) {
64
78
  if (document.mode !== 'fast' && document.mode !== 'deep') {
65
79
  throw new CliUsageError(`${label} has an unsupported lookup mode.`);
66
80
  }
67
- requiredBoundedString(document.query, 'query');
68
- requiredBoundedString(document.registrableDomain, 'registrableDomain');
81
+ const query = requiredBoundedString(document.query, 'query');
82
+ const registrableDomain = requiredBoundedString(document.registrableDomain, 'registrableDomain');
83
+ try {
84
+ const classified = classifyQuery(query);
85
+ if (classified.type !== 'domain' || classified.registrableDomain !== registrableDomain.toLowerCase().replace(/\.$/u, '')) {
86
+ throw new Error('Saved query does not match its declared registrable domain.');
87
+ }
88
+ }
89
+ catch {
90
+ throw new CliUsageError('query must identify the declared registrable domain.');
91
+ }
69
92
  requiredBoundedString(document.generatedAt, 'generatedAt');
70
93
  const diagnostics = objectOrNull(document.diagnostics);
71
94
  const rdapDiagnostics = objectOrNull(diagnostics?.rdap);
@@ -1,6 +1,6 @@
1
- import { UnsupportedOfflineArtifactError, verifyOfflineArtifact, } from "./artifact-verify.mjs";
1
+ import { hasVerifiedWholeArtifactIntegrity, UnsupportedOfflineArtifactError, verifyOfflineArtifact, } from "./artifact-verify.mjs";
2
2
  const SHARING_REVIEW_SCHEMA = 'whoisleuth.cli.sharing-review';
3
- const SHARING_REVIEW_VERSION = 1;
3
+ const SHARING_REVIEW_VERSION = 2;
4
4
  const MAX_SHARING_REVIEW_BYTES = 15 * 1024 * 1024;
5
5
  const TLP_MARKINGS = ['clear', 'green', 'amber', 'amber-strict', 'red'];
6
6
  const RECIPIENT_SCOPES = ['public', 'community', 'organization', 'named-recipients'];
@@ -103,7 +103,11 @@ async function buildSharingReview(raw, options, generatedAt = new Date().toISOSt
103
103
  let integrity = 'unsupported';
104
104
  try {
105
105
  const verification = await verifyOfflineArtifact(raw);
106
- integrity = verification.checks.contentIntegrity === 'verified' ? 'verified' : 'structure_only';
106
+ integrity = verification.state === 'verified' && hasVerifiedWholeArtifactIntegrity(verification)
107
+ ? 'verified'
108
+ : verification.state === 'integrity_valid'
109
+ ? 'projection_integrity'
110
+ : 'structure_only';
107
111
  }
108
112
  catch (error) {
109
113
  integrity = error instanceof UnsupportedOfflineArtifactError ? 'unsupported' : 'failed';
@@ -114,9 +118,11 @@ async function buildSharingReview(raw, options, generatedAt = new Date().toISOSt
114
118
  ? 'The artefact passed its supported local integrity contract.'
115
119
  : integrity === 'structure_only'
116
120
  ? 'The artefact passed its structural contract but has no verified content digest.'
117
- : integrity === 'unsupported'
118
- ? 'This artefact schema has no supported local integrity verifier; review its producer and digest contract manually.'
119
- : 'The artefact failed its supported structure or integrity contract.');
121
+ : integrity === 'projection_integrity'
122
+ ? 'The artefact passed its structural contract and projection digests, but those digests do not cover the whole file.'
123
+ : integrity === 'unsupported'
124
+ ? 'This artefact schema has no supported local integrity verifier; review its producer and digest contract manually.'
125
+ : 'The artefact failed its supported structure or integrity contract.');
120
126
  add('human-review', options.humanReviewed ? 'pass' : 'block', 'Human review', options.humanReviewed
121
127
  ? 'A deliberate human review was recorded for this sharing decision.'
122
128
  : 'Complete a deliberate human review before sharing.');