@emilia-protocol/gate 0.10.0 → 0.13.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/CHANGELOG.md +91 -0
- package/README.md +272 -0
- package/action-control-manifest.js +3 -268
- package/action-escrow-custodian.js +4 -0
- package/action-escrow-evidence.js +4 -0
- package/action-escrow-package.js +4 -0
- package/action-escrow-postgres.js +4 -0
- package/action-escrow-state.js +4 -0
- package/action-escrow-verifiers.js +4 -0
- package/action-escrow.js +4 -0
- package/action-packs.js +3 -140
- package/adapters/_kit.js +3 -104
- package/adapters/aws.js +3 -108
- package/adapters/cloudflare.js +3 -54
- package/adapters/gcp.js +3 -70
- package/adapters/github.js +3 -109
- package/adapters/jira.js +3 -55
- package/adapters/k8s.js +3 -70
- package/adapters/linear.js +3 -55
- package/adapters/salesforce.js +3 -55
- package/adapters/stripe.js +3 -81
- package/adapters/supabase.js +3 -121
- package/adapters/terraform.js +3 -59
- package/adapters/vercel.js +3 -84
- package/aec-execution.js +3 -312
- package/breakglass.js +3 -582
- package/capability-receipt.js +4 -0
- package/cf1-conformance.js +3 -106
- package/challenge-store.js +3 -69
- package/control-plane.js +3 -340
- package/coverage.js +3 -721
- package/demo.mjs +1 -1
- package/deployment-attestation.js +3 -247
- package/dist/action-control-manifest.d.ts +82 -0
- package/dist/action-control-manifest.d.ts.map +1 -0
- package/dist/action-control-manifest.js +422 -0
- package/dist/action-control-manifest.js.map +1 -0
- package/dist/action-escrow-custodian.d.ts +74 -0
- package/dist/action-escrow-custodian.d.ts.map +1 -0
- package/dist/action-escrow-custodian.js +363 -0
- package/dist/action-escrow-custodian.js.map +1 -0
- package/dist/action-escrow-evidence.d.ts +130 -0
- package/dist/action-escrow-evidence.d.ts.map +1 -0
- package/dist/action-escrow-evidence.js +1012 -0
- package/dist/action-escrow-evidence.js.map +1 -0
- package/dist/action-escrow-package.d.ts +10 -0
- package/dist/action-escrow-package.d.ts.map +1 -0
- package/dist/action-escrow-package.js +1583 -0
- package/dist/action-escrow-package.js.map +1 -0
- package/dist/action-escrow-postgres.d.ts +62 -0
- package/dist/action-escrow-postgres.d.ts.map +1 -0
- package/dist/action-escrow-postgres.js +339 -0
- package/dist/action-escrow-postgres.js.map +1 -0
- package/dist/action-escrow-state.d.ts +141 -0
- package/dist/action-escrow-state.d.ts.map +1 -0
- package/dist/action-escrow-state.js +413 -0
- package/dist/action-escrow-state.js.map +1 -0
- package/dist/action-escrow-verifiers.d.ts +65 -0
- package/dist/action-escrow-verifiers.d.ts.map +1 -0
- package/dist/action-escrow-verifiers.js +421 -0
- package/dist/action-escrow-verifiers.js.map +1 -0
- package/dist/action-escrow.d.ts +112 -0
- package/dist/action-escrow.d.ts.map +1 -0
- package/dist/action-escrow.js +2661 -0
- package/dist/action-escrow.js.map +1 -0
- package/dist/action-packs.d.ts +54 -0
- package/dist/action-packs.d.ts.map +1 -0
- package/dist/action-packs.js +143 -0
- package/dist/action-packs.js.map +1 -0
- package/dist/adapters/_kit.d.ts +50 -0
- package/dist/adapters/_kit.d.ts.map +1 -0
- package/dist/adapters/_kit.js +98 -0
- package/dist/adapters/_kit.js.map +1 -0
- package/dist/adapters/aws.d.ts +158 -0
- package/dist/adapters/aws.d.ts.map +1 -0
- package/dist/adapters/aws.js +136 -0
- package/dist/adapters/aws.js.map +1 -0
- package/dist/adapters/cloudflare.d.ts +116 -0
- package/dist/adapters/cloudflare.d.ts.map +1 -0
- package/dist/adapters/cloudflare.js +75 -0
- package/dist/adapters/cloudflare.js.map +1 -0
- package/dist/adapters/gcp.d.ts +139 -0
- package/dist/adapters/gcp.d.ts.map +1 -0
- package/dist/adapters/gcp.js +69 -0
- package/dist/adapters/gcp.js.map +1 -0
- package/dist/adapters/github.d.ts +123 -0
- package/dist/adapters/github.d.ts.map +1 -0
- package/dist/adapters/github.js +105 -0
- package/dist/adapters/github.js.map +1 -0
- package/dist/adapters/jira.d.ts +109 -0
- package/dist/adapters/jira.d.ts.map +1 -0
- package/dist/adapters/jira.js +54 -0
- package/dist/adapters/jira.js.map +1 -0
- package/dist/adapters/k8s.d.ts +139 -0
- package/dist/adapters/k8s.d.ts.map +1 -0
- package/dist/adapters/k8s.js +69 -0
- package/dist/adapters/k8s.js.map +1 -0
- package/dist/adapters/linear.d.ts +109 -0
- package/dist/adapters/linear.d.ts.map +1 -0
- package/dist/adapters/linear.js +54 -0
- package/dist/adapters/linear.js.map +1 -0
- package/dist/adapters/salesforce.d.ts +109 -0
- package/dist/adapters/salesforce.d.ts.map +1 -0
- package/dist/adapters/salesforce.js +54 -0
- package/dist/adapters/salesforce.js.map +1 -0
- package/dist/adapters/stripe.d.ts +116 -0
- package/dist/adapters/stripe.d.ts.map +1 -0
- package/dist/adapters/stripe.js +77 -0
- package/dist/adapters/stripe.js.map +1 -0
- package/dist/adapters/supabase.d.ts +127 -0
- package/dist/adapters/supabase.d.ts.map +1 -0
- package/dist/adapters/supabase.js +112 -0
- package/dist/adapters/supabase.js.map +1 -0
- package/dist/adapters/terraform.d.ts +109 -0
- package/dist/adapters/terraform.d.ts.map +1 -0
- package/dist/adapters/terraform.js +58 -0
- package/dist/adapters/terraform.js.map +1 -0
- package/dist/adapters/vercel.d.ts +114 -0
- package/dist/adapters/vercel.d.ts.map +1 -0
- package/dist/adapters/vercel.js +81 -0
- package/dist/adapters/vercel.js.map +1 -0
- package/dist/aec-execution.d.ts +107 -0
- package/dist/aec-execution.d.ts.map +1 -0
- package/dist/aec-execution.js +334 -0
- package/dist/aec-execution.js.map +1 -0
- package/dist/breakglass.d.ts +205 -0
- package/dist/breakglass.d.ts.map +1 -0
- package/dist/breakglass.js +627 -0
- package/dist/breakglass.js.map +1 -0
- package/dist/capability-receipt.d.ts +601 -0
- package/dist/capability-receipt.d.ts.map +1 -0
- package/dist/capability-receipt.js +1177 -0
- package/dist/capability-receipt.js.map +1 -0
- package/dist/cf1-conformance.d.ts +83 -0
- package/dist/cf1-conformance.d.ts.map +1 -0
- package/dist/cf1-conformance.js +94 -0
- package/dist/cf1-conformance.js.map +1 -0
- package/dist/challenge-store.d.ts +20 -0
- package/dist/challenge-store.d.ts.map +1 -0
- package/dist/challenge-store.js +62 -0
- package/dist/challenge-store.js.map +1 -0
- package/dist/control-plane.d.ts +136 -0
- package/dist/control-plane.d.ts.map +1 -0
- package/dist/control-plane.js +349 -0
- package/dist/control-plane.js.map +1 -0
- package/dist/coverage.d.ts +156 -0
- package/dist/coverage.d.ts.map +1 -0
- package/dist/coverage.js +768 -0
- package/dist/coverage.js.map +1 -0
- package/dist/deployment-attestation.d.ts +93 -0
- package/dist/deployment-attestation.d.ts.map +1 -0
- package/dist/deployment-attestation.js +262 -0
- package/dist/deployment-attestation.js.map +1 -0
- package/dist/eg1-conformance.d.ts +286 -0
- package/dist/eg1-conformance.d.ts.map +1 -0
- package/dist/eg1-conformance.js +379 -0
- package/dist/eg1-conformance.js.map +1 -0
- package/dist/enterprise.d.ts +88 -0
- package/dist/enterprise.d.ts.map +1 -0
- package/dist/enterprise.js +194 -0
- package/dist/enterprise.js.map +1 -0
- package/dist/evidence-postgres.d.ts +123 -0
- package/dist/evidence-postgres.d.ts.map +1 -0
- package/dist/evidence-postgres.js +343 -0
- package/dist/evidence-postgres.js.map +1 -0
- package/dist/evidence.d.ts +113 -0
- package/dist/evidence.d.ts.map +1 -0
- package/dist/evidence.js +369 -0
- package/dist/evidence.js.map +1 -0
- package/dist/execution-binding.d.ts +49 -0
- package/dist/execution-binding.d.ts.map +1 -0
- package/dist/execution-binding.js +243 -0
- package/dist/execution-binding.js.map +1 -0
- package/dist/formal-runtime-map.d.ts +42 -0
- package/dist/formal-runtime-map.d.ts.map +1 -0
- package/dist/formal-runtime-map.js +23 -0
- package/dist/formal-runtime-map.js.map +1 -0
- package/dist/index.d.ts +1002 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1736 -0
- package/dist/index.js.map +1 -0
- package/dist/key-registry.d.ts +60 -0
- package/dist/key-registry.d.ts.map +1 -0
- package/dist/key-registry.js +144 -0
- package/dist/key-registry.js.map +1 -0
- package/dist/mcp.d.ts +53 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +112 -0
- package/dist/mcp.js.map +1 -0
- package/dist/metering.d.ts +80 -0
- package/dist/metering.d.ts.map +1 -0
- package/dist/metering.js +227 -0
- package/dist/metering.js.map +1 -0
- package/dist/metrics.d.ts +68 -0
- package/dist/metrics.d.ts.map +1 -0
- package/dist/metrics.js +242 -0
- package/dist/metrics.js.map +1 -0
- package/dist/network-witness.d.ts +167 -0
- package/dist/network-witness.d.ts.map +1 -0
- package/dist/network-witness.js +520 -0
- package/dist/network-witness.js.map +1 -0
- package/dist/protocol-state.d.ts +141 -0
- package/dist/protocol-state.d.ts.map +1 -0
- package/dist/protocol-state.js +106 -0
- package/dist/protocol-state.js.map +1 -0
- package/dist/receipt-program.d.ts +59 -0
- package/dist/receipt-program.d.ts.map +1 -0
- package/dist/receipt-program.js +1053 -0
- package/dist/receipt-program.js.map +1 -0
- package/dist/reliance-kernel.d.ts +66 -0
- package/dist/reliance-kernel.d.ts.map +1 -0
- package/dist/reliance-kernel.js +103 -0
- package/dist/reliance-kernel.js.map +1 -0
- package/dist/reliance-packet.d.ts +67 -0
- package/dist/reliance-packet.d.ts.map +1 -0
- package/dist/reliance-packet.js +176 -0
- package/dist/reliance-packet.js.map +1 -0
- package/dist/remedy-program-postgres.d.ts +37 -0
- package/dist/remedy-program-postgres.d.ts.map +1 -0
- package/dist/remedy-program-postgres.js +291 -0
- package/dist/remedy-program-postgres.js.map +1 -0
- package/dist/remedy-program-receipt.d.ts +97 -0
- package/dist/remedy-program-receipt.d.ts.map +1 -0
- package/dist/remedy-program-receipt.js +817 -0
- package/dist/remedy-program-receipt.js.map +1 -0
- package/dist/remedy-program.d.ts +76 -0
- package/dist/remedy-program.d.ts.map +1 -0
- package/dist/remedy-program.js +1346 -0
- package/dist/remedy-program.js.map +1 -0
- package/dist/reports/art14.d.ts +101 -0
- package/dist/reports/art14.d.ts.map +1 -0
- package/dist/reports/art14.js +340 -0
- package/dist/reports/art14.js.map +1 -0
- package/dist/reports/assurance-package.d.ts +197 -0
- package/dist/reports/assurance-package.d.ts.map +1 -0
- package/dist/reports/assurance-package.js +313 -0
- package/dist/reports/assurance-package.js.map +1 -0
- package/dist/reports/auditor-workpaper.d.ts +194 -0
- package/dist/reports/auditor-workpaper.d.ts.map +1 -0
- package/dist/reports/auditor-workpaper.js +545 -0
- package/dist/reports/auditor-workpaper.js.map +1 -0
- package/dist/reports/external-verification.d.ts +76 -0
- package/dist/reports/external-verification.d.ts.map +1 -0
- package/dist/reports/external-verification.js +209 -0
- package/dist/reports/external-verification.js.map +1 -0
- package/dist/reports/reperform.d.ts +122 -0
- package/dist/reports/reperform.d.ts.map +1 -0
- package/dist/reports/reperform.js +432 -0
- package/dist/reports/reperform.js.map +1 -0
- package/dist/reports/underwriter.d.ts +127 -0
- package/dist/reports/underwriter.d.ts.map +1 -0
- package/dist/reports/underwriter.js +348 -0
- package/dist/reports/underwriter.js.map +1 -0
- package/dist/retention.d.ts +88 -0
- package/dist/retention.d.ts.map +1 -0
- package/dist/retention.js +90 -0
- package/dist/retention.js.map +1 -0
- package/dist/roster.d.ts +113 -0
- package/dist/roster.d.ts.map +1 -0
- package/dist/roster.js +261 -0
- package/dist/roster.js.map +1 -0
- package/dist/runtime-monitor.d.ts +132 -0
- package/dist/runtime-monitor.d.ts.map +1 -0
- package/dist/runtime-monitor.js +197 -0
- package/dist/runtime-monitor.js.map +1 -0
- package/dist/settlement.d.ts +68 -0
- package/dist/settlement.d.ts.map +1 -0
- package/dist/settlement.js +306 -0
- package/dist/settlement.js.map +1 -0
- package/dist/siem.d.ts +261 -0
- package/dist/siem.d.ts.map +1 -0
- package/dist/siem.js +247 -0
- package/dist/siem.js.map +1 -0
- package/dist/store-postgres.d.ts +107 -0
- package/dist/store-postgres.d.ts.map +1 -0
- package/dist/store-postgres.js +152 -0
- package/dist/store-postgres.js.map +1 -0
- package/dist/store.d.ts +95 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +202 -0
- package/dist/store.js.map +1 -0
- package/dist/strict-json.d.ts +14 -0
- package/dist/strict-json.d.ts.map +1 -0
- package/dist/strict-json.js +132 -0
- package/dist/strict-json.js.map +1 -0
- package/dist/trust-program-adapters.d.ts +122 -0
- package/dist/trust-program-adapters.d.ts.map +1 -0
- package/dist/trust-program-adapters.js +802 -0
- package/dist/trust-program-adapters.js.map +1 -0
- package/dist/trust-program-postgres.d.ts +41 -0
- package/dist/trust-program-postgres.d.ts.map +1 -0
- package/dist/trust-program-postgres.js +346 -0
- package/dist/trust-program-postgres.js.map +1 -0
- package/dist/trust-program-revocation.d.ts +206 -0
- package/dist/trust-program-revocation.d.ts.map +1 -0
- package/dist/trust-program-revocation.js +600 -0
- package/dist/trust-program-revocation.js.map +1 -0
- package/dist/trust-program.d.ts +197 -0
- package/dist/trust-program.d.ts.map +1 -0
- package/dist/trust-program.js +1351 -0
- package/dist/trust-program.js.map +1 -0
- package/dist/witness-postgres.d.ts +43 -0
- package/dist/witness-postgres.d.ts.map +1 -0
- package/dist/witness-postgres.js +92 -0
- package/dist/witness-postgres.js.map +1 -0
- package/dist/zk-range-proof.d.ts +78 -0
- package/dist/zk-range-proof.d.ts.map +1 -0
- package/dist/zk-range-proof.js +228 -0
- package/dist/zk-range-proof.js.map +1 -0
- package/eg1-conformance.js +3 -404
- package/enterprise.js +3 -180
- package/ep-assure.mjs +1 -0
- package/evidence-postgres.js +3 -356
- package/evidence.js +4 -360
- package/execution-binding.js +3 -212
- package/formal-runtime-map.js +4 -0
- package/index.js +4 -1249
- package/key-registry.js +3 -134
- package/mcp.js +3 -109
- package/metering.js +3 -226
- package/metrics.js +3 -231
- package/network-witness.js +3 -499
- package/package.json +47 -4
- package/receipt-program.js +4 -0
- package/reliance-kernel.js +3 -112
- package/reliance-packet.js +3 -175
- package/remedy-program-postgres.js +4 -0
- package/remedy-program-receipt.js +4 -0
- package/remedy-program.js +4 -0
- package/reports/art14.js +0 -0
- package/reports/assurance-package.js +2 -312
- package/reports/auditor-workpaper.js +3 -537
- package/reports/external-verification.js +3 -222
- package/reports/reperform.js +3 -424
- package/reports/underwriter.js +3 -339
- package/retention.js +3 -84
- package/roster.js +3 -264
- package/runtime-monitor.js +4 -0
- package/settlement.js +3 -299
- package/siem.js +3 -235
- package/src/action-control-manifest.ts +424 -0
- package/src/action-escrow-custodian.ts +427 -0
- package/src/action-escrow-evidence.ts +1178 -0
- package/src/action-escrow-package.ts +1821 -0
- package/src/action-escrow-postgres.ts +366 -0
- package/src/action-escrow-state.ts +498 -0
- package/src/action-escrow-verifiers.ts +484 -0
- package/src/action-escrow.ts +3039 -0
- package/src/action-packs.ts +170 -0
- package/src/adapters/_kit.ts +117 -0
- package/src/adapters/aws.ts +142 -0
- package/src/adapters/cloudflare.ts +78 -0
- package/src/adapters/gcp.ts +71 -0
- package/src/adapters/github.ts +110 -0
- package/src/adapters/jira.ts +56 -0
- package/src/adapters/k8s.ts +71 -0
- package/src/adapters/linear.ts +56 -0
- package/src/adapters/salesforce.ts +56 -0
- package/src/adapters/stripe.ts +82 -0
- package/src/adapters/supabase.ts +122 -0
- package/src/adapters/terraform.ts +60 -0
- package/src/adapters/vercel.ts +85 -0
- package/src/aec-execution.ts +354 -0
- package/src/breakglass.ts +647 -0
- package/src/capability-receipt.ts +1258 -0
- package/src/cf1-conformance.ts +120 -0
- package/src/challenge-store.ts +70 -0
- package/src/control-plane.ts +374 -0
- package/src/coverage.ts +832 -0
- package/src/deployment-attestation.ts +259 -0
- package/src/eg1-conformance.ts +471 -0
- package/src/enterprise.ts +195 -0
- package/src/evidence-postgres.ts +374 -0
- package/src/evidence.ts +367 -0
- package/src/execution-binding.ts +236 -0
- package/src/formal-runtime-map.ts +24 -0
- package/src/index.ts +2122 -0
- package/src/key-registry.ts +150 -0
- package/src/mcp.ts +120 -0
- package/src/metering.ts +237 -0
- package/src/metrics.ts +232 -0
- package/src/network-witness.ts +585 -0
- package/src/protocol-state.ts +143 -0
- package/src/protocol-state.typecheck.ts +94 -0
- package/src/receipt-program.ts +1105 -0
- package/src/reliance-kernel.ts +119 -0
- package/src/reliance-packet.ts +206 -0
- package/src/remedy-program-postgres.ts +367 -0
- package/src/remedy-program-receipt.ts +891 -0
- package/src/remedy-program.ts +1388 -0
- package/src/reports/art14.ts +361 -0
- package/src/reports/assurance-package.ts +330 -0
- package/src/reports/auditor-workpaper.ts +558 -0
- package/src/reports/external-verification.ts +232 -0
- package/src/reports/reperform.ts +441 -0
- package/src/reports/underwriter.ts +356 -0
- package/src/retention.ts +100 -0
- package/src/roster.ts +273 -0
- package/src/runtime-monitor.ts +217 -0
- package/src/settlement.ts +313 -0
- package/src/siem.ts +247 -0
- package/src/store-postgres.ts +167 -0
- package/src/store.ts +214 -0
- package/src/strict-json.ts +115 -0
- package/src/trust-program-adapters.ts +847 -0
- package/src/trust-program-postgres.ts +429 -0
- package/src/trust-program-revocation.ts +751 -0
- package/src/trust-program.ts +1460 -0
- package/src/witness-postgres.ts +106 -0
- package/src/zk-range-proof.ts +250 -0
- package/store-postgres.js +3 -161
- package/store.js +4 -198
- package/strict-json.js +3 -85
- package/trust-program-adapters.js +4 -0
- package/trust-program-postgres.js +4 -0
- package/trust-program-revocation.js +4 -0
- package/trust-program.js +4 -0
- package/witness-postgres.js +3 -96
- package/zk-range-proof.js +4 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
export declare const NETWORK_WITNESS_VERSION = "EP-GATE-NETWORK-WITNESS-v1";
|
|
2
|
+
export declare const NETWORK_WITNESS_ACCEPTANCE_VERSION = "EP-GATE-NETWORK-WITNESS-ACCEPTANCE-v1";
|
|
3
|
+
export declare const NETWORK_WITNESS_DOMAIN = "EP-GATE-NETWORK-WITNESS-v1\0";
|
|
4
|
+
export declare const NETWORK_WITNESS_EVENTS: readonly string[];
|
|
5
|
+
type NetworkWitnessChecks = {
|
|
6
|
+
shape: boolean;
|
|
7
|
+
pin: boolean;
|
|
8
|
+
signature: boolean;
|
|
9
|
+
action_binding: boolean;
|
|
10
|
+
freshness: boolean;
|
|
11
|
+
config_binding: boolean;
|
|
12
|
+
};
|
|
13
|
+
type NetworkWitnessVerifyFailure = {
|
|
14
|
+
verified: false;
|
|
15
|
+
accepted: false;
|
|
16
|
+
reason: string;
|
|
17
|
+
checks: NetworkWitnessChecks;
|
|
18
|
+
statement_digest?: undefined;
|
|
19
|
+
stream_id?: undefined;
|
|
20
|
+
sequence?: undefined;
|
|
21
|
+
action_digest?: undefined;
|
|
22
|
+
event?: undefined;
|
|
23
|
+
observed_at?: undefined;
|
|
24
|
+
witness_id?: undefined;
|
|
25
|
+
capture_point_id?: undefined;
|
|
26
|
+
limitation?: undefined;
|
|
27
|
+
};
|
|
28
|
+
type NetworkWitnessVerifySuccess = {
|
|
29
|
+
verified: true;
|
|
30
|
+
accepted: true;
|
|
31
|
+
reason: null;
|
|
32
|
+
statement_digest: string;
|
|
33
|
+
stream_id: string;
|
|
34
|
+
sequence: number;
|
|
35
|
+
action_digest: string;
|
|
36
|
+
event: string;
|
|
37
|
+
observed_at: string;
|
|
38
|
+
witness_id: string;
|
|
39
|
+
capture_point_id: string;
|
|
40
|
+
checks: NetworkWitnessChecks;
|
|
41
|
+
limitation: string;
|
|
42
|
+
};
|
|
43
|
+
type NetworkWitnessVerifyResult = NetworkWitnessVerifyFailure | NetworkWitnessVerifySuccess;
|
|
44
|
+
type NetworkWitnessVerifyOptions = {
|
|
45
|
+
pinnedWitnesses?: any[];
|
|
46
|
+
expectedActionDigest?: string;
|
|
47
|
+
expectedEvent?: string;
|
|
48
|
+
now?: number;
|
|
49
|
+
maxAgeSec?: number;
|
|
50
|
+
maxFutureSkewSec?: number;
|
|
51
|
+
};
|
|
52
|
+
type NetworkWitnessAcceptanceOptions = {
|
|
53
|
+
allowEphemeralStore?: boolean;
|
|
54
|
+
expectedStatementDigest?: string;
|
|
55
|
+
expectedActionDigest?: string;
|
|
56
|
+
expectedEvent?: string;
|
|
57
|
+
now?: number;
|
|
58
|
+
maxAgeSec?: number;
|
|
59
|
+
maxFutureSkewSec?: number;
|
|
60
|
+
};
|
|
61
|
+
interface NetworkWitnessSequenceStore {
|
|
62
|
+
durable: boolean;
|
|
63
|
+
advance: (streamId: string, sequence: number, statementDigest: string) => Promise<{
|
|
64
|
+
accepted: boolean;
|
|
65
|
+
reason: string | null;
|
|
66
|
+
}>;
|
|
67
|
+
}
|
|
68
|
+
type NetworkWitnessAcceptOptions = NetworkWitnessVerifyOptions & {
|
|
69
|
+
sequenceStore?: NetworkWitnessSequenceStore;
|
|
70
|
+
allowEphemeralStore?: boolean;
|
|
71
|
+
};
|
|
72
|
+
export declare function networkWitnessDigest(statement: any): string;
|
|
73
|
+
/** Duplicate-key-safe parser for an untrusted serialized witness artifact. */
|
|
74
|
+
export declare function parseNetworkWitnessStatement(raw: any, { maxBytes }?: {
|
|
75
|
+
maxBytes?: number | undefined;
|
|
76
|
+
}): any;
|
|
77
|
+
/** Create a signed observation. The public key is intentionally not embedded. */
|
|
78
|
+
export declare function signNetworkWitnessStatement(input: any, privateKey: any): Readonly<{
|
|
79
|
+
signature: Readonly<{
|
|
80
|
+
algorithm: "Ed25519";
|
|
81
|
+
key_id: any;
|
|
82
|
+
statement_digest: string;
|
|
83
|
+
signature_b64u: string;
|
|
84
|
+
}>;
|
|
85
|
+
'@version': string;
|
|
86
|
+
witness: {
|
|
87
|
+
id: any;
|
|
88
|
+
key_id: any;
|
|
89
|
+
capture_point_id: any;
|
|
90
|
+
};
|
|
91
|
+
observation: {
|
|
92
|
+
byte_count?: any;
|
|
93
|
+
flow_digest?: any;
|
|
94
|
+
sequence: any;
|
|
95
|
+
observed_at: any;
|
|
96
|
+
event: any;
|
|
97
|
+
direction: any;
|
|
98
|
+
action_digest: any;
|
|
99
|
+
};
|
|
100
|
+
deployment: {
|
|
101
|
+
attestation_ref?: any;
|
|
102
|
+
config_digest: any;
|
|
103
|
+
};
|
|
104
|
+
privacy: {
|
|
105
|
+
payload_captured: boolean;
|
|
106
|
+
};
|
|
107
|
+
limitations: string[];
|
|
108
|
+
}>;
|
|
109
|
+
/**
|
|
110
|
+
* Offline signature and context verification. This function never throws on a
|
|
111
|
+
* presenter-controlled statement. Sequence consumption is a separate online
|
|
112
|
+
* operation performed by acceptNetworkWitnessStatement.
|
|
113
|
+
*/
|
|
114
|
+
export declare function verifyNetworkWitnessStatement(statement: any, options?: NetworkWitnessVerifyOptions): NetworkWitnessVerifyResult;
|
|
115
|
+
export declare function createMemoryWitnessSequenceStore(): {
|
|
116
|
+
durable: boolean;
|
|
117
|
+
advance(streamId: any, sequence: any, statementDigest: any): Promise<{
|
|
118
|
+
accepted: boolean;
|
|
119
|
+
reason: string;
|
|
120
|
+
} | {
|
|
121
|
+
accepted: boolean;
|
|
122
|
+
reason: null;
|
|
123
|
+
}>;
|
|
124
|
+
snapshot(): any[];
|
|
125
|
+
};
|
|
126
|
+
/**
|
|
127
|
+
* Validate an ingestion result supplied through a relying-party-trusted option.
|
|
128
|
+
* This does not authenticate presenter-controlled JSON; callers must never move
|
|
129
|
+
* an untrusted bundle field into this trust channel.
|
|
130
|
+
*/
|
|
131
|
+
export declare function validateTrustedNetworkWitnessAcceptance(result: any, options?: NetworkWitnessAcceptanceOptions): {
|
|
132
|
+
verified: boolean;
|
|
133
|
+
accepted: boolean;
|
|
134
|
+
consumed: boolean;
|
|
135
|
+
reason: string;
|
|
136
|
+
} | {
|
|
137
|
+
verified: boolean;
|
|
138
|
+
accepted: boolean;
|
|
139
|
+
consumed: boolean;
|
|
140
|
+
reason: null;
|
|
141
|
+
acceptance_version: string;
|
|
142
|
+
statement_digest: any;
|
|
143
|
+
stream_id: any;
|
|
144
|
+
sequence: any;
|
|
145
|
+
action_digest: any;
|
|
146
|
+
event: any;
|
|
147
|
+
observed_at: any;
|
|
148
|
+
witness_id: any;
|
|
149
|
+
capture_point_id: any;
|
|
150
|
+
sequence_store_durable: boolean;
|
|
151
|
+
};
|
|
152
|
+
/** Verify and atomically advance a witness stream for online ingestion. */
|
|
153
|
+
export declare function acceptNetworkWitnessStatement(statement: any, options?: NetworkWitnessAcceptOptions): Promise<any>;
|
|
154
|
+
declare const _default: {
|
|
155
|
+
NETWORK_WITNESS_VERSION: string;
|
|
156
|
+
NETWORK_WITNESS_ACCEPTANCE_VERSION: string;
|
|
157
|
+
NETWORK_WITNESS_EVENTS: readonly string[];
|
|
158
|
+
parseNetworkWitnessStatement: typeof parseNetworkWitnessStatement;
|
|
159
|
+
networkWitnessDigest: typeof networkWitnessDigest;
|
|
160
|
+
signNetworkWitnessStatement: typeof signNetworkWitnessStatement;
|
|
161
|
+
verifyNetworkWitnessStatement: typeof verifyNetworkWitnessStatement;
|
|
162
|
+
acceptNetworkWitnessStatement: typeof acceptNetworkWitnessStatement;
|
|
163
|
+
validateTrustedNetworkWitnessAcceptance: typeof validateTrustedNetworkWitnessAcceptance;
|
|
164
|
+
createMemoryWitnessSequenceStore: typeof createMemoryWitnessSequenceStore;
|
|
165
|
+
};
|
|
166
|
+
export default _default;
|
|
167
|
+
//# sourceMappingURL=network-witness.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"network-witness.d.ts","sourceRoot":"","sources":["../src/network-witness.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,520 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
/**
|
|
4
|
+
* Independent, privacy-minimized observation evidence for EMILIA Gate.
|
|
5
|
+
*
|
|
6
|
+
* A network witness is deliberately NOT an enforcement point. It can prove a
|
|
7
|
+
* pinned sensor observed bytes associated with an action digest at a named
|
|
8
|
+
* capture point. It cannot prove the action was authorized, blocked, executed,
|
|
9
|
+
* or physically completed. Keeping that boundary in the artifact prevents a
|
|
10
|
+
* passive TAP from being marketed as a firewall.
|
|
11
|
+
*/
|
|
12
|
+
import crypto from 'node:crypto';
|
|
13
|
+
import { canonicalize } from './execution-binding.js';
|
|
14
|
+
import { strictJsonGate } from './strict-json.js';
|
|
15
|
+
export const NETWORK_WITNESS_VERSION = 'EP-GATE-NETWORK-WITNESS-v1';
|
|
16
|
+
export const NETWORK_WITNESS_ACCEPTANCE_VERSION = 'EP-GATE-NETWORK-WITNESS-ACCEPTANCE-v1';
|
|
17
|
+
export const NETWORK_WITNESS_DOMAIN = `${NETWORK_WITNESS_VERSION}\0`;
|
|
18
|
+
export const NETWORK_WITNESS_EVENTS = Object.freeze([
|
|
19
|
+
'request_observed',
|
|
20
|
+
'response_observed',
|
|
21
|
+
'effect_observed',
|
|
22
|
+
]);
|
|
23
|
+
const DIGEST_RE = /^sha256:[0-9a-f]{64}$/;
|
|
24
|
+
const DIRECTIONS = new Set(['ingress', 'egress', 'internal']);
|
|
25
|
+
const RFC3339 = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.(\d{1,9}))?Z$/;
|
|
26
|
+
function strictInstantMs(value) {
|
|
27
|
+
if (typeof value !== 'string')
|
|
28
|
+
return NaN;
|
|
29
|
+
const match = value.match(RFC3339);
|
|
30
|
+
if (!match)
|
|
31
|
+
return NaN;
|
|
32
|
+
const [, year, month, day, hour, minute, second] = match;
|
|
33
|
+
const base = new Date(0);
|
|
34
|
+
base.setUTCFullYear(Number(year), Number(month) - 1, Number(day));
|
|
35
|
+
base.setUTCHours(Number(hour), Number(minute), Number(second), 0);
|
|
36
|
+
if (base.toISOString().slice(0, 19) !== `${year}-${month}-${day}T${hour}:${minute}:${second}`)
|
|
37
|
+
return NaN;
|
|
38
|
+
const parsed = Date.parse(value);
|
|
39
|
+
return Number.isFinite(parsed) ? parsed : NaN;
|
|
40
|
+
}
|
|
41
|
+
function isPlainObject(value) {
|
|
42
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value))
|
|
43
|
+
return false;
|
|
44
|
+
const prototype = Object.getPrototypeOf(value);
|
|
45
|
+
return prototype === Object.prototype || prototype === null;
|
|
46
|
+
}
|
|
47
|
+
function exactKeys(value, allowed) {
|
|
48
|
+
return isPlainObject(value) && Object.keys(value).every((key) => allowed.has(key));
|
|
49
|
+
}
|
|
50
|
+
function nonEmptyString(value, max = 256) {
|
|
51
|
+
return typeof value === 'string' && value.length > 0 && value.length <= max && !/[\u0000-\u001f\u007f]/.test(value);
|
|
52
|
+
}
|
|
53
|
+
function digest(value) {
|
|
54
|
+
return typeof value === 'string' && DIGEST_RE.test(value);
|
|
55
|
+
}
|
|
56
|
+
function sha256(bytes) {
|
|
57
|
+
return crypto.createHash('sha256').update(bytes).digest('hex');
|
|
58
|
+
}
|
|
59
|
+
function decodeBase64Url(value, maxBytes) {
|
|
60
|
+
if (typeof value !== 'string' || value.length === 0 || !/^[A-Za-z0-9_-]+$/.test(value))
|
|
61
|
+
return null;
|
|
62
|
+
try {
|
|
63
|
+
const bytes = Buffer.from(value, 'base64url');
|
|
64
|
+
if (bytes.length === 0 || bytes.length > maxBytes || bytes.toString('base64url') !== value)
|
|
65
|
+
return null;
|
|
66
|
+
return bytes;
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function keyIdFor(key) {
|
|
73
|
+
const der = crypto.createPublicKey(key).export({ type: 'spki', format: 'der' });
|
|
74
|
+
return `ep:witness-key:sha256:${sha256(der).slice(0, 16)}`;
|
|
75
|
+
}
|
|
76
|
+
function signingBytes(body) {
|
|
77
|
+
return Buffer.from(NETWORK_WITNESS_DOMAIN + canonicalize(body), 'utf8');
|
|
78
|
+
}
|
|
79
|
+
function unsigned(statement) {
|
|
80
|
+
if (!isPlainObject(statement))
|
|
81
|
+
throw new TypeError('network witness statement must be an object');
|
|
82
|
+
const { signature: _signature, ...body } = statement;
|
|
83
|
+
return body;
|
|
84
|
+
}
|
|
85
|
+
export function networkWitnessDigest(statement) {
|
|
86
|
+
return `sha256:${sha256(signingBytes(unsigned(statement)))}`;
|
|
87
|
+
}
|
|
88
|
+
/** Duplicate-key-safe parser for an untrusted serialized witness artifact. */
|
|
89
|
+
export function parseNetworkWitnessStatement(raw, { maxBytes = 64 * 1024 } = {}) {
|
|
90
|
+
if (typeof raw !== 'string' || !Number.isSafeInteger(maxBytes) || maxBytes < 1
|
|
91
|
+
|| Buffer.byteLength(raw, 'utf8') > maxBytes)
|
|
92
|
+
return null;
|
|
93
|
+
const gated = strictJsonGate(raw);
|
|
94
|
+
if (!gated.ok)
|
|
95
|
+
return null;
|
|
96
|
+
try {
|
|
97
|
+
const parsed = JSON.parse(raw);
|
|
98
|
+
return isPlainObject(parsed) ? parsed : null;
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
function validateBody(body) {
|
|
105
|
+
if (!exactKeys(body, new Set(['@version', 'witness', 'observation', 'deployment', 'privacy', 'limitations']))) {
|
|
106
|
+
return 'statement_shape_invalid';
|
|
107
|
+
}
|
|
108
|
+
if (body['@version'] !== NETWORK_WITNESS_VERSION)
|
|
109
|
+
return 'version_invalid';
|
|
110
|
+
if (!exactKeys(body.witness, new Set(['id', 'key_id', 'capture_point_id'])))
|
|
111
|
+
return 'witness_shape_invalid';
|
|
112
|
+
if (!nonEmptyString(body.witness.id) || !nonEmptyString(body.witness.key_id)
|
|
113
|
+
|| !nonEmptyString(body.witness.capture_point_id))
|
|
114
|
+
return 'witness_identity_invalid';
|
|
115
|
+
if (!exactKeys(body.observation, new Set([
|
|
116
|
+
'sequence', 'observed_at', 'event', 'direction', 'action_digest', 'flow_digest', 'byte_count',
|
|
117
|
+
])))
|
|
118
|
+
return 'observation_shape_invalid';
|
|
119
|
+
if (!Number.isSafeInteger(body.observation.sequence) || body.observation.sequence < 0)
|
|
120
|
+
return 'sequence_invalid';
|
|
121
|
+
if (!Number.isFinite(strictInstantMs(body.observation.observed_at)))
|
|
122
|
+
return 'observed_at_invalid';
|
|
123
|
+
if (!NETWORK_WITNESS_EVENTS.includes(body.observation.event))
|
|
124
|
+
return 'event_invalid';
|
|
125
|
+
if (!DIRECTIONS.has(body.observation.direction))
|
|
126
|
+
return 'direction_invalid';
|
|
127
|
+
if (!digest(body.observation.action_digest))
|
|
128
|
+
return 'action_digest_invalid';
|
|
129
|
+
if (body.observation.flow_digest !== undefined && !digest(body.observation.flow_digest))
|
|
130
|
+
return 'flow_digest_invalid';
|
|
131
|
+
if (body.observation.byte_count !== undefined
|
|
132
|
+
&& (!Number.isSafeInteger(body.observation.byte_count) || body.observation.byte_count < 0))
|
|
133
|
+
return 'byte_count_invalid';
|
|
134
|
+
if (!exactKeys(body.deployment, new Set(['config_digest', 'attestation_ref'])))
|
|
135
|
+
return 'deployment_shape_invalid';
|
|
136
|
+
if (!digest(body.deployment.config_digest))
|
|
137
|
+
return 'config_digest_invalid';
|
|
138
|
+
if (body.deployment.attestation_ref !== undefined && !digest(body.deployment.attestation_ref)) {
|
|
139
|
+
return 'attestation_ref_invalid';
|
|
140
|
+
}
|
|
141
|
+
if (!exactKeys(body.privacy, new Set(['payload_captured'])))
|
|
142
|
+
return 'privacy_shape_invalid';
|
|
143
|
+
if (body.privacy.payload_captured !== false)
|
|
144
|
+
return 'payload_capture_forbidden';
|
|
145
|
+
if (!Array.isArray(body.limitations) || body.limitations.length < 2 || body.limitations.length > 8
|
|
146
|
+
|| body.limitations.some((item) => !nonEmptyString(item, 512)))
|
|
147
|
+
return 'limitations_invalid';
|
|
148
|
+
try {
|
|
149
|
+
canonicalize(body);
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
return 'canonical_body_invalid';
|
|
153
|
+
}
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
/** Create a signed observation. The public key is intentionally not embedded. */
|
|
157
|
+
export function signNetworkWitnessStatement(input, privateKey) {
|
|
158
|
+
if (!privateKey)
|
|
159
|
+
throw new TypeError('privateKey is required');
|
|
160
|
+
const keyId = input?.key_id ?? keyIdFor(privateKey);
|
|
161
|
+
const body = {
|
|
162
|
+
'@version': NETWORK_WITNESS_VERSION,
|
|
163
|
+
witness: {
|
|
164
|
+
id: input?.witness_id,
|
|
165
|
+
key_id: keyId,
|
|
166
|
+
capture_point_id: input?.capture_point_id,
|
|
167
|
+
},
|
|
168
|
+
observation: {
|
|
169
|
+
sequence: input?.sequence,
|
|
170
|
+
observed_at: input?.observed_at,
|
|
171
|
+
event: input?.event,
|
|
172
|
+
direction: input?.direction,
|
|
173
|
+
action_digest: input?.action_digest,
|
|
174
|
+
...(input?.flow_digest !== undefined ? { flow_digest: input.flow_digest } : {}),
|
|
175
|
+
...(input?.byte_count !== undefined ? { byte_count: input.byte_count } : {}),
|
|
176
|
+
},
|
|
177
|
+
deployment: {
|
|
178
|
+
config_digest: input?.config_digest,
|
|
179
|
+
...(input?.attestation_ref !== undefined ? { attestation_ref: input.attestation_ref } : {}),
|
|
180
|
+
},
|
|
181
|
+
privacy: { payload_captured: false },
|
|
182
|
+
limitations: [
|
|
183
|
+
'This artifact proves only that a pinned witness key signed an observation at a named capture point.',
|
|
184
|
+
'A passive network witness does not authorize, block, execute, or prove the physical outcome of an action.',
|
|
185
|
+
'Coverage and completeness depend on the relying party pinning the capture topology and expected witness set.',
|
|
186
|
+
'Rollback detection begins at a relying-party-pinned stream checkpoint; first-seen sequence numbers are not self-authenticating history.',
|
|
187
|
+
],
|
|
188
|
+
};
|
|
189
|
+
const invalid = validateBody(body);
|
|
190
|
+
if (invalid)
|
|
191
|
+
throw new TypeError(invalid);
|
|
192
|
+
const statementDigest = networkWitnessDigest(body);
|
|
193
|
+
return Object.freeze({
|
|
194
|
+
...body,
|
|
195
|
+
signature: Object.freeze({
|
|
196
|
+
algorithm: 'Ed25519',
|
|
197
|
+
key_id: keyId,
|
|
198
|
+
statement_digest: statementDigest,
|
|
199
|
+
signature_b64u: crypto.sign(null, signingBytes(body), privateKey).toString('base64url'),
|
|
200
|
+
}),
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
function findPin(pins, witness) {
|
|
204
|
+
if (!Array.isArray(pins))
|
|
205
|
+
return null;
|
|
206
|
+
return pins.find((pin) => isPlainObject(pin)
|
|
207
|
+
&& pin.witness_id === witness.id
|
|
208
|
+
&& pin.key_id === witness.key_id
|
|
209
|
+
&& Array.isArray(pin.capture_point_ids)
|
|
210
|
+
&& pin.capture_point_ids.includes(witness.capture_point_id)) ?? null;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Offline signature and context verification. This function never throws on a
|
|
214
|
+
* presenter-controlled statement. Sequence consumption is a separate online
|
|
215
|
+
* operation performed by acceptNetworkWitnessStatement.
|
|
216
|
+
*/
|
|
217
|
+
export function verifyNetworkWitnessStatement(statement, options = {}) {
|
|
218
|
+
const fail = (reason, checks = {}) => ({
|
|
219
|
+
verified: false,
|
|
220
|
+
accepted: false,
|
|
221
|
+
reason,
|
|
222
|
+
checks: {
|
|
223
|
+
shape: false,
|
|
224
|
+
pin: false,
|
|
225
|
+
signature: false,
|
|
226
|
+
action_binding: false,
|
|
227
|
+
freshness: false,
|
|
228
|
+
config_binding: false,
|
|
229
|
+
...checks,
|
|
230
|
+
},
|
|
231
|
+
});
|
|
232
|
+
try {
|
|
233
|
+
if (!isPlainObject(statement)
|
|
234
|
+
|| !exactKeys(statement, new Set(['@version', 'witness', 'observation', 'deployment', 'privacy', 'limitations', 'signature']))) {
|
|
235
|
+
return fail('statement_shape_invalid');
|
|
236
|
+
}
|
|
237
|
+
const body = unsigned(statement);
|
|
238
|
+
const invalid = validateBody(body);
|
|
239
|
+
if (invalid)
|
|
240
|
+
return fail(invalid);
|
|
241
|
+
if (!exactKeys(statement.signature, new Set(['algorithm', 'key_id', 'statement_digest', 'signature_b64u']))) {
|
|
242
|
+
return fail('signature_shape_invalid', { shape: true });
|
|
243
|
+
}
|
|
244
|
+
if (statement.signature.algorithm !== 'Ed25519'
|
|
245
|
+
|| statement.signature.key_id !== body.witness.key_id
|
|
246
|
+
|| !digest(statement.signature.statement_digest)
|
|
247
|
+
|| !nonEmptyString(statement.signature.signature_b64u, 512)) {
|
|
248
|
+
return fail('signature_envelope_invalid', { shape: true });
|
|
249
|
+
}
|
|
250
|
+
const pin = findPin(options.pinnedWitnesses, body.witness);
|
|
251
|
+
if (!pin || !nonEmptyString(pin.public_key, 4096))
|
|
252
|
+
return fail('witness_key_unpinned', { shape: true });
|
|
253
|
+
if (!Array.isArray(pin.config_digests) || pin.config_digests.length === 0
|
|
254
|
+
|| !pin.config_digests.includes(body.deployment.config_digest)) {
|
|
255
|
+
return fail('witness_config_unpinned', { shape: true, pin: true });
|
|
256
|
+
}
|
|
257
|
+
if (options.expectedActionDigest !== undefined
|
|
258
|
+
&& body.observation.action_digest !== options.expectedActionDigest) {
|
|
259
|
+
return fail('action_digest_mismatch', { shape: true, pin: true, config_binding: true });
|
|
260
|
+
}
|
|
261
|
+
if (options.expectedEvent !== undefined && body.observation.event !== options.expectedEvent) {
|
|
262
|
+
return fail('event_mismatch', { shape: true, pin: true, config_binding: true });
|
|
263
|
+
}
|
|
264
|
+
const now = options.now === undefined ? Date.now() : Number(options.now);
|
|
265
|
+
const maxAgeSec = options.maxAgeSec === undefined ? 300 : options.maxAgeSec;
|
|
266
|
+
const maxFutureSkewSec = options.maxFutureSkewSec === undefined ? 30 : options.maxFutureSkewSec;
|
|
267
|
+
if (!Number.isFinite(now) || !Number.isSafeInteger(maxAgeSec) || maxAgeSec < 0
|
|
268
|
+
|| !Number.isSafeInteger(maxFutureSkewSec) || maxFutureSkewSec < 0) {
|
|
269
|
+
return fail('verification_profile_invalid', { shape: true, pin: true, config_binding: true });
|
|
270
|
+
}
|
|
271
|
+
const observedMs = strictInstantMs(body.observation.observed_at);
|
|
272
|
+
if (observedMs > now + (maxFutureSkewSec * 1000)) {
|
|
273
|
+
return fail('observation_from_future', { shape: true, pin: true, action_binding: true, config_binding: true });
|
|
274
|
+
}
|
|
275
|
+
if (now - observedMs > maxAgeSec * 1000) {
|
|
276
|
+
return fail('observation_stale', { shape: true, pin: true, action_binding: true, config_binding: true });
|
|
277
|
+
}
|
|
278
|
+
const computedDigest = networkWitnessDigest(body);
|
|
279
|
+
if (computedDigest !== statement.signature.statement_digest) {
|
|
280
|
+
return fail('statement_digest_mismatch', {
|
|
281
|
+
shape: true, pin: true, action_binding: true, freshness: true, config_binding: true,
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
let publicKey;
|
|
285
|
+
try {
|
|
286
|
+
const keyBytes = decodeBase64Url(pin.public_key, 4096);
|
|
287
|
+
if (!keyBytes)
|
|
288
|
+
throw new TypeError('invalid base64url key');
|
|
289
|
+
publicKey = crypto.createPublicKey({
|
|
290
|
+
key: keyBytes,
|
|
291
|
+
type: 'spki',
|
|
292
|
+
format: 'der',
|
|
293
|
+
});
|
|
294
|
+
if (publicKey.asymmetricKeyType !== 'ed25519')
|
|
295
|
+
throw new TypeError('witness key must be Ed25519');
|
|
296
|
+
}
|
|
297
|
+
catch {
|
|
298
|
+
return fail('pinned_key_invalid', {
|
|
299
|
+
shape: true, pin: true, action_binding: true, freshness: true, config_binding: true,
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
const signature = decodeBase64Url(statement.signature.signature_b64u, 64);
|
|
303
|
+
if (!signature || signature.length !== 64) {
|
|
304
|
+
return fail('signature_invalid', {
|
|
305
|
+
shape: true, pin: true, action_binding: true, freshness: true, config_binding: true,
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
if (!crypto.verify(null, signingBytes(body), publicKey, signature)) {
|
|
309
|
+
return fail('signature_invalid', {
|
|
310
|
+
shape: true, pin: true, action_binding: true, freshness: true, config_binding: true,
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
return {
|
|
314
|
+
verified: true,
|
|
315
|
+
accepted: true,
|
|
316
|
+
reason: null,
|
|
317
|
+
statement_digest: computedDigest,
|
|
318
|
+
stream_id: `${body.witness.id}\0${body.witness.capture_point_id}`,
|
|
319
|
+
sequence: body.observation.sequence,
|
|
320
|
+
action_digest: body.observation.action_digest,
|
|
321
|
+
event: body.observation.event,
|
|
322
|
+
observed_at: body.observation.observed_at,
|
|
323
|
+
witness_id: body.witness.id,
|
|
324
|
+
capture_point_id: body.witness.capture_point_id,
|
|
325
|
+
checks: {
|
|
326
|
+
shape: true,
|
|
327
|
+
pin: true,
|
|
328
|
+
signature: true,
|
|
329
|
+
action_binding: true,
|
|
330
|
+
freshness: true,
|
|
331
|
+
config_binding: true,
|
|
332
|
+
},
|
|
333
|
+
limitation: 'Observation is not authorization, enforcement, execution, or physical truth.',
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
catch {
|
|
337
|
+
return fail('hostile_input_refused');
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
export function createMemoryWitnessSequenceStore() {
|
|
341
|
+
const streams = new Map();
|
|
342
|
+
return {
|
|
343
|
+
durable: false,
|
|
344
|
+
async advance(streamId, sequence, statementDigest) {
|
|
345
|
+
const previous = streams.get(streamId);
|
|
346
|
+
if (previous) {
|
|
347
|
+
if (previous.equivocated === true) {
|
|
348
|
+
return { accepted: false, reason: 'sequence_equivocation' };
|
|
349
|
+
}
|
|
350
|
+
if (sequence < previous.sequence)
|
|
351
|
+
return { accepted: false, reason: 'sequence_rollback' };
|
|
352
|
+
if (sequence === previous.sequence) {
|
|
353
|
+
if (previous.digest === statementDigest) {
|
|
354
|
+
return { accepted: false, reason: 'statement_replay' };
|
|
355
|
+
}
|
|
356
|
+
streams.set(streamId, { ...previous, equivocated: true });
|
|
357
|
+
return { accepted: false, reason: 'sequence_equivocation' };
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
streams.set(streamId, { sequence, digest: statementDigest, equivocated: false });
|
|
361
|
+
return { accepted: true, reason: null };
|
|
362
|
+
},
|
|
363
|
+
snapshot() { return [...streams.entries()].map(([stream_id, value]) => ({ stream_id, ...value })); },
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
function acceptanceResult(verified, { accepted, consumed, reason, sequenceStoreDurable, }) {
|
|
367
|
+
return Object.freeze({
|
|
368
|
+
...verified,
|
|
369
|
+
acceptance_version: NETWORK_WITNESS_ACCEPTANCE_VERSION,
|
|
370
|
+
accepted,
|
|
371
|
+
consumed,
|
|
372
|
+
reason,
|
|
373
|
+
sequence_store_durable: sequenceStoreDurable === true,
|
|
374
|
+
...(isPlainObject(verified.checks) ? { checks: Object.freeze({ ...verified.checks }) } : {}),
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Validate an ingestion result supplied through a relying-party-trusted option.
|
|
379
|
+
* This does not authenticate presenter-controlled JSON; callers must never move
|
|
380
|
+
* an untrusted bundle field into this trust channel.
|
|
381
|
+
*/
|
|
382
|
+
export function validateTrustedNetworkWitnessAcceptance(result, options = {}) {
|
|
383
|
+
const fail = (reason, fields = {}, statementVerified = false) => ({
|
|
384
|
+
verified: statementVerified === true,
|
|
385
|
+
accepted: false,
|
|
386
|
+
consumed: false,
|
|
387
|
+
reason,
|
|
388
|
+
...fields,
|
|
389
|
+
});
|
|
390
|
+
try {
|
|
391
|
+
if (!isPlainObject(result)
|
|
392
|
+
|| result.acceptance_version !== NETWORK_WITNESS_ACCEPTANCE_VERSION) {
|
|
393
|
+
return fail('trusted_witness_acceptance_invalid');
|
|
394
|
+
}
|
|
395
|
+
const common = {
|
|
396
|
+
acceptance_version: NETWORK_WITNESS_ACCEPTANCE_VERSION,
|
|
397
|
+
statement_digest: result.statement_digest,
|
|
398
|
+
stream_id: result.stream_id,
|
|
399
|
+
sequence: result.sequence,
|
|
400
|
+
action_digest: result.action_digest,
|
|
401
|
+
event: result.event,
|
|
402
|
+
observed_at: result.observed_at,
|
|
403
|
+
witness_id: result.witness_id,
|
|
404
|
+
capture_point_id: result.capture_point_id,
|
|
405
|
+
sequence_store_durable: result.sequence_store_durable === true,
|
|
406
|
+
};
|
|
407
|
+
const statementVerified = result.verified === true
|
|
408
|
+
&& digest(common.statement_digest) && digest(common.action_digest)
|
|
409
|
+
&& Number.isSafeInteger(common.sequence) && common.sequence >= 0
|
|
410
|
+
&& nonEmptyString(common.witness_id) && nonEmptyString(common.capture_point_id)
|
|
411
|
+
&& common.stream_id === `${common.witness_id}\0${common.capture_point_id}`
|
|
412
|
+
&& NETWORK_WITNESS_EVENTS.includes(common.event)
|
|
413
|
+
&& Number.isFinite(strictInstantMs(common.observed_at));
|
|
414
|
+
if (result.accepted !== true || result.consumed !== true) {
|
|
415
|
+
return fail(nonEmptyString(result.reason) ? result.reason : 'trusted_witness_acceptance_rejected', common, statementVerified);
|
|
416
|
+
}
|
|
417
|
+
if (!statementVerified || result.reason !== null) {
|
|
418
|
+
return fail('trusted_witness_acceptance_invalid');
|
|
419
|
+
}
|
|
420
|
+
if (!common.sequence_store_durable && options.allowEphemeralStore !== true) {
|
|
421
|
+
return fail('durable_sequence_store_required', common);
|
|
422
|
+
}
|
|
423
|
+
if (options.expectedStatementDigest !== undefined) {
|
|
424
|
+
if (!digest(options.expectedStatementDigest))
|
|
425
|
+
return fail('verification_profile_invalid', common);
|
|
426
|
+
if (common.statement_digest !== options.expectedStatementDigest) {
|
|
427
|
+
return fail('witness_acceptance_digest_mismatch', common);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
if (options.expectedActionDigest !== undefined
|
|
431
|
+
&& common.action_digest !== options.expectedActionDigest) {
|
|
432
|
+
return fail('action_digest_mismatch', common);
|
|
433
|
+
}
|
|
434
|
+
if (options.expectedEvent !== undefined && common.event !== options.expectedEvent) {
|
|
435
|
+
return fail('event_mismatch', common);
|
|
436
|
+
}
|
|
437
|
+
const now = options.now === undefined ? Date.now() : Number(options.now);
|
|
438
|
+
const maxAgeSec = options.maxAgeSec === undefined ? 300 : options.maxAgeSec;
|
|
439
|
+
const maxFutureSkewSec = options.maxFutureSkewSec === undefined ? 30 : options.maxFutureSkewSec;
|
|
440
|
+
if (!Number.isFinite(now) || !Number.isSafeInteger(maxAgeSec) || maxAgeSec < 0
|
|
441
|
+
|| !Number.isSafeInteger(maxFutureSkewSec) || maxFutureSkewSec < 0) {
|
|
442
|
+
return fail('verification_profile_invalid', common);
|
|
443
|
+
}
|
|
444
|
+
const observedMs = strictInstantMs(common.observed_at);
|
|
445
|
+
if (observedMs > now + (maxFutureSkewSec * 1000))
|
|
446
|
+
return fail('observation_from_future', common);
|
|
447
|
+
if (now - observedMs > maxAgeSec * 1000)
|
|
448
|
+
return fail('observation_stale', common);
|
|
449
|
+
return {
|
|
450
|
+
...common,
|
|
451
|
+
verified: true,
|
|
452
|
+
accepted: true,
|
|
453
|
+
consumed: true,
|
|
454
|
+
reason: null,
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
catch {
|
|
458
|
+
return fail('trusted_witness_acceptance_invalid');
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
/** Verify and atomically advance a witness stream for online ingestion. */
|
|
462
|
+
export async function acceptNetworkWitnessStatement(statement, options = {}) {
|
|
463
|
+
const verified = verifyNetworkWitnessStatement(statement, options);
|
|
464
|
+
if (!verified.accepted) {
|
|
465
|
+
return acceptanceResult(verified, {
|
|
466
|
+
accepted: false,
|
|
467
|
+
consumed: false,
|
|
468
|
+
reason: verified.reason,
|
|
469
|
+
sequenceStoreDurable: false,
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
const store = options.sequenceStore;
|
|
473
|
+
if (!store || typeof store.advance !== 'function'
|
|
474
|
+
|| (store.durable !== true && options.allowEphemeralStore !== true)) {
|
|
475
|
+
return acceptanceResult(verified, {
|
|
476
|
+
accepted: false,
|
|
477
|
+
consumed: false,
|
|
478
|
+
reason: 'durable_sequence_store_required',
|
|
479
|
+
sequenceStoreDurable: false,
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
try {
|
|
483
|
+
const advanced = await store.advance(verified.stream_id, verified.sequence, verified.statement_digest);
|
|
484
|
+
if (!isPlainObject(advanced) || advanced.accepted !== true || advanced.reason !== null) {
|
|
485
|
+
return acceptanceResult(verified, {
|
|
486
|
+
accepted: false,
|
|
487
|
+
consumed: false,
|
|
488
|
+
reason: nonEmptyString(advanced?.reason) ? advanced.reason : 'sequence_store_refused',
|
|
489
|
+
sequenceStoreDurable: store.durable === true,
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
return acceptanceResult(verified, {
|
|
493
|
+
accepted: true,
|
|
494
|
+
consumed: true,
|
|
495
|
+
reason: null,
|
|
496
|
+
sequenceStoreDurable: store.durable === true,
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
catch {
|
|
500
|
+
return acceptanceResult(verified, {
|
|
501
|
+
accepted: false,
|
|
502
|
+
consumed: false,
|
|
503
|
+
reason: 'sequence_store_unavailable',
|
|
504
|
+
sequenceStoreDurable: store.durable === true,
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
export default {
|
|
509
|
+
NETWORK_WITNESS_VERSION,
|
|
510
|
+
NETWORK_WITNESS_ACCEPTANCE_VERSION,
|
|
511
|
+
NETWORK_WITNESS_EVENTS,
|
|
512
|
+
parseNetworkWitnessStatement,
|
|
513
|
+
networkWitnessDigest,
|
|
514
|
+
signNetworkWitnessStatement,
|
|
515
|
+
verifyNetworkWitnessStatement,
|
|
516
|
+
acceptNetworkWitnessStatement,
|
|
517
|
+
validateTrustedNetworkWitnessAcceptance,
|
|
518
|
+
createMemoryWitnessSequenceStore,
|
|
519
|
+
};
|
|
520
|
+
//# sourceMappingURL=network-witness.js.map
|