@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.
- package/CHANGELOG.md +69 -0
- package/README.md +219 -3
- 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 +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- 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/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 +3 -267
- 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 +45 -891
- 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/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/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,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KYA-OS Entity Card — fluent BUILDER (the 10-minute adoption path).
|
|
3
|
+
*
|
|
4
|
+
* `card({ did, entityType, name })` opens a fluent chain that accumulates declared facts and
|
|
5
|
+
* `.build()`s them into an `EntityCard` — a thin, ergonomic front over {@link buildCard} that
|
|
6
|
+
* hides the card shape behind readable, self-documenting calls:
|
|
7
|
+
*
|
|
8
|
+
* card({ did, entityType: 'agent', name: 'Acme Pay' })
|
|
9
|
+
* .capability('search') // L1 bare-string capability
|
|
10
|
+
* .attestedCapability('payments.transfer', vc) // L2 attested capability (VC-backed)
|
|
11
|
+
* .accountableTo('did:web:acme.example', { via: 'vc_root>del_123' })
|
|
12
|
+
* .build();
|
|
13
|
+
*
|
|
14
|
+
* Claim-minimal like `buildCard`: it asserts only identity + type + declared capabilities +
|
|
15
|
+
* accountability locators; trust-bearing claims are PROVEN by the referenced credentials, not
|
|
16
|
+
* minted here. The infrastructure coordinates it can ALSO carry — `.usesProof()` (proof profile),
|
|
17
|
+
* `.cimd()`, `.revocation()`, `.didDocument()`, `.publicKey()` — are self-descriptive pointers, not
|
|
18
|
+
* credential-proven claims, so the ergonomic path can emit a card that plugs into the proof / CIMD /
|
|
19
|
+
* revocation machinery. `conformanceLevel` is intentionally never set — a verifier RECOMPUTES it.
|
|
20
|
+
* Pure, no I/O, no crypto: no runtime (`mcp-i-core`) dependency leaks in.
|
|
21
|
+
*/
|
|
22
|
+
import { buildCard } from './build.js';
|
|
23
|
+
import { PROOF_PROFILE_ID } from './schema.js';
|
|
24
|
+
/** The single proof profile a KYA-OS card advertises (holder-of-key, per-request `_meta`). */
|
|
25
|
+
const KYA_OS_PROOF_PROFILE = PROOF_PROFILE_ID;
|
|
26
|
+
/**
|
|
27
|
+
* A fluent accumulator over one card's declared facts. Mutable + chainable (each method returns
|
|
28
|
+
* `this`); `.build()` projects the accumulated facts through {@link buildCard}. Prefer the `card()`
|
|
29
|
+
* factory over `new CardBuilder(...)`.
|
|
30
|
+
*/
|
|
31
|
+
export class CardBuilder {
|
|
32
|
+
identity;
|
|
33
|
+
entityType;
|
|
34
|
+
name;
|
|
35
|
+
capabilities = [];
|
|
36
|
+
attestations = [];
|
|
37
|
+
responsibleParty;
|
|
38
|
+
principal;
|
|
39
|
+
delegationRef;
|
|
40
|
+
proofProfile;
|
|
41
|
+
cimdBinding;
|
|
42
|
+
revocationEntry;
|
|
43
|
+
didDocumentUrl;
|
|
44
|
+
publicKeyJwk;
|
|
45
|
+
constructor(init) {
|
|
46
|
+
this.identity = { did: init.did };
|
|
47
|
+
if (init.kid !== undefined)
|
|
48
|
+
this.identity.kid = init.kid;
|
|
49
|
+
if (init.createdAt !== undefined)
|
|
50
|
+
this.identity.createdAt = init.createdAt;
|
|
51
|
+
this.entityType = init.entityType;
|
|
52
|
+
this.name = init.name;
|
|
53
|
+
}
|
|
54
|
+
/** Declare an L1 bare-string capability (self-asserted; a verifier floors it at L1). */
|
|
55
|
+
capability(name) {
|
|
56
|
+
this.capabilities.push(name);
|
|
57
|
+
return this;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Declare an L2 capability backed by an attestation VC. Repeated calls for the SAME capability
|
|
61
|
+
* name accumulate onto its `attestations[]` (one capability, several proofs) rather than
|
|
62
|
+
* duplicating the entry.
|
|
63
|
+
*/
|
|
64
|
+
attestedCapability(name, vc) {
|
|
65
|
+
const existing = this.findAttested(name);
|
|
66
|
+
if (existing)
|
|
67
|
+
existing.attestations.push({ vc });
|
|
68
|
+
else
|
|
69
|
+
this.capabilities.push({ name, attestations: [{ vc }] });
|
|
70
|
+
return this;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Attach a standalone attestation (e.g. a KYC/KYB `IdentityVerification` VC on the responsible
|
|
74
|
+
* party) that is not tied to a single capability.
|
|
75
|
+
*/
|
|
76
|
+
attestation(attestation) {
|
|
77
|
+
this.attestations.push(attestation);
|
|
78
|
+
return this;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Declare the accountability edge: `responsibleParty` is the ultimately-accountable root (a
|
|
82
|
+
* KYC-able org), `opts.via` the compact `delegationRef` chain locator, and `opts.principal` the
|
|
83
|
+
* immediate human delegator. A verifier RECOMPUTES this edge (delegationRef → responsibleParty).
|
|
84
|
+
*/
|
|
85
|
+
accountableTo(responsibleParty, opts = {}) {
|
|
86
|
+
this.responsibleParty = responsibleParty;
|
|
87
|
+
if (opts.via !== undefined)
|
|
88
|
+
this.delegationRef = opts.via;
|
|
89
|
+
if (opts.principal !== undefined)
|
|
90
|
+
this.principal = opts.principal;
|
|
91
|
+
return this;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Advertise the per-request holder-of-key proof profile (`org.kya-os/proof@1`). This only NAMES
|
|
95
|
+
* the profile — the proof itself is never on the static card; it rides per-request `_meta`.
|
|
96
|
+
*/
|
|
97
|
+
usesProof() {
|
|
98
|
+
this.proofProfile = KYA_OS_PROOF_PROFILE;
|
|
99
|
+
return this;
|
|
100
|
+
}
|
|
101
|
+
/** Bind the L1 CIMD on-ramp coordinates (`client_id` ⇄ `did:web`, `jwks_uri` ⇄ DID keys). */
|
|
102
|
+
cimd(binding) {
|
|
103
|
+
this.cimdBinding = binding;
|
|
104
|
+
return this;
|
|
105
|
+
}
|
|
106
|
+
/** Attach the W3C Bitstring Status List revocation entry (the post-issuance kill switch). */
|
|
107
|
+
revocation(entry) {
|
|
108
|
+
this.revocationEntry = entry;
|
|
109
|
+
return this;
|
|
110
|
+
}
|
|
111
|
+
/** Record the entity's DID document URL (where the `KyaOsEntityCard` service entry lives). */
|
|
112
|
+
didDocument(url) {
|
|
113
|
+
this.didDocumentUrl = url;
|
|
114
|
+
return this;
|
|
115
|
+
}
|
|
116
|
+
/** Inline the entity's Ed25519 public JWK (the card's self-contained verification key). */
|
|
117
|
+
publicKey(jwk) {
|
|
118
|
+
this.publicKeyJwk = jwk;
|
|
119
|
+
return this;
|
|
120
|
+
}
|
|
121
|
+
/** Project the accumulated facts into an `EntityCard` (via {@link buildCard}). */
|
|
122
|
+
build() {
|
|
123
|
+
return buildCard(this.identity, {
|
|
124
|
+
entityType: this.entityType,
|
|
125
|
+
name: this.name,
|
|
126
|
+
...(this.capabilities.length > 0 ? { capabilities: this.capabilities } : {}),
|
|
127
|
+
...(this.attestations.length > 0 ? { attestations: this.attestations } : {}),
|
|
128
|
+
...(this.responsibleParty !== undefined ? { responsibleParty: this.responsibleParty } : {}),
|
|
129
|
+
...(this.principal !== undefined ? { principal: this.principal } : {}),
|
|
130
|
+
...(this.delegationRef !== undefined ? { delegationRef: this.delegationRef } : {}),
|
|
131
|
+
...(this.proofProfile !== undefined ? { proofProfile: this.proofProfile } : {}),
|
|
132
|
+
...(this.cimdBinding !== undefined ? { cimd: this.cimdBinding } : {}),
|
|
133
|
+
...(this.revocationEntry !== undefined ? { revocation: this.revocationEntry } : {}),
|
|
134
|
+
...(this.didDocumentUrl !== undefined ? { didDocument: this.didDocumentUrl } : {}),
|
|
135
|
+
...(this.publicKeyJwk !== undefined ? { publicKeyJwk: this.publicKeyJwk } : {}),
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
/** Find an already-declared attested capability by name (for attestation accumulation). */
|
|
139
|
+
findAttested(name) {
|
|
140
|
+
return this.capabilities.find((c) => typeof c !== 'string' && c.name === name);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
/** Open a fluent card-building chain (the ergonomic entry point). */
|
|
144
|
+
export function card(init) {
|
|
145
|
+
return new CardBuilder(init);
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"builder.js","sourceRoot":"","sources":["../../src/card/builder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KYA-OS Entity Card — CIMD L1 on-ramp bind.
|
|
3
|
+
*
|
|
4
|
+
* CIMD (draft-ietf-oauth-client-id-metadata-document, the MCP default since 2025-11-25) is
|
|
5
|
+
* the L1 on-ramp with zero new infra: the OAuth `client_id` IS the entity's `did:web` in its
|
|
6
|
+
* HTTPS form, and the `jwks_uri` the AS validates `private_key_jwt` against IS a mechanical
|
|
7
|
+
* projection of the DID document's keys — so OAuth client-authentication becomes a DID-key
|
|
8
|
+
* proof, and the access token the AS mints can be sender-constrained (RFC 9449 `cnf.jkt`) to
|
|
9
|
+
* the exact key the per-request holder-of-key proof later carries (closing L1 → L3).
|
|
10
|
+
*
|
|
11
|
+
* - `bindClientId` / `didFromClientId` — the W3C `did:web` ⇄ HTTPS bijection
|
|
12
|
+
* (`did:web:host:a:b` ⇄ `https://host/a/b`, the authority colon percent-encoded for ports).
|
|
13
|
+
* - `didKeyedJwks` — DID-document `verificationMethod[]` Ed25519 → an OKP JWK set
|
|
14
|
+
* (`kid` preserved), stripping any private `d` and skipping non-Ed25519 methods.
|
|
15
|
+
* - `toClientMetadata` — PROJECT the card into the CIMD doc served at the `client_id` URL
|
|
16
|
+
* (`token_endpoint_auth_method: private_key_jwt`, `_meta['org.kya-os/did']` = the DID).
|
|
17
|
+
* - `cardFromClientMetadata` — DERIVE the L1 card from a CIMD doc (a pure-CIMD client with
|
|
18
|
+
* no DID still onboards: a `did:web` is minted from its `client_id`).
|
|
19
|
+
* - `verifyCimdBind` — the anti-substitution graft, FAIL-CLOSED: origin-equality
|
|
20
|
+
* (`did:web` host === `client_id` origin === `jwks_uri` origin) AND a reciprocal
|
|
21
|
+
* `alsoKnownAs` bind, so a hostile CIMD pointing `jwks_uri` at someone else's keys (or
|
|
22
|
+
* claiming a victim's DID) fails closed.
|
|
23
|
+
*
|
|
24
|
+
* Pure + deterministic — no I/O, no crypto. All key material is projected, never minted, so
|
|
25
|
+
* no runtime (mcp-i-core) dependency leaks into `@kya-os/mcp`.
|
|
26
|
+
*/
|
|
27
|
+
import type { CimdBinding, Ed25519PublicJwk, EntityCard } from './schema.js';
|
|
28
|
+
/** CIMD `token_endpoint_auth_method` — `private_key_jwt` IS the DID-key proof. */
|
|
29
|
+
export declare const PRIVATE_KEY_JWT = "private_key_jwt";
|
|
30
|
+
/** Reverse-DNS `_meta` key carrying the entity's DID inside a CIMD document. */
|
|
31
|
+
export declare const KYA_OS_DID_META_KEY = "org.kya-os/did";
|
|
32
|
+
/** A CIMD (client_id metadata document) projected from / parsed into an EntityCard. */
|
|
33
|
+
export interface ClientMetadata {
|
|
34
|
+
client_id: string;
|
|
35
|
+
client_name: string;
|
|
36
|
+
token_endpoint_auth_method: typeof PRIVATE_KEY_JWT;
|
|
37
|
+
jwks_uri: string;
|
|
38
|
+
_meta: Record<typeof KYA_OS_DID_META_KEY, string>;
|
|
39
|
+
}
|
|
40
|
+
/** A JSON Web Key Set — the DID-keyed JWKS served at a CIMD `jwks_uri`. */
|
|
41
|
+
export interface Jwks {
|
|
42
|
+
keys: Ed25519PublicJwk[];
|
|
43
|
+
}
|
|
44
|
+
/** The fail-closed result of `verifyCimdBind` — `ok` iff there are no `reasons`. */
|
|
45
|
+
export interface CimdBindResult {
|
|
46
|
+
ok: boolean;
|
|
47
|
+
reasons: string[];
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Bind a `did:web` to its OAuth `client_id` (the W3C HTTPS form):
|
|
51
|
+
* `did:web:host:a:b` → `https://host/a/b`
|
|
52
|
+
* `did:web:host%3A3000:a` → `https://host:3000/a` (authority colon percent-decoded)
|
|
53
|
+
* `did:web:host` → `https://host`
|
|
54
|
+
*/
|
|
55
|
+
export declare function bindClientId(did: string): string;
|
|
56
|
+
/**
|
|
57
|
+
* The inverse of `bindClientId`: an HTTPS `client_id` → its `did:web` (authority colon
|
|
58
|
+
* percent-encoded for ports). `https://host/a/b` → `did:web:host:a:b`. https-only,
|
|
59
|
+
* fail-closed.
|
|
60
|
+
*/
|
|
61
|
+
export declare function didFromClientId(clientId: string): string;
|
|
62
|
+
/**
|
|
63
|
+
* Project a DID document's `verificationMethod[]` into the JWKS the AS validates
|
|
64
|
+
* `private_key_jwt` against. Only Ed25519 (`OKP`) keys are projected; `kid` is preserved
|
|
65
|
+
* (the JWK's own `kid`, else the verification method `id`); any private `d` is stripped.
|
|
66
|
+
*/
|
|
67
|
+
export declare function didKeyedJwks(didDoc: unknown): Jwks;
|
|
68
|
+
/**
|
|
69
|
+
* Project a card into the CIMD document served at its `client_id` URL. The
|
|
70
|
+
* `token_endpoint_auth_method` is `private_key_jwt` — so the AS validating it against
|
|
71
|
+
* `jwks_uri` is verifying a DID-key signature.
|
|
72
|
+
*/
|
|
73
|
+
export declare function toClientMetadata(card: EntityCard, opts: {
|
|
74
|
+
jwksUri: string;
|
|
75
|
+
}): ClientMetadata;
|
|
76
|
+
/**
|
|
77
|
+
* Derive the L1 card from a CIMD document. The DID is read from `_meta['org.kya-os/did']`
|
|
78
|
+
* when present, else MINTED from the `client_id` (a pure-CIMD client still onboards). The
|
|
79
|
+
* card is `entityType: 'client'` and carries the CIMD coordinates when a `jwks_uri` is given.
|
|
80
|
+
* Fail-closed: the result is validated through `parseCard`.
|
|
81
|
+
*/
|
|
82
|
+
export declare function cardFromClientMetadata(meta: unknown): EntityCard;
|
|
83
|
+
/**
|
|
84
|
+
* Verify a CIMD binding against the entity's DID document, FAIL-CLOSED. Enforces:
|
|
85
|
+
* 1. origin-equality — `did:web` host === `client_id` origin === `jwks_uri` origin
|
|
86
|
+
* (a hostile CIMD pointing `jwks_uri` at another origin's keys fails here);
|
|
87
|
+
* 2. a reciprocal `alsoKnownAs` bind — the DID document lists the `client_id` URL, so a
|
|
88
|
+
* CIMD cannot unilaterally claim a DID it does not control.
|
|
89
|
+
* `ok` is true iff there are no `reasons`.
|
|
90
|
+
*/
|
|
91
|
+
export declare function verifyCimdBind(cimd: CimdBinding, didDoc: unknown): CimdBindResult;
|
|
92
|
+
//# sourceMappingURL=cimd.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cimd.d.ts","sourceRoot":"","sources":["../../src/card/cimd.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAK7E,kFAAkF;AAClF,eAAO,MAAM,eAAe,oBAAoB,CAAC;AAEjD,gFAAgF;AAChF,eAAO,MAAM,mBAAmB,mBAAmB,CAAC;AAIpD,uFAAuF;AACvF,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,0BAA0B,EAAE,OAAO,eAAe,CAAC;IACnD,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC,OAAO,mBAAmB,EAAE,MAAM,CAAC,CAAC;CACnD;AAED,2EAA2E;AAC3E,MAAM,WAAW,IAAI;IACnB,IAAI,EAAE,gBAAgB,EAAE,CAAC;CAC1B;AAED,oFAAoF;AACpF,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAID;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAQhD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAaxD;AAID;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CASlD;AAID;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,cAAc,CAQ5F;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,OAAO,GAAG,UAAU,CAiBhE;AAID;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,GAAG,cAAc,CAqBjF"}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KYA-OS Entity Card — CIMD L1 on-ramp bind.
|
|
3
|
+
*
|
|
4
|
+
* CIMD (draft-ietf-oauth-client-id-metadata-document, the MCP default since 2025-11-25) is
|
|
5
|
+
* the L1 on-ramp with zero new infra: the OAuth `client_id` IS the entity's `did:web` in its
|
|
6
|
+
* HTTPS form, and the `jwks_uri` the AS validates `private_key_jwt` against IS a mechanical
|
|
7
|
+
* projection of the DID document's keys — so OAuth client-authentication becomes a DID-key
|
|
8
|
+
* proof, and the access token the AS mints can be sender-constrained (RFC 9449 `cnf.jkt`) to
|
|
9
|
+
* the exact key the per-request holder-of-key proof later carries (closing L1 → L3).
|
|
10
|
+
*
|
|
11
|
+
* - `bindClientId` / `didFromClientId` — the W3C `did:web` ⇄ HTTPS bijection
|
|
12
|
+
* (`did:web:host:a:b` ⇄ `https://host/a/b`, the authority colon percent-encoded for ports).
|
|
13
|
+
* - `didKeyedJwks` — DID-document `verificationMethod[]` Ed25519 → an OKP JWK set
|
|
14
|
+
* (`kid` preserved), stripping any private `d` and skipping non-Ed25519 methods.
|
|
15
|
+
* - `toClientMetadata` — PROJECT the card into the CIMD doc served at the `client_id` URL
|
|
16
|
+
* (`token_endpoint_auth_method: private_key_jwt`, `_meta['org.kya-os/did']` = the DID).
|
|
17
|
+
* - `cardFromClientMetadata` — DERIVE the L1 card from a CIMD doc (a pure-CIMD client with
|
|
18
|
+
* no DID still onboards: a `did:web` is minted from its `client_id`).
|
|
19
|
+
* - `verifyCimdBind` — the anti-substitution graft, FAIL-CLOSED: origin-equality
|
|
20
|
+
* (`did:web` host === `client_id` origin === `jwks_uri` origin) AND a reciprocal
|
|
21
|
+
* `alsoKnownAs` bind, so a hostile CIMD pointing `jwks_uri` at someone else's keys (or
|
|
22
|
+
* claiming a victim's DID) fails closed.
|
|
23
|
+
*
|
|
24
|
+
* Pure + deterministic — no I/O, no crypto. All key material is projected, never minted, so
|
|
25
|
+
* no runtime (mcp-i-core) dependency leaks into `@kya-os/mcp`.
|
|
26
|
+
*/
|
|
27
|
+
import { isRecord } from '../utils/guards.js';
|
|
28
|
+
import { parseCard } from './resolve.js';
|
|
29
|
+
/** The OAuth `client_id` metadata-document prefix this module transforms. */
|
|
30
|
+
const DID_WEB_PREFIX = 'did:web:';
|
|
31
|
+
/** CIMD `token_endpoint_auth_method` — `private_key_jwt` IS the DID-key proof. */
|
|
32
|
+
export const PRIVATE_KEY_JWT = 'private_key_jwt';
|
|
33
|
+
/** Reverse-DNS `_meta` key carrying the entity's DID inside a CIMD document. */
|
|
34
|
+
export const KYA_OS_DID_META_KEY = 'org.kya-os/did';
|
|
35
|
+
// ── client_id ⇄ did:web bijection ─────────────────────────────────────────────
|
|
36
|
+
/**
|
|
37
|
+
* Bind a `did:web` to its OAuth `client_id` (the W3C HTTPS form):
|
|
38
|
+
* `did:web:host:a:b` → `https://host/a/b`
|
|
39
|
+
* `did:web:host%3A3000:a` → `https://host:3000/a` (authority colon percent-decoded)
|
|
40
|
+
* `did:web:host` → `https://host`
|
|
41
|
+
*/
|
|
42
|
+
export function bindClientId(did) {
|
|
43
|
+
if (!did.startsWith(DID_WEB_PREFIX)) {
|
|
44
|
+
throw new Error(`bindClientId: only did:web has an HTTPS client_id form (got "${did}")`);
|
|
45
|
+
}
|
|
46
|
+
const [authority, ...segments] = didWebSegments(did);
|
|
47
|
+
if (!authority)
|
|
48
|
+
throw new Error(`bindClientId: did:web "${did}" has no host authority`);
|
|
49
|
+
const path = segments.length ? `/${segments.join('/')}` : '';
|
|
50
|
+
return `https://${authority}${path}`;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The inverse of `bindClientId`: an HTTPS `client_id` → its `did:web` (authority colon
|
|
54
|
+
* percent-encoded for ports). `https://host/a/b` → `did:web:host:a:b`. https-only,
|
|
55
|
+
* fail-closed.
|
|
56
|
+
*/
|
|
57
|
+
export function didFromClientId(clientId) {
|
|
58
|
+
let url;
|
|
59
|
+
try {
|
|
60
|
+
url = new URL(clientId);
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
throw new Error(`didFromClientId: client_id is not a valid URL ("${clientId}")`);
|
|
64
|
+
}
|
|
65
|
+
if (url.protocol !== 'https:') {
|
|
66
|
+
throw new Error(`didFromClientId: client_id must be https (got "${url.protocol}")`);
|
|
67
|
+
}
|
|
68
|
+
const authority = encodeURIComponent(url.host);
|
|
69
|
+
const segments = url.pathname.split('/').filter((s) => s.length > 0).map(encodeURIComponent);
|
|
70
|
+
return `${DID_WEB_PREFIX}${[authority, ...segments].join(':')}`;
|
|
71
|
+
}
|
|
72
|
+
// ── DID-keyed JWKS ─────────────────────────────────────────────────────────────
|
|
73
|
+
/**
|
|
74
|
+
* Project a DID document's `verificationMethod[]` into the JWKS the AS validates
|
|
75
|
+
* `private_key_jwt` against. Only Ed25519 (`OKP`) keys are projected; `kid` is preserved
|
|
76
|
+
* (the JWK's own `kid`, else the verification method `id`); any private `d` is stripped.
|
|
77
|
+
*/
|
|
78
|
+
export function didKeyedJwks(didDoc) {
|
|
79
|
+
const vms = isRecord(didDoc) && Array.isArray(didDoc.verificationMethod) ? didDoc.verificationMethod : [];
|
|
80
|
+
const keys = [];
|
|
81
|
+
for (const vm of vms) {
|
|
82
|
+
const jwk = vmToOkpJwk(vm);
|
|
83
|
+
if (jwk)
|
|
84
|
+
keys.push(jwk);
|
|
85
|
+
}
|
|
86
|
+
return { keys };
|
|
87
|
+
}
|
|
88
|
+
// ── CIMD document projection / derivation ──────────────────────────────────────
|
|
89
|
+
/**
|
|
90
|
+
* Project a card into the CIMD document served at its `client_id` URL. The
|
|
91
|
+
* `token_endpoint_auth_method` is `private_key_jwt` — so the AS validating it against
|
|
92
|
+
* `jwks_uri` is verifying a DID-key signature.
|
|
93
|
+
*/
|
|
94
|
+
export function toClientMetadata(card, opts) {
|
|
95
|
+
return {
|
|
96
|
+
client_id: bindClientId(card.id),
|
|
97
|
+
client_name: card.name,
|
|
98
|
+
token_endpoint_auth_method: PRIVATE_KEY_JWT,
|
|
99
|
+
jwks_uri: opts.jwksUri,
|
|
100
|
+
_meta: { [KYA_OS_DID_META_KEY]: card.id },
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Derive the L1 card from a CIMD document. The DID is read from `_meta['org.kya-os/did']`
|
|
105
|
+
* when present, else MINTED from the `client_id` (a pure-CIMD client still onboards). The
|
|
106
|
+
* card is `entityType: 'client'` and carries the CIMD coordinates when a `jwks_uri` is given.
|
|
107
|
+
* Fail-closed: the result is validated through `parseCard`.
|
|
108
|
+
*/
|
|
109
|
+
export function cardFromClientMetadata(meta) {
|
|
110
|
+
if (!isRecord(meta)) {
|
|
111
|
+
throw new Error('cardFromClientMetadata: client metadata must be an object');
|
|
112
|
+
}
|
|
113
|
+
const clientId = meta.client_id;
|
|
114
|
+
if (typeof clientId !== 'string') {
|
|
115
|
+
throw new Error('cardFromClientMetadata: missing string client_id');
|
|
116
|
+
}
|
|
117
|
+
const did = didFromMeta(meta, clientId);
|
|
118
|
+
const jwksUri = typeof meta.jwks_uri === 'string' ? meta.jwks_uri : undefined;
|
|
119
|
+
const card = {
|
|
120
|
+
id: did,
|
|
121
|
+
entityType: 'client',
|
|
122
|
+
name: typeof meta.client_name === 'string' && meta.client_name.length > 0 ? meta.client_name : did,
|
|
123
|
+
};
|
|
124
|
+
if (jwksUri !== undefined)
|
|
125
|
+
card.cimd = { clientId, jwksUri };
|
|
126
|
+
return parseCard(card);
|
|
127
|
+
}
|
|
128
|
+
// ── Anti-substitution bind (FAIL-CLOSED) ───────────────────────────────────────
|
|
129
|
+
/**
|
|
130
|
+
* Verify a CIMD binding against the entity's DID document, FAIL-CLOSED. Enforces:
|
|
131
|
+
* 1. origin-equality — `did:web` host === `client_id` origin === `jwks_uri` origin
|
|
132
|
+
* (a hostile CIMD pointing `jwks_uri` at another origin's keys fails here);
|
|
133
|
+
* 2. a reciprocal `alsoKnownAs` bind — the DID document lists the `client_id` URL, so a
|
|
134
|
+
* CIMD cannot unilaterally claim a DID it does not control.
|
|
135
|
+
* `ok` is true iff there are no `reasons`.
|
|
136
|
+
*/
|
|
137
|
+
export function verifyCimdBind(cimd, didDoc) {
|
|
138
|
+
const reasons = [];
|
|
139
|
+
const doc = isRecord(didDoc) ? didDoc : {};
|
|
140
|
+
const did = typeof doc.id === 'string' ? doc.id : '';
|
|
141
|
+
const didOrigin = safeDidOrigin(did, reasons);
|
|
142
|
+
const clientOrigin = safeOrigin(cimd.clientId, 'client_id', reasons);
|
|
143
|
+
const jwksOrigin = safeOrigin(cimd.jwksUri, 'jwks_uri', reasons);
|
|
144
|
+
if (didOrigin && clientOrigin && didOrigin !== clientOrigin) {
|
|
145
|
+
reasons.push(`origin mismatch: did:web (${didOrigin}) !== client_id (${clientOrigin})`);
|
|
146
|
+
}
|
|
147
|
+
if (clientOrigin && jwksOrigin && clientOrigin !== jwksOrigin) {
|
|
148
|
+
reasons.push(`origin mismatch: client_id (${clientOrigin}) !== jwks_uri (${jwksOrigin})`);
|
|
149
|
+
}
|
|
150
|
+
if (!aliasListed(doc.alsoKnownAs, cimd.clientId)) {
|
|
151
|
+
reasons.push(`DID document alsoKnownAs does not list client_id "${cimd.clientId}" (no reciprocal bind)`);
|
|
152
|
+
}
|
|
153
|
+
return { ok: reasons.length === 0, reasons };
|
|
154
|
+
}
|
|
155
|
+
// ── Internals ──────────────────────────────────────────────────────────────────
|
|
156
|
+
/** Split a `did:web` into its percent-decoded `:`-separated segments (authority, then path). */
|
|
157
|
+
function didWebSegments(did) {
|
|
158
|
+
return did.slice(DID_WEB_PREFIX.length).split(':').map(decodeURIComponent);
|
|
159
|
+
}
|
|
160
|
+
/** The DID for a derived card: a declared `_meta['org.kya-os/did']`, else minted from client_id. */
|
|
161
|
+
function didFromMeta(meta, clientId) {
|
|
162
|
+
const block = isRecord(meta._meta) ? meta._meta : undefined;
|
|
163
|
+
const declared = block?.[KYA_OS_DID_META_KEY];
|
|
164
|
+
return typeof declared === 'string' ? declared : didFromClientId(clientId);
|
|
165
|
+
}
|
|
166
|
+
/** Project one verification method to a public OKP JWK (Ed25519 only; `d` stripped), or null. */
|
|
167
|
+
function vmToOkpJwk(vm) {
|
|
168
|
+
if (!isRecord(vm))
|
|
169
|
+
return null;
|
|
170
|
+
const jwk = vm.publicKeyJwk;
|
|
171
|
+
if (!isRecord(jwk) || jwk.kty !== 'OKP' || jwk.crv !== 'Ed25519' || typeof jwk.x !== 'string') {
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
const okp = { kty: 'OKP', crv: 'Ed25519', x: jwk.x };
|
|
175
|
+
const kid = typeof jwk.kid === 'string' ? jwk.kid : typeof vm.id === 'string' ? vm.id : undefined;
|
|
176
|
+
if (kid !== undefined)
|
|
177
|
+
okp.kid = kid;
|
|
178
|
+
return okp;
|
|
179
|
+
}
|
|
180
|
+
/** The HTTPS origin of a `did:web`'s `client_id` form, or null (recording a reason). */
|
|
181
|
+
function safeDidOrigin(did, reasons) {
|
|
182
|
+
if (!did.startsWith(DID_WEB_PREFIX)) {
|
|
183
|
+
reasons.push(`DID document id is not a did:web ("${did}")`);
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
try {
|
|
187
|
+
return new URL(bindClientId(did)).origin;
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
reasons.push(`DID document id has no resolvable origin ("${did}")`);
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
/** The HTTPS origin of a URL, or null (recording a reason); non-https fails closed. */
|
|
195
|
+
function safeOrigin(url, label, reasons) {
|
|
196
|
+
let parsed;
|
|
197
|
+
try {
|
|
198
|
+
parsed = new URL(url);
|
|
199
|
+
}
|
|
200
|
+
catch {
|
|
201
|
+
reasons.push(`${label} is not a valid URL ("${url}")`);
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
if (parsed.protocol !== 'https:') {
|
|
205
|
+
reasons.push(`${label} must be https (got "${parsed.protocol}")`);
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
return parsed.origin;
|
|
209
|
+
}
|
|
210
|
+
/** Whether the DID document's `alsoKnownAs` reciprocally lists the `client_id` URL. */
|
|
211
|
+
function aliasListed(alsoKnownAs, clientId) {
|
|
212
|
+
if (!Array.isArray(alsoKnownAs))
|
|
213
|
+
return false;
|
|
214
|
+
return alsoKnownAs.some((aka) => typeof aka === 'string' && sameUrl(aka, clientId));
|
|
215
|
+
}
|
|
216
|
+
/** Normalized URL equality (tolerant of trailing-slash differences), fail-closed on invalid. */
|
|
217
|
+
function sameUrl(a, b) {
|
|
218
|
+
try {
|
|
219
|
+
return new URL(a).href === new URL(b).href;
|
|
220
|
+
}
|
|
221
|
+
catch {
|
|
222
|
+
return false;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
//# sourceMappingURL=cimd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cimd.js","sourceRoot":"","sources":["../../src/card/cimd.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGzC,6EAA6E;AAC7E,MAAM,cAAc,GAAG,UAAU,CAAC;AAElC,kFAAkF;AAClF,MAAM,CAAC,MAAM,eAAe,GAAG,iBAAiB,CAAC;AAEjD,gFAAgF;AAChF,MAAM,CAAC,MAAM,mBAAmB,GAAG,gBAAgB,CAAC;AAwBpD,iFAAiF;AAEjF;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAAC,GAAW;IACtC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CAAC,gEAAgE,GAAG,IAAI,CAAC,CAAC;IAC3F,CAAC;IACD,MAAM,CAAC,SAAS,EAAE,GAAG,QAAQ,CAAC,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;IACrD,IAAI,CAAC,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,GAAG,yBAAyB,CAAC,CAAC;IACxF,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7D,OAAO,WAAW,SAAS,GAAG,IAAI,EAAE,CAAC;AACvC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,QAAgB;IAC9C,IAAI,GAAQ,CAAC;IACb,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,mDAAmD,QAAQ,IAAI,CAAC,CAAC;IACnF,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,kDAAkD,GAAG,CAAC,QAAQ,IAAI,CAAC,CAAC;IACtF,CAAC;IACD,MAAM,SAAS,GAAG,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC/C,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;IAC7F,OAAO,GAAG,cAAc,GAAG,CAAC,SAAS,EAAE,GAAG,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;AAClE,CAAC;AAED,kFAAkF;AAElF;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,MAAe;IAC1C,MAAM,GAAG,GACP,QAAQ,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE,CAAC;IAChG,MAAM,IAAI,GAAuB,EAAE,CAAC;IACpC,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC;QACrB,MAAM,GAAG,GAAG,UAAU,CAAC,EAAE,CAAC,CAAC;QAC3B,IAAI,GAAG;YAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC1B,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,CAAC;AAClB,CAAC;AAED,kFAAkF;AAElF;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAgB,EAAE,IAAyB;IAC1E,OAAO;QACL,SAAS,EAAE,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;QAChC,WAAW,EAAE,IAAI,CAAC,IAAI;QACtB,0BAA0B,EAAE,eAAe;QAC3C,QAAQ,EAAE,IAAI,CAAC,OAAO;QACtB,KAAK,EAAE,EAAE,CAAC,mBAAmB,CAAC,EAAE,IAAI,CAAC,EAAE,EAAE;KAC1C,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CAAC,IAAa;IAClD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAC;IAC/E,CAAC;IACD,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC;IAChC,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;IACtE,CAAC;IACD,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACxC,MAAM,OAAO,GAAG,OAAO,IAAI,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC;IAC9E,MAAM,IAAI,GAA4B;QACpC,EAAE,EAAE,GAAG;QACP,UAAU,EAAE,QAAQ;QACpB,IAAI,EAAE,OAAO,IAAI,CAAC,WAAW,KAAK,QAAQ,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG;KACnG,CAAC;IACF,IAAI,OAAO,KAAK,SAAS;QAAE,IAAI,CAAC,IAAI,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;IAC7D,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC;AACzB,CAAC;AAED,kFAAkF;AAElF;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAC,IAAiB,EAAE,MAAe;IAC/D,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3C,MAAM,GAAG,GAAG,OAAO,GAAG,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAErD,MAAM,SAAS,GAAG,aAAa,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC9C,MAAM,YAAY,GAAG,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC;IACrE,MAAM,UAAU,GAAG,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;IAEjE,IAAI,SAAS,IAAI,YAAY,IAAI,SAAS,KAAK,YAAY,EAAE,CAAC;QAC5D,OAAO,CAAC,IAAI,CAAC,6BAA6B,SAAS,oBAAoB,YAAY,GAAG,CAAC,CAAC;IAC1F,CAAC;IACD,IAAI,YAAY,IAAI,UAAU,IAAI,YAAY,KAAK,UAAU,EAAE,CAAC;QAC9D,OAAO,CAAC,IAAI,CAAC,+BAA+B,YAAY,mBAAmB,UAAU,GAAG,CAAC,CAAC;IAC5F,CAAC;IACD,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QACjD,OAAO,CAAC,IAAI,CACV,qDAAqD,IAAI,CAAC,QAAQ,wBAAwB,CAC3F,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC;AAC/C,CAAC;AAED,kFAAkF;AAElF,gGAAgG;AAChG,SAAS,cAAc,CAAC,GAAW;IACjC,OAAO,GAAG,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;AAC7E,CAAC;AAED,oGAAoG;AACpG,SAAS,WAAW,CAAC,IAA6B,EAAE,QAAgB;IAClE,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;IAC5D,MAAM,QAAQ,GAAG,KAAK,EAAE,CAAC,mBAAmB,CAAC,CAAC;IAC9C,OAAO,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;AAC7E,CAAC;AAED,iGAAiG;AACjG,SAAS,UAAU,CAAC,EAAW;IAC7B,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QAAE,OAAO,IAAI,CAAC;IAC/B,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC;IAC5B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,GAAG,KAAK,KAAK,IAAI,GAAG,CAAC,GAAG,KAAK,SAAS,IAAI,OAAO,GAAG,CAAC,CAAC,KAAK,QAAQ,EAAE,CAAC;QAC9F,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,GAAG,GAAqB,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC;IACvE,MAAM,GAAG,GAAG,OAAO,GAAG,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IAClG,IAAI,GAAG,KAAK,SAAS;QAAE,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC;IACrC,OAAO,GAAG,CAAC;AACb,CAAC;AAED,wFAAwF;AACxF,SAAS,aAAa,CAAC,GAAW,EAAE,OAAiB;IACnD,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;QACpC,OAAO,CAAC,IAAI,CAAC,sCAAsC,GAAG,IAAI,CAAC,CAAC;QAC5D,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,IAAI,CAAC,8CAA8C,GAAG,IAAI,CAAC,CAAC;QACpE,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,uFAAuF;AACvF,SAAS,UAAU,CAAC,GAAW,EAAE,KAAa,EAAE,OAAiB;IAC/D,IAAI,MAAW,CAAC;IAChB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,IAAI,CAAC,GAAG,KAAK,yBAAyB,GAAG,IAAI,CAAC,CAAC;QACvD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACjC,OAAO,CAAC,IAAI,CAAC,GAAG,KAAK,wBAAwB,MAAM,CAAC,QAAQ,IAAI,CAAC,CAAC;QAClE,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC;AACvB,CAAC;AAED,uFAAuF;AACvF,SAAS,WAAW,CAAC,WAAoB,EAAE,QAAgB;IACzD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC;QAAE,OAAO,KAAK,CAAC;IAC9C,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,GAAG,KAAK,QAAQ,IAAI,OAAO,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC;AACtF,CAAC;AAED,gGAAgG;AAChG,SAAS,OAAO,CAAC,CAAS,EAAE,CAAS;IACnC,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KYA-OS Entity Card — DELEGATION (W3C VC 2.0 + ZCAP-LD profile, CRISP attenuation).
|
|
3
|
+
*
|
|
4
|
+
* A DelegationCredential is a W3C VC 2.0 whose `credentialSubject` IS an attenuated ZCAP-LD
|
|
5
|
+
* capability (`@context` carries `w3id.org/security/zcap/v1` + the KYA-OS delegation namespace).
|
|
6
|
+
* One credential per HOP; a delegation CHAIN runs `root → … → leaf`. We PROFILE, not fork.
|
|
7
|
+
*
|
|
8
|
+
* CRISP attenuation is enforced structurally on resolve and is FAIL-CLOSED — any broadening hop
|
|
9
|
+
* invalidates the whole chain: child `allowedAction` ⊆ parent; caveats monotone-narrowing (child
|
|
10
|
+
* `MaxAmount`/`ValidUntil` ≤ parent, no parent caveat silently dropped, unknown caveats replicated
|
|
11
|
+
* verbatim); top-level `validUntil` narrowing; CONTINUITY (the parent's delegate `invoker` MUST be
|
|
12
|
+
* the child's `issuer` — you only re-delegate what was delegated to YOUR key — and
|
|
13
|
+
* `child.parentCapability` references the parent `id`); a constant `invocationTarget`; depth ≤
|
|
14
|
+
* {@link MAX_DELEGATION_DEPTH}; ROOT `parentCapability` = the resource, `issuer`/`invocationTarget`
|
|
15
|
+
* = (optional) resource owner / resource. THE JOIN (recomputed, asserted nowhere):
|
|
16
|
+
* {@link responsiblePartyOf} = `issuer(rootVC)`, {@link leafInvokerOf} = the leaf delegate a verifier
|
|
17
|
+
* asserts equals `proof.did`. Revocation reuses the injected {@link RevocationChecker} seam from
|
|
18
|
+
* `./revocation` (no status-list churn reaches callers; NO `mcp-i-core` runtime dep). Per-hop
|
|
19
|
+
* signature verification is a SEPARATE injected concern; this module owns the CRISP + continuity recompute.
|
|
20
|
+
*/
|
|
21
|
+
import { z } from 'zod';
|
|
22
|
+
import { type BitstringStatusListEntry } from './schema.js';
|
|
23
|
+
import { type RevocationChecker } from './revocation.js';
|
|
24
|
+
export declare const DELEGATION_CONTEXT_V2 = "https://www.w3.org/ns/credentials/v2";
|
|
25
|
+
export declare const ZCAP_CONTEXT = "https://w3id.org/security/zcap/v1";
|
|
26
|
+
export declare const KYA_OS_DELEGATION_CONTEXT = "https://kya-os.org/ns/delegation/v1";
|
|
27
|
+
export declare const DELEGATION_CREDENTIAL_TYPE = "DelegationCredential";
|
|
28
|
+
export declare const MAX_DELEGATION_DEPTH = 10;
|
|
29
|
+
/** A monotone-narrowing constraint: `{type:'ValidUntil',date}` or `{type:'MaxAmount',limit,currency}`.
|
|
30
|
+
* The flat shape keeps typing clean; unknown caveat types are compared verbatim (fail-closed). */
|
|
31
|
+
export declare const CaveatSchema: z.ZodObject<{
|
|
32
|
+
type: z.ZodString;
|
|
33
|
+
date: z.ZodOptional<z.ZodString>;
|
|
34
|
+
limit: z.ZodOptional<z.ZodString>;
|
|
35
|
+
currency: z.ZodOptional<z.ZodString>;
|
|
36
|
+
}, z.core.$loose>;
|
|
37
|
+
/** The attenuated ZCAP capability carried as the VC `credentialSubject`. */
|
|
38
|
+
export declare const ZcapCapabilitySchema: z.ZodObject<{
|
|
39
|
+
id: z.ZodString;
|
|
40
|
+
controller: z.ZodOptional<z.ZodString>;
|
|
41
|
+
invoker: z.ZodOptional<z.ZodString>;
|
|
42
|
+
parentCapability: z.ZodString;
|
|
43
|
+
invocationTarget: z.ZodString;
|
|
44
|
+
allowedAction: z.ZodArray<z.ZodString>;
|
|
45
|
+
caveats: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
46
|
+
type: z.ZodString;
|
|
47
|
+
date: z.ZodOptional<z.ZodString>;
|
|
48
|
+
limit: z.ZodOptional<z.ZodString>;
|
|
49
|
+
currency: z.ZodOptional<z.ZodString>;
|
|
50
|
+
}, z.core.$loose>>>;
|
|
51
|
+
}, z.core.$loose>;
|
|
52
|
+
/** W3C Bitstring Status List v1.0 `credentialStatus` entry (the StatusList2021 successor). */
|
|
53
|
+
export declare const DelegationCredentialStatusSchema: z.ZodObject<{
|
|
54
|
+
id: z.ZodOptional<z.ZodString>;
|
|
55
|
+
type: z.ZodLiteral<"BitstringStatusListEntry">;
|
|
56
|
+
statusPurpose: z.ZodOptional<z.ZodString>;
|
|
57
|
+
statusListIndex: z.ZodString;
|
|
58
|
+
statusListCredential: z.ZodString;
|
|
59
|
+
}, z.core.$strip>;
|
|
60
|
+
/** Data Integrity proof, `eddsa-jcs-2022` cryptosuite (verified by a separate injected seam). */
|
|
61
|
+
export declare const DataIntegrityProofSchema: z.ZodObject<{
|
|
62
|
+
type: z.ZodLiteral<"DataIntegrityProof">;
|
|
63
|
+
cryptosuite: z.ZodLiteral<"eddsa-jcs-2022">;
|
|
64
|
+
}, z.core.$loose>;
|
|
65
|
+
export declare const DelegationCredentialSchema: z.ZodObject<{
|
|
66
|
+
'@context': z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodUnknown>]>>;
|
|
67
|
+
id: z.ZodOptional<z.ZodString>;
|
|
68
|
+
type: z.ZodArray<z.ZodString>;
|
|
69
|
+
issuer: z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
70
|
+
id: z.ZodString;
|
|
71
|
+
}, z.core.$loose>]>;
|
|
72
|
+
validFrom: z.ZodOptional<z.ZodString>;
|
|
73
|
+
validUntil: z.ZodOptional<z.ZodString>;
|
|
74
|
+
credentialSubject: z.ZodObject<{
|
|
75
|
+
id: z.ZodString;
|
|
76
|
+
controller: z.ZodOptional<z.ZodString>;
|
|
77
|
+
invoker: z.ZodOptional<z.ZodString>;
|
|
78
|
+
parentCapability: z.ZodString;
|
|
79
|
+
invocationTarget: z.ZodString;
|
|
80
|
+
allowedAction: z.ZodArray<z.ZodString>;
|
|
81
|
+
caveats: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
82
|
+
type: z.ZodString;
|
|
83
|
+
date: z.ZodOptional<z.ZodString>;
|
|
84
|
+
limit: z.ZodOptional<z.ZodString>;
|
|
85
|
+
currency: z.ZodOptional<z.ZodString>;
|
|
86
|
+
}, z.core.$loose>>>;
|
|
87
|
+
}, z.core.$loose>;
|
|
88
|
+
credentialStatus: z.ZodOptional<z.ZodObject<{
|
|
89
|
+
id: z.ZodOptional<z.ZodString>;
|
|
90
|
+
type: z.ZodLiteral<"BitstringStatusListEntry">;
|
|
91
|
+
statusPurpose: z.ZodOptional<z.ZodString>;
|
|
92
|
+
statusListIndex: z.ZodString;
|
|
93
|
+
statusListCredential: z.ZodString;
|
|
94
|
+
}, z.core.$strip>>;
|
|
95
|
+
proof: z.ZodOptional<z.ZodObject<{
|
|
96
|
+
type: z.ZodLiteral<"DataIntegrityProof">;
|
|
97
|
+
cryptosuite: z.ZodLiteral<"eddsa-jcs-2022">;
|
|
98
|
+
}, z.core.$loose>>;
|
|
99
|
+
}, z.core.$loose>;
|
|
100
|
+
export type Caveat = z.infer<typeof CaveatSchema>;
|
|
101
|
+
export type ZcapCapability = z.infer<typeof ZcapCapabilitySchema>;
|
|
102
|
+
export type DelegationCredentialStatus = z.infer<typeof DelegationCredentialStatusSchema>;
|
|
103
|
+
export type DelegationCredential = z.infer<typeof DelegationCredentialSchema>;
|
|
104
|
+
export type DelegationChain = readonly DelegationCredential[];
|
|
105
|
+
/** The issuer (delegator) DID, whether `issuer` is a bare string or an `{id}` object. */
|
|
106
|
+
export declare function issuerDid(vc: DelegationCredential): string;
|
|
107
|
+
/** The delegate DID granted this capability (`invoker`, falling back to `controller`). */
|
|
108
|
+
export declare function invokerDid(vc: DelegationCredential): string | undefined;
|
|
109
|
+
/** `responsibleParty` = the issuer of the ROOT VC (ultimately accountable). */
|
|
110
|
+
export declare function responsiblePartyOf(chain: DelegationChain): string | undefined;
|
|
111
|
+
/** The LEAF invoker — a verifier asserts this equals `proof.did`. */
|
|
112
|
+
export declare function leafInvokerOf(chain: DelegationChain): string | undefined;
|
|
113
|
+
/** Project a hop's `credentialStatus` onto the revocation-seam entry shape (if present). */
|
|
114
|
+
export declare function statusEntryOf(vc: DelegationCredential): BitstringStatusListEntry | undefined;
|
|
115
|
+
/** Reasons the `child` FAILS to attenuate its `parent` (empty ⇒ valid hop): action subset, caveat
|
|
116
|
+
* monotonicity, `validUntil` narrowing, invoker→issuer continuity, `parentCapability` linkage,
|
|
117
|
+
* constant `invocationTarget`. */
|
|
118
|
+
export declare function attenuates(parent: DelegationCredential, child: DelegationCredential): string[];
|
|
119
|
+
export interface DelegationChainContext {
|
|
120
|
+
resourceOwner?: string;
|
|
121
|
+
resource?: string;
|
|
122
|
+
maxDepth?: number;
|
|
123
|
+
/** Injectable clock (epoch ms) for the wall-clock expiry gate; default `Date.now` (deterministic tests inject it). */
|
|
124
|
+
now?: () => number;
|
|
125
|
+
}
|
|
126
|
+
export interface DelegationChainResult {
|
|
127
|
+
ok: boolean;
|
|
128
|
+
reasons: string[];
|
|
129
|
+
responsibleParty?: string;
|
|
130
|
+
leafInvoker?: string;
|
|
131
|
+
invocationTarget?: string;
|
|
132
|
+
allowedAction: string[];
|
|
133
|
+
depth: number;
|
|
134
|
+
}
|
|
135
|
+
/** Structurally validate a chain (CRISP + continuity), fail-closed. Signature + revocation
|
|
136
|
+
* are separate injected concerns (see {@link evaluateDelegationChain}). */
|
|
137
|
+
export declare function validateDelegationChain(chain: DelegationChain, ctx?: DelegationChainContext): DelegationChainResult;
|
|
138
|
+
export interface DelegationChainEvaluation extends DelegationChainResult {
|
|
139
|
+
fresh: boolean;
|
|
140
|
+
}
|
|
141
|
+
/** Validate structure AND revocation: run {@link validateDelegationChain}, then (only if it passes —
|
|
142
|
+
* fail-closed) cascade the injected {@link RevocationChecker} root→leaf via
|
|
143
|
+
* {@link evaluateRevocationChain}. A revoked ancestor invalidates the subtree. */
|
|
144
|
+
export declare function evaluateDelegationChain(chain: DelegationChain, check: RevocationChecker, ctx?: DelegationChainContext): Promise<DelegationChainEvaluation>;
|
|
145
|
+
//# sourceMappingURL=delegation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delegation.d.ts","sourceRoot":"","sources":["../../src/card/delegation.ts"],"names":[],"mappings":"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"}
|