@motebit/state-export-client 0.2.0 → 0.3.1
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/README.md +52 -11
- package/dist/identity-anchor.d.ts +63 -0
- package/dist/identity-anchor.d.ts.map +1 -0
- package/dist/identity-anchor.js +99 -0
- package/dist/identity-anchor.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/inner-receipts.d.ts +17 -1
- package/dist/inner-receipts.d.ts.map +1 -1
- package/dist/inner-receipts.js +5 -0
- package/dist/inner-receipts.js.map +1 -1
- package/dist/key-revocation.d.ts +50 -0
- package/dist/key-revocation.d.ts.map +1 -0
- package/dist/key-revocation.js +79 -0
- package/dist/key-revocation.js.map +1 -0
- package/dist/receipt-document.d.ts +134 -0
- package/dist/receipt-document.d.ts.map +1 -0
- package/dist/receipt-document.js +189 -0
- package/dist/receipt-document.js.map +1 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -57,6 +57,29 @@ if (inner.applicable && !inner.allValid) {
|
|
|
57
57
|
|
|
58
58
|
`verifyInnerSignedReceipts` returns `applicable: false` for v1.0 bodies, non-execution-ledger bodies, or bodies with an empty `signed_receipts` field — calm-software default, no flag required. On v1.1 bodies, every entry is parsed, every signature is checked against its embedded public key, and `delegation_receipts` chains are walked recursively.
|
|
59
59
|
|
|
60
|
+
## Quick start — verify a pasted receipt (receipt.computer)
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
import { verifyReceiptDocument } from "@motebit/state-export-client";
|
|
64
|
+
|
|
65
|
+
const v = await verifyReceiptDocument(pastedJsonText);
|
|
66
|
+
|
|
67
|
+
if (v.binding === "revoked") {
|
|
68
|
+
show(`Key revoked — do not trust (revoked at ${new Date(v.revokedAt!).toISOString()})`);
|
|
69
|
+
} else if (!v.integrity) {
|
|
70
|
+
show(`Verification failed: ${v.reason}`); // malformed_json | not_a_receipt | signature_invalid | …
|
|
71
|
+
} else if (v.binding === "anchored" || v.binding === "pinned") {
|
|
72
|
+
show(`Verified — from ${v.motebitId}`); // key bound to the motebit (anchored adds on-chain non-equivocation)
|
|
73
|
+
} else {
|
|
74
|
+
// integrity-only: signature is valid but checked against the receipt's OWN
|
|
75
|
+
// embedded key — proves the bytes weren't tampered, NOT that the key belongs
|
|
76
|
+
// to motebitId. Never render "from <motebit>" here.
|
|
77
|
+
show("Signature verified — identity not anchored");
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
`verifyReceiptDocument` is the brain behind a public, login-free receipt verifier. It runs entirely offline (no relay) for the integrity check, never throws on bad input (typed `reason`s instead), and keeps **integrity** (the bytes were signed, untampered) strictly separate from **binding** (the key belongs to this `motebitId`). The binding ladder: `integrity-only` (no options) < `pinned` (pass `options.identity` — the key is time-valid in the motebit's own succession chain) < `anchored` (also pass `options.anchor` — the binding is in the relay's transparency log AND that root is independently confirmed on-chain). Never render "from <motebit>" below `pinned`. `revoked` is off the ladder — a poison verdict: pass `options.revocation` and if the signing key has an on-chain revocation memo dated at/before the receipt, `binding` is `revoked` regardless of everything else (read from the neutral chain, never the relay's word).
|
|
82
|
+
|
|
60
83
|
## Trust-anchor chain
|
|
61
84
|
|
|
62
85
|
```
|
|
@@ -91,19 +114,37 @@ if (lookup.ok) {
|
|
|
91
114
|
}
|
|
92
115
|
```
|
|
93
116
|
|
|
117
|
+
The same on-chain channel raises a receipt's binding to `anchored`. The relay's `/identity/:motebitId` bundle carries a transparency-log inclusion proof and the tx that posted its root; `lookupIdentityLogAnchor` confirms that root really sits on-chain at the relay's **pinned** address (passed out-of-band, never from the bundle). Wire it through `verifyReceiptDocument`:
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
import { lookupIdentityLogAnchor, verifyReceiptDocument } from "@motebit/state-export-client";
|
|
121
|
+
|
|
122
|
+
const v = await verifyReceiptDocument(pastedJsonText, {
|
|
123
|
+
identity, // the motebit's identity file (reaches `pinned`)
|
|
124
|
+
anchor: {
|
|
125
|
+
proof: bundle.anchored.proof, // from GET /api/v1/identity/:motebitId
|
|
126
|
+
relayAnchorAddress: PINNED_RELAY_SOLANA_ADDRESS, // out-of-band trust root
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
// v.binding === "anchored" only when inclusion AND the on-chain root cross-check both pass.
|
|
130
|
+
```
|
|
131
|
+
|
|
94
132
|
## Programmatic surface
|
|
95
133
|
|
|
96
|
-
| Export | Kind | Role
|
|
97
|
-
| ---------------------------------------------------------- | -------- |
|
|
98
|
-
| `fetchTransparencyAnchor(baseUrl, opts?)` | function | TOFU bootstrap — fetch `/.well-known/motebit-transparency.json`, verify self-signature, return pinned `TransparencyAnchor`
|
|
99
|
-
| `verifyTransparencyDeclaration(declaration)` | function | Lower-level: verify a `SignedTransparencyDeclaration` from any source (cached, archived, fixture)
|
|
100
|
-
| `verifiedStateExportFetch(url, opts)` | function | Wrap `fetch` — verify outer envelope against body bytes + optional anchor pin
|
|
101
|
-
| `verifyManifestAgainstBytes(manifest, bodyBytes, anchor?)` | function | Lower-level: verify a parsed `ContentArtifactManifest` against bytes you already have
|
|
102
|
-
| `verifyInnerSignedReceipts(body)` | function | Recursive v1.1 inner-receipt audit — per-receipt verdict with typed failure reasons
|
|
103
|
-
| `
|
|
104
|
-
| `
|
|
105
|
-
| `
|
|
106
|
-
| `
|
|
134
|
+
| Export | Kind | Role |
|
|
135
|
+
| ---------------------------------------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
|
|
136
|
+
| `fetchTransparencyAnchor(baseUrl, opts?)` | function | TOFU bootstrap — fetch `/.well-known/motebit-transparency.json`, verify self-signature, return pinned `TransparencyAnchor` |
|
|
137
|
+
| `verifyTransparencyDeclaration(declaration)` | function | Lower-level: verify a `SignedTransparencyDeclaration` from any source (cached, archived, fixture) |
|
|
138
|
+
| `verifiedStateExportFetch(url, opts)` | function | Wrap `fetch` — verify outer envelope against body bytes + optional anchor pin |
|
|
139
|
+
| `verifyManifestAgainstBytes(manifest, bodyBytes, anchor?)` | function | Lower-level: verify a parsed `ContentArtifactManifest` against bytes you already have |
|
|
140
|
+
| `verifyInnerSignedReceipts(body)` | function | Recursive v1.1 inner-receipt audit — per-receipt verdict with typed failure reasons |
|
|
141
|
+
| `verifyReceiptDocument(jsonText)` | function | Verify a pasted/standalone receipt offline — honest view model separating integrity from identity binding (powers receipt.computer) |
|
|
142
|
+
| `lookupTransparencyAnchor(opts)` | function | Onchain — query Solana RPC for a Memo program transaction posting the declaration hash |
|
|
143
|
+
| `verifyDeclarationOnchainAnchor(declaration, anchor)` | function | Onchain — verify the Memo transaction's signer and content match the declaration |
|
|
144
|
+
| `lookupIdentityLogAnchor(address, root, opts?)` | function | Onchain — confirm a transparency-log root sits on-chain at the pinned relay address (the `anchored` binding rung) |
|
|
145
|
+
| `lookupKeyRevocation(address, keyHex, opts?)` | function | Onchain — find a `motebit:revocation:v1:` memo revoking a signing key (the `revoked` poison verdict; read from the chain, not the relay) |
|
|
146
|
+
| `StateExportFetchError` | class | Thrown on non-2xx HTTP; verifier never attempts to verify error envelopes |
|
|
147
|
+
| `MANIFEST_HEADER` | constant | The header name (`"X-Motebit-Content-Manifest"`) — exposed for custom transports |
|
|
107
148
|
|
|
108
149
|
All result types (`TransparencyAnchorResult`, `StateExportVerification`, `InnerReceiptsVerification`, etc.) and failure-reason unions are also exported — discriminated unions, type-narrowable by the `ok` / `valid` / `applicable` field.
|
|
109
150
|
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* On-chain cross-check for the identity-transparency log root.
|
|
3
|
+
*
|
|
4
|
+
* The relay's `/identity` bundle carries a Merkle inclusion proof against an
|
|
5
|
+
* `anchoredRoot` it claims to have posted on-chain. `@motebit/crypto`'s
|
|
6
|
+
* `verifyIdentityBindingAnchored` proves the leaf is included under that root —
|
|
7
|
+
* but nothing stops a relay from fabricating a root it never anchored. This
|
|
8
|
+
* module closes that gap the same way `lookupTransparencyAnchor` closes the TOFU
|
|
9
|
+
* gap on the transparency declaration: scan the relay's pinned Solana address for
|
|
10
|
+
* a memo that actually carries that exact root.
|
|
11
|
+
*
|
|
12
|
+
* The relay anchors identity-log roots through the generic `ChainAnchorSubmitter`
|
|
13
|
+
* memo (`motebit:anchor:v1:{root}:{leafCount}`), shared with settlement and
|
|
14
|
+
* credential anchoring. Matching by the EXACT root value is sound across that
|
|
15
|
+
* shared stream: identity-binding leaves hash `{type:"motebit-identity-binding",
|
|
16
|
+
* …}`, so a root over them is domain-separated from any settlement/credential
|
|
17
|
+
* root and cannot collide. We don't need a dedicated memo prefix — only the root.
|
|
18
|
+
*
|
|
19
|
+
* The pinned `relayAnchorAddress` is the trust root: it MUST come from out-of-band
|
|
20
|
+
* (canonical config / docs site / a known motebit-org keyring), NEVER from the
|
|
21
|
+
* bundle itself — passing the relay's self-asserted address would be circular
|
|
22
|
+
* trust, the same caveat the transparency anchor carries.
|
|
23
|
+
*
|
|
24
|
+
* No SDK dep — Solana JSON-RPC is plain HTTP-JSON over `fetch`, keeping the
|
|
25
|
+
* package browser-safe and dep-thin. Mirrors `onchain-anchor.ts`.
|
|
26
|
+
*/
|
|
27
|
+
export interface IdentityAnchorLookupOptions {
|
|
28
|
+
/** Solana JSON-RPC endpoint. Defaults to mainnet-beta; pin a known-good RPC. */
|
|
29
|
+
readonly rpcUrl?: string;
|
|
30
|
+
/** Inject `fetch`. Defaults to global `fetch`; tests pass a mock. */
|
|
31
|
+
readonly fetch?: typeof globalThis.fetch;
|
|
32
|
+
/**
|
|
33
|
+
* Max signatures to scan at the anchor address. Identity-log anchors share the
|
|
34
|
+
* address with settlement/credential anchors, so the target root may be several
|
|
35
|
+
* memos back; default 200 covers a generous window of recent anchoring.
|
|
36
|
+
*/
|
|
37
|
+
readonly maxSignatures?: number;
|
|
38
|
+
}
|
|
39
|
+
export type IdentityAnchorResult = {
|
|
40
|
+
readonly ok: true;
|
|
41
|
+
readonly txHash: string;
|
|
42
|
+
readonly anchoredRoot: string;
|
|
43
|
+
readonly relayAnchorAddress: string;
|
|
44
|
+
} | {
|
|
45
|
+
readonly ok: false;
|
|
46
|
+
readonly reason: IdentityAnchorFailureReason;
|
|
47
|
+
readonly detail?: string;
|
|
48
|
+
};
|
|
49
|
+
export type IdentityAnchorFailureReason = "rpc_failed" | "root_not_anchored";
|
|
50
|
+
/**
|
|
51
|
+
* Confirm `expectedRootHex` was posted on-chain by the relay at
|
|
52
|
+
* `relayAnchorAddress`. Returns a typed result — never throws on verification
|
|
53
|
+
* failure; HTTP/transport errors surface as `rpc_failed`. A clean
|
|
54
|
+
* `root_not_anchored` means the scan completed but no `motebit:anchor` memo at the
|
|
55
|
+
* address carried that root (either never anchored, or beyond the scan window).
|
|
56
|
+
*
|
|
57
|
+
* The caller is expected to run this AFTER `verifyIdentityBindingAnchored` has
|
|
58
|
+
* confirmed the leaf is included under `expectedRootHex` — this adds the second
|
|
59
|
+
* trust channel (the root is really on-chain by the known relay) on top of the
|
|
60
|
+
* inclusion proof; it does not replace it.
|
|
61
|
+
*/
|
|
62
|
+
export declare function lookupIdentityLogAnchor(relayAnchorAddress: string, expectedRootHex: string, options?: IdentityAnchorLookupOptions): Promise<IdentityAnchorResult>;
|
|
63
|
+
//# sourceMappingURL=identity-anchor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity-anchor.d.ts","sourceRoot":"","sources":["../src/identity-anchor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAKH,MAAM,WAAW,2BAA2B;IAC1C,gFAAgF;IAChF,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,qEAAqE;IACrE,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IACzC;;;;OAIG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;CACjC;AAED,MAAM,MAAM,oBAAoB,GAC5B;IACE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAClB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;CACrC,GACD;IACE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IACnB,QAAQ,CAAC,MAAM,EAAE,2BAA2B,CAAC;IAC7C,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEN,MAAM,MAAM,2BAA2B,GAAG,YAAY,GAAG,mBAAmB,CAAC;AAiB7E;;;;;;;;;;;GAWG;AACH,wBAAsB,uBAAuB,CAC3C,kBAAkB,EAAE,MAAM,EAC1B,eAAe,EAAE,MAAM,EACvB,OAAO,GAAE,2BAAgC,GACxC,OAAO,CAAC,oBAAoB,CAAC,CAyD/B"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* On-chain cross-check for the identity-transparency log root.
|
|
3
|
+
*
|
|
4
|
+
* The relay's `/identity` bundle carries a Merkle inclusion proof against an
|
|
5
|
+
* `anchoredRoot` it claims to have posted on-chain. `@motebit/crypto`'s
|
|
6
|
+
* `verifyIdentityBindingAnchored` proves the leaf is included under that root —
|
|
7
|
+
* but nothing stops a relay from fabricating a root it never anchored. This
|
|
8
|
+
* module closes that gap the same way `lookupTransparencyAnchor` closes the TOFU
|
|
9
|
+
* gap on the transparency declaration: scan the relay's pinned Solana address for
|
|
10
|
+
* a memo that actually carries that exact root.
|
|
11
|
+
*
|
|
12
|
+
* The relay anchors identity-log roots through the generic `ChainAnchorSubmitter`
|
|
13
|
+
* memo (`motebit:anchor:v1:{root}:{leafCount}`), shared with settlement and
|
|
14
|
+
* credential anchoring. Matching by the EXACT root value is sound across that
|
|
15
|
+
* shared stream: identity-binding leaves hash `{type:"motebit-identity-binding",
|
|
16
|
+
* …}`, so a root over them is domain-separated from any settlement/credential
|
|
17
|
+
* root and cannot collide. We don't need a dedicated memo prefix — only the root.
|
|
18
|
+
*
|
|
19
|
+
* The pinned `relayAnchorAddress` is the trust root: it MUST come from out-of-band
|
|
20
|
+
* (canonical config / docs site / a known motebit-org keyring), NEVER from the
|
|
21
|
+
* bundle itself — passing the relay's self-asserted address would be circular
|
|
22
|
+
* trust, the same caveat the transparency anchor carries.
|
|
23
|
+
*
|
|
24
|
+
* No SDK dep — Solana JSON-RPC is plain HTTP-JSON over `fetch`, keeping the
|
|
25
|
+
* package browser-safe and dep-thin. Mirrors `onchain-anchor.ts`.
|
|
26
|
+
*/
|
|
27
|
+
/** The generic anchor-memo prefix the relay's ChainAnchorSubmitter emits. */
|
|
28
|
+
const ANCHOR_MEMO_PREFIX = "motebit:anchor:v1:";
|
|
29
|
+
/**
|
|
30
|
+
* Confirm `expectedRootHex` was posted on-chain by the relay at
|
|
31
|
+
* `relayAnchorAddress`. Returns a typed result — never throws on verification
|
|
32
|
+
* failure; HTTP/transport errors surface as `rpc_failed`. A clean
|
|
33
|
+
* `root_not_anchored` means the scan completed but no `motebit:anchor` memo at the
|
|
34
|
+
* address carried that root (either never anchored, or beyond the scan window).
|
|
35
|
+
*
|
|
36
|
+
* The caller is expected to run this AFTER `verifyIdentityBindingAnchored` has
|
|
37
|
+
* confirmed the leaf is included under `expectedRootHex` — this adds the second
|
|
38
|
+
* trust channel (the root is really on-chain by the known relay) on top of the
|
|
39
|
+
* inclusion proof; it does not replace it.
|
|
40
|
+
*/
|
|
41
|
+
export async function lookupIdentityLogAnchor(relayAnchorAddress, expectedRootHex, options = {}) {
|
|
42
|
+
const rpcUrl = options.rpcUrl ?? "https://api.mainnet-beta.solana.com";
|
|
43
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
44
|
+
const limit = options.maxSignatures ?? 200;
|
|
45
|
+
const target = expectedRootHex.toLowerCase();
|
|
46
|
+
let signatures;
|
|
47
|
+
try {
|
|
48
|
+
const res = await fetchImpl(rpcUrl, {
|
|
49
|
+
method: "POST",
|
|
50
|
+
headers: { "Content-Type": "application/json" },
|
|
51
|
+
body: JSON.stringify({
|
|
52
|
+
jsonrpc: "2.0",
|
|
53
|
+
id: 1,
|
|
54
|
+
method: "getSignaturesForAddress",
|
|
55
|
+
params: [relayAnchorAddress, { limit }],
|
|
56
|
+
}),
|
|
57
|
+
});
|
|
58
|
+
if (!res.ok) {
|
|
59
|
+
return { ok: false, reason: "rpc_failed", detail: `HTTP ${res.status}` };
|
|
60
|
+
}
|
|
61
|
+
const body = (await res.json());
|
|
62
|
+
if (body.error !== undefined) {
|
|
63
|
+
return { ok: false, reason: "rpc_failed", detail: body.error.message };
|
|
64
|
+
}
|
|
65
|
+
signatures = body.result ?? [];
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
return {
|
|
69
|
+
ok: false,
|
|
70
|
+
reason: "rpc_failed",
|
|
71
|
+
detail: err instanceof Error ? err.message : String(err),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
for (const sig of signatures) {
|
|
75
|
+
if (sig.err !== null)
|
|
76
|
+
continue; // skip failed txs
|
|
77
|
+
if (sig.memo == null)
|
|
78
|
+
continue;
|
|
79
|
+
// Solana RPC formats memo as `[<size> (len <bytes>)] <utf-8>`; match the
|
|
80
|
+
// canonical prefix anywhere in the formatted string (robust across RPC
|
|
81
|
+
// versions), then read the 64-hex root that immediately follows it.
|
|
82
|
+
const idx = sig.memo.indexOf(ANCHOR_MEMO_PREFIX);
|
|
83
|
+
if (idx === -1)
|
|
84
|
+
continue;
|
|
85
|
+
const after = sig.memo.slice(idx + ANCHOR_MEMO_PREFIX.length);
|
|
86
|
+
const rootMatch = after.match(/^([0-9a-fA-F]{64})/);
|
|
87
|
+
if (rootMatch == null)
|
|
88
|
+
continue;
|
|
89
|
+
if (rootMatch[1].toLowerCase() === target) {
|
|
90
|
+
return { ok: true, txHash: sig.signature, anchoredRoot: target, relayAnchorAddress };
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
ok: false,
|
|
95
|
+
reason: "root_not_anchored",
|
|
96
|
+
detail: `scanned ${signatures.length} signature(s) at ${relayAnchorAddress}, none carried root ${target}`,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=identity-anchor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity-anchor.js","sourceRoot":"","sources":["../src/identity-anchor.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -48,6 +48,12 @@ export { verifiedStateExportFetch, verifyManifestAgainstBytes, StateExportFetchE
|
|
|
48
48
|
export type { StateExportVerification, StateExportVerificationFailureReason, VerifiedFetchOptions, VerifiedStateExportResponse, } from "./verified-fetch.js";
|
|
49
49
|
export { lookupTransparencyAnchor, verifyDeclarationOnchainAnchor } from "./onchain-anchor.js";
|
|
50
50
|
export type { OnchainAnchorLookupOptions, OnchainAnchorResult, OnchainAnchorFailureReason, } from "./onchain-anchor.js";
|
|
51
|
+
export { lookupIdentityLogAnchor } from "./identity-anchor.js";
|
|
52
|
+
export type { IdentityAnchorLookupOptions, IdentityAnchorResult, IdentityAnchorFailureReason, } from "./identity-anchor.js";
|
|
53
|
+
export { lookupKeyRevocation } from "./key-revocation.js";
|
|
54
|
+
export type { KeyRevocationLookupOptions, KeyRevocationResult } from "./key-revocation.js";
|
|
51
55
|
export { verifyInnerSignedReceipts } from "./inner-receipts.js";
|
|
52
56
|
export type { InnerReceiptVerification, InnerReceiptVerificationFailureReason, InnerReceiptsVerification, } from "./inner-receipts.js";
|
|
57
|
+
export { verifyReceiptDocument } from "./receipt-document.js";
|
|
58
|
+
export type { ReceiptDocumentVerification, ReceiptDocumentFailureReason, ReceiptBindingStatus, ReceiptAnchorOptions, VerifyReceiptDocumentOptions, } from "./receipt-document.js";
|
|
53
59
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAEH,OAAO,EAAE,uBAAuB,EAAE,6BAA6B,EAAE,MAAM,0BAA0B,CAAC;AAClG,YAAY,EACV,kBAAkB,EAClB,6BAA6B,EAC7B,wBAAwB,EACxB,+BAA+B,EAC/B,8BAA8B,GAC/B,MAAM,0BAA0B,CAAC;AAElC,OAAO,EACL,wBAAwB,EACxB,0BAA0B,EAC1B,qBAAqB,EACrB,eAAe,GAChB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EACV,uBAAuB,EACvB,oCAAoC,EACpC,oBAAoB,EACpB,2BAA2B,GAC5B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,wBAAwB,EAAE,8BAA8B,EAAE,MAAM,qBAAqB,CAAC;AAC/F,YAAY,EACV,0BAA0B,EAC1B,mBAAmB,EACnB,0BAA0B,GAC3B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAChE,YAAY,EACV,wBAAwB,EACxB,qCAAqC,EACrC,yBAAyB,GAC1B,MAAM,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAEH,OAAO,EAAE,uBAAuB,EAAE,6BAA6B,EAAE,MAAM,0BAA0B,CAAC;AAClG,YAAY,EACV,kBAAkB,EAClB,6BAA6B,EAC7B,wBAAwB,EACxB,+BAA+B,EAC/B,8BAA8B,GAC/B,MAAM,0BAA0B,CAAC;AAElC,OAAO,EACL,wBAAwB,EACxB,0BAA0B,EAC1B,qBAAqB,EACrB,eAAe,GAChB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EACV,uBAAuB,EACvB,oCAAoC,EACpC,oBAAoB,EACpB,2BAA2B,GAC5B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,wBAAwB,EAAE,8BAA8B,EAAE,MAAM,qBAAqB,CAAC;AAC/F,YAAY,EACV,0BAA0B,EAC1B,mBAAmB,EACnB,0BAA0B,GAC3B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,YAAY,EACV,2BAA2B,EAC3B,oBAAoB,EACpB,2BAA2B,GAC5B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,YAAY,EAAE,0BAA0B,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE3F,OAAO,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAChE,YAAY,EACV,wBAAwB,EACxB,qCAAqC,EACrC,yBAAyB,GAC1B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,YAAY,EACV,2BAA2B,EAC3B,4BAA4B,EAC5B,oBAAoB,EACpB,oBAAoB,EACpB,4BAA4B,GAC7B,MAAM,uBAAuB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -45,5 +45,8 @@
|
|
|
45
45
|
export { fetchTransparencyAnchor, verifyTransparencyDeclaration } from "./transparency-anchor.js";
|
|
46
46
|
export { verifiedStateExportFetch, verifyManifestAgainstBytes, StateExportFetchError, MANIFEST_HEADER, } from "./verified-fetch.js";
|
|
47
47
|
export { lookupTransparencyAnchor, verifyDeclarationOnchainAnchor } from "./onchain-anchor.js";
|
|
48
|
+
export { lookupIdentityLogAnchor } from "./identity-anchor.js";
|
|
49
|
+
export { lookupKeyRevocation } from "./key-revocation.js";
|
|
48
50
|
export { verifyInnerSignedReceipts } from "./inner-receipts.js";
|
|
51
|
+
export { verifyReceiptDocument } from "./receipt-document.js";
|
|
49
52
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAEH,OAAO,EAAE,uBAAuB,EAAE,6BAA6B,EAAE,MAAM,0BAA0B,CAAC;AASlG,OAAO,EACL,wBAAwB,EACxB,0BAA0B,EAC1B,qBAAqB,EACrB,eAAe,GAChB,MAAM,qBAAqB,CAAC;AAQ7B,OAAO,EAAE,wBAAwB,EAAE,8BAA8B,EAAE,MAAM,qBAAqB,CAAC;AAO/F,OAAO,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAEH,OAAO,EAAE,uBAAuB,EAAE,6BAA6B,EAAE,MAAM,0BAA0B,CAAC;AASlG,OAAO,EACL,wBAAwB,EACxB,0BAA0B,EAC1B,qBAAqB,EACrB,eAAe,GAChB,MAAM,qBAAqB,CAAC;AAQ7B,OAAO,EAAE,wBAAwB,EAAE,8BAA8B,EAAE,MAAM,qBAAqB,CAAC;AAO/F,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAO/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAG1D,OAAO,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAOhE,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC"}
|
package/dist/inner-receipts.d.ts
CHANGED
|
@@ -25,12 +25,28 @@
|
|
|
25
25
|
export interface InnerReceiptVerification {
|
|
26
26
|
/** Task identifier of the inner receipt. Pulled from the parsed receipt body. */
|
|
27
27
|
readonly taskId: string;
|
|
28
|
-
/**
|
|
28
|
+
/**
|
|
29
|
+
* The producing motebit's identifier as carried in the receipt body.
|
|
30
|
+
* NOTE: a valid signature proves the embedded key signed these bytes, NOT
|
|
31
|
+
* that the key belongs to this `motebitId` — see `identityBinding`.
|
|
32
|
+
*/
|
|
29
33
|
readonly motebitId: string;
|
|
30
34
|
/** `did:key:zXXX` derived from the receipt's embedded public key when verification succeeded. */
|
|
31
35
|
readonly signerDid?: string;
|
|
32
36
|
/** Whether the inner receipt's signature verifies against its embedded `public_key`. */
|
|
33
37
|
readonly valid: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Identity-binding status of a *successful* signature check. Always
|
|
40
|
+
* `"embedded-key-unverified"` on this path: the signature is checked
|
|
41
|
+
* against the receipt's own `public_key`, which proves byte-integrity but
|
|
42
|
+
* NOT that the key belongs to `motebitId`. Establishing binding requires
|
|
43
|
+
* an external anchor (the relay's pinned transparency key / a known-keys
|
|
44
|
+
* map). Callers MUST NOT render this as "from <motebit>" without an anchor
|
|
45
|
+
* — mirrors the content-artifact path's `producer_key_mismatch` discipline
|
|
46
|
+
* (see package CLAUDE.md "Why the trust anchor is necessary"). Absent on
|
|
47
|
+
* failures.
|
|
48
|
+
*/
|
|
49
|
+
readonly identityBinding?: "embedded-key-unverified";
|
|
34
50
|
/** Typed failure reason when `valid === false`. */
|
|
35
51
|
readonly reason?: InnerReceiptVerificationFailureReason;
|
|
36
52
|
/** Free-form detail (e.g. underlying error message). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inner-receipts.d.ts","sourceRoot":"","sources":["../src/inner-receipts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAMH,uEAAuE;AACvE,MAAM,WAAW,wBAAwB;IACvC,iFAAiF;IACjF,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB
|
|
1
|
+
{"version":3,"file":"inner-receipts.d.ts","sourceRoot":"","sources":["../src/inner-receipts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAMH,uEAAuE;AACvE,MAAM,WAAW,wBAAwB;IACvC,iFAAiF;IACjF,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,iGAAiG;IACjG,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,wFAAwF;IACxF,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,yBAAyB,CAAC;IACrD,mDAAmD;IACnD,QAAQ,CAAC,MAAM,CAAC,EAAE,qCAAqC,CAAC;IACxD,wDAAwD;IACxD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,uGAAuG;IACvG,QAAQ,CAAC,WAAW,CAAC,EAAE,wBAAwB,EAAE,CAAC;CACnD;AAED,MAAM,MAAM,qCAAqC,GAC7C,gBAAgB,GAChB,oBAAoB,GACpB,mBAAmB,GACnB,mBAAmB,GACnB,SAAS,CAAC;AAEd,oFAAoF;AACpF,MAAM,WAAW,yBAAyB;IACxC,uFAAuF;IACvF,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,yDAAyD;IACzD,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,kGAAkG;IAClG,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,+EAA+E;IAC/E,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,wBAAwB,CAAC,CAAC;IAC1D,+FAA+F;IAC/F,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;CAC9B;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,yBAAyB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAkCjG"}
|
package/dist/inner-receipts.js
CHANGED
|
@@ -96,6 +96,9 @@ async function verifyOneInner(entryJson) {
|
|
|
96
96
|
motebitId: String(receipt.motebit_id),
|
|
97
97
|
...(result.signer !== undefined && { signerDid: result.signer }),
|
|
98
98
|
valid: true,
|
|
99
|
+
...(result.keySource === "embedded" && {
|
|
100
|
+
identityBinding: "embedded-key-unverified",
|
|
101
|
+
}),
|
|
99
102
|
...(result.delegations !== undefined && result.delegations.length > 0
|
|
100
103
|
? { delegations: result.delegations.map(toInnerShape) }
|
|
101
104
|
: {}),
|
|
@@ -151,6 +154,8 @@ function toInnerShape(r) {
|
|
|
151
154
|
motebitId: String(r.receipt?.motebit_id ?? "<unknown>"),
|
|
152
155
|
...(r.signer !== undefined && { signerDid: r.signer }),
|
|
153
156
|
valid: r.valid,
|
|
157
|
+
...(r.valid &&
|
|
158
|
+
r.keySource === "embedded" && { identityBinding: "embedded-key-unverified" }),
|
|
154
159
|
...(reason !== undefined && { reason }),
|
|
155
160
|
...(errs[0]?.message !== undefined && !r.valid && { detail: errs[0].message }),
|
|
156
161
|
...(r.delegations !== undefined && r.delegations.length > 0
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inner-receipts.js","sourceRoot":"","sources":["../src/inner-receipts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAGH,OAAO,EAAE,0BAA0B,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"inner-receipts.js","sourceRoot":"","sources":["../src/inner-receipts.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* On-chain key-revocation lookup — the binding-time consumer of the relay's
|
|
3
|
+
* revocation memos.
|
|
4
|
+
*
|
|
5
|
+
* When a key is rotated away or an agent is revoked, the relay anchors a
|
|
6
|
+
* `motebit:revocation:v1:{keyHex}:{timestamp}` memo on Solana
|
|
7
|
+
* (`SolanaMemoSubmitter.submitRevocation`). This module reads those memos so a
|
|
8
|
+
* verifier can refuse to bind a receipt signed by a key that was revoked at or
|
|
9
|
+
* before the receipt's timestamp.
|
|
10
|
+
*
|
|
11
|
+
* The trust asymmetry vs. the anchored rung is the whole point: a relay can't
|
|
12
|
+
* forge an anchored root, but it COULD hide a revocation that protects it (a key
|
|
13
|
+
* it secretly controls). So revocation must be read from the neutral chain at the
|
|
14
|
+
* relay's pinned address — never taken from the relay's own `/identity` response.
|
|
15
|
+
* `revoked_at` is whatever timestamp the memo carries; if the operator backdates
|
|
16
|
+
* it to the true compromise moment, this consumer honors that automatically.
|
|
17
|
+
*
|
|
18
|
+
* No SDK dep — Solana JSON-RPC over fetch keeps the package browser-safe. Mirrors
|
|
19
|
+
* `identity-anchor.ts` / `onchain-anchor.ts`.
|
|
20
|
+
*/
|
|
21
|
+
export interface KeyRevocationLookupOptions {
|
|
22
|
+
readonly rpcUrl?: string;
|
|
23
|
+
readonly fetch?: typeof globalThis.fetch;
|
|
24
|
+
/** Max signatures to scan at the relay address. Default 200. */
|
|
25
|
+
readonly maxSignatures?: number;
|
|
26
|
+
}
|
|
27
|
+
export type KeyRevocationResult =
|
|
28
|
+
/** A revocation memo for this key was found on-chain. `revokedAt` is its timestamp (ms). */
|
|
29
|
+
{
|
|
30
|
+
readonly status: "revoked";
|
|
31
|
+
readonly revokedAt: number;
|
|
32
|
+
readonly txHash: string;
|
|
33
|
+
}
|
|
34
|
+
/** Scan completed; no revocation memo for this key at the address. */
|
|
35
|
+
| {
|
|
36
|
+
readonly status: "not_revoked";
|
|
37
|
+
}
|
|
38
|
+
/** Could not determine (RPC/transport failure) — NOT proof of safety. */
|
|
39
|
+
| {
|
|
40
|
+
readonly status: "unknown";
|
|
41
|
+
readonly detail: string;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Look up whether `signingKeyHex` has an on-chain revocation memo at the relay's
|
|
45
|
+
* pinned address. Returns the EARLIEST revocation timestamp found (the most
|
|
46
|
+
* protective — a key revoked at T cannot be trusted for anything dated ≥ T).
|
|
47
|
+
* Never throws; transport/RPC failures surface as `status: "unknown"`.
|
|
48
|
+
*/
|
|
49
|
+
export declare function lookupKeyRevocation(relayAnchorAddress: string, signingKeyHex: string, options?: KeyRevocationLookupOptions): Promise<KeyRevocationResult>;
|
|
50
|
+
//# sourceMappingURL=key-revocation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"key-revocation.d.ts","sourceRoot":"","sources":["../src/key-revocation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAIH,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IACzC,gEAAgE;IAChE,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;CACjC;AAED,MAAM,MAAM,mBAAmB;AAC7B,4FAA4F;AAC1F;IAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE;AACrF,sEAAsE;GACpE;IAAE,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAA;CAAE;AACpC,yEAAyE;GACvE;IAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAiB5D;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,kBAAkB,EAAE,MAAM,EAC1B,aAAa,EAAE,MAAM,EACrB,OAAO,GAAE,0BAA+B,GACvC,OAAO,CAAC,mBAAmB,CAAC,CA6C9B"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* On-chain key-revocation lookup — the binding-time consumer of the relay's
|
|
3
|
+
* revocation memos.
|
|
4
|
+
*
|
|
5
|
+
* When a key is rotated away or an agent is revoked, the relay anchors a
|
|
6
|
+
* `motebit:revocation:v1:{keyHex}:{timestamp}` memo on Solana
|
|
7
|
+
* (`SolanaMemoSubmitter.submitRevocation`). This module reads those memos so a
|
|
8
|
+
* verifier can refuse to bind a receipt signed by a key that was revoked at or
|
|
9
|
+
* before the receipt's timestamp.
|
|
10
|
+
*
|
|
11
|
+
* The trust asymmetry vs. the anchored rung is the whole point: a relay can't
|
|
12
|
+
* forge an anchored root, but it COULD hide a revocation that protects it (a key
|
|
13
|
+
* it secretly controls). So revocation must be read from the neutral chain at the
|
|
14
|
+
* relay's pinned address — never taken from the relay's own `/identity` response.
|
|
15
|
+
* `revoked_at` is whatever timestamp the memo carries; if the operator backdates
|
|
16
|
+
* it to the true compromise moment, this consumer honors that automatically.
|
|
17
|
+
*
|
|
18
|
+
* No SDK dep — Solana JSON-RPC over fetch keeps the package browser-safe. Mirrors
|
|
19
|
+
* `identity-anchor.ts` / `onchain-anchor.ts`.
|
|
20
|
+
*/
|
|
21
|
+
const REVOCATION_MEMO_PREFIX = "motebit:revocation:v1:";
|
|
22
|
+
/**
|
|
23
|
+
* Look up whether `signingKeyHex` has an on-chain revocation memo at the relay's
|
|
24
|
+
* pinned address. Returns the EARLIEST revocation timestamp found (the most
|
|
25
|
+
* protective — a key revoked at T cannot be trusted for anything dated ≥ T).
|
|
26
|
+
* Never throws; transport/RPC failures surface as `status: "unknown"`.
|
|
27
|
+
*/
|
|
28
|
+
export async function lookupKeyRevocation(relayAnchorAddress, signingKeyHex, options = {}) {
|
|
29
|
+
const rpcUrl = options.rpcUrl ?? "https://api.mainnet-beta.solana.com";
|
|
30
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
31
|
+
const limit = options.maxSignatures ?? 200;
|
|
32
|
+
const needle = `${REVOCATION_MEMO_PREFIX}${signingKeyHex.toLowerCase()}:`;
|
|
33
|
+
let signatures;
|
|
34
|
+
try {
|
|
35
|
+
const res = await fetchImpl(rpcUrl, {
|
|
36
|
+
method: "POST",
|
|
37
|
+
headers: { "Content-Type": "application/json" },
|
|
38
|
+
body: JSON.stringify({
|
|
39
|
+
jsonrpc: "2.0",
|
|
40
|
+
id: 1,
|
|
41
|
+
method: "getSignaturesForAddress",
|
|
42
|
+
params: [relayAnchorAddress, { limit }],
|
|
43
|
+
}),
|
|
44
|
+
});
|
|
45
|
+
if (!res.ok)
|
|
46
|
+
return { status: "unknown", detail: `HTTP ${res.status}` };
|
|
47
|
+
const body = (await res.json());
|
|
48
|
+
if (body.error !== undefined)
|
|
49
|
+
return { status: "unknown", detail: body.error.message };
|
|
50
|
+
signatures = body.result ?? [];
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
return { status: "unknown", detail: err instanceof Error ? err.message : String(err) };
|
|
54
|
+
}
|
|
55
|
+
let earliest = null;
|
|
56
|
+
for (const sig of signatures) {
|
|
57
|
+
if (sig.err !== null)
|
|
58
|
+
continue;
|
|
59
|
+
if (sig.memo == null)
|
|
60
|
+
continue;
|
|
61
|
+
const idx = sig.memo.toLowerCase().indexOf(needle);
|
|
62
|
+
if (idx === -1)
|
|
63
|
+
continue;
|
|
64
|
+
const after = sig.memo.slice(idx + needle.length);
|
|
65
|
+
const tsMatch = after.match(/^(\d+)/);
|
|
66
|
+
if (tsMatch == null)
|
|
67
|
+
continue;
|
|
68
|
+
const revokedAt = Number(tsMatch[1]);
|
|
69
|
+
if (!Number.isFinite(revokedAt))
|
|
70
|
+
continue;
|
|
71
|
+
if (earliest == null || revokedAt < earliest.revokedAt) {
|
|
72
|
+
earliest = { revokedAt, txHash: sig.signature };
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return earliest
|
|
76
|
+
? { status: "revoked", revokedAt: earliest.revokedAt, txHash: earliest.txHash }
|
|
77
|
+
: { status: "not_revoked" };
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=key-revocation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"key-revocation.js","sourceRoot":"","sources":["../src/key-revocation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verify a pasted/standalone `ExecutionReceipt` document and project it into an
|
|
3
|
+
* honest, display-ready view model — the brain behind a public receipt verifier
|
|
4
|
+
* (e.g. receipt.computer): paste a receipt, learn what it actually proves.
|
|
5
|
+
*
|
|
6
|
+
* The model's whole point is to keep two facts separate, the way the rest of the
|
|
7
|
+
* stack now does (crypto `keySource`, render-engine `bindingStatusFor`):
|
|
8
|
+
*
|
|
9
|
+
* - INTEGRITY — "the bytes were signed by *some* key and nothing was tampered."
|
|
10
|
+
* Always checkable offline from the receipt alone.
|
|
11
|
+
* - BINDING — "that key belongs to the claimed `motebit_id`." Established only
|
|
12
|
+
* when the verifying key came from a trusted external source, never from the
|
|
13
|
+
* receipt's own embedded `public_key`.
|
|
14
|
+
*
|
|
15
|
+
* Verified against the receipt's embedded key alone (offline, no options), a
|
|
16
|
+
* successful check is `integrity-only`: it never claims identity binding. Supply
|
|
17
|
+
* `options.identity` to reach `"pinned"` (the signing key is time-valid in the
|
|
18
|
+
* motebit's own succession chain), and additionally `options.anchor` to reach
|
|
19
|
+
* `"anchored"` (that binding is in the relay's transparency log AND the log root
|
|
20
|
+
* is independently confirmed on-chain). Callers branch on `binding`, not
|
|
21
|
+
* `integrity`, before rendering "from <motebit>".
|
|
22
|
+
*
|
|
23
|
+
* Browser-safe; composes `@motebit/crypto` verifiers + an injectable on-chain
|
|
24
|
+
* lookup — no new crypto here.
|
|
25
|
+
*
|
|
26
|
+
* Doctrine: `docs/doctrine/self-attesting-system.md`, `docs/doctrine/operator-transparency.md`.
|
|
27
|
+
*/
|
|
28
|
+
import { type IdentityLogInclusionProof, type MotebitIdentityFile } from "@motebit/crypto";
|
|
29
|
+
import { type IdentityAnchorLookupOptions } from "./identity-anchor.js";
|
|
30
|
+
import { type KeyRevocationLookupOptions } from "./key-revocation.js";
|
|
31
|
+
/**
|
|
32
|
+
* Identity-binding status — a ladder of increasing trust-minimization, per
|
|
33
|
+
* `docs/doctrine/identity-binding-verification.md`. `"unverified"` (signature
|
|
34
|
+
* failed) < `"integrity-only"` (signed, but checked against the receipt's own
|
|
35
|
+
* embedded key — not bound) < `"pinned"` (the signing key is time-valid for an
|
|
36
|
+
* identity file the caller supplied; sovereign chain verified, no operator
|
|
37
|
+
* anchor) < `"anchored"` (the motebit's key is committed in the relay's
|
|
38
|
+
* identity-transparency log AND that log root is independently confirmed on-chain
|
|
39
|
+
* — operator non-equivocation) < `"sovereign"` (the `motebit_id` IS the commitment
|
|
40
|
+
* to the genesis key, verified offline from the identity file alone — no operator,
|
|
41
|
+
* no anchor, no chain; the strongest root).
|
|
42
|
+
*
|
|
43
|
+
* `"revoked"` is off the ladder — a poison verdict. The signature may be valid,
|
|
44
|
+
* but the signing key was revoked on-chain at/before the receipt's timestamp, so
|
|
45
|
+
* the producer claim must NOT be trusted. It overrides every other status.
|
|
46
|
+
*/
|
|
47
|
+
export type ReceiptBindingStatus = "revoked" | "sovereign" | "anchored" | "pinned" | "integrity-only" | "unverified";
|
|
48
|
+
export type ReceiptDocumentFailureReason = "malformed_json" | "not_a_receipt" | "missing_public_key" | "signature_invalid" | "delegation_failed" | "unknown";
|
|
49
|
+
/** Honest, recursive view model for a verified (or rejected) receipt document. */
|
|
50
|
+
export interface ReceiptDocumentVerification {
|
|
51
|
+
/**
|
|
52
|
+
* True iff the signature verified (and every delegation verified) — INTEGRITY.
|
|
53
|
+
* A `true` here does NOT mean the key belongs to `motebitId`; read `binding`.
|
|
54
|
+
*/
|
|
55
|
+
readonly integrity: boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Identity-binding status (the ladder). `"anchored"` when the binding is in the
|
|
58
|
+
* relay's transparency log AND that root is confirmed on-chain; `"pinned"` when
|
|
59
|
+
* the signing key is time-valid for a caller-supplied identity file;
|
|
60
|
+
* `"integrity-only"` when only the signature is verified against the receipt's
|
|
61
|
+
* own embedded key; `"unverified"` when the signature did not verify. Surfaces
|
|
62
|
+
* MUST NOT render "from <motebit>" below `"pinned"`.
|
|
63
|
+
*/
|
|
64
|
+
readonly binding: ReceiptBindingStatus;
|
|
65
|
+
/** The Solana tx that anchored the log root, when `binding === "anchored"`. */
|
|
66
|
+
readonly anchorTxHash?: string;
|
|
67
|
+
/** When `binding === "revoked"`: the on-chain revocation timestamp (ms). */
|
|
68
|
+
readonly revokedAt?: number;
|
|
69
|
+
/** `did:key:z…` derived from the signing key when integrity holds. */
|
|
70
|
+
readonly signerDid?: string;
|
|
71
|
+
/** The producing `motebit_id` as carried in the receipt body — a claim, not proof. */
|
|
72
|
+
readonly motebitId?: string;
|
|
73
|
+
readonly taskId?: string;
|
|
74
|
+
/** Per-delegation results, recursive — mirrors the delegation chain. */
|
|
75
|
+
readonly delegations?: ReceiptDocumentVerification[];
|
|
76
|
+
/** Typed failure reason when `integrity` is false. */
|
|
77
|
+
readonly reason?: ReceiptDocumentFailureReason;
|
|
78
|
+
/** Free-form detail (e.g. underlying error message). */
|
|
79
|
+
readonly detail?: string;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Material for the `anchored` rung: the relay's identity-transparency inclusion
|
|
83
|
+
* proof plus the out-of-band pinned relay Solana address to cross-check it
|
|
84
|
+
* against. Both come from the relay's `/identity/:motebitId` bundle EXCEPT
|
|
85
|
+
* `relayAnchorAddress`, which MUST be pinned independently (not taken from the
|
|
86
|
+
* bundle) — that's the trust root that makes the on-chain check non-circular.
|
|
87
|
+
*/
|
|
88
|
+
export interface ReceiptAnchorOptions {
|
|
89
|
+
/** The relay bundle's `anchored.proof` — its `anchoredRoot` is checked on-chain. */
|
|
90
|
+
readonly proof: IdentityLogInclusionProof;
|
|
91
|
+
/** Pinned relay Solana address (out-of-band trust root). */
|
|
92
|
+
readonly relayAnchorAddress: string;
|
|
93
|
+
/** Solana RPC / fetch injection for the on-chain lookup. */
|
|
94
|
+
readonly lookup?: IdentityAnchorLookupOptions;
|
|
95
|
+
}
|
|
96
|
+
export interface VerifyReceiptDocumentOptions {
|
|
97
|
+
/**
|
|
98
|
+
* The producing motebit's identity file (its self-signed succession material).
|
|
99
|
+
* When supplied, and the receipt's signing key is time-valid for it (and the
|
|
100
|
+
* `motebit_id` matches), the result's root upgrades to `binding: "pinned"` —
|
|
101
|
+
* verified against material the caller supplied. The `anchored` / `sovereign`
|
|
102
|
+
* rungs layer operator non-equivocation on top; see
|
|
103
|
+
* `docs/doctrine/identity-binding-verification.md`.
|
|
104
|
+
*/
|
|
105
|
+
readonly identity?: MotebitIdentityFile;
|
|
106
|
+
/**
|
|
107
|
+
* Anchor material. Requires `identity` too — `anchored` is `pinned` PLUS an
|
|
108
|
+
* on-chain-confirmed transparency-log inclusion. When the inclusion proof and
|
|
109
|
+
* the on-chain root cross-check both pass, the root upgrades to
|
|
110
|
+
* `binding: "anchored"`; otherwise it degrades honestly to `pinned` /
|
|
111
|
+
* `integrity-only`.
|
|
112
|
+
*/
|
|
113
|
+
readonly anchor?: ReceiptAnchorOptions;
|
|
114
|
+
/**
|
|
115
|
+
* On-chain revocation check. The signing key is scanned for a revocation memo
|
|
116
|
+
* at the relay's pinned address (read from the neutral chain, NOT the relay's
|
|
117
|
+
* word — the relay could hide a revocation that protects it). If the key was
|
|
118
|
+
* revoked at/before the receipt's `completed_at`, `binding` is `"revoked"`,
|
|
119
|
+
* overriding every other rung. Requires no `identity` — a revoked key poisons
|
|
120
|
+
* even the integrity-only claim.
|
|
121
|
+
*/
|
|
122
|
+
readonly revocation?: {
|
|
123
|
+
readonly relayAnchorAddress: string;
|
|
124
|
+
readonly lookup?: KeyRevocationLookupOptions;
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Verify a pasted receipt document (JSON text) entirely offline. Returns a typed
|
|
129
|
+
* view model; never throws on bad input or a crypto failure — only `JSON.parse`
|
|
130
|
+
* and shape errors map to `malformed_json` / `not_a_receipt`. Pass
|
|
131
|
+
* `options.identity` to attempt the `"pinned"` binding rung.
|
|
132
|
+
*/
|
|
133
|
+
export declare function verifyReceiptDocument(jsonText: string, options?: VerifyReceiptDocumentOptions): Promise<ReceiptDocumentVerification>;
|
|
134
|
+
//# sourceMappingURL=receipt-document.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"receipt-document.d.ts","sourceRoot":"","sources":["../src/receipt-document.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAGH,OAAO,EAIL,KAAK,yBAAyB,EAC9B,KAAK,mBAAmB,EACzB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAA2B,KAAK,2BAA2B,EAAE,MAAM,sBAAsB,CAAC;AACjG,OAAO,EAAuB,KAAK,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AAE3F;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,oBAAoB,GAC5B,SAAS,GACT,WAAW,GACX,UAAU,GACV,QAAQ,GACR,gBAAgB,GAChB,YAAY,CAAC;AAEjB,MAAM,MAAM,4BAA4B,GACpC,gBAAgB,GAChB,eAAe,GACf,oBAAoB,GACpB,mBAAmB,GACnB,mBAAmB,GACnB,SAAS,CAAC;AAEd,kFAAkF;AAClF,MAAM,WAAW,2BAA2B;IAC1C;;;OAGG;IACH,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B;;;;;;;OAOG;IACH,QAAQ,CAAC,OAAO,EAAE,oBAAoB,CAAC;IACvC,+EAA+E;IAC/E,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,4EAA4E;IAC5E,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,sEAAsE;IACtE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,sFAAsF;IACtF,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,wEAAwE;IACxE,QAAQ,CAAC,WAAW,CAAC,EAAE,2BAA2B,EAAE,CAAC;IACrD,sDAAsD;IACtD,QAAQ,CAAC,MAAM,CAAC,EAAE,4BAA4B,CAAC;IAC/C,wDAAwD;IACxD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AA8DD;;;;;;GAMG;AACH,MAAM,WAAW,oBAAoB;IACnC,oFAAoF;IACpF,QAAQ,CAAC,KAAK,EAAE,yBAAyB,CAAC;IAC1C,4DAA4D;IAC5D,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,4DAA4D;IAC5D,QAAQ,CAAC,MAAM,CAAC,EAAE,2BAA2B,CAAC;CAC/C;AAED,MAAM,WAAW,4BAA4B;IAC3C;;;;;;;OAOG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,mBAAmB,CAAC;IACxC;;;;;;OAMG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,oBAAoB,CAAC;IACvC;;;;;;;OAOG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE;QACpB,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;QACpC,QAAQ,CAAC,MAAM,CAAC,EAAE,0BAA0B,CAAC;KAC9C,CAAC;CACH;AAoED;;;;;GAKG;AACH,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,4BAA4B,GACrC,OAAO,CAAC,2BAA2B,CAAC,CAiDtC"}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verify a pasted/standalone `ExecutionReceipt` document and project it into an
|
|
3
|
+
* honest, display-ready view model — the brain behind a public receipt verifier
|
|
4
|
+
* (e.g. receipt.computer): paste a receipt, learn what it actually proves.
|
|
5
|
+
*
|
|
6
|
+
* The model's whole point is to keep two facts separate, the way the rest of the
|
|
7
|
+
* stack now does (crypto `keySource`, render-engine `bindingStatusFor`):
|
|
8
|
+
*
|
|
9
|
+
* - INTEGRITY — "the bytes were signed by *some* key and nothing was tampered."
|
|
10
|
+
* Always checkable offline from the receipt alone.
|
|
11
|
+
* - BINDING — "that key belongs to the claimed `motebit_id`." Established only
|
|
12
|
+
* when the verifying key came from a trusted external source, never from the
|
|
13
|
+
* receipt's own embedded `public_key`.
|
|
14
|
+
*
|
|
15
|
+
* Verified against the receipt's embedded key alone (offline, no options), a
|
|
16
|
+
* successful check is `integrity-only`: it never claims identity binding. Supply
|
|
17
|
+
* `options.identity` to reach `"pinned"` (the signing key is time-valid in the
|
|
18
|
+
* motebit's own succession chain), and additionally `options.anchor` to reach
|
|
19
|
+
* `"anchored"` (that binding is in the relay's transparency log AND the log root
|
|
20
|
+
* is independently confirmed on-chain). Callers branch on `binding`, not
|
|
21
|
+
* `integrity`, before rendering "from <motebit>".
|
|
22
|
+
*
|
|
23
|
+
* Browser-safe; composes `@motebit/crypto` verifiers + an injectable on-chain
|
|
24
|
+
* lookup — no new crypto here.
|
|
25
|
+
*
|
|
26
|
+
* Doctrine: `docs/doctrine/self-attesting-system.md`, `docs/doctrine/operator-transparency.md`.
|
|
27
|
+
*/
|
|
28
|
+
import { verifyReceipt, verifyKeyBindingAtTime, verifyIdentityBindingAnchored, } from "@motebit/crypto";
|
|
29
|
+
import { lookupIdentityLogAnchor } from "./identity-anchor.js";
|
|
30
|
+
import { lookupKeyRevocation } from "./key-revocation.js";
|
|
31
|
+
/**
|
|
32
|
+
* Minimal structural guard for user-pasted input. We verify at the boundary
|
|
33
|
+
* (untrusted text) before handing to crypto — a non-receipt object must surface
|
|
34
|
+
* as a typed `not_a_receipt`, never an opaque downstream throw.
|
|
35
|
+
*/
|
|
36
|
+
function isExecutionReceiptShape(value) {
|
|
37
|
+
if (typeof value !== "object" || value === null)
|
|
38
|
+
return false;
|
|
39
|
+
const r = value;
|
|
40
|
+
return (typeof r["motebit_id"] === "string" &&
|
|
41
|
+
typeof r["task_id"] === "string" &&
|
|
42
|
+
typeof r["signature"] === "string" &&
|
|
43
|
+
typeof r["suite"] === "string");
|
|
44
|
+
}
|
|
45
|
+
function toView(result) {
|
|
46
|
+
const errs = result.errors ?? [];
|
|
47
|
+
const base = {
|
|
48
|
+
integrity: result.valid,
|
|
49
|
+
// `verifyReceipt` checks the signature against the receipt's own embedded
|
|
50
|
+
// key, so on its own a valid check is integrity-only. `verifyReceiptDocument`
|
|
51
|
+
// upgrades the root to `"pinned"` when a matching identity file is supplied.
|
|
52
|
+
binding: result.valid ? "integrity-only" : "unverified",
|
|
53
|
+
};
|
|
54
|
+
if (result.signer !== undefined)
|
|
55
|
+
base.signerDid = result.signer;
|
|
56
|
+
if (result.receipt) {
|
|
57
|
+
base.motebitId = String(result.receipt.motebit_id);
|
|
58
|
+
base.taskId = result.receipt.task_id;
|
|
59
|
+
}
|
|
60
|
+
if (result.delegations && result.delegations.length > 0) {
|
|
61
|
+
base.delegations = result.delegations.map(toView);
|
|
62
|
+
}
|
|
63
|
+
if (!result.valid) {
|
|
64
|
+
if (errs.some((e) => e.message.includes("No embedded public_key"))) {
|
|
65
|
+
base.reason = "missing_public_key";
|
|
66
|
+
}
|
|
67
|
+
else if (errs.some((e) => e.path === "delegation_receipts")) {
|
|
68
|
+
base.reason = "delegation_failed";
|
|
69
|
+
}
|
|
70
|
+
else if (errs.length > 0) {
|
|
71
|
+
base.reason = "signature_invalid";
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
base.reason = "unknown";
|
|
75
|
+
}
|
|
76
|
+
const detail = errs[0]?.message;
|
|
77
|
+
if (detail !== undefined)
|
|
78
|
+
base.detail = detail;
|
|
79
|
+
}
|
|
80
|
+
return base;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Promote the root to `"pinned"` iff the supplied identity file is for this
|
|
84
|
+
* receipt's motebit and its succession chain makes the signing key valid at the
|
|
85
|
+
* receipt's `completed_at`. Returns `null` (no promotion) otherwise. The chain is
|
|
86
|
+
* verified inside `verifyKeyBindingAtTime`; this is the sovereign-root half of
|
|
87
|
+
* binding (no operator anchor).
|
|
88
|
+
*/
|
|
89
|
+
async function pinnedBinding(receipt, identity) {
|
|
90
|
+
if (typeof receipt.public_key !== "string")
|
|
91
|
+
return null;
|
|
92
|
+
if (String(identity.motebit_id) !== String(receipt.motebit_id))
|
|
93
|
+
return null;
|
|
94
|
+
const r = await verifyKeyBindingAtTime(identity, receipt.public_key, receipt.completed_at);
|
|
95
|
+
return r.bound ? "pinned" : null;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Promote to `"sovereign"` iff the signing key binds AND the identity's
|
|
99
|
+
* `motebit_id` is the sovereign commitment to its genesis key. This is the
|
|
100
|
+
* strongest rung and the only fully-offline one — `verifyKeyBindingAtTime`
|
|
101
|
+
* computes both the key's window and the id↔genesis commitment from the identity
|
|
102
|
+
* file alone, so no anchor, no relay, no chain is consulted. Returns `null`
|
|
103
|
+
* (no promotion) when the motebit wasn't minted sovereignly.
|
|
104
|
+
*/
|
|
105
|
+
async function sovereignBinding(receipt, identity) {
|
|
106
|
+
if (typeof receipt.public_key !== "string")
|
|
107
|
+
return null;
|
|
108
|
+
if (String(identity.motebit_id) !== String(receipt.motebit_id))
|
|
109
|
+
return null;
|
|
110
|
+
const r = await verifyKeyBindingAtTime(identity, receipt.public_key, receipt.completed_at);
|
|
111
|
+
return r.bound === true && r.sovereign === true ? "sovereign" : null;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Promote to `"anchored"` iff (a) the signing key is sovereign-bound to the
|
|
115
|
+
* supplied identity at `completed_at` AND included under `anchor.proof`'s root
|
|
116
|
+
* (`verifyIdentityBindingAnchored`), AND (b) that root is independently confirmed
|
|
117
|
+
* on-chain at the pinned relay address (`lookupIdentityLogAnchor`). The second
|
|
118
|
+
* check is what makes it `anchored` rather than `pinned` — without it a relay
|
|
119
|
+
* could assert any root. Returns the anchoring `txHash` for provenance, or `null`
|
|
120
|
+
* (no promotion) on any failure.
|
|
121
|
+
*/
|
|
122
|
+
async function anchoredBinding(receipt, identity, anchor) {
|
|
123
|
+
if (typeof receipt.public_key !== "string")
|
|
124
|
+
return null;
|
|
125
|
+
if (String(identity.motebit_id) !== String(receipt.motebit_id))
|
|
126
|
+
return null;
|
|
127
|
+
const bound = await verifyIdentityBindingAnchored(identity, receipt.public_key, receipt.completed_at, anchor.proof);
|
|
128
|
+
if (!bound.bound)
|
|
129
|
+
return null;
|
|
130
|
+
const onchain = await lookupIdentityLogAnchor(anchor.relayAnchorAddress, anchor.proof.anchoredRoot, anchor.lookup);
|
|
131
|
+
return onchain.ok ? { txHash: onchain.txHash } : null;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Verify a pasted receipt document (JSON text) entirely offline. Returns a typed
|
|
135
|
+
* view model; never throws on bad input or a crypto failure — only `JSON.parse`
|
|
136
|
+
* and shape errors map to `malformed_json` / `not_a_receipt`. Pass
|
|
137
|
+
* `options.identity` to attempt the `"pinned"` binding rung.
|
|
138
|
+
*/
|
|
139
|
+
export async function verifyReceiptDocument(jsonText, options) {
|
|
140
|
+
let parsed;
|
|
141
|
+
try {
|
|
142
|
+
parsed = JSON.parse(jsonText);
|
|
143
|
+
}
|
|
144
|
+
catch (err) {
|
|
145
|
+
return {
|
|
146
|
+
integrity: false,
|
|
147
|
+
binding: "unverified",
|
|
148
|
+
reason: "malformed_json",
|
|
149
|
+
detail: err instanceof Error ? err.message : String(err),
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
if (!isExecutionReceiptShape(parsed)) {
|
|
153
|
+
return {
|
|
154
|
+
integrity: false,
|
|
155
|
+
binding: "unverified",
|
|
156
|
+
reason: "not_a_receipt",
|
|
157
|
+
detail: "input is not an ExecutionReceipt (missing motebit_id / task_id / signature / suite)",
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
const view = toView(await verifyReceipt(parsed));
|
|
161
|
+
if (view.integrity) {
|
|
162
|
+
// Revocation is a poison verdict — check it first, independent of `identity`.
|
|
163
|
+
// A key revoked on-chain at/before completed_at must not bind, no matter what
|
|
164
|
+
// the succession chain says.
|
|
165
|
+
if (options?.revocation && typeof parsed.public_key === "string") {
|
|
166
|
+
const rev = await lookupKeyRevocation(options.revocation.relayAnchorAddress, parsed.public_key, options.revocation.lookup);
|
|
167
|
+
if (rev.status === "revoked" && rev.revokedAt <= parsed.completed_at) {
|
|
168
|
+
return { ...view, binding: "revoked", revokedAt: rev.revokedAt };
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
if (options?.identity) {
|
|
172
|
+
// Sovereign is the strongest root AND fully offline — check it first; a
|
|
173
|
+
// sovereign motebit needs no operator anchor at all.
|
|
174
|
+
const sovereign = await sovereignBinding(parsed, options.identity);
|
|
175
|
+
if (sovereign)
|
|
176
|
+
return { ...view, binding: sovereign };
|
|
177
|
+
if (options.anchor) {
|
|
178
|
+
const anchored = await anchoredBinding(parsed, options.identity, options.anchor);
|
|
179
|
+
if (anchored)
|
|
180
|
+
return { ...view, binding: "anchored", anchorTxHash: anchored.txHash };
|
|
181
|
+
}
|
|
182
|
+
const pinned = await pinnedBinding(parsed, options.identity);
|
|
183
|
+
if (pinned)
|
|
184
|
+
return { ...view, binding: pinned };
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return view;
|
|
188
|
+
}
|
|
189
|
+
//# sourceMappingURL=receipt-document.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"receipt-document.js","sourceRoot":"","sources":["../src/receipt-document.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@motebit/state-export-client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
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
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
"operator-transparency"
|
|
36
36
|
],
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@motebit/crypto": "1.
|
|
39
|
-
"@motebit/protocol": "
|
|
38
|
+
"@motebit/crypto": "2.1.0",
|
|
39
|
+
"@motebit/protocol": "2.0.1"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@types/node": "^22.0.0",
|