@kya-os/mcp 1.7.0 → 1.9.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 (232) hide show
  1. package/CHANGELOG.md +69 -0
  2. package/README.md +219 -3
  3. package/dist/card/build.d.ts +41 -0
  4. package/dist/card/build.d.ts.map +1 -0
  5. package/dist/card/build.js +47 -0
  6. package/dist/card/build.js.map +1 -0
  7. package/dist/card/builder.d.ts +99 -0
  8. package/dist/card/builder.d.ts.map +1 -0
  9. package/dist/card/builder.js +147 -0
  10. package/dist/card/builder.js.map +1 -0
  11. package/dist/card/cimd.d.ts +92 -0
  12. package/dist/card/cimd.d.ts.map +1 -0
  13. package/dist/card/cimd.js +225 -0
  14. package/dist/card/cimd.js.map +1 -0
  15. package/dist/card/delegation.d.ts +145 -0
  16. package/dist/card/delegation.d.ts.map +1 -0
  17. package/dist/card/delegation.js +293 -0
  18. package/dist/card/delegation.js.map +1 -0
  19. package/dist/card/emit.d.ts +133 -0
  20. package/dist/card/emit.d.ts.map +1 -0
  21. package/dist/card/emit.js +127 -0
  22. package/dist/card/emit.js.map +1 -0
  23. package/dist/card/index.d.ts +43 -0
  24. package/dist/card/index.d.ts.map +1 -0
  25. package/dist/card/index.js +46 -0
  26. package/dist/card/index.js.map +1 -0
  27. package/dist/card/middleware.d.ts +112 -0
  28. package/dist/card/middleware.d.ts.map +1 -0
  29. package/dist/card/middleware.js +121 -0
  30. package/dist/card/middleware.js.map +1 -0
  31. package/dist/card/proof/build.d.ts +22 -0
  32. package/dist/card/proof/build.d.ts.map +1 -0
  33. package/dist/card/proof/build.js +55 -0
  34. package/dist/card/proof/build.js.map +1 -0
  35. package/dist/card/proof/canonical.d.ts +66 -0
  36. package/dist/card/proof/canonical.d.ts.map +1 -0
  37. package/dist/card/proof/canonical.js +131 -0
  38. package/dist/card/proof/canonical.js.map +1 -0
  39. package/dist/card/proof/http-sig.d.ts +69 -0
  40. package/dist/card/proof/http-sig.d.ts.map +1 -0
  41. package/dist/card/proof/http-sig.js +101 -0
  42. package/dist/card/proof/http-sig.js.map +1 -0
  43. package/dist/card/proof/index.d.ts +25 -0
  44. package/dist/card/proof/index.d.ts.map +1 -0
  45. package/dist/card/proof/index.js +25 -0
  46. package/dist/card/proof/index.js.map +1 -0
  47. package/dist/card/proof/nonce-cache.d.ts +67 -0
  48. package/dist/card/proof/nonce-cache.d.ts.map +1 -0
  49. package/dist/card/proof/nonce-cache.js +88 -0
  50. package/dist/card/proof/nonce-cache.js.map +1 -0
  51. package/dist/card/proof/signer.d.ts +32 -0
  52. package/dist/card/proof/signer.d.ts.map +1 -0
  53. package/dist/card/proof/signer.js +59 -0
  54. package/dist/card/proof/signer.js.map +1 -0
  55. package/dist/card/proof/types.d.ts +219 -0
  56. package/dist/card/proof/types.d.ts.map +1 -0
  57. package/dist/card/proof/types.js +87 -0
  58. package/dist/card/proof/types.js.map +1 -0
  59. package/dist/card/proof/verify.d.ts +27 -0
  60. package/dist/card/proof/verify.d.ts.map +1 -0
  61. package/dist/card/proof/verify.js +236 -0
  62. package/dist/card/proof/verify.js.map +1 -0
  63. package/dist/card/resolve.d.ts +97 -0
  64. package/dist/card/resolve.d.ts.map +1 -0
  65. package/dist/card/resolve.js +223 -0
  66. package/dist/card/resolve.js.map +1 -0
  67. package/dist/card/revocation.d.ts +96 -0
  68. package/dist/card/revocation.d.ts.map +1 -0
  69. package/dist/card/revocation.js +190 -0
  70. package/dist/card/revocation.js.map +1 -0
  71. package/dist/card/schema.d.ts +177 -0
  72. package/dist/card/schema.d.ts.map +1 -0
  73. package/dist/card/schema.js +119 -0
  74. package/dist/card/schema.js.map +1 -0
  75. package/dist/card/verify.d.ts +144 -0
  76. package/dist/card/verify.d.ts.map +1 -0
  77. package/dist/card/verify.js +132 -0
  78. package/dist/card/verify.js.map +1 -0
  79. package/dist/delegation/bitstring.d.ts +9 -7
  80. package/dist/delegation/bitstring.d.ts.map +1 -1
  81. package/dist/delegation/bitstring.js +70 -37
  82. package/dist/delegation/bitstring.js.map +1 -1
  83. package/dist/delegation/did-linkage.d.ts +23 -0
  84. package/dist/delegation/did-linkage.d.ts.map +1 -0
  85. package/dist/delegation/did-linkage.js +57 -0
  86. package/dist/delegation/did-linkage.js.map +1 -0
  87. package/dist/delegation/did-resolver-registry.d.ts +7 -0
  88. package/dist/delegation/did-resolver-registry.d.ts.map +1 -0
  89. package/dist/delegation/did-resolver-registry.js +20 -0
  90. package/dist/delegation/did-resolver-registry.js.map +1 -0
  91. package/dist/delegation/did-web-resolver.d.ts +29 -18
  92. package/dist/delegation/did-web-resolver.d.ts.map +1 -1
  93. package/dist/delegation/did-web-resolver.js +65 -35
  94. package/dist/delegation/did-web-resolver.js.map +1 -1
  95. package/dist/delegation/index.d.ts +3 -0
  96. package/dist/delegation/index.d.ts.map +1 -1
  97. package/dist/delegation/index.js +3 -0
  98. package/dist/delegation/index.js.map +1 -1
  99. package/dist/delegation/statuslist-manager.d.ts.map +1 -1
  100. package/dist/delegation/statuslist-manager.js +16 -1
  101. package/dist/delegation/statuslist-manager.js.map +1 -1
  102. package/dist/delegation/vc-jwt-verify.d.ts +61 -0
  103. package/dist/delegation/vc-jwt-verify.d.ts.map +1 -0
  104. package/dist/delegation/vc-jwt-verify.js +131 -0
  105. package/dist/delegation/vc-jwt-verify.js.map +1 -0
  106. package/dist/delegation/vc-verification-checks.d.ts +50 -0
  107. package/dist/delegation/vc-verification-checks.d.ts.map +1 -0
  108. package/dist/delegation/vc-verification-checks.js +212 -0
  109. package/dist/delegation/vc-verification-checks.js.map +1 -0
  110. package/dist/delegation/vc-verifier.d.ts +24 -61
  111. package/dist/delegation/vc-verifier.d.ts.map +1 -1
  112. package/dist/delegation/vc-verifier.js +57 -180
  113. package/dist/delegation/vc-verifier.js.map +1 -1
  114. package/dist/delegation/vc-verifier.types.d.ts +88 -0
  115. package/dist/delegation/vc-verifier.types.d.ts.map +1 -0
  116. package/dist/delegation/vc-verifier.types.js +9 -0
  117. package/dist/delegation/vc-verifier.types.js.map +1 -0
  118. package/dist/index.d.ts +3 -1
  119. package/dist/index.d.ts.map +1 -1
  120. package/dist/index.js +2 -0
  121. package/dist/index.js.map +1 -1
  122. package/dist/integrations/cheqd/dlr.d.ts +44 -0
  123. package/dist/integrations/cheqd/dlr.d.ts.map +1 -0
  124. package/dist/integrations/cheqd/dlr.js +86 -0
  125. package/dist/integrations/cheqd/dlr.js.map +1 -0
  126. package/dist/integrations/cheqd/index.d.ts +5 -0
  127. package/dist/integrations/cheqd/index.d.ts.map +1 -0
  128. package/dist/integrations/cheqd/index.js +5 -0
  129. package/dist/integrations/cheqd/index.js.map +1 -0
  130. package/dist/integrations/cheqd/linkage.d.ts +20 -0
  131. package/dist/integrations/cheqd/linkage.d.ts.map +1 -0
  132. package/dist/integrations/cheqd/linkage.js +32 -0
  133. package/dist/integrations/cheqd/linkage.js.map +1 -0
  134. package/dist/integrations/cheqd/registrar.d.ts +85 -0
  135. package/dist/integrations/cheqd/registrar.d.ts.map +1 -0
  136. package/dist/integrations/cheqd/registrar.js +304 -0
  137. package/dist/integrations/cheqd/registrar.js.map +1 -0
  138. package/dist/integrations/cheqd/resolver.d.ts +38 -0
  139. package/dist/integrations/cheqd/resolver.d.ts.map +1 -0
  140. package/dist/integrations/cheqd/resolver.js +156 -0
  141. package/dist/integrations/cheqd/resolver.js.map +1 -0
  142. package/dist/middleware/index.d.ts +2 -0
  143. package/dist/middleware/index.d.ts.map +1 -1
  144. package/dist/middleware/index.js +5 -0
  145. package/dist/middleware/index.js.map +1 -1
  146. package/dist/middleware/with-kya-os.config-types.d.ts +139 -0
  147. package/dist/middleware/with-kya-os.config-types.d.ts.map +1 -0
  148. package/dist/middleware/with-kya-os.config-types.js +9 -0
  149. package/dist/middleware/with-kya-os.config-types.js.map +1 -0
  150. package/dist/middleware/with-kya-os.d.ts +3 -267
  151. package/dist/middleware/with-kya-os.d.ts.map +1 -1
  152. package/dist/middleware/with-kya-os.delegation-gate.d.ts +19 -0
  153. package/dist/middleware/with-kya-os.delegation-gate.d.ts.map +1 -0
  154. package/dist/middleware/with-kya-os.delegation-gate.js +175 -0
  155. package/dist/middleware/with-kya-os.delegation-gate.js.map +1 -0
  156. package/dist/middleware/with-kya-os.delegation-verify.d.ts +51 -0
  157. package/dist/middleware/with-kya-os.delegation-verify.d.ts.map +1 -0
  158. package/dist/middleware/with-kya-os.delegation-verify.js +165 -0
  159. package/dist/middleware/with-kya-os.delegation-verify.js.map +1 -0
  160. package/dist/middleware/with-kya-os.deps.d.ts +40 -0
  161. package/dist/middleware/with-kya-os.deps.d.ts.map +1 -0
  162. package/dist/middleware/with-kya-os.deps.js +9 -0
  163. package/dist/middleware/with-kya-os.deps.js.map +1 -0
  164. package/dist/middleware/with-kya-os.grants.d.ts +30 -0
  165. package/dist/middleware/with-kya-os.grants.d.ts.map +1 -0
  166. package/dist/middleware/with-kya-os.grants.js +145 -0
  167. package/dist/middleware/with-kya-os.grants.js.map +1 -0
  168. package/dist/middleware/with-kya-os.helpers.d.ts +24 -0
  169. package/dist/middleware/with-kya-os.helpers.d.ts.map +1 -0
  170. package/dist/middleware/with-kya-os.helpers.js +57 -0
  171. package/dist/middleware/with-kya-os.helpers.js.map +1 -0
  172. package/dist/middleware/with-kya-os.js +45 -891
  173. package/dist/middleware/with-kya-os.js.map +1 -1
  174. package/dist/middleware/with-kya-os.policy-gate.d.ts +16 -0
  175. package/dist/middleware/with-kya-os.policy-gate.d.ts.map +1 -0
  176. package/dist/middleware/with-kya-os.policy-gate.js +98 -0
  177. package/dist/middleware/with-kya-os.policy-gate.js.map +1 -0
  178. package/dist/middleware/with-kya-os.protocol.d.ts +29 -0
  179. package/dist/middleware/with-kya-os.protocol.d.ts.map +1 -0
  180. package/dist/middleware/with-kya-os.protocol.js +121 -0
  181. package/dist/middleware/with-kya-os.protocol.js.map +1 -0
  182. package/dist/middleware/with-kya-os.session.d.ts +32 -0
  183. package/dist/middleware/with-kya-os.session.d.ts.map +1 -0
  184. package/dist/middleware/with-kya-os.session.js +201 -0
  185. package/dist/middleware/with-kya-os.session.js.map +1 -0
  186. package/dist/middleware/with-kya-os.types.d.ts +178 -0
  187. package/dist/middleware/with-kya-os.types.d.ts.map +1 -0
  188. package/dist/middleware/with-kya-os.types.js +13 -0
  189. package/dist/middleware/with-kya-os.types.js.map +1 -0
  190. package/dist/providers/runtime-fetch.d.ts +8 -0
  191. package/dist/providers/runtime-fetch.d.ts.map +1 -1
  192. package/dist/providers/runtime-fetch.js +17 -0
  193. package/dist/providers/runtime-fetch.js.map +1 -1
  194. package/dist/providers/web-crypto.d.ts.map +1 -1
  195. package/dist/providers/web-crypto.js +15 -7
  196. package/dist/providers/web-crypto.js.map +1 -1
  197. package/dist/utils/guards.d.ts +2 -0
  198. package/dist/utils/guards.d.ts.map +1 -0
  199. package/dist/utils/guards.js +4 -0
  200. package/dist/utils/guards.js.map +1 -0
  201. package/dist/utils/index.d.ts +3 -0
  202. package/dist/utils/index.d.ts.map +1 -1
  203. package/dist/utils/index.js +3 -0
  204. package/dist/utils/index.js.map +1 -1
  205. package/dist/utils/ip-classifier.d.ts +12 -0
  206. package/dist/utils/ip-classifier.d.ts.map +1 -0
  207. package/dist/utils/ip-classifier.js +153 -0
  208. package/dist/utils/ip-classifier.js.map +1 -0
  209. package/dist/utils/safe-fetch-transports.d.ts +40 -0
  210. package/dist/utils/safe-fetch-transports.d.ts.map +1 -0
  211. package/dist/utils/safe-fetch-transports.js +121 -0
  212. package/dist/utils/safe-fetch-transports.js.map +1 -0
  213. package/dist/utils/safe-fetch-types.d.ts +66 -0
  214. package/dist/utils/safe-fetch-types.d.ts.map +1 -0
  215. package/dist/utils/safe-fetch-types.js +10 -0
  216. package/dist/utils/safe-fetch-types.js.map +1 -0
  217. package/dist/utils/safe-fetch.d.ts +40 -0
  218. package/dist/utils/safe-fetch.d.ts.map +1 -0
  219. package/dist/utils/safe-fetch.js +188 -0
  220. package/dist/utils/safe-fetch.js.map +1 -0
  221. package/dist/utils/statuslist-purpose.d.ts +12 -0
  222. package/dist/utils/statuslist-purpose.d.ts.map +1 -0
  223. package/dist/utils/statuslist-purpose.js +19 -0
  224. package/dist/utils/statuslist-purpose.js.map +1 -0
  225. package/dist/utils/url.d.ts +2 -0
  226. package/dist/utils/url.d.ts.map +1 -0
  227. package/dist/utils/url.js +8 -0
  228. package/dist/utils/url.js.map +1 -0
  229. package/package.json +25 -5
  230. package/schemas/README.md +2 -1
  231. package/schemas/card-delegation-credential.json +239 -0
  232. package/schemas/kya-os-card.schema.json +284 -0
