@kya-os/mcp-i 0.1.0 → 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/README.md +406 -71
- package/dist/149.js +1 -0
- package/dist/189.js +1 -0
- package/dist/261.js +1 -0
- package/dist/28.js +1 -0
- package/dist/295.js +1 -0
- package/dist/460.js +1 -0
- package/dist/570.js +1 -0
- package/dist/634.js +1 -0
- package/dist/647.js +1 -0
- package/dist/67.js +1 -0
- package/dist/739.js +1 -0
- package/dist/742.js +1 -0
- package/dist/904.js +1 -0
- package/dist/938.js +1 -0
- package/dist/auth/api-key.d.ts +16 -0
- package/dist/auth/api-key.js +82 -0
- package/dist/auth/jwt.d.ts +43 -0
- package/dist/auth/jwt.js +51 -0
- package/dist/auth/oauth/factory.d.ts +12 -0
- package/dist/auth/oauth/factory.js +36 -0
- package/dist/auth/oauth/index.d.ts +5 -0
- package/dist/auth/oauth/index.js +27 -0
- package/dist/auth/oauth/providers/proxy-provider.d.ts +13 -0
- package/dist/auth/oauth/providers/proxy-provider.js +159 -0
- package/dist/auth/oauth/router.d.ts +4 -0
- package/dist/auth/oauth/router.js +294 -0
- package/dist/auth/oauth/storage/memory-storage.d.ts +12 -0
- package/dist/auth/oauth/storage/memory-storage.js +40 -0
- package/dist/auth/oauth/types.d.ts +112 -0
- package/dist/auth/oauth/types.js +2 -0
- package/dist/cache/__tests__/cloudflare-kv-nonce-cache.test.d.ts +4 -0
- package/dist/cache/__tests__/cloudflare-kv-nonce-cache.test.js +176 -0
- package/dist/cache/__tests__/concurrency.test.d.ts +5 -0
- package/dist/cache/__tests__/concurrency.test.js +300 -0
- package/dist/cache/__tests__/dynamodb-nonce-cache.test.d.ts +4 -0
- package/dist/cache/__tests__/dynamodb-nonce-cache.test.js +176 -0
- package/dist/cache/__tests__/memory-nonce-cache.test.d.ts +4 -0
- package/dist/cache/__tests__/memory-nonce-cache.test.js +132 -0
- package/dist/cache/__tests__/nonce-cache-factory-simple.test.d.ts +4 -0
- package/dist/cache/__tests__/nonce-cache-factory-simple.test.js +133 -0
- package/dist/cache/__tests__/nonce-cache-factory.test.d.ts +4 -0
- package/dist/cache/__tests__/nonce-cache-factory.test.js +252 -0
- package/dist/cache/__tests__/redis-nonce-cache.test.d.ts +4 -0
- package/dist/cache/__tests__/redis-nonce-cache.test.js +95 -0
- package/dist/cache/cloudflare-kv-nonce-cache.d.ts +14 -0
- package/dist/cache/cloudflare-kv-nonce-cache.js +93 -0
- package/dist/cache/dynamodb-nonce-cache.d.ts +15 -0
- package/dist/cache/dynamodb-nonce-cache.js +92 -0
- package/dist/cache/index.d.ts +16 -0
- package/dist/cache/index.js +32 -0
- package/dist/cache/memory-nonce-cache.d.ts +44 -0
- package/dist/cache/memory-nonce-cache.js +105 -0
- package/dist/cache/nonce-cache-factory.d.ts +20 -0
- package/dist/cache/nonce-cache-factory.js +208 -0
- package/dist/cache/redis-nonce-cache.d.ts +14 -0
- package/dist/cache/redis-nonce-cache.js +53 -0
- package/dist/compiler/compiler-context.d.ts +23 -0
- package/dist/compiler/compiler-context.js +24 -0
- package/dist/compiler/config/constants.d.ts +41 -0
- package/dist/compiler/config/constants.js +45 -0
- package/dist/compiler/config/index.d.ts +252 -0
- package/dist/compiler/config/index.js +15 -0
- package/dist/compiler/config/injection.d.ts +26 -0
- package/dist/compiler/config/injection.js +58 -0
- package/dist/compiler/config/schemas/experimental/index.d.ts +91 -0
- package/dist/compiler/config/schemas/experimental/index.js +16 -0
- package/dist/compiler/config/schemas/experimental/oauth.d.ts +74 -0
- package/dist/compiler/config/schemas/experimental/oauth.js +25 -0
- package/dist/compiler/config/schemas/index.d.ts +6 -0
- package/dist/compiler/config/schemas/index.js +17 -0
- package/dist/compiler/config/schemas/paths.d.ts +9 -0
- package/dist/compiler/config/schemas/paths.js +12 -0
- package/dist/compiler/config/schemas/transport/http.d.ts +82 -0
- package/dist/compiler/config/schemas/transport/http.js +33 -0
- package/dist/compiler/config/schemas/transport/stdio.d.ts +9 -0
- package/dist/compiler/config/schemas/transport/stdio.js +15 -0
- package/dist/compiler/config/schemas/webpack.d.ts +3 -0
- package/dist/compiler/config/schemas/webpack.js +15 -0
- package/dist/compiler/config/types.d.ts +1 -0
- package/dist/compiler/config/types.js +2 -0
- package/dist/compiler/config/utils.d.ts +20 -0
- package/dist/compiler/config/utils.js +36 -0
- package/dist/compiler/generate-env-code.d.ts +1 -0
- package/dist/compiler/generate-env-code.js +8 -0
- package/dist/compiler/generate-import-code.d.ts +1 -0
- package/dist/compiler/generate-import-code.js +24 -0
- package/dist/compiler/get-webpack-config/get-entries.d.ts +3 -0
- package/dist/compiler/get-webpack-config/get-entries.js +29 -0
- package/dist/compiler/get-webpack-config/get-externals.d.ts +7 -0
- package/dist/compiler/get-webpack-config/get-externals.js +88 -0
- package/dist/compiler/get-webpack-config/get-injected-variables.d.ts +8 -0
- package/dist/compiler/get-webpack-config/get-injected-variables.js +25 -0
- package/dist/compiler/get-webpack-config/index.d.ts +4 -0
- package/dist/compiler/get-webpack-config/index.js +101 -0
- package/dist/compiler/get-webpack-config/plugins.d.ts +8 -0
- package/dist/compiler/get-webpack-config/plugins.js +132 -0
- package/dist/compiler/get-webpack-config/resolve-tsconfig-paths.d.ts +9 -0
- package/dist/compiler/get-webpack-config/resolve-tsconfig-paths.js +40 -0
- package/dist/compiler/index.d.ts +6 -0
- package/dist/compiler/index.js +194 -0
- package/dist/compiler/on-first-build.d.ts +3 -0
- package/dist/compiler/on-first-build.js +58 -0
- package/dist/compiler/parse-xmcp-config.d.ts +9 -0
- package/dist/compiler/parse-xmcp-config.js +155 -0
- package/dist/compiler/start-http-server.d.ts +1 -0
- package/dist/compiler/start-http-server.js +34 -0
- package/dist/index.d.ts +12 -54
- package/dist/index.js +22 -190
- package/dist/index.js.LICENSE.txt +49 -0
- package/dist/runtime/__tests__/audit.test.d.ts +4 -0
- package/dist/runtime/__tests__/audit.test.js +328 -0
- package/dist/runtime/__tests__/identity.test.d.ts +4 -0
- package/dist/runtime/__tests__/identity.test.js +164 -0
- package/dist/runtime/__tests__/mcpi-runtime.test.d.ts +4 -0
- package/dist/runtime/__tests__/mcpi-runtime.test.js +372 -0
- package/dist/runtime/__tests__/proof.test.d.ts +4 -0
- package/dist/runtime/__tests__/proof.test.js +302 -0
- package/dist/runtime/__tests__/session.test.d.ts +4 -0
- package/dist/runtime/__tests__/session.test.js +254 -0
- package/dist/runtime/__tests__/well-known.test.d.ts +4 -0
- package/dist/runtime/__tests__/well-known.test.js +312 -0
- package/dist/runtime/adapter-express.js +2 -0
- package/dist/runtime/adapter-express.js.LICENSE.txt +252 -0
- package/dist/runtime/adapter-nextjs.js +2 -0
- package/dist/runtime/adapter-nextjs.js.LICENSE.txt +53 -0
- package/dist/runtime/adapters/express/index.d.ts +2 -0
- package/dist/runtime/adapters/express/index.js +48 -0
- package/dist/runtime/adapters/nextjs/index.d.ts +8 -0
- package/dist/runtime/adapters/nextjs/index.js +18 -0
- package/dist/runtime/audit.d.ts +93 -0
- package/dist/runtime/audit.js +212 -0
- package/dist/runtime/debug.d.ts +118 -0
- package/dist/runtime/debug.js +612 -0
- package/dist/runtime/delegation-hooks.d.ts +85 -0
- package/dist/runtime/delegation-hooks.js +116 -0
- package/dist/runtime/demo.d.ts +71 -0
- package/dist/runtime/demo.js +135 -0
- package/dist/runtime/headers.d.ts +1 -0
- package/dist/runtime/headers.js +9 -0
- package/dist/runtime/http.js +2 -0
- package/dist/runtime/http.js.LICENSE.txt +252 -0
- package/dist/runtime/identity.d.ts +105 -0
- package/dist/runtime/identity.js +232 -0
- package/dist/runtime/index.d.ts +16 -0
- package/dist/runtime/index.js +56 -0
- package/dist/runtime/mcpi-runtime.d.ts +164 -0
- package/dist/runtime/mcpi-runtime.js +352 -0
- package/dist/runtime/proof.d.ts +87 -0
- package/dist/runtime/proof.js +223 -0
- package/dist/runtime/session.d.ts +88 -0
- package/dist/runtime/session.js +216 -0
- package/dist/runtime/stdio.js +2 -0
- package/dist/runtime/stdio.js.LICENSE.txt +1 -0
- package/dist/runtime/templates/home.d.ts +2 -0
- package/dist/runtime/templates/home.js +50 -0
- package/dist/runtime/transports/http/base-streamable-http.d.ts +25 -0
- package/dist/runtime/transports/http/base-streamable-http.js +16 -0
- package/dist/runtime/transports/http/http-context.d.ts +9 -0
- package/dist/runtime/transports/http/http-context.js +8 -0
- package/dist/runtime/transports/http/index.d.ts +1 -0
- package/dist/runtime/transports/http/index.js +55 -0
- package/dist/runtime/transports/http/setup-cors.d.ts +4 -0
- package/dist/runtime/transports/http/setup-cors.js +24 -0
- package/dist/runtime/transports/http/stateless-streamable-http.d.ts +39 -0
- package/dist/runtime/transports/http/stateless-streamable-http.js +331 -0
- package/dist/runtime/transports/stdio/index.d.ts +1 -0
- package/dist/runtime/transports/stdio/index.js +51 -0
- package/dist/runtime/utils/server.d.ts +42 -0
- package/dist/runtime/utils/server.js +39 -0
- package/dist/runtime/utils/tools.d.ts +8 -0
- package/dist/runtime/utils/tools.js +115 -0
- package/dist/runtime/verifier-middleware.d.ts +76 -0
- package/dist/runtime/verifier-middleware.js +322 -0
- package/dist/runtime/well-known.d.ts +151 -0
- package/dist/runtime/well-known.js +258 -0
- package/dist/storage/config.d.ts +28 -0
- package/dist/storage/config.js +79 -0
- package/dist/storage/delegation.d.ts +59 -0
- package/dist/storage/delegation.js +130 -0
- package/dist/storage/merkle-verifier.d.ts +84 -0
- package/dist/storage/merkle-verifier.js +261 -0
- package/dist/test/__tests__/nonce-cache-integration.test.d.ts +1 -0
- package/dist/test/__tests__/nonce-cache-integration.test.js +116 -0
- package/dist/test/__tests__/nonce-cache.test.d.ts +1 -0
- package/dist/test/__tests__/nonce-cache.test.js +122 -0
- package/dist/test/__tests__/runtime-integration.test.d.ts +4 -0
- package/dist/test/__tests__/runtime-integration.test.js +192 -0
- package/dist/test/__tests__/test-infrastructure.test.d.ts +4 -0
- package/dist/test/__tests__/test-infrastructure.test.js +178 -0
- package/dist/test/deterministic-keys.d.ts +31 -0
- package/dist/test/deterministic-keys.js +108 -0
- package/dist/test/examples/test-usage-example.d.ts +140 -0
- package/dist/test/examples/test-usage-example.js +175 -0
- package/dist/test/index.d.ts +11 -0
- package/dist/test/index.js +27 -0
- package/dist/test/local-verification.d.ts +28 -0
- package/dist/test/local-verification.js +342 -0
- package/dist/test/mock-identity-provider.d.ts +96 -0
- package/dist/test/mock-identity-provider.js +243 -0
- package/dist/test/runtime-integration.d.ts +63 -0
- package/dist/test/runtime-integration.js +140 -0
- package/dist/test/test-environment.d.ts +26 -0
- package/dist/test/test-environment.js +50 -0
- package/dist/types/declarations.d.ts +1 -0
- package/dist/types/declarations.js +6 -0
- package/dist/types/middleware.d.ts +2 -0
- package/dist/types/middleware.js +2 -0
- package/dist/types/tool.d.ts +80 -0
- package/dist/types/tool.js +2 -0
- package/dist/utils/cli-icons.d.ts +3 -0
- package/dist/utils/cli-icons.js +7 -0
- package/dist/utils/constants.d.ts +6 -0
- package/dist/utils/constants.js +13 -0
- package/dist/utils/context.d.ts +33 -0
- package/dist/utils/context.js +58 -0
- package/dist/utils/file-watcher.d.ts +19 -0
- package/dist/utils/file-watcher.js +49 -0
- package/dist/utils/fs-utils.d.ts +2 -0
- package/dist/utils/fs-utils.js +22 -0
- package/dist/utils/path-validation.d.ts +3 -0
- package/dist/utils/path-validation.js +56 -0
- package/dist/utils/spawn-process.d.ts +9 -0
- package/dist/utils/spawn-process.js +50 -0
- package/dist/utils/subscribable.d.ts +12 -0
- package/dist/utils/subscribable.js +44 -0
- package/package.json +99 -21
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DefaultDelegationManager = void 0;
|
|
4
|
+
exports.createDelegationManager = createDelegationManager;
|
|
5
|
+
exports.extractDelegationContext = extractDelegationContext;
|
|
6
|
+
const config_1 = require("./config");
|
|
7
|
+
/**
|
|
8
|
+
* Default delegation manager implementation
|
|
9
|
+
*/
|
|
10
|
+
class DefaultDelegationManager {
|
|
11
|
+
config;
|
|
12
|
+
constructor(config) {
|
|
13
|
+
this.config = (0, config_1.createStorageConfig)(config);
|
|
14
|
+
}
|
|
15
|
+
async issue(request) {
|
|
16
|
+
// TODO: Replace with actual KTA delegation API call
|
|
17
|
+
// This is a placeholder implementation
|
|
18
|
+
const now = Math.floor(Date.now() / 1000);
|
|
19
|
+
const duration = request.duration || 3600; // Default 1 hour
|
|
20
|
+
const delegation = {
|
|
21
|
+
issuer: "did:web:example.com:issuer", // TODO: Get from identity
|
|
22
|
+
subject: request.subject,
|
|
23
|
+
scopes: request.scopes,
|
|
24
|
+
nbf: now,
|
|
25
|
+
exp: now + duration,
|
|
26
|
+
aud: request.audience,
|
|
27
|
+
};
|
|
28
|
+
// Mock receipt
|
|
29
|
+
const receipt = {
|
|
30
|
+
$schema: "https://schemas.kya-os.ai/mcpi/receipt/v1.0.0.json",
|
|
31
|
+
ref: `del_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
|
|
32
|
+
contentHash: `sha256:${Array.from({ length: 64 }, () => Math.floor(Math.random() * 16).toString(16)).join("")}`,
|
|
33
|
+
action: "issue",
|
|
34
|
+
ts: now,
|
|
35
|
+
logIndex: Math.floor(Math.random() * 10000),
|
|
36
|
+
logRoot: Array.from({ length: 64 }, () => Math.floor(Math.random() * 16).toString(16)).join(""),
|
|
37
|
+
inclusionProof: [
|
|
38
|
+
Array.from({ length: 64 }, () => Math.floor(Math.random() * 16).toString(16)).join(""),
|
|
39
|
+
],
|
|
40
|
+
};
|
|
41
|
+
const response = {
|
|
42
|
+
delegation,
|
|
43
|
+
receipt,
|
|
44
|
+
};
|
|
45
|
+
// Add encrypted payload for ktaEncrypted mode
|
|
46
|
+
if (this.config.mode === "ktaEncrypted" && this.config.encryptionEnabled) {
|
|
47
|
+
response.encryptedPayload = await this.encryptDelegation(delegation, request.audience);
|
|
48
|
+
}
|
|
49
|
+
return response;
|
|
50
|
+
}
|
|
51
|
+
async revoke(_delegationRef) {
|
|
52
|
+
// TODO: Replace with actual KTA revocation API call
|
|
53
|
+
// This is a placeholder implementation
|
|
54
|
+
const receipt = {
|
|
55
|
+
$schema: "https://schemas.kya-os.ai/mcpi/receipt/v1.0.0.json",
|
|
56
|
+
ref: `rev_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
|
|
57
|
+
contentHash: `sha256:${Array.from({ length: 64 }, () => Math.floor(Math.random() * 16).toString(16)).join("")}`,
|
|
58
|
+
action: "revoke",
|
|
59
|
+
ts: Math.floor(Date.now() / 1000),
|
|
60
|
+
logIndex: Math.floor(Math.random() * 10000),
|
|
61
|
+
logRoot: Array.from({ length: 64 }, () => Math.floor(Math.random() * 16).toString(16)).join(""),
|
|
62
|
+
inclusionProof: [
|
|
63
|
+
Array.from({ length: 64 }, () => Math.floor(Math.random() * 16).toString(16)).join(""),
|
|
64
|
+
],
|
|
65
|
+
};
|
|
66
|
+
return receipt;
|
|
67
|
+
}
|
|
68
|
+
async isActive(delegationRef) {
|
|
69
|
+
// TODO: Replace with actual KTA status check
|
|
70
|
+
// This is a placeholder implementation
|
|
71
|
+
// Mock: assume delegation is active if ref looks valid
|
|
72
|
+
return delegationRef.startsWith("del_") && delegationRef.length > 10;
|
|
73
|
+
}
|
|
74
|
+
async get(delegationRef) {
|
|
75
|
+
// TODO: Replace with actual KTA lookup
|
|
76
|
+
// This is a placeholder implementation
|
|
77
|
+
if (!(await this.isActive(delegationRef))) {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
// Mock delegation
|
|
81
|
+
const now = Math.floor(Date.now() / 1000);
|
|
82
|
+
return {
|
|
83
|
+
issuer: "did:web:example.com:issuer",
|
|
84
|
+
subject: "did:web:example.com:subject",
|
|
85
|
+
scopes: ["read", "write"],
|
|
86
|
+
nbf: now - 3600,
|
|
87
|
+
exp: now + 3600,
|
|
88
|
+
delegationRef,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
async listBySubject(_subject) {
|
|
92
|
+
// TODO: Replace with actual KTA query
|
|
93
|
+
// This is a placeholder implementation
|
|
94
|
+
// Mock: return empty list for now
|
|
95
|
+
return [];
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Encrypt delegation payload for audience
|
|
99
|
+
*/
|
|
100
|
+
async encryptDelegation(delegation, _audience) {
|
|
101
|
+
// TODO: Implement actual audience-key encryption
|
|
102
|
+
// This is a placeholder implementation
|
|
103
|
+
const payload = JSON.stringify(delegation);
|
|
104
|
+
// Mock encryption: base64 encode for now
|
|
105
|
+
// In real implementation, this would use the audience's public key
|
|
106
|
+
return Buffer.from(payload).toString("base64");
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
exports.DefaultDelegationManager = DefaultDelegationManager;
|
|
110
|
+
/**
|
|
111
|
+
* Create delegation manager instance
|
|
112
|
+
*/
|
|
113
|
+
function createDelegationManager(config) {
|
|
114
|
+
return new DefaultDelegationManager(config);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Extract delegation context from proof metadata
|
|
118
|
+
*/
|
|
119
|
+
function extractDelegationContext(delegationRef) {
|
|
120
|
+
if (!delegationRef) {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
// TODO: Parse delegation reference and extract context
|
|
124
|
+
// This is a placeholder implementation
|
|
125
|
+
return {
|
|
126
|
+
delegationRef,
|
|
127
|
+
scopes: ["read", "write"], // Mock scopes
|
|
128
|
+
expiresAt: Date.now() + 3600000, // Mock expiry (1 hour from now)
|
|
129
|
+
};
|
|
130
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { Receipt } from "@kya-os/contracts/registry";
|
|
2
|
+
/**
|
|
3
|
+
* Merkle log verifier for receipt verification
|
|
4
|
+
*/
|
|
5
|
+
export interface MerkleProofNode {
|
|
6
|
+
hash: string;
|
|
7
|
+
isLeft: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface LogRoot {
|
|
10
|
+
root: string;
|
|
11
|
+
size: number;
|
|
12
|
+
timestamp: number;
|
|
13
|
+
}
|
|
14
|
+
export interface VerificationResult {
|
|
15
|
+
valid: boolean;
|
|
16
|
+
error?: string;
|
|
17
|
+
logRoot?: LogRoot;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Merkle log verifier implementation
|
|
21
|
+
*/
|
|
22
|
+
export declare class MerkleLogVerifier {
|
|
23
|
+
/**
|
|
24
|
+
* Verify a receipt's inclusion proof against a log root
|
|
25
|
+
*/
|
|
26
|
+
static verifyInclusion(receipt: Receipt, logRoot: LogRoot): Promise<VerificationResult>;
|
|
27
|
+
/**
|
|
28
|
+
* Compute leaf hash from receipt content
|
|
29
|
+
*/
|
|
30
|
+
private static computeLeafHash;
|
|
31
|
+
/**
|
|
32
|
+
* Compute root hash from inclusion proof
|
|
33
|
+
*/
|
|
34
|
+
private static computeRootFromProof;
|
|
35
|
+
/**
|
|
36
|
+
* Hash a pair of nodes
|
|
37
|
+
*/
|
|
38
|
+
private static hashPair;
|
|
39
|
+
/**
|
|
40
|
+
* Verify consistency between two log roots
|
|
41
|
+
*/
|
|
42
|
+
static verifyConsistency(oldRoot: LogRoot, newRoot: LogRoot, consistencyProof: string[]): Promise<VerificationResult>;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Receipt verifier with policy controls
|
|
46
|
+
*/
|
|
47
|
+
export declare class ReceiptVerifier {
|
|
48
|
+
private options;
|
|
49
|
+
constructor(options?: ReceiptVerifierOptions);
|
|
50
|
+
/**
|
|
51
|
+
* Verify a receipt against KTA log
|
|
52
|
+
*/
|
|
53
|
+
verify(receipt: Receipt): Promise<VerificationResult>;
|
|
54
|
+
/**
|
|
55
|
+
* Batch verify multiple receipts
|
|
56
|
+
*/
|
|
57
|
+
verifyBatch(receipts: Receipt[]): Promise<VerificationResult[]>;
|
|
58
|
+
/**
|
|
59
|
+
* Fetch current log root from KTA
|
|
60
|
+
*/
|
|
61
|
+
private fetchLogRoot;
|
|
62
|
+
}
|
|
63
|
+
export interface ReceiptVerifierOptions {
|
|
64
|
+
/**
|
|
65
|
+
* Enable receipt verification
|
|
66
|
+
*/
|
|
67
|
+
enabled?: boolean;
|
|
68
|
+
/**
|
|
69
|
+
* KTA base URL
|
|
70
|
+
*/
|
|
71
|
+
ktaBaseUrl?: string;
|
|
72
|
+
/**
|
|
73
|
+
* Allow mock data for testing
|
|
74
|
+
*/
|
|
75
|
+
allowMockData?: boolean;
|
|
76
|
+
/**
|
|
77
|
+
* Cache log root for this duration (seconds)
|
|
78
|
+
*/
|
|
79
|
+
cacheLogRootTtl?: number;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Create receipt verifier instance
|
|
83
|
+
*/
|
|
84
|
+
export declare function createReceiptVerifier(options?: ReceiptVerifierOptions): ReceiptVerifier;
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ReceiptVerifier = exports.MerkleLogVerifier = void 0;
|
|
4
|
+
exports.createReceiptVerifier = createReceiptVerifier;
|
|
5
|
+
const crypto_1 = require("crypto");
|
|
6
|
+
/**
|
|
7
|
+
* Merkle log verifier implementation
|
|
8
|
+
*/
|
|
9
|
+
class MerkleLogVerifier {
|
|
10
|
+
/**
|
|
11
|
+
* Verify a receipt's inclusion proof against a log root
|
|
12
|
+
*/
|
|
13
|
+
static async verifyInclusion(receipt, logRoot) {
|
|
14
|
+
try {
|
|
15
|
+
// Validate receipt format
|
|
16
|
+
if (!receipt.inclusionProof || !Array.isArray(receipt.inclusionProof)) {
|
|
17
|
+
return {
|
|
18
|
+
valid: false,
|
|
19
|
+
error: "Invalid inclusion proof format",
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
if (receipt.logIndex < 0 || receipt.logIndex >= logRoot.size) {
|
|
23
|
+
return {
|
|
24
|
+
valid: false,
|
|
25
|
+
error: `Log index ${receipt.logIndex} out of bounds for log size ${logRoot.size}`,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
// Compute leaf hash from receipt content
|
|
29
|
+
const leafHash = await this.computeLeafHash(receipt);
|
|
30
|
+
// Verify inclusion proof
|
|
31
|
+
const computedRoot = await this.computeRootFromProof(leafHash, receipt.logIndex, receipt.inclusionProof);
|
|
32
|
+
const isValid = computedRoot === logRoot.root;
|
|
33
|
+
return {
|
|
34
|
+
valid: isValid,
|
|
35
|
+
error: isValid ? undefined : "Inclusion proof verification failed",
|
|
36
|
+
logRoot,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
return {
|
|
41
|
+
valid: false,
|
|
42
|
+
error: error instanceof Error ? error.message : "Verification failed",
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Compute leaf hash from receipt content
|
|
48
|
+
*/
|
|
49
|
+
static async computeLeafHash(receipt) {
|
|
50
|
+
// Create canonical representation of receipt for hashing
|
|
51
|
+
const canonical = {
|
|
52
|
+
ref: receipt.ref,
|
|
53
|
+
contentHash: receipt.contentHash,
|
|
54
|
+
action: receipt.action,
|
|
55
|
+
ts: receipt.ts,
|
|
56
|
+
};
|
|
57
|
+
const encoder = new TextEncoder();
|
|
58
|
+
const data = encoder.encode(JSON.stringify(canonical));
|
|
59
|
+
const hashBuffer = await crypto_1.webcrypto.subtle.digest("SHA-256", data);
|
|
60
|
+
const hashArray = new Uint8Array(hashBuffer);
|
|
61
|
+
return Array.from(hashArray)
|
|
62
|
+
.map((b) => b.toString(16).padStart(2, "0"))
|
|
63
|
+
.join("");
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Compute root hash from inclusion proof
|
|
67
|
+
*/
|
|
68
|
+
static async computeRootFromProof(leafHash, leafIndex, proof) {
|
|
69
|
+
let currentHash = leafHash;
|
|
70
|
+
let currentIndex = leafIndex;
|
|
71
|
+
for (const proofHash of proof) {
|
|
72
|
+
// Determine if current node is left or right child
|
|
73
|
+
const isLeftChild = currentIndex % 2 === 0;
|
|
74
|
+
if (isLeftChild) {
|
|
75
|
+
// Current node is left child, proof hash is right sibling
|
|
76
|
+
currentHash = await this.hashPair(currentHash, proofHash);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
// Current node is right child, proof hash is left sibling
|
|
80
|
+
currentHash = await this.hashPair(proofHash, currentHash);
|
|
81
|
+
}
|
|
82
|
+
// Move up to parent level
|
|
83
|
+
currentIndex = Math.floor(currentIndex / 2);
|
|
84
|
+
}
|
|
85
|
+
return currentHash;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Hash a pair of nodes
|
|
89
|
+
*/
|
|
90
|
+
static async hashPair(left, right) {
|
|
91
|
+
const encoder = new TextEncoder();
|
|
92
|
+
const data = encoder.encode(left + right);
|
|
93
|
+
const hashBuffer = await crypto_1.webcrypto.subtle.digest("SHA-256", data);
|
|
94
|
+
const hashArray = new Uint8Array(hashBuffer);
|
|
95
|
+
return Array.from(hashArray)
|
|
96
|
+
.map((b) => b.toString(16).padStart(2, "0"))
|
|
97
|
+
.join("");
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Verify consistency between two log roots
|
|
101
|
+
*/
|
|
102
|
+
static async verifyConsistency(oldRoot, newRoot, consistencyProof) {
|
|
103
|
+
try {
|
|
104
|
+
if (oldRoot.size > newRoot.size) {
|
|
105
|
+
return {
|
|
106
|
+
valid: false,
|
|
107
|
+
error: "Old log size cannot be greater than new log size",
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
if (oldRoot.size === newRoot.size) {
|
|
111
|
+
// Same size, roots should be identical
|
|
112
|
+
return {
|
|
113
|
+
valid: oldRoot.root === newRoot.root,
|
|
114
|
+
error: oldRoot.root === newRoot.root
|
|
115
|
+
? undefined
|
|
116
|
+
: "Roots don't match for same size logs",
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
// TODO: Implement full consistency proof verification
|
|
120
|
+
// This is a simplified version for demonstration
|
|
121
|
+
const isValid = consistencyProof.length > 0 && oldRoot.timestamp <= newRoot.timestamp;
|
|
122
|
+
return {
|
|
123
|
+
valid: isValid,
|
|
124
|
+
error: isValid ? undefined : "Consistency proof verification failed",
|
|
125
|
+
logRoot: newRoot,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
return {
|
|
130
|
+
valid: false,
|
|
131
|
+
error: error instanceof Error
|
|
132
|
+
? error.message
|
|
133
|
+
: "Consistency verification failed",
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
exports.MerkleLogVerifier = MerkleLogVerifier;
|
|
139
|
+
/**
|
|
140
|
+
* Receipt verifier with policy controls
|
|
141
|
+
*/
|
|
142
|
+
class ReceiptVerifier {
|
|
143
|
+
options;
|
|
144
|
+
constructor(options = {}) {
|
|
145
|
+
this.options = options;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Verify a receipt against KTA log
|
|
149
|
+
*/
|
|
150
|
+
async verify(receipt) {
|
|
151
|
+
try {
|
|
152
|
+
// Skip verification if disabled
|
|
153
|
+
if (!this.options.enabled) {
|
|
154
|
+
return {
|
|
155
|
+
valid: true,
|
|
156
|
+
error: "Receipt verification disabled",
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
// Fetch current log root from KTA
|
|
160
|
+
const logRoot = await this.fetchLogRoot();
|
|
161
|
+
if (!logRoot) {
|
|
162
|
+
return {
|
|
163
|
+
valid: false,
|
|
164
|
+
error: "Failed to fetch log root from KTA",
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
// Verify inclusion proof
|
|
168
|
+
return await MerkleLogVerifier.verifyInclusion(receipt, logRoot);
|
|
169
|
+
}
|
|
170
|
+
catch (error) {
|
|
171
|
+
return {
|
|
172
|
+
valid: false,
|
|
173
|
+
error: error instanceof Error
|
|
174
|
+
? error.message
|
|
175
|
+
: "Receipt verification failed",
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Batch verify multiple receipts
|
|
181
|
+
*/
|
|
182
|
+
async verifyBatch(receipts) {
|
|
183
|
+
const results = [];
|
|
184
|
+
// Fetch log root once for all receipts
|
|
185
|
+
const logRoot = this.options.enabled ? await this.fetchLogRoot() : null;
|
|
186
|
+
for (const receipt of receipts) {
|
|
187
|
+
if (!this.options.enabled) {
|
|
188
|
+
results.push({
|
|
189
|
+
valid: true,
|
|
190
|
+
error: "Receipt verification disabled",
|
|
191
|
+
});
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
if (!logRoot) {
|
|
195
|
+
results.push({
|
|
196
|
+
valid: false,
|
|
197
|
+
error: "Failed to fetch log root from KTA",
|
|
198
|
+
});
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
try {
|
|
202
|
+
const result = await MerkleLogVerifier.verifyInclusion(receipt, logRoot);
|
|
203
|
+
results.push(result);
|
|
204
|
+
}
|
|
205
|
+
catch (error) {
|
|
206
|
+
results.push({
|
|
207
|
+
valid: false,
|
|
208
|
+
error: error instanceof Error
|
|
209
|
+
? error.message
|
|
210
|
+
: "Receipt verification failed",
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return results;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Fetch current log root from KTA
|
|
218
|
+
*/
|
|
219
|
+
async fetchLogRoot() {
|
|
220
|
+
try {
|
|
221
|
+
// TODO: Replace with actual KTA API call
|
|
222
|
+
// This is a placeholder implementation
|
|
223
|
+
const ktaUrl = this.options.ktaBaseUrl || "https://knowthat.ai";
|
|
224
|
+
const response = await fetch(`${ktaUrl}/api/log/root`);
|
|
225
|
+
if (!response.ok) {
|
|
226
|
+
throw new Error(`KTA API error: ${response.status}`);
|
|
227
|
+
}
|
|
228
|
+
const data = await response.json();
|
|
229
|
+
return {
|
|
230
|
+
root: data.root,
|
|
231
|
+
size: data.size,
|
|
232
|
+
timestamp: data.timestamp,
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
catch (error) {
|
|
236
|
+
// In case of network error, return mock data for testing
|
|
237
|
+
if (this.options.allowMockData) {
|
|
238
|
+
return {
|
|
239
|
+
root: Array.from({ length: 64 }, () => Math.floor(Math.random() * 16).toString(16)).join(""),
|
|
240
|
+
size: 10000,
|
|
241
|
+
timestamp: Math.floor(Date.now() / 1000),
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
console.warn("Failed to fetch log root from KTA:", error);
|
|
245
|
+
return null;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
exports.ReceiptVerifier = ReceiptVerifier;
|
|
250
|
+
/**
|
|
251
|
+
* Create receipt verifier instance
|
|
252
|
+
*/
|
|
253
|
+
function createReceiptVerifier(options) {
|
|
254
|
+
return new ReceiptVerifier({
|
|
255
|
+
enabled: true,
|
|
256
|
+
ktaBaseUrl: "https://knowthat.ai",
|
|
257
|
+
allowMockData: false,
|
|
258
|
+
cacheLogRootTtl: 300, // 5 minutes
|
|
259
|
+
...options,
|
|
260
|
+
});
|
|
261
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const index_js_1 = require("../../cache/index.js");
|
|
5
|
+
/**
|
|
6
|
+
* Integration tests showing how nonce cache would be used in session management
|
|
7
|
+
*/
|
|
8
|
+
(0, vitest_1.describe)("Nonce Cache Integration", () => {
|
|
9
|
+
let cache;
|
|
10
|
+
(0, vitest_1.beforeEach)(async () => {
|
|
11
|
+
cache = await (0, index_js_1.createNonceCache)();
|
|
12
|
+
});
|
|
13
|
+
(0, vitest_1.describe)("Session Management Integration", () => {
|
|
14
|
+
class MockSessionManager {
|
|
15
|
+
nonceCache;
|
|
16
|
+
constructor(nonceCache) {
|
|
17
|
+
this.nonceCache = nonceCache;
|
|
18
|
+
}
|
|
19
|
+
async validateHandshake(nonce, sessionTtl) {
|
|
20
|
+
// Check for replay attack
|
|
21
|
+
if (await this.nonceCache.has(nonce)) {
|
|
22
|
+
throw new Error("XMCP_I_EHANDSHAKE: Nonce already used - potential replay attack");
|
|
23
|
+
}
|
|
24
|
+
// Add nonce with session TTL to prevent replay
|
|
25
|
+
await this.nonceCache.add(nonce, sessionTtl);
|
|
26
|
+
}
|
|
27
|
+
async isNonceUsed(nonce) {
|
|
28
|
+
return await this.nonceCache.has(nonce);
|
|
29
|
+
}
|
|
30
|
+
async cleanup() {
|
|
31
|
+
await this.nonceCache.cleanup();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
(0, vitest_1.it)("should prevent replay attacks in session management", async () => {
|
|
35
|
+
const sessionManager = new MockSessionManager(cache);
|
|
36
|
+
const nonce = "test-nonce-123";
|
|
37
|
+
const sessionTtl = 1800; // 30 minutes
|
|
38
|
+
// First handshake should succeed
|
|
39
|
+
await (0, vitest_1.expect)(sessionManager.validateHandshake(nonce, sessionTtl)).resolves.not.toThrow();
|
|
40
|
+
// Verify nonce is now marked as used
|
|
41
|
+
(0, vitest_1.expect)(await sessionManager.isNonceUsed(nonce)).toBe(true);
|
|
42
|
+
// Second handshake with same nonce should fail (replay attack)
|
|
43
|
+
await (0, vitest_1.expect)(sessionManager.validateHandshake(nonce, sessionTtl)).rejects.toThrow("potential replay attack");
|
|
44
|
+
});
|
|
45
|
+
(0, vitest_1.it)("should handle sequential nonce validation attempts", async () => {
|
|
46
|
+
const sessionManager = new MockSessionManager(cache);
|
|
47
|
+
const nonce = "sequential-nonce";
|
|
48
|
+
const sessionTtl = 1800;
|
|
49
|
+
// First attempt should succeed
|
|
50
|
+
await (0, vitest_1.expect)(sessionManager.validateHandshake(nonce, sessionTtl)).resolves.not.toThrow();
|
|
51
|
+
// Subsequent attempts should fail (replay attack)
|
|
52
|
+
await (0, vitest_1.expect)(sessionManager.validateHandshake(nonce, sessionTtl)).rejects.toThrow("potential replay attack");
|
|
53
|
+
await (0, vitest_1.expect)(sessionManager.validateHandshake(nonce, sessionTtl)).rejects.toThrow("potential replay attack");
|
|
54
|
+
});
|
|
55
|
+
(0, vitest_1.it)("should allow different nonces in the same session window", async () => {
|
|
56
|
+
const sessionManager = new MockSessionManager(cache);
|
|
57
|
+
const sessionTtl = 1800;
|
|
58
|
+
// Different nonces should all be allowed
|
|
59
|
+
const nonces = ["nonce-1", "nonce-2", "nonce-3"];
|
|
60
|
+
for (const nonce of nonces) {
|
|
61
|
+
await (0, vitest_1.expect)(sessionManager.validateHandshake(nonce, sessionTtl)).resolves.not.toThrow();
|
|
62
|
+
}
|
|
63
|
+
// All nonces should be marked as used
|
|
64
|
+
for (const nonce of nonces) {
|
|
65
|
+
(0, vitest_1.expect)(await sessionManager.isNonceUsed(nonce)).toBe(true);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
(0, vitest_1.it)("should handle nonce expiry correctly", async () => {
|
|
69
|
+
const sessionManager = new MockSessionManager(cache);
|
|
70
|
+
const nonce = "expiring-nonce";
|
|
71
|
+
const shortTtl = 0.1; // 0.1 seconds
|
|
72
|
+
// Add nonce with short TTL
|
|
73
|
+
await sessionManager.validateHandshake(nonce, shortTtl);
|
|
74
|
+
// Should be marked as used immediately
|
|
75
|
+
(0, vitest_1.expect)(await sessionManager.isNonceUsed(nonce)).toBe(true);
|
|
76
|
+
// Wait for expiry
|
|
77
|
+
await new Promise((resolve) => setTimeout(resolve, 150));
|
|
78
|
+
// Should no longer be marked as used after expiry
|
|
79
|
+
(0, vitest_1.expect)(await sessionManager.isNonceUsed(nonce)).toBe(false);
|
|
80
|
+
// Should be able to use the same nonce again after expiry
|
|
81
|
+
await (0, vitest_1.expect)(sessionManager.validateHandshake(nonce, shortTtl)).resolves.not.toThrow();
|
|
82
|
+
});
|
|
83
|
+
(0, vitest_1.it)("should handle cleanup operations safely", async () => {
|
|
84
|
+
const sessionManager = new MockSessionManager(cache);
|
|
85
|
+
// Add some nonces with different TTLs
|
|
86
|
+
await sessionManager.validateHandshake("long-lived", 3600);
|
|
87
|
+
await sessionManager.validateHandshake("short-lived", 0.1);
|
|
88
|
+
// Wait for short-lived to expire
|
|
89
|
+
await new Promise((resolve) => setTimeout(resolve, 150));
|
|
90
|
+
// Cleanup should not throw
|
|
91
|
+
await (0, vitest_1.expect)(sessionManager.cleanup()).resolves.not.toThrow();
|
|
92
|
+
// Long-lived should still exist, short-lived should be gone
|
|
93
|
+
(0, vitest_1.expect)(await sessionManager.isNonceUsed("long-lived")).toBe(true);
|
|
94
|
+
(0, vitest_1.expect)(await sessionManager.isNonceUsed("short-lived")).toBe(false);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
(0, vitest_1.describe)("Error Handling Integration", () => {
|
|
98
|
+
(0, vitest_1.it)("should provide structured error messages for replay attacks", async () => {
|
|
99
|
+
const nonce = "error-test-nonce";
|
|
100
|
+
await cache.add(nonce, 60);
|
|
101
|
+
try {
|
|
102
|
+
await cache.add(nonce, 60);
|
|
103
|
+
vitest_1.expect.fail("Should have thrown an error");
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
(0, vitest_1.expect)(error.message).toContain("Nonce error-test-nonce already exists");
|
|
107
|
+
(0, vitest_1.expect)(error.message).toContain("potential replay attack");
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
(0, vitest_1.it)("should handle cache backend failures gracefully", async () => {
|
|
111
|
+
// This test verifies that the factory falls back to memory cache
|
|
112
|
+
// when other backends fail (already tested in the factory tests)
|
|
113
|
+
(0, vitest_1.expect)(cache).toBeInstanceOf(index_js_1.MemoryNonceCache);
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|