@slicedearth/whoisleuth-cli 1.45.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DISCLOSURE +7 -3
- package/NOTICE +5 -4
- package/README.md +74 -124
- package/SECURITY.md +6 -3
- package/bin/whoisleuth.mjs +7 -4
- package/cli/archive-inspect.mjs +28 -10
- package/cli/arguments.mjs +450 -173
- package/cli/artifact-structure.mjs +2507 -0
- package/cli/artifact-verify.mjs +286 -64
- package/cli/bounded-json.mjs +1 -0
- package/cli/bulk-checkpoint.mjs +35 -23
- package/cli/bulk-command-runner.mjs +2 -5
- package/cli/bulk.mjs +9 -2
- package/cli/case-pack.mjs +435 -46
- package/cli/ci-report.mjs +6 -1
- package/cli/collection-preflight.mjs +2 -2
- package/cli/command-catalogue.mjs +12 -3
- package/cli/command-reference.mjs +948 -106
- package/cli/completion.mjs +504 -218
- package/cli/config-profile.mjs +13 -3
- package/cli/ct-event-intake.mjs +32 -2
- package/cli/discover.mjs +7 -1
- package/cli/discovery-observation-snapshot.mjs +24 -28
- package/cli/discovery-scan-command-runner.mjs +13 -14
- package/cli/discovery-scan.mjs +17 -3
- package/cli/discovery-snapshot.mjs +15 -7
- package/cli/discovery-workflow.mjs +2 -3
- package/cli/doctor.mjs +2 -2
- package/cli/domain-control-monitor.mjs +215 -36
- package/cli/domain-control-observations.mjs +34 -17
- package/cli/errors.mjs +8 -3
- package/cli/evidence-command-runner.mjs +17 -11
- package/cli/evidence-signing.mjs +68 -50
- package/cli/export-evidence.mjs +11 -4
- package/cli/external-observation-mapping.mjs +3 -3
- package/cli/formatters/html.mjs +3 -3
- package/cli/formatters/json.mjs +20 -32
- package/cli/formatters/terminal.mjs +586 -22
- package/cli/input.mjs +62 -0
- package/cli/interactive-launcher.mjs +226 -0
- package/cli/interchange-report.mjs +226 -0
- package/cli/investigation-manifest.mjs +16 -17
- package/cli/investigation-plan.mjs +167 -16
- package/cli/investigation-run.mjs +80 -24
- package/cli/local-mmdb-review.mjs +45 -14
- package/cli/lookalike-calibration.mjs +3 -1
- package/cli/lookup-brief.mjs +13 -8
- package/cli/lookup-browser.mjs +844 -0
- package/cli/lookup-command-runner.mjs +96 -33
- package/cli/lookup-diff.mjs +11 -2
- package/cli/lookup-plan.mjs +1 -0
- package/cli/mail-review.mjs +206 -94
- package/cli/manual.mjs +5 -5
- package/cli/network-command-runner.mjs +78 -0
- package/cli/offline-evidence-review.mjs +45 -14
- package/cli/open-asset-model-bridge.mjs +1 -1
- package/cli/output-file.mjs +70 -14
- package/cli/page-compare.mjs +18 -10
- package/cli/progress-events.mjs +2 -1
- package/cli/progress.mjs +3 -3
- package/cli/registry-cohort.mjs +343 -61
- package/cli/registry-doctor.mjs +67 -28
- package/cli/registry-support.mjs +2 -1
- package/cli/retained-artifact-diff.mjs +375 -0
- package/cli/risk-calibration.mjs +89 -40
- package/cli/runner.mjs +322 -246
- package/cli/saved-lookup.mjs +439 -49
- package/cli/sharing-review.mjs +18 -7
- package/cli/source-reliability.mjs +75 -36
- package/cli/terminal-presentation.mjs +43 -18
- package/docs/cli-reference.md +125 -1334
- package/docs/cli.md +87 -236
- package/frontend/src/lib/analysis/domain-control-manifest-core.js +3 -0
- package/frontend/src/lib/analysis/domain-control-records.js +3 -0
- package/lib/application-version.mjs +3 -0
- package/lib/availability.mjs +72 -52
- package/lib/bounded-contract-normalizers.mjs +2 -4
- package/lib/bounded-file.mjs +91 -4
- package/lib/bounded-json.mjs +287 -0
- package/lib/browser-library-profile.mjs +1 -1
- package/lib/certificate-extension-profile.mjs +2 -1
- package/lib/classify.mjs +56 -5
- package/lib/client-behavior-profile.mjs +1 -1
- package/lib/credential-surface-profile.mjs +1 -1
- package/lib/cryptographic-assurance.mjs +173 -0
- package/lib/ct-query.mjs +3 -3
- package/lib/ct-search.mjs +120 -64
- package/lib/distributed-operation-budget.mjs +4 -2
- package/lib/dns-delegation-health.mjs +9 -6
- package/lib/dns-intelligence.mjs +4 -3
- package/lib/dns-resolver-selection.mjs +6 -4
- package/lib/dnssec-chain-validation.mjs +1052 -0
- package/lib/dnssec-evidence-validation.mjs +23 -10
- package/lib/domain-assurance.mjs +12 -12
- package/lib/domain-change-packet.mjs +7 -5
- package/lib/domain-control-flight-recorder.mjs +442 -78
- package/lib/domain-control-manifest.mjs +314 -171
- package/lib/domain-posture-analysis.mjs +5 -2
- package/lib/domain-posture.mjs +7 -4
- package/lib/encrypted-dns-contract.mjs +2 -3
- package/lib/evidence-export.mjs +1243 -88
- package/lib/evidence-report-markdown.mjs +3 -0
- package/lib/evidence-report.mjs +5 -0
- package/lib/external-intelligence-risk.mjs +26 -10
- package/lib/favicon.mjs +8 -5
- package/lib/feature-policy.mjs +1 -1
- package/lib/homepage-metadata-contract.mjs +290 -0
- package/lib/hostname.mjs +1 -1
- package/lib/html-signals.mjs +89 -5
- package/lib/http-evidence-bounds.mjs +3 -0
- package/lib/http-intelligence.mjs +332 -6
- package/lib/interchange-fidelity-registry.mjs +124 -0
- package/lib/local-geoip-evidence.mjs +2 -1
- package/lib/lookup-cache.mjs +6 -4
- package/lib/lookup-network-evidence-bounds.mjs +9 -0
- package/lib/lookup.mjs +27 -4
- package/lib/observed-network-context.mjs +1 -1
- package/lib/outbound-identity.mjs +2 -3
- package/lib/page-fingerprints.mjs +2 -2
- package/lib/page-role-profile.mjs +1 -1
- package/lib/perceptual-hash.mjs +12 -4
- package/lib/portable-generator.mjs +29 -0
- package/lib/provider-policy-admission.mjs +11 -4
- package/lib/rdap-bootstrap.mjs +76 -16
- package/lib/rdap-client.mjs +20 -12
- package/lib/rdap-normalization.mjs +324 -80
- package/lib/rdap-registrar.mjs +5 -1
- package/lib/rdap-transport.mjs +2 -2
- package/lib/rdap-validation.mjs +65 -14
- package/lib/rdap.mjs +2 -2
- package/lib/registrable-domain.mjs +36 -0
- package/lib/registry-capabilities.mjs +3 -0
- package/lib/registry-capability-catalogue.mjs +12 -2
- package/lib/registry-comparison.mjs +28 -11
- package/lib/registry-insights.mjs +7 -0
- package/lib/response-policy.mjs +27 -4
- package/lib/risk-calibration-summary.mjs +340 -0
- package/lib/risk-scoring.mjs +4 -3
- package/lib/rpki-evidence.mjs +9 -8
- package/lib/safe-fetch.mjs +121 -50
- package/lib/security-txt.mjs +27 -4
- package/lib/service-binding-dns.mjs +6 -1
- package/lib/smtp-transport-review.mjs +787 -0
- package/lib/sslbl-certificates.generated.mjs +136 -134
- package/lib/sslbl-intelligence.mjs +6 -8
- package/lib/static-html-analysis.mjs +301 -4
- package/lib/structured-data-identity.mjs +51 -19
- package/lib/threat-intelligence-fixtures.mjs +2 -4
- package/lib/threat-intelligence-manifests.mjs +2 -7
- package/lib/threat-intelligence-runtime.mjs +5 -15
- package/lib/threat-intelligence-types.mjs +21 -1
- package/lib/threatfox-intelligence.mjs +7 -3
- package/lib/tls-intelligence.mjs +15 -9
- package/lib/tlsa-evidence.mjs +37 -7
- package/lib/urlhaus-intelligence.mjs +4 -2
- package/lib/urlscan-intelligence.mjs +6 -5
- package/lib/website-security-posture.mjs +1 -1
- package/lib/website-technology.mjs +1 -1
- package/lib/whois-authority.mjs +43 -8
- package/lib/whois-chain.mjs +25 -3
- package/lib/whois-normalization.mjs +3 -1
- package/lib/whois-transport.mjs +12 -3
- package/lib/zone-intent-review.mjs +1 -1
- package/package.json +12 -4
- package/packages/cases/case-brand-profile-references.mjs +85 -0
- package/{frontend/src/lib/analysis/case-evidence-model.js → packages/cases/case-evidence-model.mjs} +43 -14
- package/packages/cases/case-investigation-branch-model.mjs +132 -0
- package/packages/cases/case-migration-model.mjs +476 -0
- package/{frontend/src/lib/analysis/case-model.js → packages/cases/case-model.mjs} +3 -3
- package/{frontend/src/lib/analysis/case-record-contracts.js → packages/cases/case-record-contracts.mjs} +3 -19
- package/{frontend/src/lib/analysis/case-record-core.js → packages/cases/case-record-core.mjs} +58 -31
- package/packages/cases/case-record-model.mjs +9 -0
- package/{frontend/src/lib/analysis/case-record-operations.js → packages/cases/case-record-operations.mjs} +106 -33
- package/{frontend/src/lib/analysis/case-report.js → packages/cases/case-report.mjs} +143 -16
- package/packages/cases/case-response-model.mjs +1604 -0
- package/packages/cases/case-response-packet.mjs +1312 -0
- package/{frontend/src/lib/analysis/case-storage-model.js → packages/cases/case-storage-model.mjs} +2 -2
- package/{frontend/src/lib/analysis/http-summary.js → packages/cases/http-summary.mjs} +1 -1
- package/packages/cases/opaque-reference-id.mjs +9 -0
- package/packages/comparison/comparison-ledger-bulk.mjs +366 -0
- package/packages/comparison/comparison-ledger-contract.mjs +241 -0
- package/packages/comparison/comparison-ledger-json.mjs +80 -0
- package/packages/comparison/comparison-ledger-serialization.mjs +52 -0
- package/packages/comparison/favicon-similarity.mjs +78 -0
- package/{frontend/src/lib/analysis/page-similarity.js → packages/comparison/page-similarity.mjs} +4 -3
- package/{frontend/src/lib/analysis/relationship-evidence.js → packages/comparison/relationship-evidence.mjs} +6 -7
- package/packages/contracts/analyst-review-state-contract.mjs +61 -0
- package/packages/contracts/analyst-review-state.mjs +50 -0
- package/packages/contracts/case-portability.mjs +1310 -0
- package/packages/contracts/cli-command-catalogue.mjs +2 -0
- package/packages/contracts/cli-lookup.mjs +394 -0
- package/packages/contracts/domain-control-flight-recorder.mjs +461 -0
- package/packages/contracts/domain-control-manifest.mjs +1027 -0
- package/packages/contracts/domain-control-monitor.mjs +310 -0
- package/packages/contracts/domain-control-review.mjs +828 -0
- package/packages/contracts/domain-name.mjs +4 -0
- package/packages/contracts/external-observation-interchange.mjs +224 -0
- package/packages/contracts/extracted-domain-lifecycle.mjs +218 -0
- package/packages/contracts/investigation-portability.mjs +331 -0
- package/packages/contracts/offline-comparison.mjs +160 -0
- package/packages/contracts/risk-calibration.mjs +1288 -0
- package/packages/contracts/schema-compatibility.mjs +71 -0
- package/packages/contracts/schema-lifecycle.mjs +1702 -0
- package/packages/contracts/sslbl-snapshot.mjs +17 -0
- package/packages/contracts/workspace-portability.mjs +1347 -0
- package/packages/evidence/artifact-integrity.mjs +65 -0
- package/packages/evidence/decision-fact.mjs +735 -0
- package/packages/evidence/domain-control-runtime.mjs +547 -0
- package/packages/evidence/domain-name.mjs +41 -0
- package/packages/evidence/observation.mjs +384 -0
- package/{frontend/src/lib/analysis/external-findings-import.js → packages/interchange/external-findings-import.mjs} +86 -20
- package/packages/interchange/retained-text.mjs +8 -0
- package/{frontend/src/lib/analysis/acquisition-decision-packet.js → packages/investigation/acquisition-decision-packet.mjs} +11 -8
- package/{frontend/src/lib/analysis/bulk-domain-comparison.js → packages/investigation/bulk-domain-comparison.mjs} +28 -9
- package/{frontend/src/lib/analysis/bulk-mail-exposure.js → packages/investigation/bulk-mail-exposure.mjs} +67 -18
- package/{frontend/src/lib/analysis/bulk-review-export.js → packages/investigation/bulk-review-export.mjs} +10 -9
- package/packages/investigation/bulk-review-policy.mjs +1 -0
- package/{frontend/src/lib/analysis/investigation-capsule.js → packages/investigation/investigation-capsule.mjs} +50 -18
- package/packages/investigation/lookup-artefact-inputs.mjs +1 -0
- package/{frontend/src/lib/analysis/lookup-asset-graph.js → packages/investigation/lookup-asset-graph.mjs} +4 -2
- package/packages/investigation/lookup-claim-passport.mjs +232 -0
- package/packages/investigation/lookup-claim-readiness.mjs +287 -0
- package/packages/investigation/lookup-investigation-brief.mjs +172 -0
- package/packages/monitoring/analyst-review-state.mjs +680 -0
- package/{frontend/src/lib/analysis/brand-profile-model.js → packages/workspace/brand-profile-model.mjs} +97 -50
- package/{frontend/src/lib/analysis/bulk-review-model.js → packages/workspace/bulk-review-model.mjs} +15 -15
- package/{frontend/src/lib/analysis/bulk-session-model.js → packages/workspace/bulk-session-model.mjs} +179 -39
- package/{frontend/src/lib/analysis/bulk-sort.js → packages/workspace/bulk-sort.mjs} +12 -5
- package/{frontend/src/lib/analysis/campaign-model.js → packages/workspace/campaign-model.mjs} +20 -22
- package/{frontend/src/lib/analysis/detection-rule-model.js → packages/workspace/detection-rule-model.mjs} +15 -17
- package/packages/workspace/hostile-input.mjs +172 -0
- package/{frontend/src/lib/analysis/investigation-guide.js → packages/workspace/investigation-guide.mjs} +51 -46
- package/{frontend/src/lib/analysis/investigation-template-model.js → packages/workspace/investigation-template-model.mjs} +15 -15
- package/{frontend/src/lib/analysis/page-baseline.js → packages/workspace/page-baseline.mjs} +6 -13
- package/{frontend/src/lib/analysis/relationship-observation-model.js → packages/workspace/relationship-observation-model.mjs} +13 -17
- package/{frontend/src/lib/analysis/shortlist-model.js → packages/workspace/shortlist-model.mjs} +20 -18
- package/{frontend/src/lib/analysis/watchlist-history.js → packages/workspace/watchlist-history.mjs} +9 -16
- package/{frontend/src/lib/analysis/watchlist-store.js → packages/workspace/watchlist-store.mjs} +24 -17
- package/{frontend/src/lib/analysis/website-snapshot-model.js → packages/workspace/website-snapshot-model.mjs} +18 -12
- package/{frontend/src/lib/analysis/workspace-archive-crypto.js → packages/workspace/workspace-archive-crypto.mjs} +49 -19
- package/{frontend/src/lib/analysis/workspace-archive.js → packages/workspace/workspace-archive.mjs} +195 -84
- package/third-party-notices.txt +112 -5834
- package/frontend/src/lib/analysis/artifact-integrity.js +0 -21
- package/frontend/src/lib/analysis/bulk-retry-plan.js +0 -79
- package/frontend/src/lib/analysis/bulk-source-coverage.js +0 -76
- package/frontend/src/lib/analysis/case-migration-model.js +0 -253
- package/frontend/src/lib/analysis/case-record-model.js +0 -7
- package/frontend/src/lib/analysis/case-response-model.js +0 -669
- package/frontend/src/lib/analysis/case-response-packet.js +0 -573
- package/frontend/src/lib/analysis/lookup-decision-support.js +0 -487
- package/frontend/src/lib/analysis/lookup-investigation-brief.js +0 -153
- package/frontend/src/lib/analysis/lookup-presentation.js +0 -58
- package/frontend/src/lib/analysis/lookup-response.js +0 -2
- package/frontend/src/lib/analysis/lookup-source-refresh.js +0 -277
- package/frontend/src/lib/analysis/lookup-summary-model.js +0 -398
- package/frontend/src/lib/analysis/scoring.js +0 -55
- package/frontend/src/lib/analysis/utils.js +0 -232
- package/frontend/src/lib/analysis/visualization-bounds.js +0 -26
- package/frontend/src/lib/analysis/visualization-force-graph.js +0 -352
- package/frontend/src/lib/analysis/visualization-matrix.js +0 -88
- package/frontend/src/lib/analysis/visualization-models.js +0 -369
- package/frontend/src/lib/analysis/visualization-time-series.js +0 -144
- package/lib/bounded-json-response.mjs +0 -157
- package/lib/lookup-response-contract.mjs +0 -346
- package/lib/observation.mjs +0 -114
- /package/{frontend/src/lib/analysis/acquisition-due-diligence.js → packages/investigation/acquisition-due-diligence.mjs} +0 -0
- /package/{frontend/src/lib/analysis/evidence-coverage-ledger.js → packages/investigation/evidence-coverage-ledger.mjs} +0 -0
- /package/{frontend/src/lib/analysis/dns-record-normalization.js → packages/workspace/dns-record-normalization.mjs} +0 -0
package/docs/cli.md
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
# WHOISleuth CLI guide
|
|
2
2
|
|
|
3
|
-
The first-party CLI runs
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
[
|
|
8
|
-
artefact
|
|
3
|
+
The first-party CLI runs on the operator's machine and does not call the hosted
|
|
4
|
+
WHOISleuth deployment. Use this guide for installation, common commands,
|
|
5
|
+
collection boundaries and output. Installed `whoisleuth --help`, focused
|
|
6
|
+
`--help` and `whoisleuth commands` output are the authority for that installed
|
|
7
|
+
version. The [CLI reference](cli-reference.md) covers durable command and
|
|
8
|
+
artefact contracts.
|
|
9
|
+
|
|
10
|
+
The generated [privacy and data-flow catalogue](https://github.com/slicedearth/whoisleuth/blob/main/docs/privacy-data-flow-catalogue.md)
|
|
11
|
+
lists the network, recipient, retention and export boundary for every command.
|
|
9
12
|
|
|
10
13
|
## Installation
|
|
11
14
|
|
|
12
|
-
Public releases require Node.js 24 or later
|
|
13
|
-
command:
|
|
15
|
+
Public releases require Node.js 24 or later:
|
|
14
16
|
|
|
15
17
|
```bash
|
|
16
18
|
npm exec --yes --ignore-scripts --package=@slicedearth/whoisleuth-cli -- whoisleuth --help
|
|
@@ -26,277 +28,126 @@ whoisleuth --version
|
|
|
26
28
|
whoisleuth doctor
|
|
27
29
|
```
|
|
28
30
|
|
|
29
|
-
The
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
From a repository checkout, replace `whoisleuth` with
|
|
35
|
-
`node bin/whoisleuth.mts`. Maintainers can assemble, install, and smoke-test the
|
|
36
|
-
exact compiled package closure without publishing it:
|
|
37
|
-
|
|
38
|
-
```bash
|
|
39
|
-
npm run cli:package:check
|
|
40
|
-
```
|
|
31
|
+
The package and application share one semantic version. The package requires no
|
|
32
|
+
dependency lifecycle scripts. From a repository checkout, replace `whoisleuth`
|
|
33
|
+
with `node bin/whoisleuth.mts`; maintainers can verify the exact package closure
|
|
34
|
+
with `npm run cli:package:check`.
|
|
41
35
|
|
|
42
36
|
## First commands
|
|
43
37
|
|
|
44
|
-
Inspect the installed
|
|
38
|
+
Inspect the installed command set and plan one Lookup before collecting:
|
|
45
39
|
|
|
46
40
|
```bash
|
|
47
41
|
whoisleuth --help
|
|
48
|
-
whoisleuth commands
|
|
42
|
+
whoisleuth commands --common
|
|
49
43
|
whoisleuth doctor
|
|
50
|
-
whoisleuth lookup example.
|
|
44
|
+
whoisleuth lookup example.test --plan --json
|
|
51
45
|
```
|
|
52
46
|
|
|
53
|
-
Run
|
|
47
|
+
Run Fast or Deep Lookup:
|
|
54
48
|
|
|
55
49
|
```bash
|
|
56
|
-
whoisleuth
|
|
57
|
-
whoisleuth lookup example.
|
|
58
|
-
whoisleuth lookup example.
|
|
59
|
-
whoisleuth lookup example.
|
|
50
|
+
whoisleuth example.test
|
|
51
|
+
whoisleuth lookup example.test --deep
|
|
52
|
+
whoisleuth lookup example.test --deep --summary
|
|
53
|
+
whoisleuth lookup example.test --deep --browse
|
|
54
|
+
whoisleuth lookup example.test --deep --markdown --output lookup.md
|
|
60
55
|
```
|
|
61
56
|
|
|
62
|
-
Process
|
|
63
|
-
saved result without sending it anywhere:
|
|
57
|
+
Process selected local input:
|
|
64
58
|
|
|
65
59
|
```bash
|
|
66
60
|
whoisleuth bulk domains.txt --csv
|
|
67
|
-
whoisleuth discover example.
|
|
68
|
-
whoisleuth verify-artifact lookup.json --json
|
|
61
|
+
whoisleuth discover example.test --preset common --jsonl
|
|
62
|
+
whoisleuth verify-artifact lookup.json --json --strict-exit
|
|
69
63
|
whoisleuth compare lookup.json --json
|
|
70
64
|
whoisleuth brief lookup.json
|
|
71
|
-
whoisleuth registry-doctor lookup.json --json
|
|
72
65
|
```
|
|
73
66
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
## Collection profiles
|
|
79
|
-
|
|
80
|
-
Commands are classified as either networked or offline in focused help, the
|
|
81
|
-
generated manual, and `commands --json`.
|
|
82
|
-
|
|
83
|
-
| Profile | Boundary |
|
|
84
|
-
| --- | --- |
|
|
85
|
-
| Fast Lookup | Conservative default for domain triage. It does not run WHOIS or deep website and TLS collection. |
|
|
86
|
-
| Deep Lookup | Explicitly requested bounded RDAP, WHOIS, DNS, website, TLS, registrar-RDAP, and observed-network work where applicable. |
|
|
87
|
-
| Compact deep Bulk | Uses the shared Lookup orchestration but omits full-only response fields and collectors. |
|
|
88
|
-
| Offline review | Reads only the named bounded artefact or analyst-authored input and makes no network request. |
|
|
89
|
-
|
|
90
|
-
Networked commands run from the local machine and contact the sources declared
|
|
91
|
-
by their profile. They do not use the hosted login or hosted usage controls;
|
|
92
|
-
upstream services can see and rate-limit the local network address. The CLI
|
|
93
|
-
does not implicitly enable the browser Console's optional external intelligence
|
|
94
|
-
actions.
|
|
95
|
-
|
|
96
|
-
`lookup --plan` performs classification and emits a versioned preflight without
|
|
97
|
-
starting collection. It lists planned source families and disclosure targets,
|
|
98
|
-
but cannot predict cache state, live configuration, redirects, referrals,
|
|
99
|
-
source availability, or exact request count.
|
|
67
|
+
One strict domain, IP address or ASN can occupy command position as Lookup
|
|
68
|
+
shorthand. URL-like or ambiguous input requires the explicit `lookup` command.
|
|
69
|
+
Only `bulk` accepts multiple targets.
|
|
100
70
|
|
|
101
|
-
|
|
102
|
-
bounded checks against fixed diagnostic infrastructure and retains only state,
|
|
103
|
-
HTTP status, and a bounded explanation.
|
|
71
|
+
## Command groups
|
|
104
72
|
|
|
105
|
-
|
|
73
|
+
The installed registry groups commands under the same analyst vocabulary as the
|
|
74
|
+
application:
|
|
106
75
|
|
|
107
|
-
|
|
|
76
|
+
| Group | Common commands |
|
|
108
77
|
| --- | --- |
|
|
109
|
-
| Investigate
|
|
110
|
-
|
|
|
111
|
-
|
|
|
112
|
-
|
|
|
113
|
-
| Plan and assure changes | `domain-control`, `monitor-once`, `assurance`, `change-packet`, `workflow-plan`, `workflow-run` |
|
|
114
|
-
| Verify and package evidence | `case-pack`, `manifest`, `oam-export`, `verify-artifact`, `inspect-archive`, `sign-artifact`, `verify-signature`, `export` |
|
|
115
|
-
| Calibrate offline | `risk-calibrate`, `lookalike-calibrate` |
|
|
116
|
-
| Operate the CLI | `doctor`, `registry-scaffold`, `commands`, `completion`, `manual` |
|
|
78
|
+
| Investigate | `lookup`, `bulk`, `discover`, `ct-search`, `posture`, `http`, `tls`, `compare`, `brief` |
|
|
79
|
+
| Respond | `case-pack`, `change-packet`, `sharing-review`, `export` |
|
|
80
|
+
| Assure | `dnssec-validate`, `mail-transport`, `domain-control`, `assurance`, `workflow-plan`, `diff`, `inspect-archive`, `verify-artifact` |
|
|
81
|
+
| Utilities | `doctor`, `commands`, `completion`, `manual`, `registry-scaffold` |
|
|
117
82
|
|
|
118
|
-
|
|
83
|
+
Filter the canonical index without running the selected commands:
|
|
119
84
|
|
|
120
85
|
```bash
|
|
121
|
-
whoisleuth
|
|
122
|
-
whoisleuth
|
|
86
|
+
whoisleuth commands --group investigate
|
|
87
|
+
whoisleuth commands --group respond --mode offline
|
|
123
88
|
whoisleuth commands --json
|
|
124
89
|
whoisleuth manual | man -l -
|
|
125
90
|
```
|
|
126
91
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
restrained semantic colour and transient progress on stderr. Redirected output,
|
|
131
|
-
JSON, and JSONL contain no ANSI sequences or progress text. State remains
|
|
132
|
-
explicit in text, so colour is never the only distinction.
|
|
133
|
-
|
|
134
|
-
- `--json` and `--jsonl` provide bounded machine-readable documents.
|
|
135
|
-
- `--summary` and `--verbose` change human detail without changing collection.
|
|
136
|
-
- `--no-color` or `NO_COLOR` disables colour.
|
|
137
|
-
- `WHOISLEUTH_NO_PROGRESS=1` disables the transient progress indicator.
|
|
138
|
-
- `--events` keeps the final document on stdout and writes versioned JSONL
|
|
139
|
-
lifecycle events to stderr.
|
|
140
|
-
- `--strict-exit` treats failures in explicitly requested source families as a
|
|
141
|
-
partial failure while keeping skipped or unsupported sources neutral.
|
|
142
|
-
- `--fail-on` applies explicit `source-failure`, `inconclusive`, `danger`, or
|
|
143
|
-
`material-drift` automation policy where the selected command supports it.
|
|
144
|
-
- `--junit` emits bounded CI test cases for Lookup, Bulk, and one-shot control
|
|
145
|
-
reviews; owned-domain Posture can emit `--sarif` only with
|
|
146
|
-
`--owned-domain`.
|
|
147
|
-
|
|
148
|
-
`--config <file> --profile <name>` applies a strict version-1 local profile.
|
|
149
|
-
The default path is `$XDG_CONFIG_HOME/whoisleuth/config.json`. Profiles can set
|
|
150
|
-
only presentation mode, Fast collection, bounded concurrency, and observer or
|
|
151
|
-
vantage labels. They cannot add targets, enable Deep collection, select output
|
|
152
|
-
paths, approve network work, or set failure policy. Explicit command options
|
|
153
|
-
override defaults from the same option group.
|
|
154
|
-
|
|
155
|
-
Every command accepts `--output <file>`. WHOISleuth buffers bounded output,
|
|
156
|
-
creates a private temporary file beside the destination, syncs it, and publishes
|
|
157
|
-
it atomically with mode `0600`. Existing destinations are refused unless
|
|
158
|
-
`--force` is deliberately combined with `--output`. Failed or cancelled
|
|
159
|
-
commands do not publish partial files. Output is capped at 32 MiB.
|
|
160
|
-
|
|
161
|
-
## Exit codes
|
|
162
|
-
|
|
163
|
-
| Code | Meaning |
|
|
164
|
-
| ---: | --- |
|
|
165
|
-
| 0 | Command completed. Individual sources can still be partial or inconclusive; inspect diagnostics. |
|
|
166
|
-
| 2 | Invalid command, option, input, or stdin shape. |
|
|
167
|
-
| 3 | The requested lookup, collection, or comparison could not run. |
|
|
168
|
-
| 4 | A bounded operation completed partially. |
|
|
169
|
-
| 70 | Unexpected CLI bootstrap failure. |
|
|
170
|
-
| 130 | The analyst cancelled the command; no partial final result was emitted. |
|
|
171
|
-
| 143 | The process received SIGTERM; no partial final result was emitted. |
|
|
172
|
-
|
|
173
|
-
## Detailed command reference
|
|
174
|
-
|
|
175
|
-
The headings below preserve the established guide anchors while moving their
|
|
176
|
-
full contracts into the packaged reference.
|
|
177
|
-
|
|
178
|
-
### Registry capability coverage
|
|
179
|
-
|
|
180
|
-
[Read the complete registry capability reference.](cli-reference.md#registry-capability-coverage)
|
|
181
|
-
|
|
182
|
-
### Offline Risk calibration
|
|
183
|
-
|
|
184
|
-
[Read the calibration dataset and replay contract.](cli-reference.md#offline-risk-calibration)
|
|
185
|
-
|
|
186
|
-
### Lookalike review-yield calibration
|
|
187
|
-
|
|
188
|
-
[Read the reviewed candidate calibration contract.](cli-reference.md#lookalike-review-yield-calibration)
|
|
189
|
-
|
|
190
|
-
### Offline artefact verification
|
|
191
|
-
|
|
192
|
-
[Read the archive, saved Lookup, and signed-artefact verification contract.](cli-reference.md#offline-artefact-verification)
|
|
193
|
-
|
|
194
|
-
### Privacy-safe source reliability report
|
|
195
|
-
|
|
196
|
-
[Read the target-free source diagnostic contract.](cli-reference.md#privacy-safe-source-reliability-report)
|
|
197
|
-
|
|
198
|
-
### Workspace archive inspection
|
|
199
|
-
|
|
200
|
-
[Read the redacted archive summary, stable content-digest, transfer-check, and
|
|
201
|
-
search contract.](cli-reference.md#workspace-archive-inspection)
|
|
202
|
-
|
|
203
|
-
### Optional evidence-package signing
|
|
204
|
-
|
|
205
|
-
[Read the local signing and verification contract.](cli-reference.md#optional-evidence-package-signing)
|
|
206
|
-
|
|
207
|
-
### Reproducible investigation manifest
|
|
208
|
-
|
|
209
|
-
[Read the ordered, path-free artefact digest contract.](cli-reference.md#reproducible-investigation-manifest)
|
|
92
|
+
`registry-scaffold` has a separate fixture bootstrap contract: its `--profile`
|
|
93
|
+
selects one fixed fixture profile and it rejects shared `--config` profiles.
|
|
94
|
+
It creates sanitised local fixtures and does not contact a registry.
|
|
210
95
|
|
|
211
|
-
|
|
96
|
+
## Collection boundaries
|
|
212
97
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
[Read the offline, source-qualified event import contract.](cli-reference.md#local-certificate-event-intake)
|
|
222
|
-
|
|
223
|
-
### Declarative observation interchange
|
|
224
|
-
|
|
225
|
-
[Read the bounded field-mapping and Open Asset Model bridge contracts.](cli-reference.md#declarative-observation-interchange)
|
|
226
|
-
|
|
227
|
-
### Lookalike discovery
|
|
228
|
-
|
|
229
|
-
[Read candidate generation, dictionaries, snapshots, and output behaviour.](cli-reference.md#lookalike-discovery)
|
|
230
|
-
|
|
231
|
-
### Supervised candidate scan
|
|
232
|
-
|
|
233
|
-
[Read the bounded candidate collection workflow.](cli-reference.md#supervised-candidate-scan)
|
|
234
|
-
|
|
235
|
-
### Domain posture audit
|
|
236
|
-
|
|
237
|
-
[Read the DNS, mail, and certificate posture contract.](cli-reference.md#domain-posture-audit)
|
|
238
|
-
|
|
239
|
-
### HTTP intelligence
|
|
240
|
-
|
|
241
|
-
[Read the bounded HTTP collection contract.](cli-reference.md#http-intelligence)
|
|
242
|
-
|
|
243
|
-
### TLS intelligence
|
|
244
|
-
|
|
245
|
-
[Read the bounded TLS collection contract.](cli-reference.md#tls-intelligence)
|
|
246
|
-
|
|
247
|
-
### Registry-source comparison
|
|
248
|
-
|
|
249
|
-
[Read the normalised RDAP and WHOIS comparison contract.](cli-reference.md#registry-source-comparison)
|
|
250
|
-
|
|
251
|
-
### Static page comparison
|
|
252
|
-
|
|
253
|
-
[Read saved page-identity comparison behaviour.](cli-reference.md#static-page-comparison)
|
|
254
|
-
|
|
255
|
-
### Passive mail exposure review
|
|
256
|
-
|
|
257
|
-
[Read the saved-evidence mail review contract.](cli-reference.md#passive-mail-exposure-review)
|
|
258
|
-
|
|
259
|
-
### Offline supplied-evidence review
|
|
260
|
-
|
|
261
|
-
[Read the DNSSEC, DANE, zone-intent, portfolio, domain-change, and supplied-observation review contract.](cli-reference.md#offline-supplied-evidence-review)
|
|
262
|
-
|
|
263
|
-
### Domain control manifests
|
|
264
|
-
|
|
265
|
-
[Read desired-state manifest and drift-review behaviour.](cli-reference.md#domain-control-manifests)
|
|
266
|
-
|
|
267
|
-
### Domain assurance review
|
|
268
|
-
|
|
269
|
-
[Read planned-change, recovery-dependency, and retirement contracts.](cli-reference.md#domain-assurance-review)
|
|
270
|
-
|
|
271
|
-
### Domain change assurance packet
|
|
272
|
-
|
|
273
|
-
[Read the bounded pre-change, post-change, planning, and integrity contract.](cli-reference.md#domain-change-assurance-packet)
|
|
274
|
-
|
|
275
|
-
### Pre-sharing review
|
|
98
|
+
| Mode | Behaviour |
|
|
99
|
+
| --- | --- |
|
|
100
|
+
| Fast Lookup | Registration-first triage without WHOIS or deeper website and TLS collection. |
|
|
101
|
+
| Deep Lookup | Explicit RDAP, WHOIS, DNS, website, TLS, registrar-RDAP and observed-network collection where applicable. |
|
|
102
|
+
| Compact Deep Bulk | Comparison fields from shared Lookup orchestration, omitting full-only collectors and response fields. |
|
|
103
|
+
| Offline | Reads only the named local artefact, stdin or built-in catalogue. |
|
|
104
|
+
| Authorised active | Requires its dedicated command and per-run owned-or-authorised acknowledgement. |
|
|
276
105
|
|
|
277
|
-
|
|
106
|
+
Networked commands run from the local machine and contact the sources named in
|
|
107
|
+
their focused help. They do not use the hosted login or hosted usage controls.
|
|
108
|
+
`lookup --plan` lists planned source families and disclosure targets before
|
|
109
|
+
collection. `doctor` is offline unless `--network` is selected.
|
|
278
110
|
|
|
279
|
-
|
|
111
|
+
## Output and automation
|
|
280
112
|
|
|
281
|
-
|
|
113
|
+
Terminal text is the default. Commands expose JSON, JSONL, CSV, Markdown, HTML
|
|
114
|
+
or domain-only output only where declared by the installed registry. Redirected
|
|
115
|
+
and machine output contains no ANSI or transient progress text.
|
|
282
116
|
|
|
283
|
-
|
|
117
|
+
- `--summary` and `--verbose` change presentation, not collection.
|
|
118
|
+
- `lookup --browse` provides an interactive terminal view; press `?` for keys.
|
|
119
|
+
- `--events` writes versioned lifecycle events to stderr.
|
|
120
|
+
- `--strict-exit` and `--fail-on` expose selected evidence states to automation.
|
|
121
|
+
- `--output` writes a private local file atomically and refuses an existing path
|
|
122
|
+
unless `--force` is also selected.
|
|
284
123
|
|
|
285
|
-
|
|
124
|
+
Local configuration profiles can set presentation, Fast collection, bounded
|
|
125
|
+
concurrency and observer labels. They cannot add targets, enable Deep
|
|
126
|
+
collection, choose output paths or approve network work. Explicit command
|
|
127
|
+
options override profile defaults.
|
|
286
128
|
|
|
287
|
-
|
|
129
|
+
## Exit codes
|
|
288
130
|
|
|
289
|
-
|
|
131
|
+
| Code | Meaning |
|
|
132
|
+
| ---: | --- |
|
|
133
|
+
| 0 | The command completed. |
|
|
134
|
+
| 2 | Invalid command, option or input. |
|
|
135
|
+
| 3 | Collection, lookup or comparison failed. |
|
|
136
|
+
| 4 | The result was partial or a selected evidence policy was not met. |
|
|
137
|
+
| 70 | Internal CLI bootstrap failure. |
|
|
138
|
+
| 130 | The analyst cancelled the command. |
|
|
139
|
+
| 143 | The process received SIGTERM. |
|
|
290
140
|
|
|
291
|
-
|
|
141
|
+
## Command details
|
|
292
142
|
|
|
293
|
-
|
|
143
|
+
Run `whoisleuth <command> --help` for exact arguments, input ceilings, network
|
|
144
|
+
effects and output formats. The packaged [CLI reference](cli-reference.md) gives
|
|
145
|
+
the longer-lived compatibility and evidence contracts, while the generated
|
|
146
|
+
[online command reference](https://whoisleuth.com/cli#commands) provides a searchable index.
|
|
294
147
|
|
|
295
148
|
## Safety and limitations
|
|
296
149
|
|
|
297
150
|
WHOISleuth is a defensive investigation tool, not an authorisation mechanism.
|
|
298
|
-
Operators remain responsible for applicable law
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
Offline analyst assertions remain separately attributed and are not converted
|
|
302
|
-
into observed facts.
|
|
151
|
+
Operators remain responsible for permission, applicable law and provider terms.
|
|
152
|
+
Incomplete evidence remains explicitly qualified, and analyst assertions remain
|
|
153
|
+
separate from observed facts.
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
// Historical browser-safe import facade. The pure domain-control manifest
|
|
2
|
+
// contract is shared by browser, CLI, and Node adapters.
|
|
3
|
+
export { DOMAIN_CONTROL_MANIFEST_VERSION, DOMAIN_CONTROL_PASSPORT_INPUT_SCHEMA, DOMAIN_CONTROL_PASSPORT_LIMITATIONS, DOMAIN_CONTROL_PASSPORT_SCHEMA, DOMAIN_CONTROL_PASSPORT_VERSION, MAX_DOMAIN_CONTROL_MANIFEST_BYTES, MAX_DOMAIN_CONTROL_PASSPORT_BYTES, MAX_DOMAIN_CONTROL_PASSPORT_ENTRIES, assertDomainControlPassportByteBudget, buildUnsignedDomainControlPassport, domainControlPassportSerialisedBytes, normalizeDomainControlPassportDocument, } from "../../../../packages/evidence/domain-control-runtime.mjs";
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
// Historical browser-safe import facade. Domain-control record normalisation
|
|
2
|
+
// is owned by the pure evidence package and shared unchanged across runtimes.
|
|
3
|
+
export { MAX_CANONICAL_DOMAIN_CONTROL_RECORDS, canonicalCaaRecord, canonicalDomainControlRecordList, canonicalDsRecord, canonicalMxRecord, } from "../../../../packages/evidence/domain-control-runtime.mjs";
|
package/lib/availability.mjs
CHANGED
|
@@ -32,10 +32,24 @@ function errorRecord(value) {
|
|
|
32
32
|
? value
|
|
33
33
|
: {};
|
|
34
34
|
}
|
|
35
|
+
function registryStatusToken(value) {
|
|
36
|
+
return value.toLowerCase().replace(/[^a-z0-9]+/gu, '');
|
|
37
|
+
}
|
|
35
38
|
function rdapEventDate(events, action) {
|
|
36
39
|
const date = events.find((event) => event.action === action)?.date;
|
|
37
40
|
return typeof date === 'string' ? date : null;
|
|
38
41
|
}
|
|
42
|
+
function withoutHttpDeliveryMetadata(value) {
|
|
43
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
44
|
+
return value;
|
|
45
|
+
const output = { ...value };
|
|
46
|
+
if (output.response && typeof output.response === 'object' && !Array.isArray(output.response)) {
|
|
47
|
+
const response = { ...output.response };
|
|
48
|
+
delete response.deliveryMetadata;
|
|
49
|
+
output.response = response;
|
|
50
|
+
}
|
|
51
|
+
return output;
|
|
52
|
+
}
|
|
39
53
|
// No marketplace (Afternic/Sedo/Dan.com/GoDaddy Auctions/etc.) offers a
|
|
40
54
|
// free, no-auth API to check "is this specific domain listed for sale" -
|
|
41
55
|
// what's checkable without credentials is the parking/landing-page
|
|
@@ -115,18 +129,17 @@ const PRIVACY_MARKERS = [
|
|
|
115
129
|
/not disclosed/i,
|
|
116
130
|
/withheld for privacy/i,
|
|
117
131
|
];
|
|
118
|
-
//
|
|
119
|
-
//
|
|
120
|
-
//
|
|
121
|
-
//
|
|
122
|
-
//
|
|
123
|
-
// same practical answer as an explicit privacy-proxy service: no.
|
|
132
|
+
// Explicit privacy/redaction markers establish a positive privacy signal.
|
|
133
|
+
// Usable public contact data establishes a negative one. A missing or blank
|
|
134
|
+
// contact can instead reflect registry policy, access tier, parser coverage,
|
|
135
|
+
// or ordinary omission, so it remains inconclusive rather than being promoted
|
|
136
|
+
// to an affirmative privacy claim.
|
|
124
137
|
function isPrivacyProtected(registrant) {
|
|
125
138
|
if (!registrant)
|
|
126
|
-
return
|
|
139
|
+
return null;
|
|
127
140
|
const blob = [registrant.name, registrant.org, registrant.email].filter(Boolean).join(' ');
|
|
128
141
|
if (!blob)
|
|
129
|
-
return
|
|
142
|
+
return null;
|
|
130
143
|
return PRIVACY_MARKERS.some((re) => re.test(blob));
|
|
131
144
|
}
|
|
132
145
|
// RDAP Lookup retains a bounded multi-value contact inventory, but Bulk and
|
|
@@ -197,7 +210,10 @@ async function checkDnsDelegation(domain, { resolver = dns.resolveNs } = {}) {
|
|
|
197
210
|
// domain has "no site": transient DNS/TLS/network failures, a slow origin, or
|
|
198
211
|
// an HTTP error can all produce the same null body. Keeping that distinction
|
|
199
212
|
// avoids turning an inconclusive probe into a false inactivity claim.
|
|
200
|
-
async function fetchHomepage(domain, { fetcher = safeFetchDetailed } = {}) {
|
|
213
|
+
async function fetchHomepage(domain, { fetcher = safeFetchDetailed, timeoutMs = HOMEPAGE_FETCH_TIMEOUT_MS } = {}) {
|
|
214
|
+
const requestTimeoutMs = Number.isInteger(timeoutMs) && timeoutMs >= 10 && timeoutMs <= HOMEPAGE_FETCH_TIMEOUT_MS
|
|
215
|
+
? timeoutMs
|
|
216
|
+
: HOMEPAGE_FETCH_TIMEOUT_MS;
|
|
201
217
|
const headers = whoisleuthRequestHeaders();
|
|
202
218
|
const failures = [];
|
|
203
219
|
const probeStartedAt = Date.now();
|
|
@@ -205,7 +221,7 @@ async function fetchHomepage(domain, { fetcher = safeFetchDetailed } = {}) {
|
|
|
205
221
|
const requestUrl = `${scheme}://${domain}`;
|
|
206
222
|
const attemptStartedAt = Date.now();
|
|
207
223
|
const controller = new AbortController();
|
|
208
|
-
const timeout = setTimeout(() => controller.abort(),
|
|
224
|
+
const timeout = setTimeout(() => controller.abort(), requestTimeoutMs);
|
|
209
225
|
try {
|
|
210
226
|
const fetched = await fetcher(requestUrl, { signal: controller.signal, headers });
|
|
211
227
|
const fetchedResponse = fetched instanceof Response ? fetched : fetched.response;
|
|
@@ -274,7 +290,7 @@ async function fetchHomepage(domain, { fetcher = safeFetchDetailed } = {}) {
|
|
|
274
290
|
catch (err) {
|
|
275
291
|
const error = errorRecord(err);
|
|
276
292
|
const reason = error.name === 'AbortError'
|
|
277
|
-
?
|
|
293
|
+
? `timed out after ${requestTimeoutMs} milliseconds`
|
|
278
294
|
: nonEmptyErrorMessage(err, 'request failed')
|
|
279
295
|
.replace(/[\u0000-\u001f\u007f]+/g, ' ')
|
|
280
296
|
.slice(0, 180);
|
|
@@ -446,40 +462,39 @@ async function checkDomainAvailability(domain, options = {}) {
|
|
|
446
462
|
source: 'whois',
|
|
447
463
|
};
|
|
448
464
|
}
|
|
449
|
-
if (parsed.
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
registrar
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|| registrar || createdDate || expiryDate || nameservers.length > 0 || statuses.length > 0) {
|
|
465
|
+
if (parsed.registrationStatus === 'registered') {
|
|
466
|
+
if (parsed.nameservers.length)
|
|
467
|
+
nameservers = parsed.nameservers;
|
|
468
|
+
if (parsed.statuses.length)
|
|
469
|
+
statuses = parsed.statuses.map((status) => status.toLowerCase());
|
|
470
|
+
if (parsed.registrar) {
|
|
471
|
+
registrar = {
|
|
472
|
+
handle: null,
|
|
473
|
+
ianaId: parsed.registrarIanaId || null,
|
|
474
|
+
name: parsed.registrar,
|
|
475
|
+
org: null,
|
|
476
|
+
email: parsed.abuseEmail || null,
|
|
477
|
+
phone: parsed.abusePhone || null,
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
if (parsed.registrantName || parsed.registrantOrg || parsed.registrantEmail || parsed.registrantPhone) {
|
|
481
|
+
registrant = {
|
|
482
|
+
handle: null,
|
|
483
|
+
name: parsed.registrantName || null,
|
|
484
|
+
org: parsed.registrantOrg || null,
|
|
485
|
+
email: parsed.registrantEmail || null,
|
|
486
|
+
phone: parsed.registrantPhone || null,
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
if (parsed.abuseEmail || parsed.abusePhone) {
|
|
490
|
+
abuse = { handle: null, name: null, org: parsed.registrar || null, email: parsed.abuseEmail || null, phone: parsed.abusePhone || null };
|
|
491
|
+
}
|
|
492
|
+
createdDate = parsed.createdDate || null;
|
|
493
|
+
expiryDate = parsed.expiryDate || null;
|
|
494
|
+
createdDateIso = parsed.createdDateIso || parsed.lifecycle?.createdDateIso || registryDateIso(createdDate);
|
|
495
|
+
expiryDateIso = parsed.expiryDateIso || parsed.lifecycle?.expiryDateIso || registryDateIso(expiryDate);
|
|
496
|
+
if (!dnssec)
|
|
497
|
+
dnssec = parsed.dnssec || null;
|
|
483
498
|
registrationSource = 'whois';
|
|
484
499
|
}
|
|
485
500
|
}
|
|
@@ -491,9 +506,7 @@ async function checkDomainAvailability(domain, options = {}) {
|
|
|
491
506
|
// registration evidence either - e.g. the registry answered inconclusively
|
|
492
507
|
// or every referral hop failed/rate-limited. Report "unknown" rather than
|
|
493
508
|
// fabricating "registered" from an empty record.
|
|
494
|
-
const hasWhoisRegistrationData = whoisParsed?.registrationStatus === 'registered'
|
|
495
|
-
|| Boolean(registrar) || Boolean(createdDate) || Boolean(expiryDate)
|
|
496
|
-
|| nameservers.length > 0 || statuses.length > 0;
|
|
509
|
+
const hasWhoisRegistrationData = whoisParsed?.registrationStatus === 'registered';
|
|
497
510
|
let dnsDelegated = false;
|
|
498
511
|
if (!rdapFound && !hasWhoisRegistrationData && dnsDelegationPromise) {
|
|
499
512
|
const delegation = await dnsDelegationPromise;
|
|
@@ -547,7 +560,10 @@ async function checkDomainAvailability(domain, options = {}) {
|
|
|
547
560
|
dnssec,
|
|
548
561
|
source: registrationSource,
|
|
549
562
|
};
|
|
550
|
-
if (statuses.some((
|
|
563
|
+
if (statuses.some((status) => {
|
|
564
|
+
const normalizedStatus = registryStatusToken(status);
|
|
565
|
+
return normalizedStatus.includes('pendingdelete') || normalizedStatus.includes('redemptionperiod');
|
|
566
|
+
})) {
|
|
551
567
|
return {
|
|
552
568
|
state: 'expiring',
|
|
553
569
|
confidence: 'medium',
|
|
@@ -646,6 +662,7 @@ async function checkDomainAvailability(domain, options = {}) {
|
|
|
646
662
|
responseHeaders: homepage.technologyHeaders,
|
|
647
663
|
activityStatus,
|
|
648
664
|
includePageIdentity: pageIdentityEligible,
|
|
665
|
+
includePublicationMetadata: options.includePublicationMetadata !== false,
|
|
649
666
|
...(options.includeCredentialSurfaceProfile !== undefined
|
|
650
667
|
? { includeCredentialSurfaceProfile: options.includeCredentialSurfaceProfile }
|
|
651
668
|
: {}),
|
|
@@ -659,6 +676,9 @@ async function checkDomainAvailability(domain, options = {}) {
|
|
|
659
676
|
}
|
|
660
677
|
}
|
|
661
678
|
const responsePolicy = qualifyResponsePolicyWithCspMeta(homepage.responsePolicy, htmlSignals.cspMetaPolicy);
|
|
679
|
+
const retainedHttp = options.includeDeliveryMetadata === false
|
|
680
|
+
? withoutHttpDeliveryMetadata(homepage.http)
|
|
681
|
+
: homepage.http;
|
|
662
682
|
const { cspMetaPolicy: _cspMetaPolicy, ...retainedHtmlSignals } = htmlSignals;
|
|
663
683
|
const securityPosture = options.includeSecurityPosture === false ? null : analyzeWebsiteSecurityPosture({
|
|
664
684
|
http: homepage.http,
|
|
@@ -692,7 +712,7 @@ async function checkDomainAvailability(domain, options = {}) {
|
|
|
692
712
|
activityStatus,
|
|
693
713
|
websiteProbeStatus,
|
|
694
714
|
websiteProbeDetail,
|
|
695
|
-
http:
|
|
715
|
+
http: retainedHttp,
|
|
696
716
|
deepScanComplete,
|
|
697
717
|
faviconHash,
|
|
698
718
|
faviconPHash,
|
|
@@ -716,7 +736,7 @@ async function checkDomainAvailability(domain, options = {}) {
|
|
|
716
736
|
activityStatus,
|
|
717
737
|
websiteProbeStatus,
|
|
718
738
|
websiteProbeDetail,
|
|
719
|
-
http:
|
|
739
|
+
http: retainedHttp,
|
|
720
740
|
deepScanComplete,
|
|
721
741
|
faviconHash,
|
|
722
742
|
faviconPHash,
|
|
@@ -733,4 +753,4 @@ async function checkDomainAvailability(domain, options = {}) {
|
|
|
733
753
|
hasDmarc: dnsIntelligence.hasDmarc,
|
|
734
754
|
};
|
|
735
755
|
}
|
|
736
|
-
export { checkDomainAvailability, checkDnsDelegation, fetchHomepage, deriveWebsiteActivity, forSaleRedirectSignal, parseRegistryDate as parseWhoisDate, };
|
|
756
|
+
export { checkDomainAvailability, checkDnsDelegation, fetchHomepage, isPrivacyProtected, deriveWebsiteActivity, forSaleRedirectSignal, parseRegistryDate as parseWhoisDate, };
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// not infer missing values and keep every string, object, enum, and counter
|
|
3
3
|
// bounded before a provider or connector result reaches its public model.
|
|
4
4
|
import { domainToASCII } from 'node:url';
|
|
5
|
+
import { normalizeExplicitIsoTimestamp } from "../packages/evidence/observation.mjs";
|
|
5
6
|
export function isRecord(value) {
|
|
6
7
|
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
7
8
|
}
|
|
@@ -26,10 +27,7 @@ export function strictBoundedString(value, maxLength) {
|
|
|
26
27
|
return normalized && normalized.length <= maxLength ? normalized : null;
|
|
27
28
|
}
|
|
28
29
|
export function isoTimestamp(value) {
|
|
29
|
-
|
|
30
|
-
return null;
|
|
31
|
-
const timestamp = Date.parse(value);
|
|
32
|
-
return Number.isFinite(timestamp) ? new Date(timestamp).toISOString() : null;
|
|
30
|
+
return normalizeExplicitIsoTimestamp(value);
|
|
33
31
|
}
|
|
34
32
|
export function boundedHttpsUrl(value, maxLength) {
|
|
35
33
|
const raw = strictBoundedString(value, maxLength);
|