@@ -0,0 +1,97 @@
1
+ /**
2
+ * KYA-OS Entity Card — RESOLVE (discovery).
3
+ *
4
+ * Discover another entity's card — the conventional, UNAUTHENTICATED half. Discovery
5
+ * precedes the proof: you need the card's DID (the proof audience) before you can mint a
6
+ * proof against it.
7
+ *
8
+ * The card's canonical home is the `KyaOsEntityCard` service entry on the entity's
9
+ * `did:web` DID document, NOT a bespoke `/.well-known` file. `resolveCard` is multi-surface:
10
+ * - a `did:web` (or `{ did }`) resolves in TWO steps — `did.json` → the `KyaOsEntityCard`
11
+ * service entry → `card.json`;
12
+ * - `{ cardUrl }` fetches a `card.json` directly (the lazy-fetch target of a `cardRef`);
13
+ * - `{ serverMeta }` reads a server.json / catalog `_meta['org.kya-os/card']` entry — a
14
+ * `{ 'org.kya-os/cardRef' }` and a `did:web` inline summary DEREFERENCE the entity's canonical
15
+ * `card.json` (the summary is a discovery INDEX, its `id` names the DID, never trusted as an
16
+ * authoritative card); a `did:key` summary has no web home to dereference, so it is parsed
17
+ * directly — fail-closed because the summary carries the `revocation` kill switch and
18
+ * `delegationRef` (see `resolveFromServerMeta`);
19
+ * - `{ a2a }` follows an A2A AgentExtension's `params.cardUrl`;
20
+ * - `{ agentFacts }` two-steps from a NANDA AgentFacts `id` (a `did:web`).
21
+ *
22
+ * EVERY outbound fetch goes through the injected `SafeFetch` seam (SSRF-hardened, https-only,
23
+ * private-range-denied — see `src/utils/safe-fetch.ts`), because resolution now follows
24
+ * attacker-influenced URLs across four discovery surfaces.
25
+ */
26
+ import type { SafeFetch } from '../utils/safe-fetch.js';
27
+ import { type EntityCard } from './schema.js';
28
+ /** DID-document `service[].type` string that anchors the card (we own only this string). */
29
+ export declare const KYA_OS_CARD_SERVICE_TYPE = "KyaOsEntityCard";
30
+ /** DID-document `service[].id` fragment for the card service entry. */
31
+ export declare const KYA_OS_CARD_SERVICE_ID = "#kya-os-card";
32
+ /** Reverse-DNS `_meta` key carrying the card (inline summary or a `cardRef`) on MCP surfaces. */
33
+ export declare const KYA_OS_CARD_META_KEY = "org.kya-os/card";
34
+ /** Reverse-DNS key whose value is a lazy-fetch `card.json` URL inside `org.kya-os/card`. */
35
+ export declare const KYA_OS_CARD_REF_KEY = "org.kya-os/cardRef";
36
+ /**
37
+ * Bare-domain (org-root) card convention. A path-form `did:web:host:a:b` anchors its card at
38
+ * `/a/b/card.json`, but a BARE `did:web:host` (an org root — e.g. the default trusted issuer
39
+ * `did:web:example.com`) has no path segment, so its card lives at this well-known path. Defined
40
+ * ONCE here so `didWebToCardUrl` (emit) and the summary-derive resolve path agree on one URL —
41
+ * closing the emit/resolve asymmetry that previously locked bare org roots out of the helpers.
42
+ */
43
+ export declare const KYA_OS_CARD_WELL_KNOWN_PATH = ".well-known/kya-os-card.json";
44
+ /** A non-DID reference form `resolveCard` accepts in addition to a bare `did:web` string. */
45
+ export type CardRef = {
46
+ did: string;
47
+ } | {
48
+ cardUrl: string;
49
+ } | {
50
+ serverMeta: unknown;
51
+ } | {
52
+ a2a: unknown;
53
+ } | {
54
+ agentFacts: unknown;
55
+ };
56
+ export type ResolveCardInput = string | CardRef;
57
+ export interface ResolveCardDeps {
58
+ /** SSRF-hardened fetch seam — every outbound request is routed through it. */
59
+ fetch: SafeFetch;
60
+ }
61
+ /**
62
+ * Discover an entity's card from any supported reference form. A `did:web` resolves in two
63
+ * steps (`did.json` → `KyaOsEntityCard` service → `card.json`); the reference forms short-cut
64
+ * to the `card.json` URL (or an inline summary). `did:key` has no domain anchor, so a
65
+ * `did:key` card must be supplied directly (e.g. via `parseCard`), never resolved.
66
+ *
67
+ * THROW CONTRACT (fail-closed — deliberately UNLIKE the DID-METHOD resolvers, which return
68
+ * null so a failed method can be retried): every failure path REJECTS with a reasoned `Error`
69
+ * (message prefixed `resolveCard:`, or a `ZodError` from `parseCard` on an invalid card body).
70
+ * `resolveCard` NEVER resolves to `null`/`undefined`. Rationale: this is a security-relevant
71
+ * verify surface — a silently-null card would let an integrator mistake "couldn't resolve" for
72
+ * "no card = allow" (fail-open). Integrators MUST wrap the call and treat a throw as a hard
73
+ * deny. See CONTRIBUTING.md → Code Style for why this surface is scoped out of the null-on-
74
+ * failure resolver rule.
75
+ */
76
+ export declare function resolveCard(input: ResolveCardInput, deps: ResolveCardDeps): Promise<EntityCard>;
77
+ /**
78
+ * Map a `did:web` to its per-entity card URL:
79
+ * did:web:host:a:b → https://host/a/b/card.json
80
+ * did:web:host → https://host/.well-known/kya-os-card.json (the bare org-root convention)
81
+ *
82
+ * A bare `did:web:host` (an org root, incl. the default trusted issuer) resolves to the
83
+ * well-known card path so the trust anchors can publish their own card via the shipped helpers,
84
+ * and the emit projections agree with the summary-derive resolve path on this one URL. A
85
+ * non-`did:web` DID (e.g. `did:key`) has no web home, so this throws with actionable guidance:
86
+ * emit it onto the inline summary + AgentFacts surfaces, or supply an explicit `serviceEndpoint`.
87
+ */
88
+ export declare function didWebToCardUrl(did: string): string;
89
+ /**
90
+ * Map a `did:web` to its DID document URL (W3C did:web):
91
+ * did:web:host:a:b → https://host/a/b/did.json
92
+ * did:web:host → https://host/.well-known/did.json
93
+ */
94
+ export declare function didWebToDidDocUrl(did: string): string;
95
+ /** Validate + parse an unknown value into an EntityCard (throws a ZodError on mismatch). */
96
+ export declare function parseCard(value: unknown): EntityCard;
97
+ //# sourceMappingURL=resolve.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/card/resolve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAoB,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAKhE,4FAA4F;AAC5F,eAAO,MAAM,wBAAwB,oBAAoB,CAAC;AAC1D,uEAAuE;AACvE,eAAO,MAAM,sBAAsB,iBAAiB,CAAC;AACrD,iGAAiG;AACjG,eAAO,MAAM,oBAAoB,oBAAoB,CAAC;AACtD,4FAA4F;AAC5F,eAAO,MAAM,mBAAmB,uBAAuB,CAAC;AACxD;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B,iCAAiC,CAAC;AAE1E,6FAA6F;AAC7F,MAAM,MAAM,OAAO,GACf;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,GACf;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,GACnB;IAAE,UAAU,EAAE,OAAO,CAAA;CAAE,GACvB;IAAE,GAAG,EAAE,OAAO,CAAA;CAAE,GAChB;IAAE,UAAU,EAAE,OAAO,CAAA;CAAE,CAAC;AAE5B,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,OAAO,CAAC;AAEhD,MAAM,WAAW,eAAe;IAC9B,8EAA8E;IAC9E,KAAK,EAAE,SAAS,CAAC;CAClB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,gBAAgB,EACvB,IAAI,EAAE,eAAe,GACpB,OAAO,CAAC,UAAU,CAAC,CASrB;AAmID;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAQnD;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAGrD;AAED,4FAA4F;AAC5F,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,UAAU,CAEpD"}
@@ -0,0 +1,223 @@
1
+ /**
2
+ * KYA-OS Entity Card — RESOLVE (discovery).
3
+ *
4
+ * Discover another entity's card — the conventional, UNAUTHENTICATED half. Discovery
5
+ * precedes the proof: you need the card's DID (the proof audience) before you can mint a
6
+ * proof against it.
7
+ *
8
+ * The card's canonical home is the `KyaOsEntityCard` service entry on the entity's
9
+ * `did:web` DID document, NOT a bespoke `/.well-known` file. `resolveCard` is multi-surface:
10
+ * - a `did:web` (or `{ did }`) resolves in TWO steps — `did.json` → the `KyaOsEntityCard`
11
+ * service entry → `card.json`;
12
+ * - `{ cardUrl }` fetches a `card.json` directly (the lazy-fetch target of a `cardRef`);
13
+ * - `{ serverMeta }` reads a server.json / catalog `_meta['org.kya-os/card']` entry — a
14
+ * `{ 'org.kya-os/cardRef' }` and a `did:web` inline summary DEREFERENCE the entity's canonical
15
+ * `card.json` (the summary is a discovery INDEX, its `id` names the DID, never trusted as an
16
+ * authoritative card); a `did:key` summary has no web home to dereference, so it is parsed
17
+ * directly — fail-closed because the summary carries the `revocation` kill switch and
18
+ * `delegationRef` (see `resolveFromServerMeta`);
19
+ * - `{ a2a }` follows an A2A AgentExtension's `params.cardUrl`;
20
+ * - `{ agentFacts }` two-steps from a NANDA AgentFacts `id` (a `did:web`).
21
+ *
22
+ * EVERY outbound fetch goes through the injected `SafeFetch` seam (SSRF-hardened, https-only,
23
+ * private-range-denied — see `src/utils/safe-fetch.ts`), because resolution now follows
24
+ * attacker-influenced URLs across four discovery surfaces.
25
+ */
26
+ import { isRecord } from '../utils/guards.js';
27
+ import { EntityCardSchema } from './schema.js';
28
+ // ── Canonical discovery constants (co-located in the lowest module so `emit.ts`, which
29
+ // builds these surfaces, can depend on `resolve.ts` one-way without an import cycle) ──
30
+ /** DID-document `service[].type` string that anchors the card (we own only this string). */
31
+ export const KYA_OS_CARD_SERVICE_TYPE = 'KyaOsEntityCard';
32
+ /** DID-document `service[].id` fragment for the card service entry. */
33
+ export const KYA_OS_CARD_SERVICE_ID = '#kya-os-card';
34
+ /** Reverse-DNS `_meta` key carrying the card (inline summary or a `cardRef`) on MCP surfaces. */
35
+ export const KYA_OS_CARD_META_KEY = 'org.kya-os/card';
36
+ /** Reverse-DNS key whose value is a lazy-fetch `card.json` URL inside `org.kya-os/card`. */
37
+ export const KYA_OS_CARD_REF_KEY = 'org.kya-os/cardRef';
38
+ /**
39
+ * Bare-domain (org-root) card convention. A path-form `did:web:host:a:b` anchors its card at
40
+ * `/a/b/card.json`, but a BARE `did:web:host` (an org root — e.g. the default trusted issuer
41
+ * `did:web:example.com`) has no path segment, so its card lives at this well-known path. Defined
42
+ * ONCE here so `didWebToCardUrl` (emit) and the summary-derive resolve path agree on one URL —
43
+ * closing the emit/resolve asymmetry that previously locked bare org roots out of the helpers.
44
+ */
45
+ export const KYA_OS_CARD_WELL_KNOWN_PATH = '.well-known/kya-os-card.json';
46
+ /**
47
+ * Discover an entity's card from any supported reference form. A `did:web` resolves in two
48
+ * steps (`did.json` → `KyaOsEntityCard` service → `card.json`); the reference forms short-cut
49
+ * to the `card.json` URL (or an inline summary). `did:key` has no domain anchor, so a
50
+ * `did:key` card must be supplied directly (e.g. via `parseCard`), never resolved.
51
+ *
52
+ * THROW CONTRACT (fail-closed — deliberately UNLIKE the DID-METHOD resolvers, which return
53
+ * null so a failed method can be retried): every failure path REJECTS with a reasoned `Error`
54
+ * (message prefixed `resolveCard:`, or a `ZodError` from `parseCard` on an invalid card body).
55
+ * `resolveCard` NEVER resolves to `null`/`undefined`. Rationale: this is a security-relevant
56
+ * verify surface — a silently-null card would let an integrator mistake "couldn't resolve" for
57
+ * "no card = allow" (fail-open). Integrators MUST wrap the call and treat a throw as a hard
58
+ * deny. See CONTRIBUTING.md → Code Style for why this surface is scoped out of the null-on-
59
+ * failure resolver rule.
60
+ */
61
+ export async function resolveCard(input, deps) {
62
+ const { fetch } = deps;
63
+ if (typeof input === 'string')
64
+ return resolveDidWeb(input, fetch);
65
+ if ('did' in input)
66
+ return resolveDidWeb(input.did, fetch);
67
+ if ('cardUrl' in input)
68
+ return fetchCard(input.cardUrl, fetch);
69
+ if ('serverMeta' in input)
70
+ return resolveFromServerMeta(input.serverMeta, fetch);
71
+ if ('a2a' in input)
72
+ return fetchCard(cardUrlFromA2A(input.a2a), fetch);
73
+ if ('agentFacts' in input)
74
+ return resolveDidWeb(didFromAgentFacts(input.agentFacts), fetch);
75
+ throw new Error('resolveCard: unrecognized reference form');
76
+ }
77
+ /** Two-step `did:web` resolution: `did.json` → `KyaOsEntityCard` service → `card.json`. */
78
+ async function resolveDidWeb(did, fetch) {
79
+ if (!did.startsWith('did:web:')) {
80
+ throw new Error(`resolveCard: only did:web is resolvable (got "${did}"); supply a did:key card directly`);
81
+ }
82
+ const didDoc = await fetchJson(didWebToDidDocUrl(did), fetch);
83
+ return fetchCard(cardEndpointFromDidDoc(didDoc, did), fetch, did);
84
+ }
85
+ /**
86
+ * Read a server.json / catalog `_meta` block and resolve it fail-closed. An explicit
87
+ * `org.kya-os/cardRef` is a lazy-fetch URL; an inline summary is a discovery INDEX handled by
88
+ * `resolveInlineSummary` (dereference for `did:web`, parse-in-place for `did:key`).
89
+ */
90
+ async function resolveFromServerMeta(serverMeta, fetch) {
91
+ const entry = isRecord(serverMeta) ? serverMeta[KYA_OS_CARD_META_KEY] : undefined;
92
+ if (entry === undefined) {
93
+ throw new Error(`resolveCard: serverMeta has no "${KYA_OS_CARD_META_KEY}" entry`);
94
+ }
95
+ const ref = isRecord(entry) ? entry[KYA_OS_CARD_REF_KEY] : undefined;
96
+ if (typeof ref === 'string')
97
+ return fetchCard(ref, fetch);
98
+ return resolveInlineSummary(entry, fetch);
99
+ }
100
+ /**
101
+ * Resolve an inline `_meta` summary fail-closed. A `did:web` summary is a discovery INDEX: its
102
+ * `id` names the DID, so we DEREFERENCE the canonical `card.json` and never trust the (claim-
103
+ * minimal) summary as a first-class card — landing back on the one authoritative source that
104
+ * carries `revocation`/`delegationRef`/`attestations`, so a revoked card cannot fail open. A
105
+ * `did:key` id has NO web home to dereference, so the summary is parsed directly; this stays
106
+ * fail-closed because the summary now carries the `revocation` kill switch and `delegationRef`
107
+ * (the projection is self-verifiable), so `verifyCard`'s status-list checker is still consulted
108
+ * and a revoked `did:key` card verifies `ok:false`.
109
+ *
110
+ * SECURITY (§12.6): the `did:key` branch trusts the *presented* summary — a `did:key` has no
111
+ * origin-served `card.json` to dereference, so an intermediary that strips `revocation` from an
112
+ * unsigned `did:key` summary can hide a revocation. `did:web` is REQUIRED for revocable Entities.
113
+ */
114
+ async function resolveInlineSummary(entry, fetch) {
115
+ const id = isRecord(entry) ? entry.id : undefined;
116
+ if (typeof id !== 'string') {
117
+ throw new Error(`resolveCard: inline "${KYA_OS_CARD_META_KEY}" summary has no string id (DID)`);
118
+ }
119
+ if (id.startsWith('did:web:'))
120
+ return fetchCard(didWebToCardUrl(id), fetch, id);
121
+ return parseCard(entry);
122
+ }
123
+ /** Locate the `KyaOsEntityCard` service entry's endpoint on a DID document (fail-closed). */
124
+ function cardEndpointFromDidDoc(didDoc, did) {
125
+ const services = isRecord(didDoc) && Array.isArray(didDoc.service) ? didDoc.service : [];
126
+ for (const svc of services) {
127
+ if (isRecord(svc) &&
128
+ svc.type === KYA_OS_CARD_SERVICE_TYPE &&
129
+ typeof svc.serviceEndpoint === 'string') {
130
+ return svc.serviceEndpoint;
131
+ }
132
+ }
133
+ throw new Error(`resolveCard: DID document for "${did}" has no ${KYA_OS_CARD_SERVICE_TYPE} service entry`);
134
+ }
135
+ /** Pull the `card.json` URL out of an A2A AgentExtension's `params.cardUrl` (fail-closed). */
136
+ function cardUrlFromA2A(a2a) {
137
+ const params = isRecord(a2a) ? a2a.params : undefined;
138
+ const cardUrl = isRecord(params) ? params.cardUrl : undefined;
139
+ if (typeof cardUrl !== 'string') {
140
+ throw new Error('resolveCard: A2A extension has no string params.cardUrl');
141
+ }
142
+ return cardUrl;
143
+ }
144
+ /** Pull the agent DID out of a NANDA AgentFacts document's `id` (fail-closed). */
145
+ function didFromAgentFacts(agentFacts) {
146
+ const id = isRecord(agentFacts) ? agentFacts.id : undefined;
147
+ if (typeof id !== 'string') {
148
+ throw new Error('resolveCard: AgentFacts has no string id (DID)');
149
+ }
150
+ return id;
151
+ }
152
+ /** GET a URL through the SafeFetch seam and return its parsed JSON (throws on non-2xx). */
153
+ async function fetchJson(url, fetch) {
154
+ const res = await fetch(url);
155
+ if (!res.ok)
156
+ throw new Error(`resolveCard: GET ${url} → ${res.status}`);
157
+ return res.json();
158
+ }
159
+ /**
160
+ * GET a `card.json` URL and validate it into an `EntityCard`. When `expectedDid` is supplied — every
161
+ * DID-anchored resolve path (`did:web` two-step, inline `did:web` summary, AgentFacts) — BIND the
162
+ * fetched card to it: its `id` MUST equal that DID (normalized), else FAIL CLOSED. This closes the
163
+ * cross-origin confusion where a DID document's `KyaOsEntityCard` service entry points at a card for
164
+ * a DIFFERENT DID (or a compromised third-party endpoint), which would otherwise attribute another
165
+ * entity's claims/capabilities to the resolved DID. The `{ cardUrl }` and A2A paths carry no
166
+ * independent DID to bind against, so they pass no `expectedDid` (the URL itself is the trust root).
167
+ */
168
+ async function fetchCard(url, fetch, expectedDid) {
169
+ const card = parseCard(await fetchJson(url, fetch));
170
+ if (expectedDid !== undefined && normalizeDid(card.id) !== normalizeDid(expectedDid)) {
171
+ throw new Error(`resolveCard: resolved card id "${card.id}" ≠ requested DID "${expectedDid}" (identity mismatch) — fail-closed`);
172
+ }
173
+ return card;
174
+ }
175
+ /** Decompose a `did:web` into its host + slash-joined path segments. */
176
+ function parseDidWeb(did) {
177
+ const parts = did.slice('did:web:'.length).split(':').map(decodeURIComponent);
178
+ return { host: parts[0] ?? '', path: parts.slice(1).join('/') };
179
+ }
180
+ /**
181
+ * Canonicalize a DID for identity comparison. For `did:web` the DNS host is case-INsensitive and the
182
+ * segments are percent-decoded (reusing {@link parseDidWeb}), so `did:web:Example.com` binds to
183
+ * `did:web:example.com`; other DID methods (e.g. `did:key`, case-sensitive base58) compare verbatim.
184
+ */
185
+ function normalizeDid(did) {
186
+ if (!did.startsWith('did:web:'))
187
+ return did;
188
+ const { host, path } = parseDidWeb(did);
189
+ const base = `did:web:${host.toLowerCase()}`;
190
+ return path ? `${base}:${path.split('/').join(':')}` : base;
191
+ }
192
+ /**
193
+ * Map a `did:web` to its per-entity card URL:
194
+ * did:web:host:a:b → https://host/a/b/card.json
195
+ * did:web:host → https://host/.well-known/kya-os-card.json (the bare org-root convention)
196
+ *
197
+ * A bare `did:web:host` (an org root, incl. the default trusted issuer) resolves to the
198
+ * well-known card path so the trust anchors can publish their own card via the shipped helpers,
199
+ * and the emit projections agree with the summary-derive resolve path on this one URL. A
200
+ * non-`did:web` DID (e.g. `did:key`) has no web home, so this throws with actionable guidance:
201
+ * emit it onto the inline summary + AgentFacts surfaces, or supply an explicit `serviceEndpoint`.
202
+ */
203
+ export function didWebToCardUrl(did) {
204
+ if (!did.startsWith('did:web:')) {
205
+ throw new Error(`didWebToCardUrl: only a did:web has a web card URL (got "${did}"); a did:key card has no web home — emit it onto the inline summary + AgentFacts surfaces, or supply an explicit serviceEndpoint`);
206
+ }
207
+ const { host, path } = parseDidWeb(did);
208
+ return path ? `https://${host}/${path}/card.json` : `https://${host}/${KYA_OS_CARD_WELL_KNOWN_PATH}`;
209
+ }
210
+ /**
211
+ * Map a `did:web` to its DID document URL (W3C did:web):
212
+ * did:web:host:a:b → https://host/a/b/did.json
213
+ * did:web:host → https://host/.well-known/did.json
214
+ */
215
+ export function didWebToDidDocUrl(did) {
216
+ const { host, path } = parseDidWeb(did);
217
+ return path ? `https://${host}/${path}/did.json` : `https://${host}/.well-known/did.json`;
218
+ }
219
+ /** Validate + parse an unknown value into an EntityCard (throws a ZodError on mismatch). */
220
+ export function parseCard(value) {
221
+ return EntityCardSchema.parse(value);
222
+ }
223
+ //# sourceMappingURL=resolve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../src/card/resolve.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * KYA-OS Entity Card — REVOCATION seam (W3C Bitstring Status List v1.0).
3
+ *
4
+ * Capability + delegation credentials are revocable, so a verifier must be able to ask "is
5
+ * THIS credential still live?" without the question's shape leaking into callers. This module
6
+ * ships that question as a pluggable seam — `RevocationChecker` — so the VC-2.0 / status-list
7
+ * churn stays behind one interface (the same injected-seam discipline `verifyCard` already
8
+ * uses for its capability / attestation / accountability verifiers; NO `mcp-i-core` runtime
9
+ * dependency leaks into `@kya-os/mcp`).
10
+ *
11
+ * `createRevocationChecker` is the DEFAULT implementation over W3C Bitstring Status List v1.0
12
+ * (`BitstringStatusListEntry` — the StatusList2021 SUCCESSOR). It resolves the entry's
13
+ * `statusListCredential` through the injected, SSRF-hardened {@link SafeFetch} seam, inflates
14
+ * the multibase / GZIP `encodedList` bitstring, and reads the bit at `statusListIndex`.
15
+ *
16
+ * FAIL-CLOSED is the invariant: an unreachable status list, a malformed credential, a
17
+ * mismatched `statusPurpose`, or an out-of-range index all resolve to `{ revoked: true }` —
18
+ * the absence of proof-of-liveness is treated as revoked, never as "probably fine".
19
+ *
20
+ * Each verdict also reports `fresh`: `true` only when read from a LIVE, in-validity-window
21
+ * status list. A stale (past `validUntil`) or not-yet-valid list still yields a readable bit
22
+ * but `fresh: false`. {@link evaluateRevocationChain} walks a delegation chain root→leaf and
23
+ * fail-closes (cascading: a revoked parent invalidates the whole subtree) on the first
24
+ * revoked/unresolvable hop, threading `fresh` through every hop. The caller decides the gate:
25
+ * L2 accepts a non-revoked chain (cached / offline-verifiable); L3 additionally requires
26
+ * `fresh` (a live status check). NOT wired into `verifyCard` here — a later step injects it.
27
+ */
28
+ import type { SafeFetch } from '../utils/safe-fetch.js';
29
+ import type { BitstringStatusListEntry } from './schema.js';
30
+ /** The `statusPurpose` this checker evaluates by default (revocation, not suspension). */
31
+ export declare const STATUS_PURPOSE_REVOCATION = "revocation";
32
+ /**
33
+ * Inflate a GZIP `encodedList` payload to the raw status bitstring. The seam that keeps this
34
+ * verifier ISOMORPHIC: the default is Node-only (`node:zlib`), but a Workers / Deno / browser
35
+ * deployment injects a `DecompressionStream`-based impl so the bundle never pulls `node:zlib`.
36
+ * MAY be sync or async; MUST reject (throw / reject) on non-inflatable input (fail-closed).
37
+ */
38
+ export type Decompress = (bytes: Uint8Array) => Uint8Array | Promise<Uint8Array>;
39
+ /** Verdict for ONE status entry. */
40
+ export interface RevocationStatus {
41
+ /** True iff the status bit is set OR the status could not be proven clear (fail-closed). */
42
+ revoked: boolean;
43
+ /** True iff read from a LIVE, in-validity-window status list (drives the L2/L3 gate). */
44
+ fresh: boolean;
45
+ }
46
+ /**
47
+ * The injected revocation seam: resolve a `BitstringStatusListEntry` to a {@link RevocationStatus}.
48
+ * A runtime supplies an implementation (the default is {@link createRevocationChecker}); a
49
+ * caller may inject a cache-backed or offline variant. Implementations MUST fail closed.
50
+ */
51
+ export type RevocationChecker = (entry: BitstringStatusListEntry) => Promise<RevocationStatus>;
52
+ /** Result of a cascading root→leaf chain walk. */
53
+ export interface RevocationChainResult {
54
+ /** True iff EVERY hop is non-revoked (fail-closed: any revoked/unresolvable hop ⇒ false). */
55
+ ok: boolean;
56
+ /** True iff EVERY checked hop was read from a live, in-window status list. */
57
+ fresh: boolean;
58
+ /** Fail-closed reasons (empty ⇒ ok). */
59
+ reasons: string[];
60
+ }
61
+ /** Dependencies for the default Bitstring Status List v1.0 checker. */
62
+ export interface RevocationCheckerDeps {
63
+ /** SSRF-hardened fetch seam used to resolve the `statusListCredential`. */
64
+ fetch: SafeFetch;
65
+ /** Injectable clock returning epoch MILLISECONDS (deterministic freshness tests). */
66
+ now?: () => number;
67
+ /** `statusPurpose` to honour; default {@link STATUS_PURPOSE_REVOCATION}. */
68
+ statusPurpose?: string;
69
+ /**
70
+ * Injectable GZIP inflation seam ({@link Decompress}). DEFAULT = `node:zlib` `gunzipSync` bounded
71
+ * to the 16 MiB {@link MAX_STATUS_LIST_BYTES} `maxOutputLength` cap (so a decompression bomb
72
+ * THROWS mid-inflation ⇒ fail-closed, never allocating the whole payload). Non-Node runtimes
73
+ * inject a `DecompressionStream`-based impl; when they do, the default is never referenced so a
74
+ * bundler tree-shakes `node:zlib` out of the graph. An injected impl SHOULD bound its own output
75
+ * — {@link decodeStatusList} still applies the cap as a post-inflation backstop regardless.
76
+ */
77
+ decompress?: Decompress;
78
+ }
79
+ /**
80
+ * Build the default `RevocationChecker` over W3C Bitstring Status List v1.0. Every outbound
81
+ * request rides the injected {@link SafeFetch}; any failure on the path (unreachable, non-2xx,
82
+ * malformed, wrong purpose, out-of-range index) resolves {@link FAIL_CLOSED}.
83
+ */
84
+ export declare function createRevocationChecker(deps: RevocationCheckerDeps): RevocationChecker;
85
+ /**
86
+ * Walk a delegation/capability chain root→leaf and fail-close on the first revoked or
87
+ * unresolvable hop (cascading — a revoked ancestor invalidates the subtree, so the walk
88
+ * short-circuits). `fresh` is the AND of every checked hop's liveness.
89
+ *
90
+ * An empty set of status entries is trivially `ok` (nothing is revoked — an offline/L2-acceptable
91
+ * verdict) but is NOT `fresh`: freshness is a LIVE-check signal, and zero checks obtained no live
92
+ * signal. An L3 liveness gate that requires `fresh` therefore cannot be satisfied by a chain that
93
+ * simply omits all `credentialStatus` entries — it must consult at least one live status list.
94
+ */
95
+ export declare function evaluateRevocationChain(entries: readonly BitstringStatusListEntry[], check: RevocationChecker): Promise<RevocationChainResult>;
96
+ //# sourceMappingURL=revocation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"revocation.d.ts","sourceRoot":"","sources":["../../src/card/revocation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAKH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAE5D,0FAA0F;AAC1F,eAAO,MAAM,yBAAyB,eAAe,CAAC;AAEtD;;;;;GAKG;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,KAAK,EAAE,UAAU,KAAK,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAcjF,oCAAoC;AACpC,MAAM,WAAW,gBAAgB;IAC/B,4FAA4F;IAC5F,OAAO,EAAE,OAAO,CAAC;IACjB,yFAAyF;IACzF,KAAK,EAAE,OAAO,CAAC;CAChB;AAED;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,KAAK,EAAE,wBAAwB,KAAK,OAAO,CAAC,gBAAgB,CAAC,CAAC;AAE/F,kDAAkD;AAClD,MAAM,WAAW,qBAAqB;IACpC,6FAA6F;IAC7F,EAAE,EAAE,OAAO,CAAC;IACZ,8EAA8E;IAC9E,KAAK,EAAE,OAAO,CAAC;IACf,wCAAwC;IACxC,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,uEAAuE;AACvE,MAAM,WAAW,qBAAqB;IACpC,2EAA2E;IAC3E,KAAK,EAAE,SAAS,CAAC;IACjB,qFAAqF;IACrF,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,4EAA4E;IAC5E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB;AAKD;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,qBAAqB,GAAG,iBAAiB,CAetF;AAED;;;;;;;;;GASG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,SAAS,wBAAwB,EAAE,EAC5C,KAAK,EAAE,iBAAiB,GACvB,OAAO,CAAC,qBAAqB,CAAC,CAiBhC"}
@@ -0,0 +1,190 @@
1
+ /**
2
+ * KYA-OS Entity Card — REVOCATION seam (W3C Bitstring Status List v1.0).
3
+ *
4
+ * Capability + delegation credentials are revocable, so a verifier must be able to ask "is
5
+ * THIS credential still live?" without the question's shape leaking into callers. This module
6
+ * ships that question as a pluggable seam — `RevocationChecker` — so the VC-2.0 / status-list
7
+ * churn stays behind one interface (the same injected-seam discipline `verifyCard` already
8
+ * uses for its capability / attestation / accountability verifiers; NO `mcp-i-core` runtime
9
+ * dependency leaks into `@kya-os/mcp`).
10
+ *
11
+ * `createRevocationChecker` is the DEFAULT implementation over W3C Bitstring Status List v1.0
12
+ * (`BitstringStatusListEntry` — the StatusList2021 SUCCESSOR). It resolves the entry's
13
+ * `statusListCredential` through the injected, SSRF-hardened {@link SafeFetch} seam, inflates
14
+ * the multibase / GZIP `encodedList` bitstring, and reads the bit at `statusListIndex`.
15
+ *
16
+ * FAIL-CLOSED is the invariant: an unreachable status list, a malformed credential, a
17
+ * mismatched `statusPurpose`, or an out-of-range index all resolve to `{ revoked: true }` —
18
+ * the absence of proof-of-liveness is treated as revoked, never as "probably fine".
19
+ *
20
+ * Each verdict also reports `fresh`: `true` only when read from a LIVE, in-validity-window
21
+ * status list. A stale (past `validUntil`) or not-yet-valid list still yields a readable bit
22
+ * but `fresh: false`. {@link evaluateRevocationChain} walks a delegation chain root→leaf and
23
+ * fail-closes (cascading: a revoked parent invalidates the whole subtree) on the first
24
+ * revoked/unresolvable hop, threading `fresh` through every hop. The caller decides the gate:
25
+ * L2 accepts a non-revoked chain (cached / offline-verifiable); L3 additionally requires
26
+ * `fresh` (a live status check). NOT wired into `verifyCard` here — a later step injects it.
27
+ */
28
+ import { base64urlDecodeToBytes } from '../utils/base64.js';
29
+ import { isRecord } from '../utils/guards.js';
30
+ import { assertStatusPurpose } from '../utils/statuslist-purpose.js';
31
+ /** The `statusPurpose` this checker evaluates by default (revocation, not suspension). */
32
+ export const STATUS_PURPOSE_REVOCATION = 'revocation';
33
+ /** Multibase prefix for an unpadded base64url payload (W3C Bitstring Status List `encodedList`). */
34
+ const MULTIBASE_BASE64URL = 'u';
35
+ /**
36
+ * Hard ceiling on the INFLATED status bitstring (16 MiB ⇒ ~134M entries — far beyond any
37
+ * herd-privacy list). A status bitstring is fixed-size, so a generous fixed cap costs nothing
38
+ * legitimate while stopping a decompression bomb: without it, the ~786 KB of GZIP that fits
39
+ * inside SafeFetch's 1 MiB body cap inflates to ~800 MB, blocking the event loop on a synchronous
40
+ * `gunzipSync`. Exceeding the cap makes `gunzipSync` throw, which the checker converts to
41
+ * FAIL_CLOSED — preserving the module's uniform fail-closed posture. */
42
+ const MAX_STATUS_LIST_BYTES = 16 * 1024 * 1024;
43
+ /** Fail-closed verdict: status indeterminate ⇒ treat as revoked AND not fresh. */
44
+ const FAIL_CLOSED = { revoked: true, fresh: false };
45
+ /**
46
+ * Build the default `RevocationChecker` over W3C Bitstring Status List v1.0. Every outbound
47
+ * request rides the injected {@link SafeFetch}; any failure on the path (unreachable, non-2xx,
48
+ * malformed, wrong purpose, out-of-range index) resolves {@link FAIL_CLOSED}.
49
+ */
50
+ export function createRevocationChecker(deps) {
51
+ const clock = deps.now ?? (() => Date.now());
52
+ const wantedPurpose = deps.statusPurpose ?? STATUS_PURPOSE_REVOCATION;
53
+ const decompress = deps.decompress ?? defaultNodeGunzip;
54
+ return async function check(entry) {
55
+ try {
56
+ const credential = await fetchStatusList(entry.statusListCredential, deps.fetch);
57
+ assertStatusPurpose(statusListSubject(credential).statusPurpose, wantedPurpose);
58
+ const bits = await decodeStatusList(credential, decompress);
59
+ const revoked = readBit(bits, parseIndex(entry.statusListIndex));
60
+ return { revoked, fresh: isLive(credential, clock()) };
61
+ }
62
+ catch {
63
+ return FAIL_CLOSED;
64
+ }
65
+ };
66
+ }
67
+ /**
68
+ * Walk a delegation/capability chain root→leaf and fail-close on the first revoked or
69
+ * unresolvable hop (cascading — a revoked ancestor invalidates the subtree, so the walk
70
+ * short-circuits). `fresh` is the AND of every checked hop's liveness.
71
+ *
72
+ * An empty set of status entries is trivially `ok` (nothing is revoked — an offline/L2-acceptable
73
+ * verdict) but is NOT `fresh`: freshness is a LIVE-check signal, and zero checks obtained no live
74
+ * signal. An L3 liveness gate that requires `fresh` therefore cannot be satisfied by a chain that
75
+ * simply omits all `credentialStatus` entries — it must consult at least one live status list.
76
+ */
77
+ export async function evaluateRevocationChain(entries, check) {
78
+ let fresh = entries.length > 0; // no entries ⇒ no live signal ⇒ not fresh (fail-closed for L3)
79
+ for (const [hop, entry] of entries.entries()) {
80
+ const status = await check(entry);
81
+ fresh = fresh && status.fresh;
82
+ if (status.revoked) {
83
+ return {
84
+ ok: false,
85
+ fresh: false,
86
+ reasons: [
87
+ `revocation: hop ${hop} (${entry.statusListCredential}#${entry.statusListIndex}) ` +
88
+ 'is revoked or unresolvable — fail-closed, subtree invalidated',
89
+ ],
90
+ };
91
+ }
92
+ }
93
+ return { ok: true, fresh, reasons: [] };
94
+ }
95
+ // ── Internals ──────────────────────────────────────────────────────────────────
96
+ /** GET the status-list credential through SafeFetch (throws on non-2xx / non-object body). */
97
+ async function fetchStatusList(url, fetch) {
98
+ const res = await fetch(url);
99
+ if (!res.ok)
100
+ throw new Error(`revocation: status-list GET ${url} → ${res.status}`);
101
+ const body = await res.json();
102
+ if (!isRecord(body))
103
+ throw new Error('revocation: status-list credential is not an object');
104
+ return body;
105
+ }
106
+ /** The `credentialSubject` of a status-list credential (throws if absent). */
107
+ function statusListSubject(credential) {
108
+ const subject = credential.credentialSubject;
109
+ if (!isRecord(subject))
110
+ throw new Error('revocation: status-list has no credentialSubject');
111
+ return subject;
112
+ }
113
+ /**
114
+ * DEFAULT {@link Decompress}: `node:zlib` `gunzipSync` bounded to {@link MAX_STATUS_LIST_BYTES}
115
+ * so an oversized inflation THROWS mid-stream (fail-closed) instead of allocating the whole bomb.
116
+ * Pulled in via a DYNAMIC `import('node:zlib')` — only when no `decompress` was injected — so a
117
+ * Workers / Deno / browser bundle that supplies its own seam keeps `node:zlib` out of the graph.
118
+ */
119
+ async function defaultNodeGunzip(bytes) {
120
+ const { gunzipSync } = await import('node:zlib');
121
+ return new Uint8Array(gunzipSync(bytes, { maxOutputLength: MAX_STATUS_LIST_BYTES }));
122
+ }
123
+ /**
124
+ * Inflate the multibase / GZIP `encodedList` into the raw status bitstring bytes through the
125
+ * injected {@link Decompress} seam. The 16 MiB cap is re-checked here as a POST-inflation backstop:
126
+ * the default gunzip caps mid-stream, but an injected (edge) decompressor that does not bound its
127
+ * own output is still fail-closed against an oversized bitstring at this seam.
128
+ */
129
+ async function decodeStatusList(credential, decompress) {
130
+ const encoded = statusListSubject(credential).encodedList;
131
+ if (typeof encoded !== 'string' || encoded.length === 0) {
132
+ throw new Error('revocation: status-list has no encodedList');
133
+ }
134
+ const base64url = encoded[0] === MULTIBASE_BASE64URL ? encoded.slice(1) : encoded;
135
+ const inflated = await decompress(base64urlDecodeToBytes(base64url));
136
+ if (inflated.length > MAX_STATUS_LIST_BYTES) {
137
+ throw new Error(`revocation: status list too large: ${inflated.length} bytes exceeds ${MAX_STATUS_LIST_BYTES}`);
138
+ }
139
+ return inflated instanceof Uint8Array ? inflated : new Uint8Array(inflated);
140
+ }
141
+ /**
142
+ * Parse the decimal `statusListIndex` (a non-negative integer expressed as a string), fail-closed.
143
+ * MUST be canonical decimal only: `Number()` alone would coerce whitespace (`" "` → 0), hex
144
+ * (`"0x2A"` → 42), octal, `"+42"`, and `"1e1"` → 10 — silently reading a DIFFERENT (often clear) bit
145
+ * than the credential names, so a revoked credential could read as live. Reject anything that is not
146
+ * `[0-9]+`.
147
+ */
148
+ function parseIndex(raw) {
149
+ if (!/^[0-9]+$/.test(raw)) {
150
+ throw new Error(`revocation: statusListIndex must be a canonical non-negative decimal (got "${raw}")`);
151
+ }
152
+ const index = Number(raw);
153
+ if (!Number.isSafeInteger(index) || index < 0) {
154
+ throw new Error(`revocation: statusListIndex out of range "${raw}"`);
155
+ }
156
+ return index;
157
+ }
158
+ /**
159
+ * Read the status bit at `index` — MSB-first within each byte (W3C Bitstring encoding).
160
+ * Uses FULL-PRECISION arithmetic (`Math.floor(index / 8)`, `index % 8`) rather than the 32-bit
161
+ * bitwise ops `>>>`/`&`, which coerce their operand to uint32 first: an index ≥ 2^32 would
162
+ * silently wrap onto a low byte (e.g. 2^32+5 ⇒ byte 0, bit 5) and read the WRONG — often clear —
163
+ * bit, turning an out-of-range index that MUST fail-closed into a fail-OPEN "not revoked". With
164
+ * full-precision arithmetic an out-of-range byte offset indexes past the bitstring, yielding
165
+ * `undefined` ⇒ throw ⇒ FAIL_CLOSED. */
166
+ function readBit(bits, index) {
167
+ const byte = bits[Math.floor(index / 8)];
168
+ if (byte === undefined) {
169
+ throw new Error(`revocation: statusListIndex ${index} is out of range for the status list`);
170
+ }
171
+ return (byte & (0x80 >> (index % 8))) !== 0;
172
+ }
173
+ /** True iff `nowMs` falls inside the credential's `[validFrom, validUntil]` window (if declared). */
174
+ function isLive(credential, nowMs) {
175
+ const validUntil = parseDate(credential.validUntil ?? credential.expirationDate);
176
+ if (validUntil !== undefined && validUntil < nowMs)
177
+ return false; // stale → cached-OK at L2 only
178
+ const validFrom = parseDate(credential.validFrom ?? credential.issuanceDate);
179
+ if (validFrom !== undefined && validFrom > nowMs)
180
+ return false; // not yet valid
181
+ return true;
182
+ }
183
+ /** Parse an ISO-8601 date string to epoch ms, or `undefined` when absent / unparseable. */
184
+ function parseDate(value) {
185
+ if (typeof value !== 'string')
186
+ return undefined;
187
+ const ms = Date.parse(value);
188
+ return Number.isNaN(ms) ? undefined : ms;
189
+ }
190
+ //# sourceMappingURL=revocation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"revocation.js","sourceRoot":"","sources":["../../src/card/revocation.ts"],"names":[],"mappings":"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"}