@slicedearth/whoisleuth-cli 1.43.0 → 1.47.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DISCLOSURE +7 -3
- package/NOTICE +5 -4
- package/README.md +67 -10
- package/bin/whoisleuth.mjs +22 -9
- package/cli/arguments.mjs +256 -9
- package/cli/artifact-structure.mjs +1833 -0
- package/cli/artifact-verify.mjs +242 -49
- package/cli/bounded-json.mjs +1 -0
- package/cli/bulk-checkpoint.mjs +67 -31
- package/cli/bulk-command-runner.mjs +16 -6
- package/cli/bulk.mjs +18 -7
- package/cli/case-pack.mjs +819 -34
- package/cli/command-reference.mjs +48 -24
- package/cli/completion.mjs +50 -11
- package/cli/config-profile.mjs +15 -12
- package/cli/ct-event-intake.mjs +32 -2
- package/cli/discovery-observation-snapshot.mjs +8 -14
- package/cli/discovery-scan-command-runner.mjs +18 -6
- package/cli/discovery-snapshot.mjs +8 -15
- package/cli/discovery-workflow.mjs +2 -3
- package/cli/doctor.mjs +2 -2
- package/cli/domain-control-monitor.mjs +21 -15
- package/cli/domain-control-observations.mjs +25 -2
- package/cli/errors.mjs +7 -1
- package/cli/evidence-command-runner.mjs +17 -11
- package/cli/evidence-signing.mjs +73 -45
- package/cli/export-evidence.mjs +11 -4
- package/cli/formatters/html.mjs +3 -3
- package/cli/formatters/json.mjs +12 -4
- package/cli/formatters/terminal.mjs +4 -1
- package/cli/http.mjs +2 -1
- package/cli/input.mjs +57 -0
- package/cli/interchange-report.mjs +226 -0
- package/cli/investigation-manifest.mjs +16 -17
- package/cli/investigation-run.mjs +71 -23
- package/cli/local-mmdb-review.mjs +45 -14
- package/cli/lookup-command-runner.mjs +2 -2
- package/cli/lookup-diff.mjs +9 -0
- package/cli/lookup-reconcile.mjs +1 -1
- package/cli/mail-review.mjs +5 -5
- package/cli/manual.mjs +1 -1
- package/cli/network-command-runner.mjs +78 -0
- package/cli/offline-evidence-review.mjs +28 -8
- package/cli/page-compare.mjs +8 -5
- package/cli/registry-cohort.mjs +385 -61
- package/cli/registry-fixture-scaffold.mjs +4 -3
- package/cli/registry-support.mjs +2 -1
- package/cli/retained-artifact-diff.mjs +376 -0
- package/cli/risk-calibration.mjs +7 -5
- package/cli/runner.mjs +150 -177
- package/cli/saved-lookup.mjs +26 -3
- package/cli/sharing-review.mjs +12 -6
- package/docs/cli-reference.md +467 -74
- package/docs/cli.md +25 -5
- package/frontend/src/lib/analysis/acquisition-decision-packet.js +4 -4
- package/frontend/src/lib/analysis/acquisition-due-diligence.js +1 -1
- package/frontend/src/lib/analysis/artifact-integrity.js +42 -0
- package/frontend/src/lib/analysis/brand-profile-model.js +33 -7
- package/frontend/src/lib/analysis/bulk-domain-comparison.js +25 -5
- package/frontend/src/lib/analysis/bulk-mail-exposure.js +66 -15
- package/frontend/src/lib/analysis/bulk-retry-plan.js +1 -1
- package/frontend/src/lib/analysis/bulk-review-export.js +7 -6
- package/frontend/src/lib/analysis/bulk-review-model.js +3 -2
- package/frontend/src/lib/analysis/bulk-session-model.js +192 -26
- package/frontend/src/lib/analysis/bulk-sort.js +4 -0
- package/frontend/src/lib/analysis/case-brand-profile-references.js +85 -0
- package/frontend/src/lib/analysis/case-evidence-model.js +9 -1
- package/frontend/src/lib/analysis/case-investigation-branch-model.js +134 -0
- package/frontend/src/lib/analysis/case-migration-model.js +83 -31
- package/frontend/src/lib/analysis/case-record-contracts.js +4 -2
- package/frontend/src/lib/analysis/case-record-core.js +1 -1
- package/frontend/src/lib/analysis/case-record-model.js +2 -0
- package/frontend/src/lib/analysis/case-record-operations.js +43 -13
- package/frontend/src/lib/analysis/case-report.js +39 -6
- package/frontend/src/lib/analysis/case-response-model.js +66 -7
- package/frontend/src/lib/analysis/case-response-packet.js +15 -5
- package/frontend/src/lib/analysis/comparison-ledger-bulk.js +366 -0
- package/frontend/src/lib/analysis/comparison-ledger-contract.js +241 -0
- package/frontend/src/lib/analysis/comparison-ledger-json.js +79 -0
- package/frontend/src/lib/analysis/comparison-ledger-serialization.js +51 -0
- package/frontend/src/lib/analysis/domain-control-manifest-core.js +145 -0
- package/frontend/src/lib/analysis/domain-control-records.js +88 -0
- package/frontend/src/lib/analysis/external-findings-import.js +70 -6
- package/frontend/src/lib/analysis/investigation-capsule.js +47 -13
- package/frontend/src/lib/analysis/investigation-guide.js +52 -10
- package/frontend/src/lib/analysis/investigation-template-model.js +9 -6
- package/frontend/src/lib/analysis/lookup-asset-graph.js +8 -8
- package/frontend/src/lib/analysis/lookup-claim-passport.js +236 -0
- package/frontend/src/lib/analysis/lookup-claim-readiness.js +280 -0
- package/frontend/src/lib/analysis/lookup-decision-support.js +63 -8
- package/frontend/src/lib/analysis/lookup-presentation.js +70 -14
- package/frontend/src/lib/analysis/lookup-source-refresh.js +36 -63
- package/frontend/src/lib/analysis/opaque-reference-id.js +9 -0
- package/frontend/src/lib/analysis/utils.js +27 -4
- package/frontend/src/lib/analysis/visualization-matrix.js +71 -28
- package/frontend/src/lib/analysis/visualization-models.js +63 -94
- package/frontend/src/lib/analysis/visualization-time-series.js +53 -12
- package/frontend/src/lib/analysis/website-snapshot-model.js +6 -0
- package/frontend/src/lib/analysis/workspace-archive-crypto.js +1 -4
- package/frontend/src/lib/analysis/workspace-archive.js +105 -19
- package/lib/application-version.mjs +3 -0
- package/lib/availability.mjs +14 -12
- package/lib/bounded-file.mjs +82 -0
- package/lib/bounded-json-response.mjs +170 -0
- package/lib/bounded-json.mjs +249 -0
- package/lib/browser-library-profile.mjs +167 -38
- package/lib/certificate-extension-profile.mjs +2 -1
- package/lib/cryptographic-assurance.mjs +155 -0
- package/lib/ct-search.mjs +87 -47
- package/lib/dns-intelligence.mjs +3 -2
- package/lib/dns-resolver-selection.mjs +6 -4
- package/lib/dnssec-chain-validation.mjs +1053 -0
- package/lib/dnssec-evidence-validation.mjs +10 -3
- package/lib/domain-change-packet.mjs +7 -5
- package/lib/domain-control-manifest.mjs +17 -129
- package/lib/domain-posture.mjs +7 -4
- package/lib/evidence-export.mjs +751 -78
- package/lib/evidence-report-markdown.mjs +3 -0
- package/lib/evidence-report.mjs +5 -0
- package/lib/favicon.mjs +8 -5
- package/lib/http-evidence-bounds.mjs +3 -0
- package/lib/http-intelligence.mjs +2 -5
- package/lib/interchange-fidelity-registry.mjs +122 -0
- package/lib/local-geoip-evidence.mjs +2 -1
- package/lib/lookup-cache.mjs +5 -1
- package/lib/lookup-network-evidence-bounds.mjs +9 -0
- package/lib/lookup-response-contract.mjs +691 -3
- package/lib/lookup.mjs +2 -2
- package/lib/observation.mjs +7 -6
- package/lib/outbound-identity.mjs +2 -3
- package/lib/perceptual-hash.mjs +12 -4
- package/lib/portable-generator.mjs +21 -0
- package/lib/provider-policy-admission.mjs +9 -4
- package/lib/rdap-normalization.mjs +18 -5
- package/lib/rdap-registrar.mjs +5 -1
- package/lib/rdap-transport.mjs +6 -6
- package/lib/registry-capabilities.mjs +3 -0
- package/lib/registry-capability-catalogue.mjs +12 -2
- package/lib/registry-comparison.mjs +28 -11
- package/lib/risk-calibration-summary.mjs +338 -0
- package/lib/rpki-evidence.mjs +9 -8
- package/lib/safe-fetch.mjs +96 -42
- package/lib/security-txt.mjs +26 -3
- package/lib/service-binding-dns.mjs +6 -1
- package/lib/smtp-transport-review.mjs +784 -0
- package/lib/sslbl-certificates.generated.mjs +136 -134
- package/lib/threat-intelligence-runtime.mjs +4 -13
- package/lib/threat-intelligence-types.mjs +18 -1
- package/lib/tls-intelligence.mjs +11 -5
- package/lib/tlsa-evidence.mjs +37 -7
- package/lib/website-technology.mjs +2 -6
- package/package.json +1 -1
- package/third-party-notices.txt +95 -5817
package/docs/cli-reference.md
CHANGED
|
@@ -63,7 +63,7 @@ node bin/whoisleuth.mts ct-search 'example brand' --json
|
|
|
63
63
|
node bin/whoisleuth.mts discover example.com --preset common --jsonl
|
|
64
64
|
node bin/whoisleuth.mts discover example.test --dictionary private-terms.txt --snapshot discovery-state.json --json
|
|
65
65
|
node bin/whoisleuth.mts discover-scan example.test --scan-limit 50 --checkpoint candidate-scan.json --json
|
|
66
|
-
node bin/whoisleuth.mts discover-scan example.test --deep --scan-limit 20 --resolver
|
|
66
|
+
node bin/whoisleuth.mts discover-scan example.test --deep --scan-limit 20 --resolver <public-resolver-ip> --observation-snapshot observed-candidates.json --csv
|
|
67
67
|
node bin/whoisleuth.mts posture example.com --selectors selector1 --retired-selectors selector0 --mail-profile defensive-no-mail --json
|
|
68
68
|
node bin/whoisleuth.mts http example.com --json
|
|
69
69
|
node bin/whoisleuth.mts tls example.com --json
|
|
@@ -72,9 +72,10 @@ node bin/whoisleuth.mts registry-doctor lookup.json --json
|
|
|
72
72
|
node bin/whoisleuth.mts registry-cohort saved-lookups.jsonl --json
|
|
73
73
|
node bin/whoisleuth.mts registry-scaffold --profile example-profile --suffix test --scenario registered
|
|
74
74
|
node bin/whoisleuth.mts risk-calibrate calibration.json --json
|
|
75
|
+
node bin/whoisleuth.mts risk-calibrate calibration.json --summary-json
|
|
75
76
|
node bin/whoisleuth.mts lookalike-calibrate reviewed-candidates.json --json
|
|
76
77
|
node bin/whoisleuth.mts verify-artifact workspace.json --json
|
|
77
|
-
node bin/whoisleuth.mts verify-artifact lookup.json --json
|
|
78
|
+
node bin/whoisleuth.mts verify-artifact lookup.json --json --strict-exit
|
|
78
79
|
node bin/whoisleuth.mts verify-artifact workspace-encrypted.json --passphrase-file passphrase.txt --json
|
|
79
80
|
node bin/whoisleuth.mts source-report lookup.json --json
|
|
80
81
|
node bin/whoisleuth.mts inspect-archive workspace.json --json
|
|
@@ -89,6 +90,8 @@ node bin/whoisleuth.mts lookup example.com --deep --json > lookup.json
|
|
|
89
90
|
node bin/whoisleuth.mts compare lookup.json --json
|
|
90
91
|
node bin/whoisleuth.mts page-compare official.json candidate.json --json
|
|
91
92
|
node bin/whoisleuth.mts mail-review bulk.json --json
|
|
93
|
+
node bin/whoisleuth.mts dnssec-validate example.test --resolver "$PUBLIC_RESOLVER_IP" --trust-anchor anchor.json --owned-or-authorized --json
|
|
94
|
+
node bin/whoisleuth.mts mail-transport selected-mx.json --resolver "$PUBLIC_RESOLVER_IP" --trust-anchor anchor.json --owned-or-authorized --active-probe --json
|
|
92
95
|
node bin/whoisleuth.mts review-evidence dnssec-evidence.json --json
|
|
93
96
|
node bin/whoisleuth.mts review-evidence trust-store-comparison.json --json
|
|
94
97
|
node bin/whoisleuth.mts domain-control domain-control-input.json --json
|
|
@@ -201,7 +204,7 @@ ordinary package-check candidate remain private. Explicitly reviewed CLI
|
|
|
201
204
|
release candidates can be published under the scoped public package described
|
|
202
205
|
in the installation section.
|
|
203
206
|
|
|
204
|
-
Commands that query RDAP, WHOIS, DNS, HTTP, TLS, or Certificate Transparency do
|
|
207
|
+
Commands that query RDAP, WHOIS, DNS, HTTP, TLS, SMTP, or Certificate Transparency do
|
|
205
208
|
so directly from the machine running the CLI. They do not use the hosted login,
|
|
206
209
|
hosted session, or deployment usage controls; upstream providers can see and
|
|
207
210
|
rate-limit the local machine's network address. Offline `discover`, `compare`,
|
|
@@ -213,6 +216,12 @@ rate-limit the local machine's network address. Offline `discover`, `compare`,
|
|
|
213
216
|
`commands`, `completion`, and `manual` operations make no network requests. Commands write
|
|
214
217
|
to stdout unless the analyst deliberately selects a local output file.
|
|
215
218
|
|
|
219
|
+
Path operands are opened through one bounded regular-file boundary. Named
|
|
220
|
+
pipes, devices and directories are refused without waiting for a writer;
|
|
221
|
+
symbolic links to regular analyst-selected files remain supported. Standard
|
|
222
|
+
input is the only intentional streaming input and observes the same command
|
|
223
|
+
byte limit and cancellation signal.
|
|
224
|
+
|
|
216
225
|
## Output
|
|
217
226
|
|
|
218
227
|
Human-readable terminal output is the default. On an interactive terminal it
|
|
@@ -252,7 +261,10 @@ normal output is emitted.
|
|
|
252
261
|
`lookup --markdown` and `lookup --html` build the existing normalised evidence
|
|
253
262
|
report directly after one completed domain lookup. They do not start a second
|
|
254
263
|
collection. These report formats reject IP and ASN inputs before collection;
|
|
255
|
-
JSON and terminal output remain available for those query types.
|
|
264
|
+
JSON and terminal output remain available for those query types. Both readable
|
|
265
|
+
formats include a fixed local generator footer by default. `--no-attribution`
|
|
266
|
+
removes that presentation-only footer without changing evidence-source
|
|
267
|
+
attribution, generator metadata in JSON, or collection behaviour.
|
|
256
268
|
|
|
257
269
|
Lookup terminal output supports three detail levels. The standard view keeps
|
|
258
270
|
the normal bounded evidence summary. `--summary` keeps the source states and
|
|
@@ -330,7 +342,8 @@ delivery observed by the caller.
|
|
|
330
342
|
|
|
331
343
|
Pressing Ctrl-C asks an in-flight Lookup or Bulk run to stop, suppresses any
|
|
332
344
|
partial final result, flushes an enabled Bulk checkpoint, and exits with code
|
|
333
|
-
130.
|
|
345
|
+
130. SIGTERM follows the same graceful cleanup path and exits with code 143.
|
|
346
|
+
Already started network operations remain subject to their existing hard
|
|
334
347
|
timeouts while the shared in-process API unwinds; the executable terminates
|
|
335
348
|
after CLI cleanup. A second Ctrl-C removes any known unpublished temporary
|
|
336
349
|
output file on a best-effort basis before exiting immediately.
|
|
@@ -338,21 +351,38 @@ output file on a best-effort basis before exiting immediately.
|
|
|
338
351
|
Bulk can persist compact progress with `--checkpoint <file>`. A new checkpoint
|
|
339
352
|
is private, bounded to 16 MiB, versioned, and tied to the exact ordered input
|
|
340
353
|
and scan mode by SHA-256. It stores only compact per-item results, never full
|
|
341
|
-
Lookup responses.
|
|
354
|
+
Lookup responses. Checkpoint schema 2 records a nullable per-row observation
|
|
355
|
+
time. Schema 1 remains readable, but its resumed rows keep observation time
|
|
356
|
+
unknown rather than inheriting the resume time. Reusing the same path is
|
|
357
|
+
refused unless `--resume` is also
|
|
342
358
|
specified. Resume revalidates the complete untrusted document and skips only
|
|
343
359
|
the exact completed rows; changed input, mode, schema, digest, or malformed
|
|
344
360
|
results fail closed.
|
|
345
361
|
|
|
362
|
+
Bulk JSON, JSONL, and item documents use schema version 3. Each row includes
|
|
363
|
+
`observedAt` and a `collectionOrigin` of `current_run` or
|
|
364
|
+
`resumed_checkpoint`; the top-level `generatedAt` remains the report creation
|
|
365
|
+
time. HTTP JSON uses schema version 2 and adds the explicit `assessment` field.
|
|
366
|
+
The legacy `activityStatus` field remains for compatibility, but is `null`
|
|
367
|
+
when collection is inconclusive rather than labelling the target unreachable.
|
|
368
|
+
Consumers should use `assessment`; older version-1 `unreachable` values remain
|
|
369
|
+
historical inconclusive labels, not proof that a target cannot be reached.
|
|
370
|
+
|
|
346
371
|
If checkpoint persistence fails after collection, WHOISleuth still emits the
|
|
347
372
|
completed final result, reports the checkpoint limitation, and exits with code
|
|
348
373
|
4. The last successfully published checkpoint remains available, but it may
|
|
349
374
|
not contain the final completed items.
|
|
350
375
|
|
|
351
|
-
`diff <left.json> <right.json>` compares two
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
376
|
+
`diff <left.json> <right.json>` compares two compatible retained artefacts
|
|
377
|
+
entirely offline. Saved Lookup documents keep their version-1 lookup-diff
|
|
378
|
+
output. Portable Bulk-session exports and domain-portfolio reviews emit a
|
|
379
|
+
`whoisleuth.cli.comparison-ledger` version-1 document with a value-free bounded
|
|
380
|
+
index and at most 256 exact detail rows. Bulk exports containing more than one
|
|
381
|
+
session require `--left-session <id>` or `--right-session <id>` as applicable.
|
|
382
|
+
The command keeps missing, unavailable, equal, added, and different evidence
|
|
383
|
+
separate, treats later portfolio omission as incomplete rather than removal,
|
|
384
|
+
and retains no input path. It makes no ownership, safety, or maliciousness
|
|
385
|
+
inference.
|
|
356
386
|
|
|
357
387
|
`lookup --observer <label> --vantage <label>` can add two bounded analyst labels
|
|
358
388
|
to a saved Lookup document. The labels identify the person or process that ran
|
|
@@ -393,9 +423,10 @@ machine access is not evidence that a domain is unregistered or safe.
|
|
|
393
423
|
| 4 | A bounded operation completed partially, such as Bulk item failures or failed explicit Doctor network checks. |
|
|
394
424
|
| 70 | Unexpected CLI bootstrap failure. |
|
|
395
425
|
| 130 | The analyst cancelled the command. No partial final result was emitted. |
|
|
426
|
+
| 143 | The process received SIGTERM. No partial final result was emitted. |
|
|
396
427
|
|
|
397
428
|
This release supports `lookup`, `bulk`, `ct-search`, `ct-intake`, `map-observations`, `oam-export`, `discover`, `discover-scan`, `posture`,
|
|
398
|
-
`http`, `tls`, `registry-support`, `registry-doctor`, `registry-cohort`, `registry-scaffold`, `risk-calibrate`,
|
|
429
|
+
`http`, `tls`, `dnssec-validate`, `mail-transport`, `registry-support`, `registry-doctor`, `registry-cohort`, `registry-scaffold`, `risk-calibrate`,
|
|
399
430
|
`lookalike-calibrate`, `verify-artifact`,
|
|
400
431
|
`inspect-archive`, `manifest`, `sign-artifact`, `verify-signature`, `source-report`,
|
|
401
432
|
`compare`, `page-compare`, `mail-review`, `review-evidence`, `brief`, `case-pack`, `domain-control`,
|
|
@@ -411,15 +442,18 @@ catalogue for one domain or suffix. It distinguishes an explicit
|
|
|
411
442
|
fixture-backed or access-documented suffix profile from the generic IANA
|
|
412
443
|
discovery profile and reports the RDAP and WHOIS discovery/access paths,
|
|
413
444
|
WHOIS query and parser profiles, fixture scenarios,
|
|
414
|
-
verification references, documentation references,
|
|
445
|
+
verification references, documentation references, an optional reviewed
|
|
446
|
+
official browser-lookup URL, and the catalogue's
|
|
415
447
|
limitation. The same document includes a dated, official-source aggregate of
|
|
416
448
|
generic, generic-restricted, sponsored, and infrastructure RDAP coverage. That
|
|
417
449
|
snapshot is separate from the suffix profile and from live reachability.
|
|
418
450
|
|
|
419
|
-
Terminal output is bounded and control-safe. `--json` emits version
|
|
451
|
+
Terminal output is bounded and control-safe. `--json` emits version 4 of the
|
|
420
452
|
`whoisleuth.cli.registry-support` schema. Unknown but syntactically valid
|
|
421
453
|
suffixes retain the generic `discovery_only` profile; malformed input exits
|
|
422
454
|
with code 2. The command never probes a registry or tests current reachability.
|
|
455
|
+
An official lookup URL is emitted only for an individually reviewed HTTPS
|
|
456
|
+
destination. The CLI does not open it or append the investigated domain.
|
|
423
457
|
Coverage is context only and cannot decide registration, availability,
|
|
424
458
|
ownership, safety, or maliciousness.
|
|
425
459
|
|
|
@@ -432,12 +466,15 @@ and event consistency. A missing identifier or metadata field is a publication
|
|
|
432
466
|
omission, not a failed lookup. The command is offline, makes no retry, and
|
|
433
467
|
cannot establish current registry reachability.
|
|
434
468
|
|
|
435
|
-
`registry-cohort [lookups.json|
|
|
436
|
-
Lookups
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
469
|
+
`registry-cohort [lookups-or-reports.json|jsonl]` accepts either 1 to 500 saved
|
|
470
|
+
Lookups or an unmixed collection of retained `whoisleuth.cli.registry-cohort`
|
|
471
|
+
version-1/version-2 reports. It emits version 2 with target-free suffix and
|
|
472
|
+
capability-profile timelines, an explicit sample window, retained-report count,
|
|
473
|
+
and at most 50 visible points per cohort. A version-1 report becomes one
|
|
474
|
+
retained point. A cohort with fewer than five samples remains insufficient,
|
|
475
|
+
and overlapping retained samples are never summed or promoted to independent
|
|
476
|
+
consistency. Domains, queries, filenames, and raw registry evidence are not
|
|
477
|
+
retained.
|
|
441
478
|
|
|
442
479
|
`registry-scaffold --profile <id> --suffix <suffix> --scenario <state>` emits
|
|
443
480
|
one bounded, sanitised synthetic fixture scaffold from the installed registry
|
|
@@ -459,7 +496,9 @@ pinned official RDAP extension fixture with the reviewed local interpretation
|
|
|
459
496
|
catalogue entirely offline. `--live` performs one bounded manual fetch from the
|
|
460
497
|
fixed official CSV URL and reports added, removed, renamed, status-changed,
|
|
461
498
|
unrecognized, and local-only identifiers. `--json` emits
|
|
462
|
-
`whoisleuth.rdap-extension-drift-audit` version 1.
|
|
499
|
+
`whoisleuth.rdap-extension-drift-audit` version 1. The manual live fetch keeps one
|
|
500
|
+
10-second deadline armed through the capped 128 KiB body read and fails closed if
|
|
501
|
+
the official CSV is truncated. Drift exits with status 1 and
|
|
463
502
|
requires specification and fixture review; the command never enables an
|
|
464
503
|
extension, changes authority or availability logic, or issues reverse search.
|
|
465
504
|
|
|
@@ -481,7 +520,18 @@ thresholds from 40 through 90 and identifies 70 as the current review band. It
|
|
|
481
520
|
also reports F1, balanced accuracy, Wilson 95% intervals, deliberately small
|
|
482
521
|
scan-depth and review-reason strata, and a current-versus-previous model replay.
|
|
483
522
|
Strata with fewer than 20 included labels are marked insufficient rather than
|
|
484
|
-
presented as reliable performance estimates.
|
|
523
|
+
presented as reliable performance estimates. Report version 3 distinguishes
|
|
524
|
+
the ordinary `detailed` output from the aggregate `summary` projection.
|
|
525
|
+
|
|
526
|
+
`--json` emits the bounded detailed report, including record identifiers,
|
|
527
|
+
domains, analyst dispositions, scores and factor summaries. Use
|
|
528
|
+
`--summary-json` for the target-free aggregate accepted by Monitor's local
|
|
529
|
+
calibration explorer. That projection retains only dataset and model versions,
|
|
530
|
+
aggregate class and score-band counts, fixed-threshold confusion metrics and
|
|
531
|
+
Wilson intervals, bounded strata, model-comparison counts, and an explicit
|
|
532
|
+
zero-target privacy declaration. It contains no record array, identifier,
|
|
533
|
+
domain, evidence field, factor, note or provider payload. Both forms remain
|
|
534
|
+
offline and are written only when the analyst deliberately selects an output.
|
|
485
535
|
|
|
486
536
|
The JSON report derives a bounded `interoperabilityTags` list from the
|
|
487
537
|
analyst-owned disposition and review reason. The mapping uses reviewed MISP
|
|
@@ -518,7 +568,7 @@ and bounded before scoring. The accepted dataset envelope is:
|
|
|
518
568
|
and `expected` are negative labels. `unreviewed`, `suspicious`, and
|
|
519
569
|
`closed_no_action` remain contextual and are excluded from threshold quality
|
|
520
570
|
metrics, as are records for which Risk is not applicable. Terminal output caps
|
|
521
|
-
its record list at 100 while `--json` retains the complete bounded report,
|
|
571
|
+
its record list at 100 while `--json` retains the complete bounded detailed report,
|
|
522
572
|
factor breakdowns, score bands, confidence intervals, bounded strata, model
|
|
523
573
|
comparison counts, and per-threshold confusion metrics. Analyst
|
|
524
574
|
dispositions and heuristic scores are review context: neither proves
|
|
@@ -557,16 +607,29 @@ establish that a current candidate is malicious or safe.
|
|
|
557
607
|
`verify-artifact` validates a supported local artefact without printing its
|
|
558
608
|
evidence contents. Input is capped at 15 MiB. It currently recognises ordinary
|
|
559
609
|
and encrypted workspace archives, case-response packets, acquisition-decision
|
|
560
|
-
exports, domain-comparison exports, Bulk mail-exposure exports, and Bulk review
|
|
610
|
+
exports, supported Lookup-evidence exports, Lookup claim passports, domain-comparison exports, Bulk mail-exposure exports, and Bulk review
|
|
561
611
|
manifests. Reviewed CLI case packs are checked against their canonical digest,
|
|
562
612
|
bounded browser-importable case collection, audience, and review marker. The
|
|
563
|
-
command
|
|
564
|
-
capsule, including its
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
613
|
+
command verifies both the embedded projections and whole-capsule digest of an
|
|
614
|
+
investigation capsule version 2, including its metadata and linked
|
|
615
|
+
source-contract digests, and reports `verified`. The non-embedded Lookup
|
|
616
|
+
evidence must still be retained separately. Legacy capsule version 1 covers
|
|
617
|
+
only the embedded brief, graph, and optional analyst-record projections, so it
|
|
618
|
+
remains `integrity_valid` rather than whole-file `verified`. It also validates
|
|
619
|
+
the bounded versioned structure of saved CLI Lookup JSON and current
|
|
620
|
+
Lookup-evidence schemas 25 and 26. Because neither saved Lookup documents nor full
|
|
621
|
+
Lookup-evidence exports embed a checksum or signature, those results are
|
|
622
|
+
reported as `structure_valid` with content integrity explicitly unchecked.
|
|
623
|
+
Lookup-evidence verification closes the supported export envelopes and source
|
|
624
|
+
wrappers, enforces the same 5 MiB, 20,000-entry, and 24-level limits as browser
|
|
625
|
+
replay, and does not claim that
|
|
626
|
+
an observation is accurate, current, or unchanged. Exact retained-file identity
|
|
627
|
+
requires a verified investigation manifest and matching `--manifest-entry`;
|
|
628
|
+
the evidence file can contain a bounded privacy-projected registry RDAP
|
|
629
|
+
publication, normalised WHOIS values, and bounded contacts, so review it before
|
|
630
|
+
sharing. Request and response headers, cookies, session and credential fields,
|
|
631
|
+
and URL credentials, queries, and fragments are excluded. Saved Lookup validation retains its
|
|
632
|
+
stricter 8 MiB document ceiling.
|
|
570
633
|
|
|
571
634
|
For an ordinary workspace archive, the command validates the versioned
|
|
572
635
|
structure, section byte counts, record counts, and per-section checksums. For a
|
|
@@ -574,6 +637,11 @@ supported signed review artefact, it validates the declared SHA-256 digest. An
|
|
|
574
637
|
encrypted archive without `--passphrase-file` can establish only that the
|
|
575
638
|
envelope is structurally valid; it reports `envelope_valid` and explicitly
|
|
576
639
|
leaves authenticated encryption and inner checksums unchecked.
|
|
640
|
+
Checksum validity is reported separately from importability. A checksum-valid
|
|
641
|
+
archive can therefore list unsupported sections when it contains a section
|
|
642
|
+
schema this version cannot restore, or skipped and pruned records when a
|
|
643
|
+
supported section cannot be restored completely; inspect those counts before
|
|
644
|
+
importing.
|
|
577
645
|
|
|
578
646
|
Supplying a separate passphrase file, capped at 1 KiB, allows authenticated
|
|
579
647
|
decryption followed by the ordinary workspace checks. The passphrase is never
|
|
@@ -581,6 +649,83 @@ accepted as a command-line value, printed, or retained. Verification detects
|
|
|
581
649
|
changes against the artefact's declared contract; it does not authenticate the
|
|
582
650
|
analyst or establish that an observation was accurate or remains current.
|
|
583
651
|
|
|
652
|
+
`--manifest <manifest.json> --manifest-entry <artifact-N>` additionally verifies
|
|
653
|
+
the selected investigation manifest before comparing its declared entry with
|
|
654
|
+
the supplied artefact. `identity_verified` requires the exact UTF-8 byte length
|
|
655
|
+
and raw digest as well as canonical digest, schema, and version. A
|
|
656
|
+
`canonical_match_only` result means semantic JSON identity survived but the
|
|
657
|
+
retained bytes differ, so it is a partial result under `--strict-exit`.
|
|
658
|
+
`mismatch` likewise remains separate from the artefact's own structure or
|
|
659
|
+
integrity result. Manifest paths and artefact contents are not copied into the
|
|
660
|
+
verification report.
|
|
661
|
+
|
|
662
|
+
Verification reports use `whoisleuth.offline-artifact-verification` version 3
|
|
663
|
+
and do not expose an always-true validity shortcut. The explicit state and
|
|
664
|
+
checks distinguish structure, whole-file integrity, projection integrity, and
|
|
665
|
+
authenticated encryption. `--strict-exit` returns exit 0 for `verified` and
|
|
666
|
+
`structure_valid` when no manifest identity is requested or exact identity is
|
|
667
|
+
verified. It returns partial-failure exit 4 for `integrity_valid`,
|
|
668
|
+
`envelope_valid`, canonical-only identity, or identity mismatch; ordinary
|
|
669
|
+
verification errors retain their existing error codes. Raw JSON is scanned
|
|
670
|
+
before parsing to reject duplicate object keys and excessive nesting or
|
|
671
|
+
key/value counts.
|
|
672
|
+
|
|
673
|
+
Current integrity-bearing review outputs use `sorted-json-v2`, whose object-key
|
|
674
|
+
order is a locale-independent JavaScript code-unit order. Readers select the
|
|
675
|
+
canonical bytes from an exact artifact-version and canonicalization pair,
|
|
676
|
+
reject mixed or missing current declarations, and validate bounded structure
|
|
677
|
+
before any legacy hashing. Historical outputs keep their original
|
|
678
|
+
`sorted-json-v1` bytes and are accepted only through their legacy version.
|
|
679
|
+
Version 1 used the runtime's ambient `localeCompare` ordering, so historical
|
|
680
|
+
files containing non-ASCII object-key extensions require a compatible locale
|
|
681
|
+
and ICU ordering to verify; it is not a portable canonicalization guarantee.
|
|
682
|
+
The fixed keys emitted by the supported legacy builders are ASCII, but only
|
|
683
|
+
version 2 provides the cross-locale portability contract.
|
|
684
|
+
|
|
685
|
+
The current/legacy integrity pairs are: acquisition decision 2/1, Lookup claim
|
|
686
|
+
passport 1 (sorted-json-v2 only),
|
|
687
|
+
domain-comparison export 4/3 with nested comparison 3, Bulk mail-exposure
|
|
688
|
+
export 2/1 with nested report 1, Bulk review manifest 2/1, domain-control
|
|
689
|
+
manifest 2/1, domain-change packet 2/1 with input 1, investigation manifest
|
|
690
|
+
2/1, case-response packet 6/5, investigation capsule 2/1, CLI case-pack packet
|
|
691
|
+
2/1 with Case schema 12, and signed evidence package 2/1. Current outputs
|
|
692
|
+
declare `sorted-json-v2`; legacy declarations remain explicit only where their
|
|
693
|
+
historical contract included one.
|
|
694
|
+
|
|
695
|
+
## Interchange fidelity report
|
|
696
|
+
|
|
697
|
+
`interchange-report [artifact.json]` explains what one recognised portable
|
|
698
|
+
artefact preserves, excludes, and supports in browser and CLI workflows. It
|
|
699
|
+
recognises supported Lookup-evidence exports, Lookup claim passports, domain-control passports, Brand Profile exports from versions 2
|
|
700
|
+
through 6, workspace archives from versions 1 through 5, encrypted workspace
|
|
701
|
+
envelopes, reviewed CLI case packs, and the retired one-way desired-baseline
|
|
702
|
+
export. The retired export is identified as unsupported rather than silently
|
|
703
|
+
treated as a current passport.
|
|
704
|
+
|
|
705
|
+
Output is metadata-only: registered schema and version, verification state,
|
|
706
|
+
bounded counts, browser import/export support, CLI read/write/verify support,
|
|
707
|
+
semantic fidelity, and fixed preserved or excluded field-group identifiers.
|
|
708
|
+
For workspace archives, checksum validity and complete browser importability are
|
|
709
|
+
reported separately. A checksum-valid archive with a newer inner section stays
|
|
710
|
+
verified for integrity while its fidelity is withheld and importability is
|
|
711
|
+
reported as partial. The same partial state applies when browser preview would
|
|
712
|
+
block a section, skip a malformed record, or prune data to a collection bound.
|
|
713
|
+
It never echoes a target, contact, note, evidence value, passphrase, arbitrary
|
|
714
|
+
unknown schema string, or encrypted content. A separate `--passphrase-file`
|
|
715
|
+
can authenticate an encrypted workspace; without it, only the envelope is
|
|
716
|
+
reported as valid and fidelity is withheld. Each registered interchange family
|
|
717
|
+
declares its exact assurance requirement: browser-importable structure is
|
|
718
|
+
sufficient for Brand Profile normalisation and the current bounded
|
|
719
|
+
Lookup-evidence contract, while checksummed formats
|
|
720
|
+
require whole-file integrity and encrypted workspaces additionally require
|
|
721
|
+
authenticated decryption. “Semantic exact after normalisation” does not mean byte
|
|
722
|
+
identity, current evidence, or a successful round trip through an unrelated
|
|
723
|
+
format.
|
|
724
|
+
|
|
725
|
+
For case packs, the fixed fidelity metadata explicitly lists public-audience
|
|
726
|
+
Brand Profile references as excluded and trusted/internal references as
|
|
727
|
+
preserved. The report never prints an identifier or other stored value.
|
|
728
|
+
|
|
584
729
|
## Privacy-safe source reliability report
|
|
585
730
|
|
|
586
731
|
`source-report` summarises source states, durations, truncation, and rate-limit
|
|
@@ -641,22 +786,32 @@ node bin/whoisleuth.mts sign-artifact packet.json --private-key-file analyst-pri
|
|
|
641
786
|
node bin/whoisleuth.mts verify-signature packet.signed.json --public-key-file analyst-public.pem
|
|
642
787
|
```
|
|
643
788
|
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
789
|
+
New signed packages use version 2 with `sorted-json-v2` canonicalisation and
|
|
790
|
+
embed the public key, key identifier, canonical UTC signature time, and
|
|
791
|
+
original artefact. Signing requires verified structure plus a verified
|
|
792
|
+
applicable integrity contract; a recomputed digest around an empty or malformed
|
|
793
|
+
document is rejected. Signature verification reports cryptographic status and
|
|
794
|
+
embedded-artifact assurance separately in
|
|
795
|
+
`whoisleuth.evidence-signature-verification` version 2. A result can therefore
|
|
796
|
+
remain `signature_valid` while embedded-artifact assurance is `not_verified`;
|
|
797
|
+
the signature authenticates those exact bytes without upgrading their
|
|
798
|
+
structure or inner integrity. Signer trust is separately reported as
|
|
799
|
+
`trusted_key` or `embedded_key_only`. Without a separately supplied trusted public key,
|
|
649
800
|
verification establishes only that the package is internally self-consistent.
|
|
801
|
+
Historical version-1 packages remain verifiable with their explicit
|
|
802
|
+
`sorted-json-v1` signature declaration when their original locale-dependent
|
|
803
|
+
ordering is reproduced; version 2 is the portable signature contract.
|
|
650
804
|
WHOISleuth does not generate, store, recover, rotate, publish, or establish
|
|
651
805
|
trust in signing keys.
|
|
652
806
|
|
|
653
807
|
## Reproducible investigation manifest
|
|
654
808
|
|
|
655
809
|
`manifest <artefact.json> [...] --workflow <label>` reads from 1 to 16 ordered
|
|
656
|
-
JSON artefacts and emits `whoisleuth.investigation-manifest` version
|
|
810
|
+
JSON artefacts and emits `whoisleuth.investigation-manifest` version 2. Each
|
|
657
811
|
entry records its sequence, bounded schema and version metadata, exact UTF-8
|
|
658
|
-
content digest, canonical JSON digest, and byte count.
|
|
659
|
-
|
|
812
|
+
content digest, `sorted-json-v2` canonical JSON digest, and byte count. Version
|
|
813
|
+
1 manifests remain verifiable with their historical digest bytes. The manifest
|
|
814
|
+
also records the installed CLI version and can include an externally calculated
|
|
660
815
|
`--configuration-digest sha256:...` without copying configuration values.
|
|
661
816
|
|
|
662
817
|
Source paths, filenames, command-line arguments, and artefact contents are not
|
|
@@ -725,12 +880,17 @@ time, certificate SHA-256 digest, one or more DNS names, completeness, and
|
|
|
725
880
|
optional issuer, expiry, and limitations. Unknown fields, malformed names,
|
|
726
881
|
unsupported completeness values, and oversized batches are rejected.
|
|
727
882
|
|
|
728
|
-
JSON output uses the existing `whoisleuth.external-findings` version
|
|
883
|
+
JSON output uses the existing `whoisleuth.external-findings` version 4 contract
|
|
729
884
|
and can be deliberately imported into the browser Console. Wildcard names are
|
|
730
885
|
normalised to their base DNS name, exact event/domain duplicates are removed,
|
|
731
886
|
and deterministic output is capped at 100 findings, 25 domains, and 20 findings
|
|
732
887
|
per domain to match the browser import boundary. Omission is stated in each
|
|
733
888
|
retained finding when the supplied batch exceeds those limits. The command
|
|
889
|
+
makes a deterministic event identifier and preserves the supplied log id,
|
|
890
|
+
certificate digest, issuer, expiry, original DNS-name count, and whether the
|
|
891
|
+
bounded import retained the complete supplied name set. This metadata lets the
|
|
892
|
+
browser replay reviewed issuer and certificate-name expectations without
|
|
893
|
+
mistaking an omitted name for a mismatch. The command
|
|
734
894
|
makes no request and treats every certificate event as a review lead, not proof
|
|
735
895
|
that the certificate was served, requested, or controlled by the named domain.
|
|
736
896
|
|
|
@@ -746,7 +906,7 @@ computed expressions, network endpoints, or executable callbacks. Prototype
|
|
|
746
906
|
paths and unknown fields are rejected.
|
|
747
907
|
|
|
748
908
|
The resulting JSON is the existing browser-compatible
|
|
749
|
-
`whoisleuth.external-findings` version
|
|
909
|
+
`whoisleuth.external-findings` version 4 contract. It retains source identity,
|
|
750
910
|
observation time, completeness, and limitations, while stating that field
|
|
751
911
|
semantics were not independently verified. Deterministic output is capped at
|
|
752
912
|
100 findings, 25 domains, and 20 findings per domain. The command makes no
|
|
@@ -883,6 +1043,9 @@ and BIMI directly from the local machine. Literal SPF include and redirect
|
|
|
883
1043
|
branches are expanded within fixed depth, policy-query, DNS-term, void-answer,
|
|
884
1044
|
cycle, and time bounds. External DMARC reporting authorisation and external
|
|
885
1045
|
nameserver, mail, SPF, and reporting dependencies are separately reported.
|
|
1046
|
+
The MTA-STS policy request uses the fixed HTTPS policy host and well-known path;
|
|
1047
|
+
HTTP redirects are not followed, as required by RFC 8461, and a redirect leaves
|
|
1048
|
+
that evidence unavailable rather than borrowing a policy body from another URL.
|
|
886
1049
|
Supply up to ten known active and retired DKIM selectors in total with
|
|
887
1050
|
`--selectors selector1,selector2` and `--retired-selectors selector0`;
|
|
888
1051
|
selectors cannot be reliably discovered from DNS, so no-selector output
|
|
@@ -980,6 +1143,9 @@ complete supported static page-identity observations on both sides.
|
|
|
980
1143
|
|
|
981
1144
|
Each page component remains independent. Exact, similar, overlapping,
|
|
982
1145
|
different, unavailable, and partial evidence are not collapsed into a score.
|
|
1146
|
+
Version 3 also withholds technology-set equality and disjointness whenever
|
|
1147
|
+
either saved technology observation is partial or truncated; the retained
|
|
1148
|
+
identifiers remain visible only as incomplete evidence.
|
|
983
1149
|
Matching components are investigative relationships rather than proof of
|
|
984
1150
|
copying, common ownership, control, intent, safety, or maliciousness. Static
|
|
985
1151
|
comparison does not execute JavaScript; use the optional local rendered
|
|
@@ -1001,14 +1167,126 @@ behaviour, SMTP banners, or whether a mail server is rogue, safe, or malicious.
|
|
|
1001
1167
|
An analyst may add a bounded `tlsaEvidence` object to a version-2 Bulk item for
|
|
1002
1168
|
offline DANE review. It must name the exact `_25._tcp.<mx-host>` service, and
|
|
1003
1169
|
that host must occur in the same item's retained MX evidence. A certificate
|
|
1004
|
-
association match is complete only when `dnssecState` is `validated`.
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1170
|
+
association match is complete only when `dnssecState` is `validated`. For an
|
|
1171
|
+
SMTP relay service on `_25._tcp`, PKIX-TA usage 0 and PKIX-EE usage 1 are
|
|
1172
|
+
reported as unsupported and cannot complete SMTP DANE assurance because RFC
|
|
1173
|
+
7672 leaves their SMTP treatment undefined. Usage 2 likewise
|
|
1174
|
+
cannot complete DANE-TA assurance because this offline action does not construct
|
|
1175
|
+
or validate a path from the observed leaf to the supplied trust-anchor material.
|
|
1176
|
+
For other service ports, usage 0 compares against the bounded
|
|
1177
|
+
`authorityMaterials` array and remains path-binding limited, while usage 1
|
|
1178
|
+
compares against the leaf and still requires independently validated PKIX.
|
|
1179
|
+
Usage 3 compares against the supplied leaf certificate or SPKI. Mismatched
|
|
1008
1180
|
service names, missing certificate roles, unvalidated prerequisites, malformed
|
|
1009
1181
|
material, and truncation remain invalid, partial, or untrusted rather than
|
|
1010
1182
|
becoming a DANE match.
|
|
1011
1183
|
|
|
1184
|
+
## Isolated cryptographic and mail transport review
|
|
1185
|
+
|
|
1186
|
+
These two network actions are disconnected from Lookup, Bulk, monitoring, and
|
|
1187
|
+
fixed recipes. They run only through their dedicated commands, require
|
|
1188
|
+
`--owned-or-authorized` on every invocation, use one caller-selected literal
|
|
1189
|
+
public resolver address, and require a local version-1
|
|
1190
|
+
`whoisleuth.dnssec-trust-anchor` JSON file. The resolver receives the DNS
|
|
1191
|
+
questions and can apply its own logging and retention. Resolver hostnames,
|
|
1192
|
+
private or reserved addresses, automatic resolver selection, and a non-default
|
|
1193
|
+
DNS port are refused.
|
|
1194
|
+
|
|
1195
|
+
Queries set RD, CD, and EDNS DO so the selected recursive resolver returns
|
|
1196
|
+
DNSSEC material for local validation; the resolver's AD bit is recorded only
|
|
1197
|
+
as response metadata and never substitutes for local cryptographic checks.
|
|
1198
|
+
|
|
1199
|
+
`dnssec-validate <domain> --resolver <public-IP> --trust-anchor <anchor.json>
|
|
1200
|
+
--owned-or-authorized` performs an isolated DNS-over-TCP validation from the
|
|
1201
|
+
supplied anchor. It validates supported DS, DNSKEY, and RRSIG relationships,
|
|
1202
|
+
and supported authenticated NSEC or exact NSEC3 denial evidence. NSEC3 opt-out
|
|
1203
|
+
spans and unknown flags remain explicitly unsupported. The action
|
|
1204
|
+
is capped at 32 DNS queries, eight delegations, 512 KiB of DNS
|
|
1205
|
+
response bytes, 2.5 seconds per query, and 15 seconds total, with no retry.
|
|
1206
|
+
Authenticated RRsets are capped at 32 records and 16 matching signatures, and
|
|
1207
|
+
denial review accepts at most 16 NSEC3 records per response.
|
|
1208
|
+
Canonical RRsets are deduplicated and ordered by canonical RDATA before the
|
|
1209
|
+
fixed owner, type, class, TTL, and length fields are constructed. NSEC Next
|
|
1210
|
+
Domain Name case is preserved as required for its canonical RDATA, while the
|
|
1211
|
+
RRSIG Signer's Name in signed data is canonical lowercase. A positive RRset
|
|
1212
|
+
whose RRSIG label count indicates wildcard expansion remains `unsupported`
|
|
1213
|
+
unless authenticated denial evidence proves the expansion; this version does
|
|
1214
|
+
not infer that proof from the signature alone.
|
|
1215
|
+
Supported signature algorithms are 5, 7, 8, 10, 13, 14, 15, and 16; supported
|
|
1216
|
+
DS digests are 1, 2, and 4; NSEC3 iteration counts above 500 remain
|
|
1217
|
+
unsupported. The output is `whoisleuth.dnssec-chain-validation` version 1 and
|
|
1218
|
+
keeps `secure`, `insecure`, `bogus`, `indeterminate`, `timed_out`,
|
|
1219
|
+
`unsupported`, and `invalid` separate. Resolver transport failures do not
|
|
1220
|
+
become cryptographic failures. The report retains the target, selected
|
|
1221
|
+
resolver, trust-anchor source and review time, validated zones, bounded counts,
|
|
1222
|
+
state, failure stage, and limitations. DNS wire responses, DNSKEY public keys,
|
|
1223
|
+
signatures, and transaction identifiers are not retained. `secure` describes
|
|
1224
|
+
the supported chain at that observation time; it is not an ownership,
|
|
1225
|
+
availability, safety, or maliciousness conclusion.
|
|
1226
|
+
|
|
1227
|
+
The trust-anchor document contains exactly `schema`, `version`, `zone`,
|
|
1228
|
+
`source`, `reviewedAt`, and one to eight `dsRecords`. Each DS entry contains
|
|
1229
|
+
`keyTag`, `algorithm`, `digestType`, and a correctly sized hexadecimal
|
|
1230
|
+
`digest`. The file is capped at 64 KiB. WHOISleuth does not download, refresh,
|
|
1231
|
+
select, or vouch for an anchor; maintaining its source and review time is the
|
|
1232
|
+
operator's responsibility.
|
|
1233
|
+
|
|
1234
|
+
`mail-transport [input.json] --resolver <public-IP> --trust-anchor
|
|
1235
|
+
<anchor.json> --owned-or-authorized --active-probe` additionally requires a
|
|
1236
|
+
separate active-probe acknowledgement on every run. Its version-1
|
|
1237
|
+
`whoisleuth.mail-transport.input` names one domain, one to three distinct
|
|
1238
|
+
selected MX hostnames, and optional bounded `policyContext.mtaSts` and
|
|
1239
|
+
`policyContext.tlsRpt` observations. Policy entries retain a supplied state,
|
|
1240
|
+
source, observation time, and `complete`, `partial`, or `unavailable`
|
|
1241
|
+
completeness; the command does not fetch either policy.
|
|
1242
|
+
|
|
1243
|
+
Selected hosts are processed sequentially. Each host is resolved through the
|
|
1244
|
+
chosen resolver, every returned connection candidate is checked as a public
|
|
1245
|
+
IP address, at most 16 candidates and four aliases are accepted per resolution,
|
|
1246
|
+
and the selected address must still occur in a fresh resolution immediately
|
|
1247
|
+
before one direct pinned port-25 connection. The client accepts only bounded
|
|
1248
|
+
printable-ASCII SMTP reply framing, sends exactly `EHLO whoisleuth.invalid`, and sends
|
|
1249
|
+
`STARTTLS` only when advertised. It never sends `AUTH`, `MAIL FROM`, `RCPT TO`,
|
|
1250
|
+
`DATA`, `VRFY`, `EXPN`, a message, or a retry. Per endpoint, SMTP response data
|
|
1251
|
+
is capped at 16 KiB, 64 lines, 1,000 bytes per line, and 32 retained capability
|
|
1252
|
+
names; one leaf certificate is accepted up to 256 KiB and the fixed endpoint
|
|
1253
|
+
timeout is eight seconds. Expiry aborts and destroys the connection. The entire
|
|
1254
|
+
sequential run is capped at 30 seconds and shares a
|
|
1255
|
+
32-query, 512-KiB DNS budget.
|
|
1256
|
+
|
|
1257
|
+
Address provenance advances only through `selected`, `revalidated`, and
|
|
1258
|
+
`connected`; failures retain the strongest completed stage and never describe a
|
|
1259
|
+
DNS candidate as connection evidence. Successful fresh public-address checking
|
|
1260
|
+
uses `resolution.state=public_revalidated`. The separate
|
|
1261
|
+
`addressAuthentication.state` is `not_evaluated` after an address candidate is
|
|
1262
|
+
retained because the A or AAAA RRset and any CNAME chain are not
|
|
1263
|
+
cryptographically validated by this action; it is `unavailable` when no
|
|
1264
|
+
candidate was retained.
|
|
1265
|
+
|
|
1266
|
+
TLSA records for `_25._tcp.<selected-mx>` are compared only after their RRset
|
|
1267
|
+
or denial evidence validates through that endpoint's separately reported
|
|
1268
|
+
DNSSEC context. PKIX authorisation, certificate hostname identity,
|
|
1269
|
+
DNSSEC-chain validation, TLSA publication, DANE comparison, STARTTLS, SMTP
|
|
1270
|
+
transport, MTA-STS context, and TLS-RPT context retain separate states;
|
|
1271
|
+
missing or incomplete evidence in one family is never filled from another.
|
|
1272
|
+
If a DANE-TA TLSA usage 2 association is published, active STARTTLS review
|
|
1273
|
+
retains only the observed leaf certificate and leaves that comparison partial
|
|
1274
|
+
because this action does not construct or validate a certificate path to a
|
|
1275
|
+
TLSA trust anchor.
|
|
1276
|
+
The `whoisleuth.cli.mail-transport-review` version-1 output retains selected MX
|
|
1277
|
+
names, the bounded address value, family, highest proven address stage, and
|
|
1278
|
+
separate address-authentication state, greeting status and SHA-256 digest, capability
|
|
1279
|
+
names, certificate and SPKI SHA-256 digests, protocol and cipher labels,
|
|
1280
|
+
bounded certificate authorization or identity error text, source times, counts,
|
|
1281
|
+
completeness, and limitations. Raw greeting or reply
|
|
1282
|
+
text, certificate bytes, TLS session material, and DNS wire responses are not
|
|
1283
|
+
retained. Only address values whose stage is `connected` can form an exact
|
|
1284
|
+
shared-address lead. Address, greeting-digest, and certificate-digest matches
|
|
1285
|
+
are labelled review leads only; they do not establish a rogue endpoint, common
|
|
1286
|
+
ownership, coordination, intent, safety, or maliciousness. Neither action
|
|
1287
|
+
changes Risk, Opportunity, registration availability, or any stored browser
|
|
1288
|
+
record.
|
|
1289
|
+
|
|
1012
1290
|
## Offline supplied-evidence review
|
|
1013
1291
|
|
|
1014
1292
|
`review-evidence [evidence.json]` accepts one version-1 JSON input and performs
|
|
@@ -1029,7 +1307,12 @@ Supported input schemas are:
|
|
|
1029
1307
|
`_port._transport.hostname` service and compares supplied leaf or authority
|
|
1030
1308
|
certificate/SPKI bytes. `matched` requires independently validated DNSSEC;
|
|
1031
1309
|
PKIX-TA and PKIX-EE usages also require an independently validated PKIX path.
|
|
1032
|
-
|
|
1310
|
+
PKIX-TA usage 0 retains per-record authority comparisons but cannot complete
|
|
1311
|
+
PKIX-TA assurance because supplied authority material is not proven to belong
|
|
1312
|
+
to that validated path. DANE-TA usage 2 likewise cannot complete DANE-TA
|
|
1313
|
+
assurance because this offline action does not construct or validate a
|
|
1314
|
+
leaf-to-anchor certificate path. The command does not retrieve the certificate
|
|
1315
|
+
or negotiate STARTTLS.
|
|
1033
1316
|
- `whoisleuth.rdap-search-input`: normalises a supplied RDAP search-help
|
|
1034
1317
|
response and prepares an exact supported reverse-search request without
|
|
1035
1318
|
sending it. If the document also contains a previously obtained `response`,
|
|
@@ -1038,6 +1321,13 @@ Supported input schemas are:
|
|
|
1038
1321
|
the response as authoritative or complete.
|
|
1039
1322
|
- `whoisleuth.rpki-route-input`: compares a route prefix and origin ASN with a
|
|
1040
1323
|
bounded analyst-supplied VRP set.
|
|
1324
|
+
- `whoisleuth.cryptographic-assurance.input`: accepts separately wrapped,
|
|
1325
|
+
source-qualified DNSSEC, route-origin, and DANE/TLSA evidence and emits three
|
|
1326
|
+
independent cards. Every card retains its own authority, source, observation
|
|
1327
|
+
time, state, completeness, result, and limitations. An omitted family remains
|
|
1328
|
+
`unavailable`; the version-1 `whoisleuth.cryptographic-assurance.review`
|
|
1329
|
+
contains `combinedState: null` and never emits a scalar score or combined
|
|
1330
|
+
verdict.
|
|
1041
1331
|
- `whoisleuth.local-geoip-query`: queries an analyst-supplied bounded prefix
|
|
1042
1332
|
database whose source, version, and licence metadata remain in the result.
|
|
1043
1333
|
- `whoisleuth.local-mmdb-query`: with an explicit `--mmdb <database-file>`,
|
|
@@ -1113,8 +1403,9 @@ fingerprint, registrar-lock preference, and a renewal-review date for up to 100
|
|
|
1113
1403
|
domains. Empty fields mean unconfigured; they do not require a record to be
|
|
1114
1404
|
absent.
|
|
1115
1405
|
|
|
1116
|
-
The emitted `whoisleuth.domain-control-manifest` version
|
|
1117
|
-
protected by a
|
|
1406
|
+
The emitted `whoisleuth.domain-control-manifest` version 2 is normalised and
|
|
1407
|
+
protected by a `sorted-json-v2` SHA-256 digest. Version 1 remains readable with
|
|
1408
|
+
its historical canonicalization contract. Either version can also be passed to
|
|
1118
1409
|
`sign-artifact` for an optional local Ed25519 signature. Integrity and
|
|
1119
1410
|
signature verification detect changes and authenticate possession of the
|
|
1120
1411
|
selected key; neither establishes that the desired state is correct. Manifest
|
|
@@ -1122,6 +1413,15 @@ input and verification reject unknown fields, and verification rejects
|
|
|
1122
1413
|
non-canonical content rather than returning a shape that differs from the
|
|
1123
1414
|
normalised contract covered by the digest.
|
|
1124
1415
|
|
|
1416
|
+
The same version-two manifest is the browser Console's domain-control passport
|
|
1417
|
+
format; its browser and CLI input envelope remains version 1. A deliberately
|
|
1418
|
+
selected passport can move the supported desired-state
|
|
1419
|
+
subset between Brand Profiles and the CLI without copying profile identity,
|
|
1420
|
+
notes, observations, change windows, suppressions, or other browser-only
|
|
1421
|
+
planning. Browser import verifies the digest and presents a field-level,
|
|
1422
|
+
non-destructive preview. A manifest remains an analyst-authored expectation in
|
|
1423
|
+
either runtime; interoperability does not make it observed evidence.
|
|
1424
|
+
|
|
1125
1425
|
A review input uses `whoisleuth.domain-control-review-input` version 1 and
|
|
1126
1426
|
contains one manifest plus separately attributed observations. Only a complete
|
|
1127
1427
|
`observed` field may produce `drift`. Partial, unavailable, unsupported, and
|
|
@@ -1129,6 +1429,17 @@ missing observations remain inconclusive, and unrelated observations are
|
|
|
1129
1429
|
counted but ignored. The review performs no DNS, RDAP, HTTP, TLS, SMTP, or
|
|
1130
1430
|
registrar request.
|
|
1131
1431
|
|
|
1432
|
+
The saved-Lookup review envelope uses
|
|
1433
|
+
`whoisleuth.cli.domain-control-review-input` version 1 and accepts from 1 to
|
|
1434
|
+
100 saved Lookup documents. The raw envelope is scanned before parsing for
|
|
1435
|
+
duplicate keys, the prototype-sensitive `__proto__` key, and a 50-level
|
|
1436
|
+
envelope depth that preserves each saved Lookup's standalone 48-level limit.
|
|
1437
|
+
Its aggregate scanner permits up to 5,050,000 keys and 10,100,000 values so
|
|
1438
|
+
the envelope does not silently narrow the per-document version-1 contract;
|
|
1439
|
+
no individual object or array may contain more than 10,000 items, and the
|
|
1440
|
+
command's byte ceiling remains authoritative. Each embedded Lookup is
|
|
1441
|
+
then independently revalidated against its ordinary saved-document bounds.
|
|
1442
|
+
|
|
1132
1443
|
## Domain assurance review
|
|
1133
1444
|
|
|
1134
1445
|
`assurance [input.json]` reviews one bounded analyst-authored workflow entirely
|
|
@@ -1158,10 +1469,11 @@ no registrar, DNS, mail, certificate, or recovery configuration.
|
|
|
1158
1469
|
|
|
1159
1470
|
`change-packet [input.json]` combines one pre-change domain review, one
|
|
1160
1471
|
post-change domain review, and one planned-change assurance input for the same
|
|
1161
|
-
domain. The input
|
|
1472
|
+
domain. The input remains `whoisleuth.domain-change-packet.input` version 1. The
|
|
1162
1473
|
command revalidates each nested contract, summarises changed authoritative
|
|
1163
|
-
record sets, and emits `whoisleuth.domain-change-packet` version
|
|
1164
|
-
|
|
1474
|
+
record sets, and emits `whoisleuth.domain-change-packet` version 2 with a
|
|
1475
|
+
`sorted-json-v2` SHA-256 integrity digest. Historical packet version 1 remains
|
|
1476
|
+
verifiable with its original digest bytes.
|
|
1165
1477
|
|
|
1166
1478
|
The packet is ready only when both supplied observation reviews and the change
|
|
1167
1479
|
plan pass their own bounded gates. Partial or unavailable evidence remains a
|
|
@@ -1216,14 +1528,46 @@ canonical SHA-256 digest and redaction manifest. It refuses an invalid,
|
|
|
1216
1528
|
duplicate, larger, or generated package above the browser's 2 MiB import limit
|
|
1217
1529
|
rather than silently omitting records or evidence. Trusted output removes notes,
|
|
1218
1530
|
recipient values, and manual-pivot targets. Public output additionally removes
|
|
1219
|
-
actions
|
|
1220
|
-
|
|
1531
|
+
actions, analyst assertions, named investigation branches, and every exact
|
|
1532
|
+
Brand Profile identifier from both the top-level cases and embedded Case report
|
|
1533
|
+
v8 projections. Its redaction manifest records the bounded
|
|
1534
|
+
`brandProfileReferencesOmitted` count, which cannot exceed 200. Trusted and
|
|
1535
|
+
internal output preserve the exact references and record zero omissions.
|
|
1536
|
+
Trusted output retains branch references while redacting action recipients.
|
|
1537
|
+
The review flag records an explicit choice; it does not prove recipient
|
|
1538
|
+
authorisation, profile ownership, attribution, or factual correctness.
|
|
1221
1539
|
|
|
1222
1540
|
`verify-artifact` recognises the complete case-pack envelope before browser
|
|
1223
1541
|
import. It checks the canonical digest, supported case-export schema, bounded
|
|
1224
1542
|
case count, report count, audience and explicit review marker without printing
|
|
1225
|
-
case contents.
|
|
1226
|
-
|
|
1543
|
+
case contents. For Case schema 12 it validates the opaque-reference syntax,
|
|
1544
|
+
requires public cases and reports to contain no references, and requires
|
|
1545
|
+
trusted or internal report references to match their top-level case. The
|
|
1546
|
+
case-pack envelope is version 2 with `sorted-json-v2` integrity; a valid legacy
|
|
1547
|
+
version-1 pack carrying a
|
|
1548
|
+
pre-v12 Case collection remains accepted without inventing the new field or
|
|
1549
|
+
redaction count. Current builders reject a schema-12 raw case unless its
|
|
1550
|
+
complete bounded Case projection, safe canonical identity, and unique
|
|
1551
|
+
at-most-eight reference list survive normalisation exactly; over-bound notes,
|
|
1552
|
+
actions, and other fields are not silently truncated. Legacy builder input
|
|
1553
|
+
remains lenient for later fields. Before digest calculation, the verifier binds
|
|
1554
|
+
each report's supported schema version, canonical Case identifier, domain, and
|
|
1555
|
+
audience-sensitive projection to its top-level case. It rejects re-signed
|
|
1556
|
+
public notes, actions, assertions, branches, recipients, manual-trail targets,
|
|
1557
|
+
or Brand Profile references, and the corresponding trusted-field leaks,
|
|
1558
|
+
including copies at unexpected nested paths. It also enforces the exact
|
|
1559
|
+
epoch-specific audience exclusion list, source-case count, and omission-count
|
|
1560
|
+
rules. Current Case schema 12 requires report v8, schema 11 requires report v7,
|
|
1561
|
+
and schemas through 10 accept supported reports through v6 without inventing
|
|
1562
|
+
later branch or Brand-reference fields. For every audience and Case schema 2
|
|
1563
|
+
through 11, retained Case and report nodes must have the same object, array,
|
|
1564
|
+
null, or scalar kind as their bounded normalised projection, and every nested
|
|
1565
|
+
key must belong to that versioned projection. Historical omissions remain
|
|
1566
|
+
valid, while re-signed scalar substitutions and undeclared private fields do
|
|
1567
|
+
not. These checks
|
|
1568
|
+
also govern offline verification and interchange-fidelity classification. This
|
|
1569
|
+
detects a changed or internally inconsistent hand-off file but does not
|
|
1570
|
+
authenticate the analyst, recipient, source observations, or review decision.
|
|
1227
1571
|
|
|
1228
1572
|
`monitor-once [manifest.json]` performs one bounded Deep control review for at
|
|
1229
1573
|
most 20 manifest domains with concurrency capped at three. An optional
|
|
@@ -1236,13 +1580,23 @@ failure policies are supported.
|
|
|
1236
1580
|
installed fixed recipes. Network steps require `--approve-network` for that
|
|
1237
1581
|
invocation. Analyst-selection placeholders always pause. A bounded `--resume`
|
|
1238
1582
|
state must match the exact recipe and subject, cannot add commands or shell
|
|
1239
|
-
syntax, and is not evidence that earlier results remain current.
|
|
1583
|
+
syntax, and is not evidence that earlier results remain current. Retained
|
|
1584
|
+
successful steps must form an exact contiguous prefix of the installed recipe,
|
|
1585
|
+
including command, ordered arguments, mode and output schema. A final failed
|
|
1586
|
+
step is retried rather than trusted as completed.
|
|
1587
|
+
|
|
1588
|
+
The `domain-triage` plan deliberately pairs `export` with `verify-artifact`.
|
|
1589
|
+
A fresh current Lookup-evidence export must pass the verifier as
|
|
1590
|
+
`structure_valid`; this establishes bounded contract compatibility, not a
|
|
1591
|
+
checksum, signature, source truth, or observation currency.
|
|
1240
1592
|
|
|
1241
1593
|
## Optional local rendered capture
|
|
1242
1594
|
|
|
1243
1595
|
`packages/web-capture` is a private repo-local Playwright package, not part of
|
|
1244
1596
|
the distributable core CLI or hosted application. It requires an explicit
|
|
1245
|
-
authorisation flag and one new output
|
|
1597
|
+
authorisation flag, one domain-hosted HTTP(S) target, and one new output
|
|
1598
|
+
directory. IP-literal targets are rejected so successful manifests remain
|
|
1599
|
+
compatible with the domain-only Cases importer:
|
|
1246
1600
|
|
|
1247
1601
|
```bash
|
|
1248
1602
|
npm run capture:local -- https://example.test --output-dir ./capture-example --authorize-rendered-capture
|
|
@@ -1254,22 +1608,38 @@ digest containing hashes and bounded element counts rather than markup or page
|
|
|
1254
1608
|
text, and a version-2 `whoisleuth.web-capture-manifest` compatible with the
|
|
1255
1609
|
Cases importer. Version-1 manifests remain importable.
|
|
1256
1610
|
|
|
1257
|
-
Rendered capture executes page JavaScript.
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
page
|
|
1262
|
-
|
|
1263
|
-
|
|
1611
|
+
Rendered capture executes page JavaScript. Each admitted resource operator
|
|
1612
|
+
receives the exact requested URL, including path and query, and ordinary
|
|
1613
|
+
allowlisted request headers; structured manifest and digest fields retain only
|
|
1614
|
+
the target hostname, final HTTP(S) origin, admitted public resource hostnames,
|
|
1615
|
+
and one control-sanitised page title of up to 300 characters, not those paths or queries. The screenshot necessarily
|
|
1616
|
+
preserves visible rendered content and may include page text or a page-reflected
|
|
1617
|
+
path or query until the operator deletes it. It caps HTTP(S) requests and request
|
|
1618
|
+
hostnames, blocks downloads, service workers, dedicated and shared workers, WebSockets, WebRTC, WebTransport,
|
|
1619
|
+
non-read methods, credentials, non-default ports, and private or reserved
|
|
1620
|
+
addresses, and retains no request path, query, headers, bodies, cookies,
|
|
1621
|
+
credentials, DOM markup, or body text in the structured manifest or digest
|
|
1622
|
+
beyond that bounded title. Every browser request is intercepted, its hostname is resolved again,
|
|
1623
|
+
and the bounded response is fetched through WHOISleuth's public-address-pinned
|
|
1624
|
+
transport. Individual responses are capped at 4 MiB and all fetched response
|
|
1625
|
+
bodies together are capped at 24 MiB. Redirect destinations pass through the
|
|
1626
|
+
same interception and validation before collection continues. Use a disposable
|
|
1627
|
+
network-restricted environment for untrusted targets because rendered page code
|
|
1628
|
+
still executes inside the isolated browser process.
|
|
1264
1629
|
|
|
1265
1630
|
The separate offline comparison command accepts two selected version-2 local
|
|
1266
1631
|
capture manifests. It first verifies each referenced screenshot and DOM digest
|
|
1267
1632
|
against its declared size, SHA-256, screenshot dimensions, and perceptual hash;
|
|
1268
1633
|
it also validates bounded source and limitation metadata and requires the DOM,
|
|
1269
1634
|
manifest, and source collection times to agree. It then
|
|
1270
|
-
compares screenshot distance, exact
|
|
1271
|
-
|
|
1272
|
-
|
|
1635
|
+
compares screenshot distance, exact equality of the bounded preorder
|
|
1636
|
+
element-tag sequence and body text-node sequence, bounded element counts, page
|
|
1637
|
+
identity, technologies, and request-domain sets. The tag sequence omits nesting
|
|
1638
|
+
and attributes. The version-1 DOM-digest schema retains the `visibleText` field
|
|
1639
|
+
name for compatibility, but it includes bounded body text nodes that CSS or
|
|
1640
|
+
non-rendered containers may hide and is not a visibility claim.
|
|
1641
|
+
Version-2 comparison output reports only whether the two bounded page titles
|
|
1642
|
+
match; it does not copy either title. It does not recrawl either target, reveal the input paths, or collapse the
|
|
1273
1643
|
independent components into a similarity or maliciousness score. A missing
|
|
1274
1644
|
perceptual hash remains unavailable rather than becoming a visual difference.
|
|
1275
1645
|
|
|
@@ -1282,13 +1652,36 @@ stdout, so use ordinary shell redirection when a file is wanted. Pretty JSON is
|
|
|
1282
1652
|
the default; `--compact` emits one compact JSON line for pipeline use, while
|
|
1283
1653
|
`--markdown` produces a readable source-attributed summary and `--html`
|
|
1284
1654
|
produces a self-contained printable report. Compact, Markdown, and HTML output
|
|
1285
|
-
are mutually exclusive.
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
The
|
|
1290
|
-
|
|
1291
|
-
|
|
1655
|
+
are mutually exclusive. Markdown and HTML include the fixed generator footer
|
|
1656
|
+
by default; `--no-attribution` removes only that footer and is rejected for
|
|
1657
|
+
JSON output.
|
|
1658
|
+
|
|
1659
|
+
The current schema-26 JSON output can be passed directly to
|
|
1660
|
+
`verify-artifact`. The verifier reports `structure_valid` because this format
|
|
1661
|
+
has no embedded checksum or signature. Use a verified investigation manifest
|
|
1662
|
+
and exact manifest-entry identity when byte-for-byte retention matters, and
|
|
1663
|
+
review the bounded privacy-projected registry RDAP publication, normalised
|
|
1664
|
+
WHOIS values, and bounded contacts before sharing. `interchange-report`
|
|
1665
|
+
recognises the current format and describes the
|
|
1666
|
+
browser replay as lossy by design because replay renders bounded normalised
|
|
1667
|
+
facts rather than raw payloads. Schema 25 remains readable when its retained
|
|
1668
|
+
historical wrappers differ from retained diagnostics in the ways emitted by
|
|
1669
|
+
the former producer. The diagnostics remain authoritative, unavailable wrapper
|
|
1670
|
+
data is suppressed during replay, and other contradictory legacy shapes fail
|
|
1671
|
+
closed rather than becoming positive observations.
|
|
1672
|
+
|
|
1673
|
+
The saved input is capped at 8 MiB and scanned before parsing for duplicate
|
|
1674
|
+
object keys, the prototype-sensitive `__proto__` key, more than 48 nesting levels, more than 50,000
|
|
1675
|
+
keys, more than 100,000 values, or more than 10,000 items in one container. It is then revalidated using the same schema, source-status,
|
|
1676
|
+
parsed-data, scalar, list, and event boundaries as `compare`. Portable
|
|
1677
|
+
projection stops at 24 levels and 20,000 entries before recursive copying, and
|
|
1678
|
+
the completed package must pass the same portable-tree assertion used by the
|
|
1679
|
+
browser replay and serializer.
|
|
1680
|
+
The export retains query context, explicitly projected source diagnostics,
|
|
1681
|
+
normalised registry data, a bounded privacy-projected registry RDAP
|
|
1682
|
+
publication, availability analysis, bounded WHOIS referral-hop
|
|
1683
|
+
metadata without response bodies, and the shared
|
|
1684
|
+
registry-source comparison. Version 23 can add the exact local
|
|
1292
1685
|
SSLBL comparison already represented by a deep full Lookup. Version 21 adds the bounded registry
|
|
1293
1686
|
lifecycle, disclosure, publication-quality, reconciliation, and abuse-routing
|
|
1294
1687
|
interpretation derived from the already-collected sources. Registrar RDAP raw
|