@forestrie/forestrie-cli 0.8.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.
Files changed (124) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +425 -0
  3. package/TRUST-MODEL.md +8 -0
  4. package/dist/cli.js +33811 -0
  5. package/dist/decode-receipt.d.ts +19 -0
  6. package/dist/decode-receipt.d.ts.map +1 -0
  7. package/dist/decode-receipt.js +19 -0
  8. package/dist/decode-receipt.js.map +1 -0
  9. package/dist/index.d.ts +11 -0
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +11 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/lib/decode-receipt-cbor.d.ts +26 -0
  14. package/dist/lib/decode-receipt-cbor.d.ts.map +1 -0
  15. package/dist/lib/decode-receipt-cbor.js +182 -0
  16. package/dist/lib/decode-receipt-cbor.js.map +1 -0
  17. package/dist/lib/decode-receipt-decode.d.ts +103 -0
  18. package/dist/lib/decode-receipt-decode.d.ts.map +1 -0
  19. package/dist/lib/decode-receipt-decode.js +237 -0
  20. package/dist/lib/decode-receipt-decode.js.map +1 -0
  21. package/dist/lib/decode-receipt-labels.d.ts +54 -0
  22. package/dist/lib/decode-receipt-labels.d.ts.map +1 -0
  23. package/dist/lib/decode-receipt-labels.js +117 -0
  24. package/dist/lib/decode-receipt-labels.js.map +1 -0
  25. package/dist/lib/decode-receipt-render.d.ts +11 -0
  26. package/dist/lib/decode-receipt-render.d.ts.map +1 -0
  27. package/dist/lib/decode-receipt-render.js +242 -0
  28. package/dist/lib/decode-receipt-render.js.map +1 -0
  29. package/package.json +83 -0
  30. package/src/cli.ts +5 -0
  31. package/src/command.ts +51 -0
  32. package/src/commands/admin-onboard-token.ts +51 -0
  33. package/src/commands/admin.ts +20 -0
  34. package/src/commands/complete-grant.ts +41 -0
  35. package/src/commands/create-consistency-proof.ts +44 -0
  36. package/src/commands/create-log.ts +95 -0
  37. package/src/commands/decode-receipt.ts +20 -0
  38. package/src/commands/delegate.ts +55 -0
  39. package/src/commands/deploy.ts +72 -0
  40. package/src/commands/fetch-accumulator.ts +49 -0
  41. package/src/commands/onboard-genesis.ts +70 -0
  42. package/src/commands/onboard-request.ts +59 -0
  43. package/src/commands/register-grant.ts +74 -0
  44. package/src/commands/register.ts +54 -0
  45. package/src/commands/resolve-receipt.ts +101 -0
  46. package/src/commands/sign-statement.ts +53 -0
  47. package/src/commands/verify-grant.ts +89 -0
  48. package/src/commands/verify.ts +92 -0
  49. package/src/commoncli.ts +34 -0
  50. package/src/decode-receipt.ts +56 -0
  51. package/src/index.ts +10 -0
  52. package/src/lib/bytes.ts +7 -0
  53. package/src/lib/checkpoint-provider.ts +297 -0
  54. package/src/lib/complete-grant-derive.ts +237 -0
  55. package/src/lib/consistency-proof.ts +271 -0
  56. package/src/lib/create-log-build.ts +168 -0
  57. package/src/lib/create-log-prepare.ts +75 -0
  58. package/src/lib/create-receipt-chain-verify.ts +267 -0
  59. package/src/lib/create-receipt-derive.ts +208 -0
  60. package/src/lib/create-receipt-inputs.ts +79 -0
  61. package/src/lib/decode-checkpoint-calldata.ts +188 -0
  62. package/src/lib/decode-receipt-cbor.ts +202 -0
  63. package/src/lib/decode-receipt-decode.ts +333 -0
  64. package/src/lib/decode-receipt-labels.ts +132 -0
  65. package/src/lib/decode-receipt-render.ts +284 -0
  66. package/src/lib/delegate-flow.ts +289 -0
  67. package/src/lib/delegate-voucher.ts +122 -0
  68. package/src/lib/deploy-artifact.ts +79 -0
  69. package/src/lib/deploy-bootstrap.ts +100 -0
  70. package/src/lib/deploy-flow.ts +184 -0
  71. package/src/lib/deploy-genesis-log-id.ts +29 -0
  72. package/src/lib/deploy-rpc.ts +40 -0
  73. package/src/lib/deployment-record.ts +65 -0
  74. package/src/lib/fsio.ts +91 -0
  75. package/src/lib/grant-flags-local.ts +19 -0
  76. package/src/lib/onboard-attestation.ts +120 -0
  77. package/src/lib/onboard-genesis-body.ts +94 -0
  78. package/src/lib/openssl-error-queue.ts +56 -0
  79. package/src/lib/register-flow.ts +292 -0
  80. package/src/lib/register-grant-build.ts +173 -0
  81. package/src/lib/register-grant-complete.ts +47 -0
  82. package/src/lib/register-grant-flow.ts +258 -0
  83. package/src/lib/resolve-receipt-freshen.ts +221 -0
  84. package/src/lib/sign-statement-build.ts +117 -0
  85. package/src/lib/sign-statement-key.ts +145 -0
  86. package/src/lib/verify-anchored.ts +326 -0
  87. package/src/lib/verify-checkpoint-chain.ts +160 -0
  88. package/src/lib/verify-eventscan.ts +214 -0
  89. package/src/lib/verify-inputs.ts +143 -0
  90. package/src/lib/verify-known-accumulator.ts +161 -0
  91. package/src/lib/verify-report.ts +265 -0
  92. package/src/lib/x402-payment.ts +115 -0
  93. package/src/main/admin-onboard-token.ts +216 -0
  94. package/src/main/complete-grant.ts +265 -0
  95. package/src/main/create-consistency-proof.ts +83 -0
  96. package/src/main/create-log.ts +347 -0
  97. package/src/main/create-receipt.ts +763 -0
  98. package/src/main/decode-receipt.ts +72 -0
  99. package/src/main/delegate.ts +141 -0
  100. package/src/main/deploy.ts +273 -0
  101. package/src/main/fetch-accumulator.ts +181 -0
  102. package/src/main/not-implemented.ts +43 -0
  103. package/src/main/onboard-genesis.ts +192 -0
  104. package/src/main/onboard-request.ts +333 -0
  105. package/src/main/register-grant.ts +270 -0
  106. package/src/main/register.ts +243 -0
  107. package/src/main/sign-statement.ts +168 -0
  108. package/src/main/verify.ts +767 -0
  109. package/src/options/admin-onboard-token.ts +48 -0
  110. package/src/options/common.ts +69 -0
  111. package/src/options/complete-grant.ts +40 -0
  112. package/src/options/create-consistency-proof.ts +63 -0
  113. package/src/options/create-log.ts +99 -0
  114. package/src/options/create-receipt.ts +243 -0
  115. package/src/options/decode-receipt.ts +25 -0
  116. package/src/options/delegate.ts +93 -0
  117. package/src/options/deploy.ts +105 -0
  118. package/src/options/fetch-accumulator.ts +62 -0
  119. package/src/options/onboard-genesis.ts +74 -0
  120. package/src/options/onboard-request.ts +57 -0
  121. package/src/options/register-grant.ts +72 -0
  122. package/src/options/register.ts +71 -0
  123. package/src/options/sign-statement.ts +64 -0
  124. package/src/options/verify.ts +250 -0
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Public library entry: the pure COSE-receipt decoder and renderer that
3
+ * backs `forestrie decode-receipt`.
4
+ *
5
+ * Imported as `@forestrie/forestrie-cli/decode-receipt`. Everything here
6
+ * is runtime-neutral — no `node:*`, no `Bun.*`, no I/O, no network. It
7
+ * takes receipt bytes and returns a display model (plus a text
8
+ * rendering of it), so it runs unchanged in Node, Bun, Deno, a worker
9
+ * or a browser. The only dependencies are `@forestrie/receipt-verify`
10
+ * (the load-bearing receipt parse) and `@forestrie/encoding`.
11
+ *
12
+ * Decoding is display only: it does NOT verify signatures or inclusion.
13
+ * That is `forestrie verify` / `@forestrie/receipt-verify`.
14
+ */
15
+ export { DecodeReceiptError, bytesToHex, decodeReceipt, toJson, type DecodeReceiptStage, type DecodedClaim, type DecodedHeaderEntry, type DecodedReceipt, type Json, } from "./lib/decode-receipt-decode.js";
16
+ export { renderReceipt } from "./lib/decode-receipt-render.js";
17
+ export { ALG_NAMES, COSE_KEY_PARAM_NAMES, COSE_SIGN1_TAG, CWT_CLAIMS_LABEL, CWT_CLAIM_NAMES, DELEGATION_CERT_LABEL, HEADER_LABELS, PROOFS_CONSISTENCY_KEY, PROOFS_INCLUSION_KEY, PROOF_KIND_NAMES, SEAL_PEAK_RECEIPTS_LABEL, VDS_LABEL, VDS_NAMES, VERIFIABLE_PROOFS_LABEL, headerLabelInfo, type LabelInfo, } from "./lib/decode-receipt-labels.js";
18
+ export { CborDecodeError, decodeCborMap, decodeCborValue, isCborTagged, type CborTagged, type CborValue, } from "./lib/decode-receipt-cbor.js";
19
+ //# sourceMappingURL=decode-receipt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decode-receipt.d.ts","sourceRoot":"","sources":["../src/decode-receipt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EACL,kBAAkB,EAClB,UAAU,EACV,aAAa,EACb,MAAM,EACN,KAAK,kBAAkB,EACvB,KAAK,YAAY,EACjB,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,IAAI,GACV,MAAM,gCAAgC,CAAC;AAExC,OAAO,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAE/D,OAAO,EACL,SAAS,EACT,oBAAoB,EACpB,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,qBAAqB,EACrB,aAAa,EACb,sBAAsB,EACtB,oBAAoB,EACpB,gBAAgB,EAChB,wBAAwB,EACxB,SAAS,EACT,SAAS,EACT,uBAAuB,EACvB,eAAe,EACf,KAAK,SAAS,GACf,MAAM,gCAAgC,CAAC;AAExC,OAAO,EACL,eAAe,EACf,aAAa,EACb,eAAe,EACf,YAAY,EACZ,KAAK,UAAU,EACf,KAAK,SAAS,GACf,MAAM,8BAA8B,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Public library entry: the pure COSE-receipt decoder and renderer that
3
+ * backs `forestrie decode-receipt`.
4
+ *
5
+ * Imported as `@forestrie/forestrie-cli/decode-receipt`. Everything here
6
+ * is runtime-neutral — no `node:*`, no `Bun.*`, no I/O, no network. It
7
+ * takes receipt bytes and returns a display model (plus a text
8
+ * rendering of it), so it runs unchanged in Node, Bun, Deno, a worker
9
+ * or a browser. The only dependencies are `@forestrie/receipt-verify`
10
+ * (the load-bearing receipt parse) and `@forestrie/encoding`.
11
+ *
12
+ * Decoding is display only: it does NOT verify signatures or inclusion.
13
+ * That is `forestrie verify` / `@forestrie/receipt-verify`.
14
+ */
15
+ export { DecodeReceiptError, bytesToHex, decodeReceipt, toJson, } from "./lib/decode-receipt-decode.js";
16
+ export { renderReceipt } from "./lib/decode-receipt-render.js";
17
+ export { ALG_NAMES, COSE_KEY_PARAM_NAMES, COSE_SIGN1_TAG, CWT_CLAIMS_LABEL, CWT_CLAIM_NAMES, DELEGATION_CERT_LABEL, HEADER_LABELS, PROOFS_CONSISTENCY_KEY, PROOFS_INCLUSION_KEY, PROOF_KIND_NAMES, SEAL_PEAK_RECEIPTS_LABEL, VDS_LABEL, VDS_NAMES, VERIFIABLE_PROOFS_LABEL, headerLabelInfo, } from "./lib/decode-receipt-labels.js";
18
+ export { CborDecodeError, decodeCborMap, decodeCborValue, isCborTagged, } from "./lib/decode-receipt-cbor.js";
19
+ //# sourceMappingURL=decode-receipt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decode-receipt.js","sourceRoot":"","sources":["../src/decode-receipt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EACL,kBAAkB,EAClB,UAAU,EACV,aAAa,EACb,MAAM,GAMP,MAAM,gCAAgC,CAAC;AAExC,OAAO,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAE/D,OAAO,EACL,SAAS,EACT,oBAAoB,EACpB,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,qBAAqB,EACrB,aAAa,EACb,sBAAsB,EACtB,oBAAoB,EACpB,gBAAgB,EAChB,wBAAwB,EACxB,SAAS,EACT,SAAS,EACT,uBAAuB,EACvB,eAAe,GAEhB,MAAM,gCAAgC,CAAC;AAExC,OAAO,EACL,eAAe,EACf,aAAa,EACb,eAAe,EACf,YAAY,GAGb,MAAM,8BAA8B,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Package entry for `@forestrie/forestrie-cli`.
3
+ *
4
+ * This package is primarily a CLI (`forestrie`). Its one supported
5
+ * library surface is the pure receipt decoder/renderer, re-exported
6
+ * here and also reachable directly as
7
+ * `@forestrie/forestrie-cli/decode-receipt` — prefer the subpath, it is
8
+ * the stable name and will not grow unrelated exports.
9
+ */
10
+ export * from "./decode-receipt.js";
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,cAAc,qBAAqB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Package entry for `@forestrie/forestrie-cli`.
3
+ *
4
+ * This package is primarily a CLI (`forestrie`). Its one supported
5
+ * library surface is the pure receipt decoder/renderer, re-exported
6
+ * here and also reachable directly as
7
+ * `@forestrie/forestrie-cli/decode-receipt` — prefer the subpath, it is
8
+ * the stable name and will not grow unrelated exports.
9
+ */
10
+ export * from "./decode-receipt.js";
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,cAAc,qBAAqB,CAAC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Minimal CBOR reader for `forestrie decode-receipt` display (FOR-346).
3
+ *
4
+ * Only used where the published helpers stop: `parseReceipt`
5
+ * (`@forestrie/receipt-verify`) returns the COSE protected header as an
6
+ * opaque bstr, and this command's whole job is to show what is inside
7
+ * it (alg, kid, vds, CWT claims). Display-only — no re-encoding, no
8
+ * crypto. Definite lengths only: the forestrie encoders (go-cose,
9
+ * cbor-x, `@forestrie/encoding` canonical emit) never produce
10
+ * indefinite-length items.
11
+ */
12
+ export declare class CborDecodeError extends Error {
13
+ }
14
+ /** A decoded CBOR tag wrapper. */
15
+ export type CborTagged = {
16
+ tag: number;
17
+ value: CborValue;
18
+ };
19
+ export type CborValue = number | bigint | string | boolean | null | undefined | Uint8Array | CborValue[] | Map<CborValue, CborValue> | CborTagged;
20
+ /** True when `value` is a `CborTagged` wrapper (not a Map/array/bytes). */
21
+ export declare function isCborTagged(value: unknown): value is CborTagged;
22
+ /** Decode a single CBOR item; trailing bytes are an error. */
23
+ export declare function decodeCborValue(bytes: Uint8Array): CborValue;
24
+ /** Decode CBOR bytes that must contain a map (e.g. a COSE protected header). */
25
+ export declare function decodeCborMap(bytes: Uint8Array): Map<CborValue, CborValue>;
26
+ //# sourceMappingURL=decode-receipt-cbor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decode-receipt-cbor.d.ts","sourceRoot":"","sources":["../../src/lib/decode-receipt-cbor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,qBAAa,eAAgB,SAAQ,KAAK;CAAG;AAE7C,kCAAkC;AAClC,MAAM,MAAM,UAAU,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,SAAS,CAAA;CAAE,CAAC;AAE3D,MAAM,MAAM,SAAS,GACjB,MAAM,GACN,MAAM,GACN,MAAM,GACN,OAAO,GACP,IAAI,GACJ,SAAS,GACT,UAAU,GACV,SAAS,EAAE,GACX,GAAG,CAAC,SAAS,EAAE,SAAS,CAAC,GACzB,UAAU,CAAC;AAEf,2EAA2E;AAC3E,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,UAAU,CAUhE;AAyID,8DAA8D;AAC9D,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG,SAAS,CAa5D;AAED,gFAAgF;AAChF,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,GAAG,CAAC,SAAS,EAAE,SAAS,CAAC,CAO1E"}
@@ -0,0 +1,182 @@
1
+ /**
2
+ * Minimal CBOR reader for `forestrie decode-receipt` display (FOR-346).
3
+ *
4
+ * Only used where the published helpers stop: `parseReceipt`
5
+ * (`@forestrie/receipt-verify`) returns the COSE protected header as an
6
+ * opaque bstr, and this command's whole job is to show what is inside
7
+ * it (alg, kid, vds, CWT claims). Display-only — no re-encoding, no
8
+ * crypto. Definite lengths only: the forestrie encoders (go-cose,
9
+ * cbor-x, `@forestrie/encoding` canonical emit) never produce
10
+ * indefinite-length items.
11
+ */
12
+ export class CborDecodeError extends Error {
13
+ }
14
+ /** True when `value` is a `CborTagged` wrapper (not a Map/array/bytes). */
15
+ export function isCborTagged(value) {
16
+ return (typeof value === "object" &&
17
+ value !== null &&
18
+ !(value instanceof Map) &&
19
+ !(value instanceof Uint8Array) &&
20
+ !Array.isArray(value) &&
21
+ typeof value.tag === "number" &&
22
+ "value" in value);
23
+ }
24
+ function need(c, n) {
25
+ if (c.offset + n > c.bytes.length) {
26
+ throw new CborDecodeError("unexpected end of CBOR data");
27
+ }
28
+ }
29
+ function readArgument(c, info) {
30
+ if (info < 24)
31
+ return info;
32
+ if (info === 24) {
33
+ need(c, 1);
34
+ return c.bytes[c.offset++];
35
+ }
36
+ if (info === 25) {
37
+ need(c, 2);
38
+ const v = c.view.getUint16(c.offset);
39
+ c.offset += 2;
40
+ return v;
41
+ }
42
+ if (info === 26) {
43
+ need(c, 4);
44
+ const v = c.view.getUint32(c.offset);
45
+ c.offset += 4;
46
+ return v;
47
+ }
48
+ if (info === 27) {
49
+ need(c, 8);
50
+ const v = c.view.getBigUint64(c.offset);
51
+ c.offset += 8;
52
+ return v <= BigInt(Number.MAX_SAFE_INTEGER) ? Number(v) : v;
53
+ }
54
+ if (info === 31) {
55
+ throw new CborDecodeError("indefinite-length CBOR items are not supported");
56
+ }
57
+ throw new CborDecodeError(`reserved CBOR additional info ${info}`);
58
+ }
59
+ function toLength(arg, what) {
60
+ if (typeof arg === "bigint" || !Number.isSafeInteger(arg)) {
61
+ throw new CborDecodeError(`${what} length too large`);
62
+ }
63
+ return arg;
64
+ }
65
+ function readFloat(c, info) {
66
+ if (info === 25) {
67
+ // IEEE 754 half precision (RFC 8949 appendix D).
68
+ need(c, 2);
69
+ const half = c.view.getUint16(c.offset);
70
+ c.offset += 2;
71
+ const sign = half & 0x8000 ? -1 : 1;
72
+ const exp = (half >> 10) & 0x1f;
73
+ const frac = half & 0x03ff;
74
+ if (exp === 0)
75
+ return sign * frac * 2 ** -24;
76
+ if (exp === 31)
77
+ return frac ? Number.NaN : sign * Number.POSITIVE_INFINITY;
78
+ return sign * (1024 + frac) * 2 ** (exp - 25);
79
+ }
80
+ if (info === 26) {
81
+ need(c, 4);
82
+ const v = c.view.getFloat32(c.offset);
83
+ c.offset += 4;
84
+ return v;
85
+ }
86
+ need(c, 8);
87
+ const v = c.view.getFloat64(c.offset);
88
+ c.offset += 8;
89
+ return v;
90
+ }
91
+ function readItem(c, depth) {
92
+ if (depth > 64)
93
+ throw new CborDecodeError("CBOR nesting too deep");
94
+ need(c, 1);
95
+ const initial = c.bytes[c.offset++];
96
+ const major = initial >> 5;
97
+ const info = initial & 0x1f;
98
+ switch (major) {
99
+ case 0:
100
+ return readArgument(c, info);
101
+ case 1: {
102
+ const arg = readArgument(c, info);
103
+ return typeof arg === "bigint" ? -1n - arg : -1 - arg;
104
+ }
105
+ case 2: {
106
+ const len = toLength(readArgument(c, info), "byte string");
107
+ need(c, len);
108
+ const out = c.bytes.slice(c.offset, c.offset + len);
109
+ c.offset += len;
110
+ return out;
111
+ }
112
+ case 3: {
113
+ const len = toLength(readArgument(c, info), "text string");
114
+ need(c, len);
115
+ const out = new TextDecoder("utf-8", { fatal: true }).decode(c.bytes.subarray(c.offset, c.offset + len));
116
+ c.offset += len;
117
+ return out;
118
+ }
119
+ case 4: {
120
+ const len = toLength(readArgument(c, info), "array");
121
+ const out = [];
122
+ for (let i = 0; i < len; i += 1)
123
+ out.push(readItem(c, depth + 1));
124
+ return out;
125
+ }
126
+ case 5: {
127
+ const len = toLength(readArgument(c, info), "map");
128
+ const out = new Map();
129
+ for (let i = 0; i < len; i += 1) {
130
+ const key = readItem(c, depth + 1);
131
+ out.set(key, readItem(c, depth + 1));
132
+ }
133
+ return out;
134
+ }
135
+ case 6: {
136
+ const tag = toLength(readArgument(c, info), "tag");
137
+ return { tag, value: readItem(c, depth + 1) };
138
+ }
139
+ default: {
140
+ // major 7: simple values and floats
141
+ if (info === 20)
142
+ return false;
143
+ if (info === 21)
144
+ return true;
145
+ if (info === 22)
146
+ return null;
147
+ if (info === 23)
148
+ return undefined;
149
+ if (info === 24) {
150
+ need(c, 1);
151
+ return c.bytes[c.offset++];
152
+ }
153
+ if (info >= 25 && info <= 27)
154
+ return readFloat(c, info);
155
+ throw new CborDecodeError(`unsupported CBOR simple value (info ${info})`);
156
+ }
157
+ }
158
+ }
159
+ /** Decode a single CBOR item; trailing bytes are an error. */
160
+ export function decodeCborValue(bytes) {
161
+ const cursor = {
162
+ bytes,
163
+ view: new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength),
164
+ offset: 0,
165
+ };
166
+ const value = readItem(cursor, 0);
167
+ if (cursor.offset !== bytes.length) {
168
+ throw new CborDecodeError(`trailing bytes after CBOR item (${bytes.length - cursor.offset} left)`);
169
+ }
170
+ return value;
171
+ }
172
+ /** Decode CBOR bytes that must contain a map (e.g. a COSE protected header). */
173
+ export function decodeCborMap(bytes) {
174
+ if (bytes.length === 0)
175
+ return new Map();
176
+ const value = decodeCborValue(bytes);
177
+ if (!(value instanceof Map)) {
178
+ throw new CborDecodeError("expected a CBOR map");
179
+ }
180
+ return value;
181
+ }
182
+ //# sourceMappingURL=decode-receipt-cbor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decode-receipt-cbor.js","sourceRoot":"","sources":["../../src/lib/decode-receipt-cbor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Structural decode for `forestrie decode-receipt` (FOR-346).
3
+ *
4
+ * `parseReceipt` (`@forestrie/receipt-verify`) does the load-bearing
5
+ * receipt parse (COSE_Sign1 shape, tag-18 tolerance, payload rules,
6
+ * header 396 inclusion proof). This module turns that result into a
7
+ * display model: protected header contents (which `parseReceipt` leaves
8
+ * as opaque bstr), named labels, and JSON-safe values. Unknown labels
9
+ * are carried through raw — never dropped.
10
+ */
11
+ /** Parse stage names surfaced in structured errors. */
12
+ export type DecodeReceiptStage = "input" | "envelope" | "cose-sign1" | "payload" | "protected-header" | "inclusion-proof";
13
+ /** Structured decode failure: which parse stage rejected the input. */
14
+ export declare class DecodeReceiptError extends Error {
15
+ readonly stage: DecodeReceiptStage;
16
+ constructor(stage: DecodeReceiptStage, message: string);
17
+ }
18
+ /** JSON-safe value: bytes become `h'…'` diagnostic-notation strings. */
19
+ export type Json = string | number | boolean | null | Json[] | {
20
+ [key: string]: Json;
21
+ };
22
+ export type DecodedHeaderEntry = {
23
+ /** Raw CBOR label (int, or string for text keys). */
24
+ label: number | string;
25
+ /** Registry name, or null when the label is unknown (shown raw). */
26
+ name: string | null;
27
+ /** Registry provenance note, when known. */
28
+ note: string | null;
29
+ /** Full-fidelity value (bytes as h'…'). */
30
+ value: Json;
31
+ };
32
+ export type DecodedClaim = {
33
+ key: number | string;
34
+ name: string | null;
35
+ value: Json;
36
+ };
37
+ export type DecodedReceipt = {
38
+ /** Total receipt size in bytes. */
39
+ byteLength: number;
40
+ /** Outer CBOR tag (18 for COSE_Sign1) or null when untagged. */
41
+ tag: number | null;
42
+ protected: {
43
+ byteLength: number;
44
+ alg: {
45
+ value: number;
46
+ name: string | null;
47
+ } | null;
48
+ kid: {
49
+ hex: string;
50
+ byteLength: number;
51
+ } | {
52
+ text: string;
53
+ } | null;
54
+ vds: {
55
+ value: number;
56
+ name: string | null;
57
+ } | null;
58
+ /** CWT claims (header 15), incl. any cnf / ephemeral key material. */
59
+ cwtClaims: DecodedClaim[] | null;
60
+ entries: DecodedHeaderEntry[];
61
+ };
62
+ unprotected: {
63
+ entries: DecodedHeaderEntry[];
64
+ delegation: {
65
+ byteLength: number;
66
+ nestedCoseSign1: boolean;
67
+ } | null;
68
+ /** Present when this is a checkpoint carrying pre-signed peak receipts. */
69
+ peakReceipts: {
70
+ count: number;
71
+ } | null;
72
+ };
73
+ payload: {
74
+ detached: true;
75
+ } | {
76
+ detached: false;
77
+ byteLength: number;
78
+ hex: string;
79
+ };
80
+ signature: {
81
+ byteLength: number;
82
+ hex: string;
83
+ };
84
+ /** MMR inclusion proof summary (header 396, key -1). */
85
+ inclusion: {
86
+ mmrIndex: string;
87
+ pathLength: number;
88
+ path: string[];
89
+ /** 32-byte peak hash when the payload is attached; null when detached. */
90
+ peakHex: string | null;
91
+ peakSource: "payload" | "derived at verify time (detached payload)";
92
+ };
93
+ };
94
+ export declare function bytesToHex(bytes: Uint8Array): string;
95
+ /** Convert any decoded CBOR / cbor-x value to JSON-safe display form. */
96
+ export declare function toJson(value: unknown): Json;
97
+ /**
98
+ * Decode receipt bytes to the display model.
99
+ *
100
+ * @throws DecodeReceiptError naming the parse stage on malformed input
101
+ */
102
+ export declare function decodeReceipt(receiptBytes: Uint8Array): DecodedReceipt;
103
+ //# sourceMappingURL=decode-receipt-decode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decode-receipt-decode.d.ts","sourceRoot":"","sources":["../../src/lib/decode-receipt-decode.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,237 @@
1
+ /**
2
+ * Structural decode for `forestrie decode-receipt` (FOR-346).
3
+ *
4
+ * `parseReceipt` (`@forestrie/receipt-verify`) does the load-bearing
5
+ * receipt parse (COSE_Sign1 shape, tag-18 tolerance, payload rules,
6
+ * header 396 inclusion proof). This module turns that result into a
7
+ * display model: protected header contents (which `parseReceipt` leaves
8
+ * as opaque bstr), named labels, and JSON-safe values. Unknown labels
9
+ * are carried through raw — never dropped.
10
+ */
11
+ import { parseReceipt } from "@forestrie/receipt-verify";
12
+ import { coseUnprotectedToMap, decodeCoseSign1 } from "@forestrie/encoding";
13
+ import { CborDecodeError, decodeCborMap, isCborTagged, } from "./decode-receipt-cbor.js";
14
+ import { ALG_NAMES, COSE_SIGN1_TAG, CWT_CLAIMS_LABEL, CWT_CLAIM_NAMES, COSE_KEY_PARAM_NAMES, DELEGATION_CERT_LABEL, SEAL_PEAK_RECEIPTS_LABEL, VDS_LABEL, VDS_NAMES, headerLabelInfo, } from "./decode-receipt-labels.js";
15
+ /** Structured decode failure: which parse stage rejected the input. */
16
+ export class DecodeReceiptError extends Error {
17
+ stage;
18
+ constructor(stage, message) {
19
+ super(message);
20
+ this.name = "DecodeReceiptError";
21
+ this.stage = stage;
22
+ }
23
+ }
24
+ const HEX = Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0"));
25
+ export function bytesToHex(bytes) {
26
+ let out = "";
27
+ for (const b of bytes)
28
+ out += HEX[b];
29
+ return out;
30
+ }
31
+ /** Convert any decoded CBOR / cbor-x value to JSON-safe display form. */
32
+ export function toJson(value) {
33
+ if (value === null || value === undefined)
34
+ return null;
35
+ if (typeof value === "boolean" || typeof value === "string")
36
+ return value;
37
+ if (typeof value === "number") {
38
+ return Number.isFinite(value) ? value : String(value);
39
+ }
40
+ if (typeof value === "bigint") {
41
+ return value >= BigInt(Number.MIN_SAFE_INTEGER) &&
42
+ value <= BigInt(Number.MAX_SAFE_INTEGER)
43
+ ? Number(value)
44
+ : value.toString(10);
45
+ }
46
+ if (value instanceof Uint8Array)
47
+ return `h'${bytesToHex(value)}'`;
48
+ if (Array.isArray(value))
49
+ return value.map(toJson);
50
+ if (value instanceof Map) {
51
+ const out = {};
52
+ for (const [k, v] of value)
53
+ out[String(toJson(k))] = toJson(v);
54
+ return out;
55
+ }
56
+ if (isCborTagged(value)) {
57
+ return { tag: value.tag, value: toJson(value.value) };
58
+ }
59
+ if (typeof value === "object") {
60
+ const out = {};
61
+ for (const [k, v] of Object.entries(value))
62
+ out[k] = toJson(v);
63
+ return out;
64
+ }
65
+ return String(value);
66
+ }
67
+ function numericLabel(key) {
68
+ if (typeof key === "number")
69
+ return key;
70
+ if (typeof key === "bigint")
71
+ return Number(key);
72
+ const n = Number(key);
73
+ return Number.isFinite(n) ? n : String(key);
74
+ }
75
+ function headerEntry(key, value) {
76
+ const label = numericLabel(key);
77
+ const info = typeof label === "number" ? headerLabelInfo(label) : null;
78
+ return {
79
+ label,
80
+ name: info?.name ?? null,
81
+ note: info?.note ?? null,
82
+ value: toJson(value),
83
+ };
84
+ }
85
+ function decodeCwtClaims(claims) {
86
+ if (!(claims instanceof Map)) {
87
+ return [{ key: "(malformed)", name: null, value: toJson(claims) }];
88
+ }
89
+ const out = [];
90
+ for (const [k, v] of claims) {
91
+ const key = numericLabel(k);
92
+ const name = typeof key === "number" ? (CWT_CLAIM_NAMES.get(key) ?? null) : null;
93
+ // cnf (8) carries key material — name COSE_Key params for the audience.
94
+ if (key === 8 && v instanceof Map) {
95
+ const cnf = {};
96
+ for (const [pk, pv] of v) {
97
+ const paramKey = numericLabel(pk);
98
+ const paramName = typeof paramKey === "number"
99
+ ? COSE_KEY_PARAM_NAMES.get(paramKey)
100
+ : undefined;
101
+ cnf[paramName ? `${paramKey} (${paramName})` : String(paramKey)] =
102
+ toJson(pv);
103
+ }
104
+ out.push({ key, name, value: cnf });
105
+ continue;
106
+ }
107
+ out.push({ key, name, value: toJson(v) });
108
+ }
109
+ return out;
110
+ }
111
+ /** Classify a `parseReceipt` failure by the stage that rejected the input. */
112
+ function classifyParseReceiptError(error) {
113
+ const message = error instanceof Error ? error.message : String(error);
114
+ if (/COSE Sign1/i.test(message)) {
115
+ return new DecodeReceiptError("cose-sign1", message);
116
+ }
117
+ if (/payload/i.test(message)) {
118
+ return new DecodeReceiptError("payload", message);
119
+ }
120
+ if (/header 396|proof/i.test(message)) {
121
+ return new DecodeReceiptError("inclusion-proof", message);
122
+ }
123
+ // Anything else came out of the CBOR envelope decode.
124
+ return new DecodeReceiptError("envelope", message);
125
+ }
126
+ /**
127
+ * Decode receipt bytes to the display model.
128
+ *
129
+ * @throws DecodeReceiptError naming the parse stage on malformed input
130
+ */
131
+ export function decodeReceipt(receiptBytes) {
132
+ if (receiptBytes.length === 0) {
133
+ throw new DecodeReceiptError("input", "receipt is empty (0 bytes)");
134
+ }
135
+ // Tag tolerance: parseReceipt accepts both; record which form we got.
136
+ // Tag 18 with a 1-byte argument encodes as the initial byte 0xd2.
137
+ const tag = receiptBytes[0] === 0xd2 ? COSE_SIGN1_TAG : null;
138
+ let parsed;
139
+ try {
140
+ parsed = parseReceipt(receiptBytes);
141
+ }
142
+ catch (error) {
143
+ throw classifyParseReceiptError(error);
144
+ }
145
+ const [protectedBstr, unprotectedRaw, payload, signature] = parsed.coseSign1;
146
+ // Protected header: parseReceipt keeps it opaque (signed bytes); open it.
147
+ let protectedMap;
148
+ try {
149
+ protectedMap = decodeCborMap(protectedBstr);
150
+ }
151
+ catch (error) {
152
+ const message = error instanceof CborDecodeError
153
+ ? `protected header is not a valid CBOR map: ${error.message}`
154
+ : String(error);
155
+ throw new DecodeReceiptError("protected-header", message);
156
+ }
157
+ let alg = null;
158
+ let kid = null;
159
+ let vds = null;
160
+ let cwtClaims = null;
161
+ const protectedEntries = [];
162
+ for (const [k, v] of protectedMap) {
163
+ protectedEntries.push(headerEntry(k, v));
164
+ const label = numericLabel(k);
165
+ if (label === 1 && (typeof v === "number" || typeof v === "bigint")) {
166
+ const value = Number(v);
167
+ alg = { value, name: ALG_NAMES.get(value) ?? null };
168
+ }
169
+ else if (label === 4) {
170
+ if (v instanceof Uint8Array) {
171
+ kid = { hex: bytesToHex(v), byteLength: v.length };
172
+ }
173
+ else if (typeof v === "string") {
174
+ kid = { text: v };
175
+ }
176
+ }
177
+ else if (label === VDS_LABEL &&
178
+ (typeof v === "number" || typeof v === "bigint")) {
179
+ const value = Number(v);
180
+ vds = { value, name: VDS_NAMES.get(value) ?? null };
181
+ }
182
+ else if (label === CWT_CLAIMS_LABEL) {
183
+ cwtClaims = decodeCwtClaims(v);
184
+ }
185
+ }
186
+ // Unprotected header: already decoded by parseReceipt's CBOR pass.
187
+ const unprotectedMap = coseUnprotectedToMap(unprotectedRaw);
188
+ const unprotectedEntries = [];
189
+ let delegation = null;
190
+ let peakReceipts = null;
191
+ for (const [label, value] of unprotectedMap) {
192
+ unprotectedEntries.push(headerEntry(label, value));
193
+ if (label === DELEGATION_CERT_LABEL && value instanceof Uint8Array) {
194
+ delegation = {
195
+ byteLength: value.length,
196
+ nestedCoseSign1: decodeCoseSign1(value) !== null,
197
+ };
198
+ }
199
+ else if (label === SEAL_PEAK_RECEIPTS_LABEL && Array.isArray(value)) {
200
+ peakReceipts = { count: value.length };
201
+ }
202
+ }
203
+ const path = parsed.proof.path.map(bytesToHex);
204
+ const peakHex = parsed.explicitPeak ? bytesToHex(parsed.explicitPeak) : null;
205
+ return {
206
+ byteLength: receiptBytes.length,
207
+ tag,
208
+ protected: {
209
+ byteLength: protectedBstr.length,
210
+ alg,
211
+ kid,
212
+ vds,
213
+ cwtClaims,
214
+ entries: protectedEntries,
215
+ },
216
+ unprotected: {
217
+ entries: unprotectedEntries,
218
+ delegation,
219
+ peakReceipts,
220
+ },
221
+ payload: payload instanceof Uint8Array
222
+ ? { detached: false, byteLength: payload.length, hex: bytesToHex(payload) }
223
+ : { detached: true },
224
+ signature: { byteLength: signature.length, hex: bytesToHex(signature) },
225
+ inclusion: {
226
+ // parseReceipt always sets mmrIndex; Proof marks it optional.
227
+ mmrIndex: (parsed.proof.mmrIndex ?? 0n).toString(10),
228
+ pathLength: path.length,
229
+ path,
230
+ peakHex,
231
+ peakSource: peakHex
232
+ ? "payload"
233
+ : "derived at verify time (detached payload)",
234
+ },
235
+ };
236
+ }
237
+ //# sourceMappingURL=decode-receipt-decode.js.map