@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
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// Pure, bounded workspace archive composition. Existing typed store models remain the
|
|
2
2
|
// authority for normalization and merge semantics; this module only packages
|
|
3
3
|
// their portable contracts, verifies integrity, and previews conflicts.
|
|
4
|
-
import { buildCaseExport, enforceStoreBudget
|
|
4
|
+
import { buildCaseExport, enforceStoreBudget } from "../cases/case-storage-model.mjs";
|
|
5
|
+
import { mergeCases } from "../cases/case-migration-model.mjs";
|
|
5
6
|
import { assertBrandProfileStoreBudget, buildBrandProfileExport, mergeBrandProfiles, normalizeBrandProfileId, } from "./brand-profile-model.mjs";
|
|
6
7
|
import { assertCampaignStoreBudget, buildCampaignExport, mergeCampaigns, } from "./campaign-model.mjs";
|
|
7
8
|
import { normalizeExplicitIsoTimestamp } from "../evidence/observation.mjs";
|
|
@@ -18,6 +19,8 @@ import { buildAnalystReviewStateExport, emptyAnalystReviewStateStore, mergeAnaly
|
|
|
18
19
|
import { isSupportedWorkspaceArchiveVersion, MAX_WORKSPACE_ARCHIVE_BYTES, MAX_WORKSPACE_ARCHIVE_SECTION_BYTES, MAX_WORKSPACE_ARCHIVE_SECTIONS, serialiseWorkspaceArchiveSection, SUPPORTED_WORKSPACE_ARCHIVE_VERSIONS, WORKSPACE_ARCHIVE_CASE_SECTION, WORKSPACE_ARCHIVE_SCHEMA, WORKSPACE_ARCHIVE_SECTION_IDS, PUBLIC_WORKSPACE_ARCHIVE_SECTION_IDS, PUBLIC_WORKSPACE_ARCHIVE_VERSION, WORKSPACE_ARCHIVE_VERSION, WORKSPACE_SETTINGS_COMPATIBILITY, WORKSPACE_SETTINGS_SCHEMA, WORKSPACE_SETTINGS_VERSION, } from "../contracts/case-portability.mjs";
|
|
19
20
|
import { ANALYST_REVIEW_STATE_COMPATIBILITY } from "../contracts/analyst-review-state.mjs";
|
|
20
21
|
import { WORKSPACE_PORTABILITY_ARCHIVE_SECTION_REFERENCES } from "../contracts/workspace-portability.mjs";
|
|
22
|
+
import { CASE_VIEWS_COMPATIBILITY } from "../contracts/case-views.mjs";
|
|
23
|
+
import { emptyCaseViewsStore, mergeCaseViews, normalizeCaseViewsStore } from "./case-views.mjs";
|
|
21
24
|
export { isSupportedWorkspaceArchiveVersion, MAX_WORKSPACE_ARCHIVE_BYTES, MAX_WORKSPACE_ARCHIVE_SECTION_BYTES, MAX_WORKSPACE_ARCHIVE_SECTIONS, SUPPORTED_WORKSPACE_ARCHIVE_VERSIONS, WORKSPACE_ARCHIVE_CASE_SECTION, WORKSPACE_ARCHIVE_SCHEMA, WORKSPACE_ARCHIVE_SECTION_IDS, PUBLIC_WORKSPACE_ARCHIVE_SECTION_IDS, PUBLIC_WORKSPACE_ARCHIVE_VERSION, WORKSPACE_ARCHIVE_VERSION, WORKSPACE_SETTINGS_SCHEMA, WORKSPACE_SETTINGS_VERSION, };
|
|
22
25
|
const CONTROL_RE = /[\x00-\x1f\x7f]/;
|
|
23
26
|
const CHECKSUM_RE = /^sha256:[a-f0-9]{64}$/;
|
|
@@ -111,6 +114,7 @@ function workspaceArchiveSections(input, now) {
|
|
|
111
114
|
investigationTemplates: buildInvestigationTemplateExport(input.investigationTemplates, now),
|
|
112
115
|
bulkReview: buildBulkReviewExport(input.bulkReview),
|
|
113
116
|
analystReviewState: buildAnalystReviewStateExport(input.analystReviewState),
|
|
117
|
+
caseViews: normalizeCaseViewsStore(input.caseViews),
|
|
114
118
|
settings: settingsDocument(input),
|
|
115
119
|
};
|
|
116
120
|
}
|
|
@@ -150,7 +154,7 @@ const SECTION_DEFINITIONS = [
|
|
|
150
154
|
merge: (local, data) => {
|
|
151
155
|
const result = mergeCases(local.cases, data);
|
|
152
156
|
const bounded = enforceStoreBudget(result.cases);
|
|
153
|
-
return { ...result,
|
|
157
|
+
return { ...result, document: bounded.cases, pruned: bounded.pruned };
|
|
154
158
|
},
|
|
155
159
|
},
|
|
156
160
|
{
|
|
@@ -158,7 +162,7 @@ const SECTION_DEFINITIONS = [
|
|
|
158
162
|
count: (data) => arrayCount(data, 'campaigns'),
|
|
159
163
|
merge: (local, data) => {
|
|
160
164
|
const result = mergeCampaigns(local.campaigns, data);
|
|
161
|
-
return { ...result,
|
|
165
|
+
return { ...result, document: assertCampaignStoreBudget(result.campaigns).campaigns };
|
|
162
166
|
},
|
|
163
167
|
},
|
|
164
168
|
{
|
|
@@ -166,7 +170,8 @@ const SECTION_DEFINITIONS = [
|
|
|
166
170
|
count: (data) => arrayCount(data, 'profiles'),
|
|
167
171
|
merge: (local, data, now) => {
|
|
168
172
|
const result = mergeBrandProfiles(local.brandProfiles, data, { nowIso: now });
|
|
169
|
-
|
|
173
|
+
const profiles = assertBrandProfileStoreBudget(result.profiles).profiles;
|
|
174
|
+
return { ...result, profiles, document: profiles };
|
|
170
175
|
},
|
|
171
176
|
},
|
|
172
177
|
{
|
|
@@ -174,7 +179,7 @@ const SECTION_DEFINITIONS = [
|
|
|
174
179
|
count: (data) => objectCount(data, 'watchlists'),
|
|
175
180
|
merge: (local, data) => {
|
|
176
181
|
const result = mergeWatchlistStores(local.watchlists, data);
|
|
177
|
-
return { ...result,
|
|
182
|
+
return { ...result, document: assertWatchlistStoreBudget(result.watchlists).watchlists };
|
|
178
183
|
},
|
|
179
184
|
},
|
|
180
185
|
{
|
|
@@ -182,7 +187,7 @@ const SECTION_DEFINITIONS = [
|
|
|
182
187
|
count: (data) => arrayCount(data, 'entries'),
|
|
183
188
|
merge: (local, data) => {
|
|
184
189
|
const result = mergeShortlistStores(local.shortlist, data);
|
|
185
|
-
return { ...result,
|
|
190
|
+
return { ...result, document: assertShortlistStoreBudget(result.entries).entries };
|
|
186
191
|
},
|
|
187
192
|
},
|
|
188
193
|
{
|
|
@@ -190,14 +195,17 @@ const SECTION_DEFINITIONS = [
|
|
|
190
195
|
count: (data) => arrayCount(data, 'rules'),
|
|
191
196
|
merge: (local, data) => {
|
|
192
197
|
const result = mergeDetectionRules(local.detectionRules, data);
|
|
193
|
-
return { ...result,
|
|
198
|
+
return { ...result, document: assertDetectionRuleStoreBudget(result.rules).rules };
|
|
194
199
|
},
|
|
195
200
|
},
|
|
196
201
|
{
|
|
197
202
|
...sectionContract('relationshipObservations'),
|
|
198
203
|
label: 'Retained relationship observations',
|
|
199
204
|
count: (data) => arrayCount(data, 'observations'),
|
|
200
|
-
merge: (local, data) =>
|
|
205
|
+
merge: (local, data) => {
|
|
206
|
+
const result = mergeRelationshipObservations(local.relationshipObservations, data);
|
|
207
|
+
return { ...result, document: result.observations };
|
|
208
|
+
},
|
|
201
209
|
},
|
|
202
210
|
{
|
|
203
211
|
...sectionContract('bulkSessions'),
|
|
@@ -205,27 +213,36 @@ const SECTION_DEFINITIONS = [
|
|
|
205
213
|
count: (data) => arrayCount(data, 'sessions'),
|
|
206
214
|
merge: (local, data) => {
|
|
207
215
|
const result = mergeBulkSessions(local.bulkSessions, data);
|
|
208
|
-
enforceBulkSessionStoreBudget(result.sessions);
|
|
209
|
-
return result;
|
|
216
|
+
const bounded = enforceBulkSessionStoreBudget(result.sessions);
|
|
217
|
+
return { ...result, document: bounded.store.sessions };
|
|
210
218
|
},
|
|
211
219
|
},
|
|
212
220
|
{
|
|
213
221
|
...sectionContract('websiteSnapshots'),
|
|
214
222
|
label: 'Website profile snapshots',
|
|
215
223
|
count: (data) => arrayCount(data, 'snapshots'),
|
|
216
|
-
merge: (local, data) =>
|
|
224
|
+
merge: (local, data) => {
|
|
225
|
+
const result = mergeWebsiteSnapshots(local.websiteSnapshots, data);
|
|
226
|
+
return { ...result, document: result.snapshots };
|
|
227
|
+
},
|
|
217
228
|
},
|
|
218
229
|
{
|
|
219
230
|
...sectionContract('investigationTemplates'),
|
|
220
231
|
label: 'Investigation templates',
|
|
221
232
|
count: (data) => arrayCount(data, 'templates'),
|
|
222
|
-
merge: (local, data) =>
|
|
233
|
+
merge: (local, data) => {
|
|
234
|
+
const result = mergeInvestigationTemplates(local.investigationTemplates, data);
|
|
235
|
+
return { ...result, document: result.templates };
|
|
236
|
+
},
|
|
223
237
|
},
|
|
224
238
|
{
|
|
225
239
|
...sectionContract('bulkReview'),
|
|
226
240
|
label: 'Bulk saved views and review queue',
|
|
227
241
|
count: (data) => arrayCount(data, 'presets') + arrayCount(data, 'rows'),
|
|
228
|
-
merge: (local, data) =>
|
|
242
|
+
merge: (local, data) => {
|
|
243
|
+
const result = mergeBulkReviewStores(local.bulkReview, data);
|
|
244
|
+
return { ...result, document: result.store };
|
|
245
|
+
},
|
|
229
246
|
},
|
|
230
247
|
{
|
|
231
248
|
id: 'analystReviewState',
|
|
@@ -234,7 +251,19 @@ const SECTION_DEFINITIONS = [
|
|
|
234
251
|
version: ANALYST_REVIEW_STATE_COMPATIBILITY.currentVersion,
|
|
235
252
|
supportedVersions: ANALYST_REVIEW_STATE_COMPATIBILITY.supportedVersions,
|
|
236
253
|
count: (data) => arrayCount(data, 'records'),
|
|
237
|
-
merge: (local, data) =>
|
|
254
|
+
merge: (local, data) => {
|
|
255
|
+
const result = mergeAnalystReviewStateStores(local.analystReviewState, data);
|
|
256
|
+
return { ...result, document: result.store };
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
id: 'caseViews', label: 'Saved Case views', schema: compatibilitySchema(CASE_VIEWS_COMPATIBILITY),
|
|
261
|
+
version: CASE_VIEWS_COMPATIBILITY.currentVersion, supportedVersions: CASE_VIEWS_COMPATIBILITY.supportedVersions,
|
|
262
|
+
count: (data) => arrayCount(data, 'views'),
|
|
263
|
+
merge: (local, data) => {
|
|
264
|
+
const result = mergeCaseViews(local.caseViews, data);
|
|
265
|
+
return { ...result, document: result.store };
|
|
266
|
+
},
|
|
238
267
|
},
|
|
239
268
|
{
|
|
240
269
|
id: 'settings', label: 'Workspace settings', schema: compatibilitySchema(WORKSPACE_SETTINGS_COMPATIBILITY),
|
|
@@ -245,6 +274,19 @@ const SECTION_DEFINITIONS = [
|
|
|
245
274
|
},
|
|
246
275
|
];
|
|
247
276
|
const DEFINITION_BY_ID = new Map(SECTION_DEFINITIONS.map((definition) => [definition.id, definition]));
|
|
277
|
+
/** Apply previously verified data sections through the same owners as preview. */
|
|
278
|
+
export function mergeReadyWorkspaceArchiveData(localInput, sections, generatedAt) {
|
|
279
|
+
if (sections.length > MAX_WORKSPACE_ARCHIVE_SECTIONS || new Set(sections.map(section => section.id)).size !== sections.length) {
|
|
280
|
+
throw new Error('Workspace data sections exceed their count or contain duplicate identities.');
|
|
281
|
+
}
|
|
282
|
+
const local = normalizedInput(localInput);
|
|
283
|
+
return sections.map(section => {
|
|
284
|
+
const definition = DEFINITION_BY_ID.get(section.id);
|
|
285
|
+
if (section.status !== 'ready' || !definition?.merge)
|
|
286
|
+
throw new Error('Only verified, supported workspace data sections can be merged.');
|
|
287
|
+
return { ...definition.merge(local, section.data, generatedAt), id: section.id };
|
|
288
|
+
});
|
|
289
|
+
}
|
|
248
290
|
const SECTION_ORDER = new Map(WORKSPACE_ARCHIVE_SECTION_IDS.map((id, index) => [id, index]));
|
|
249
291
|
function canonicalSectionOrder(left, right) {
|
|
250
292
|
const leftIndex = SECTION_ORDER.get(left.id) ?? Number.MAX_SAFE_INTEGER;
|
|
@@ -266,6 +308,7 @@ function normalizedInput(input) {
|
|
|
266
308
|
investigationTemplates: Array.isArray(value.investigationTemplates) ? value.investigationTemplates : [],
|
|
267
309
|
bulkReview: record(value.bulkReview) || {},
|
|
268
310
|
analystReviewState: record(value.analystReviewState) || emptyAnalystReviewStateStore(),
|
|
311
|
+
caseViews: value.caseViews ?? emptyCaseViewsStore(),
|
|
269
312
|
settings: record(value.settings) || {},
|
|
270
313
|
};
|
|
271
314
|
}
|
|
@@ -273,7 +316,7 @@ function ensureArchiveBudget(value) {
|
|
|
273
316
|
const serialized = serialize(value);
|
|
274
317
|
const bytes = byteLength(serialized);
|
|
275
318
|
if (bytes > MAX_WORKSPACE_ARCHIVE_BYTES) {
|
|
276
|
-
throw new Error(
|
|
319
|
+
throw new Error(`Workspace archives are limited to ${MAX_WORKSPACE_ARCHIVE_BYTES / 1024 / 1024} MiB. Export smaller collections separately before trying again.`);
|
|
277
320
|
}
|
|
278
321
|
return { serialized, bytes };
|
|
279
322
|
}
|
|
@@ -290,7 +333,7 @@ export async function buildWorkspaceArchive(input, options = {}) {
|
|
|
290
333
|
const data = sections[definition.id];
|
|
291
334
|
const sectionBytes = byteLength(serialize(data));
|
|
292
335
|
if (sectionBytes > MAX_WORKSPACE_ARCHIVE_SECTION_BYTES) {
|
|
293
|
-
throw new Error(`${definition.label} exceeds the
|
|
336
|
+
throw new Error(`${definition.label} exceeds the ${MAX_WORKSPACE_ARCHIVE_SECTION_BYTES / 1024 / 1024} MiB workspace archive section limit.`);
|
|
294
337
|
}
|
|
295
338
|
const recordCount = definition.count(data);
|
|
296
339
|
manifestSections.push({
|
|
@@ -338,8 +381,11 @@ function manifestEntry(raw) {
|
|
|
338
381
|
}
|
|
339
382
|
/** Validate structure, section byte counts, and checksums without applying data. */
|
|
340
383
|
export async function readWorkspaceArchive(raw, options = {}) {
|
|
341
|
-
assertWorkspaceInputGraph(raw, 'Workspace archive');
|
|
342
|
-
|
|
384
|
+
assertWorkspaceInputGraph(raw, 'Workspace archive', { maximumBytes: MAX_WORKSPACE_ARCHIVE_BYTES });
|
|
385
|
+
// Snapshot before the first asynchronous digest: caller-owned data must not
|
|
386
|
+
// change between its checksum, contract checks and eventual import preview.
|
|
387
|
+
const { serialized, bytes } = ensureArchiveBudget(raw);
|
|
388
|
+
const value = record(JSON.parse(serialized));
|
|
343
389
|
if (!value || value.schema !== WORKSPACE_ARCHIVE_SCHEMA) {
|
|
344
390
|
throw new Error('This file is not a WHOISleuth workspace archive.');
|
|
345
391
|
}
|
|
@@ -355,11 +401,10 @@ export async function readWorkspaceArchive(raw, options = {}) {
|
|
|
355
401
|
const sourceVersion = value.version;
|
|
356
402
|
const expectedSectionIds = sourceVersion === PUBLIC_WORKSPACE_ARCHIVE_VERSION
|
|
357
403
|
? PUBLIC_WORKSPACE_ARCHIVE_SECTION_IDS
|
|
358
|
-
: WORKSPACE_ARCHIVE_SECTION_IDS;
|
|
404
|
+
: sourceVersion < 9 ? WORKSPACE_ARCHIVE_SECTION_IDS.filter(id => id !== 'caseViews') : WORKSPACE_ARCHIVE_SECTION_IDS;
|
|
359
405
|
const generatedAt = timestamp(value.generatedAt);
|
|
360
406
|
if (!generatedAt)
|
|
361
407
|
throw new Error('The workspace archive generation time is invalid.');
|
|
362
|
-
const { bytes } = ensureArchiveBudget(value);
|
|
363
408
|
assertExactKeys(value, WORKSPACE_ARCHIVE_ROOT_KEYS, `version ${sourceVersion} envelope`);
|
|
364
409
|
const manifest = record(value.manifest);
|
|
365
410
|
const sectionValues = record(value.sections);
|
|
@@ -423,7 +468,7 @@ export async function readWorkspaceArchive(raw, options = {}) {
|
|
|
423
468
|
else if (definition.count(data) !== entry.recordCount) {
|
|
424
469
|
throw new Error(`${entry.id} does not match its manifest record count.`);
|
|
425
470
|
}
|
|
426
|
-
sections.push({ ...entry, label: definition?.label || entry.id, status, reason, data
|
|
471
|
+
sections.push({ ...entry, label: definition?.label || entry.id, status, reason, data });
|
|
427
472
|
totalRecords += entry.recordCount;
|
|
428
473
|
}
|
|
429
474
|
if (Object.keys(sectionValues).some((id) => !seen.has(id))) {
|
|
@@ -450,6 +495,15 @@ export async function readWorkspaceArchive(raw, options = {}) {
|
|
|
450
495
|
data,
|
|
451
496
|
});
|
|
452
497
|
}
|
|
498
|
+
if (sourceVersion < 9) {
|
|
499
|
+
const data = emptyCaseViewsStore();
|
|
500
|
+
sections.push({
|
|
501
|
+
id: 'caseViews', label: 'Saved Case views', schema: compatibilitySchema(CASE_VIEWS_COMPATIBILITY),
|
|
502
|
+
version: CASE_VIEWS_COMPATIBILITY.currentVersion, recordCount: 0,
|
|
503
|
+
bytes: byteLength(serialize(data)), checksum: await checksum(data, options.cryptoProvider), status: 'ready',
|
|
504
|
+
reason: 'This archive predates saved Case views. Import supplies an empty section and does not remove existing views.', data,
|
|
505
|
+
});
|
|
506
|
+
}
|
|
453
507
|
sections.sort(canonicalSectionOrder);
|
|
454
508
|
return {
|
|
455
509
|
schema: WORKSPACE_ARCHIVE_SCHEMA,
|
|
@@ -491,9 +545,20 @@ function settingsPreview(data, local, mergedProfiles) {
|
|
|
491
545
|
|| (skipped === 0 && activeProfileId !== retainedActiveProfileId));
|
|
492
546
|
return { added: 0, updated, skipped, reason, settings: { activeProfileId, theme } };
|
|
493
547
|
}
|
|
548
|
+
/** Retain one verified snapshot; each read or preview returns an independent copy. */
|
|
549
|
+
export async function prepareWorkspaceArchive(raw, options = {}) {
|
|
550
|
+
const archive = await readWorkspaceArchive(raw, options);
|
|
551
|
+
return Object.freeze({
|
|
552
|
+
read: () => clone(archive),
|
|
553
|
+
preview: (localInput, selection = {}) => previewVerifiedWorkspaceArchive(clone(archive), localInput, selection),
|
|
554
|
+
});
|
|
555
|
+
}
|
|
494
556
|
/** Preview section-specific non-destructive merge outcomes without writing. */
|
|
495
557
|
export async function previewWorkspaceArchive(raw, localInput, options = {}) {
|
|
496
|
-
|
|
558
|
+
// A one-shot preview owns the reader result directly; retained readers copy it.
|
|
559
|
+
return previewVerifiedWorkspaceArchive(await readWorkspaceArchive(raw, options), localInput, options);
|
|
560
|
+
}
|
|
561
|
+
function previewVerifiedWorkspaceArchive(archive, localInput, options) {
|
|
497
562
|
const local = normalizedInput(localInput);
|
|
498
563
|
const results = [];
|
|
499
564
|
let mergedProfiles = local.brandProfiles;
|
|
@@ -520,15 +585,14 @@ export async function previewWorkspaceArchive(raw, localInput, options = {}) {
|
|
|
520
585
|
results.push({
|
|
521
586
|
...section,
|
|
522
587
|
status: 'ready',
|
|
523
|
-
reason:
|
|
524
|
-
? result.reason ?? 'The imported workspace preference was skipped. Existing browser-local context is preserved.'
|
|
525
|
-
: section.reason,
|
|
588
|
+
reason: selected && result.reason ? result.reason : section.reason,
|
|
526
589
|
added: result.added ?? 0,
|
|
527
590
|
updated: result.updated ?? 0,
|
|
528
591
|
skipped: result.skipped ?? 0,
|
|
529
592
|
pruned: result.pruned ?? 0,
|
|
530
593
|
brandProfileReferencesOmitted: result.brandProfileReferencesOmitted ?? 0,
|
|
531
594
|
authoredHistoryOmitted: result.authoredHistoryOmitted ?? 0,
|
|
595
|
+
evidenceHistoryOmitted: result.evidenceHistoryOmitted ?? 0,
|
|
532
596
|
selected,
|
|
533
597
|
normalizedSettings: result.settings || null,
|
|
534
598
|
});
|
|
@@ -569,6 +633,7 @@ export async function previewWorkspaceArchive(raw, localInput, options = {}) {
|
|
|
569
633
|
pruned: 0,
|
|
570
634
|
brandProfileReferencesOmitted: 0,
|
|
571
635
|
authoredHistoryOmitted: 0,
|
|
636
|
+
evidenceHistoryOmitted: 0,
|
|
572
637
|
selected: false,
|
|
573
638
|
normalizedSettings: dependentId === 'settings' ? null : dependentSection.normalizedSettings ?? null,
|
|
574
639
|
};
|