@kya-os/mcp 1.6.1 → 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.
- package/CHANGELOG.md +117 -0
- package/README.md +228 -3
- package/dist/authz/index.d.ts +1 -0
- package/dist/authz/index.d.ts.map +1 -1
- package/dist/authz/index.js +1 -0
- package/dist/authz/index.js.map +1 -1
- package/dist/authz/oidc/oidc-adapter.d.ts +10 -2
- package/dist/authz/oidc/oidc-adapter.d.ts.map +1 -1
- package/dist/authz/oidc/oidc-adapter.js +18 -9
- package/dist/authz/oidc/oidc-adapter.js.map +1 -1
- package/dist/authz/oidc/pending-flow-store.d.ts +80 -0
- package/dist/authz/oidc/pending-flow-store.d.ts.map +1 -0
- package/dist/authz/oidc/pending-flow-store.js +82 -0
- package/dist/authz/oidc/pending-flow-store.js.map +1 -0
- package/dist/card/build.d.ts +41 -0
- package/dist/card/build.d.ts.map +1 -0
- package/dist/card/build.js +47 -0
- package/dist/card/build.js.map +1 -0
- package/dist/card/builder.d.ts +99 -0
- package/dist/card/builder.d.ts.map +1 -0
- package/dist/card/builder.js +147 -0
- package/dist/card/builder.js.map +1 -0
- package/dist/card/cimd.d.ts +92 -0
- package/dist/card/cimd.d.ts.map +1 -0
- package/dist/card/cimd.js +225 -0
- package/dist/card/cimd.js.map +1 -0
- package/dist/card/delegation.d.ts +145 -0
- package/dist/card/delegation.d.ts.map +1 -0
- package/dist/card/delegation.js +293 -0
- package/dist/card/delegation.js.map +1 -0
- package/dist/card/emit.d.ts +133 -0
- package/dist/card/emit.d.ts.map +1 -0
- package/dist/card/emit.js +127 -0
- package/dist/card/emit.js.map +1 -0
- package/dist/card/index.d.ts +43 -0
- package/dist/card/index.d.ts.map +1 -0
- package/dist/card/index.js +46 -0
- package/dist/card/index.js.map +1 -0
- package/dist/card/middleware.d.ts +112 -0
- package/dist/card/middleware.d.ts.map +1 -0
- package/dist/card/middleware.js +121 -0
- package/dist/card/middleware.js.map +1 -0
- package/dist/card/proof/build.d.ts +22 -0
- package/dist/card/proof/build.d.ts.map +1 -0
- package/dist/card/proof/build.js +55 -0
- package/dist/card/proof/build.js.map +1 -0
- package/dist/card/proof/canonical.d.ts +66 -0
- package/dist/card/proof/canonical.d.ts.map +1 -0
- package/dist/card/proof/canonical.js +131 -0
- package/dist/card/proof/canonical.js.map +1 -0
- package/dist/card/proof/http-sig.d.ts +69 -0
- package/dist/card/proof/http-sig.d.ts.map +1 -0
- package/dist/card/proof/http-sig.js +101 -0
- package/dist/card/proof/http-sig.js.map +1 -0
- package/dist/card/proof/index.d.ts +25 -0
- package/dist/card/proof/index.d.ts.map +1 -0
- package/dist/card/proof/index.js +25 -0
- package/dist/card/proof/index.js.map +1 -0
- package/dist/card/proof/nonce-cache.d.ts +67 -0
- package/dist/card/proof/nonce-cache.d.ts.map +1 -0
- package/dist/card/proof/nonce-cache.js +88 -0
- package/dist/card/proof/nonce-cache.js.map +1 -0
- package/dist/card/proof/signer.d.ts +32 -0
- package/dist/card/proof/signer.d.ts.map +1 -0
- package/dist/card/proof/signer.js +59 -0
- package/dist/card/proof/signer.js.map +1 -0
- package/dist/card/proof/types.d.ts +219 -0
- package/dist/card/proof/types.d.ts.map +1 -0
- package/dist/card/proof/types.js +87 -0
- package/dist/card/proof/types.js.map +1 -0
- package/dist/card/proof/verify.d.ts +27 -0
- package/dist/card/proof/verify.d.ts.map +1 -0
- package/dist/card/proof/verify.js +236 -0
- package/dist/card/proof/verify.js.map +1 -0
- package/dist/card/resolve.d.ts +97 -0
- package/dist/card/resolve.d.ts.map +1 -0
- package/dist/card/resolve.js +223 -0
- package/dist/card/resolve.js.map +1 -0
- package/dist/card/revocation.d.ts +96 -0
- package/dist/card/revocation.d.ts.map +1 -0
- package/dist/card/revocation.js +190 -0
- package/dist/card/revocation.js.map +1 -0
- package/dist/card/schema.d.ts +177 -0
- package/dist/card/schema.d.ts.map +1 -0
- package/dist/card/schema.js +119 -0
- package/dist/card/schema.js.map +1 -0
- package/dist/card/verify.d.ts +144 -0
- package/dist/card/verify.d.ts.map +1 -0
- package/dist/card/verify.js +132 -0
- package/dist/card/verify.js.map +1 -0
- package/dist/delegation/bitstring.d.ts +9 -7
- package/dist/delegation/bitstring.d.ts.map +1 -1
- package/dist/delegation/bitstring.js +70 -37
- package/dist/delegation/bitstring.js.map +1 -1
- package/dist/delegation/did-linkage.d.ts +23 -0
- package/dist/delegation/did-linkage.d.ts.map +1 -0
- package/dist/delegation/did-linkage.js +57 -0
- package/dist/delegation/did-linkage.js.map +1 -0
- package/dist/delegation/did-resolver-registry.d.ts +7 -0
- package/dist/delegation/did-resolver-registry.d.ts.map +1 -0
- package/dist/delegation/did-resolver-registry.js +20 -0
- package/dist/delegation/did-resolver-registry.js.map +1 -0
- package/dist/delegation/did-web-resolver.d.ts +29 -18
- package/dist/delegation/did-web-resolver.d.ts.map +1 -1
- package/dist/delegation/did-web-resolver.js +65 -35
- package/dist/delegation/did-web-resolver.js.map +1 -1
- package/dist/delegation/index.d.ts +3 -0
- package/dist/delegation/index.d.ts.map +1 -1
- package/dist/delegation/index.js +3 -0
- package/dist/delegation/index.js.map +1 -1
- package/dist/delegation/statuslist-manager.d.ts.map +1 -1
- package/dist/delegation/statuslist-manager.js +16 -1
- package/dist/delegation/statuslist-manager.js.map +1 -1
- package/dist/delegation/vc-jwt-verify.d.ts +61 -0
- package/dist/delegation/vc-jwt-verify.d.ts.map +1 -0
- package/dist/delegation/vc-jwt-verify.js +131 -0
- package/dist/delegation/vc-jwt-verify.js.map +1 -0
- package/dist/delegation/vc-verification-checks.d.ts +50 -0
- package/dist/delegation/vc-verification-checks.d.ts.map +1 -0
- package/dist/delegation/vc-verification-checks.js +212 -0
- package/dist/delegation/vc-verification-checks.js.map +1 -0
- package/dist/delegation/vc-verifier.d.ts +24 -61
- package/dist/delegation/vc-verifier.d.ts.map +1 -1
- package/dist/delegation/vc-verifier.js +57 -180
- package/dist/delegation/vc-verifier.js.map +1 -1
- package/dist/delegation/vc-verifier.types.d.ts +88 -0
- package/dist/delegation/vc-verifier.types.d.ts.map +1 -0
- package/dist/delegation/vc-verifier.types.js +9 -0
- package/dist/delegation/vc-verifier.types.js.map +1 -0
- package/dist/index.d.ts +8 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -3
- package/dist/index.js.map +1 -1
- package/dist/integrations/cheqd/dlr.d.ts +44 -0
- package/dist/integrations/cheqd/dlr.d.ts.map +1 -0
- package/dist/integrations/cheqd/dlr.js +86 -0
- package/dist/integrations/cheqd/dlr.js.map +1 -0
- package/dist/integrations/cheqd/index.d.ts +5 -0
- package/dist/integrations/cheqd/index.d.ts.map +1 -0
- package/dist/integrations/cheqd/index.js +5 -0
- package/dist/integrations/cheqd/index.js.map +1 -0
- package/dist/integrations/cheqd/linkage.d.ts +20 -0
- package/dist/integrations/cheqd/linkage.d.ts.map +1 -0
- package/dist/integrations/cheqd/linkage.js +32 -0
- package/dist/integrations/cheqd/linkage.js.map +1 -0
- package/dist/integrations/cheqd/registrar.d.ts +85 -0
- package/dist/integrations/cheqd/registrar.d.ts.map +1 -0
- package/dist/integrations/cheqd/registrar.js +304 -0
- package/dist/integrations/cheqd/registrar.js.map +1 -0
- package/dist/integrations/cheqd/resolver.d.ts +38 -0
- package/dist/integrations/cheqd/resolver.d.ts.map +1 -0
- package/dist/integrations/cheqd/resolver.js +156 -0
- package/dist/integrations/cheqd/resolver.js.map +1 -0
- package/dist/middleware/index.d.ts +2 -0
- package/dist/middleware/index.d.ts.map +1 -1
- package/dist/middleware/index.js +5 -0
- package/dist/middleware/index.js.map +1 -1
- package/dist/middleware/kya-os-transport.d.ts +2 -1
- package/dist/middleware/kya-os-transport.d.ts.map +1 -1
- package/dist/middleware/kya-os-transport.js +2 -1
- package/dist/middleware/kya-os-transport.js.map +1 -1
- package/dist/middleware/with-kya-os-server.d.ts +21 -4
- package/dist/middleware/with-kya-os-server.d.ts.map +1 -1
- package/dist/middleware/with-kya-os-server.js +4 -0
- package/dist/middleware/with-kya-os-server.js.map +1 -1
- package/dist/middleware/with-kya-os.config-types.d.ts +139 -0
- package/dist/middleware/with-kya-os.config-types.d.ts.map +1 -0
- package/dist/middleware/with-kya-os.config-types.js +9 -0
- package/dist/middleware/with-kya-os.config-types.js.map +1 -0
- package/dist/middleware/with-kya-os.d.ts +10 -238
- package/dist/middleware/with-kya-os.d.ts.map +1 -1
- package/dist/middleware/with-kya-os.delegation-gate.d.ts +19 -0
- package/dist/middleware/with-kya-os.delegation-gate.d.ts.map +1 -0
- package/dist/middleware/with-kya-os.delegation-gate.js +175 -0
- package/dist/middleware/with-kya-os.delegation-gate.js.map +1 -0
- package/dist/middleware/with-kya-os.delegation-verify.d.ts +51 -0
- package/dist/middleware/with-kya-os.delegation-verify.d.ts.map +1 -0
- package/dist/middleware/with-kya-os.delegation-verify.js +165 -0
- package/dist/middleware/with-kya-os.delegation-verify.js.map +1 -0
- package/dist/middleware/with-kya-os.deps.d.ts +40 -0
- package/dist/middleware/with-kya-os.deps.d.ts.map +1 -0
- package/dist/middleware/with-kya-os.deps.js +9 -0
- package/dist/middleware/with-kya-os.deps.js.map +1 -0
- package/dist/middleware/with-kya-os.grants.d.ts +30 -0
- package/dist/middleware/with-kya-os.grants.d.ts.map +1 -0
- package/dist/middleware/with-kya-os.grants.js +145 -0
- package/dist/middleware/with-kya-os.grants.js.map +1 -0
- package/dist/middleware/with-kya-os.helpers.d.ts +24 -0
- package/dist/middleware/with-kya-os.helpers.d.ts.map +1 -0
- package/dist/middleware/with-kya-os.helpers.js +57 -0
- package/dist/middleware/with-kya-os.helpers.js.map +1 -0
- package/dist/middleware/with-kya-os.js +65 -703
- package/dist/middleware/with-kya-os.js.map +1 -1
- package/dist/middleware/with-kya-os.policy-gate.d.ts +16 -0
- package/dist/middleware/with-kya-os.policy-gate.d.ts.map +1 -0
- package/dist/middleware/with-kya-os.policy-gate.js +98 -0
- package/dist/middleware/with-kya-os.policy-gate.js.map +1 -0
- package/dist/middleware/with-kya-os.protocol.d.ts +29 -0
- package/dist/middleware/with-kya-os.protocol.d.ts.map +1 -0
- package/dist/middleware/with-kya-os.protocol.js +121 -0
- package/dist/middleware/with-kya-os.protocol.js.map +1 -0
- package/dist/middleware/with-kya-os.session.d.ts +32 -0
- package/dist/middleware/with-kya-os.session.d.ts.map +1 -0
- package/dist/middleware/with-kya-os.session.js +201 -0
- package/dist/middleware/with-kya-os.session.js.map +1 -0
- package/dist/middleware/with-kya-os.types.d.ts +178 -0
- package/dist/middleware/with-kya-os.types.d.ts.map +1 -0
- package/dist/middleware/with-kya-os.types.js +13 -0
- package/dist/middleware/with-kya-os.types.js.map +1 -0
- package/dist/proof/generator.d.ts +21 -0
- package/dist/proof/generator.d.ts.map +1 -1
- package/dist/proof/generator.js +21 -0
- package/dist/proof/generator.js.map +1 -1
- package/dist/proof/index.d.ts +1 -1
- package/dist/proof/index.d.ts.map +1 -1
- package/dist/proof/index.js +1 -1
- package/dist/proof/index.js.map +1 -1
- package/dist/proof/verifier.d.ts +26 -3
- package/dist/proof/verifier.d.ts.map +1 -1
- package/dist/proof/verifier.js +54 -24
- package/dist/proof/verifier.js.map +1 -1
- package/dist/providers/grant-store.d.ts +10 -1
- package/dist/providers/grant-store.d.ts.map +1 -1
- package/dist/providers/grant-store.js.map +1 -1
- package/dist/providers/runtime-fetch.d.ts +8 -0
- package/dist/providers/runtime-fetch.d.ts.map +1 -1
- package/dist/providers/runtime-fetch.js +17 -0
- package/dist/providers/runtime-fetch.js.map +1 -1
- package/dist/providers/web-crypto.d.ts.map +1 -1
- package/dist/providers/web-crypto.js +15 -7
- package/dist/providers/web-crypto.js.map +1 -1
- package/dist/session/index.d.ts +1 -0
- package/dist/session/index.d.ts.map +1 -1
- package/dist/session/index.js +1 -0
- package/dist/session/index.js.map +1 -1
- package/dist/session/manager.d.ts +17 -6
- package/dist/session/manager.d.ts.map +1 -1
- package/dist/session/manager.js +16 -26
- package/dist/session/manager.js.map +1 -1
- package/dist/session/session-store.d.ts +78 -0
- package/dist/session/session-store.d.ts.map +1 -0
- package/dist/session/session-store.js +79 -0
- package/dist/session/session-store.js.map +1 -0
- package/dist/types/protocol.d.ts +9 -3
- package/dist/types/protocol.d.ts.map +1 -1
- package/dist/types/protocol.js.map +1 -1
- package/dist/utils/guards.d.ts +2 -0
- package/dist/utils/guards.d.ts.map +1 -0
- package/dist/utils/guards.js +4 -0
- package/dist/utils/guards.js.map +1 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +3 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/ip-classifier.d.ts +12 -0
- package/dist/utils/ip-classifier.d.ts.map +1 -0
- package/dist/utils/ip-classifier.js +153 -0
- package/dist/utils/ip-classifier.js.map +1 -0
- package/dist/utils/safe-fetch-transports.d.ts +40 -0
- package/dist/utils/safe-fetch-transports.d.ts.map +1 -0
- package/dist/utils/safe-fetch-transports.js +121 -0
- package/dist/utils/safe-fetch-transports.js.map +1 -0
- package/dist/utils/safe-fetch-types.d.ts +66 -0
- package/dist/utils/safe-fetch-types.d.ts.map +1 -0
- package/dist/utils/safe-fetch-types.js +10 -0
- package/dist/utils/safe-fetch-types.js.map +1 -0
- package/dist/utils/safe-fetch.d.ts +40 -0
- package/dist/utils/safe-fetch.d.ts.map +1 -0
- package/dist/utils/safe-fetch.js +188 -0
- package/dist/utils/safe-fetch.js.map +1 -0
- package/dist/utils/statuslist-purpose.d.ts +12 -0
- package/dist/utils/statuslist-purpose.d.ts.map +1 -0
- package/dist/utils/statuslist-purpose.js +19 -0
- package/dist/utils/statuslist-purpose.js.map +1 -0
- package/dist/utils/url.d.ts +2 -0
- package/dist/utils/url.d.ts.map +1 -0
- package/dist/utils/url.js +8 -0
- package/dist/utils/url.js.map +1 -0
- package/package.json +25 -5
- package/schemas/README.md +2 -1
- package/schemas/card-delegation-credential.json +239 -0
- package/schemas/kya-os-card.schema.json +284 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KYA-OS Entity Card — v1.1 profile helpers
|
|
3
|
+
*
|
|
4
|
+
* Reference helpers for the typed, DID-anchored entity card. See
|
|
5
|
+
* `SPEC-ENTITY-CARD.md` and `schemas/kya-os-card.schema.json`. Three moves, each in a
|
|
6
|
+
* focused submodule re-exported here:
|
|
7
|
+
* - buildCard (./build): EMIT this entity's card from its identity + declared facts.
|
|
8
|
+
* - emit (./emit): PROJECT the card onto every discovery rail (DID service entry,
|
|
9
|
+
* MCP `_meta`, catalog, A2A extension, NANDA AgentFacts).
|
|
10
|
+
* - resolveCard (./resolve): DISCOVER another entity's card (multi-surface, via SafeFetch).
|
|
11
|
+
* - verifyCard (./verify): VERIFY the card's claims — RECOMPUTING the conformance
|
|
12
|
+
* level rather than trusting whatever the card declares.
|
|
13
|
+
* - cimd (./cimd): BIND the L1 CIMD on-ramp — `client_id` ⇄ `did:web`, DID-keyed
|
|
14
|
+
* JWKS, and the fail-closed origin/`alsoKnownAs` substitution graft.
|
|
15
|
+
* - proof (./proof): MINT + VERIFY the stateless per-request holder-of-key proof
|
|
16
|
+
* (`org.kya-os/proof@1`) — sender-constrained, fail-closed.
|
|
17
|
+
* - delegation (./delegation): VALIDATE the W3C VC 2.0 + ZCAP-LD delegation chain — CRISP
|
|
18
|
+
* attenuation + continuity, `responsibleParty`/leaf-invoker, fail-closed.
|
|
19
|
+
* - builder (./builder): the fluent `card()` chain — the 10-minute path to a valid card.
|
|
20
|
+
* - middleware (./middleware): `withKyaOsCard` (mount the discovery artifacts) + `requireProof`
|
|
21
|
+
* (the per-request holder-of-key guard, 401-shaped on fail).
|
|
22
|
+
*
|
|
23
|
+
* All cryptographic verification is injected via pluggable seams (the same pattern
|
|
24
|
+
* `validateLevel2` already uses for its `signatureVerifier`), so `@kya-os/mcp` stays
|
|
25
|
+
* free of any runtime (mcp-i-core) dependency. The conformance LEVEL is derived in
|
|
26
|
+
* `./verify`, never baked into a function name.
|
|
27
|
+
*
|
|
28
|
+
* The card shape is defined once as a zod schema in `./schema` (mirroring the
|
|
29
|
+
* published `schemas/kya-os-card.schema.json`); types are `z.infer`-derived.
|
|
30
|
+
*/
|
|
31
|
+
export * from './schema.js';
|
|
32
|
+
export * from './build.js';
|
|
33
|
+
export * from './emit.js';
|
|
34
|
+
export * from './resolve.js';
|
|
35
|
+
export * from './verify.js';
|
|
36
|
+
export * from './cimd.js';
|
|
37
|
+
export * from './proof/index.js';
|
|
38
|
+
export * from './delegation.js';
|
|
39
|
+
export * from './builder.js';
|
|
40
|
+
export * from './middleware.js';
|
|
41
|
+
export * from './revocation.js';
|
|
42
|
+
// The SSRF-hardened fetch is the card's production wiring for resolveCard / status-list
|
|
43
|
+
// resolution — export it (and the address classifier) so consumers can actually reach it,
|
|
44
|
+
// not just the mocked-transport unit tests.
|
|
45
|
+
export { createSafeFetch, fetchTransport, isBlockedAddress, } from '../utils/safe-fetch.js';
|
|
46
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/card/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAEhC,wFAAwF;AACxF,0FAA0F;AAC1F,4CAA4C;AAC5C,OAAO,EACL,eAAe,EACf,cAAc,EACd,gBAAgB,GAQjB,MAAM,wBAAwB,CAAC"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KYA-OS Entity Card — DevX middleware (the 10-minute adoption path).
|
|
3
|
+
*
|
|
4
|
+
* Two ergonomic wrappers hide the RFC 9421 / 9449 / 8785 machinery behind one call each:
|
|
5
|
+
*
|
|
6
|
+
* - `withKyaOsCard(card)` — the EMIT side. Bundles the three artifacts a server must publish
|
|
7
|
+
* (the `card.json` body, the `KyaOsEntityCard` DID-document service entry, and the
|
|
8
|
+
* `server.json` `_meta['org.kya-os/card']` fragment) and MOUNTS them onto existing objects —
|
|
9
|
+
* merging the `_meta` into a server.json and appending the service entry to a DID document,
|
|
10
|
+
* both immutably (a shallow clone; a stripped `_meta` degrades to a fetch, never a failure).
|
|
11
|
+
*
|
|
12
|
+
* - `requireProof(deps, { minLevel? })` — the VERIFY side. Returns a per-request guard that
|
|
13
|
+
* reads the holder-of-key proof from `_meta['org.kya-os/proof@1']`, RECOMPUTES it via
|
|
14
|
+
* `./proof` ({@link verifyCardProof}) — every binding, fail-closed — enforces a minimum
|
|
15
|
+
* assurance, and returns a 401-shaped result on any failure. The caller passes the exact
|
|
16
|
+
* `{ method, params }` the client signed (i.e. WITHOUT `_meta`), so the recomputed
|
|
17
|
+
* `requestHash` matches.
|
|
18
|
+
*
|
|
19
|
+
* Pure composition over the shipped engine — no new crypto, no runtime (`mcp-i-core`) dependency.
|
|
20
|
+
*/
|
|
21
|
+
import type { ToolRequest } from '../proof/generator.js';
|
|
22
|
+
import { type DidServiceEntry, type ServerCardMeta } from './emit.js';
|
|
23
|
+
import { type ProofAssurance, type VerifyProofDeps } from './proof/index.js';
|
|
24
|
+
import type { EntityCard } from './schema.js';
|
|
25
|
+
/** A structurally-typed MCP `server.json` (open shape; only `_meta` is read/merged). */
|
|
26
|
+
export interface ServerJsonLike {
|
|
27
|
+
_meta?: Record<string, unknown>;
|
|
28
|
+
[key: string]: unknown;
|
|
29
|
+
}
|
|
30
|
+
/** A structurally-typed DID document (open shape; only `service[]` is read/appended). */
|
|
31
|
+
export interface DidDocumentLike {
|
|
32
|
+
service?: unknown[];
|
|
33
|
+
[key: string]: unknown;
|
|
34
|
+
}
|
|
35
|
+
/** The three publishable artifacts of a card + immutable mounters for a server.json / DID doc. */
|
|
36
|
+
export interface KyaOsCardMount {
|
|
37
|
+
/** Serve this at the entity's `card.json` endpoint (the canonical source of truth). */
|
|
38
|
+
cardJson: EntityCard;
|
|
39
|
+
/**
|
|
40
|
+
* Add this to the entity's `did:web` DID-document `service[]` (the card's canonical home).
|
|
41
|
+
* `undefined` for a `did:key` card, which has no HTTPS card endpoint — publish `serverMeta` instead.
|
|
42
|
+
*/
|
|
43
|
+
didServiceEntry?: DidServiceEntry;
|
|
44
|
+
/** Merge this into an MCP `server.json` / catalog `_meta`. */
|
|
45
|
+
serverMeta: ServerCardMeta;
|
|
46
|
+
/** Return a shallow clone of `serverJson` with the card `_meta` merged in (other keys preserved). */
|
|
47
|
+
mountServerJson<T extends ServerJsonLike>(serverJson: T): T & {
|
|
48
|
+
_meta: Record<string, unknown>;
|
|
49
|
+
};
|
|
50
|
+
/** Return a shallow clone of `didDoc` with the `KyaOsEntityCard` service entry appended (dedup by id). */
|
|
51
|
+
mountDidDocument<T extends DidDocumentLike>(didDoc: T): T & {
|
|
52
|
+
service: unknown[];
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Bundle a card into its three discovery artifacts and hand back immutable mounters. `opts.byRef`
|
|
57
|
+
* projects the `_meta` as a lazy-fetch `cardRef` instead of an inline summary. NOTE: the DID
|
|
58
|
+
* service entry (and a by-ref `_meta`) require a path-form `did:web` — a `did:key` dev card has no
|
|
59
|
+
* HTTPS card endpoint and this fails closed (see `didWebToCardUrl`).
|
|
60
|
+
*/
|
|
61
|
+
export declare function withKyaOsCard(card: EntityCard, opts?: {
|
|
62
|
+
byRef?: boolean;
|
|
63
|
+
}): KyaOsCardMount;
|
|
64
|
+
/** A minimum proof assurance the guard enforces. Default: any valid proof (`L3-minus`) passes. */
|
|
65
|
+
export type MinProofLevel = ProofAssurance;
|
|
66
|
+
/** A snake_case rejection code (aligned to the `./proof` reason vocabulary). */
|
|
67
|
+
export type ProofGateCode = 'proof_missing' | 'proof_invalid' | 'proof_level_insufficient';
|
|
68
|
+
/** A 401-shaped rejection: a stable `code`, a human message, and the raw recompute `reasons`. */
|
|
69
|
+
export interface ProofGateError {
|
|
70
|
+
code: ProofGateCode;
|
|
71
|
+
message: string;
|
|
72
|
+
reasons: string[];
|
|
73
|
+
}
|
|
74
|
+
/** The guard verdict: a pass carries the accountable principal + assurance; a fail is 401-shaped. */
|
|
75
|
+
export type ProofGateResult = {
|
|
76
|
+
ok: true;
|
|
77
|
+
did: string;
|
|
78
|
+
level: ProofAssurance;
|
|
79
|
+
warnings?: string[];
|
|
80
|
+
} | {
|
|
81
|
+
ok: false;
|
|
82
|
+
status: 401;
|
|
83
|
+
error: ProofGateError;
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* A per-request holder-of-key guard. Pass the exact request the client SIGNED (`{ method, params }`
|
|
87
|
+
* without `_meta`) and the `_meta` bag that carried the proof; the guard recomputes every binding.
|
|
88
|
+
*/
|
|
89
|
+
export type ProofGuard = (req: ToolRequest, meta: unknown) => Promise<ProofGateResult>;
|
|
90
|
+
/** Options for {@link requireProof}. */
|
|
91
|
+
export interface RequireProofOptions {
|
|
92
|
+
/** Minimum assurance a valid proof must carry (`L3` requires the AS `cnf` fusion). */
|
|
93
|
+
minLevel?: MinProofLevel;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Build a per-request holder-of-key guard from the pre-bound proof-verification seams. The returned
|
|
97
|
+
* guard reads `_meta['org.kya-os/proof@1']`, RECOMPUTES it against the request via {@link verifyCardProof},
|
|
98
|
+
* enforces `opts.minLevel`, and returns `{ ok: true, did, level }` or a 401-shaped rejection. Fail-closed
|
|
99
|
+
* throughout: a missing proof, a broken binding, a throwing verifier, or an assurance below `minLevel`
|
|
100
|
+
* all reject.
|
|
101
|
+
*
|
|
102
|
+
* REPLAY DEFENSE (do NOT skip): `deps.consumeNonceIfFresh` MUST be an ATOMIC test-AND-set — it
|
|
103
|
+
* records the nonce and returns `false` on a replay (SPEC §12.2). A pure read that never persists
|
|
104
|
+
* the nonce is a replay hole. Wire the batteries-included `InMemoryNonceCache` (single-process,
|
|
105
|
+
* race-free) or `consumeFromNonceCacheProvider` (shared store); with neither seam supplied every
|
|
106
|
+
* request FAILS CLOSED (`nonce_seam_missing`).
|
|
107
|
+
*/
|
|
108
|
+
export declare function requireProof(deps: VerifyProofDeps, opts?: RequireProofOptions): ProofGuard;
|
|
109
|
+
/** Read the card proof (`org.kya-os/proof@1`) out of a `_meta` record (undefined when absent / not an
|
|
110
|
+
* object). A legacy session proof under `org.kya-os/proof` is a different key and is simply not seen. */
|
|
111
|
+
export declare function readCardProof(meta: unknown): unknown;
|
|
112
|
+
//# sourceMappingURL=middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/card/middleware.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEzD,OAAO,EAGL,KAAK,eAAe,EACpB,KAAK,cAAc,EACpB,MAAM,WAAW,CAAC;AACnB,OAAO,EAGL,KAAK,cAAc,EAEnB,KAAK,eAAe,EACrB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAI9C,wFAAwF;AACxF,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,yFAAyF;AACzF,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC;IACpB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,kGAAkG;AAClG,MAAM,WAAW,cAAc;IAC7B,uFAAuF;IACvF,QAAQ,EAAE,UAAU,CAAC;IACrB;;;OAGG;IACH,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,8DAA8D;IAC9D,UAAU,EAAE,cAAc,CAAC;IAC3B,qGAAqG;IACrG,eAAe,CAAC,CAAC,SAAS,cAAc,EAAE,UAAU,EAAE,CAAC,GAAG,CAAC,GAAG;QAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC;IACjG,0GAA0G;IAC1G,gBAAgB,CAAC,CAAC,SAAS,eAAe,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG;QAAE,OAAO,EAAE,OAAO,EAAE,CAAA;KAAE,CAAC;CACpF;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,cAAc,CA4B9F;AAsBD,kGAAkG;AAClG,MAAM,MAAM,aAAa,GAAG,cAAc,CAAC;AAE3C,gFAAgF;AAChF,MAAM,MAAM,aAAa,GAAG,eAAe,GAAG,eAAe,GAAG,0BAA0B,CAAC;AAE3F,iGAAiG;AACjG,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,aAAa,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,qGAAqG;AACrG,MAAM,MAAM,eAAe,GACvB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,cAAc,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,GACrE;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,GAAG,CAAC;IAAC,KAAK,EAAE,cAAc,CAAA;CAAE,CAAC;AAEtD;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC,eAAe,CAAC,CAAC;AAEvF,wCAAwC;AACxC,MAAM,WAAW,mBAAmB;IAClC,sFAAsF;IACtF,QAAQ,CAAC,EAAE,aAAa,CAAC;CAC1B;AAKD;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,eAAe,EAAE,IAAI,GAAE,mBAAwB,GAAG,UAAU,CAsB9F;AAED;0GAC0G;AAC1G,wBAAgB,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAEpD"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KYA-OS Entity Card — DevX middleware (the 10-minute adoption path).
|
|
3
|
+
*
|
|
4
|
+
* Two ergonomic wrappers hide the RFC 9421 / 9449 / 8785 machinery behind one call each:
|
|
5
|
+
*
|
|
6
|
+
* - `withKyaOsCard(card)` — the EMIT side. Bundles the three artifacts a server must publish
|
|
7
|
+
* (the `card.json` body, the `KyaOsEntityCard` DID-document service entry, and the
|
|
8
|
+
* `server.json` `_meta['org.kya-os/card']` fragment) and MOUNTS them onto existing objects —
|
|
9
|
+
* merging the `_meta` into a server.json and appending the service entry to a DID document,
|
|
10
|
+
* both immutably (a shallow clone; a stripped `_meta` degrades to a fetch, never a failure).
|
|
11
|
+
*
|
|
12
|
+
* - `requireProof(deps, { minLevel? })` — the VERIFY side. Returns a per-request guard that
|
|
13
|
+
* reads the holder-of-key proof from `_meta['org.kya-os/proof@1']`, RECOMPUTES it via
|
|
14
|
+
* `./proof` ({@link verifyCardProof}) — every binding, fail-closed — enforces a minimum
|
|
15
|
+
* assurance, and returns a 401-shaped result on any failure. The caller passes the exact
|
|
16
|
+
* `{ method, params }` the client signed (i.e. WITHOUT `_meta`), so the recomputed
|
|
17
|
+
* `requestHash` matches.
|
|
18
|
+
*
|
|
19
|
+
* Pure composition over the shipped engine — no new crypto, no runtime (`mcp-i-core`) dependency.
|
|
20
|
+
*/
|
|
21
|
+
import { isRecord } from '../utils/guards.js';
|
|
22
|
+
import { toDidServiceEntry, toServerCardMeta, } from './emit.js';
|
|
23
|
+
import { verifyCardProof, KYA_OS_CARD_PROOF_META_KEY, } from './proof/index.js';
|
|
24
|
+
/**
|
|
25
|
+
* Bundle a card into its three discovery artifacts and hand back immutable mounters. `opts.byRef`
|
|
26
|
+
* projects the `_meta` as a lazy-fetch `cardRef` instead of an inline summary. NOTE: the DID
|
|
27
|
+
* service entry (and a by-ref `_meta`) require a path-form `did:web` — a `did:key` dev card has no
|
|
28
|
+
* HTTPS card endpoint and this fails closed (see `didWebToCardUrl`).
|
|
29
|
+
*/
|
|
30
|
+
export function withKyaOsCard(card, opts = {}) {
|
|
31
|
+
const isDidWeb = card.id.startsWith('did:web:');
|
|
32
|
+
if (opts.byRef && !isDidWeb) {
|
|
33
|
+
throw new Error(`withKyaOsCard: { byRef } needs an HTTPS card URL that only a did:web card has (got "${card.id}"); ` +
|
|
34
|
+
'use the default inline summary for a did:key card');
|
|
35
|
+
}
|
|
36
|
+
// The DID-document service entry anchors the card at an HTTPS endpoint — only a did:web card has
|
|
37
|
+
// one. A did:key dev card still projects an inline `serverMeta`; it just has no web service entry,
|
|
38
|
+
// so building one is skipped rather than thrown (the caller may only want `mountServerJson`).
|
|
39
|
+
const didServiceEntry = isDidWeb ? toDidServiceEntry(card) : undefined;
|
|
40
|
+
const serverMeta = toServerCardMeta(card, opts);
|
|
41
|
+
return {
|
|
42
|
+
cardJson: card,
|
|
43
|
+
didServiceEntry,
|
|
44
|
+
serverMeta,
|
|
45
|
+
mountServerJson: (serverJson) => mergeServerMeta(serverJson, serverMeta),
|
|
46
|
+
mountDidDocument: (didDoc) => {
|
|
47
|
+
if (!didServiceEntry) {
|
|
48
|
+
throw new Error(`withKyaOsCard: card "${card.id}" is not a did:web card, so it has no DID-document service ` +
|
|
49
|
+
'entry to mount — publish its inline serverMeta with mountServerJson instead');
|
|
50
|
+
}
|
|
51
|
+
return appendService(didDoc, didServiceEntry);
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/** Merge the card `_meta` fragment into a server.json `_meta` (shallow clone; card key wins). */
|
|
56
|
+
function mergeServerMeta(serverJson, meta) {
|
|
57
|
+
return { ...serverJson, _meta: { ...(serverJson._meta ?? {}), ...meta } };
|
|
58
|
+
}
|
|
59
|
+
/** Append the `KyaOsEntityCard` service entry to a DID document's `service[]` (dedup by id, clone). */
|
|
60
|
+
function appendService(didDoc, entry) {
|
|
61
|
+
const existing = Array.isArray(didDoc.service) ? didDoc.service : [];
|
|
62
|
+
const deduped = existing.filter((s) => !(isRecord(s) && s.id === entry.id));
|
|
63
|
+
return { ...didDoc, service: [...deduped, entry] };
|
|
64
|
+
}
|
|
65
|
+
/** Assurance ordering for the `minLevel` gate (`L3-minus` is the floor, `L3` the ceiling). */
|
|
66
|
+
const ASSURANCE_RANK = { 'L3-minus': 1, L3: 2 };
|
|
67
|
+
/**
|
|
68
|
+
* Build a per-request holder-of-key guard from the pre-bound proof-verification seams. The returned
|
|
69
|
+
* guard reads `_meta['org.kya-os/proof@1']`, RECOMPUTES it against the request via {@link verifyCardProof},
|
|
70
|
+
* enforces `opts.minLevel`, and returns `{ ok: true, did, level }` or a 401-shaped rejection. Fail-closed
|
|
71
|
+
* throughout: a missing proof, a broken binding, a throwing verifier, or an assurance below `minLevel`
|
|
72
|
+
* all reject.
|
|
73
|
+
*
|
|
74
|
+
* REPLAY DEFENSE (do NOT skip): `deps.consumeNonceIfFresh` MUST be an ATOMIC test-AND-set — it
|
|
75
|
+
* records the nonce and returns `false` on a replay (SPEC §12.2). A pure read that never persists
|
|
76
|
+
* the nonce is a replay hole. Wire the batteries-included `InMemoryNonceCache` (single-process,
|
|
77
|
+
* race-free) or `consumeFromNonceCacheProvider` (shared store); with neither seam supplied every
|
|
78
|
+
* request FAILS CLOSED (`nonce_seam_missing`).
|
|
79
|
+
*/
|
|
80
|
+
export function requireProof(deps, opts = {}) {
|
|
81
|
+
return async (req, meta) => {
|
|
82
|
+
const proof = readCardProof(meta);
|
|
83
|
+
if (proof === undefined) {
|
|
84
|
+
return fail('proof_missing', 'no org.kya-os/proof@1 in _meta', ['proof_missing']);
|
|
85
|
+
}
|
|
86
|
+
const result = await recompute(proof, req, deps);
|
|
87
|
+
if (!result.ok || result.did === undefined || result.level === undefined) {
|
|
88
|
+
return fail('proof_invalid', 'holder-of-key proof did not verify', result.reasons);
|
|
89
|
+
}
|
|
90
|
+
const level = result.level;
|
|
91
|
+
if (opts.minLevel && ASSURANCE_RANK[level] < ASSURANCE_RANK[opts.minLevel]) {
|
|
92
|
+
const message = `proof assurance ${level} is below the required ${opts.minLevel}`;
|
|
93
|
+
return fail('proof_level_insufficient', message, ['proof_level_insufficient']);
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
ok: true,
|
|
97
|
+
did: result.did,
|
|
98
|
+
level,
|
|
99
|
+
...(result.warnings ? { warnings: result.warnings } : {}),
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/** Read the card proof (`org.kya-os/proof@1`) out of a `_meta` record (undefined when absent / not an
|
|
104
|
+
* object). A legacy session proof under `org.kya-os/proof` is a different key and is simply not seen. */
|
|
105
|
+
export function readCardProof(meta) {
|
|
106
|
+
return isRecord(meta) ? meta[KYA_OS_CARD_PROOF_META_KEY] : undefined;
|
|
107
|
+
}
|
|
108
|
+
/** Recompute the proof, fail-closed: a throwing verifier demotes to a rejected result (never escapes). */
|
|
109
|
+
async function recompute(proof, req, deps) {
|
|
110
|
+
try {
|
|
111
|
+
return await verifyCardProof(proof, req, deps);
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
return { ok: false, reasons: ['proof_verifier_threw'] };
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/** A 401-shaped rejection. */
|
|
118
|
+
function fail(code, message, reasons) {
|
|
119
|
+
return { ok: false, status: 401, error: { code, message, reasons } };
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../src/card/middleware.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KYA-OS Entity Card proof — MINT (`buildCardProof`).
|
|
3
|
+
*
|
|
4
|
+
* Mint a stateless, sender-constrained `org.kya-os/proof@1` for one request and return it under the
|
|
5
|
+
* card proof's OWN `_meta` key ({@link KYA_OS_CARD_PROOF_META_KEY} = `org.kya-os/proof@1`), distinct
|
|
6
|
+
* from the legacy session proof's `org.kya-os/proof` so the two coexist. The proof binds:
|
|
7
|
+
* `requestHash` → THIS body (JCS), `audience` → THIS recipient, `nonce` + `created`/`expires` → NOW,
|
|
8
|
+
* `kid` → the signing DID key, and (optionally) `cnf.jkt` → the token's RFC 9449 sender-constraint.
|
|
9
|
+
* Crypto is entirely inside the injected {@link ProofSigner}.
|
|
10
|
+
*/
|
|
11
|
+
import type { ToolRequest } from '../../proof/generator.js';
|
|
12
|
+
import { KYA_OS_CARD_PROOF_META_KEY, type BuildProofContext, type CardProofMeta, type ProofSigner } from './types.js';
|
|
13
|
+
/**
|
|
14
|
+
* Mint an `org.kya-os/proof@1` for `req`, signed by `signer`, bound to `ctx`. Returns the proof
|
|
15
|
+
* keyed by {@link KYA_OS_CARD_PROOF_META_KEY} so it can be spread straight into an MCP request
|
|
16
|
+
* `_meta`. The `cnf.jkt` is `ctx.cnfJkt` when given, else the signer's own key thumbprint, else
|
|
17
|
+
* omitted (an L3-minus proof — still bound by request + audience + nonce + key).
|
|
18
|
+
*/
|
|
19
|
+
export declare function buildCardProof(req: ToolRequest, signer: ProofSigner, ctx: BuildProofContext): Promise<{
|
|
20
|
+
[KYA_OS_CARD_PROOF_META_KEY]: CardProofMeta;
|
|
21
|
+
}>;
|
|
22
|
+
//# sourceMappingURL=build.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../../src/card/proof/build.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAG5D,OAAO,EAEL,0BAA0B,EAG1B,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,KAAK,WAAW,EACjB,MAAM,YAAY,CAAC;AAEpB;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAE,WAAW,EAChB,MAAM,EAAE,WAAW,EACnB,GAAG,EAAE,iBAAiB,GACrB,OAAO,CAAC;IAAE,CAAC,0BAA0B,CAAC,EAAE,aAAa,CAAA;CAAE,CAAC,CAoC1D"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KYA-OS Entity Card proof — MINT (`buildCardProof`).
|
|
3
|
+
*
|
|
4
|
+
* Mint a stateless, sender-constrained `org.kya-os/proof@1` for one request and return it under the
|
|
5
|
+
* card proof's OWN `_meta` key ({@link KYA_OS_CARD_PROOF_META_KEY} = `org.kya-os/proof@1`), distinct
|
|
6
|
+
* from the legacy session proof's `org.kya-os/proof` so the two coexist. The proof binds:
|
|
7
|
+
* `requestHash` → THIS body (JCS), `audience` → THIS recipient, `nonce` + `created`/`expires` → NOW,
|
|
8
|
+
* `kid` → the signing DID key, and (optionally) `cnf.jkt` → the token's RFC 9449 sender-constraint.
|
|
9
|
+
* Crypto is entirely inside the injected {@link ProofSigner}.
|
|
10
|
+
*/
|
|
11
|
+
import { canonicalPayloadBytes, computeRequestHash } from './canonical.js';
|
|
12
|
+
import { httpSignatureBaseBytes } from './http-sig.js';
|
|
13
|
+
import { DEFAULT_TTL_SEC, KYA_OS_CARD_PROOF_META_KEY, MAX_TTL_SEC, PROOF_PROFILE_V1, } from './types.js';
|
|
14
|
+
/**
|
|
15
|
+
* Mint an `org.kya-os/proof@1` for `req`, signed by `signer`, bound to `ctx`. Returns the proof
|
|
16
|
+
* keyed by {@link KYA_OS_CARD_PROOF_META_KEY} so it can be spread straight into an MCP request
|
|
17
|
+
* `_meta`. The `cnf.jkt` is `ctx.cnfJkt` when given, else the signer's own key thumbprint, else
|
|
18
|
+
* omitted (an L3-minus proof — still bound by request + audience + nonce + key).
|
|
19
|
+
*/
|
|
20
|
+
export async function buildCardProof(req, signer, ctx) {
|
|
21
|
+
const created = Math.floor((ctx.now?.() ?? Date.now()) / 1000);
|
|
22
|
+
const ttlSec = ctx.ttlSec ?? DEFAULT_TTL_SEC;
|
|
23
|
+
// Fail FAST at mint: a proof longer than the profile cap is guaranteed to be rejected by the
|
|
24
|
+
// verifier (ttl_too_long), so surface the caller's error here rather than emit a doomed proof.
|
|
25
|
+
// The verifier remains the authoritative enforcer; both reference the one shared MAX_TTL_SEC.
|
|
26
|
+
if (ttlSec > MAX_TTL_SEC) {
|
|
27
|
+
throw new Error(`buildCardProof: ttlSec ${ttlSec} exceeds the profile cap of ${MAX_TTL_SEC}s — mint a shorter-lived proof`);
|
|
28
|
+
}
|
|
29
|
+
const expires = created + ttlSec;
|
|
30
|
+
const requestHash = await computeRequestHash(req);
|
|
31
|
+
const jkt = ctx.cnfJkt ?? signer.jkt;
|
|
32
|
+
const unsigned = {
|
|
33
|
+
prf: PROOF_PROFILE_V1,
|
|
34
|
+
alg: signer.alg ?? 'EdDSA',
|
|
35
|
+
did: signer.did,
|
|
36
|
+
kid: signer.kid,
|
|
37
|
+
audience: ctx.audience,
|
|
38
|
+
nonce: ctx.nonce,
|
|
39
|
+
created,
|
|
40
|
+
expires,
|
|
41
|
+
requestHash,
|
|
42
|
+
...(jkt !== undefined ? { cnf: { jkt } } : {}),
|
|
43
|
+
jws: '',
|
|
44
|
+
};
|
|
45
|
+
const jws = await signer.sign(canonicalPayloadBytes(unsigned));
|
|
46
|
+
const signed = { ...unsigned, jws };
|
|
47
|
+
// Dual carrier: when the signer exposes a raw-signature seam, ALSO sign the RFC 9421 base so the
|
|
48
|
+
// HTTP Message Signature sibling is genuinely cross-verifiable against the DID key. Absent it,
|
|
49
|
+
// the proof ships JWS-only and the sibling degrades away (never a failure).
|
|
50
|
+
if (!signer.signRaw)
|
|
51
|
+
return { [KYA_OS_CARD_PROOF_META_KEY]: signed };
|
|
52
|
+
const httpSig = await signer.signRaw(httpSignatureBaseBytes(signed));
|
|
53
|
+
return { [KYA_OS_CARD_PROOF_META_KEY]: { ...signed, httpSig } };
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=build.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build.js","sourceRoot":"","sources":["../../../src/card/proof/build.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAC3E,OAAO,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EACL,eAAe,EACf,0BAA0B,EAC1B,WAAW,EACX,gBAAgB,GAIjB,MAAM,YAAY,CAAC;AAEpB;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,GAAgB,EAChB,MAAmB,EACnB,GAAsB;IAEtB,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;IAC/D,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,IAAI,eAAe,CAAC;IAC7C,6FAA6F;IAC7F,+FAA+F;IAC/F,8FAA8F;IAC9F,IAAI,MAAM,GAAG,WAAW,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,0BAA0B,MAAM,+BAA+B,WAAW,gCAAgC,CAAC,CAAC;IAC9H,CAAC;IACD,MAAM,OAAO,GAAG,OAAO,GAAG,MAAM,CAAC;IACjC,MAAM,WAAW,GAAG,MAAM,kBAAkB,CAAC,GAAG,CAAC,CAAC;IAClD,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,IAAI,MAAM,CAAC,GAAG,CAAC;IAErC,MAAM,QAAQ,GAAkB;QAC9B,GAAG,EAAE,gBAAgB;QACrB,GAAG,EAAE,MAAM,CAAC,GAAG,IAAI,OAAO;QAC1B,GAAG,EAAE,MAAM,CAAC,GAAG;QACf,GAAG,EAAE,MAAM,CAAC,GAAG;QACf,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,OAAO;QACP,OAAO;QACP,WAAW;QACX,GAAG,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9C,GAAG,EAAE,EAAE;KACR,CAAC;IAEF,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,qBAAqB,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC/D,MAAM,MAAM,GAAkB,EAAE,GAAG,QAAQ,EAAE,GAAG,EAAE,CAAC;IAEnD,iGAAiG;IACjG,+FAA+F;IAC/F,4EAA4E;IAC5E,IAAI,CAAC,MAAM,CAAC,OAAO;QAAE,OAAO,EAAE,CAAC,0BAA0B,CAAC,EAAE,MAAM,EAAE,CAAC;IACrE,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,sBAAsB,CAAC,MAAM,CAAC,CAAC,CAAC;IACrE,OAAO,EAAE,CAAC,0BAA0B,CAAC,EAAE,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,EAAE,CAAC;AAClE,CAAC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KYA-OS Entity Card proof — canonicalization + hashing (the single source of truth).
|
|
3
|
+
*
|
|
4
|
+
* Both the minter ({@link buildCardProof}) and the verifier ({@link verifyCardProof}) derive
|
|
5
|
+
* their signing input from HERE, so the two can never drift. Reuses `json-canonicalize` (RFC
|
|
6
|
+
* 8785 / JCS) — the same canonicalizer `src/proof/generator.ts` uses — and the same
|
|
7
|
+
* `{ method, params }` request shape, so the `requestHash` is cross-implementation stable.
|
|
8
|
+
*
|
|
9
|
+
* `requestHash` is emitted in the RFC 9421 Content-Digest structured-field form
|
|
10
|
+
* (`sha-256=:<base64>:`) so the HTTP Message Signature sibling can carry it verbatim.
|
|
11
|
+
*/
|
|
12
|
+
import type { ToolRequest } from '../../proof/generator.js';
|
|
13
|
+
import type { CardProofMeta } from './types.js';
|
|
14
|
+
/** A signing JWK (Ed25519 OKP or P-256 EC; public, or private with `d`) — typed locally to avoid a
|
|
15
|
+
* DOM lib dependency. `y` is present only for EC (P-256) keys. */
|
|
16
|
+
export interface RawSigningJwk {
|
|
17
|
+
kty: string;
|
|
18
|
+
crv: string;
|
|
19
|
+
x: string;
|
|
20
|
+
y?: string;
|
|
21
|
+
d?: string;
|
|
22
|
+
}
|
|
23
|
+
/** SHA-256 over `bytes`. */
|
|
24
|
+
export declare function sha256(bytes: Uint8Array): Promise<Uint8Array>;
|
|
25
|
+
/**
|
|
26
|
+
* A RAW EdDSA signature (NOT JWS-framed) over `data` with an Ed25519 private JWK. This is the
|
|
27
|
+
* signature a stock RFC 9421 verifier expects over the signature base — distinct from the detached
|
|
28
|
+
* JWS, whose signature also covers the protected header and so can never satisfy a 9421 verifier.
|
|
29
|
+
*/
|
|
30
|
+
export declare function ed25519SignRaw(privateJwk: RawSigningJwk, data: Uint8Array): Promise<Uint8Array>;
|
|
31
|
+
/** Verify a RAW EdDSA signature over `data` against an Ed25519 public JWK. Fail-closed on error. */
|
|
32
|
+
export declare function ed25519VerifyRaw(publicJwk: RawSigningJwk, signature: Uint8Array, data: Uint8Array): Promise<boolean>;
|
|
33
|
+
/**
|
|
34
|
+
* A RAW ES256 signature (ECDSA P-256 over SHA-256, `r||s` — NOT DER, NOT JWS-framed) over `data`
|
|
35
|
+
* with a P-256 private JWK. This is the RFC 9421 `ecdsa-p256-sha256` form a stock 9421 verifier
|
|
36
|
+
* reconstructs over the signature base — the FIPS-eligible sibling to {@link ed25519SignRaw}.
|
|
37
|
+
*/
|
|
38
|
+
export declare function es256SignRaw(privateJwk: RawSigningJwk, data: Uint8Array): Promise<Uint8Array>;
|
|
39
|
+
/** Verify a RAW ES256 signature over `data` against a P-256 public JWK. Fail-closed on error. */
|
|
40
|
+
export declare function es256VerifyRaw(publicJwk: RawSigningJwk, signature: Uint8Array, data: Uint8Array): Promise<boolean>;
|
|
41
|
+
/**
|
|
42
|
+
* Bind a request to its `requestHash`: SHA-256 over `JCS({ method, params })`, emitted as the RFC
|
|
43
|
+
* 9421 Content-Digest structured field `sha-256=:<base64>:` (chosen so the HTTP Message Signature
|
|
44
|
+
* sibling can carry it verbatim, §8.3/§8.5).
|
|
45
|
+
*
|
|
46
|
+
* INPUT-SHAPE parity, OUTPUT-FORMAT difference: the JCS input mirrors the legacy hasher's
|
|
47
|
+
* `{ method, params }` shape, so the underlying digest BYTES are identical — but the legacy hasher
|
|
48
|
+
* ({@link computeCanonicalHashes}) emits `sha256:<hex>`, so the two STRINGS never compare equal.
|
|
49
|
+
* A card proof is verified ONLY by the card verifier (which recomputes this exact form); do not
|
|
50
|
+
* string-compare it against a legacy `sha256:<hex>` value — use {@link digestsEqual} to compare the
|
|
51
|
+
* underlying digests across formats.
|
|
52
|
+
*/
|
|
53
|
+
export declare function computeRequestHash(req: ToolRequest): Promise<string>;
|
|
54
|
+
/**
|
|
55
|
+
* True iff two request-hash strings carry the SAME SHA-256 digest, accepting EITHER the card's RFC
|
|
56
|
+
* 9421 `sha-256=:<base64>:` form or the legacy `sha256:<hex>` form. The two forms are never
|
|
57
|
+
* string-equal for the same digest, so cross-format integrators MUST compare with this, not `===`.
|
|
58
|
+
*/
|
|
59
|
+
export declare function digestsEqual(a: string, b: string): boolean;
|
|
60
|
+
/** The COVERED claims (every proof field except `jws`) — the object the JWS actually signs. */
|
|
61
|
+
export declare function coveredClaims(meta: CardProofMeta): Record<string, unknown>;
|
|
62
|
+
/** The JCS canonical bytes of the covered claims — the exact detached-JWS signing payload. */
|
|
63
|
+
export declare function canonicalPayloadBytes(meta: CardProofMeta): Uint8Array;
|
|
64
|
+
/** Re-encode a base64url value (a JWS signature) as standard base64 (an RFC 9421 byte sequence). */
|
|
65
|
+
export declare function base64urlToBase64(b64url: string): string;
|
|
66
|
+
//# sourceMappingURL=canonical.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canonical.d.ts","sourceRoot":"","sources":["../../../src/card/proof/canonical.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE5D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAIhD;mEACmE;AACnE,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,CAAC,CAAC,EAAE,MAAM,CAAC;CACZ;AAmCD,4BAA4B;AAC5B,wBAAsB,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAEnE;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,UAAU,EAAE,aAAa,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAIrG;AAED,oGAAoG;AACpG,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,aAAa,EACxB,SAAS,EAAE,UAAU,EACrB,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,OAAO,CAAC,CAQlB;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,UAAU,EAAE,aAAa,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAInG;AAED,iGAAiG;AACjG,wBAAsB,cAAc,CAClC,SAAS,EAAE,aAAa,EACxB,SAAS,EAAE,UAAU,EACrB,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,OAAO,CAAC,CAclB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAM1E;AAaD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAI1D;AAED,+FAA+F;AAC/F,wBAAgB,aAAa,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAa1E;AAED,8FAA8F;AAC9F,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,aAAa,GAAG,UAAU,CAErE;AAED,oGAAoG;AACpG,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAExD"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KYA-OS Entity Card proof — canonicalization + hashing (the single source of truth).
|
|
3
|
+
*
|
|
4
|
+
* Both the minter ({@link buildCardProof}) and the verifier ({@link verifyCardProof}) derive
|
|
5
|
+
* their signing input from HERE, so the two can never drift. Reuses `json-canonicalize` (RFC
|
|
6
|
+
* 8785 / JCS) — the same canonicalizer `src/proof/generator.ts` uses — and the same
|
|
7
|
+
* `{ method, params }` request shape, so the `requestHash` is cross-implementation stable.
|
|
8
|
+
*
|
|
9
|
+
* `requestHash` is emitted in the RFC 9421 Content-Digest structured-field form
|
|
10
|
+
* (`sha-256=:<base64>:`) so the HTTP Message Signature sibling can carry it verbatim.
|
|
11
|
+
*/
|
|
12
|
+
import { canonicalize } from 'json-canonicalize';
|
|
13
|
+
import { base64ToBytes, base64urlDecodeToBytes, bytesToBase64 } from '../../utils/base64.js';
|
|
14
|
+
const encoder = new TextEncoder();
|
|
15
|
+
const ED25519 = { name: 'Ed25519' };
|
|
16
|
+
const ES256_IMPORT = { name: 'ECDSA', namedCurve: 'P-256' };
|
|
17
|
+
const ES256_SIGN = { name: 'ECDSA', hash: 'SHA-256' };
|
|
18
|
+
/** The WebCrypto subtle (Node ≥ 20 / Workers via `globalThis.crypto`), fail-closed when absent. */
|
|
19
|
+
function subtle() {
|
|
20
|
+
const c = globalThis.crypto;
|
|
21
|
+
if (!c?.subtle)
|
|
22
|
+
throw new Error('card/proof: WebCrypto SubtleCrypto is unavailable');
|
|
23
|
+
return c.subtle;
|
|
24
|
+
}
|
|
25
|
+
/** SHA-256 over `bytes`. */
|
|
26
|
+
export async function sha256(bytes) {
|
|
27
|
+
return new Uint8Array(await subtle().digest('SHA-256', bytes));
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* A RAW EdDSA signature (NOT JWS-framed) over `data` with an Ed25519 private JWK. This is the
|
|
31
|
+
* signature a stock RFC 9421 verifier expects over the signature base — distinct from the detached
|
|
32
|
+
* JWS, whose signature also covers the protected header and so can never satisfy a 9421 verifier.
|
|
33
|
+
*/
|
|
34
|
+
export async function ed25519SignRaw(privateJwk, data) {
|
|
35
|
+
const s = subtle();
|
|
36
|
+
const key = await s.importKey('jwk', privateJwk, ED25519, false, ['sign']);
|
|
37
|
+
return new Uint8Array(await s.sign(ED25519, key, data));
|
|
38
|
+
}
|
|
39
|
+
/** Verify a RAW EdDSA signature over `data` against an Ed25519 public JWK. Fail-closed on error. */
|
|
40
|
+
export async function ed25519VerifyRaw(publicJwk, signature, data) {
|
|
41
|
+
try {
|
|
42
|
+
const s = subtle();
|
|
43
|
+
const key = await s.importKey('jwk', { kty: publicJwk.kty, crv: publicJwk.crv, x: publicJwk.x }, ED25519, false, ['verify']);
|
|
44
|
+
return await s.verify(ED25519, key, signature, data);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* A RAW ES256 signature (ECDSA P-256 over SHA-256, `r||s` — NOT DER, NOT JWS-framed) over `data`
|
|
52
|
+
* with a P-256 private JWK. This is the RFC 9421 `ecdsa-p256-sha256` form a stock 9421 verifier
|
|
53
|
+
* reconstructs over the signature base — the FIPS-eligible sibling to {@link ed25519SignRaw}.
|
|
54
|
+
*/
|
|
55
|
+
export async function es256SignRaw(privateJwk, data) {
|
|
56
|
+
const s = subtle();
|
|
57
|
+
const key = await s.importKey('jwk', privateJwk, ES256_IMPORT, false, ['sign']);
|
|
58
|
+
return new Uint8Array(await s.sign(ES256_SIGN, key, data));
|
|
59
|
+
}
|
|
60
|
+
/** Verify a RAW ES256 signature over `data` against a P-256 public JWK. Fail-closed on error. */
|
|
61
|
+
export async function es256VerifyRaw(publicJwk, signature, data) {
|
|
62
|
+
try {
|
|
63
|
+
const s = subtle();
|
|
64
|
+
const key = await s.importKey('jwk', { kty: publicJwk.kty, crv: publicJwk.crv, x: publicJwk.x, y: publicJwk.y }, ES256_IMPORT, false, ['verify']);
|
|
65
|
+
return await s.verify(ES256_SIGN, key, signature, data);
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Bind a request to its `requestHash`: SHA-256 over `JCS({ method, params })`, emitted as the RFC
|
|
73
|
+
* 9421 Content-Digest structured field `sha-256=:<base64>:` (chosen so the HTTP Message Signature
|
|
74
|
+
* sibling can carry it verbatim, §8.3/§8.5).
|
|
75
|
+
*
|
|
76
|
+
* INPUT-SHAPE parity, OUTPUT-FORMAT difference: the JCS input mirrors the legacy hasher's
|
|
77
|
+
* `{ method, params }` shape, so the underlying digest BYTES are identical — but the legacy hasher
|
|
78
|
+
* ({@link computeCanonicalHashes}) emits `sha256:<hex>`, so the two STRINGS never compare equal.
|
|
79
|
+
* A card proof is verified ONLY by the card verifier (which recomputes this exact form); do not
|
|
80
|
+
* string-compare it against a legacy `sha256:<hex>` value — use {@link digestsEqual} to compare the
|
|
81
|
+
* underlying digests across formats.
|
|
82
|
+
*/
|
|
83
|
+
export async function computeRequestHash(req) {
|
|
84
|
+
const canonicalRequest = { method: req.method, ...(req.params ? { params: req.params } : {}) };
|
|
85
|
+
const digest = await sha256(encoder.encode(canonicalize(canonicalRequest)));
|
|
86
|
+
return `sha-256=:${bytesToBase64(digest)}:`;
|
|
87
|
+
}
|
|
88
|
+
/** Hex of the SHA-256 digest carried by a `sha-256=:<base64>:` (RFC 9421) or `sha256:<hex>` (legacy)
|
|
89
|
+
* string, or `null` if it is neither form. Lets integrators compare the two formats by digest. */
|
|
90
|
+
function digestHex(value) {
|
|
91
|
+
const rfc9421 = /^sha-256=:([A-Za-z0-9+/=]+):$/.exec(value.trim());
|
|
92
|
+
if (rfc9421?.[1]) {
|
|
93
|
+
return Array.from(base64ToBytes(rfc9421[1]), (b) => b.toString(16).padStart(2, '0')).join('');
|
|
94
|
+
}
|
|
95
|
+
const legacy = /^sha256:([0-9a-fA-F]+)$/.exec(value.trim());
|
|
96
|
+
return legacy?.[1] ? legacy[1].toLowerCase() : null;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* True iff two request-hash strings carry the SAME SHA-256 digest, accepting EITHER the card's RFC
|
|
100
|
+
* 9421 `sha-256=:<base64>:` form or the legacy `sha256:<hex>` form. The two forms are never
|
|
101
|
+
* string-equal for the same digest, so cross-format integrators MUST compare with this, not `===`.
|
|
102
|
+
*/
|
|
103
|
+
export function digestsEqual(a, b) {
|
|
104
|
+
const ha = digestHex(a);
|
|
105
|
+
const hb = digestHex(b);
|
|
106
|
+
return ha !== null && ha === hb;
|
|
107
|
+
}
|
|
108
|
+
/** The COVERED claims (every proof field except `jws`) — the object the JWS actually signs. */
|
|
109
|
+
export function coveredClaims(meta) {
|
|
110
|
+
return {
|
|
111
|
+
prf: meta.prf,
|
|
112
|
+
alg: meta.alg,
|
|
113
|
+
did: meta.did,
|
|
114
|
+
kid: meta.kid,
|
|
115
|
+
audience: meta.audience,
|
|
116
|
+
nonce: meta.nonce,
|
|
117
|
+
created: meta.created,
|
|
118
|
+
expires: meta.expires,
|
|
119
|
+
requestHash: meta.requestHash,
|
|
120
|
+
...(meta.cnf ? { cnf: meta.cnf } : {}),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
/** The JCS canonical bytes of the covered claims — the exact detached-JWS signing payload. */
|
|
124
|
+
export function canonicalPayloadBytes(meta) {
|
|
125
|
+
return encoder.encode(canonicalize(coveredClaims(meta)));
|
|
126
|
+
}
|
|
127
|
+
/** Re-encode a base64url value (a JWS signature) as standard base64 (an RFC 9421 byte sequence). */
|
|
128
|
+
export function base64urlToBase64(b64url) {
|
|
129
|
+
return bytesToBase64(base64urlDecodeToBytes(b64url));
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=canonical.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canonical.js","sourceRoot":"","sources":["../../../src/card/proof/canonical.ts"],"names":[],"mappings":"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"}
|