@kya-os/verifier 1.3.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 +265 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/core.js +678 -0
- package/dist/core.js.map +1 -0
- package/dist/express.d.ts.map +1 -0
- package/dist/express.js +204 -0
- package/dist/express.js.map +1 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +103 -0
- package/dist/index.js.map +1 -0
- package/dist/worker.d.ts +160 -0
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +237 -0
- package/dist/worker.js.map +1 -0
- package/package.json +66 -0
package/dist/worker.js
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import { VerifierCore } from "./core.js";
|
|
2
|
+
/**
|
|
3
|
+
* Extract proof from Cloudflare Worker request
|
|
4
|
+
*/
|
|
5
|
+
async function extractProofFromRequest(request) {
|
|
6
|
+
try {
|
|
7
|
+
// Try to get proof from X-XMCP-I-Proof header
|
|
8
|
+
const proofHeader = request.headers.get("X-XMCP-I-Proof");
|
|
9
|
+
if (proofHeader) {
|
|
10
|
+
return JSON.parse(proofHeader);
|
|
11
|
+
}
|
|
12
|
+
// Try to get proof from request body if it's a POST/PUT
|
|
13
|
+
if (request.method === "POST" || request.method === "PUT") {
|
|
14
|
+
const contentType = request.headers.get("content-type");
|
|
15
|
+
if (contentType?.includes("application/json")) {
|
|
16
|
+
const body = (await request.clone().json());
|
|
17
|
+
if (body?.meta?.proof) {
|
|
18
|
+
return body.meta.proof;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
console.warn("Failed to extract proof from request:", error);
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Extract audience from request
|
|
31
|
+
*/
|
|
32
|
+
function extractAudienceFromRequest(request) {
|
|
33
|
+
const url = new URL(request.url);
|
|
34
|
+
return url.host;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Create verifier config from Worker environment
|
|
38
|
+
*
|
|
39
|
+
* @param env - Worker environment bindings
|
|
40
|
+
* @param overrides - Optional config overrides
|
|
41
|
+
* @returns WorkerVerifierConfig
|
|
42
|
+
*/
|
|
43
|
+
export function createConfigFromEnv(env, overrides) {
|
|
44
|
+
return {
|
|
45
|
+
ktaBaseUrl: env.KYA_API_URL || "https://knowthat.ai",
|
|
46
|
+
enableDelegationCheck: true,
|
|
47
|
+
clockSkewTolerance: env.XMCP_I_TS_SKEW_SEC
|
|
48
|
+
? parseInt(env.XMCP_I_TS_SKEW_SEC, 10)
|
|
49
|
+
: 120,
|
|
50
|
+
sessionTimeout: env.XMCP_I_SESSION_TTL
|
|
51
|
+
? parseInt(env.XMCP_I_SESSION_TTL, 10)
|
|
52
|
+
: 1800,
|
|
53
|
+
kvNamespace: env.NONCE_CACHE,
|
|
54
|
+
nonceTtl: 1800,
|
|
55
|
+
...overrides,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Cloudflare Worker verifier function
|
|
60
|
+
*
|
|
61
|
+
* Usage with environment bindings:
|
|
62
|
+
* ```typescript
|
|
63
|
+
* export default {
|
|
64
|
+
* async fetch(request: Request, env: WorkerEnv): Promise<Response> {
|
|
65
|
+
* const config = createConfigFromEnv(env);
|
|
66
|
+
* const result = await verifyWorker(request, config);
|
|
67
|
+
*
|
|
68
|
+
* if (!result.success) {
|
|
69
|
+
* return applyVerificationToResponse(result);
|
|
70
|
+
* }
|
|
71
|
+
*
|
|
72
|
+
* // Continue with verified request...
|
|
73
|
+
* }
|
|
74
|
+
* }
|
|
75
|
+
* ```
|
|
76
|
+
*
|
|
77
|
+
* @param request - The incoming request
|
|
78
|
+
* @param config - Optional verifier configuration
|
|
79
|
+
* @returns Promise<VerifierResult> - Verification result with headers or error
|
|
80
|
+
*/
|
|
81
|
+
export async function verifyWorker(request, config) {
|
|
82
|
+
try {
|
|
83
|
+
// Extract proof from request
|
|
84
|
+
const proof = await extractProofFromRequest(request);
|
|
85
|
+
if (!proof) {
|
|
86
|
+
return {
|
|
87
|
+
success: false,
|
|
88
|
+
error: {
|
|
89
|
+
code: "XMCP_I_ENOIDENTITY",
|
|
90
|
+
message: "No proof found in request",
|
|
91
|
+
httpStatus: 401,
|
|
92
|
+
details: {
|
|
93
|
+
reason: "Request must include proof in X-XMCP-I-Proof header or request body",
|
|
94
|
+
remediation: "Ensure XMCP-I client is properly configured",
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
// Extract audience from request
|
|
100
|
+
const audience = extractAudienceFromRequest(request);
|
|
101
|
+
// Create verifier and verify proof
|
|
102
|
+
const verifier = new VerifierCore(config);
|
|
103
|
+
const result = await verifier.verify({
|
|
104
|
+
proof,
|
|
105
|
+
audience,
|
|
106
|
+
timestamp: Math.floor(Date.now() / 1000),
|
|
107
|
+
});
|
|
108
|
+
return result;
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
return {
|
|
112
|
+
success: false,
|
|
113
|
+
error: {
|
|
114
|
+
code: "XMCP_I_EVERIFY",
|
|
115
|
+
message: error instanceof Error ? error.message : "Verification failed",
|
|
116
|
+
httpStatus: 500,
|
|
117
|
+
details: {
|
|
118
|
+
reason: "Unexpected error during Worker verification",
|
|
119
|
+
remediation: "Check request format and try again",
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Cloudflare Worker middleware factory
|
|
127
|
+
*
|
|
128
|
+
* Creates a middleware function that can be used in Worker request handlers
|
|
129
|
+
*
|
|
130
|
+
* @param config - Optional verifier configuration
|
|
131
|
+
* @returns Middleware function
|
|
132
|
+
*/
|
|
133
|
+
export function createWorkerMiddleware(config) {
|
|
134
|
+
return async (request) => {
|
|
135
|
+
return verifyWorker(request, config);
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Helper to apply verification result to a Response
|
|
140
|
+
*
|
|
141
|
+
* @param result - Verification result
|
|
142
|
+
* @param response - Response to modify
|
|
143
|
+
* @returns Modified response with headers or error response
|
|
144
|
+
*/
|
|
145
|
+
export function applyVerificationToResponse(result, response) {
|
|
146
|
+
if (!result.success) {
|
|
147
|
+
return new Response(JSON.stringify({
|
|
148
|
+
code: result.error.code,
|
|
149
|
+
message: result.error.message,
|
|
150
|
+
details: result.error.details,
|
|
151
|
+
}), {
|
|
152
|
+
status: result.error.httpStatus,
|
|
153
|
+
headers: {
|
|
154
|
+
"Content-Type": "application/json",
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
// Apply headers to existing response or create new one
|
|
159
|
+
const headers = new Headers(response?.headers);
|
|
160
|
+
if (result.headers) {
|
|
161
|
+
Object.entries(result.headers).forEach(([key, value]) => {
|
|
162
|
+
headers.set(key, value);
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
if (response) {
|
|
166
|
+
return new Response(response.body, {
|
|
167
|
+
status: response.status,
|
|
168
|
+
statusText: response.statusText,
|
|
169
|
+
headers,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
return new Response(null, { status: 200, headers });
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Complete example with environment bindings and KV nonce cache
|
|
176
|
+
*
|
|
177
|
+
* wrangler.toml:
|
|
178
|
+
* ```toml
|
|
179
|
+
* name = "my-mcp-verifier"
|
|
180
|
+
* main = "src/index.ts"
|
|
181
|
+
* compatibility_date = "2024-01-01"
|
|
182
|
+
*
|
|
183
|
+
* [[kv_namespaces]]
|
|
184
|
+
* binding = "NONCE_CACHE"
|
|
185
|
+
* id = "your-kv-namespace-id"
|
|
186
|
+
*
|
|
187
|
+
* [vars]
|
|
188
|
+
* KYA_API_URL = "https://knowthat.ai"
|
|
189
|
+
* ```
|
|
190
|
+
*
|
|
191
|
+
* src/index.ts:
|
|
192
|
+
* ```typescript
|
|
193
|
+
* import { verifyWorker, applyVerificationToResponse, createConfigFromEnv, type WorkerEnv } from "@kya-os/verifier/worker";
|
|
194
|
+
*
|
|
195
|
+
* export default {
|
|
196
|
+
* async fetch(request: Request, env: WorkerEnv): Promise<Response> {
|
|
197
|
+
* // Create config from environment
|
|
198
|
+
* const config = createConfigFromEnv(env);
|
|
199
|
+
*
|
|
200
|
+
* // Verify the request
|
|
201
|
+
* const result = await verifyWorker(request, config);
|
|
202
|
+
*
|
|
203
|
+
* if (!result.success) {
|
|
204
|
+
* return applyVerificationToResponse(result);
|
|
205
|
+
* }
|
|
206
|
+
*
|
|
207
|
+
* // Access verified agent context
|
|
208
|
+
* const agentDID = result.agentContext?.did;
|
|
209
|
+
* const agentScopes = result.agentContext?.scopes || [];
|
|
210
|
+
*
|
|
211
|
+
* // Continue with verified request
|
|
212
|
+
* const response = new Response(JSON.stringify({
|
|
213
|
+
* message: "Verified!",
|
|
214
|
+
* agent: result.agentContext
|
|
215
|
+
* }), {
|
|
216
|
+
* headers: { "Content-Type": "application/json" }
|
|
217
|
+
* });
|
|
218
|
+
*
|
|
219
|
+
* // Add verification headers to response
|
|
220
|
+
* return applyVerificationToResponse(result, response);
|
|
221
|
+
* }
|
|
222
|
+
* }
|
|
223
|
+
* ```
|
|
224
|
+
*
|
|
225
|
+
* Deploy:
|
|
226
|
+
* ```bash
|
|
227
|
+
* # Create KV namespace
|
|
228
|
+
* wrangler kv:namespace create NONCE_CACHE
|
|
229
|
+
*
|
|
230
|
+
* # Add secrets
|
|
231
|
+
* wrangler secret put KYA_VOUCHED_API_KEY
|
|
232
|
+
*
|
|
233
|
+
* # Deploy
|
|
234
|
+
* wrangler deploy
|
|
235
|
+
* ```
|
|
236
|
+
*/
|
|
237
|
+
//# sourceMappingURL=worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker.js","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kya-os/verifier",
|
|
3
|
+
"version": "1.3.0",
|
|
4
|
+
"description": "Isomorphic verifier middleware for XMCP-I proof validation",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./worker": {
|
|
14
|
+
"types": "./dist/worker.d.ts",
|
|
15
|
+
"import": "./dist/worker.js"
|
|
16
|
+
},
|
|
17
|
+
"./express": {
|
|
18
|
+
"types": "./dist/express.d.ts",
|
|
19
|
+
"import": "./dist/express.js"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist/**/*",
|
|
24
|
+
"README.md"
|
|
25
|
+
],
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "tsc -p tsconfig.build.json",
|
|
28
|
+
"dev": "tsc -p tsconfig.build.json --watch",
|
|
29
|
+
"test": "vitest run",
|
|
30
|
+
"test:watch": "vitest",
|
|
31
|
+
"clean": "rm -rf dist"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@kya-os/contracts": "^1.2.0",
|
|
35
|
+
"jose": "^5.2.0"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@types/node": "^20.11.0",
|
|
39
|
+
"typescript": "^5.3.0",
|
|
40
|
+
"vitest": "^1.2.0"
|
|
41
|
+
},
|
|
42
|
+
"peerDependencies": {
|
|
43
|
+
"@types/express": "^4.17.0"
|
|
44
|
+
},
|
|
45
|
+
"peerDependenciesMeta": {
|
|
46
|
+
"@types/express": {
|
|
47
|
+
"optional": true
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"keywords": [
|
|
51
|
+
"xmcp-i",
|
|
52
|
+
"verifier",
|
|
53
|
+
"middleware",
|
|
54
|
+
"identity",
|
|
55
|
+
"proof",
|
|
56
|
+
"cloudflare-workers",
|
|
57
|
+
"express"
|
|
58
|
+
],
|
|
59
|
+
"author": "KYA OS",
|
|
60
|
+
"license": "MIT",
|
|
61
|
+
"repository": {
|
|
62
|
+
"type": "git",
|
|
63
|
+
"url": "https://github.com/kya-os/xmcp-i.git",
|
|
64
|
+
"directory": "packages/verifier"
|
|
65
|
+
}
|
|
66
|
+
}
|