@slicedearth/whoisleuth-cli 2.2.0 → 2.4.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/NOTICE +6 -0
- package/README.md +20 -15
- package/bin/whoisleuth.mjs +8 -1
- package/cli/archive-content-digest.mjs +14 -0
- package/cli/archive-inspect.mjs +20 -53
- package/cli/arguments.mjs +454 -1748
- package/cli/artifact-validation/case-response.mjs +66 -35
- package/cli/artifact-validation/investigation-capsule.mjs +52 -31
- package/cli/artifact-validation/lookup-evidence.mjs +12 -6
- package/cli/artifact-validation/signed-review.mjs +112 -72
- package/cli/artifact-validation/structure-primitives.mjs +1 -105
- package/cli/artifact-verify.mjs +90 -24
- package/cli/assurance-command-runner.mjs +39 -4
- package/cli/bagit-folder.mjs +57 -0
- package/cli/bagit-review.mjs +23 -0
- package/cli/bounded-json.mjs +1 -1
- package/cli/bulk-checkpoint.mjs +34 -3
- package/cli/bulk-command-runner.mjs +2 -0
- package/cli/bulk-output.mjs +29 -3
- package/cli/case-command.mjs +195 -0
- package/cli/case-pack.mjs +66 -111
- package/cli/command-argument-grammar.mjs +215 -0
- package/cli/command-reference.mjs +342 -285
- package/cli/completion.mjs +303 -80
- package/cli/config-profile.mjs +7 -5
- package/cli/ct-event-intake.mjs +12 -12
- package/cli/discover.mjs +4 -3
- package/cli/discovery-observation-snapshot.mjs +59 -18
- package/cli/discovery-scan-command-runner.mjs +21 -0
- package/cli/discovery-scan.mjs +13 -4
- package/cli/discovery-workflow.mjs +1 -1
- package/cli/domain-control-monitor.mjs +50 -20
- package/cli/domain-control-observations.mjs +149 -102
- package/cli/errors.mjs +33 -1
- package/cli/evidence-command-runner.mjs +16 -5
- package/cli/evidence-signing.mjs +2 -2
- package/cli/external-observation-mapping.mjs +7 -8
- package/cli/formatters/terminal-lookup.mjs +18 -46
- package/cli/formatters/terminal-shared.mjs +5 -3
- package/cli/formatters/terminal-technology.mjs +114 -0
- package/cli/inline-command-families.mjs +2 -0
- package/cli/input.mjs +116 -0
- package/cli/interactive-launcher.mjs +2 -160
- package/cli/interchange-report.mjs +18 -8
- package/cli/investigation-artifacts.mjs +176 -0
- package/cli/investigation-checkpoint.mjs +10 -0
- package/cli/investigation-folder.mjs +114 -0
- package/cli/investigation-manifest.mjs +1 -112
- package/cli/investigation-package-review.mjs +103 -0
- package/cli/investigation-plan.mjs +32 -19
- package/cli/investigation-run.mjs +188 -33
- package/cli/local-document-checkpoint.mjs +170 -0
- package/cli/lookalike-calibration.mjs +7 -2
- package/cli/lookup-brief.mjs +4 -2
- package/cli/lookup-browser-view.mjs +1 -1
- package/cli/lookup-browser.mjs +5 -12
- package/cli/lookup-command-runner.mjs +17 -6
- package/cli/lookup-diff.mjs +37 -3
- package/cli/lookup-plan.mjs +11 -5
- package/cli/lookup-reconcile.mjs +10 -8
- package/cli/mail-header-review.mjs +467 -0
- package/cli/mail-review.mjs +66 -14
- package/cli/manual.mjs +1 -0
- package/cli/network-command-runner.mjs +2 -0
- package/cli/output-file.mjs +31 -5
- package/cli/registry-doctor.mjs +3 -1
- package/cli/registry-support.mjs +1 -1
- package/cli/retained-artifact-diff.mjs +2 -2
- package/cli/review-command-runner.mjs +70 -0
- package/cli/risk-calibration.mjs +19 -17
- package/cli/runner.mjs +62 -7
- package/cli/sharing-review.mjs +21 -34
- package/cli/signer-trust.mjs +104 -0
- package/cli/source-reliability.mjs +74 -83
- package/cli/terminal-input.mjs +168 -0
- package/cli/workflow-command-runner.mjs +68 -13
- package/docs/cli-reference.md +77 -24
- package/docs/cli.md +300 -25
- package/lib/abort.mjs +4 -1
- package/lib/availability.mjs +161 -112
- package/lib/bounded-file.mjs +3 -1
- package/lib/bounded-html-document.mjs +125 -0
- package/lib/bounded-json.mjs +51 -8
- package/lib/browser-library-profile.mjs +42 -51
- package/lib/browser-library-worker.mjs +112 -0
- package/lib/client-behavior-profile.mjs +3 -3
- package/lib/ct-search.mjs +11 -4
- package/lib/dns-convergence-review.mjs +1 -0
- package/lib/dns-delegation-health.mjs +24 -14
- package/lib/dns-inheritance-review.mjs +217 -0
- package/lib/dns-intelligence.mjs +73 -26
- package/lib/dns-mx.mjs +1 -1
- package/lib/dnssec-chain-validation.mjs +6 -0
- package/lib/dnssec-evidence-validation.mjs +11 -3
- package/lib/domain-change-packet.mjs +49 -16
- package/lib/domain-change-review.mjs +14 -8
- package/lib/domain-control-flight-recorder.mjs +221 -117
- package/lib/domain-control-manifest.mjs +129 -69
- package/lib/domain-posture-analysis.mjs +20 -7
- package/lib/domain-posture-parsers.mjs +201 -8
- package/lib/domain-posture.mjs +147 -29
- package/lib/evidence-export-privacy.mjs +561 -0
- package/lib/evidence-export.mjs +11 -543
- package/lib/evidence-report.mjs +5 -3
- package/lib/favicon.mjs +117 -41
- package/lib/generated/cisa-kev-catalog.mjs +12 -4
- package/lib/generated/registrar-standing-catalogue.mjs +7 -7
- package/lib/generated/retire-browser-catalog.mjs +2335 -940
- package/lib/hostname.mjs +2 -38
- package/lib/html-signals.mjs +111 -108
- package/lib/http-evidence-bounds.mjs +2 -1
- package/lib/http-intelligence.mjs +39 -26
- package/lib/local-geoip-evidence.mjs +19 -3
- package/lib/lookup-cache.mjs +34 -11
- package/lib/lookup-child-profile-contract.mjs +24 -15
- package/lib/lookup-diagnostics.mjs +24 -1
- package/lib/lookup-progress.mjs +30 -13
- package/lib/lookup-response-contract.mjs +1048 -0
- package/lib/lookup-response.mjs +8 -10
- package/lib/lookup-source-progress.mjs +40 -14
- package/lib/lookup.mjs +48 -27
- package/lib/nameserver-preflight-review.mjs +1 -0
- package/lib/observed-network-context.mjs +43 -27
- package/lib/outbound-request-bounds.mjs +4 -1
- package/lib/page-fingerprints.mjs +69 -133
- package/lib/page-role-profile.mjs +12 -8
- package/lib/perceptual-hash.mjs +43 -14
- package/lib/rdap-bootstrap.mjs +72 -22
- package/lib/rdap-capabilities.mjs +1 -1
- package/lib/rdap-client.mjs +15 -7
- package/lib/rdap-normalization.mjs +33 -18
- package/lib/rdap-search-workbench.mjs +1 -1
- package/lib/rdap-transport.mjs +47 -20
- package/lib/rdap-types.mjs +2 -1
- package/lib/rdap.mjs +18 -3
- package/lib/registrable-domain.mjs +21 -1
- package/lib/registrar-standing-contract.mjs +1 -0
- package/lib/registry-capabilities.mjs +5 -1
- package/lib/registry-capability-catalogue.mjs +2 -1
- package/lib/registry-dates.mjs +2 -190
- package/lib/registry-insights.mjs +85 -34
- package/lib/response-policy.mjs +86 -48
- package/lib/risk-calibration-summary.mjs +18 -6
- package/lib/rpki-evidence.mjs +8 -5
- package/lib/safe-fetch.mjs +54 -47
- package/lib/security-txt.mjs +42 -7
- package/lib/service-binding-dns.mjs +8 -0
- package/lib/smtp-transport-review.mjs +27 -15
- package/lib/sslbl-certificates.generated.mjs +136 -135
- package/lib/static-html-analysis.mjs +178 -151
- package/lib/structured-data-identity.mjs +1 -0
- package/lib/technology-markup.mjs +100 -0
- package/lib/threat-intelligence-manifests.mjs +11 -139
- package/lib/threat-intelligence-runtime.mjs +24 -52
- package/lib/threat-intelligence-targets.mjs +6 -34
- package/lib/threat-intelligence-types.mjs +39 -0
- package/lib/typosquat-generator.mjs +19 -15
- package/lib/urlhaus-intelligence.mjs +8 -3
- package/lib/urlscan-intelligence.mjs +1 -1
- package/lib/website-security-posture.mjs +30 -6
- package/lib/website-technology.mjs +153 -45
- package/lib/whois-authority.mjs +14 -2
- package/lib/whois-chain.mjs +9 -2
- package/lib/whois-common-formats.mjs +5 -5
- package/lib/whois-contracts.mjs +2 -1
- package/lib/whois-dialects.mjs +2 -2
- package/lib/whois-parser-support.mjs +8 -1
- package/lib/whois-transport.mjs +23 -7
- package/lib/zone-intent-review.mjs +16 -6
- package/package.json +2 -1
- package/packages/cases/case-attachment-model.mjs +83 -0
- package/packages/cases/case-evidence-model.mjs +156 -62
- package/packages/cases/case-export-input.mjs +53 -0
- package/packages/cases/case-migration-model.mjs +127 -44
- package/packages/cases/case-model.mjs +1 -0
- package/packages/cases/case-recheck-model.mjs +91 -0
- package/packages/cases/case-record-contracts.mjs +5 -20
- package/packages/cases/case-record-core.mjs +12 -22
- package/packages/cases/case-record-decisions.mjs +72 -0
- package/packages/cases/case-record-model.mjs +1 -0
- package/packages/cases/case-record-operations.mjs +95 -31
- package/packages/cases/case-record-projection.mjs +221 -0
- package/packages/cases/case-report.mjs +70 -54
- package/packages/cases/case-response-actions.mjs +654 -0
- package/packages/cases/case-response-model.mjs +64 -1115
- package/packages/cases/case-response-outcomes.mjs +317 -0
- package/packages/cases/case-response-packet-render.mjs +153 -0
- package/packages/cases/case-response-packet-types.mjs +1 -0
- package/packages/cases/case-response-packet-vocabulary.mjs +48 -0
- package/packages/cases/case-response-packet.mjs +74 -572
- package/packages/cases/case-response-records.mjs +94 -0
- package/packages/cases/case-response-review-inputs.mjs +371 -0
- package/packages/cases/case-response-values.mjs +85 -0
- package/packages/cases/case-review-package.mjs +45 -0
- package/packages/cases/case-selection.mjs +46 -0
- package/packages/cases/case-storage-model.mjs +31 -2
- package/packages/cases/response-route-freshness.mjs +16 -0
- package/packages/comparison/capture-context.mjs +61 -0
- package/packages/comparison/comparison-ledger-bulk.mjs +13 -11
- package/packages/comparison/page-similarity.mjs +5 -2
- package/packages/comparison/relationship-evidence.mjs +85 -8
- package/packages/comparison/relationship-provenance.mjs +93 -0
- package/packages/contracts/analyst-interchange.mjs +216 -0
- package/packages/contracts/analyst-review-state-contract.mjs +11 -0
- package/packages/contracts/analyst-review-state.mjs +5 -4
- package/packages/contracts/case-portability.mjs +366 -83
- package/packages/contracts/case-views-contract.mjs +12 -0
- package/packages/contracts/case-views.mjs +26 -0
- package/packages/contracts/cli-command-semantics.mjs +94 -0
- package/packages/contracts/cli-lookup.mjs +0 -1
- package/packages/contracts/domain-control-flight-recorder.mjs +80 -42
- package/packages/contracts/domain-control-manifest.mjs +127 -73
- package/packages/contracts/domain-control-monitor.mjs +48 -45
- package/packages/contracts/domain-control-review.mjs +179 -121
- package/packages/contracts/domain-name.mjs +21 -0
- package/packages/contracts/external-observation-interchange.mjs +2 -1
- package/packages/contracts/extracted-domain-lifecycle.mjs +11 -32
- package/packages/contracts/http-url.mjs +2 -0
- package/packages/contracts/investigation-package-limits.mjs +24 -0
- package/packages/contracts/investigation-portability.mjs +56 -27
- package/packages/contracts/investigation-run.mjs +16 -0
- package/packages/contracts/ip-address.mjs +34 -0
- package/packages/contracts/lookup-evidence.mjs +35 -0
- package/packages/contracts/offline-comparison.mjs +1 -2
- package/packages/contracts/page-fingerprints.mjs +15 -0
- package/packages/contracts/risk-calibration.mjs +15 -11
- package/packages/contracts/schema-compatibility.mjs +1 -1
- package/packages/contracts/schema-lifecycle.mjs +83 -153
- package/packages/contracts/selected-file-limits.mjs +6 -0
- package/packages/contracts/vulnerability-identifiers.mjs +5 -0
- package/packages/contracts/web-capture.mjs +10 -0
- package/packages/contracts/workspace-portability.mjs +183 -211
- package/packages/evidence/artifact-integrity.mjs +8 -2
- package/packages/evidence/artifact-structure.mjs +105 -0
- package/packages/evidence/decision-fact.mjs +4 -1
- package/packages/evidence/domain-control-runtime.mjs +201 -33
- package/packages/evidence/domain-posture-context.mjs +79 -0
- package/packages/evidence/image-regions.mjs +56 -0
- package/packages/evidence/latest-observations.mjs +28 -0
- package/packages/evidence/lookup-target.mjs +104 -0
- package/packages/evidence/observation.mjs +16 -1
- package/packages/evidence/passphrase-encryption.mjs +44 -0
- package/packages/evidence/record-identity.mjs +72 -0
- package/packages/evidence/registry-dates.mjs +190 -0
- package/packages/evidence/retained-file.mjs +69 -0
- package/packages/evidence/review-age.mjs +14 -0
- package/packages/interchange/bagit.mjs +342 -0
- package/packages/interchange/bounded-zip-extraction.mjs +278 -0
- package/packages/interchange/crc32.mjs +17 -0
- package/packages/interchange/external-findings-import.mjs +92 -51
- package/packages/interchange/web-capture-import.mjs +382 -0
- package/packages/investigation/bulk-mail-exposure.mjs +2 -1
- package/packages/investigation/investigation-bagit.mjs +14 -0
- package/packages/investigation/investigation-capsule.mjs +33 -5
- package/packages/investigation/investigation-manifest.mjs +200 -0
- package/packages/investigation/investigation-package-crypto.mjs +98 -0
- package/packages/investigation/investigation-package.mjs +200 -0
- package/packages/investigation/lookup-asset-graph-inputs.mjs +38 -0
- package/packages/investigation/lookup-asset-graph.mjs +193 -165
- package/packages/investigation/lookup-claim-readiness.mjs +18 -0
- package/packages/investigation/lookup-investigation-brief.mjs +3 -3
- package/packages/investigation/lookup-task-guidance.mjs +58 -0
- package/packages/monitoring/analyst-review-state.mjs +38 -90
- package/packages/workspace/brand-profile-model.mjs +276 -22
- package/packages/workspace/bulk-columns.mjs +17 -0
- package/packages/workspace/bulk-review-model.mjs +23 -11
- package/packages/workspace/bulk-session-model.mjs +100 -24
- package/packages/workspace/bulk-sort.mjs +1 -0
- package/packages/workspace/case-views.mjs +102 -0
- package/packages/workspace/detection-rule-model.mjs +70 -22
- package/packages/workspace/hostile-input.mjs +29 -8
- package/packages/workspace/investigation-template-model.mjs +19 -4
- package/packages/workspace/page-baseline.mjs +18 -15
- package/packages/workspace/relationship-observation-model.mjs +41 -23
- package/packages/workspace/watchlist-history.mjs +2 -2
- package/packages/workspace/watchlist-store.mjs +8 -2
- package/packages/workspace/website-snapshot-model.mjs +164 -26
- package/packages/workspace/workspace-archive-crypto.mjs +41 -61
- package/packages/workspace/workspace-archive.mjs +87 -21
- package/third-party-notices.txt +29 -2
- package/cli/evidence-command-arguments.mjs +0 -156
- package/packages/investigation/bulk-review-export.mjs +0 -63
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import { exactKeys, requireBoundedString, requireDomainName, requireIsoTimestamp, requireRecord, } from "./bounded-contract-normalizers.mjs";
|
|
2
2
|
import { DOMAIN_ASSURANCE_INPUT_SCHEMA, buildDomainAssurance, } from "./domain-assurance.mjs";
|
|
3
|
-
import { DOMAIN_CHANGE_INPUT_SCHEMA, reviewDomainChange, } from "./domain-change-review.mjs";
|
|
3
|
+
import { DOMAIN_CHANGE_INPUT_SCHEMA, DOMAIN_CHANGE_REVIEW_VERSION, reviewDomainChange, } from "./domain-change-review.mjs";
|
|
4
4
|
import { SORTED_JSON_V2, sha256ArtifactDigestV2 } from "../packages/evidence/artifact-integrity.mjs";
|
|
5
5
|
export const DOMAIN_CHANGE_PACKET_INPUT_SCHEMA = 'whoisleuth.domain-change-packet.input';
|
|
6
6
|
export const DOMAIN_CHANGE_PACKET_SCHEMA = 'whoisleuth.domain-change-packet';
|
|
7
7
|
export const DOMAIN_CHANGE_PACKET_INPUT_VERSION = 1;
|
|
8
|
-
export const DOMAIN_CHANGE_PACKET_VERSION =
|
|
8
|
+
export const DOMAIN_CHANGE_PACKET_VERSION = 3;
|
|
9
|
+
export const DOMAIN_CHANGE_PACKET_REVIEW_VERSIONS = Object.freeze({
|
|
10
|
+
2: 1,
|
|
11
|
+
[DOMAIN_CHANGE_PACKET_VERSION]: DOMAIN_CHANGE_REVIEW_VERSION,
|
|
12
|
+
});
|
|
13
|
+
export const SUPPORTED_DOMAIN_CHANGE_PACKET_VERSIONS = Object.freeze(Object.keys(DOMAIN_CHANGE_PACKET_REVIEW_VERSIONS).map(Number));
|
|
9
14
|
export const MAX_DOMAIN_CHANGE_PACKET_INPUT_BYTES = 6 * 1024 * 1024;
|
|
10
15
|
const ROOT_KEYS = new Set([
|
|
11
16
|
'schema',
|
|
@@ -38,23 +43,50 @@ function changeSummary(before, after) {
|
|
|
38
43
|
const beforeRows = rows(before);
|
|
39
44
|
const afterRows = rows(after);
|
|
40
45
|
const keys = [...new Set([...beforeRows.keys(), ...afterRows.keys()])].sort();
|
|
41
|
-
|
|
46
|
+
const authorityCollectionComplete = (review) => {
|
|
47
|
+
const representative = review.authoritativeRecordMatrix[0];
|
|
48
|
+
return Boolean(representative
|
|
49
|
+
&& representative.observations.length >= 2
|
|
50
|
+
&& representative.observations.every((item) => item.state === 'observed'));
|
|
51
|
+
};
|
|
52
|
+
const rowEvidence = (review, row) => {
|
|
53
|
+
if (!row)
|
|
54
|
+
return Object.freeze({
|
|
55
|
+
state: authorityCollectionComplete(review) ? 'complete' : 'unavailable',
|
|
56
|
+
values: Object.freeze([]),
|
|
57
|
+
});
|
|
58
|
+
if (row.observations.some((item) => item.state !== 'observed')) {
|
|
59
|
+
return Object.freeze({ state: 'partial', values: Object.freeze([]) });
|
|
60
|
+
}
|
|
61
|
+
if (row.state === 'different')
|
|
62
|
+
return Object.freeze({ state: 'inconsistent', values: Object.freeze([]) });
|
|
63
|
+
if (row.state !== 'aligned')
|
|
64
|
+
return Object.freeze({ state: 'insufficient', values: Object.freeze([]) });
|
|
65
|
+
return Object.freeze({
|
|
66
|
+
state: 'complete',
|
|
67
|
+
values: Object.freeze([...new Set(row.observations.flatMap((item) => item.values))].sort()),
|
|
68
|
+
});
|
|
69
|
+
};
|
|
70
|
+
const changed = [];
|
|
71
|
+
for (const key of keys.slice(0, 500)) {
|
|
42
72
|
const left = beforeRows.get(key);
|
|
43
73
|
const right = afterRows.get(key);
|
|
44
|
-
const leftValues = left?.observations.flatMap((item) => item.values) ?? [];
|
|
45
|
-
const rightValues = right?.observations.flatMap((item) => item.values) ?? [];
|
|
46
|
-
const beforeValues = [...new Set(leftValues)].sort();
|
|
47
|
-
const afterValues = [...new Set(rightValues)].sort();
|
|
48
|
-
if (JSON.stringify(beforeValues) === JSON.stringify(afterValues))
|
|
49
|
-
return [];
|
|
50
74
|
const [owner, type] = key.split('\u0000');
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
75
|
+
const beforeEvidence = rowEvidence(before, left);
|
|
76
|
+
const afterEvidence = rowEvidence(after, right);
|
|
77
|
+
if (beforeEvidence.state !== 'complete' || afterEvidence.state !== 'complete') {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
if (JSON.stringify(beforeEvidence.values) === JSON.stringify(afterEvidence.values))
|
|
81
|
+
continue;
|
|
82
|
+
changed.push(Object.freeze({
|
|
83
|
+
owner: owner ?? '',
|
|
84
|
+
type: type ?? '',
|
|
85
|
+
beforeValues: beforeEvidence.values,
|
|
86
|
+
afterValues: afterEvidence.values,
|
|
87
|
+
}));
|
|
88
|
+
}
|
|
89
|
+
return Object.freeze(changed);
|
|
58
90
|
}
|
|
59
91
|
export async function buildDomainChangePacket(inputRaw, generatedAtValue = new Date().toISOString()) {
|
|
60
92
|
const input = record(inputRaw, 'Domain change packet input');
|
|
@@ -99,6 +131,7 @@ export async function buildDomainChangePacket(inputRaw, generatedAtValue = new D
|
|
|
99
131
|
limitations: Object.freeze([
|
|
100
132
|
'This packet is assembled only from analyst-supplied observations and planning metadata and makes no network request or configuration change.',
|
|
101
133
|
'A ready result means the supplied bounded checks passed; it does not prove control, propagation completion, successful recovery, or absence of unobserved dependencies.',
|
|
134
|
+
'Authoritative record-set changes are reported only when both sides contain complete consistent observations; gate reasons describe incomplete comparisons.',
|
|
102
135
|
'The integrity digest detects later changes to this packet but does not authenticate its author. Use a separately managed signing key when signer authentication is required.',
|
|
103
136
|
]),
|
|
104
137
|
});
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { exactKeys, requireBoundedString, requireDomainName, requireIsoTimestamp, requireRecord, } from "./bounded-contract-normalizers.mjs";
|
|
2
2
|
import { normaliseRdata } from "./zone-intent-review.mjs";
|
|
3
3
|
export const DOMAIN_CHANGE_INPUT_SCHEMA = 'whoisleuth.domain-change.input';
|
|
4
|
+
export const DOMAIN_CHANGE_INPUT_VERSION = 1;
|
|
4
5
|
export const DOMAIN_CHANGE_REVIEW_SCHEMA = 'whoisleuth.domain-change.review';
|
|
5
|
-
export const DOMAIN_CHANGE_REVIEW_VERSION =
|
|
6
|
+
export const DOMAIN_CHANGE_REVIEW_VERSION = 2;
|
|
6
7
|
export const MAX_DOMAIN_CHANGE_VANTAGES = 16;
|
|
7
8
|
export const MAX_DOMAIN_CHANGE_RECORDS = 500;
|
|
8
9
|
const ROOT_KEYS = new Set(['schema', 'version', 'domain', 'authoritySnapshots', 'resolverSnapshots', 'acmeDependencies', 'certificate', 'hsts']);
|
|
@@ -89,6 +90,9 @@ function normaliseSnapshots(value, apex, label) {
|
|
|
89
90
|
throw new TypeError(`${label} labels must be unique.`);
|
|
90
91
|
return Object.freeze(snapshots);
|
|
91
92
|
}
|
|
93
|
+
function snapshotProvenance(snapshot) {
|
|
94
|
+
return Object.freeze({ label: snapshot.label, source: snapshot.source, state: snapshot.state, observedAt: snapshot.observedAt });
|
|
95
|
+
}
|
|
92
96
|
function recordMatrix(snapshots) {
|
|
93
97
|
const keys = [...new Set(snapshots.flatMap((snapshot) => snapshot.records.map((item) => `${item.owner}\u0000${item.type}`)))].sort();
|
|
94
98
|
return Object.freeze(keys.map((key) => {
|
|
@@ -97,9 +101,7 @@ function recordMatrix(snapshots) {
|
|
|
97
101
|
const matches = snapshot.records.filter((item) => item.owner === recordOwner && item.type === type);
|
|
98
102
|
const ttls = matches.map((item) => item.ttl).filter((ttl) => ttl !== null);
|
|
99
103
|
return Object.freeze({
|
|
100
|
-
|
|
101
|
-
source: snapshot.source,
|
|
102
|
-
state: snapshot.state,
|
|
104
|
+
...snapshotProvenance(snapshot),
|
|
103
105
|
values: Object.freeze([...new Set(matches.map((item) => item.value))].sort()),
|
|
104
106
|
ttlRange: ttls.length ? Object.freeze({
|
|
105
107
|
minimum: Math.min(...ttls),
|
|
@@ -200,7 +202,7 @@ function normaliseCertificate(value) {
|
|
|
200
202
|
}
|
|
201
203
|
function reviewCertificate(certificate) {
|
|
202
204
|
if (!certificate)
|
|
203
|
-
return Object.freeze({ state: 'not_supplied', continuity: 'unknown', findings: Object.freeze([]) });
|
|
205
|
+
return Object.freeze({ state: 'not_supplied', observedAt: null, continuity: 'unknown', findings: Object.freeze([]) });
|
|
204
206
|
const continuity = !certificate.currentSpkiSha256 || !certificate.plannedSpkiSha256
|
|
205
207
|
? 'unknown'
|
|
206
208
|
: certificate.currentSpkiSha256 === certificate.plannedSpkiSha256 ? 'retained' : 'changes';
|
|
@@ -210,7 +212,7 @@ function reviewCertificate(certificate) {
|
|
|
210
212
|
...(certificate.embeddedSctCount === 0
|
|
211
213
|
? ['No embedded certificate-transparency timestamp was observed; this does not establish that the certificate was not logged by another mechanism.'] : []),
|
|
212
214
|
];
|
|
213
|
-
return Object.freeze({ state: certificate.state, continuity, findings: Object.freeze(findings) });
|
|
215
|
+
return Object.freeze({ state: certificate.state, observedAt: certificate.observedAt, continuity, findings: Object.freeze(findings) });
|
|
214
216
|
}
|
|
215
217
|
function normaliseHsts(value) {
|
|
216
218
|
if (value === null || value === undefined)
|
|
@@ -236,8 +238,8 @@ function serviceInventory(snapshots) {
|
|
|
236
238
|
}
|
|
237
239
|
export function reviewDomainChange(inputRaw, generatedAtValue = new Date().toISOString()) {
|
|
238
240
|
const input = requireRecord(inputRaw, 'Domain change input');
|
|
239
|
-
if (input.schema !== DOMAIN_CHANGE_INPUT_SCHEMA || input.version !==
|
|
240
|
-
throw new TypeError(`Domain change input must use ${DOMAIN_CHANGE_INPUT_SCHEMA} version
|
|
241
|
+
if (input.schema !== DOMAIN_CHANGE_INPUT_SCHEMA || input.version !== DOMAIN_CHANGE_INPUT_VERSION)
|
|
242
|
+
throw new TypeError(`Domain change input must use ${DOMAIN_CHANGE_INPUT_SCHEMA} version ${DOMAIN_CHANGE_INPUT_VERSION}.`);
|
|
241
243
|
exactKeys(input, ROOT_KEYS, 'Domain change input');
|
|
242
244
|
const apex = domain(input.domain, 'domain');
|
|
243
245
|
const authoritySnapshots = normaliseSnapshots(input.authoritySnapshots ?? [], apex, 'authoritySnapshots');
|
|
@@ -285,6 +287,10 @@ export function reviewDomainChange(inputRaw, generatedAtValue = new Date().toISO
|
|
|
285
287
|
generatedAt: timestamp(generatedAtValue, 'generatedAt'),
|
|
286
288
|
domain: apex,
|
|
287
289
|
state: reviewRequired ? 'review' : 'ready',
|
|
290
|
+
sourceObservations: Object.freeze({
|
|
291
|
+
authorities: Object.freeze(authoritySnapshots.map(snapshotProvenance)),
|
|
292
|
+
resolvers: Object.freeze(resolverSnapshots.map(snapshotProvenance)),
|
|
293
|
+
}),
|
|
288
294
|
authoritativeRecordMatrix: authorityMatrix,
|
|
289
295
|
resolverDivergenceMatrix: resolverMatrix,
|
|
290
296
|
dnssecAutomation: reviewDnssecAutomation(authorityMatrix),
|