@motebit/state-export-client 0.2.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.
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Verified-fetch wrapper for motebit state-export endpoints.
3
+ *
4
+ * Every `app.get(...)` in `services/relay/src/state-export.ts` emits an
5
+ * outer `ContentArtifactManifest` in the `X-Motebit-Content-Manifest`
6
+ * HTTP header (signed by the relay's identity). This module wraps
7
+ * `fetch` to verify the manifest against the response body bytes on
8
+ * every call, optionally pinning the producer key against a trust
9
+ * anchor obtained from `fetchTransparencyAnchor`.
10
+ *
11
+ * The consumer-side primitive that turns producer-side signing into
12
+ * an operational invariant: an operator who silently degrades their
13
+ * own signing breaks their own dashboard. Doctrine:
14
+ * `docs/doctrine/nist-alignment.md` §8, `docs/doctrine/self-attesting-system.md`.
15
+ */
16
+ import type { ContentArtifactType } from "@motebit/protocol";
17
+ import type { TransparencyAnchor } from "./transparency-anchor.js";
18
+ /** HTTP header carrying the relay-signed content-artifact manifest. */
19
+ export declare const MANIFEST_HEADER = "X-Motebit-Content-Manifest";
20
+ /** Verification outcome accompanying every state-export response body. */
21
+ export type StateExportVerification = {
22
+ readonly valid: true;
23
+ readonly producerPublicKeyHex: string;
24
+ readonly producerDid: string;
25
+ readonly artifactType: ContentArtifactType;
26
+ readonly claimGenerator: string;
27
+ readonly producedAt: string;
28
+ readonly contentHash: string;
29
+ } | {
30
+ readonly valid: false;
31
+ readonly reason: StateExportVerificationFailureReason;
32
+ readonly detail?: string;
33
+ };
34
+ export type StateExportVerificationFailureReason = "manifest_header_missing" | "malformed_manifest_header" | "content_hash_mismatch" | "signature_invalid" | "malformed_public_key" | "malformed_signature" | "unsupported_suite" | "producer_key_mismatch";
35
+ export interface VerifiedStateExportResponse<T> {
36
+ /**
37
+ * Parsed JSON body — present only when verification succeeded.
38
+ * `null` on verification failure: callers MUST check
39
+ * `verification.valid` before consuming the body. Never render
40
+ * unverified state.
41
+ */
42
+ readonly body: T | null;
43
+ /** Raw bytes the verifier hashed. Exposed so callers that need byte-level access (audit, hashing, re-serialization) don't double-fetch. */
44
+ readonly bodyBytes: Uint8Array;
45
+ /** Structured verification result. Callers branch on `valid` for UI status and `reason` for audit logging. */
46
+ readonly verification: StateExportVerification;
47
+ }
48
+ export interface VerifiedFetchOptions {
49
+ /**
50
+ * Trust anchor obtained from `fetchTransparencyAnchor`. When set,
51
+ * the verifier rejects with `producer_key_mismatch` if the manifest's
52
+ * declared producer key does not match the pinned hex value.
53
+ *
54
+ * Omitting the anchor still verifies the manifest's self-consistency
55
+ * (content_hash + signature against the declared key) — but a verifier
56
+ * with no pin trusts the declared key. Production callers SHOULD
57
+ * always pass an anchor.
58
+ */
59
+ readonly anchor?: TransparencyAnchor;
60
+ /**
61
+ * Inject the fetch implementation. Defaults to global `fetch`. Tests
62
+ * pass a mock; integrators with auth-proxy or tunneling transports
63
+ * pass a wrapper.
64
+ */
65
+ readonly fetch?: typeof globalThis.fetch;
66
+ /** Forwarded to the underlying fetch call. */
67
+ readonly init?: RequestInit;
68
+ }
69
+ /**
70
+ * Fetch a state-export endpoint and verify its content-artifact
71
+ * manifest against the response body bytes. Returns the parsed body,
72
+ * the raw bytes, and a typed verification result.
73
+ *
74
+ * The verifier reads `X-Motebit-Content-Manifest` from the response,
75
+ * decodes the base64url-encoded canonical-JSON manifest, recomputes
76
+ * SHA-256 over the body bytes, and verifies the signature against the
77
+ * manifest's declared producer key. With `anchor` set, also enforces
78
+ * a byte-equal match between the declared key and the pinned key.
79
+ *
80
+ * Non-2xx HTTP responses throw — the verifier does not attempt to
81
+ * verify error bodies. A 5xx response from the relay is a service
82
+ * outage, not a signing failure; let the caller's catch handle it.
83
+ */
84
+ export declare function verifiedStateExportFetch<T>(url: string, options?: VerifiedFetchOptions): Promise<VerifiedStateExportResponse<T>>;
85
+ /**
86
+ * Pure-function verifier: decode the header value, parse the manifest,
87
+ * verify against the body bytes, optionally enforce the producer-key
88
+ * pin. Exposed so tests + audit tooling can replay a captured response
89
+ * without a fresh HTTP round-trip.
90
+ */
91
+ export declare function verifyManifestAgainstBytes(headerValue: string | null, bodyBytes: Uint8Array, anchor?: TransparencyAnchor): Promise<StateExportVerification>;
92
+ /**
93
+ * Thrown when the underlying HTTP fetch returns non-2xx. The verifier
94
+ * does not attempt to verify error bodies — the relay's error
95
+ * envelope is unsigned by design (signing 5xx pages would be
96
+ * misleading provenance for a service outage).
97
+ */
98
+ export declare class StateExportFetchError extends Error {
99
+ readonly status: number;
100
+ readonly statusText: string;
101
+ readonly body: string;
102
+ readonly url: string;
103
+ constructor(status: number, statusText: string, body: string, url: string);
104
+ }
105
+ //# sourceMappingURL=verified-fetch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verified-fetch.d.ts","sourceRoot":"","sources":["../src/verified-fetch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAE7D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAEnE,uEAAuE;AACvE,eAAO,MAAM,eAAe,+BAA+B,CAAC;AAE5D,0EAA0E;AAC1E,MAAM,MAAM,uBAAuB,GAC/B;IACE,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC;IACrB,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IACtC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAAC;IAC3C,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B,GACD;IACE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,oCAAoC,CAAC;IACtD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEN,MAAM,MAAM,oCAAoC,GAC5C,yBAAyB,GACzB,2BAA2B,GAC3B,uBAAuB,GACvB,mBAAmB,GACnB,sBAAsB,GACtB,qBAAqB,GACrB,mBAAmB,GACnB,uBAAuB,CAAC;AAE5B,MAAM,WAAW,2BAA2B,CAAC,CAAC;IAC5C;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;IACxB,2IAA2I;IAC3I,QAAQ,CAAC,SAAS,EAAE,UAAU,CAAC;IAC/B,8GAA8G;IAC9G,QAAQ,CAAC,YAAY,EAAE,uBAAuB,CAAC;CAChD;AAED,MAAM,WAAW,oBAAoB;IACnC;;;;;;;;;OASG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,kBAAkB,CAAC;IACrC;;;;OAIG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IACzC,8CAA8C;IAC9C,QAAQ,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC;CAC7B;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,wBAAwB,CAAC,CAAC,EAC9C,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,2BAA2B,CAAC,CAAC,CAAC,CAAC,CA6CzC;AAED;;;;;GAKG;AACH,wBAAsB,0BAA0B,CAC9C,WAAW,EAAE,MAAM,GAAG,IAAI,EAC1B,SAAS,EAAE,UAAU,EACrB,MAAM,CAAC,EAAE,kBAAkB,GAC1B,OAAO,CAAC,uBAAuB,CAAC,CAoDlC;AAED;;;;;GAKG;AACH,qBAAa,qBAAsB,SAAQ,KAAK;aAE5B,MAAM,EAAE,MAAM;aACd,UAAU,EAAE,MAAM;aAClB,IAAI,EAAE,MAAM;aACZ,GAAG,EAAE,MAAM;gBAHX,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM;CAK9B"}
@@ -0,0 +1,164 @@
1
+ /**
2
+ * Verified-fetch wrapper for motebit state-export endpoints.
3
+ *
4
+ * Every `app.get(...)` in `services/relay/src/state-export.ts` emits an
5
+ * outer `ContentArtifactManifest` in the `X-Motebit-Content-Manifest`
6
+ * HTTP header (signed by the relay's identity). This module wraps
7
+ * `fetch` to verify the manifest against the response body bytes on
8
+ * every call, optionally pinning the producer key against a trust
9
+ * anchor obtained from `fetchTransparencyAnchor`.
10
+ *
11
+ * The consumer-side primitive that turns producer-side signing into
12
+ * an operational invariant: an operator who silently degrades their
13
+ * own signing breaks their own dashboard. Doctrine:
14
+ * `docs/doctrine/nist-alignment.md` §8, `docs/doctrine/self-attesting-system.md`.
15
+ */
16
+ import { verifyContentArtifact } from "@motebit/crypto";
17
+ /** HTTP header carrying the relay-signed content-artifact manifest. */
18
+ export const MANIFEST_HEADER = "X-Motebit-Content-Manifest";
19
+ /**
20
+ * Fetch a state-export endpoint and verify its content-artifact
21
+ * manifest against the response body bytes. Returns the parsed body,
22
+ * the raw bytes, and a typed verification result.
23
+ *
24
+ * The verifier reads `X-Motebit-Content-Manifest` from the response,
25
+ * decodes the base64url-encoded canonical-JSON manifest, recomputes
26
+ * SHA-256 over the body bytes, and verifies the signature against the
27
+ * manifest's declared producer key. With `anchor` set, also enforces
28
+ * a byte-equal match between the declared key and the pinned key.
29
+ *
30
+ * Non-2xx HTTP responses throw — the verifier does not attempt to
31
+ * verify error bodies. A 5xx response from the relay is a service
32
+ * outage, not a signing failure; let the caller's catch handle it.
33
+ */
34
+ export async function verifiedStateExportFetch(url, options = {}) {
35
+ const fetchImpl = options.fetch ?? globalThis.fetch;
36
+ const res = await fetchImpl(url, options.init);
37
+ if (!res.ok) {
38
+ const body = await res.text().catch(() => "");
39
+ throw new StateExportFetchError(res.status, res.statusText, body, url);
40
+ }
41
+ // Read body bytes once — JSON.parse runs over a UTF-8 decode of the
42
+ // same bytes the verifier hashes. ArrayBuffer keeps both views safe.
43
+ const arrayBuffer = await res.arrayBuffer();
44
+ const bodyBytes = new Uint8Array(arrayBuffer);
45
+ // Verify BEFORE JSON-parse: a tampered body can corrupt JSON
46
+ // structure, which would mask the typed crypto reason
47
+ // (`content_hash_mismatch`) behind a generic parse error. Running
48
+ // verification first preserves the structured failure reason for
49
+ // audit logging even when the bytes are wholly garbage.
50
+ const headerValue = res.headers.get(MANIFEST_HEADER);
51
+ const verification = await verifyManifestAgainstBytes(headerValue, bodyBytes, options.anchor);
52
+ // JSON parsing only meaningful when the bytes are what the producer
53
+ // signed. On verification failure, `body` is null — callers MUST
54
+ // check `verification.valid` before rendering; the discriminated
55
+ // union below makes that compile-time enforceable.
56
+ let body = null;
57
+ if (verification.valid) {
58
+ const bodyText = new TextDecoder().decode(bodyBytes);
59
+ try {
60
+ body = JSON.parse(bodyText);
61
+ }
62
+ catch (err) {
63
+ // Verified bytes that don't parse as JSON are a producer bug —
64
+ // the manifest swore these bytes are the export, but they aren't
65
+ // valid JSON. Surface as a thrown error rather than mixing
66
+ // crypto-valid + parse-failed into the same return shape.
67
+ throw new StateExportFetchError(200, "verified body is not valid JSON", err instanceof Error ? err.message : String(err), url);
68
+ }
69
+ }
70
+ return { body, bodyBytes, verification };
71
+ }
72
+ /**
73
+ * Pure-function verifier: decode the header value, parse the manifest,
74
+ * verify against the body bytes, optionally enforce the producer-key
75
+ * pin. Exposed so tests + audit tooling can replay a captured response
76
+ * without a fresh HTTP round-trip.
77
+ */
78
+ export async function verifyManifestAgainstBytes(headerValue, bodyBytes, anchor) {
79
+ if (headerValue == null || headerValue === "") {
80
+ return { valid: false, reason: "manifest_header_missing" };
81
+ }
82
+ let manifest;
83
+ try {
84
+ const manifestBytes = base64UrlDecode(headerValue);
85
+ const manifestJson = new TextDecoder().decode(manifestBytes);
86
+ manifest = JSON.parse(manifestJson);
87
+ }
88
+ catch (err) {
89
+ return {
90
+ valid: false,
91
+ reason: "malformed_manifest_header",
92
+ detail: err instanceof Error ? err.message : String(err),
93
+ };
94
+ }
95
+ // Producer-key pin runs BEFORE the crypto check — a key-mismatch
96
+ // rejection is cheaper and more informative than a generic
97
+ // signature_invalid when the verifier knows the expected signer.
98
+ if (anchor !== undefined) {
99
+ const declared = manifest.producer_public_key.toLowerCase();
100
+ if (declared !== anchor.relayPublicKeyHex) {
101
+ return {
102
+ valid: false,
103
+ reason: "producer_key_mismatch",
104
+ detail: `expected ${anchor.relayPublicKeyHex}, got ${declared}`,
105
+ };
106
+ }
107
+ }
108
+ const result = await verifyContentArtifact(manifest, bodyBytes);
109
+ if (!result.valid) {
110
+ // Map primitive reasons into the consumer-facing failure union.
111
+ // Both unions share most variants verbatim; the consumer-facing
112
+ // one adds the header- and key-pin-specific reasons above.
113
+ return {
114
+ valid: false,
115
+ reason: result.reason,
116
+ };
117
+ }
118
+ return {
119
+ valid: true,
120
+ producerPublicKeyHex: manifest.producer_public_key.toLowerCase(),
121
+ producerDid: manifest.producer,
122
+ artifactType: manifest.artifact_type,
123
+ claimGenerator: manifest.claim_generator,
124
+ producedAt: manifest.produced_at,
125
+ contentHash: manifest.content_hash,
126
+ };
127
+ }
128
+ /**
129
+ * Thrown when the underlying HTTP fetch returns non-2xx. The verifier
130
+ * does not attempt to verify error bodies — the relay's error
131
+ * envelope is unsigned by design (signing 5xx pages would be
132
+ * misleading provenance for a service outage).
133
+ */
134
+ export class StateExportFetchError extends Error {
135
+ status;
136
+ statusText;
137
+ body;
138
+ url;
139
+ constructor(status, statusText, body, url) {
140
+ super(`state-export fetch ${url} → ${status} ${statusText}`);
141
+ this.status = status;
142
+ this.statusText = statusText;
143
+ this.body = body;
144
+ this.url = url;
145
+ this.name = "StateExportFetchError";
146
+ }
147
+ }
148
+ /**
149
+ * Inline base64url decoder — avoids pulling Buffer (Node-only) or a
150
+ * new dependency. Browsers + Node 20+ have `atob`, but `atob` rejects
151
+ * base64url; we normalize to standard base64 first.
152
+ */
153
+ function base64UrlDecode(input) {
154
+ const normalized = input.replace(/-/g, "+").replace(/_/g, "/");
155
+ // atob requires padded base64. Compute padding from length mod 4.
156
+ const padded = normalized + "=".repeat((4 - (normalized.length % 4)) % 4);
157
+ const binary = atob(padded);
158
+ const bytes = new Uint8Array(binary.length);
159
+ for (let i = 0; i < binary.length; i++) {
160
+ bytes[i] = binary.charCodeAt(i);
161
+ }
162
+ return bytes;
163
+ }
164
+ //# sourceMappingURL=verified-fetch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verified-fetch.js","sourceRoot":"","sources":["../src/verified-fetch.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@motebit/state-export-client",
3
+ "version": "0.2.0",
4
+ "description": "Browser-safe client for verified motebit state-export reads. Wraps fetch with X-Motebit-Content-Manifest verification + Trust-On-First-Use bootstrap from /.well-known/motebit-transparency.json. Apache-2.0; consumes @motebit/crypto + @motebit/protocol only.",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/motebit/motebit",
8
+ "directory": "packages/state-export-client"
9
+ },
10
+ "type": "module",
11
+ "main": "./dist/index.js",
12
+ "types": "./dist/index.d.ts",
13
+ "exports": {
14
+ ".": {
15
+ "types": "./dist/index.d.ts",
16
+ "default": "./dist/index.js"
17
+ }
18
+ },
19
+ "files": [
20
+ "dist/**/*.js",
21
+ "dist/**/*.js.map",
22
+ "dist/**/*.d.ts",
23
+ "dist/**/*.d.ts.map",
24
+ "LICENSE",
25
+ "NOTICE",
26
+ "README.md"
27
+ ],
28
+ "sideEffects": false,
29
+ "license": "Apache-2.0",
30
+ "keywords": [
31
+ "motebit",
32
+ "verification",
33
+ "self-attesting",
34
+ "content-provenance",
35
+ "operator-transparency"
36
+ ],
37
+ "dependencies": {
38
+ "@motebit/crypto": "1.3.0",
39
+ "@motebit/protocol": "1.3.0"
40
+ },
41
+ "devDependencies": {
42
+ "@types/node": "^22.0.0",
43
+ "typescript": "^5.6.0",
44
+ "vitest": "^2.1.0"
45
+ },
46
+ "scripts": {
47
+ "build": "tsc -b",
48
+ "test": "vitest run",
49
+ "test:coverage": "vitest run --coverage",
50
+ "typecheck": "tsc --noEmit",
51
+ "lint": "eslint --parser-options=project:tsconfig.eslint.json src/",
52
+ "clean": "rm -rf dist .turbo *.tsbuildinfo"
53
+ }
54
+ }