@kya-os/mcp 1.5.0 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +82 -0
- package/dist/authz/accountability.d.ts +35 -0
- package/dist/authz/accountability.d.ts.map +1 -0
- package/dist/authz/accountability.js +28 -0
- package/dist/authz/accountability.js.map +1 -0
- package/dist/authz/adapter.d.ts +47 -0
- package/dist/authz/adapter.d.ts.map +1 -0
- package/dist/authz/adapter.js +10 -0
- package/dist/authz/adapter.js.map +1 -0
- package/dist/authz/examples/inmemory-oidc.d.ts +29 -0
- package/dist/authz/examples/inmemory-oidc.d.ts.map +1 -0
- package/dist/authz/examples/inmemory-oidc.js +68 -0
- package/dist/authz/examples/inmemory-oidc.js.map +1 -0
- package/dist/authz/index.d.ts +19 -0
- package/dist/authz/index.d.ts.map +1 -0
- package/dist/authz/index.js +19 -0
- package/dist/authz/index.js.map +1 -0
- package/dist/authz/oidc/authorize.d.ts +25 -0
- package/dist/authz/oidc/authorize.d.ts.map +1 -0
- package/dist/authz/oidc/authorize.js +24 -0
- package/dist/authz/oidc/authorize.js.map +1 -0
- package/dist/authz/oidc/metadata.d.ts +43 -0
- package/dist/authz/oidc/metadata.d.ts.map +1 -0
- package/dist/authz/oidc/metadata.js +32 -0
- package/dist/authz/oidc/metadata.js.map +1 -0
- package/dist/authz/oidc/oidc-adapter.d.ts +52 -0
- package/dist/authz/oidc/oidc-adapter.d.ts.map +1 -0
- package/dist/authz/oidc/oidc-adapter.js +131 -0
- package/dist/authz/oidc/oidc-adapter.js.map +1 -0
- package/dist/authz/oidc/pkce.d.ts +20 -0
- package/dist/authz/oidc/pkce.d.ts.map +1 -0
- package/dist/authz/oidc/pkce.js +29 -0
- package/dist/authz/oidc/pkce.js.map +1 -0
- package/dist/authz/registry.d.ts +29 -0
- package/dist/authz/registry.d.ts.map +1 -0
- package/dist/authz/registry.js +48 -0
- package/dist/authz/registry.js.map +1 -0
- package/dist/authz/requirement.d.ts +38 -0
- package/dist/authz/requirement.d.ts.map +1 -0
- package/dist/authz/requirement.js +45 -0
- package/dist/authz/requirement.js.map +1 -0
- package/dist/delegation/chain-enforcement.d.ts +86 -0
- package/dist/delegation/chain-enforcement.d.ts.map +1 -0
- package/dist/delegation/chain-enforcement.js +224 -0
- package/dist/delegation/chain-enforcement.js.map +1 -0
- package/dist/delegation/holder-binding.d.ts +128 -0
- package/dist/delegation/holder-binding.d.ts.map +1 -0
- package/dist/delegation/holder-binding.js +175 -0
- package/dist/delegation/holder-binding.js.map +1 -0
- package/dist/delegation/index.d.ts +2 -0
- package/dist/delegation/index.d.ts.map +1 -1
- package/dist/delegation/index.js +2 -0
- package/dist/delegation/index.js.map +1 -1
- package/dist/errors.d.ts +1 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +1 -0
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/middleware/with-kya-os.d.ts +35 -1
- package/dist/middleware/with-kya-os.d.ts.map +1 -1
- package/dist/middleware/with-kya-os.js +94 -192
- package/dist/middleware/with-kya-os.js.map +1 -1
- package/dist/providers/grant-store.d.ts +98 -0
- package/dist/providers/grant-store.d.ts.map +1 -0
- package/dist/providers/grant-store.js +92 -0
- package/dist/providers/grant-store.js.map +1 -0
- package/dist/providers/index.d.ts +2 -0
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js +2 -0
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/runtime-fetch.d.ts +14 -0
- package/dist/providers/runtime-fetch.d.ts.map +1 -1
- package/dist/providers/runtime-fetch.js +22 -0
- package/dist/providers/runtime-fetch.js.map +1 -1
- package/dist/providers/web-crypto.d.ts +35 -0
- package/dist/providers/web-crypto.d.ts.map +1 -0
- package/dist/providers/web-crypto.js +91 -0
- package/dist/providers/web-crypto.js.map +1 -0
- package/dist/types/protocol.d.ts +1 -1
- package/dist/types/protocol.d.ts.map +1 -1
- package/dist/types/protocol.js +1 -1
- package/dist/types/protocol.js.map +1 -1
- package/package.json +25 -16
- package/schemas/README.md +1 -1
- package/schemas/delegation-credential.json +2 -2
- package/schemas/detached-proof.json +1 -1
- package/schemas/handshake-request.json +1 -1
- package/schemas/handshake-response.json +1 -1
- package/schemas/well-known-mcpi.json +1 -1
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Delegation chain enforcement — framework-agnostic core (E3 · #2888).
|
|
3
|
+
*
|
|
4
|
+
* The leaf→root chain walk, scope-attenuation, audience binding, confused-deputy
|
|
5
|
+
* guard (KYA-OS §11.6), and ancestor-revocation rules, lifted out of the
|
|
6
|
+
* `with-kya-os` middleware closure so the SAME logic runs in every host (MCP
|
|
7
|
+
* middleware, an HTTP PEP, the conformance harness) against one implementation
|
|
8
|
+
* rather than a per-transport fork.
|
|
9
|
+
*
|
|
10
|
+
* Dependencies are injected as ports (interface-first): a per-credential
|
|
11
|
+
* verifier, an optional ancestor resolver, and an optional graph-backed
|
|
12
|
+
* `RevocationChecker`. Nothing here imports a transport or framework.
|
|
13
|
+
*/
|
|
14
|
+
import { extractDelegationFromVC, } from "../types/protocol.js";
|
|
15
|
+
import { verifyDelegationAudience } from "./audience-validator.js";
|
|
16
|
+
/** Union of a credential's delegation scopes and its constraint scopes. */
|
|
17
|
+
export function getDelegationScopes(credential) {
|
|
18
|
+
const scopes = new Set();
|
|
19
|
+
for (const scope of credential.credentialSubject.delegation.scopes ?? []) {
|
|
20
|
+
scopes.add(scope);
|
|
21
|
+
}
|
|
22
|
+
for (const scope of credential.credentialSubject.delegation.constraints?.scopes ?? []) {
|
|
23
|
+
scopes.add(scope);
|
|
24
|
+
}
|
|
25
|
+
return Array.from(scopes);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* A child re-delegation may only narrow (attenuate) its parent's authority.
|
|
29
|
+
* Enforces flat-scope subset AND crisp-matcher subset (by matcher+resource),
|
|
30
|
+
* failing closed on any widening. Pure; never throws.
|
|
31
|
+
*/
|
|
32
|
+
export function validateScopeAttenuation(parentCredential, childCredential) {
|
|
33
|
+
const parentScopes = getDelegationScopes(parentCredential);
|
|
34
|
+
const childScopes = getDelegationScopes(childCredential);
|
|
35
|
+
const childDelegation = childCredential.credentialSubject.delegation;
|
|
36
|
+
// CRISP matcher attenuation: getDelegationScopes does NOT see constraints.crisp.scopes,
|
|
37
|
+
// so a re-delegation could otherwise widen authority by introducing a broad
|
|
38
|
+
// prefix/regex matcher (e.g. resource:"" matches every scope). Require the child's
|
|
39
|
+
// crisp matchers to be a subset of the parent's (by matcher+resource). Fail closed.
|
|
40
|
+
const crispKey = (s) => `${s.matcher}\u0000${s.resource}`;
|
|
41
|
+
const parentCrisp = new Set((parentCredential.credentialSubject.delegation.constraints.crisp?.scopes ?? []).map(crispKey));
|
|
42
|
+
const widenedCrisp = (childDelegation.constraints.crisp?.scopes ?? []).filter((s) => !parentCrisp.has(crispKey(s)));
|
|
43
|
+
if (widenedCrisp.length > 0) {
|
|
44
|
+
return {
|
|
45
|
+
valid: false,
|
|
46
|
+
reason: `Delegation ${childDelegation.id} introduces crisp scope matcher(s) absent from parent ${parentCredential.credentialSubject.delegation.id}: ${widenedCrisp
|
|
47
|
+
.map((s) => `${s.matcher}:${s.resource}`)
|
|
48
|
+
.join(", ")}`,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
if (parentScopes.length === 0) {
|
|
52
|
+
return { valid: true };
|
|
53
|
+
}
|
|
54
|
+
if (childScopes.length === 0) {
|
|
55
|
+
return {
|
|
56
|
+
valid: false,
|
|
57
|
+
reason: `Delegation ${childDelegation.id} omits scopes required to prove attenuation from parent ${parentCredential.credentialSubject.delegation.id}`,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
const parentScopeSet = new Set(parentScopes);
|
|
61
|
+
const widenedScopes = childScopes.filter((scope) => !parentScopeSet.has(scope));
|
|
62
|
+
if (widenedScopes.length > 0) {
|
|
63
|
+
return {
|
|
64
|
+
valid: false,
|
|
65
|
+
reason: `Delegation ${childDelegation.id} widens scopes beyond parent ${parentCredential.credentialSubject.delegation.id}: ${widenedScopes.join(", ")}`,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
return { valid: true };
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Validate a delegation credential and (if re-delegated) its full chain:
|
|
72
|
+
* structural shape, per-credential verification, audience binding to the server,
|
|
73
|
+
* the §11.6 re-delegation audience-constraint requirement, parent↔child linkage
|
|
74
|
+
* (parentId + issuerDid==parent.subjectDid), cycle detection, scope attenuation,
|
|
75
|
+
* and — when a {@link RevocationChecker} is supplied — graph-backed ancestor
|
|
76
|
+
* revocation. Never throws on a malformed input; returns `{ valid, reason }`.
|
|
77
|
+
*/
|
|
78
|
+
export async function validateDelegationChain(leafCredential, deps, options) {
|
|
79
|
+
// Shape guard (validate* never-throw contract): a structurally malformed leaf
|
|
80
|
+
// returns a { valid, reason } result rather than letting extractDelegationFromVC
|
|
81
|
+
// or the downstream scope check throw. Requires both
|
|
82
|
+
// credentialSubject.delegation AND .constraints (the verifier's own invariant).
|
|
83
|
+
const leafDelegationObj = leafCredential?.credentialSubject?.delegation;
|
|
84
|
+
if (!leafDelegationObj ||
|
|
85
|
+
typeof leafDelegationObj !== "object" ||
|
|
86
|
+
!leafDelegationObj.constraints ||
|
|
87
|
+
typeof leafDelegationObj.constraints !== "object") {
|
|
88
|
+
return {
|
|
89
|
+
valid: false,
|
|
90
|
+
reason: "Malformed delegation credential: missing credentialSubject.delegation or its constraints",
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
const leafDelegation = extractDelegationFromVC(leafCredential);
|
|
94
|
+
let chain = [leafCredential];
|
|
95
|
+
if (leafDelegation.parentId) {
|
|
96
|
+
if (!deps.resolveDelegationChain) {
|
|
97
|
+
return {
|
|
98
|
+
valid: false,
|
|
99
|
+
reason: `Delegation ${leafDelegation.id} references parent ${leafDelegation.parentId} but no resolveDelegationChain handler is configured`,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
let resolvedChain;
|
|
103
|
+
try {
|
|
104
|
+
resolvedChain = await deps.resolveDelegationChain(leafCredential);
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
return {
|
|
108
|
+
valid: false,
|
|
109
|
+
reason: `Failed to resolve delegation chain: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
if (resolvedChain.length === 0) {
|
|
113
|
+
return {
|
|
114
|
+
valid: false,
|
|
115
|
+
reason: `Delegation ${leafDelegation.id} references parent ${leafDelegation.parentId} but the resolved chain is empty`,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
const leafIndex = resolvedChain.findIndex((credential) => credential.credentialSubject.delegation.id === leafDelegation.id);
|
|
119
|
+
if (leafIndex !== -1 && leafIndex !== resolvedChain.length - 1) {
|
|
120
|
+
return {
|
|
121
|
+
valid: false,
|
|
122
|
+
reason: `Resolved delegation chain for ${leafDelegation.id} must end with the leaf credential`,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
chain = leafIndex === -1 ? [...resolvedChain, leafCredential] : resolvedChain;
|
|
126
|
+
}
|
|
127
|
+
const seenIds = new Set();
|
|
128
|
+
let previousDelegation;
|
|
129
|
+
let previousCredential;
|
|
130
|
+
for (const credential of chain) {
|
|
131
|
+
const delegation = extractDelegationFromVC(credential);
|
|
132
|
+
if (seenIds.has(delegation.id)) {
|
|
133
|
+
return {
|
|
134
|
+
valid: false,
|
|
135
|
+
reason: `Delegation chain contains a circular reference at ${delegation.id}`,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
seenIds.add(delegation.id);
|
|
139
|
+
if (credential.credentialStatus && !deps.statusListConfigured) {
|
|
140
|
+
return {
|
|
141
|
+
valid: false,
|
|
142
|
+
reason: `Delegation ${delegation.id} has credentialStatus but no statusListResolver is configured`,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
const credentialVerification = await deps.verifier.verifyDelegationCredential(credential, {
|
|
146
|
+
...(options?.skipSignature ? { skipSignature: true } : {}),
|
|
147
|
+
});
|
|
148
|
+
if (!credentialVerification.valid) {
|
|
149
|
+
return {
|
|
150
|
+
valid: false,
|
|
151
|
+
reason: `Delegation ${delegation.id} invalid: ${credentialVerification.reason}`,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
if (!verifyDelegationAudience(delegation, deps.serverDid)) {
|
|
155
|
+
return {
|
|
156
|
+
valid: false,
|
|
157
|
+
reason: `Delegation ${delegation.id} audience does not include server DID ${deps.serverDid}`,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
// Every non-root credential in the chain MUST carry an `audience` constraint
|
|
161
|
+
// binding it to the verifying server. This closes the confused-deputy class
|
|
162
|
+
// where a re-delegated credential is forwarded to an unintended server
|
|
163
|
+
// (KYA-OS §11.6). Unconditional as of 1.4.0.
|
|
164
|
+
if (delegation.parentId && !delegation.constraints.audience) {
|
|
165
|
+
return {
|
|
166
|
+
valid: false,
|
|
167
|
+
reason: `Delegation ${delegation.id} is a re-delegation (parentId: ${delegation.parentId}) but has no audience constraint. Re-delegations MUST include an audience constraint (KYA-OS §11.6)`,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
if (!previousDelegation || !previousCredential) {
|
|
171
|
+
if (delegation.parentId) {
|
|
172
|
+
return {
|
|
173
|
+
valid: false,
|
|
174
|
+
reason: `Resolved delegation chain is incomplete: root delegation ${delegation.id} still references parent ${delegation.parentId}`,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
previousDelegation = delegation;
|
|
178
|
+
previousCredential = credential;
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
if (delegation.parentId !== previousDelegation.id) {
|
|
182
|
+
return {
|
|
183
|
+
valid: false,
|
|
184
|
+
reason: `Delegation ${delegation.id} references parent ${delegation.parentId} but expected ${previousDelegation.id}`,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
if (delegation.issuerDid !== previousDelegation.subjectDid) {
|
|
188
|
+
return {
|
|
189
|
+
valid: false,
|
|
190
|
+
reason: `Delegation ${delegation.id} issued by ${delegation.issuerDid} but parent subject is ${previousDelegation.subjectDid}`,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
const scopeValidation = validateScopeAttenuation(previousCredential, credential);
|
|
194
|
+
if (!scopeValidation.valid) {
|
|
195
|
+
return scopeValidation;
|
|
196
|
+
}
|
|
197
|
+
previousDelegation = delegation;
|
|
198
|
+
previousCredential = credential;
|
|
199
|
+
}
|
|
200
|
+
const finalDelegation = extractDelegationFromVC(chain[chain.length - 1]);
|
|
201
|
+
if (finalDelegation.id !== leafDelegation.id) {
|
|
202
|
+
return {
|
|
203
|
+
valid: false,
|
|
204
|
+
reason: `Resolved delegation chain ended at ${finalDelegation.id} instead of leaf ${leafDelegation.id}`,
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
// E3.1: graph-backed ancestor revocation. Independent of how the chain above
|
|
208
|
+
// was resolved — catches a cascade-revoked ANCESTOR even when the leaf's own
|
|
209
|
+
// credentialStatus bit was never flipped. Opt-in: only runs when a checker is
|
|
210
|
+
// wired, so existing callers are unaffected.
|
|
211
|
+
if (deps.revocationChecker) {
|
|
212
|
+
const revocation = await deps.revocationChecker.isRevoked(leafDelegation.id);
|
|
213
|
+
if (revocation.revoked) {
|
|
214
|
+
return {
|
|
215
|
+
valid: false,
|
|
216
|
+
reason: revocation.revokedAncestor
|
|
217
|
+
? `Delegation ${leafDelegation.id} is revoked via ancestor ${revocation.revokedAncestor}`
|
|
218
|
+
: `Delegation ${leafDelegation.id} is revoked${revocation.reason ? `: ${revocation.reason}` : ""}`,
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return { valid: true };
|
|
223
|
+
}
|
|
224
|
+
//# sourceMappingURL=chain-enforcement.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chain-enforcement.js","sourceRoot":"","sources":["../../src/delegation/chain-enforcement.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Holder binding — enforce that a request proof is bound to the delegation subject.
|
|
3
|
+
*
|
|
4
|
+
* A delegation credential names a subject DID and grants it authority. On its
|
|
5
|
+
* own that credential is a *bearer* token: anyone who obtains the string can
|
|
6
|
+
* present it. Holder binding closes that gap (spec §11.8 theft-replay residual)
|
|
7
|
+
* by requiring the caller to prove possession of the subject DID's key on the
|
|
8
|
+
* request itself.
|
|
9
|
+
*
|
|
10
|
+
* For a `did:key` subject the proof is exact and needs no new credential fields:
|
|
11
|
+
* the DID *is* the public key, so "the proof verifies against the subject DID's
|
|
12
|
+
* key" is equivalent to "the caller holds the subject's private key". This module
|
|
13
|
+
* derives the subject key straight from the DID and verifies the request proof
|
|
14
|
+
* against it. A proof signed by any other key — a thief replaying a stolen
|
|
15
|
+
* credential — cannot verify and is rejected.
|
|
16
|
+
*
|
|
17
|
+
* `did:web` (and other non-`did:key`) subjects do not encode their key in the
|
|
18
|
+
* DID and may rotate or hold several keys, so phase-1 cannot pin "the" key for
|
|
19
|
+
* them. They are reported {@link HolderBindingStatus | not_applicable} so the
|
|
20
|
+
* caller can defer them to cnf-based binding (phase 2) instead of rejecting
|
|
21
|
+
* legitimate traffic. Callers MUST surface that gap (e.g. log it) rather than
|
|
22
|
+
* treat `not_applicable` as success.
|
|
23
|
+
*/
|
|
24
|
+
import type { ProofVerifier } from '../proof/verifier.js';
|
|
25
|
+
import type { ToolRequest, ToolResponse, ProofAgentIdentity } from '../proof/generator.js';
|
|
26
|
+
import type { DetachedProof } from '../types/protocol.js';
|
|
27
|
+
import type { CryptoProvider } from '../providers/base.js';
|
|
28
|
+
/**
|
|
29
|
+
* Whether an argument key is reserved KYA-OS protocol envelope (`_kyaos*`:
|
|
30
|
+
* `_kyaos_delegation`, `_kyaos_proof`, `_kyaos_approvals`, …) rather than caller
|
|
31
|
+
* tool intent. The SINGLE predicate behind both the holder-binding request hash
|
|
32
|
+
* and the middleware's handler-arg stripping, so the set excluded from the bound
|
|
33
|
+
* hash and the set withheld from the handler cannot drift — a proof binds exactly
|
|
34
|
+
* the call the handler runs.
|
|
35
|
+
*/
|
|
36
|
+
export declare function isKyaOsControlArg(key: string): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* The canonical request a holder-binding proof binds: the tool name plus the
|
|
39
|
+
* caller's business arguments, with protocol control args stripped. SHARED by
|
|
40
|
+
* the client (when minting the proof) and the PEP (when verifying it) so the two
|
|
41
|
+
* cannot drift — the request hash is computed over the identical shape on both
|
|
42
|
+
* sides regardless of which control args rode along.
|
|
43
|
+
*/
|
|
44
|
+
export declare function toHolderBindingRequest(toolName: string, args: Record<string, unknown>): ToolRequest;
|
|
45
|
+
export interface GenerateRequestProofInput {
|
|
46
|
+
/** The agent (delegation subject) identity holding the signing key. */
|
|
47
|
+
identity: ProofAgentIdentity;
|
|
48
|
+
/** Crypto provider used to sign and to mint the per-request nonce. */
|
|
49
|
+
crypto: CryptoProvider;
|
|
50
|
+
/** The tool being called. */
|
|
51
|
+
toolName: string;
|
|
52
|
+
/** The tool arguments (control args are stripped before binding). */
|
|
53
|
+
args: Record<string, unknown>;
|
|
54
|
+
/** The server DID the call is addressed to. */
|
|
55
|
+
audience: string;
|
|
56
|
+
/** The handshake session id, when one exists. */
|
|
57
|
+
sessionId?: string;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Mint the `_kyaos_proof` a key-bearing agent attaches to an outbound tool call
|
|
61
|
+
* — the client half of holder binding. It is a request-only detached proof (no
|
|
62
|
+
* response yet) signed by the agent's key over {@link toHolderBindingRequest}.
|
|
63
|
+
* A fresh nonce is generated per call so the PEP's replay cache rejects reuse.
|
|
64
|
+
*/
|
|
65
|
+
export declare function generateRequestProof(input: GenerateRequestProofInput): Promise<DetachedProof>;
|
|
66
|
+
/**
|
|
67
|
+
* Stable, client-facing error code for a failed holder binding. Distinct from
|
|
68
|
+
* the verifier's granular codes (which are kept in {@link HolderBindingResult.cause}
|
|
69
|
+
* for server-side diagnosis) so a binding failure presents one reason to callers
|
|
70
|
+
* and never leaks why the proof was rejected.
|
|
71
|
+
*/
|
|
72
|
+
export declare const HOLDER_BINDING_ERROR = "holder_binding_failed";
|
|
73
|
+
/**
|
|
74
|
+
* - `bound` — subject is a did:key and the proof verifies against its key: the
|
|
75
|
+
* caller is the holder. Allow.
|
|
76
|
+
* - `unbound` — subject is a did:key but the proof failed (wrong key, tampered
|
|
77
|
+
* request, stale, or replayed). Reject — this is the theft-replay closure.
|
|
78
|
+
* - `not_applicable` — subject is not a did:key, so phase-1 cannot bind it.
|
|
79
|
+
* Defer to cnf-based binding (phase 2); the caller decides how to treat it.
|
|
80
|
+
*/
|
|
81
|
+
export type HolderBindingStatus = 'bound' | 'unbound' | 'not_applicable';
|
|
82
|
+
/**
|
|
83
|
+
* Whether phase-1 holder binding can bind this subject. True only for did:key
|
|
84
|
+
* (the DID encodes the key). The PEP uses this to decide between *enforcing* a
|
|
85
|
+
* proof (did:key) and *deferring* to cnf binding (did:web and others), so it
|
|
86
|
+
* never rejects legitimate traffic it cannot yet bind.
|
|
87
|
+
*/
|
|
88
|
+
export declare function isHolderBindingApplicable(subjectDid: string): boolean;
|
|
89
|
+
export interface AssertHolderBindingInput {
|
|
90
|
+
/** The per-request detached proof presented by the caller. */
|
|
91
|
+
proof: DetachedProof;
|
|
92
|
+
/** The delegation subject DID the proof must be bound to. */
|
|
93
|
+
subjectDid: string;
|
|
94
|
+
/** The request the proof must bind (content binding). */
|
|
95
|
+
request: ToolRequest;
|
|
96
|
+
/**
|
|
97
|
+
* The response the proof binds, when the proof carries one. Inbound request
|
|
98
|
+
* proofs are request-only and omit this.
|
|
99
|
+
*/
|
|
100
|
+
response?: ToolResponse;
|
|
101
|
+
/**
|
|
102
|
+
* The audience the proof must be addressed to — the recipient server's DID
|
|
103
|
+
* (RFC 8707 "to-whom" binding). When set, `proof.meta.audience` must equal it
|
|
104
|
+
* (or be one of the array, for DID rotation / multi-DID servers); a proof
|
|
105
|
+
* minted for another server is rejected, closing confused-deputy replay across
|
|
106
|
+
* servers. Omit to skip the audience check (back-compatible).
|
|
107
|
+
*/
|
|
108
|
+
expectedAudience?: string | string[];
|
|
109
|
+
/** The existing verifier — supplies signature, nonce, timestamp and content checks. */
|
|
110
|
+
proofVerifier: ProofVerifier;
|
|
111
|
+
}
|
|
112
|
+
export interface HolderBindingResult {
|
|
113
|
+
status: HolderBindingStatus;
|
|
114
|
+
/** Human-readable explanation (present whenever status is not `bound`). */
|
|
115
|
+
reason?: string;
|
|
116
|
+
/** {@link HOLDER_BINDING_ERROR} when status is `unbound`. */
|
|
117
|
+
errorCode?: typeof HOLDER_BINDING_ERROR;
|
|
118
|
+
/** Underlying verifier error code, for server-side diagnosis only. */
|
|
119
|
+
cause?: string;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Assert that `proof` is a holder-of-key proof for `subjectDid` over `request`.
|
|
123
|
+
*
|
|
124
|
+
* @see module documentation for the did:key / did:web split and the security
|
|
125
|
+
* property each branch enforces.
|
|
126
|
+
*/
|
|
127
|
+
export declare function assertHolderBinding(input: AssertHolderBindingInput): Promise<HolderBindingResult>;
|
|
128
|
+
//# sourceMappingURL=holder-binding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"holder-binding.d.ts","sourceRoot":"","sources":["../../src/delegation/holder-binding.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAMH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAU3D;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,WAAW,CAMb;AAED,MAAM,WAAW,yBAAyB;IACxC,uEAAuE;IACvE,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,sEAAsE;IACtE,MAAM,EAAE,cAAc,CAAC;IACvB,6BAA6B;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,+CAA+C;IAC/C,QAAQ,EAAE,MAAM,CAAC;IACjB,iDAAiD;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,yBAAyB,GAC/B,OAAO,CAAC,aAAa,CAAC,CAgBxB;AAED;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,0BAA0B,CAAC;AAE5D;;;;;;;GAOG;AACH,MAAM,MAAM,mBAAmB,GAAG,OAAO,GAAG,SAAS,GAAG,gBAAgB,CAAC;AAEzE;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAErE;AAED,MAAM,WAAW,wBAAwB;IACvC,8DAA8D;IAC9D,KAAK,EAAE,aAAa,CAAC;IACrB,6DAA6D;IAC7D,UAAU,EAAE,MAAM,CAAC;IACnB,yDAAyD;IACzD,OAAO,EAAE,WAAW,CAAC;IACrB;;;OAGG;IACH,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACrC,uFAAuF;IACvF,aAAa,EAAE,aAAa,CAAC;CAC9B;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,mBAAmB,CAAC;IAC5B,2EAA2E;IAC3E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,SAAS,CAAC,EAAE,OAAO,oBAAoB,CAAC;IACxC,sEAAsE;IACtE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,wBAAwB,GAC9B,OAAO,CAAC,mBAAmB,CAAC,CA4E9B"}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Holder binding — enforce that a request proof is bound to the delegation subject.
|
|
3
|
+
*
|
|
4
|
+
* A delegation credential names a subject DID and grants it authority. On its
|
|
5
|
+
* own that credential is a *bearer* token: anyone who obtains the string can
|
|
6
|
+
* present it. Holder binding closes that gap (spec §11.8 theft-replay residual)
|
|
7
|
+
* by requiring the caller to prove possession of the subject DID's key on the
|
|
8
|
+
* request itself.
|
|
9
|
+
*
|
|
10
|
+
* For a `did:key` subject the proof is exact and needs no new credential fields:
|
|
11
|
+
* the DID *is* the public key, so "the proof verifies against the subject DID's
|
|
12
|
+
* key" is equivalent to "the caller holds the subject's private key". This module
|
|
13
|
+
* derives the subject key straight from the DID and verifies the request proof
|
|
14
|
+
* against it. A proof signed by any other key — a thief replaying a stolen
|
|
15
|
+
* credential — cannot verify and is rejected.
|
|
16
|
+
*
|
|
17
|
+
* `did:web` (and other non-`did:key`) subjects do not encode their key in the
|
|
18
|
+
* DID and may rotate or hold several keys, so phase-1 cannot pin "the" key for
|
|
19
|
+
* them. They are reported {@link HolderBindingStatus | not_applicable} so the
|
|
20
|
+
* caller can defer them to cnf-based binding (phase 2) instead of rejecting
|
|
21
|
+
* legitimate traffic. Callers MUST surface that gap (e.g. log it) rather than
|
|
22
|
+
* treat `not_applicable` as success.
|
|
23
|
+
*/
|
|
24
|
+
import { extractPublicKeyFromDidKey, publicKeyToJwk } from './did-key-resolver.js';
|
|
25
|
+
import { getDidMethod, didKeyFragment } from '../utils/did-helpers.js';
|
|
26
|
+
import { ProofGenerator } from '../proof/generator.js';
|
|
27
|
+
import { base64urlEncodeFromBytes } from '../utils/base64.js';
|
|
28
|
+
/**
|
|
29
|
+
* The control-arg key prefix. Args beginning with this are protocol envelope
|
|
30
|
+
* (`_kyaos_delegation`, `_kyaos_proof`, `_kyaos_approvals`), not the caller's
|
|
31
|
+
* tool intent, so they are excluded from the holder-binding request hash.
|
|
32
|
+
*/
|
|
33
|
+
const KYAOS_CONTROL_PREFIX = '_kyaos';
|
|
34
|
+
/**
|
|
35
|
+
* Whether an argument key is reserved KYA-OS protocol envelope (`_kyaos*`:
|
|
36
|
+
* `_kyaos_delegation`, `_kyaos_proof`, `_kyaos_approvals`, …) rather than caller
|
|
37
|
+
* tool intent. The SINGLE predicate behind both the holder-binding request hash
|
|
38
|
+
* and the middleware's handler-arg stripping, so the set excluded from the bound
|
|
39
|
+
* hash and the set withheld from the handler cannot drift — a proof binds exactly
|
|
40
|
+
* the call the handler runs.
|
|
41
|
+
*/
|
|
42
|
+
export function isKyaOsControlArg(key) {
|
|
43
|
+
return key.startsWith(KYAOS_CONTROL_PREFIX);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* The canonical request a holder-binding proof binds: the tool name plus the
|
|
47
|
+
* caller's business arguments, with protocol control args stripped. SHARED by
|
|
48
|
+
* the client (when minting the proof) and the PEP (when verifying it) so the two
|
|
49
|
+
* cannot drift — the request hash is computed over the identical shape on both
|
|
50
|
+
* sides regardless of which control args rode along.
|
|
51
|
+
*/
|
|
52
|
+
export function toHolderBindingRequest(toolName, args) {
|
|
53
|
+
const params = {};
|
|
54
|
+
for (const [k, v] of Object.entries(args)) {
|
|
55
|
+
if (!isKyaOsControlArg(k))
|
|
56
|
+
params[k] = v;
|
|
57
|
+
}
|
|
58
|
+
return { method: toolName, params };
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Mint the `_kyaos_proof` a key-bearing agent attaches to an outbound tool call
|
|
62
|
+
* — the client half of holder binding. It is a request-only detached proof (no
|
|
63
|
+
* response yet) signed by the agent's key over {@link toHolderBindingRequest}.
|
|
64
|
+
* A fresh nonce is generated per call so the PEP's replay cache rejects reuse.
|
|
65
|
+
*/
|
|
66
|
+
export async function generateRequestProof(input) {
|
|
67
|
+
const { identity, crypto, toolName, args, audience, sessionId } = input;
|
|
68
|
+
const generator = new ProofGenerator(identity, crypto);
|
|
69
|
+
const request = toHolderBindingRequest(toolName, args);
|
|
70
|
+
const nonce = base64urlEncodeFromBytes(await crypto.randomBytes(16));
|
|
71
|
+
const now = Math.floor(Date.now() / 1000);
|
|
72
|
+
return generator.generateProof(request, undefined, {
|
|
73
|
+
sessionId: sessionId ?? '',
|
|
74
|
+
audience,
|
|
75
|
+
nonce,
|
|
76
|
+
timestamp: now,
|
|
77
|
+
createdAt: now,
|
|
78
|
+
lastActivity: now,
|
|
79
|
+
ttlMinutes: 30,
|
|
80
|
+
identityState: 'anonymous',
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Stable, client-facing error code for a failed holder binding. Distinct from
|
|
85
|
+
* the verifier's granular codes (which are kept in {@link HolderBindingResult.cause}
|
|
86
|
+
* for server-side diagnosis) so a binding failure presents one reason to callers
|
|
87
|
+
* and never leaks why the proof was rejected.
|
|
88
|
+
*/
|
|
89
|
+
export const HOLDER_BINDING_ERROR = 'holder_binding_failed';
|
|
90
|
+
/**
|
|
91
|
+
* Whether phase-1 holder binding can bind this subject. True only for did:key
|
|
92
|
+
* (the DID encodes the key). The PEP uses this to decide between *enforcing* a
|
|
93
|
+
* proof (did:key) and *deferring* to cnf binding (did:web and others), so it
|
|
94
|
+
* never rejects legitimate traffic it cannot yet bind.
|
|
95
|
+
*/
|
|
96
|
+
export function isHolderBindingApplicable(subjectDid) {
|
|
97
|
+
return extractPublicKeyFromDidKey(subjectDid) !== null;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Assert that `proof` is a holder-of-key proof for `subjectDid` over `request`.
|
|
101
|
+
*
|
|
102
|
+
* @see module documentation for the did:key / did:web split and the security
|
|
103
|
+
* property each branch enforces.
|
|
104
|
+
*/
|
|
105
|
+
export async function assertHolderBinding(input) {
|
|
106
|
+
const { proof, subjectDid, request, response, expectedAudience, proofVerifier } = input;
|
|
107
|
+
// Phase-1 scope: did:key subjects only — the DID encodes the key, so holding
|
|
108
|
+
// the key is being the subject. Anything else is deferred to cnf binding.
|
|
109
|
+
const subjectKeyBytes = extractPublicKeyFromDidKey(subjectDid);
|
|
110
|
+
if (!subjectKeyBytes) {
|
|
111
|
+
return {
|
|
112
|
+
status: 'not_applicable',
|
|
113
|
+
reason: `Holder binding (phase 1) covers did:key subjects only; ` +
|
|
114
|
+
`"${getDidMethod(subjectDid) ?? 'unknown'}" is deferred to cnf-based binding`,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
// Fail closed on a structurally malformed proof (e.g. the {} a caller
|
|
118
|
+
// substitutes when a string proof fails to parse) — never throw out of the
|
|
119
|
+
// gate, which would surface as an internal error instead of a binding failure.
|
|
120
|
+
if (typeof proof?.meta !== 'object' || proof.meta === null) {
|
|
121
|
+
return {
|
|
122
|
+
status: 'unbound',
|
|
123
|
+
errorCode: HOLDER_BINDING_ERROR,
|
|
124
|
+
reason: 'Malformed proof: missing meta',
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
// Pre-crypto consistency: the proof must self-declare the delegation subject.
|
|
128
|
+
// Cheap, and gives a precise reason before the signature check.
|
|
129
|
+
if (proof.meta.did !== subjectDid) {
|
|
130
|
+
return {
|
|
131
|
+
status: 'unbound',
|
|
132
|
+
errorCode: HOLDER_BINDING_ERROR,
|
|
133
|
+
reason: 'Proof subject does not match the delegation subject',
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
// Audience binding (RFC 8707): the proof must be addressed to THIS server. A
|
|
137
|
+
// proof minted for another server cannot be replayed here. Checked before the
|
|
138
|
+
// signature so a misdirected proof fails fast without burning its nonce.
|
|
139
|
+
if (expectedAudience !== undefined) {
|
|
140
|
+
const allowed = Array.isArray(expectedAudience) ? expectedAudience : [expectedAudience];
|
|
141
|
+
if (!allowed.includes(proof.meta.audience)) {
|
|
142
|
+
return {
|
|
143
|
+
status: 'unbound',
|
|
144
|
+
errorCode: HOLDER_BINDING_ERROR,
|
|
145
|
+
reason: 'Proof audience does not match this server',
|
|
146
|
+
cause: 'audience_mismatch',
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
// The binding itself: verify the proof against the SUBJECT DID's key. The
|
|
151
|
+
// verifier reconstructs the signed payload from proof.meta (sub/iss = subject),
|
|
152
|
+
// so a proof signed by any other key cannot verify here — defeating a
|
|
153
|
+
// stolen-credential replay — and a tampered request fails content binding.
|
|
154
|
+
// Tag the key with the subject's canonical did:key verification-method id.
|
|
155
|
+
// The verifier's kid check (publicKeyJwk.kid === proof.meta.kid) then enforces
|
|
156
|
+
// that the proof's kid is the subject's verification method — a proof citing
|
|
157
|
+
// any other kid is rejected before the signature is even checked. The key
|
|
158
|
+
// material (x) still comes from the DID, so the signature is the real binding.
|
|
159
|
+
const subjectKey = publicKeyToJwk(subjectKeyBytes);
|
|
160
|
+
subjectKey.kid = `${subjectDid}#${didKeyFragment(subjectDid)}`;
|
|
161
|
+
const verification = await proofVerifier.verifyProof(proof, subjectKey, {
|
|
162
|
+
request,
|
|
163
|
+
...(response !== undefined ? { response } : {}),
|
|
164
|
+
});
|
|
165
|
+
if (!verification.valid) {
|
|
166
|
+
return {
|
|
167
|
+
status: 'unbound',
|
|
168
|
+
errorCode: HOLDER_BINDING_ERROR,
|
|
169
|
+
reason: 'Request proof is not bound to the delegation subject',
|
|
170
|
+
...(verification.errorCode !== undefined ? { cause: verification.errorCode } : {}),
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
return { status: 'bound' };
|
|
174
|
+
}
|
|
175
|
+
//# sourceMappingURL=holder-binding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"holder-binding.js","sourceRoot":"","sources":["../../src/delegation/holder-binding.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,6 +15,8 @@ export * from './outbound-proof.js';
|
|
|
15
15
|
export * from './outbound-headers.js';
|
|
16
16
|
export * from './audience-validator.js';
|
|
17
17
|
export * from './scope-matcher.js';
|
|
18
|
+
export * from './holder-binding.js';
|
|
19
|
+
export * from './chain-enforcement.js';
|
|
18
20
|
export { createDidKeyResolver, resolveDidKeySync, isEd25519DidKey, extractPublicKeyFromDidKey, publicKeyToJwk, } from './did-key-resolver.js';
|
|
19
21
|
export { DidWebResolver, createDidWebResolver, isDidWeb, parseDidWeb, didWebToUrl, buildDidWebDocument, } from './did-web-resolver.js';
|
|
20
22
|
export { MemoryStatusListStorage } from './storage/memory-statuslist-storage.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/delegation/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,YAAY,CAAC;AAC3B,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,OAAO,EACL,oBAAoB,EACpB,iBAAiB,EACjB,eAAe,EACf,0BAA0B,EAC1B,cAAc,GACf,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,cAAc,EACd,oBAAoB,EACpB,QAAQ,EACR,WAAW,EACX,WAAW,EACX,mBAAmB,GACpB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,uBAAuB,EAAE,MAAM,wCAAwC,CAAC;AACjF,OAAO,EAAE,4BAA4B,EAAE,MAAM,mCAAmC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/delegation/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,YAAY,CAAC;AAC3B,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,wBAAwB,CAAC;AACvC,OAAO,EACL,oBAAoB,EACpB,iBAAiB,EACjB,eAAe,EACf,0BAA0B,EAC1B,cAAc,GACf,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,cAAc,EACd,oBAAoB,EACpB,QAAQ,EACR,WAAW,EACX,WAAW,EACX,mBAAmB,GACpB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,uBAAuB,EAAE,MAAM,wCAAwC,CAAC;AACjF,OAAO,EAAE,4BAA4B,EAAE,MAAM,mCAAmC,CAAC"}
|
package/dist/delegation/index.js
CHANGED
|
@@ -15,6 +15,8 @@ export * from './outbound-proof.js';
|
|
|
15
15
|
export * from './outbound-headers.js';
|
|
16
16
|
export * from './audience-validator.js';
|
|
17
17
|
export * from './scope-matcher.js';
|
|
18
|
+
export * from './holder-binding.js';
|
|
19
|
+
export * from './chain-enforcement.js';
|
|
18
20
|
export { createDidKeyResolver, resolveDidKeySync, isEd25519DidKey, extractPublicKeyFromDidKey, publicKeyToJwk, } from './did-key-resolver.js';
|
|
19
21
|
export { DidWebResolver, createDidWebResolver, isDidWeb, parseDidWeb, didWebToUrl, buildDidWebDocument, } from './did-web-resolver.js';
|
|
20
22
|
export { MemoryStatusListStorage } from './storage/memory-statuslist-storage.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/delegation/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,YAAY,CAAC;AAC3B,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,OAAO,EACL,oBAAoB,EACpB,iBAAiB,EACjB,eAAe,EACf,0BAA0B,EAC1B,cAAc,GACf,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,cAAc,EACd,oBAAoB,EACpB,QAAQ,EACR,WAAW,EACX,WAAW,EACX,mBAAmB,GACpB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,uBAAuB,EAAE,MAAM,wCAAwC,CAAC;AACjF,OAAO,EAAE,4BAA4B,EAAE,MAAM,mCAAmC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/delegation/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,YAAY,CAAC;AAC3B,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,wBAAwB,CAAC;AACvC,OAAO,EACL,oBAAoB,EACpB,iBAAiB,EACjB,eAAe,EACf,0BAA0B,EAC1B,cAAc,GACf,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,cAAc,EACd,oBAAoB,EACpB,QAAQ,EACR,WAAW,EACX,WAAW,EACX,mBAAmB,GACpB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,uBAAuB,EAAE,MAAM,wCAAwC,CAAC;AACjF,OAAO,EAAE,4BAA4B,EAAE,MAAM,mCAAmC,CAAC"}
|
package/dist/errors.d.ts
CHANGED
|
@@ -24,6 +24,7 @@ export declare const KYA_OS_ERROR_CODES: {
|
|
|
24
24
|
readonly delegation_not_yet_valid: "delegation_not_yet_valid";
|
|
25
25
|
readonly delegation_revoked: "delegation_revoked";
|
|
26
26
|
readonly delegation_invalid: "delegation_invalid";
|
|
27
|
+
readonly holder_binding_failed: "holder_binding_failed";
|
|
27
28
|
readonly budget_exceeded: "budget_exceeded";
|
|
28
29
|
readonly rate_limit_exceeded: "rate_limit_exceeded";
|
|
29
30
|
readonly invalid_token: "invalid_token";
|
package/dist/errors.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,eAAO,MAAM,kBAAkB
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;CAuCrB,CAAC;AAEX,MAAM,MAAM,cAAc,GACxB,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,OAAO,kBAAkB,CAAC,CAAC;AAE/D,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,cAAc,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,cAAc,EACpB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,kBAAkB,CAEpB"}
|
package/dist/errors.js
CHANGED
|
@@ -28,6 +28,7 @@ export const KYA_OS_ERROR_CODES = {
|
|
|
28
28
|
delegation_not_yet_valid: "delegation_not_yet_valid",
|
|
29
29
|
delegation_revoked: "delegation_revoked",
|
|
30
30
|
delegation_invalid: "delegation_invalid",
|
|
31
|
+
holder_binding_failed: "holder_binding_failed",
|
|
31
32
|
budget_exceeded: "budget_exceeded",
|
|
32
33
|
rate_limit_exceeded: "rate_limit_exceeded",
|
|
33
34
|
// Token errors
|
package/dist/errors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,eAAe;IACf,aAAa,EAAE,eAAe;IAC9B,WAAW,EAAE,aAAa;IAC1B,YAAY,EAAE,cAAc;IAC5B,cAAc,EAAE,gBAAgB;IAEhC,wBAAwB;IACxB,aAAa,EAAE,eAAe;IAC9B,kBAAkB,EAAE,oBAAoB;IAExC,6BAA6B;IAC7B,gBAAgB,EAAE,kBAAkB;IACpC,eAAe,EAAE,iBAAiB;IAClC,eAAe,EAAE,iBAAiB;IAElC,oBAAoB;IACpB,mBAAmB,EAAE,qBAAqB;IAC1C,kBAAkB,EAAE,oBAAoB;IACxC,aAAa,EAAE,eAAe;IAC9B,kBAAkB,EAAE,oBAAoB;IACxC,wBAAwB,EAAE,0BAA0B;IACpD,kBAAkB,EAAE,oBAAoB;IACxC,kBAAkB,EAAE,oBAAoB;IACxC,eAAe,EAAE,iBAAiB;IAClC,mBAAmB,EAAE,qBAAqB;IAE1C,eAAe;IACf,aAAa,EAAE,eAAe;IAC9B,aAAa,EAAE,eAAe;IAE9B,kBAAkB;IAClB,cAAc,EAAE,gBAAgB;IAChC,YAAY,EAAE,cAAc;IAE5B,gBAAgB;IAChB,mBAAmB,EAAE,qBAAqB;IAC1C,aAAa,EAAE,eAAe;CACtB,CAAC;AAWX,MAAM,UAAU,gBAAgB,CAC9B,IAAoB,EACpB,OAAe,EACf,OAAiC;IAEjC,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAClE,CAAC"}
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,eAAe;IACf,aAAa,EAAE,eAAe;IAC9B,WAAW,EAAE,aAAa;IAC1B,YAAY,EAAE,cAAc;IAC5B,cAAc,EAAE,gBAAgB;IAEhC,wBAAwB;IACxB,aAAa,EAAE,eAAe;IAC9B,kBAAkB,EAAE,oBAAoB;IAExC,6BAA6B;IAC7B,gBAAgB,EAAE,kBAAkB;IACpC,eAAe,EAAE,iBAAiB;IAClC,eAAe,EAAE,iBAAiB;IAElC,oBAAoB;IACpB,mBAAmB,EAAE,qBAAqB;IAC1C,kBAAkB,EAAE,oBAAoB;IACxC,aAAa,EAAE,eAAe;IAC9B,kBAAkB,EAAE,oBAAoB;IACxC,wBAAwB,EAAE,0BAA0B;IACpD,kBAAkB,EAAE,oBAAoB;IACxC,kBAAkB,EAAE,oBAAoB;IACxC,qBAAqB,EAAE,uBAAuB;IAC9C,eAAe,EAAE,iBAAiB;IAClC,mBAAmB,EAAE,qBAAqB;IAE1C,eAAe;IACf,aAAa,EAAE,eAAe;IAC9B,aAAa,EAAE,eAAe;IAE9B,kBAAkB;IAClB,cAAc,EAAE,gBAAgB;IAChC,YAAY,EAAE,cAAc;IAE5B,gBAAgB;IAChB,mBAAmB,EAAE,qBAAqB;IAC1C,aAAa,EAAE,eAAe;CACtB,CAAC;AAWX,MAAM,UAAU,gBAAgB,CAC9B,IAAoB,EACpB,OAAe,EACf,OAAiC;IAEjC,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAClE,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -28,6 +28,7 @@ export { verifyDelegationAudience, } from './delegation/audience-validator.js';
|
|
|
28
28
|
export { buildDelegationProofJWT, buildChainString, type DelegationProofOptions, type Ed25519PrivateJWK, } from './delegation/outbound-proof.js';
|
|
29
29
|
export { buildOutboundDelegationHeaders, OUTBOUND_HEADER_NAMES, type OutboundDelegationContext, type OutboundDelegationHeaders, } from './delegation/outbound-headers.js';
|
|
30
30
|
export { canonicalizeJSON, createUnsignedVCJWT, completeVCJWT, parseVCJWT, type VCJWTHeader, type VCJWTPayload, } from './delegation/utils.js';
|
|
31
|
+
export { assertHolderBinding, generateRequestProof, toHolderBindingRequest, isHolderBindingApplicable, isKyaOsControlArg, HOLDER_BINDING_ERROR, type AssertHolderBindingInput, type GenerateRequestProofInput, type HolderBindingResult, type HolderBindingStatus, } from './delegation/holder-binding.js';
|
|
31
32
|
export { MemoryStatusListStorage } from './delegation/storage/memory-statuslist-storage.js';
|
|
32
33
|
export { MemoryDelegationGraphStorage } from './delegation/storage/memory-graph-storage.js';
|
|
33
34
|
export { createDidKeyResolver, resolveDidKeySync, isEd25519DidKey, extractPublicKeyFromDidKey, publicKeyToJwk, } from './delegation/did-key-resolver.js';
|
|
@@ -43,7 +44,7 @@ export { CryptoProvider, ClockProvider, FetchProvider, StorageProvider, NonceCac
|
|
|
43
44
|
export { MemoryStorageProvider, MemoryNonceCacheProvider, MemoryIdentityProvider, } from './providers/memory.js';
|
|
44
45
|
export { NodeCryptoProvider } from './providers/node-crypto.js';
|
|
45
46
|
export { SystemClockProvider } from './providers/system-clock.js';
|
|
46
|
-
export { RuntimeFetchProvider } from './providers/runtime-fetch.js';
|
|
47
|
+
export { RuntimeFetchProvider, NoopFetchProvider } from './providers/runtime-fetch.js';
|
|
47
48
|
export { AuditLogProvider, MemoryAuditLogProvider, NoopAuditLogProvider, buildAuditRecord, } from './providers/audit-log.js';
|
|
48
49
|
export { createKyaOsMiddleware, type KyaOsConfig, type KyaOsDelegationConfig, type KyaOsIdentityConfig, type KyaOsMiddleware, type KyaOsToolDefinition, type KyaOsToolHandler, type KyaOsServer, withKyaOs, generateIdentity, type WithKyaOsOptions, } from './middleware/index.js';
|
|
49
50
|
export * from './policy/index.js';
|