@slicedearth/whoisleuth-cli 2.3.0 → 2.5.1
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.
- package/NOTICE +8 -2
- package/README.md +19 -15
- package/bin/whoisleuth.mjs +8 -1
- package/cli/archive-content-digest.mjs +14 -0
- package/cli/archive-inspect.mjs +20 -53
- package/cli/argument-values.mjs +55 -0
- package/cli/arguments.mjs +24 -408
- package/cli/artifact-validation/case-response.mjs +65 -44
- package/cli/artifact-validation/investigation-capsule.mjs +52 -31
- package/cli/artifact-validation/lookup-evidence.mjs +15 -9
- package/cli/artifact-validation/signed-review.mjs +136 -68
- package/cli/artifact-validation/structure-primitives.mjs +1 -105
- package/cli/artifact-verify.mjs +92 -24
- package/cli/assurance-arguments.mjs +56 -0
- package/cli/assurance-command-definitions.mjs +179 -0
- package/cli/assurance-command-runner.mjs +40 -5
- package/cli/bagit-folder.mjs +57 -0
- package/cli/bagit-review.mjs +23 -0
- package/cli/bounded-json.mjs +1 -1
- package/cli/bulk-checkpoint.mjs +1 -1
- package/cli/bulk-command-runner.mjs +4 -2
- package/cli/bulk-output.mjs +29 -3
- package/cli/bulk.mjs +2 -3
- package/cli/case-command.mjs +212 -0
- package/cli/case-pack.mjs +50 -32
- package/cli/ci-report.mjs +6 -3
- package/cli/collection-arguments.mjs +123 -0
- package/cli/collection-command-definitions.mjs +330 -0
- package/cli/collection-preflight.mjs +8 -1
- package/cli/command-argument-grammar.mjs +8 -206
- package/cli/command-definition.mjs +329 -0
- package/cli/command-reference.mjs +94 -1357
- package/cli/command-seeds.mjs +18 -0
- package/cli/compare.mjs +1 -1
- package/cli/completion.mjs +298 -79
- package/cli/config-profile.mjs +8 -6
- package/cli/ct-event-intake.mjs +16 -16
- package/cli/discover.mjs +5 -4
- package/cli/discovery-observation-snapshot.mjs +46 -18
- package/cli/discovery-scan-command-runner.mjs +5 -3
- package/cli/discovery-scan.mjs +7 -4
- package/cli/discovery-snapshot.mjs +2 -2
- package/cli/discovery-workflow.mjs +5 -5
- package/cli/domain-control-monitor.mjs +50 -20
- package/cli/domain-control-observations.mjs +151 -103
- package/cli/errors.mjs +37 -6
- package/cli/evidence-arguments.mjs +46 -0
- package/cli/evidence-command-definitions.mjs +69 -0
- package/cli/evidence-command-runner.mjs +18 -8
- package/cli/evidence-signing.mjs +5 -4
- package/cli/external-observation-mapping.mjs +9 -10
- package/cli/formatters/terminal-command-formats.mjs +6 -0
- package/cli/formatters/terminal-lookup.mjs +24 -46
- package/cli/formatters/terminal-shared.mjs +5 -3
- package/cli/formatters/terminal-technology.mjs +114 -0
- package/cli/history-arguments.mjs +39 -0
- package/cli/history-command-definitions.mjs +88 -0
- package/cli/indicator-set-command.mjs +33 -0
- package/cli/inline-command-families.mjs +6 -46
- package/cli/inline-command-runner.mjs +4 -31
- package/cli/input.mjs +2 -2
- package/cli/intake-command.mjs +107 -0
- package/cli/interactive-launcher.mjs +2 -160
- package/cli/interchange-report.mjs +8 -10
- package/cli/investigation-artifacts.mjs +176 -0
- package/cli/investigation-checkpoint.mjs +10 -0
- package/cli/investigation-folder.mjs +114 -0
- package/cli/investigation-manifest.mjs +1 -112
- package/cli/investigation-package-review.mjs +103 -0
- package/cli/investigation-plan.mjs +38 -147
- package/cli/investigation-recipes.mjs +177 -0
- package/cli/investigation-run.mjs +256 -35
- package/cli/local-document-checkpoint.mjs +170 -0
- package/cli/local-mmdb-review.mjs +197 -17
- package/cli/lookalike-calibration.mjs +1 -1
- package/cli/lookup-brief.mjs +2 -2
- package/cli/lookup-browser.mjs +5 -12
- package/cli/lookup-command-runner.mjs +33 -39
- package/cli/lookup-diff.mjs +47 -12
- package/cli/lookup-plan.mjs +16 -14
- package/cli/lookup-reconcile.mjs +15 -12
- package/cli/lookup-timeline.mjs +7 -6
- package/cli/mail-header-review.mjs +24 -247
- package/cli/mail-review.mjs +75 -21
- package/cli/manual.mjs +1 -0
- package/cli/network-arguments.mjs +51 -0
- package/cli/network-command-definitions.mjs +130 -0
- package/cli/network-command-runner.mjs +45 -31
- package/cli/offline-evidence-review.mjs +39 -6
- package/cli/output-file.mjs +31 -5
- package/cli/posture.mjs +1 -1
- package/cli/registry-doctor.mjs +3 -1
- package/cli/registry-fixture-scaffold.mjs +1 -1
- package/cli/registry-support.mjs +1 -1
- package/cli/retained-artifact-diff.mjs +10 -9
- package/cli/review-arguments.mjs +131 -0
- package/cli/review-command-definitions.mjs +273 -0
- package/cli/review-command-runner.mjs +104 -149
- package/cli/risk-calibration.mjs +8 -8
- package/cli/runner.mjs +74 -37
- package/cli/saved-lookup.mjs +2 -2
- package/cli/selected-input-worker.mjs +63 -0
- package/cli/sharing-review.mjs +8 -80
- package/cli/signer-trust.mjs +104 -0
- package/cli/source-reliability.mjs +75 -84
- package/cli/support-arguments.mjs +49 -0
- package/cli/support-command-definitions.mjs +209 -0
- package/cli/support-command-runner.mjs +2 -2
- package/cli/terminal-input.mjs +168 -0
- package/cli/workflow-arguments.mjs +86 -0
- package/cli/workflow-command-definitions.mjs +78 -0
- package/cli/workflow-command-runner.mjs +75 -13
- package/docs/cli-reference.md +103 -30
- package/docs/cli.md +510 -25
- package/docs/contextual-reviews.md +155 -0
- package/lib/abort.mjs +4 -1
- package/lib/analyst-taxonomy.mjs +2 -40
- package/lib/application-version.mjs +1 -1
- package/lib/availability.mjs +27 -754
- package/lib/bounded-contract-normalizers.mjs +4 -0
- package/lib/bounded-file.mjs +3 -1
- package/lib/bounded-html-document.mjs +125 -0
- package/lib/bounded-json.mjs +2 -290
- package/lib/browser-library-profile.mjs +99 -130
- package/lib/browser-library-worker.mjs +112 -0
- package/lib/candidate-provenance-bounds.mjs +2 -0
- package/lib/classify.mjs +1 -1
- package/lib/client-behavior-profile.mjs +3 -3
- package/lib/ct-query.mjs +2 -27
- package/lib/ct-response-bounds.mjs +2 -9
- package/lib/ct-search.mjs +89 -46
- package/lib/dmarc-discovery.mjs +62 -0
- package/lib/dns-convergence-review.mjs +21 -8
- package/lib/dns-delegation-health.mjs +36 -22
- package/lib/dns-inheritance-review.mjs +207 -0
- package/lib/dns-intelligence.mjs +44 -29
- package/lib/dns-mx.mjs +1 -1
- package/lib/dns-query-coverage.mjs +40 -0
- package/lib/dnssec-evidence-validation.mjs +11 -3
- package/lib/domain-assurance.mjs +1 -1
- package/lib/domain-change-packet.mjs +18 -14
- package/lib/domain-change-review.mjs +40 -16
- package/lib/domain-control-flight-recorder.mjs +301 -124
- package/lib/domain-control-manifest.mjs +126 -58
- package/lib/domain-posture-analysis.mjs +41 -11
- package/lib/domain-posture-parsers.mjs +88 -6
- package/lib/domain-posture.mjs +120 -32
- package/lib/domain-registration.mjs +392 -0
- package/lib/evidence-export-privacy.mjs +568 -0
- package/lib/evidence-export.mjs +12 -593
- package/lib/evidence-report.mjs +7 -2
- package/lib/external-intelligence-risk.mjs +2 -124
- package/lib/favicon.mjs +117 -41
- package/lib/generated/cisa-kev-catalog.mjs +50 -4
- package/lib/generated/registrar-standing-catalogue.mjs +18 -10
- package/lib/generated/retire-browser-catalog.mjs +2742 -1034
- package/lib/generated/{unicode-confusables-17.mjs → unicode-confusables.mjs} +33 -33
- package/lib/html-signals.mjs +87 -85
- package/lib/http-evidence-bounds.mjs +2 -7
- package/lib/http-intelligence.mjs +52 -27
- package/lib/idn-confusable-policy.mjs +6 -4
- package/lib/idn-confusables.mjs +1 -1
- package/lib/interchange-fidelity-registry.mjs +10 -0
- package/lib/lookup-cache.mjs +34 -11
- package/lib/lookup-child-profile-contract.mjs +24 -15
- package/lib/lookup-contract-primitives.mjs +1 -1
- package/lib/lookup-diagnostics.mjs +2 -1
- package/lib/lookup-network-evidence-bounds.mjs +1 -10
- package/lib/lookup-progress.mjs +79 -13
- package/lib/lookup-response-contract.mjs +1077 -0
- package/lib/lookup-response.mjs +11 -24
- package/lib/lookup-source-progress.mjs +24 -35
- package/lib/lookup.mjs +49 -28
- package/lib/observed-network-context.mjs +43 -27
- package/lib/opportunity-scoring.mjs +2 -107
- package/lib/outbound-identity.mjs +1 -1
- package/lib/outbound-request-bounds.mjs +4 -1
- package/lib/page-fingerprints.mjs +87 -134
- package/lib/page-role-profile.mjs +12 -8
- package/lib/perceptual-hash-comparison.mjs +2 -34
- package/lib/perceptual-hash.mjs +79 -24
- package/lib/portable-generator.mjs +2 -29
- package/lib/project-metadata.mjs +2 -8
- package/lib/rdap-bootstrap.mjs +72 -22
- package/lib/rdap-client.mjs +26 -14
- package/lib/rdap-normalization.mjs +33 -18
- package/lib/rdap-search-workbench.mjs +1 -1
- package/lib/rdap-transport.mjs +47 -20
- package/lib/rdap-types.mjs +2 -1
- package/lib/rdap.mjs +18 -3
- package/lib/registrable-domain.mjs +2 -36
- package/lib/registrar-standing-contract.mjs +2 -1
- package/lib/registrar-standing.mjs +9 -13
- package/lib/registry-capabilities.mjs +7 -3
- package/lib/registry-capability-catalogue.mjs +29 -20
- package/lib/registry-dates.mjs +2 -190
- package/lib/registry-insights.mjs +56 -18
- package/lib/response-policy.mjs +86 -48
- package/lib/risk-calibration-summary.mjs +2 -338
- package/lib/risk-scoring.mjs +2 -345
- package/lib/rpki-evidence.mjs +8 -5
- package/lib/safe-fetch.mjs +54 -47
- package/lib/scoring-evidence-quality.mjs +2 -107
- package/lib/security-txt.mjs +10 -7
- package/lib/semantic-version.mjs +2 -54
- package/lib/service-binding-dns.mjs +35 -0
- package/lib/smtp-transport-review.mjs +75 -34
- package/lib/sslbl-certificates.generated.mjs +141 -138
- package/lib/static-html-analysis.mjs +117 -146
- package/lib/structured-data-identity.mjs +2 -1
- package/lib/technology-markup.mjs +100 -0
- package/lib/threat-intelligence-manifests.mjs +11 -139
- package/lib/threat-intelligence-runtime.mjs +24 -52
- package/lib/threat-intelligence-targets.mjs +6 -34
- package/lib/threat-intelligence-types.mjs +2 -36
- package/lib/typosquat-generator.mjs +29 -16
- package/lib/urlhaus-intelligence.mjs +8 -3
- package/lib/urlscan-intelligence.mjs +1 -1
- package/lib/website-enrichment.mjs +388 -0
- package/lib/website-security-posture.mjs +30 -6
- package/lib/website-technology.mjs +111 -71
- package/lib/whois-authority.mjs +55 -5
- package/lib/whois-chain.mjs +9 -2
- package/lib/whois-common-formats.mjs +5 -5
- package/lib/whois-contracts.mjs +2 -1
- package/lib/whois-dialects.mjs +2 -2
- package/lib/whois-normalization.mjs +3 -1
- package/lib/whois-parser-support.mjs +8 -1
- package/lib/whois-parser.mjs +5 -3
- package/lib/whois-transport.mjs +23 -7
- package/package.json +14 -14
- package/packages/analysis/analyst-taxonomy.mjs +40 -0
- package/packages/analysis/bounded-json.mjs +330 -0
- package/packages/analysis/candidate-provenance-bounds.mjs +4 -0
- package/packages/analysis/cli-argument-grammar.mjs +216 -0
- package/packages/analysis/ct-query.mjs +27 -0
- package/packages/analysis/ct-response-bounds.mjs +9 -0
- package/packages/analysis/external-intelligence-risk.mjs +124 -0
- package/packages/analysis/http-evidence-bounds.mjs +8 -0
- package/packages/analysis/lookup-network-evidence-bounds.mjs +10 -0
- package/packages/analysis/opportunity-scoring.mjs +107 -0
- package/packages/analysis/perceptual-hash-comparison.mjs +34 -0
- package/packages/analysis/portable-generator.mjs +29 -0
- package/packages/analysis/project-metadata.mjs +8 -0
- package/packages/analysis/registrable-domain.mjs +56 -0
- package/packages/analysis/risk-calibration-summary.mjs +352 -0
- package/packages/analysis/risk-scoring.mjs +345 -0
- package/packages/analysis/scoring-evidence-quality.mjs +107 -0
- package/packages/analysis/semantic-version.mjs +54 -0
- package/packages/analysis/threat-intelligence-types.mjs +75 -0
- package/packages/cases/case-attachment-model.mjs +83 -0
- package/packages/cases/case-evidence-links.mjs +135 -0
- package/packages/cases/case-evidence-model.mjs +229 -69
- package/packages/cases/case-evidence-quality.mjs +5 -0
- package/packages/cases/case-export-input.mjs +55 -0
- package/packages/cases/case-incident-context.mjs +52 -0
- package/packages/cases/case-markdown.mjs +11 -0
- package/packages/cases/case-migration-model.mjs +98 -48
- package/packages/cases/case-model.mjs +1 -0
- package/packages/cases/case-recheck-model.mjs +149 -0
- package/packages/cases/case-record-contracts.mjs +1 -1
- package/packages/cases/case-record-core.mjs +4 -3
- package/packages/cases/case-record-operations.mjs +123 -133
- package/packages/cases/case-record-projection.mjs +30 -20
- package/packages/cases/case-record-version-input.mjs +19 -0
- package/packages/cases/case-report.mjs +114 -67
- package/packages/cases/case-requested-evidence.mjs +146 -0
- package/packages/cases/case-response-actions.mjs +756 -0
- package/packages/cases/case-response-model.mjs +49 -1129
- package/packages/cases/case-response-outcomes.mjs +338 -0
- package/packages/cases/case-response-packet-render.mjs +157 -0
- package/packages/cases/case-response-packet-types.mjs +1 -0
- package/packages/cases/case-response-packet-vocabulary.mjs +48 -0
- package/packages/cases/case-response-packet.mjs +58 -593
- package/packages/cases/case-response-records.mjs +93 -0
- package/packages/cases/case-response-review-inputs.mjs +382 -0
- package/packages/cases/case-response-values.mjs +85 -0
- package/packages/cases/case-review-package.mjs +45 -0
- package/packages/cases/case-selection.mjs +46 -0
- package/packages/cases/case-storage-model.mjs +26 -1
- package/packages/cases/case-workflow-metadata.mjs +225 -0
- package/packages/cases/case-workflow-migration.mjs +43 -0
- package/packages/cases/http-summary.mjs +6 -1
- package/packages/cases/response-route-freshness.mjs +16 -0
- package/packages/comparison/capture-context.mjs +61 -0
- package/packages/comparison/comparison-ledger-bulk.mjs +4 -1
- package/packages/comparison/favicon-similarity.mjs +1 -1
- package/packages/comparison/page-similarity.mjs +3 -2
- package/packages/comparison/relationship-evidence.mjs +103 -14
- package/packages/comparison/relationship-provenance.mjs +99 -0
- package/packages/contracts/analyst-interchange.mjs +234 -0
- package/packages/contracts/analyst-review-state-contract.mjs +11 -0
- package/packages/contracts/analyst-review-state.mjs +5 -4
- package/packages/contracts/case-portability.mjs +370 -114
- package/packages/contracts/case-views-contract.mjs +12 -0
- package/packages/contracts/case-views.mjs +26 -0
- package/packages/contracts/cli-command-semantics.mjs +3 -0
- package/packages/contracts/cli-grammar.mjs +6 -0
- package/packages/contracts/cli-lookup-brief.mjs +2 -0
- package/packages/contracts/cli-lookup.mjs +0 -1
- package/packages/contracts/context-review.mjs +24 -0
- package/packages/contracts/document-intake.mjs +11 -0
- package/packages/contracts/domain-control-flight-recorder.mjs +98 -44
- package/packages/contracts/domain-control-manifest.mjs +128 -74
- package/packages/contracts/domain-control-monitor.mjs +59 -45
- package/packages/contracts/domain-control-review.mjs +200 -121
- package/packages/contracts/domain-name.mjs +21 -0
- package/packages/contracts/external-observation-interchange.mjs +2 -1
- package/packages/contracts/extracted-domain-lifecycle.mjs +11 -32
- package/packages/contracts/har-review.mjs +2 -0
- package/packages/contracts/http-url.mjs +2 -0
- package/packages/contracts/identity-events.mjs +4 -0
- package/packages/contracts/investigation-package-limits.mjs +24 -0
- package/packages/contracts/investigation-portability.mjs +56 -27
- package/packages/contracts/investigation-run.mjs +18 -0
- package/packages/contracts/ip-address.mjs +44 -0
- package/packages/contracts/lookup-evidence.mjs +35 -0
- package/packages/contracts/mail-authentication.mjs +5 -0
- package/packages/contracts/message-intake.mjs +31 -0
- package/packages/contracts/offline-comparison.mjs +4 -2
- package/packages/contracts/page-fingerprints.mjs +15 -0
- package/packages/contracts/passive-mail.mjs +10 -0
- package/packages/contracts/risk-calibration.mjs +0 -1
- package/packages/contracts/schema-compatibility.mjs +1 -1
- package/packages/contracts/schema-lifecycle.mjs +83 -153
- package/packages/contracts/selected-file-limits.mjs +6 -0
- package/packages/contracts/vulnerability-identifiers.mjs +5 -0
- package/packages/contracts/web-capture.mjs +10 -0
- package/packages/contracts/workspace-portability.mjs +219 -238
- package/packages/evidence/artifact-integrity.mjs +8 -2
- package/packages/evidence/artifact-structure.mjs +105 -0
- package/packages/evidence/collection-quality.mjs +67 -0
- package/packages/evidence/decision-fact.mjs +4 -1
- package/packages/evidence/dns-query-outcome.mjs +72 -0
- package/packages/evidence/domain-control-runtime.mjs +155 -27
- package/packages/evidence/domain-posture-context.mjs +79 -0
- package/packages/evidence/email-recipient.mjs +18 -0
- package/packages/evidence/image-regions.mjs +56 -0
- package/packages/evidence/latest-observations.mjs +28 -0
- package/packages/evidence/lookup-target.mjs +108 -0
- package/packages/evidence/observation.mjs +18 -1
- package/packages/evidence/passphrase-encryption.mjs +44 -0
- package/packages/evidence/png-pixels.mjs +117 -0
- package/packages/evidence/public-address-policy.mjs +83 -0
- package/packages/evidence/record-identity.mjs +72 -0
- package/packages/evidence/registry-dates.mjs +190 -0
- package/packages/evidence/retained-file.mjs +69 -0
- package/packages/evidence/review-age.mjs +14 -0
- package/packages/interchange/bagit.mjs +342 -0
- package/packages/interchange/bounded-zip-extraction.mjs +278 -0
- package/packages/interchange/crc32.mjs +17 -0
- package/packages/interchange/defensive-indicator-export.mjs +264 -0
- package/packages/interchange/external-findings-import.mjs +93 -61
- package/packages/interchange/managed-indicator-export.mjs +35 -0
- package/packages/interchange/managed-indicator-set.mjs +210 -0
- package/packages/interchange/misp-indicator-export.mjs +93 -0
- package/packages/interchange/sharing-policy.mjs +56 -0
- package/packages/interchange/stix-indicator-export.mjs +129 -0
- package/packages/interchange/web-capture-import.mjs +389 -0
- package/packages/investigation/acquisition-decision-packet.mjs +1 -1
- package/packages/investigation/bulk-mail-exposure.mjs +9 -14
- package/packages/investigation/capture-coverage.mjs +57 -0
- package/packages/investigation/connector-provenance-review.mjs +100 -0
- package/packages/investigation/context-review.mjs +35 -0
- package/packages/investigation/document-intake.mjs +81 -0
- package/packages/investigation/docx-intake.mjs +133 -0
- package/packages/investigation/domain-history-review.mjs +100 -0
- package/packages/investigation/domain-transition-review.mjs +47 -0
- package/packages/investigation/evidence-coverage-ledger.mjs +9 -1
- package/packages/investigation/har-intake.mjs +68 -0
- package/packages/investigation/identity-event-intake.mjs +131 -0
- package/packages/investigation/identity-incident-review.mjs +39 -0
- package/packages/investigation/incident-sequence-review.mjs +58 -0
- package/packages/investigation/intake-report.mjs +19 -0
- package/packages/investigation/investigation-bagit.mjs +14 -0
- package/packages/investigation/investigation-capsule.mjs +33 -5
- package/packages/investigation/investigation-manifest.mjs +200 -0
- package/packages/investigation/investigation-package-crypto.mjs +98 -0
- package/packages/investigation/investigation-package.mjs +200 -0
- package/packages/investigation/link-intake.mjs +179 -0
- package/packages/investigation/lookup-asset-graph-inputs.mjs +38 -0
- package/packages/investigation/lookup-asset-graph.mjs +161 -141
- package/packages/investigation/lookup-claim-readiness.mjs +18 -0
- package/packages/investigation/lookup-investigation-brief.mjs +3 -3
- package/packages/investigation/lookup-task-guidance.mjs +58 -0
- package/packages/investigation/mail-authentication-review.mjs +222 -0
- package/packages/investigation/mail-header-identity.mjs +209 -0
- package/packages/investigation/message-intake.mjs +195 -0
- package/packages/investigation/page-behaviour.mjs +113 -0
- package/packages/investigation/pdf-intake.mjs +155 -0
- package/packages/investigation/platform-continuity-review.mjs +60 -0
- package/packages/investigation/qr-intake.mjs +56 -0
- package/packages/investigation/requested-action-hints.mjs +11 -0
- package/packages/investigation/selected-input-review.mjs +17 -0
- package/packages/investigation/storefront-review.mjs +70 -0
- package/packages/monitoring/analyst-review-state.mjs +38 -90
- package/packages/workspace/brand-profile-model.mjs +160 -22
- package/packages/workspace/bulk-columns.mjs +17 -0
- package/packages/workspace/bulk-review-model.mjs +39 -31
- package/packages/workspace/bulk-session-model.mjs +112 -27
- package/packages/workspace/bulk-sort.mjs +1 -0
- package/packages/workspace/campaign-model.mjs +1 -1
- package/packages/workspace/case-views.mjs +102 -0
- package/packages/workspace/detection-rule-model.mjs +1 -1
- package/packages/workspace/hostile-input.mjs +29 -8
- package/packages/workspace/investigation-guide.mjs +2 -2
- package/packages/workspace/investigation-template-model.mjs +45 -6
- package/packages/workspace/page-baseline.mjs +20 -17
- package/packages/workspace/relationship-observation-model.mjs +54 -35
- package/packages/workspace/shortlist-model.mjs +14 -5
- package/packages/workspace/watchlist-history.mjs +30 -14
- package/packages/workspace/watchlist-store.mjs +24 -6
- package/packages/workspace/website-snapshot-model.mjs +98 -33
- package/packages/workspace/workspace-archive-crypto.mjs +41 -61
- package/packages/workspace/workspace-archive.mjs +90 -25
- package/third-party-notices.txt +577 -17
- package/lib/hostname.mjs +0 -38
- package/packages/investigation/bulk-review-export.mjs +0 -63
package/NOTICE
CHANGED
|
@@ -38,8 +38,14 @@ distributed as third-party-notices.txt. The website inventory is served at
|
|
|
38
38
|
only the CLI runtime dependency closure. Both are generated from the reviewed
|
|
39
39
|
lockfile, and the website inventory is checked for lockfile drift in CI.
|
|
40
40
|
|
|
41
|
-
The
|
|
42
|
-
|
|
41
|
+
The development-only fixtures/risk-evaluation/rows.json is a minimised,
|
|
42
|
+
stratified adaptation of PhiUSIIL Phishing URL (Website), Arvind Prasad and
|
|
43
|
+
Shalini Chandra (2024), licensed under CC BY 4.0 without warranties. The source
|
|
44
|
+
and licence links, modifications and reproduction instructions are in that
|
|
45
|
+
directory's README.md. This dataset is not included in the website or CLI.
|
|
46
|
+
|
|
47
|
+
The generated Unicode confusable projection is derived from the Unicode UTS #39
|
|
48
|
+
data file confusables.txt. Its source version and digest accompany the projection.
|
|
43
49
|
|
|
44
50
|
UNICODE LICENSE V3 COPYRIGHT AND PERMISSION NOTICE
|
|
45
51
|
Copyright © 1991-2026 Unicode, Inc.
|
package/README.md
CHANGED
|
@@ -51,14 +51,7 @@ only `bulk` accepts multiple targets.
|
|
|
51
51
|
|
|
52
52
|
## Command groups
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
| --- | --- |
|
|
56
|
-
| Investigate | `lookup`, `bulk`, `discover`, `ct-search`, `posture`, `http`, `tls`, `compare`, `mail-headers`, `brief` |
|
|
57
|
-
| Respond | `case-pack`, `change-packet`, `sharing-review`, `export` |
|
|
58
|
-
| Assure | `dnssec-validate`, `mail-transport`, `domain-control`, `assurance`, `workflow-plan`, `diff`, `inspect-archive`, `verify-artifact` |
|
|
59
|
-
| Utilities | `doctor`, `commands`, `completion`, `manual`, `registry-scaffold` |
|
|
60
|
-
|
|
61
|
-
Use the installed registry for the complete inventory:
|
|
54
|
+
Use the installed registry to browse Investigate, Respond, Assure and Utilities:
|
|
62
55
|
|
|
63
56
|
```bash
|
|
64
57
|
whoisleuth commands --group investigate
|
|
@@ -67,10 +60,6 @@ whoisleuth commands --json
|
|
|
67
60
|
whoisleuth manual | man -l -
|
|
68
61
|
```
|
|
69
62
|
|
|
70
|
-
`registry-scaffold` has a separate fixture contract: its `--profile` selects a
|
|
71
|
-
fixed fixture profile and it rejects shared `--config` profiles. It creates
|
|
72
|
-
sanitised local fixture material.
|
|
73
|
-
|
|
74
63
|
## Collection and output
|
|
75
64
|
|
|
76
65
|
Fast Lookup is registration-first. Deep Lookup explicitly adds the applicable
|
|
@@ -86,9 +75,24 @@ or domain-only output only where declared. `--output` writes a private local
|
|
|
86
75
|
file atomically and refuses an existing path unless `--force` is selected.
|
|
87
76
|
`--strict-exit` and `--fail-on` expose selected evidence states to automation.
|
|
88
77
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
78
|
+
`case open --domain example.test --output cases.json` creates an ordinary local
|
|
79
|
+
Case file. `case show`, `note`, `pin`, `assess` and `recheck` review or update it
|
|
80
|
+
offline. Mutations require explicit output and preserve earlier retained evidence;
|
|
81
|
+
see `docs/cli.md#local-case-files` for JSON inputs and conflict handling. Working
|
|
82
|
+
files contain private analyst content, not attached file bytes.
|
|
83
|
+
|
|
84
|
+
`manifest --package --output evidence.wlep --passphrase-file ./passphrase.txt`
|
|
85
|
+
encrypts selected evidence files and their manifest. Use the same explicit
|
|
86
|
+
passphrase file with `verify-artifact --package` to authenticate and verify it
|
|
87
|
+
offline. Ordinary ZIPs and folder exports remain unencrypted; see `docs/cli.md`
|
|
88
|
+
for complete examples and file-handling boundaries.
|
|
89
|
+
|
|
90
|
+
`workflow-run` pauses on a partial collection. Resume retains it without
|
|
91
|
+
recollection and keeps exit code 4 even if later steps finish. Failed validation
|
|
92
|
+
or export steps remain retryable. See `docs/cli.md` for checkpoint compatibility.
|
|
93
|
+
|
|
94
|
+
The included `docs/cli-reference.md` lists common exit codes and compatibility
|
|
95
|
+
contracts. A completed command can still contain partial source evidence.
|
|
92
96
|
|
|
93
97
|
## Repository checkout
|
|
94
98
|
|
package/bin/whoisleuth.mjs
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
3
|
import EXIT_CODES from "../cli/exit-codes.mjs";
|
|
4
|
-
import { metaActionDefinition } from "../cli/command-reference.mjs";
|
|
4
|
+
import { HELP, commandHelp, isCliCommand, metaActionDefinition } from "../cli/command-reference.mjs";
|
|
5
|
+
import { presentTerminalOutput, terminalPresentation } from "../cli/terminal-presentation.mjs";
|
|
5
6
|
for (const stream of [process.stdout, process.stderr]) {
|
|
6
7
|
stream.on('error', (error) => {
|
|
7
8
|
if (error.code === 'EPIPE')
|
|
@@ -10,6 +11,9 @@ for (const stream of [process.stdout, process.stderr]) {
|
|
|
10
11
|
});
|
|
11
12
|
}
|
|
12
13
|
const argv = process.argv.slice(2);
|
|
14
|
+
const rootHelp = argv.length === 1 && metaActionDefinition('help').aliases.includes(argv[0] ?? '');
|
|
15
|
+
const command = argv.length === 2 && isCliCommand(argv[0])
|
|
16
|
+
&& metaActionDefinition('help').aliases.includes(argv[1] ?? '') ? argv[0] : null;
|
|
13
17
|
if (argv.length === 1 && metaActionDefinition('version').aliases.includes(argv[0] ?? '')) {
|
|
14
18
|
const require = createRequire(import.meta.url);
|
|
15
19
|
const metadata = require('../package.json');
|
|
@@ -21,6 +25,9 @@ if (argv.length === 1 && metaActionDefinition('version').aliases.includes(argv[0
|
|
|
21
25
|
process.stdout.write(`${metadata.version}\n`);
|
|
22
26
|
}
|
|
23
27
|
}
|
|
28
|
+
else if (rootHelp || command) {
|
|
29
|
+
process.stdout.write(presentTerminalOutput(command ? commandHelp(command) : HELP, terminalPresentation(process.stdout)));
|
|
30
|
+
}
|
|
24
31
|
else {
|
|
25
32
|
const [configModule, errorsModule, outputModule, runnerModule] = await Promise.all([
|
|
26
33
|
import("../cli/config-profile.mjs"),
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** Bare hashes retain their original v1 meaning; new identities declare v2. */
|
|
2
|
+
export function parseArchiveContentDigest(value) {
|
|
3
|
+
if (value === null || value === undefined || value === '')
|
|
4
|
+
return null;
|
|
5
|
+
if (typeof value !== 'string' || value.length > 'sorted-json-v2:sha256:'.length + 64) {
|
|
6
|
+
throw new TypeError('Expected archive content digest must be sha256:<64 lowercase hex> or sorted-json-v2:sha256:<64 lowercase hex>.');
|
|
7
|
+
}
|
|
8
|
+
const explicit = value.startsWith('sorted-json-v2:');
|
|
9
|
+
const digestSha256 = explicit ? value.slice('sorted-json-v2:'.length) : value;
|
|
10
|
+
if (!/^sha256:[a-f0-9]{64}$/u.test(digestSha256)) {
|
|
11
|
+
throw new TypeError('Expected archive content digest must be sha256:<64 lowercase hex> or sorted-json-v2:sha256:<64 lowercase hex>.');
|
|
12
|
+
}
|
|
13
|
+
return Object.freeze({ canonicalization: explicit ? 'sorted-json-v2' : 'sorted-json-v1', digestSha256 });
|
|
14
|
+
}
|
package/cli/archive-inspect.mjs
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import { Buffer } from 'node:buffer';
|
|
2
2
|
import { createHash } from 'node:crypto';
|
|
3
3
|
import { domainToASCII } from 'node:url';
|
|
4
|
-
import { scanBoundedJson } from "../lib/bounded-json.mjs";
|
|
5
|
-
import { decryptWorkspaceArchive, isEncryptedWorkspaceArchive, } from "../packages/workspace/workspace-archive-crypto.mjs";
|
|
6
4
|
import { WORKSPACE_ARCHIVE_SCHEMA, readWorkspaceArchive, } from "../packages/workspace/workspace-archive.mjs";
|
|
7
|
-
import { canonicalArtifactJson } from "../packages/evidence/artifact-integrity.mjs";
|
|
8
|
-
import {
|
|
5
|
+
import { canonicalArtifactJson, canonicalArtifactJsonV2 } from "../packages/evidence/artifact-integrity.mjs";
|
|
6
|
+
import { parseArchiveContentDigest } from "./archive-content-digest.mjs";
|
|
7
|
+
import { verifyOfflineWorkspaceArchive } from "./artifact-verify.mjs";
|
|
9
8
|
import { safeTerminalValue } from "./formatters/terminal.mjs";
|
|
10
9
|
export const ARCHIVE_INSPECTION_SCHEMA = 'whoisleuth.workspace-archive-inspection';
|
|
11
|
-
export const ARCHIVE_INSPECTION_VERSION =
|
|
10
|
+
export const ARCHIVE_INSPECTION_VERSION = 3;
|
|
12
11
|
export const MAX_ARCHIVE_SEARCH_LENGTH = 253;
|
|
13
12
|
export const MAX_ARCHIVE_SEARCH_MATCHES = 100;
|
|
14
13
|
export const MAX_ARCHIVE_SEARCH_NODES = 100_000;
|
|
@@ -22,32 +21,11 @@ const SEARCHABLE_FIELDS = new Set([
|
|
|
22
21
|
'target',
|
|
23
22
|
]);
|
|
24
23
|
const CONTROL_RE = /[\u0000-\u001f\u007f]/u;
|
|
25
|
-
const SHA256_DIGEST_RE = /^sha256:[a-f0-9]{64}$/u;
|
|
26
24
|
function record(value) {
|
|
27
25
|
return value && typeof value === 'object' && !Array.isArray(value)
|
|
28
26
|
? value
|
|
29
27
|
: null;
|
|
30
28
|
}
|
|
31
|
-
function parseJson(raw) {
|
|
32
|
-
if (typeof raw !== 'string')
|
|
33
|
-
throw new TypeError('Archive input must be UTF-8 JSON text.');
|
|
34
|
-
const bytes = Buffer.byteLength(raw, 'utf8');
|
|
35
|
-
if (bytes === 0 || bytes > MAX_OFFLINE_ARTIFACT_BYTES) {
|
|
36
|
-
throw new TypeError(`Archive input must be between 1 byte and ${MAX_OFFLINE_ARTIFACT_BYTES} bytes.`);
|
|
37
|
-
}
|
|
38
|
-
let parsed;
|
|
39
|
-
try {
|
|
40
|
-
scanBoundedJson(raw);
|
|
41
|
-
parsed = JSON.parse(raw);
|
|
42
|
-
}
|
|
43
|
-
catch {
|
|
44
|
-
throw new TypeError('Archive input must be valid bounded JSON without duplicate keys.');
|
|
45
|
-
}
|
|
46
|
-
const value = record(parsed);
|
|
47
|
-
if (!value)
|
|
48
|
-
throw new TypeError('Archive input must contain one JSON object.');
|
|
49
|
-
return value;
|
|
50
|
-
}
|
|
51
29
|
function normalizeSearch(value) {
|
|
52
30
|
if (value === null || value === undefined || value === '')
|
|
53
31
|
return null;
|
|
@@ -71,7 +49,7 @@ function canonicalSearchValue(value) {
|
|
|
71
49
|
function valueDigest(value) {
|
|
72
50
|
return createHash('sha256').update(value, 'utf8').digest('hex');
|
|
73
51
|
}
|
|
74
|
-
function
|
|
52
|
+
function archiveContentDigests(sections) {
|
|
75
53
|
const identity = sections.map((section) => ({
|
|
76
54
|
id: section.id,
|
|
77
55
|
schema: section.schema,
|
|
@@ -85,15 +63,10 @@ function archiveContentDigest(sections) {
|
|
|
85
63
|
return content;
|
|
86
64
|
})(),
|
|
87
65
|
}));
|
|
88
|
-
return
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
return null;
|
|
93
|
-
if (typeof value !== 'string' || !SHA256_DIGEST_RE.test(value)) {
|
|
94
|
-
throw new TypeError('Expected archive content digest must use the form sha256 followed by 64 lowercase hexadecimal characters.');
|
|
95
|
-
}
|
|
96
|
-
return value;
|
|
66
|
+
return Object.freeze({
|
|
67
|
+
current: `sha256:${createHash('sha256').update(canonicalArtifactJsonV2(identity), 'utf8').digest('hex')}`,
|
|
68
|
+
legacy: `sha256:${createHash('sha256').update(canonicalArtifactJson(identity), 'utf8').digest('hex')}`,
|
|
69
|
+
});
|
|
97
70
|
}
|
|
98
71
|
function searchSection(section, value, search, reveal, results, state) {
|
|
99
72
|
const stack = [{ value, depth: 0 }];
|
|
@@ -146,21 +119,10 @@ function searchSection(section, value, search, reveal, results, state) {
|
|
|
146
119
|
}
|
|
147
120
|
}
|
|
148
121
|
export async function inspectWorkspaceArchive(raw, options = {}) {
|
|
149
|
-
const
|
|
150
|
-
const encrypted =
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
}
|
|
154
|
-
await verifyOfflineArtifact(raw, options.passphrase === undefined
|
|
155
|
-
? {}
|
|
156
|
-
: { passphrase: options.passphrase });
|
|
157
|
-
const archiveValue = encrypted
|
|
158
|
-
? await decryptWorkspaceArchive(parsed, options.passphrase)
|
|
159
|
-
: parsed;
|
|
160
|
-
const archive = await readWorkspaceArchive(archiveValue);
|
|
161
|
-
const contentDigestSha256 = archiveContentDigest(archive.sections);
|
|
162
|
-
const expectedDigest = expectedContentDigest(options.expectedContentDigest);
|
|
163
|
-
if (expectedDigest && expectedDigest !== contentDigestSha256) {
|
|
122
|
+
const expectedDigest = parseArchiveContentDigest(options.expectedContentDigest);
|
|
123
|
+
const { archive, encrypted } = await verifyOfflineWorkspaceArchive(raw, options);
|
|
124
|
+
const digests = archiveContentDigests(archive.sections);
|
|
125
|
+
if (expectedDigest && expectedDigest.digestSha256 !== (expectedDigest.canonicalization === 'sorted-json-v2' ? digests.current : digests.legacy)) {
|
|
164
126
|
throw new TypeError('Workspace archive content digest did not match the expected value.');
|
|
165
127
|
}
|
|
166
128
|
const search = normalizeSearch(options.search);
|
|
@@ -196,7 +158,9 @@ export async function inspectWorkspaceArchive(raw, options = {}) {
|
|
|
196
158
|
inputBytes: Buffer.byteLength(raw, 'utf8'),
|
|
197
159
|
sectionCount: archive.sections.length,
|
|
198
160
|
recordCount: archive.sections.reduce((sum, section) => sum + section.recordCount, 0),
|
|
199
|
-
|
|
161
|
+
contentDigest: `sorted-json-v2:${digests.current}`,
|
|
162
|
+
contentDigestSha256: digests.legacy,
|
|
163
|
+
expectedContentDigestCanonicalization: expectedDigest?.canonicalization ?? null,
|
|
200
164
|
}),
|
|
201
165
|
sections: Object.freeze(archive.sections.map((section) => Object.freeze({
|
|
202
166
|
id: section.id,
|
|
@@ -218,6 +182,7 @@ export async function inspectWorkspaceArchive(raw, options = {}) {
|
|
|
218
182
|
limitations: Object.freeze([
|
|
219
183
|
'Inspection validates the archive and reports bounded section metadata without printing retained evidence by default.',
|
|
220
184
|
'The content digest covers ordered section identities and normalised content after excluding each section export timestamp. Equality detects matching retained archive content but does not authenticate its source or accuracy.',
|
|
185
|
+
'Use the versioned contentDigest identity for new comparisons. The compatibility contentDigestSha256 field and bare expected hashes retain the original locale-sensitive digest; they are not a cross-locale identity guarantee.',
|
|
221
186
|
'Search checks exact values in a small allowlist of target fields and never searches analyst notes, contacts, or raw evidence.',
|
|
222
187
|
...(reveal
|
|
223
188
|
? ['Search values were revealed only because the operator supplied --reveal; handle the output as sensitive evidence.']
|
|
@@ -234,7 +199,9 @@ export function formatArchiveInspection(report) {
|
|
|
234
199
|
`Archive: ${report.archive.encrypted ? 'encrypted' : 'plain'} · v${report.archive.version}`,
|
|
235
200
|
`Sections: ${report.summary.sectionCount}`,
|
|
236
201
|
`Records: ${report.summary.recordCount}`,
|
|
237
|
-
`Content
|
|
202
|
+
`Content identity: ${report.summary.contentDigest}`,
|
|
203
|
+
...(report.summary.expectedContentDigestCanonicalization === 'sorted-json-v1'
|
|
204
|
+
? ['Expected digest matched using the legacy locale-sensitive form.'] : []),
|
|
238
205
|
];
|
|
239
206
|
for (const section of report.sections) {
|
|
240
207
|
lines.push(`${safeTerminalValue(section.label)}: ${section.recordCount} records · ${safeTerminalValue(section.status)} · ${section.bytes} bytes`);
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import {} from "./command-argument-grammar.mjs";
|
|
2
|
+
import { CliUsageError } from "./errors.mjs";
|
|
3
|
+
import { parseCliFailPolicies, } from "./fail-policy.mjs";
|
|
4
|
+
import { PRESENTATION_OPTIONS } from "./command-definition.mjs";
|
|
5
|
+
function terminalOptions(parsed) {
|
|
6
|
+
return { quiet: parsed.hasOption('--quiet'), color: !parsed.hasOption('--no-color') };
|
|
7
|
+
}
|
|
8
|
+
function jsonOutput(parsed) {
|
|
9
|
+
return parsed.hasOption('--json') ? 'json' : 'terminal';
|
|
10
|
+
}
|
|
11
|
+
function normalizedLabel(parsed, option, maximum) {
|
|
12
|
+
const value = parsed.optionValue(option);
|
|
13
|
+
if (value === null)
|
|
14
|
+
return null;
|
|
15
|
+
const normalized = value.replace(/\s+/gu, ' ').trim();
|
|
16
|
+
if (!normalized || normalized.length > maximum) {
|
|
17
|
+
throw new CliUsageError(`${option} requires a label of at most ${maximum} characters.`);
|
|
18
|
+
}
|
|
19
|
+
return normalized;
|
|
20
|
+
}
|
|
21
|
+
function failPolicies(parsed, command) {
|
|
22
|
+
const value = parsed.optionValue('--fail-on');
|
|
23
|
+
return value === null ? null : parseCliFailPolicies(value, command);
|
|
24
|
+
}
|
|
25
|
+
function parseOutput(parsed, definition) {
|
|
26
|
+
// Membership proves the returned literal belongs to this command's declared
|
|
27
|
+
// options. Grammar validation independently rejects conflicting selections.
|
|
28
|
+
return (PRESENTATION_OPTIONS.find(([option]) => definition.options.includes(option) && parsed.hasOption(option))?.[2] ?? 'terminal');
|
|
29
|
+
}
|
|
30
|
+
function parseTwoFileComparisonArguments(parsed, command) {
|
|
31
|
+
const sources = parsed.positionalValues('sources');
|
|
32
|
+
if (sources[0] === sources[1])
|
|
33
|
+
throw new CliUsageError(`${command} requires two different input files.`);
|
|
34
|
+
return {
|
|
35
|
+
leftSource: sources[0],
|
|
36
|
+
rightSource: sources[1],
|
|
37
|
+
output: jsonOutput(parsed),
|
|
38
|
+
...terminalOptions(parsed),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function uniqueSources(parsed, command) {
|
|
42
|
+
const sources = parsed.positionalValues('sources');
|
|
43
|
+
if (new Set(sources).size !== sources.length)
|
|
44
|
+
throw new CliUsageError(`${command} input files must be different.`);
|
|
45
|
+
return sources;
|
|
46
|
+
}
|
|
47
|
+
function singleInputAction(action, parsed, positionalName = 'source') {
|
|
48
|
+
return {
|
|
49
|
+
action,
|
|
50
|
+
[positionalName]: parsed.positionalValue(positionalName),
|
|
51
|
+
output: jsonOutput(parsed),
|
|
52
|
+
...terminalOptions(parsed),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
export { terminalOptions, jsonOutput, normalizedLabel, failPolicies, parseOutput, parseTwoFileComparisonArguments, uniqueSources, singleInputAction, };
|