@kya-os/mcp 1.2.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 +64 -0
- package/LICENSE +21 -0
- package/README.md +135 -0
- package/dist/auth/handshake.d.ts +119 -0
- package/dist/auth/handshake.d.ts.map +1 -0
- package/dist/auth/handshake.js +267 -0
- package/dist/auth/handshake.js.map +1 -0
- package/dist/auth/index.d.ts +3 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +2 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/types.d.ts +31 -0
- package/dist/auth/types.d.ts.map +1 -0
- package/dist/auth/types.js +7 -0
- package/dist/auth/types.js.map +1 -0
- package/dist/delegation/audience-validator.d.ts +9 -0
- package/dist/delegation/audience-validator.d.ts.map +1 -0
- package/dist/delegation/audience-validator.js +17 -0
- package/dist/delegation/audience-validator.js.map +1 -0
- package/dist/delegation/bitstring.d.ts +37 -0
- package/dist/delegation/bitstring.d.ts.map +1 -0
- package/dist/delegation/bitstring.js +117 -0
- package/dist/delegation/bitstring.js.map +1 -0
- package/dist/delegation/cascading-revocation.d.ts +45 -0
- package/dist/delegation/cascading-revocation.d.ts.map +1 -0
- package/dist/delegation/cascading-revocation.js +150 -0
- package/dist/delegation/cascading-revocation.js.map +1 -0
- package/dist/delegation/delegation-graph.d.ts +49 -0
- package/dist/delegation/delegation-graph.d.ts.map +1 -0
- package/dist/delegation/delegation-graph.js +99 -0
- package/dist/delegation/delegation-graph.js.map +1 -0
- package/dist/delegation/did-key-resolver.d.ts +64 -0
- package/dist/delegation/did-key-resolver.d.ts.map +1 -0
- package/dist/delegation/did-key-resolver.js +157 -0
- package/dist/delegation/did-key-resolver.js.map +1 -0
- package/dist/delegation/did-web-resolver.d.ts +83 -0
- package/dist/delegation/did-web-resolver.d.ts.map +1 -0
- package/dist/delegation/did-web-resolver.js +218 -0
- package/dist/delegation/did-web-resolver.js.map +1 -0
- package/dist/delegation/index.d.ts +21 -0
- package/dist/delegation/index.d.ts.map +1 -0
- package/dist/delegation/index.js +21 -0
- package/dist/delegation/index.js.map +1 -0
- package/dist/delegation/outbound-headers.d.ts +79 -0
- package/dist/delegation/outbound-headers.d.ts.map +1 -0
- package/dist/delegation/outbound-headers.js +138 -0
- package/dist/delegation/outbound-headers.js.map +1 -0
- package/dist/delegation/outbound-proof.d.ts +43 -0
- package/dist/delegation/outbound-proof.d.ts.map +1 -0
- package/dist/delegation/outbound-proof.js +52 -0
- package/dist/delegation/outbound-proof.js.map +1 -0
- package/dist/delegation/statuslist-manager.d.ts +47 -0
- package/dist/delegation/statuslist-manager.d.ts.map +1 -0
- package/dist/delegation/statuslist-manager.js +139 -0
- package/dist/delegation/statuslist-manager.js.map +1 -0
- package/dist/delegation/storage/memory-graph-storage.d.ts +70 -0
- package/dist/delegation/storage/memory-graph-storage.d.ts.map +1 -0
- package/dist/delegation/storage/memory-graph-storage.js +145 -0
- package/dist/delegation/storage/memory-graph-storage.js.map +1 -0
- package/dist/delegation/storage/memory-statuslist-storage.d.ts +19 -0
- package/dist/delegation/storage/memory-statuslist-storage.d.ts.map +1 -0
- package/dist/delegation/storage/memory-statuslist-storage.js +33 -0
- package/dist/delegation/storage/memory-statuslist-storage.js.map +1 -0
- package/dist/delegation/utils.d.ts +49 -0
- package/dist/delegation/utils.d.ts.map +1 -0
- package/dist/delegation/utils.js +131 -0
- package/dist/delegation/utils.js.map +1 -0
- package/dist/delegation/vc-issuer.d.ts +56 -0
- package/dist/delegation/vc-issuer.d.ts.map +1 -0
- package/dist/delegation/vc-issuer.js +80 -0
- package/dist/delegation/vc-issuer.js.map +1 -0
- package/dist/delegation/vc-verifier.d.ts +112 -0
- package/dist/delegation/vc-verifier.d.ts.map +1 -0
- package/dist/delegation/vc-verifier.js +280 -0
- package/dist/delegation/vc-verifier.js.map +1 -0
- package/dist/errors.d.ts +42 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +45 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +56 -0
- package/dist/index.js.map +1 -0
- package/dist/logging/index.d.ts +2 -0
- package/dist/logging/index.d.ts.map +1 -0
- package/dist/logging/index.js +2 -0
- package/dist/logging/index.js.map +1 -0
- package/dist/logging/logger.d.ts +23 -0
- package/dist/logging/logger.d.ts.map +1 -0
- package/dist/logging/logger.js +82 -0
- package/dist/logging/logger.js.map +1 -0
- package/dist/middleware/index.d.ts +12 -0
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +12 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/middleware/mcpi-transport.d.ts +39 -0
- package/dist/middleware/mcpi-transport.d.ts.map +1 -0
- package/dist/middleware/mcpi-transport.js +121 -0
- package/dist/middleware/mcpi-transport.js.map +1 -0
- package/dist/middleware/with-mcpi-server.d.ts +78 -0
- package/dist/middleware/with-mcpi-server.d.ts.map +1 -0
- package/dist/middleware/with-mcpi-server.js +109 -0
- package/dist/middleware/with-mcpi-server.js.map +1 -0
- package/dist/middleware/with-mcpi.d.ts +202 -0
- package/dist/middleware/with-mcpi.d.ts.map +1 -0
- package/dist/middleware/with-mcpi.js +625 -0
- package/dist/middleware/with-mcpi.js.map +1 -0
- package/dist/proof/errors.d.ts +49 -0
- package/dist/proof/errors.d.ts.map +1 -0
- package/dist/proof/errors.js +61 -0
- package/dist/proof/errors.js.map +1 -0
- package/dist/proof/generator.d.ts +65 -0
- package/dist/proof/generator.d.ts.map +1 -0
- package/dist/proof/generator.js +163 -0
- package/dist/proof/generator.js.map +1 -0
- package/dist/proof/index.d.ts +4 -0
- package/dist/proof/index.d.ts.map +1 -0
- package/dist/proof/index.js +4 -0
- package/dist/proof/index.js.map +1 -0
- package/dist/proof/verifier.d.ts +108 -0
- package/dist/proof/verifier.d.ts.map +1 -0
- package/dist/proof/verifier.js +299 -0
- package/dist/proof/verifier.js.map +1 -0
- package/dist/providers/base.d.ts +64 -0
- package/dist/providers/base.d.ts.map +1 -0
- package/dist/providers/base.js +19 -0
- package/dist/providers/base.js.map +1 -0
- package/dist/providers/index.d.ts +4 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +4 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/memory.d.ts +33 -0
- package/dist/providers/memory.d.ts.map +1 -0
- package/dist/providers/memory.js +102 -0
- package/dist/providers/memory.js.map +1 -0
- package/dist/providers/node-crypto.d.ts +26 -0
- package/dist/providers/node-crypto.d.ts.map +1 -0
- package/dist/providers/node-crypto.js +69 -0
- package/dist/providers/node-crypto.js.map +1 -0
- package/dist/session/index.d.ts +2 -0
- package/dist/session/index.d.ts.map +1 -0
- package/dist/session/index.js +2 -0
- package/dist/session/index.js.map +1 -0
- package/dist/session/manager.d.ts +83 -0
- package/dist/session/manager.d.ts.map +1 -0
- package/dist/session/manager.js +267 -0
- package/dist/session/manager.js.map +1 -0
- package/dist/types/protocol.d.ts +320 -0
- package/dist/types/protocol.d.ts.map +1 -0
- package/dist/types/protocol.js +229 -0
- package/dist/types/protocol.js.map +1 -0
- package/dist/utils/base58.d.ts +31 -0
- package/dist/utils/base58.d.ts.map +1 -0
- package/dist/utils/base58.js +104 -0
- package/dist/utils/base58.js.map +1 -0
- package/dist/utils/base64.d.ts +13 -0
- package/dist/utils/base64.d.ts.map +1 -0
- package/dist/utils/base64.js +99 -0
- package/dist/utils/base64.js.map +1 -0
- package/dist/utils/crypto-service.d.ts +37 -0
- package/dist/utils/crypto-service.d.ts.map +1 -0
- package/dist/utils/crypto-service.js +154 -0
- package/dist/utils/crypto-service.js.map +1 -0
- package/dist/utils/did-helpers.d.ts +168 -0
- package/dist/utils/did-helpers.d.ts.map +1 -0
- package/dist/utils/did-helpers.js +211 -0
- package/dist/utils/did-helpers.js.map +1 -0
- package/dist/utils/ed25519-constants.d.ts +18 -0
- package/dist/utils/ed25519-constants.d.ts.map +1 -0
- package/dist/utils/ed25519-constants.js +21 -0
- package/dist/utils/ed25519-constants.js.map +1 -0
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +5 -0
- package/dist/utils/index.js.map +1 -0
- package/package.json +115 -0
- package/schemas/README.md +117 -0
- package/schemas/delegation-credential.json +312 -0
- package/schemas/detached-proof.json +97 -0
- package/schemas/handshake-request.json +84 -0
- package/schemas/handshake-response.json +67 -0
- package/schemas/well-known-mcpi.json +176 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Outbound Delegation Headers
|
|
3
|
+
*
|
|
4
|
+
* Builds the full set of outbound delegation headers for forwarding
|
|
5
|
+
* delegation context to downstream services.
|
|
6
|
+
*
|
|
7
|
+
* Headers (MCP-I §7):
|
|
8
|
+
* - KYA-Agent-DID: the original agent's DID
|
|
9
|
+
* - KYA-Delegation-Chain: the delegation chain ID (vcId of the root delegation)
|
|
10
|
+
* - KYA-Session-Id: the current session ID
|
|
11
|
+
* - KYA-Delegation-Proof: a signed JWT proving the delegation is being forwarded
|
|
12
|
+
*
|
|
13
|
+
* Related Spec: MCP-I §7 — Outbound Delegation Propagation
|
|
14
|
+
*/
|
|
15
|
+
import type { SessionContext, DelegationRecord } from '../types/protocol.js';
|
|
16
|
+
/**
|
|
17
|
+
* Header names for outbound delegation propagation
|
|
18
|
+
*/
|
|
19
|
+
export declare const OUTBOUND_HEADER_NAMES: {
|
|
20
|
+
readonly AGENT_DID: "KYA-Agent-DID";
|
|
21
|
+
readonly DELEGATION_CHAIN: "KYA-Delegation-Chain";
|
|
22
|
+
readonly SESSION_ID: "KYA-Session-Id";
|
|
23
|
+
readonly DELEGATION_PROOF: "KYA-Delegation-Proof";
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Context required to build outbound delegation headers
|
|
27
|
+
*/
|
|
28
|
+
export interface OutboundDelegationContext {
|
|
29
|
+
/** The current session context */
|
|
30
|
+
session: SessionContext;
|
|
31
|
+
/** The delegation record being forwarded */
|
|
32
|
+
delegation: DelegationRecord;
|
|
33
|
+
/** The MCP server's identity for signing the proof */
|
|
34
|
+
serverIdentity: {
|
|
35
|
+
did: string;
|
|
36
|
+
kid: string;
|
|
37
|
+
privateKey: string;
|
|
38
|
+
};
|
|
39
|
+
/** The downstream URL being called */
|
|
40
|
+
targetUrl: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Outbound delegation headers to attach to downstream requests
|
|
44
|
+
*/
|
|
45
|
+
export interface OutboundDelegationHeaders {
|
|
46
|
+
'KYA-Agent-DID': string;
|
|
47
|
+
'KYA-Delegation-Chain': string;
|
|
48
|
+
'KYA-Session-Id': string;
|
|
49
|
+
'KYA-Delegation-Proof': string;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Build outbound delegation headers for forwarding to downstream services.
|
|
53
|
+
*
|
|
54
|
+
* When an MCP server calls a downstream service on behalf of an agent,
|
|
55
|
+
* it MUST forward the delegation context using these headers so the
|
|
56
|
+
* downstream service can independently verify the delegation chain.
|
|
57
|
+
*
|
|
58
|
+
* @param context - The delegation context including session, delegation, and server identity
|
|
59
|
+
* @returns Headers object to attach to the outbound request
|
|
60
|
+
*
|
|
61
|
+
* @throws {Error} If session is missing agentDid or sessionId
|
|
62
|
+
* @throws {Error} If delegation is missing vcId
|
|
63
|
+
* @throws {Error} If serverIdentity.did is not a valid Ed25519 did:key
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```typescript
|
|
67
|
+
* const headers = await buildOutboundDelegationHeaders({
|
|
68
|
+
* session,
|
|
69
|
+
* delegation,
|
|
70
|
+
* serverIdentity: { did: serverDid, kid: serverKid, privateKey },
|
|
71
|
+
* targetUrl: 'https://downstream-api.example.com/resource',
|
|
72
|
+
* });
|
|
73
|
+
*
|
|
74
|
+
* // Attach headers to your HTTP request
|
|
75
|
+
* fetch(targetUrl, { headers });
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
export declare function buildOutboundDelegationHeaders(context: OutboundDelegationContext): Promise<OutboundDelegationHeaders>;
|
|
79
|
+
//# sourceMappingURL=outbound-headers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outbound-headers.d.ts","sourceRoot":"","sources":["../../src/delegation/outbound-headers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAM7E;;GAEG;AACH,eAAO,MAAM,qBAAqB;;;;;CAKxB,CAAC;AAEX;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,kCAAkC;IAClC,OAAO,EAAE,cAAc,CAAC;IACxB,4CAA4C;IAC5C,UAAU,EAAE,gBAAgB,CAAC;IAC7B,sDAAsD;IACtD,cAAc,EAAE;QACd,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,EAAE,MAAM,CAAC;QACZ,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,sCAAsC;IACtC,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,eAAe,EAAE,MAAM,CAAC;IACxB,sBAAsB,EAAE,MAAM,CAAC;IAC/B,gBAAgB,EAAE,MAAM,CAAC;IACzB,sBAAsB,EAAE,MAAM,CAAC;CAChC;AAgDD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAsB,8BAA8B,CAClD,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,yBAAyB,CAAC,CAuDpC"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Outbound Delegation Headers
|
|
3
|
+
*
|
|
4
|
+
* Builds the full set of outbound delegation headers for forwarding
|
|
5
|
+
* delegation context to downstream services.
|
|
6
|
+
*
|
|
7
|
+
* Headers (MCP-I §7):
|
|
8
|
+
* - KYA-Agent-DID: the original agent's DID
|
|
9
|
+
* - KYA-Delegation-Chain: the delegation chain ID (vcId of the root delegation)
|
|
10
|
+
* - KYA-Session-Id: the current session ID
|
|
11
|
+
* - KYA-Delegation-Proof: a signed JWT proving the delegation is being forwarded
|
|
12
|
+
*
|
|
13
|
+
* Related Spec: MCP-I §7 — Outbound Delegation Propagation
|
|
14
|
+
*/
|
|
15
|
+
import { buildDelegationProofJWT } from './outbound-proof.js';
|
|
16
|
+
import { extractPublicKeyFromDidKey, isEd25519DidKey } from './did-key-resolver.js';
|
|
17
|
+
import { base64ToBytes, base64urlEncodeFromBytes } from '../utils/base64.js';
|
|
18
|
+
import { logger } from '../logging/index.js';
|
|
19
|
+
/**
|
|
20
|
+
* Header names for outbound delegation propagation
|
|
21
|
+
*/
|
|
22
|
+
export const OUTBOUND_HEADER_NAMES = {
|
|
23
|
+
AGENT_DID: 'KYA-Agent-DID',
|
|
24
|
+
DELEGATION_CHAIN: 'KYA-Delegation-Chain',
|
|
25
|
+
SESSION_ID: 'KYA-Session-Id',
|
|
26
|
+
DELEGATION_PROOF: 'KYA-Delegation-Proof',
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Extract hostname from a URL
|
|
30
|
+
*/
|
|
31
|
+
function extractHostname(url) {
|
|
32
|
+
try {
|
|
33
|
+
const parsed = new URL(url);
|
|
34
|
+
return parsed.hostname;
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
logger.warn('Failed to parse target URL, using as-is', { url });
|
|
38
|
+
return url;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Convert base64 private key and DID to Ed25519 JWK format
|
|
43
|
+
*/
|
|
44
|
+
function buildPrivateKeyJwk(privateKeyBase64, serverDid) {
|
|
45
|
+
// Decode the private key from base64
|
|
46
|
+
const privateKeyBytes = base64ToBytes(privateKeyBase64);
|
|
47
|
+
// Extract the 32-byte seed (handle both 32-byte and 64-byte formats)
|
|
48
|
+
const seed = privateKeyBytes.length === 64
|
|
49
|
+
? privateKeyBytes.subarray(0, 32)
|
|
50
|
+
: privateKeyBytes;
|
|
51
|
+
// Extract public key from did:key
|
|
52
|
+
if (!isEd25519DidKey(serverDid)) {
|
|
53
|
+
throw new Error(`Server DID must be did:key with Ed25519: ${serverDid}`);
|
|
54
|
+
}
|
|
55
|
+
const publicKeyBytes = extractPublicKeyFromDidKey(serverDid);
|
|
56
|
+
if (!publicKeyBytes) {
|
|
57
|
+
throw new Error(`Failed to extract public key from DID: ${serverDid}`);
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
kty: 'OKP',
|
|
61
|
+
crv: 'Ed25519',
|
|
62
|
+
x: base64urlEncodeFromBytes(publicKeyBytes),
|
|
63
|
+
d: base64urlEncodeFromBytes(seed),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Build outbound delegation headers for forwarding to downstream services.
|
|
68
|
+
*
|
|
69
|
+
* When an MCP server calls a downstream service on behalf of an agent,
|
|
70
|
+
* it MUST forward the delegation context using these headers so the
|
|
71
|
+
* downstream service can independently verify the delegation chain.
|
|
72
|
+
*
|
|
73
|
+
* @param context - The delegation context including session, delegation, and server identity
|
|
74
|
+
* @returns Headers object to attach to the outbound request
|
|
75
|
+
*
|
|
76
|
+
* @throws {Error} If session is missing agentDid or sessionId
|
|
77
|
+
* @throws {Error} If delegation is missing vcId
|
|
78
|
+
* @throws {Error} If serverIdentity.did is not a valid Ed25519 did:key
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```typescript
|
|
82
|
+
* const headers = await buildOutboundDelegationHeaders({
|
|
83
|
+
* session,
|
|
84
|
+
* delegation,
|
|
85
|
+
* serverIdentity: { did: serverDid, kid: serverKid, privateKey },
|
|
86
|
+
* targetUrl: 'https://downstream-api.example.com/resource',
|
|
87
|
+
* });
|
|
88
|
+
*
|
|
89
|
+
* // Attach headers to your HTTP request
|
|
90
|
+
* fetch(targetUrl, { headers });
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
export async function buildOutboundDelegationHeaders(context) {
|
|
94
|
+
const { session, delegation, serverIdentity, targetUrl } = context;
|
|
95
|
+
// Validate required fields
|
|
96
|
+
if (!session.agentDid) {
|
|
97
|
+
throw new Error('Session must have agentDid for outbound delegation');
|
|
98
|
+
}
|
|
99
|
+
if (!session.sessionId) {
|
|
100
|
+
throw new Error('Session must have sessionId for outbound delegation');
|
|
101
|
+
}
|
|
102
|
+
if (!delegation.vcId) {
|
|
103
|
+
throw new Error('Delegation must have vcId for outbound delegation');
|
|
104
|
+
}
|
|
105
|
+
// Extract hostname for JWT audience
|
|
106
|
+
const targetHostname = extractHostname(targetUrl);
|
|
107
|
+
// Build the private key JWK from the server identity
|
|
108
|
+
const privateKeyJwk = buildPrivateKeyJwk(serverIdentity.privateKey, serverIdentity.did);
|
|
109
|
+
// Build the delegation proof JWT
|
|
110
|
+
// Per MCP-I §7, the JWT has:
|
|
111
|
+
// - iss: serverDid (the MCP server forwarding the request)
|
|
112
|
+
// - sub: agentDid (the original agent)
|
|
113
|
+
// - aud: targetHostname (the downstream service)
|
|
114
|
+
// - scope: "delegation:propagate"
|
|
115
|
+
const jwt = await buildDelegationProofJWT({
|
|
116
|
+
agentDid: serverIdentity.did, // becomes iss (server forwarding)
|
|
117
|
+
userDid: session.agentDid, // becomes sub (original agent)
|
|
118
|
+
delegationId: delegation.id,
|
|
119
|
+
delegationChain: delegation.vcId,
|
|
120
|
+
scopes: ['delegation:propagate'],
|
|
121
|
+
privateKeyJwk,
|
|
122
|
+
kid: serverIdentity.kid,
|
|
123
|
+
targetHostname,
|
|
124
|
+
});
|
|
125
|
+
logger.debug('Built outbound delegation headers', {
|
|
126
|
+
agentDid: session.agentDid,
|
|
127
|
+
delegationChain: delegation.vcId,
|
|
128
|
+
sessionId: session.sessionId,
|
|
129
|
+
targetHostname,
|
|
130
|
+
});
|
|
131
|
+
return {
|
|
132
|
+
'KYA-Agent-DID': session.agentDid,
|
|
133
|
+
'KYA-Delegation-Chain': delegation.vcId,
|
|
134
|
+
'KYA-Session-Id': session.sessionId,
|
|
135
|
+
'KYA-Delegation-Proof': jwt,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=outbound-headers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outbound-headers.js","sourceRoot":"","sources":["../../src/delegation/outbound-headers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Outbound Delegation Proof
|
|
3
|
+
*
|
|
4
|
+
* Builds signed delegation proof JWTs for injection on outbound HTTP requests.
|
|
5
|
+
* Enables downstream services to independently verify the delegation chain.
|
|
6
|
+
*
|
|
7
|
+
* Wire format: signed compact EdDSA JWT (60s TTL, per-call jti)
|
|
8
|
+
* Header injection: KYA-Delegation-Id, KYA-Delegation-Chain, KYA-Delegation-Proof, KYA-Granted-Scopes
|
|
9
|
+
*
|
|
10
|
+
* Related Spec: MCP-I §2 — Outbound Delegation Propagation
|
|
11
|
+
*/
|
|
12
|
+
import type { DelegationRecord } from '../types/protocol.js';
|
|
13
|
+
export interface Ed25519PrivateJWK {
|
|
14
|
+
kty: 'OKP';
|
|
15
|
+
crv: 'Ed25519';
|
|
16
|
+
x: string;
|
|
17
|
+
d: string;
|
|
18
|
+
kid?: string;
|
|
19
|
+
use?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface DelegationProofOptions {
|
|
22
|
+
agentDid: string;
|
|
23
|
+
userDid: string;
|
|
24
|
+
delegationId: string;
|
|
25
|
+
delegationChain: string;
|
|
26
|
+
scopes: string[];
|
|
27
|
+
privateKeyJwk: Ed25519PrivateJWK;
|
|
28
|
+
kid: string;
|
|
29
|
+
targetHostname: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Build a signed delegation proof JWT for outbound HTTP requests.
|
|
33
|
+
*
|
|
34
|
+
* Creates a short-lived (60s) EdDSA-signed JWT containing delegation context
|
|
35
|
+
* that can be verified by downstream services without access to the MCP server.
|
|
36
|
+
*
|
|
37
|
+
* @param options - Proof options including DIDs, delegation info, scopes, and signing key
|
|
38
|
+
* @returns Compact JWS string (header.payload.signature)
|
|
39
|
+
* @throws {Error} If key import or signing fails
|
|
40
|
+
*/
|
|
41
|
+
export declare function buildDelegationProofJWT(options: DelegationProofOptions): Promise<string>;
|
|
42
|
+
export declare function buildChainString(delegation: DelegationRecord): string;
|
|
43
|
+
//# sourceMappingURL=outbound-proof.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outbound-proof.d.ts","sourceRoot":"","sources":["../../src/delegation/outbound-proof.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,KAAK,CAAC;IACX,GAAG,EAAE,SAAS,CAAC;IACf,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,aAAa,EAAE,iBAAiB,CAAC;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;;GASG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,MAAM,CAAC,CAgCjB;AAED,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,gBAAgB,GAAG,MAAM,CAQrE"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Outbound Delegation Proof
|
|
3
|
+
*
|
|
4
|
+
* Builds signed delegation proof JWTs for injection on outbound HTTP requests.
|
|
5
|
+
* Enables downstream services to independently verify the delegation chain.
|
|
6
|
+
*
|
|
7
|
+
* Wire format: signed compact EdDSA JWT (60s TTL, per-call jti)
|
|
8
|
+
* Header injection: KYA-Delegation-Id, KYA-Delegation-Chain, KYA-Delegation-Proof, KYA-Granted-Scopes
|
|
9
|
+
*
|
|
10
|
+
* Related Spec: MCP-I §2 — Outbound Delegation Propagation
|
|
11
|
+
*/
|
|
12
|
+
import { SignJWT, importJWK } from 'jose';
|
|
13
|
+
/**
|
|
14
|
+
* Build a signed delegation proof JWT for outbound HTTP requests.
|
|
15
|
+
*
|
|
16
|
+
* Creates a short-lived (60s) EdDSA-signed JWT containing delegation context
|
|
17
|
+
* that can be verified by downstream services without access to the MCP server.
|
|
18
|
+
*
|
|
19
|
+
* @param options - Proof options including DIDs, delegation info, scopes, and signing key
|
|
20
|
+
* @returns Compact JWS string (header.payload.signature)
|
|
21
|
+
* @throws {Error} If key import or signing fails
|
|
22
|
+
*/
|
|
23
|
+
export async function buildDelegationProofJWT(options) {
|
|
24
|
+
const { agentDid, userDid, delegationId, delegationChain, scopes, privateKeyJwk, kid, targetHostname, } = options;
|
|
25
|
+
const privateKey = await importJWK(privateKeyJwk, 'EdDSA');
|
|
26
|
+
const iat = Math.floor(Date.now() / 1000);
|
|
27
|
+
const exp = iat + 60;
|
|
28
|
+
const jwt = await new SignJWT({
|
|
29
|
+
delegation_id: delegationId,
|
|
30
|
+
delegation_chain: delegationChain,
|
|
31
|
+
scope: scopes.join(','),
|
|
32
|
+
})
|
|
33
|
+
.setProtectedHeader({ alg: 'EdDSA', kid })
|
|
34
|
+
.setIssuer(agentDid)
|
|
35
|
+
.setSubject(userDid)
|
|
36
|
+
.setJti(crypto.randomUUID())
|
|
37
|
+
.setAudience(targetHostname)
|
|
38
|
+
.setIssuedAt(iat)
|
|
39
|
+
.setExpirationTime(exp)
|
|
40
|
+
.sign(privateKey);
|
|
41
|
+
return jwt;
|
|
42
|
+
}
|
|
43
|
+
export function buildChainString(delegation) {
|
|
44
|
+
if (!delegation.id && !delegation.vcId) {
|
|
45
|
+
return '';
|
|
46
|
+
}
|
|
47
|
+
if (!delegation.vcId) {
|
|
48
|
+
return delegation.id;
|
|
49
|
+
}
|
|
50
|
+
return `${delegation.vcId}>${delegation.id}`;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=outbound-proof.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outbound-proof.js","sourceRoot":"","sources":["../../src/delegation/outbound-proof.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAuB1C;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,OAA+B;IAE/B,MAAM,EACJ,QAAQ,EACR,OAAO,EACP,YAAY,EACZ,eAAe,EACf,MAAM,EACN,aAAa,EACb,GAAG,EACH,cAAc,GACf,GAAG,OAAO,CAAC;IAEZ,MAAM,UAAU,GAAG,MAAM,SAAS,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;IAE3D,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IAC1C,MAAM,GAAG,GAAG,GAAG,GAAG,EAAE,CAAC;IAErB,MAAM,GAAG,GAAG,MAAM,IAAI,OAAO,CAAC;QAC5B,aAAa,EAAE,YAAY;QAC3B,gBAAgB,EAAE,eAAe;QACjC,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;KACxB,CAAC;SACC,kBAAkB,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC;SACzC,SAAS,CAAC,QAAQ,CAAC;SACnB,UAAU,CAAC,OAAO,CAAC;SACnB,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;SAC3B,WAAW,CAAC,cAAc,CAAC;SAC3B,WAAW,CAAC,GAAG,CAAC;SAChB,iBAAiB,CAAC,GAAG,CAAC;SACtB,IAAI,CAAC,UAAU,CAAC,CAAC;IAEpB,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,UAA4B;IAC3D,IAAI,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;QACvC,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;QACrB,OAAO,UAAU,CAAC,EAAE,CAAC;IACvB,CAAC;IACD,OAAO,GAAG,UAAU,CAAC,IAAI,IAAI,UAAU,CAAC,EAAE,EAAE,CAAC;AAC/C,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* StatusList2021 Manager
|
|
3
|
+
*
|
|
4
|
+
* Manages StatusList2021 credentials for efficient delegation revocation.
|
|
5
|
+
*
|
|
6
|
+
* Related Spec: W3C StatusList2021
|
|
7
|
+
*/
|
|
8
|
+
import type { StatusList2021Credential, CredentialStatus } from '../types/protocol.js';
|
|
9
|
+
import { type CompressionFunction, type DecompressionFunction } from './bitstring.js';
|
|
10
|
+
import type { VCSigningFunction } from './vc-issuer.js';
|
|
11
|
+
export interface StatusListStorageProvider {
|
|
12
|
+
getStatusList(statusListId: string): Promise<StatusList2021Credential | null>;
|
|
13
|
+
setStatusList(statusListId: string, credential: StatusList2021Credential): Promise<void>;
|
|
14
|
+
allocateIndex(statusListId: string): Promise<number>;
|
|
15
|
+
}
|
|
16
|
+
export interface StatusListIdentityProvider {
|
|
17
|
+
getDid(): string;
|
|
18
|
+
getKeyId(): string;
|
|
19
|
+
}
|
|
20
|
+
export declare class StatusList2021Manager {
|
|
21
|
+
private storage;
|
|
22
|
+
private identity;
|
|
23
|
+
private signingFunction;
|
|
24
|
+
private compressor;
|
|
25
|
+
private decompressor;
|
|
26
|
+
private statusListBaseUrl;
|
|
27
|
+
private defaultListSize;
|
|
28
|
+
/** Per-status-list mutex to serialize updateStatus calls and prevent race conditions. */
|
|
29
|
+
private updateLocks;
|
|
30
|
+
constructor(storage: StatusListStorageProvider, identity: StatusListIdentityProvider, signingFunction: VCSigningFunction, compressor: CompressionFunction, decompressor: DecompressionFunction, options?: {
|
|
31
|
+
statusListBaseUrl?: string;
|
|
32
|
+
defaultListSize?: number;
|
|
33
|
+
});
|
|
34
|
+
allocateStatusEntry(purpose: 'revocation' | 'suspension'): Promise<CredentialStatus>;
|
|
35
|
+
updateStatus(credentialStatus: CredentialStatus, revoked: boolean): Promise<void>;
|
|
36
|
+
private doUpdateStatus;
|
|
37
|
+
checkStatus(credentialStatus: CredentialStatus): Promise<boolean>;
|
|
38
|
+
getRevokedIndices(statusListId: string): Promise<number[]>;
|
|
39
|
+
private ensureStatusListExists;
|
|
40
|
+
getStatusListBaseUrl(): string;
|
|
41
|
+
getDefaultListSize(): number;
|
|
42
|
+
}
|
|
43
|
+
export declare function createStatusListManager(storage: StatusListStorageProvider, identity: StatusListIdentityProvider, signingFunction: VCSigningFunction, compressor: CompressionFunction, decompressor: DecompressionFunction, options?: {
|
|
44
|
+
statusListBaseUrl?: string;
|
|
45
|
+
defaultListSize?: number;
|
|
46
|
+
}): StatusList2021Manager;
|
|
47
|
+
//# sourceMappingURL=statuslist-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"statuslist-manager.d.ts","sourceRoot":"","sources":["../../src/delegation/statuslist-manager.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EACV,wBAAwB,EACxB,gBAAgB,EACjB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAoB,KAAK,mBAAmB,EAAE,KAAK,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AACxG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAGxD,MAAM,WAAW,yBAAyB;IACxC,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,wBAAwB,GAAG,IAAI,CAAC,CAAC;IAC9E,aAAa,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzF,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACtD;AAED,MAAM,WAAW,0BAA0B;IACzC,MAAM,IAAI,MAAM,CAAC;IACjB,QAAQ,IAAI,MAAM,CAAC;CACpB;AAED,qBAAa,qBAAqB;IAO9B,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,eAAe;IACvB,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,YAAY;IAVtB,OAAO,CAAC,iBAAiB,CAAS;IAClC,OAAO,CAAC,eAAe,CAAS;IAChC,yFAAyF;IACzF,OAAO,CAAC,WAAW,CAAoC;gBAG7C,OAAO,EAAE,yBAAyB,EAClC,QAAQ,EAAE,0BAA0B,EACpC,eAAe,EAAE,iBAAiB,EAClC,UAAU,EAAE,mBAAmB,EAC/B,YAAY,EAAE,qBAAqB,EAC3C,OAAO,CAAC,EAAE;QACR,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;KAC1B;IAMG,mBAAmB,CAAC,OAAO,EAAE,YAAY,GAAG,YAAY,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAkBpF,YAAY,CAAC,gBAAgB,EAAE,gBAAgB,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;YAezE,cAAc;IA6CtB,WAAW,CAAC,gBAAgB,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC;IAoBjE,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;YAelD,sBAAsB;IAgDpC,oBAAoB,IAAI,MAAM;IAI9B,kBAAkB,IAAI,MAAM;CAG7B;AAED,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,yBAAyB,EAClC,QAAQ,EAAE,0BAA0B,EACpC,eAAe,EAAE,iBAAiB,EAClC,UAAU,EAAE,mBAAmB,EAC/B,YAAY,EAAE,qBAAqB,EACnC,OAAO,CAAC,EAAE;IACR,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,GACA,qBAAqB,CASvB"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* StatusList2021 Manager
|
|
3
|
+
*
|
|
4
|
+
* Manages StatusList2021 credentials for efficient delegation revocation.
|
|
5
|
+
*
|
|
6
|
+
* Related Spec: W3C StatusList2021
|
|
7
|
+
*/
|
|
8
|
+
import { BitstringManager } from './bitstring.js';
|
|
9
|
+
import { canonicalizeJSON } from './utils.js';
|
|
10
|
+
export class StatusList2021Manager {
|
|
11
|
+
storage;
|
|
12
|
+
identity;
|
|
13
|
+
signingFunction;
|
|
14
|
+
compressor;
|
|
15
|
+
decompressor;
|
|
16
|
+
statusListBaseUrl;
|
|
17
|
+
defaultListSize;
|
|
18
|
+
/** Per-status-list mutex to serialize updateStatus calls and prevent race conditions. */
|
|
19
|
+
updateLocks = new Map();
|
|
20
|
+
constructor(storage, identity, signingFunction, compressor, decompressor, options) {
|
|
21
|
+
this.storage = storage;
|
|
22
|
+
this.identity = identity;
|
|
23
|
+
this.signingFunction = signingFunction;
|
|
24
|
+
this.compressor = compressor;
|
|
25
|
+
this.decompressor = decompressor;
|
|
26
|
+
this.statusListBaseUrl = options?.statusListBaseUrl || 'https://status.example.com';
|
|
27
|
+
this.defaultListSize = options?.defaultListSize || 131072;
|
|
28
|
+
}
|
|
29
|
+
async allocateStatusEntry(purpose) {
|
|
30
|
+
const statusListId = `${this.statusListBaseUrl}/${purpose}/v1`;
|
|
31
|
+
const index = await this.storage.allocateIndex(statusListId);
|
|
32
|
+
await this.ensureStatusListExists(statusListId, purpose);
|
|
33
|
+
const credentialStatus = {
|
|
34
|
+
id: `${statusListId}#${index}`,
|
|
35
|
+
type: 'StatusList2021Entry',
|
|
36
|
+
statusPurpose: purpose,
|
|
37
|
+
statusListIndex: index.toString(),
|
|
38
|
+
statusListCredential: statusListId,
|
|
39
|
+
};
|
|
40
|
+
return credentialStatus;
|
|
41
|
+
}
|
|
42
|
+
async updateStatus(credentialStatus, revoked) {
|
|
43
|
+
const { statusListCredential } = credentialStatus;
|
|
44
|
+
// Serialize updates per status list to prevent concurrent read-modify-write races.
|
|
45
|
+
// Each call chains on the previous operation for the same list.
|
|
46
|
+
const previous = this.updateLocks.get(statusListCredential) ?? Promise.resolve();
|
|
47
|
+
const operation = previous.then(() => this.doUpdateStatus(credentialStatus, revoked));
|
|
48
|
+
// Store a non-rejecting version so the chain continues even if one update fails
|
|
49
|
+
this.updateLocks.set(statusListCredential, operation.catch(() => { }));
|
|
50
|
+
// Propagate the actual error to the caller
|
|
51
|
+
await operation;
|
|
52
|
+
}
|
|
53
|
+
async doUpdateStatus(credentialStatus, revoked) {
|
|
54
|
+
const { statusListCredential, statusListIndex } = credentialStatus;
|
|
55
|
+
const statusList = await this.storage.getStatusList(statusListCredential);
|
|
56
|
+
if (!statusList) {
|
|
57
|
+
throw new Error(`Status list not found: ${statusListCredential}`);
|
|
58
|
+
}
|
|
59
|
+
const manager = await BitstringManager.decode(statusList.credentialSubject.encodedList, this.compressor, this.decompressor);
|
|
60
|
+
const index = parseInt(statusListIndex, 10);
|
|
61
|
+
manager.setBit(index, revoked);
|
|
62
|
+
const encodedList = await manager.encode();
|
|
63
|
+
const updatedCredential = {
|
|
64
|
+
...statusList,
|
|
65
|
+
credentialSubject: {
|
|
66
|
+
...statusList.credentialSubject,
|
|
67
|
+
encodedList,
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
const unsignedCredential = { ...updatedCredential };
|
|
71
|
+
delete unsignedCredential['proof'];
|
|
72
|
+
const canonicalVC = canonicalizeJSON(unsignedCredential);
|
|
73
|
+
const proof = await this.signingFunction(canonicalVC, this.identity.getDid(), this.identity.getKeyId());
|
|
74
|
+
const signedCredential = {
|
|
75
|
+
...updatedCredential,
|
|
76
|
+
proof,
|
|
77
|
+
};
|
|
78
|
+
await this.storage.setStatusList(statusListCredential, signedCredential);
|
|
79
|
+
}
|
|
80
|
+
async checkStatus(credentialStatus) {
|
|
81
|
+
const { statusListCredential, statusListIndex } = credentialStatus;
|
|
82
|
+
const statusList = await this.storage.getStatusList(statusListCredential);
|
|
83
|
+
if (!statusList) {
|
|
84
|
+
throw new Error(`Status list not found: ${statusListCredential} — cannot determine revocation status`);
|
|
85
|
+
}
|
|
86
|
+
const manager = await BitstringManager.decode(statusList.credentialSubject.encodedList, this.compressor, this.decompressor);
|
|
87
|
+
const index = parseInt(statusListIndex, 10);
|
|
88
|
+
return manager.getBit(index);
|
|
89
|
+
}
|
|
90
|
+
async getRevokedIndices(statusListId) {
|
|
91
|
+
const statusList = await this.storage.getStatusList(statusListId);
|
|
92
|
+
if (!statusList) {
|
|
93
|
+
return [];
|
|
94
|
+
}
|
|
95
|
+
const manager = await BitstringManager.decode(statusList.credentialSubject.encodedList, this.compressor, this.decompressor);
|
|
96
|
+
return manager.getSetBits();
|
|
97
|
+
}
|
|
98
|
+
async ensureStatusListExists(statusListId, purpose) {
|
|
99
|
+
const existing = await this.storage.getStatusList(statusListId);
|
|
100
|
+
if (existing) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const manager = new BitstringManager(this.defaultListSize, this.compressor, this.decompressor);
|
|
104
|
+
const encodedList = await manager.encode();
|
|
105
|
+
const unsignedCredential = {
|
|
106
|
+
'@context': [
|
|
107
|
+
'https://www.w3.org/2018/credentials/v1',
|
|
108
|
+
'https://w3id.org/vc/status-list/2021/v1',
|
|
109
|
+
],
|
|
110
|
+
id: statusListId,
|
|
111
|
+
type: ['VerifiableCredential', 'StatusList2021Credential'],
|
|
112
|
+
issuer: this.identity.getDid(),
|
|
113
|
+
issuanceDate: new Date().toISOString(),
|
|
114
|
+
credentialSubject: {
|
|
115
|
+
id: `${statusListId}#list`,
|
|
116
|
+
type: 'StatusList2021',
|
|
117
|
+
statusPurpose: purpose,
|
|
118
|
+
encodedList,
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
const canonicalVC = canonicalizeJSON(unsignedCredential);
|
|
122
|
+
const proof = await this.signingFunction(canonicalVC, this.identity.getDid(), this.identity.getKeyId());
|
|
123
|
+
const signedCredential = {
|
|
124
|
+
...unsignedCredential,
|
|
125
|
+
proof,
|
|
126
|
+
};
|
|
127
|
+
await this.storage.setStatusList(statusListId, signedCredential);
|
|
128
|
+
}
|
|
129
|
+
getStatusListBaseUrl() {
|
|
130
|
+
return this.statusListBaseUrl;
|
|
131
|
+
}
|
|
132
|
+
getDefaultListSize() {
|
|
133
|
+
return this.defaultListSize;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
export function createStatusListManager(storage, identity, signingFunction, compressor, decompressor, options) {
|
|
137
|
+
return new StatusList2021Manager(storage, identity, signingFunction, compressor, decompressor, options);
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=statuslist-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"statuslist-manager.js","sourceRoot":"","sources":["../../src/delegation/statuslist-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-Memory Delegation Graph Storage Provider
|
|
3
|
+
*
|
|
4
|
+
* Memory-based implementation for testing and development.
|
|
5
|
+
* NOT suitable for production (no persistence).
|
|
6
|
+
*
|
|
7
|
+
* SOLID: Implements DelegationGraphStorageProvider interface
|
|
8
|
+
*/
|
|
9
|
+
import type { DelegationGraphStorageProvider, DelegationNode } from '../delegation-graph.js';
|
|
10
|
+
/**
|
|
11
|
+
* Memory-based Delegation Graph storage
|
|
12
|
+
*
|
|
13
|
+
* Stores delegation nodes in memory with efficient graph queries.
|
|
14
|
+
* Useful for:
|
|
15
|
+
* - Unit tests
|
|
16
|
+
* - Integration tests
|
|
17
|
+
* - Development/debugging
|
|
18
|
+
* - Examples
|
|
19
|
+
*/
|
|
20
|
+
export declare class MemoryDelegationGraphStorage implements DelegationGraphStorageProvider {
|
|
21
|
+
private nodes;
|
|
22
|
+
/**
|
|
23
|
+
* Get a delegation node by ID
|
|
24
|
+
*/
|
|
25
|
+
getNode(delegationId: string): Promise<DelegationNode | null>;
|
|
26
|
+
/**
|
|
27
|
+
* Save a delegation node
|
|
28
|
+
*/
|
|
29
|
+
setNode(node: DelegationNode): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Get all children of a delegation
|
|
32
|
+
*/
|
|
33
|
+
getChildren(delegationId: string): Promise<DelegationNode[]>;
|
|
34
|
+
/**
|
|
35
|
+
* Get the full chain from root to this delegation
|
|
36
|
+
*/
|
|
37
|
+
getChain(delegationId: string): Promise<DelegationNode[]>;
|
|
38
|
+
/**
|
|
39
|
+
* Get all descendants (children, grandchildren, etc.)
|
|
40
|
+
*
|
|
41
|
+
* Uses BFS for efficiency.
|
|
42
|
+
*/
|
|
43
|
+
getDescendants(delegationId: string): Promise<DelegationNode[]>;
|
|
44
|
+
/**
|
|
45
|
+
* Delete a node
|
|
46
|
+
*/
|
|
47
|
+
deleteNode(delegationId: string): Promise<void>;
|
|
48
|
+
/**
|
|
49
|
+
* Clear all data (for testing)
|
|
50
|
+
*/
|
|
51
|
+
clear(): void;
|
|
52
|
+
/**
|
|
53
|
+
* Get all node IDs (for testing)
|
|
54
|
+
*/
|
|
55
|
+
getAllNodeIds(): string[];
|
|
56
|
+
/**
|
|
57
|
+
* Get graph statistics (for testing/debugging)
|
|
58
|
+
*/
|
|
59
|
+
getStats(): {
|
|
60
|
+
totalNodes: number;
|
|
61
|
+
rootNodes: number;
|
|
62
|
+
leafNodes: number;
|
|
63
|
+
maxDepth: number;
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Synchronous chain retrieval (for stats)
|
|
67
|
+
*/
|
|
68
|
+
private getChainSync;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=memory-graph-storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-graph-storage.d.ts","sourceRoot":"","sources":["../../../src/delegation/storage/memory-graph-storage.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EACV,8BAA8B,EAC9B,cAAc,EACf,MAAM,wBAAwB,CAAC;AAEhC;;;;;;;;;GASG;AACH,qBAAa,4BACX,YAAW,8BAA8B;IAEzC,OAAO,CAAC,KAAK,CAAqC;IAElD;;OAEG;IACG,OAAO,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAInE;;OAEG;IACG,OAAO,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlD;;OAEG;IACG,WAAW,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IASlE;;OAEG;IACG,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAgB/D;;;;OAIG;IACG,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IA+BrE;;OAEG;IACG,UAAU,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIrD;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,aAAa,IAAI,MAAM,EAAE;IAIzB;;OAEG;IACH,QAAQ,IAAI;QACV,UAAU,EAAE,MAAM,CAAC;QACnB,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;KAClB;IAqBD;;OAEG;IACH,OAAO,CAAC,YAAY;CAcrB"}
|