@kya-os/mcp-i-core 1.1.13-canary.2 → 1.1.14-canary.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/dist/index.d.ts +30 -22
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -1
- package/dist/index.js.map +1 -1
- package/dist/runtime/base.d.ts +14 -0
- package/dist/runtime/base.d.ts.map +1 -1
- package/dist/runtime/base.js +46 -13
- package/dist/runtime/base.js.map +1 -1
- package/dist/services/access-control.service.d.ts +100 -0
- package/dist/services/access-control.service.d.ts.map +1 -0
- package/dist/services/access-control.service.js +134 -0
- package/dist/services/access-control.service.js.map +1 -0
- package/dist/services/crypto.service.d.ts +69 -0
- package/dist/services/crypto.service.d.ts.map +1 -0
- package/dist/services/crypto.service.js +225 -0
- package/dist/services/crypto.service.js.map +1 -0
- package/dist/services/errors.d.ts +49 -0
- package/dist/services/errors.d.ts.map +1 -0
- package/dist/services/errors.js +66 -0
- package/dist/services/errors.js.map +1 -0
- package/dist/services/index.d.ts +5 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +8 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/proof-verifier.d.ts +98 -0
- package/dist/services/proof-verifier.d.ts.map +1 -0
- package/dist/services/proof-verifier.js +318 -0
- package/dist/services/proof-verifier.js.map +1 -0
- package/dist/utils/base64.d.ts +31 -0
- package/dist/utils/base64.d.ts.map +1 -0
- package/dist/utils/base64.js +138 -0
- package/dist/utils/base64.js.map +1 -0
- package/dist/utils/index.d.ts +3 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +2 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/storage-keys.d.ts +119 -0
- package/dist/utils/storage-keys.d.ts.map +1 -0
- package/dist/utils/storage-keys.js +217 -0
- package/dist/utils/storage-keys.js.map +1 -0
- package/package.json +3 -2
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* ProofVerifier
|
|
4
|
+
*
|
|
5
|
+
* Centralized proof verification service that validates DetachedProof
|
|
6
|
+
* signatures, enforces nonce replay protection, and checks timestamp skew.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.ProofVerifier = void 0;
|
|
10
|
+
const crypto_service_js_1 = require("./crypto.service.js");
|
|
11
|
+
const proof_1 = require("@kya-os/contracts/proof");
|
|
12
|
+
const json_canonicalize_1 = require("json-canonicalize");
|
|
13
|
+
const errors_js_1 = require("./errors.js");
|
|
14
|
+
class ProofVerifier {
|
|
15
|
+
cryptoService;
|
|
16
|
+
clock;
|
|
17
|
+
nonceCache;
|
|
18
|
+
fetch;
|
|
19
|
+
timestampSkewSeconds;
|
|
20
|
+
nonceTtlSeconds;
|
|
21
|
+
constructor(config) {
|
|
22
|
+
this.cryptoService = new crypto_service_js_1.CryptoService(config.cryptoProvider);
|
|
23
|
+
this.clock = config.clockProvider;
|
|
24
|
+
this.nonceCache = config.nonceCacheProvider;
|
|
25
|
+
this.fetch = config.fetchProvider;
|
|
26
|
+
this.timestampSkewSeconds = config.timestampSkewSeconds ?? 120; // Default 2 minutes
|
|
27
|
+
this.nonceTtlSeconds = config.nonceTtlSeconds ?? 300; // Default 5 minutes
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Verify a DetachedProof
|
|
31
|
+
* Automatically reconstructs canonical payload from proof.meta for signature verification
|
|
32
|
+
* @param proof - The proof to verify
|
|
33
|
+
* @param publicKeyJwk - Ed25519 public key in JWK format (from DID document)
|
|
34
|
+
* @returns Verification result
|
|
35
|
+
*/
|
|
36
|
+
async verifyProof(proof, publicKeyJwk) {
|
|
37
|
+
try {
|
|
38
|
+
// 1. Validate proof structure
|
|
39
|
+
const structureValidation = await this.validateProofStructure(proof);
|
|
40
|
+
if (!structureValidation.valid) {
|
|
41
|
+
return structureValidation;
|
|
42
|
+
}
|
|
43
|
+
const validatedProof = structureValidation.proof;
|
|
44
|
+
// 2. Check nonce replay protection
|
|
45
|
+
const nonceValidation = await this.validateNonce(validatedProof.meta.nonce);
|
|
46
|
+
if (!nonceValidation.valid) {
|
|
47
|
+
return nonceValidation;
|
|
48
|
+
}
|
|
49
|
+
// 3. Check timestamp skew
|
|
50
|
+
const timestampValidation = await this.validateTimestamp(validatedProof.meta.ts);
|
|
51
|
+
if (!timestampValidation.valid) {
|
|
52
|
+
return timestampValidation;
|
|
53
|
+
}
|
|
54
|
+
// 4. Reconstruct canonical payload from proof meta
|
|
55
|
+
const canonicalPayloadString = this.buildCanonicalPayload(validatedProof.meta);
|
|
56
|
+
const canonicalPayloadBytes = new TextEncoder().encode(canonicalPayloadString);
|
|
57
|
+
// 5. Verify JWS signature with detached canonical payload
|
|
58
|
+
const signatureValidation = await this.verifySignature(validatedProof.jws, publicKeyJwk, canonicalPayloadBytes, validatedProof.meta.kid);
|
|
59
|
+
if (!signatureValidation.valid) {
|
|
60
|
+
return signatureValidation;
|
|
61
|
+
}
|
|
62
|
+
// 6. Add nonce to cache to prevent replay
|
|
63
|
+
await this.addNonceToCache(validatedProof.meta.nonce);
|
|
64
|
+
return {
|
|
65
|
+
valid: true,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
// Security-safe failure: never throw, always return error result
|
|
70
|
+
return {
|
|
71
|
+
valid: false,
|
|
72
|
+
reason: "Proof verification error",
|
|
73
|
+
errorCode: errors_js_1.PROOF_VERIFICATION_ERROR_CODES.VERIFICATION_ERROR,
|
|
74
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
75
|
+
details: {
|
|
76
|
+
errorMessage: error instanceof Error ? error.message : String(error),
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Verify proof with detached payload (for CLI/verifier compatibility)
|
|
83
|
+
* @param proof - The proof to verify
|
|
84
|
+
* @param canonicalPayload - Canonical JSON payload (for detached JWS) as string or Uint8Array
|
|
85
|
+
* @param publicKeyJwk - Ed25519 public key in JWK format
|
|
86
|
+
* @returns Verification result
|
|
87
|
+
*/
|
|
88
|
+
async verifyProofDetached(proof, canonicalPayload, publicKeyJwk) {
|
|
89
|
+
try {
|
|
90
|
+
// 1. Validate proof structure
|
|
91
|
+
const structureValidation = await this.validateProofStructure(proof);
|
|
92
|
+
if (!structureValidation.valid) {
|
|
93
|
+
return structureValidation;
|
|
94
|
+
}
|
|
95
|
+
const validatedProof = structureValidation.proof;
|
|
96
|
+
// 2. Check nonce replay protection
|
|
97
|
+
const nonceValidation = await this.validateNonce(validatedProof.meta.nonce);
|
|
98
|
+
if (!nonceValidation.valid) {
|
|
99
|
+
return nonceValidation;
|
|
100
|
+
}
|
|
101
|
+
// 3. Check timestamp skew
|
|
102
|
+
const timestampValidation = await this.validateTimestamp(validatedProof.meta.ts);
|
|
103
|
+
if (!timestampValidation.valid) {
|
|
104
|
+
return timestampValidation;
|
|
105
|
+
}
|
|
106
|
+
// 4. Convert canonical payload to Uint8Array if needed
|
|
107
|
+
const canonicalPayloadBytes = canonicalPayload instanceof Uint8Array
|
|
108
|
+
? canonicalPayload
|
|
109
|
+
: new TextEncoder().encode(canonicalPayload);
|
|
110
|
+
// 5. Verify JWS signature with detached payload
|
|
111
|
+
const signatureValidation = await this.verifySignature(validatedProof.jws, publicKeyJwk, canonicalPayloadBytes, validatedProof.meta.kid);
|
|
112
|
+
if (!signatureValidation.valid) {
|
|
113
|
+
return signatureValidation;
|
|
114
|
+
}
|
|
115
|
+
// 6. Add nonce to cache
|
|
116
|
+
await this.addNonceToCache(validatedProof.meta.nonce);
|
|
117
|
+
return {
|
|
118
|
+
valid: true,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
// Security-safe failure: never throw, always return error result
|
|
123
|
+
return {
|
|
124
|
+
valid: false,
|
|
125
|
+
reason: "Proof verification error",
|
|
126
|
+
errorCode: errors_js_1.PROOF_VERIFICATION_ERROR_CODES.VERIFICATION_ERROR,
|
|
127
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
128
|
+
details: {
|
|
129
|
+
errorMessage: error instanceof Error ? error.message : String(error),
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Validate proof structure using Zod schema
|
|
136
|
+
* @private
|
|
137
|
+
*/
|
|
138
|
+
async validateProofStructure(proof) {
|
|
139
|
+
const validationResult = proof_1.DetachedProofSchema.safeParse(proof);
|
|
140
|
+
if (!validationResult.success) {
|
|
141
|
+
return {
|
|
142
|
+
valid: false,
|
|
143
|
+
reason: "Invalid proof structure",
|
|
144
|
+
errorCode: errors_js_1.PROOF_VERIFICATION_ERROR_CODES.INVALID_PROOF_STRUCTURE,
|
|
145
|
+
error: new Error(`Proof validation failed: ${validationResult.error.message}`),
|
|
146
|
+
details: {
|
|
147
|
+
zodErrors: validationResult.error.errors,
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
return {
|
|
152
|
+
valid: true,
|
|
153
|
+
proof: validationResult.data,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Validate nonce replay protection
|
|
158
|
+
* @private
|
|
159
|
+
*/
|
|
160
|
+
async validateNonce(nonce) {
|
|
161
|
+
const nonceUsed = await this.nonceCache.has(nonce);
|
|
162
|
+
if (nonceUsed) {
|
|
163
|
+
return {
|
|
164
|
+
valid: false,
|
|
165
|
+
reason: "Nonce already used (replay attack detected)",
|
|
166
|
+
errorCode: errors_js_1.PROOF_VERIFICATION_ERROR_CODES.NONCE_REPLAY_DETECTED,
|
|
167
|
+
details: {
|
|
168
|
+
nonce,
|
|
169
|
+
},
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
return { valid: true };
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Validate timestamp skew
|
|
176
|
+
* @private
|
|
177
|
+
*/
|
|
178
|
+
async validateTimestamp(timestamp) {
|
|
179
|
+
// Convert seconds to milliseconds for clock provider (which uses Date.now())
|
|
180
|
+
const timestampMs = timestamp * 1000;
|
|
181
|
+
if (!this.clock.isWithinSkew(timestampMs, this.timestampSkewSeconds)) {
|
|
182
|
+
return {
|
|
183
|
+
valid: false,
|
|
184
|
+
reason: `Timestamp out of skew window (skew: ${this.timestampSkewSeconds}s)`,
|
|
185
|
+
errorCode: errors_js_1.PROOF_VERIFICATION_ERROR_CODES.TIMESTAMP_SKEW_EXCEEDED,
|
|
186
|
+
details: {
|
|
187
|
+
timestamp,
|
|
188
|
+
timestampMs,
|
|
189
|
+
skewSeconds: this.timestampSkewSeconds,
|
|
190
|
+
currentTime: this.clock.now(),
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
return { valid: true };
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Verify JWS signature
|
|
198
|
+
* @private
|
|
199
|
+
*/
|
|
200
|
+
async verifySignature(jws, publicKeyJwk, canonicalPayloadBytes, expectedKid) {
|
|
201
|
+
const signatureValid = await this.cryptoService.verifyJWS(jws, publicKeyJwk, {
|
|
202
|
+
detachedPayload: canonicalPayloadBytes,
|
|
203
|
+
expectedKid,
|
|
204
|
+
alg: "EdDSA",
|
|
205
|
+
});
|
|
206
|
+
if (!signatureValid) {
|
|
207
|
+
return {
|
|
208
|
+
valid: false,
|
|
209
|
+
reason: "Invalid JWS signature",
|
|
210
|
+
errorCode: errors_js_1.PROOF_VERIFICATION_ERROR_CODES.INVALID_JWS_SIGNATURE,
|
|
211
|
+
details: {
|
|
212
|
+
jwsLength: jws.length,
|
|
213
|
+
expectedKid,
|
|
214
|
+
actualKid: publicKeyJwk.kid,
|
|
215
|
+
},
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
return { valid: true };
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Add nonce to cache to prevent replay
|
|
222
|
+
* @private
|
|
223
|
+
*/
|
|
224
|
+
async addNonceToCache(nonce) {
|
|
225
|
+
const expiresAt = this.clock.calculateExpiry(this.nonceTtlSeconds);
|
|
226
|
+
await this.nonceCache.add(nonce, expiresAt);
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Fetch public key from DID document
|
|
230
|
+
* @param did - DID to resolve
|
|
231
|
+
* @param kid - Key ID (optional, defaults to first verification method)
|
|
232
|
+
* @returns Ed25519 JWK or null if not found
|
|
233
|
+
* @throws {ProofVerificationError} If DID resolution fails with specific error code
|
|
234
|
+
*/
|
|
235
|
+
async fetchPublicKeyFromDID(did, kid) {
|
|
236
|
+
try {
|
|
237
|
+
const didDoc = await this.fetch.resolveDID(did);
|
|
238
|
+
if (!didDoc) {
|
|
239
|
+
throw new errors_js_1.ProofVerificationError(errors_js_1.PROOF_VERIFICATION_ERROR_CODES.DID_DOCUMENT_NOT_FOUND, `DID document not found: ${did}`, { did });
|
|
240
|
+
}
|
|
241
|
+
if (!didDoc.verificationMethod ||
|
|
242
|
+
didDoc.verificationMethod.length === 0) {
|
|
243
|
+
throw new errors_js_1.ProofVerificationError(errors_js_1.PROOF_VERIFICATION_ERROR_CODES.VERIFICATION_METHOD_NOT_FOUND, `No verification methods found in DID document: ${did}`, { did });
|
|
244
|
+
}
|
|
245
|
+
// Find verification method by kid or use first one
|
|
246
|
+
let verificationMethod;
|
|
247
|
+
if (kid) {
|
|
248
|
+
const kidWithHash = kid.startsWith("#") ? kid : `#${kid}`;
|
|
249
|
+
verificationMethod = didDoc.verificationMethod.find((vm) => vm.id === kidWithHash || vm.id === `${did}${kidWithHash}`);
|
|
250
|
+
if (!verificationMethod) {
|
|
251
|
+
throw new errors_js_1.ProofVerificationError(errors_js_1.PROOF_VERIFICATION_ERROR_CODES.VERIFICATION_METHOD_NOT_FOUND, `Verification method not found for kid: ${kid}`, {
|
|
252
|
+
did,
|
|
253
|
+
kid,
|
|
254
|
+
availableKids: didDoc.verificationMethod.map((vm) => vm.id),
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
else {
|
|
259
|
+
verificationMethod = didDoc.verificationMethod[0];
|
|
260
|
+
}
|
|
261
|
+
if (!verificationMethod?.publicKeyJwk) {
|
|
262
|
+
throw new errors_js_1.ProofVerificationError(errors_js_1.PROOF_VERIFICATION_ERROR_CODES.PUBLIC_KEY_NOT_FOUND, `Public key JWK not found in verification method`, { did, kid, verificationMethodId: verificationMethod?.id });
|
|
263
|
+
}
|
|
264
|
+
const jwk = verificationMethod.publicKeyJwk;
|
|
265
|
+
// Validate it's an Ed25519 key
|
|
266
|
+
if (jwk.kty !== "OKP" || jwk.crv !== "Ed25519" || !jwk.x) {
|
|
267
|
+
throw new errors_js_1.ProofVerificationError(errors_js_1.PROOF_VERIFICATION_ERROR_CODES.INVALID_JWK_FORMAT, `Unsupported key type or curve: kty=${jwk.kty}, crv=${jwk.crv}`, { did, kid, jwk: { kty: jwk.kty, crv: jwk.crv } });
|
|
268
|
+
}
|
|
269
|
+
return jwk;
|
|
270
|
+
}
|
|
271
|
+
catch (error) {
|
|
272
|
+
if (error instanceof errors_js_1.ProofVerificationError) {
|
|
273
|
+
throw error;
|
|
274
|
+
}
|
|
275
|
+
console.error("[ProofVerifier] Failed to fetch public key from DID:", error);
|
|
276
|
+
throw new errors_js_1.ProofVerificationError(errors_js_1.PROOF_VERIFICATION_ERROR_CODES.DID_RESOLUTION_FAILED, `DID resolution failed: ${error instanceof Error ? error.message : String(error)}`, {
|
|
277
|
+
did,
|
|
278
|
+
kid,
|
|
279
|
+
originalError: error instanceof Error ? error.message : String(error),
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Build canonical payload from proof meta
|
|
285
|
+
*
|
|
286
|
+
* CRITICAL: This must reconstruct the exact JWS payload structure that was originally signed.
|
|
287
|
+
* The original JWS payload uses standard JWT claims (aud, sub, iss) plus custom proof claims,
|
|
288
|
+
* NOT the proof.meta structure directly.
|
|
289
|
+
*
|
|
290
|
+
* @param meta - Proof metadata
|
|
291
|
+
* @returns Canonical JSON string matching the original JWS payload structure
|
|
292
|
+
*/
|
|
293
|
+
buildCanonicalPayload(meta) {
|
|
294
|
+
// Reconstruct the original JWS payload structure that was signed
|
|
295
|
+
// This matches the structure used in proof generation (proof.ts, proof-generator.ts)
|
|
296
|
+
const payload = {
|
|
297
|
+
// Standard JWT claims (RFC 7519) - these are what was actually signed
|
|
298
|
+
aud: meta.audience, // Audience (who the token is for)
|
|
299
|
+
sub: meta.did, // Subject (agent DID)
|
|
300
|
+
iss: meta.did, // Issuer (agent DID - self-issued)
|
|
301
|
+
// Custom MCP-I proof claims
|
|
302
|
+
requestHash: meta.requestHash,
|
|
303
|
+
responseHash: meta.responseHash,
|
|
304
|
+
ts: meta.ts,
|
|
305
|
+
nonce: meta.nonce,
|
|
306
|
+
sessionId: meta.sessionId,
|
|
307
|
+
// Optional claims (only include if present)
|
|
308
|
+
...(meta.scopeId && { scopeId: meta.scopeId }),
|
|
309
|
+
...(meta.delegationRef && { delegationRef: meta.delegationRef }),
|
|
310
|
+
...(meta.clientDid && { clientDid: meta.clientDid }),
|
|
311
|
+
};
|
|
312
|
+
// Canonicalize the reconstructed payload using the same function as proof generation
|
|
313
|
+
// CRITICAL: Must use json-canonicalize canonicalize() to match proof.ts exactly
|
|
314
|
+
return (0, json_canonicalize_1.canonicalize)(payload);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
exports.ProofVerifier = ProofVerifier;
|
|
318
|
+
//# sourceMappingURL=proof-verifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proof-verifier.js","sourceRoot":"","sources":["../../src/services/proof-verifier.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base64URL Encoding/Decoding Utilities
|
|
3
|
+
*
|
|
4
|
+
* Environment-aware base64url helpers that work in both Node.js and Cloudflare Workers.
|
|
5
|
+
* Uses Buffer in Node.js, TextEncoder/Decoder fallback for Workers.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Decode base64url string to string
|
|
9
|
+
*/
|
|
10
|
+
export declare function base64urlDecodeToString(input: string): string;
|
|
11
|
+
/**
|
|
12
|
+
* Decode base64url string to Uint8Array
|
|
13
|
+
*/
|
|
14
|
+
export declare function base64urlDecodeToBytes(input: string): Uint8Array;
|
|
15
|
+
/**
|
|
16
|
+
* Encode string to base64url
|
|
17
|
+
*/
|
|
18
|
+
export declare function base64urlEncodeFromString(input: string): string;
|
|
19
|
+
/**
|
|
20
|
+
* Encode Uint8Array to base64url
|
|
21
|
+
*/
|
|
22
|
+
export declare function base64urlEncodeFromBytes(bytes: Uint8Array): string;
|
|
23
|
+
/**
|
|
24
|
+
* Convert bytes to standard base64 (not base64url)
|
|
25
|
+
*/
|
|
26
|
+
export declare function bytesToBase64(bytes: Uint8Array): string;
|
|
27
|
+
/**
|
|
28
|
+
* Convert standard base64 to bytes
|
|
29
|
+
*/
|
|
30
|
+
export declare function base64ToBytes(base64: string): Uint8Array;
|
|
31
|
+
//# sourceMappingURL=base64.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base64.d.ts","sourceRoot":"","sources":["../../src/utils/base64.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CA+B7D;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAuBhE;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAU/D;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAalE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAWvD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAaxD"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Base64URL Encoding/Decoding Utilities
|
|
4
|
+
*
|
|
5
|
+
* Environment-aware base64url helpers that work in both Node.js and Cloudflare Workers.
|
|
6
|
+
* Uses Buffer in Node.js, TextEncoder/Decoder fallback for Workers.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.base64urlDecodeToString = base64urlDecodeToString;
|
|
10
|
+
exports.base64urlDecodeToBytes = base64urlDecodeToBytes;
|
|
11
|
+
exports.base64urlEncodeFromString = base64urlEncodeFromString;
|
|
12
|
+
exports.base64urlEncodeFromBytes = base64urlEncodeFromBytes;
|
|
13
|
+
exports.bytesToBase64 = bytesToBase64;
|
|
14
|
+
exports.base64ToBytes = base64ToBytes;
|
|
15
|
+
/**
|
|
16
|
+
* Decode base64url string to string
|
|
17
|
+
*/
|
|
18
|
+
function base64urlDecodeToString(input) {
|
|
19
|
+
const padded = addPadding(input);
|
|
20
|
+
const base64 = padded.replace(/-/g, "+").replace(/_/g, "/");
|
|
21
|
+
// For platforms that don't have Buffer (e.g., Cloudflare Workers)
|
|
22
|
+
if (typeof atob !== "undefined") {
|
|
23
|
+
try {
|
|
24
|
+
return atob(base64);
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
throw new Error(`Invalid base64url string: ${error instanceof Error ? error.message : String(error)}`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
// For Node.js environments - Buffer.from doesn't throw for invalid base64
|
|
31
|
+
// We need to validate by checking if the input contains only valid base64 characters
|
|
32
|
+
// Base64 characters: A-Z, a-z, 0-9, +, /, = (padding)
|
|
33
|
+
const base64Regex = /^[A-Za-z0-9+/]*={0,2}$/;
|
|
34
|
+
if (!base64Regex.test(base64)) {
|
|
35
|
+
throw new Error("Invalid base64url string: contains invalid characters");
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
const decoded = Buffer.from(base64, "base64").toString("utf-8");
|
|
39
|
+
return decoded;
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
throw new Error(`Invalid base64url string: ${error instanceof Error ? error.message : String(error)}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Decode base64url string to Uint8Array
|
|
47
|
+
*/
|
|
48
|
+
function base64urlDecodeToBytes(input) {
|
|
49
|
+
const padded = addPadding(input);
|
|
50
|
+
const base64 = padded.replace(/-/g, "+").replace(/_/g, "/");
|
|
51
|
+
// For platforms that don't have Buffer (e.g., Cloudflare Workers)
|
|
52
|
+
if (typeof atob !== "undefined") {
|
|
53
|
+
try {
|
|
54
|
+
const binaryString = atob(base64);
|
|
55
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
56
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
57
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
58
|
+
}
|
|
59
|
+
return bytes;
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
throw new Error(`Invalid base64url string: ${error instanceof Error ? error.message : String(error)}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// For Node.js environments - Buffer.from doesn't throw, so we can't validate here
|
|
66
|
+
// The caller should validate the result if needed
|
|
67
|
+
return new Uint8Array(Buffer.from(base64, "base64"));
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Encode string to base64url
|
|
71
|
+
*/
|
|
72
|
+
function base64urlEncodeFromString(input) {
|
|
73
|
+
// For platforms that don't have Buffer
|
|
74
|
+
if (typeof btoa !== "undefined") {
|
|
75
|
+
const base64 = btoa(input);
|
|
76
|
+
return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
77
|
+
}
|
|
78
|
+
// For Node.js environments
|
|
79
|
+
const base64 = Buffer.from(input, "utf-8").toString("base64");
|
|
80
|
+
return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Encode Uint8Array to base64url
|
|
84
|
+
*/
|
|
85
|
+
function base64urlEncodeFromBytes(bytes) {
|
|
86
|
+
// For platforms that don't have Buffer
|
|
87
|
+
if (typeof btoa !== "undefined") {
|
|
88
|
+
const binaryString = Array.from(bytes)
|
|
89
|
+
.map((byte) => String.fromCharCode(byte))
|
|
90
|
+
.join("");
|
|
91
|
+
const base64 = btoa(binaryString);
|
|
92
|
+
return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
93
|
+
}
|
|
94
|
+
// For Node.js environments
|
|
95
|
+
const base64 = Buffer.from(bytes).toString("base64");
|
|
96
|
+
return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Convert bytes to standard base64 (not base64url)
|
|
100
|
+
*/
|
|
101
|
+
function bytesToBase64(bytes) {
|
|
102
|
+
// For platforms that don't have Buffer
|
|
103
|
+
if (typeof btoa !== "undefined") {
|
|
104
|
+
const binaryString = Array.from(bytes)
|
|
105
|
+
.map((byte) => String.fromCharCode(byte))
|
|
106
|
+
.join("");
|
|
107
|
+
return btoa(binaryString);
|
|
108
|
+
}
|
|
109
|
+
// For Node.js environments
|
|
110
|
+
return Buffer.from(bytes).toString("base64");
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Convert standard base64 to bytes
|
|
114
|
+
*/
|
|
115
|
+
function base64ToBytes(base64) {
|
|
116
|
+
// For platforms that don't have Buffer
|
|
117
|
+
if (typeof atob !== "undefined") {
|
|
118
|
+
const binaryString = atob(base64);
|
|
119
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
120
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
121
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
122
|
+
}
|
|
123
|
+
return bytes;
|
|
124
|
+
}
|
|
125
|
+
// For Node.js environments
|
|
126
|
+
return new Uint8Array(Buffer.from(base64, "base64"));
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Add padding to base64url string if needed
|
|
130
|
+
*/
|
|
131
|
+
function addPadding(input) {
|
|
132
|
+
const remainder = input.length % 4;
|
|
133
|
+
if (remainder === 0) {
|
|
134
|
+
return input;
|
|
135
|
+
}
|
|
136
|
+
return input + "=".repeat((4 - remainder) % 4);
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=base64.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base64.js","sourceRoot":"","sources":["../../src/utils/base64.ts"],"names":[],"mappings":"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"}
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,QAAQ,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,QAAQ,CAAC;AACvB,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC"}
|
package/dist/utils/index.js
CHANGED
|
@@ -18,4 +18,6 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
18
18
|
};
|
|
19
19
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
20
|
__exportStar(require("./cors"), exports);
|
|
21
|
+
__exportStar(require("./base64"), exports);
|
|
22
|
+
__exportStar(require("./storage-keys"), exports);
|
|
21
23
|
//# sourceMappingURL=index.js.map
|
package/dist/utils/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":";AAAA;;GAEG;;;;;;;;;;;;;;;;AAEH,yCAAuB"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":";AAAA;;GAEG;;;;;;;;;;;;;;;;AAEH,yCAAuB;AACvB,2CAAyB;AACzB,iDAA+B"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Storage Key Migration Utilities
|
|
3
|
+
*
|
|
4
|
+
* Provides utilities for migrating from old storage key formats to new composite formats.
|
|
5
|
+
* This supports Phase 3 Task 2 (StorageService) and Phase 4 (User DID identity linking).
|
|
6
|
+
*
|
|
7
|
+
* @package @kya-os/mcp-i-core
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Legacy storage key format (agent-only, causes multi-tenant conflicts)
|
|
11
|
+
* Format: `agent:${agentDid}:delegation`
|
|
12
|
+
*/
|
|
13
|
+
export declare function legacyDelegationKey(agentDid: string): string;
|
|
14
|
+
/**
|
|
15
|
+
* New composite storage key format (user+agent scoped, prevents conflicts)
|
|
16
|
+
* Format: `delegation:user:${userDid}:agent:${agentDid}:project:${projectId}`
|
|
17
|
+
*
|
|
18
|
+
* Note: projectId is optional for backward compatibility
|
|
19
|
+
*/
|
|
20
|
+
export declare function compositeDelegationKey(userDid: string, agentDid: string, projectId?: string): string;
|
|
21
|
+
/**
|
|
22
|
+
* Session cache key format
|
|
23
|
+
* Format: `session:${sessionId}`
|
|
24
|
+
*/
|
|
25
|
+
export declare function sessionKey(sessionId: string): string;
|
|
26
|
+
/**
|
|
27
|
+
* User DID storage key format
|
|
28
|
+
* Format: `userDid:oauth:${provider}:${subject}`
|
|
29
|
+
*/
|
|
30
|
+
export declare function userDidKey(provider: string, subject: string): string;
|
|
31
|
+
/**
|
|
32
|
+
* OAuth identity mapping key format
|
|
33
|
+
* Format: `oauth:${provider}:${subject}`
|
|
34
|
+
*/
|
|
35
|
+
export declare function oauthIdentityKey(provider: string, subject: string): string;
|
|
36
|
+
/**
|
|
37
|
+
* Verification cache key format
|
|
38
|
+
* Format: `verified:${tokenHash}`
|
|
39
|
+
*/
|
|
40
|
+
export declare function verificationCacheKey(tokenHash: string): string;
|
|
41
|
+
/**
|
|
42
|
+
* Nonce tracking key format
|
|
43
|
+
* Format: `nonce:${nonce}`
|
|
44
|
+
*/
|
|
45
|
+
export declare function nonceKey(nonce: string): string;
|
|
46
|
+
/**
|
|
47
|
+
* Storage key migration result
|
|
48
|
+
*/
|
|
49
|
+
export interface MigrationResult {
|
|
50
|
+
/** Number of keys migrated */
|
|
51
|
+
migrated: number;
|
|
52
|
+
/** Number of keys that failed to migrate */
|
|
53
|
+
failed: number;
|
|
54
|
+
/** List of migrated key pairs (old -> new) */
|
|
55
|
+
migrations: Array<{
|
|
56
|
+
oldKey: string;
|
|
57
|
+
newKey: string;
|
|
58
|
+
}>;
|
|
59
|
+
/** List of errors encountered */
|
|
60
|
+
errors: Array<{
|
|
61
|
+
key: string;
|
|
62
|
+
error: string;
|
|
63
|
+
}>;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Storage provider interface for migration operations
|
|
67
|
+
*
|
|
68
|
+
* Matches the base StorageProvider abstract class contract.
|
|
69
|
+
*/
|
|
70
|
+
export interface StorageProvider {
|
|
71
|
+
get(key: string): Promise<string | null>;
|
|
72
|
+
set(key: string, value: string): Promise<void>;
|
|
73
|
+
delete(key: string): Promise<void>;
|
|
74
|
+
list(prefix?: string): Promise<string[]>;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Migrate delegation keys from legacy format to composite format
|
|
78
|
+
*
|
|
79
|
+
* This function:
|
|
80
|
+
* 1. Finds all legacy keys (`agent:${did}:delegation`)
|
|
81
|
+
* 2. Attempts to extract userDid from session data or OAuth mappings
|
|
82
|
+
* 3. Creates new composite keys (`delegation:user:${userDid}:agent:${agentDid}`)
|
|
83
|
+
* 4. Copies values to new keys
|
|
84
|
+
* 5. Optionally deletes old keys (dry-run mode available)
|
|
85
|
+
*
|
|
86
|
+
* @param storage - Storage provider instance
|
|
87
|
+
* @param options - Migration options
|
|
88
|
+
* @returns Migration result with statistics
|
|
89
|
+
*/
|
|
90
|
+
export declare function migrateDelegationKeys(storage: StorageProvider, options?: {
|
|
91
|
+
/** If true, only report what would be migrated without making changes */
|
|
92
|
+
dryRun?: boolean;
|
|
93
|
+
/** If true, delete old keys after successful migration */
|
|
94
|
+
deleteOldKeys?: boolean;
|
|
95
|
+
/** Optional userDid resolver function (if not provided, attempts to extract from session) */
|
|
96
|
+
resolveUserDid?: (agentDid: string, sessionId?: string) => Promise<string | null>;
|
|
97
|
+
}): Promise<MigrationResult>;
|
|
98
|
+
/**
|
|
99
|
+
* Storage key constants for consistent namespace management
|
|
100
|
+
*
|
|
101
|
+
* These match the Phase 4 storage key architecture.
|
|
102
|
+
*/
|
|
103
|
+
export declare const STORAGE_KEYS: {
|
|
104
|
+
/** User DID storage (persistent - 90 days) */
|
|
105
|
+
readonly userDid: typeof userDidKey;
|
|
106
|
+
/** OAuth identity mapping (persistent - 90 days) */
|
|
107
|
+
readonly oauthIdentity: typeof oauthIdentityKey;
|
|
108
|
+
/** User+Agent delegation tokens (persistent - 7 days) */
|
|
109
|
+
readonly delegation: typeof compositeDelegationKey;
|
|
110
|
+
/** Session cache (temporary - 30 minutes) */
|
|
111
|
+
readonly session: typeof sessionKey;
|
|
112
|
+
/** Legacy delegation format (deprecated - 24 hours) */
|
|
113
|
+
readonly legacyDelegation: typeof legacyDelegationKey;
|
|
114
|
+
/** Verification cache (temporary - 5 minutes) */
|
|
115
|
+
readonly verificationCache: typeof verificationCacheKey;
|
|
116
|
+
/** Nonce tracking (temporary - 5 minutes) */
|
|
117
|
+
readonly nonce: typeof nonceKey;
|
|
118
|
+
};
|
|
119
|
+
//# sourceMappingURL=storage-keys.d.ts.map
|