@kya-os/mcp-i-cloudflare 1.4.1-canary.1 → 1.4.1-canary.10

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.
Files changed (51) hide show
  1. package/README.md +120 -1
  2. package/dist/adapter.d.ts +6 -0
  3. package/dist/adapter.d.ts.map +1 -1
  4. package/dist/adapter.js +29 -0
  5. package/dist/adapter.js.map +1 -1
  6. package/dist/agent.d.ts.map +1 -1
  7. package/dist/agent.js +8 -0
  8. package/dist/agent.js.map +1 -1
  9. package/dist/app.d.ts +6 -3
  10. package/dist/app.d.ts.map +1 -1
  11. package/dist/app.js +14 -1
  12. package/dist/app.js.map +1 -1
  13. package/dist/index.d.ts +3 -1
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +5 -1
  16. package/dist/index.js.map +1 -1
  17. package/dist/runtime.d.ts +22 -8
  18. package/dist/runtime.d.ts.map +1 -1
  19. package/dist/runtime.js +125 -28
  20. package/dist/runtime.js.map +1 -1
  21. package/dist/server.d.ts.map +1 -1
  22. package/dist/server.js +23 -4
  23. package/dist/server.js.map +1 -1
  24. package/dist/services/admin.service.d.ts.map +1 -1
  25. package/dist/services/admin.service.js +36 -3
  26. package/dist/services/admin.service.js.map +1 -1
  27. package/dist/services/consent-config.service.d.ts +46 -0
  28. package/dist/services/consent-config.service.d.ts.map +1 -0
  29. package/dist/services/consent-config.service.js +157 -0
  30. package/dist/services/consent-config.service.js.map +1 -0
  31. package/dist/services/consent-page-renderer.d.ts +137 -0
  32. package/dist/services/consent-page-renderer.d.ts.map +1 -0
  33. package/dist/services/consent-page-renderer.js +539 -0
  34. package/dist/services/consent-page-renderer.js.map +1 -0
  35. package/dist/services/consent.service.d.ts +58 -3
  36. package/dist/services/consent.service.d.ts.map +1 -1
  37. package/dist/services/consent.service.js +373 -18
  38. package/dist/services/consent.service.js.map +1 -1
  39. package/dist/services/proof-batch-queue.d.ts +104 -0
  40. package/dist/services/proof-batch-queue.d.ts.map +1 -0
  41. package/dist/services/proof-batch-queue.js +209 -0
  42. package/dist/services/proof-batch-queue.js.map +1 -0
  43. package/dist/services/proof.service.d.ts +38 -1
  44. package/dist/services/proof.service.d.ts.map +1 -1
  45. package/dist/services/proof.service.js +214 -21
  46. package/dist/services/proof.service.js.map +1 -1
  47. package/dist/services/transport.service.d.ts +47 -0
  48. package/dist/services/transport.service.d.ts.map +1 -0
  49. package/dist/services/transport.service.js +76 -0
  50. package/dist/services/transport.service.js.map +1 -0
  51. package/package.json +2 -2
@@ -0,0 +1,539 @@
1
+ /**
2
+ * Consent Page Renderer
3
+ *
4
+ * Renders secure consent pages with comprehensive XSS prevention.
5
+ * All user input is sanitized and escaped before rendering.
6
+ *
7
+ * Security Requirements:
8
+ * - All user input escaped with escapeHtml()
9
+ * - URLs validated before use
10
+ * - CSS colors validated
11
+ * - CSP headers enforced
12
+ * - No eval() or innerHTML with user data
13
+ *
14
+ * Related Spec: MCP-I Phase 0 Implementation Plan, Task B.4
15
+ */
16
+ /**
17
+ * Consent Page Renderer
18
+ *
19
+ * Renders HTML consent pages with security-first approach
20
+ */
21
+ export class ConsentPageRenderer {
22
+ /**
23
+ * Render consent page HTML
24
+ *
25
+ * @param config - Consent page configuration (will be sanitized)
26
+ * @returns HTML string
27
+ */
28
+ render(config) {
29
+ const sanitized = this.sanitizeConfig(config);
30
+ return `<!DOCTYPE html>
31
+ <html lang="en">
32
+ <head>
33
+ <meta charset="UTF-8">
34
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
35
+ <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.tailwindcss.com; style-src 'self' 'unsafe-inline' https://cdn.tailwindcss.com; img-src 'self' data: https:; font-src 'self' data:;">
36
+ <title>Authorize ${sanitized.tool}</title>
37
+ <script src="https://cdn.tailwindcss.com"></script>
38
+ </head>
39
+ <body class="bg-gray-50 min-h-screen flex items-center justify-center p-4">
40
+ <div class="bg-white rounded-lg shadow-lg max-w-md w-full p-6">
41
+ ${this.renderHeader(sanitized)}
42
+ ${this.renderScopes(sanitized.scopes)}
43
+ ${this.renderTerms(sanitized.terms)}
44
+ ${this.renderCustomFields(sanitized.customFields)}
45
+ ${this.renderForm(sanitized)}
46
+ </div>
47
+ ${this.renderScript(sanitized)}
48
+ </body>
49
+ </html>`;
50
+ }
51
+ /**
52
+ * Render success page HTML
53
+ *
54
+ * @param config - Success page configuration
55
+ * @returns HTML string
56
+ */
57
+ renderSuccess(config) {
58
+ const sanitizedDelegationId = this.escapeHtml(config.delegationId);
59
+ const autoCloseScript = config.autoClose
60
+ ? "<script>setTimeout(function(){window.close();}, 2000);</script>"
61
+ : "";
62
+ return `<!DOCTYPE html>
63
+ <html lang="en">
64
+ <head>
65
+ <meta charset="UTF-8">
66
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
67
+ <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.tailwindcss.com; style-src 'self' 'unsafe-inline' https://cdn.tailwindcss.com;">
68
+ <title>Authorization Successful</title>
69
+ <script src="https://cdn.tailwindcss.com"></script>
70
+ </head>
71
+ <body class="bg-gray-50 min-h-screen flex items-center justify-center">
72
+ <div class="bg-white rounded-lg shadow-lg p-6 text-center">
73
+ <svg class="mx-auto h-12 w-12 text-green-500 mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
74
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
75
+ </svg>
76
+ <h1 class="text-2xl font-bold mb-2">Authorization Successful</h1>
77
+ <p class="text-gray-600">You can now close this window.</p>
78
+ <p class="text-sm text-gray-500 mt-2">Delegation ID: <code class="bg-gray-100 px-2 py-1 rounded">${sanitizedDelegationId}</code></p>
79
+ ${autoCloseScript}
80
+ </div>
81
+ </body>
82
+ </html>`;
83
+ }
84
+ /**
85
+ * Escape HTML special characters
86
+ *
87
+ * Prevents XSS by escaping characters that have special meaning in HTML
88
+ *
89
+ * @param text - Text to escape
90
+ * @returns Escaped text
91
+ */
92
+ escapeHtml(text) {
93
+ const map = {
94
+ "&": "&amp;",
95
+ "<": "&lt;",
96
+ ">": "&gt;",
97
+ '"': "&quot;",
98
+ "'": "&#039;",
99
+ "/": "&#x2F;",
100
+ };
101
+ return text.replace(/[&<>"'/]/g, (m) => map[m]);
102
+ }
103
+ /**
104
+ * Validate and sanitize URL
105
+ *
106
+ * @param url - URL to validate
107
+ * @returns Sanitized URL or original if invalid (for fallback)
108
+ */
109
+ validateUrl(url) {
110
+ try {
111
+ const parsed = new URL(url);
112
+ // Only allow http/https protocols
113
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
114
+ return url; // Return original for fallback (will be handled by caller)
115
+ }
116
+ return url; // Return original URL (already safe after validation)
117
+ }
118
+ catch {
119
+ return url; // Return original for fallback
120
+ }
121
+ }
122
+ /**
123
+ * Validate CSS color (hex format)
124
+ *
125
+ * @param color - Color to validate
126
+ * @returns Validated color or default
127
+ */
128
+ validateColor(color) {
129
+ // Must be valid hex color (#RRGGBB)
130
+ if (/^#[0-9A-Fa-f]{6}$/.test(color)) {
131
+ return color;
132
+ }
133
+ // Return safe default
134
+ return "#2563eb";
135
+ }
136
+ /**
137
+ * Sanitize consent page configuration
138
+ *
139
+ * Deep sanitization of all user input fields
140
+ * Note: serverUrl is validated but not escaped (needed for JavaScript)
141
+ *
142
+ * @param config - Configuration to sanitize
143
+ * @returns Sanitized configuration
144
+ */
145
+ sanitizeConfig(config) {
146
+ // Validate serverUrl but don't escape it (needed in JavaScript)
147
+ // If validation fails, keep original (will be handled by form action)
148
+ const validatedServerUrl = this.validateUrl(config.serverUrl);
149
+ return {
150
+ ...config,
151
+ tool: this.escapeHtml(config.tool),
152
+ toolDescription: this.escapeHtml(config.toolDescription),
153
+ scopes: config.scopes.map((s) => this.escapeHtml(s)),
154
+ agentDid: this.escapeHtml(config.agentDid),
155
+ sessionId: this.escapeHtml(config.sessionId),
156
+ projectId: this.escapeHtml(config.projectId),
157
+ serverUrl: validatedServerUrl, // Validated but not escaped (safe for JS)
158
+ branding: config.branding
159
+ ? this.sanitizeBranding(config.branding)
160
+ : undefined,
161
+ terms: config.terms ? this.sanitizeTerms(config.terms) : undefined,
162
+ customFields: config.customFields
163
+ ? config.customFields.map((f) => this.sanitizeCustomField(f))
164
+ : undefined,
165
+ };
166
+ }
167
+ /**
168
+ * Sanitize branding configuration
169
+ *
170
+ * @param branding - Branding to sanitize
171
+ * @returns Sanitized branding
172
+ */
173
+ sanitizeBranding(branding) {
174
+ // Validate logoUrl - if invalid, set to undefined to prevent rendering
175
+ let logoUrl = branding.logoUrl;
176
+ if (logoUrl) {
177
+ const validated = this.validateUrl(logoUrl);
178
+ // If validation failed (returned original but protocol is invalid), don't use it
179
+ try {
180
+ const parsed = new URL(validated);
181
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
182
+ logoUrl = undefined; // Invalid protocol, don't render
183
+ }
184
+ }
185
+ catch {
186
+ logoUrl = undefined; // Invalid URL, don't render
187
+ }
188
+ }
189
+ return {
190
+ ...branding,
191
+ primaryColor: branding.primaryColor
192
+ ? this.validateColor(branding.primaryColor)
193
+ : undefined,
194
+ logoUrl,
195
+ companyName: branding.companyName
196
+ ? this.escapeHtml(branding.companyName)
197
+ : undefined,
198
+ theme: branding.theme === "light" ||
199
+ branding.theme === "dark" ||
200
+ branding.theme === "auto"
201
+ ? branding.theme
202
+ : undefined,
203
+ };
204
+ }
205
+ /**
206
+ * Sanitize terms configuration
207
+ *
208
+ * @param terms - Terms to sanitize
209
+ * @returns Sanitized terms
210
+ */
211
+ sanitizeTerms(terms) {
212
+ return {
213
+ ...terms,
214
+ text: terms.text ? this.escapeHtml(terms.text) : undefined,
215
+ url: terms.url ? this.validateUrl(terms.url) : undefined,
216
+ version: terms.version ? this.escapeHtml(terms.version) : undefined,
217
+ };
218
+ }
219
+ /**
220
+ * Sanitize custom field
221
+ *
222
+ * @param field - Field to sanitize
223
+ * @returns Sanitized field
224
+ */
225
+ sanitizeCustomField(field) {
226
+ return {
227
+ ...field,
228
+ name: this.escapeHtml(field.name),
229
+ label: this.escapeHtml(field.label),
230
+ placeholder: field.placeholder
231
+ ? this.escapeHtml(field.placeholder)
232
+ : undefined,
233
+ options: field.options
234
+ ? field.options.map((opt) => ({
235
+ value: this.escapeHtml(opt.value),
236
+ label: this.escapeHtml(opt.label),
237
+ }))
238
+ : undefined,
239
+ pattern: field.pattern ? this.escapeHtml(field.pattern) : undefined,
240
+ };
241
+ }
242
+ /**
243
+ * Render page header
244
+ *
245
+ * @param config - Sanitized configuration
246
+ * @returns HTML string
247
+ */
248
+ renderHeader(config) {
249
+ const branding = config.branding;
250
+ // Escape logoUrl for HTML attribute to prevent XSS
251
+ const logoUrlEscaped = branding?.logoUrl
252
+ ? this.escapeHtml(branding.logoUrl)
253
+ : '';
254
+ const logoHtml = branding?.logoUrl
255
+ ? `<img src="${logoUrlEscaped}" alt="${branding.companyName || "Logo"}" class="h-12 w-auto mb-4" />`
256
+ : "";
257
+ const companyName = branding?.companyName
258
+ ? `<p class="text-sm text-gray-600 mb-2">${branding.companyName}</p>`
259
+ : "";
260
+ const primaryColor = branding?.primaryColor || "#2563eb";
261
+ return `
262
+ <div class="text-center mb-6">
263
+ ${logoHtml}
264
+ ${companyName}
265
+ <h1 class="text-2xl font-bold mb-2" style="color: ${primaryColor};">Authorize ${config.tool}</h1>
266
+ <p class="text-gray-600">${config.toolDescription}</p>
267
+ </div>`;
268
+ }
269
+ /**
270
+ * Render scopes list
271
+ *
272
+ * @param scopes - Sanitized scopes
273
+ * @returns HTML string
274
+ */
275
+ renderScopes(scopes) {
276
+ if (scopes.length === 0) {
277
+ return '<div class="mb-4"><p class="text-sm text-gray-600">No specific permissions required.</p></div>';
278
+ }
279
+ const scopeItems = scopes
280
+ .map((scope) => `
281
+ <li class="flex items-start">
282
+ <svg class="h-5 w-5 text-green-500 mr-2 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
283
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
284
+ </svg>
285
+ <span class="text-sm text-gray-700">${scope}</span>
286
+ </li>`)
287
+ .join("");
288
+ return `
289
+ <div class="mb-6">
290
+ <h2 class="text-lg font-semibold mb-3">Permissions Requested</h2>
291
+ <ul class="space-y-2">
292
+ ${scopeItems}
293
+ </ul>
294
+ </div>`;
295
+ }
296
+ /**
297
+ * Render terms section
298
+ *
299
+ * @param terms - Sanitized terms
300
+ * @returns HTML string
301
+ */
302
+ renderTerms(terms) {
303
+ if (!terms) {
304
+ return "";
305
+ }
306
+ const termsText = terms.text
307
+ ? `<p class="text-sm text-gray-600 mb-4">${terms.text}</p>`
308
+ : "";
309
+ // Escape URL for HTML attribute to prevent XSS
310
+ const termsUrlEscaped = terms.url ? this.escapeHtml(terms.url) : '';
311
+ const termsLink = terms.url
312
+ ? `<a href="${termsUrlEscaped}" target="_blank" rel="noopener noreferrer" class="text-blue-600 hover:underline text-sm">View Terms</a>`
313
+ : "";
314
+ return `
315
+ <div class="mb-6">
316
+ ${termsText}
317
+ ${termsLink}
318
+ </div>`;
319
+ }
320
+ /**
321
+ * Render custom fields
322
+ *
323
+ * @param fields - Sanitized custom fields
324
+ * @returns HTML string
325
+ */
326
+ renderCustomFields(fields) {
327
+ if (!fields || fields.length === 0) {
328
+ return "";
329
+ }
330
+ const fieldHtml = fields
331
+ .map((field) => {
332
+ const requiredAttr = field.required ? "required" : "";
333
+ const patternAttr = field.pattern ? `pattern="${field.pattern}"` : "";
334
+ const placeholderAttr = field.placeholder
335
+ ? `placeholder="${field.placeholder}"`
336
+ : "";
337
+ if (field.type === "checkbox") {
338
+ return `
339
+ <div class="mb-4">
340
+ <label class="flex items-center">
341
+ <input type="checkbox" name="${field.name}" ${requiredAttr} class="mr-2" />
342
+ <span class="text-sm text-gray-700">${field.label}</span>
343
+ </label>
344
+ </div>`;
345
+ }
346
+ else if (field.type === "select") {
347
+ const options = field.options
348
+ ? field.options
349
+ .map((opt) => `<option value="${opt.value}">${opt.label}</option>`)
350
+ .join("")
351
+ : "";
352
+ return `
353
+ <div class="mb-4">
354
+ <label class="block text-sm font-medium text-gray-700 mb-1">${field.label}</label>
355
+ <select name="${field.name}" ${requiredAttr} class="w-full px-3 py-2 border border-gray-300 rounded-md">
356
+ ${options}
357
+ </select>
358
+ </div>`;
359
+ }
360
+ else if (field.type === "textarea") {
361
+ return `
362
+ <div class="mb-4">
363
+ <label class="block text-sm font-medium text-gray-700 mb-1">${field.label}</label>
364
+ <textarea name="${field.name}" ${requiredAttr} ${placeholderAttr} rows="3" class="w-full px-3 py-2 border border-gray-300 rounded-md"></textarea>
365
+ </div>`;
366
+ }
367
+ else {
368
+ // text field
369
+ return `
370
+ <div class="mb-4">
371
+ <label class="block text-sm font-medium text-gray-700 mb-1">${field.label}</label>
372
+ <input type="text" name="${field.name}" ${requiredAttr} ${placeholderAttr} ${patternAttr} class="w-full px-3 py-2 border border-gray-300 rounded-md" />
373
+ </div>`;
374
+ }
375
+ })
376
+ .join("");
377
+ return `
378
+ <div class="mb-6">
379
+ <h2 class="text-lg font-semibold mb-3">Additional Information</h2>
380
+ ${fieldHtml}
381
+ </div>`;
382
+ }
383
+ /**
384
+ * Render form
385
+ *
386
+ * @param config - Sanitized configuration
387
+ * @returns HTML string
388
+ */
389
+ renderForm(config) {
390
+ const scopesJson = JSON.stringify(config.scopes);
391
+ const agentDid = config.agentDid;
392
+ const sessionId = config.sessionId;
393
+ const projectId = config.projectId;
394
+ const tool = config.tool;
395
+ // Escape serverUrl for HTML attribute to prevent XSS
396
+ const serverUrlEscaped = this.escapeHtml(config.serverUrl);
397
+ return `
398
+ <form id="consent-form" method="POST" action="${serverUrlEscaped}/consent/approve" class="space-y-4">
399
+ <input type="hidden" name="tool" value="${tool}" />
400
+ <input type="hidden" name="scopes" value="${scopesJson}" />
401
+ <input type="hidden" name="agent_did" value="${agentDid}" />
402
+ <input type="hidden" name="session_id" value="${sessionId}" />
403
+ <input type="hidden" name="project_id" value="${projectId}" />
404
+
405
+ ${config.terms?.required
406
+ ? `
407
+ <div class="mb-4">
408
+ <label class="flex items-start">
409
+ <input type="checkbox" name="termsAccepted" required class="mr-2 mt-1" />
410
+ <span class="text-sm text-gray-700">I accept the terms and conditions</span>
411
+ </label>
412
+ </div>
413
+ `
414
+ : ""}
415
+
416
+ <div class="flex gap-3">
417
+ <button type="submit" class="flex-1 bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2">
418
+ Approve
419
+ </button>
420
+ <button type="button" onclick="window.close()" class="flex-1 bg-gray-200 text-gray-700 px-4 py-2 rounded-md hover:bg-gray-300 focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2">
421
+ Cancel
422
+ </button>
423
+ </div>
424
+ </form>`;
425
+ }
426
+ /**
427
+ * Render JavaScript for form handling
428
+ *
429
+ * @param config - Sanitized configuration
430
+ * @returns HTML string
431
+ */
432
+ renderScript(config) {
433
+ // serverUrl is already validated, but we need to escape it for JavaScript string
434
+ // Use JSON.stringify to safely embed the URL in JavaScript
435
+ const serverUrlJs = JSON.stringify(config.serverUrl);
436
+ return `
437
+ <script>
438
+ (function() {
439
+ const form = document.getElementById('consent-form');
440
+ if (!form) return;
441
+
442
+ const serverUrl = ${serverUrlJs};
443
+
444
+ form.addEventListener('submit', async function(e) {
445
+ e.preventDefault();
446
+
447
+ const formData = new FormData(form);
448
+
449
+ // Safely parse scopes JSON
450
+ const scopesValue = formData.get('scopes');
451
+ let scopes = [];
452
+ if (scopesValue && typeof scopesValue === 'string' && scopesValue.trim()) {
453
+ try {
454
+ scopes = JSON.parse(scopesValue);
455
+ } catch (e) {
456
+ console.error('Failed to parse scopes:', e);
457
+ alert('Error: Invalid scopes format');
458
+ return;
459
+ }
460
+ }
461
+
462
+ const data = {
463
+ tool: formData.get('tool'),
464
+ scopes: scopes,
465
+ agent_did: formData.get('agent_did'),
466
+ session_id: formData.get('session_id'),
467
+ project_id: formData.get('project_id'),
468
+ termsAccepted: formData.get('termsAccepted') === 'on',
469
+ customFields: {}
470
+ };
471
+
472
+ // Collect custom fields
473
+ ${config.customFields
474
+ ?.map((field) => {
475
+ // Field names are already sanitized, but escape for JS string safety
476
+ const fieldNameJs = JSON.stringify(field.name);
477
+ if (field.type === "checkbox") {
478
+ return `data.customFields[${fieldNameJs}] = formData.get(${fieldNameJs}) === 'on';`;
479
+ }
480
+ else {
481
+ return `const ${field.name.replace(/[^a-zA-Z0-9_]/g, "_")}Value = formData.get(${fieldNameJs}); if (${field.name.replace(/[^a-zA-Z0-9_]/g, "_")}Value) data.customFields[${fieldNameJs}] = ${field.name.replace(/[^a-zA-Z0-9_]/g, "_")}Value;`;
482
+ }
483
+ })
484
+ .join("\n ") || ""}
485
+
486
+ try {
487
+ const response = await fetch(serverUrl + '/consent/approve', {
488
+ method: 'POST',
489
+ headers: {
490
+ 'Content-Type': 'application/json'
491
+ },
492
+ body: JSON.stringify(data)
493
+ });
494
+
495
+ // Check if response is JSON and parse it
496
+ const contentType = response.headers.get('content-type');
497
+ const text = await response.text();
498
+
499
+ if (!contentType || !contentType.includes('application/json')) {
500
+ console.error('Non-JSON response:', text);
501
+ alert('Error: Server returned invalid response. Status: ' + response.status);
502
+ return;
503
+ }
504
+
505
+ // Parse JSON response
506
+ let result;
507
+ try {
508
+ if (!text || !text.trim()) {
509
+ throw new Error('Empty response');
510
+ }
511
+ result = JSON.parse(text);
512
+ } catch (parseError) {
513
+ console.error('Failed to parse JSON response:', parseError);
514
+ alert('Error: Invalid response from server');
515
+ return;
516
+ }
517
+
518
+ if (result.success) {
519
+ const successUrl = serverUrl + '/consent/success?delegation_id=' + encodeURIComponent(result.delegation_id || 'unknown');
520
+ // Include project_id if available so autoClose can be checked
521
+ const projectId = formData.get('project_id');
522
+ if (projectId) {
523
+ window.location.href = successUrl + '&project_id=' + encodeURIComponent(projectId);
524
+ } else {
525
+ window.location.href = successUrl;
526
+ }
527
+ } else {
528
+ alert('Authorization failed: ' + (result.error || 'Unknown error'));
529
+ }
530
+ } catch (error) {
531
+ console.error('Error submitting authorization:', error);
532
+ alert('Error submitting authorization: ' + (error instanceof Error ? error.message : String(error)));
533
+ }
534
+ });
535
+ })();
536
+ </script>`;
537
+ }
538
+ }
539
+ //# sourceMappingURL=consent-page-renderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consent-page-renderer.js","sourceRoot":"","sources":["../../src/services/consent-page-renderer.ts"],"names":[],"mappings":"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"}
@@ -2,24 +2,79 @@
2
2
  * Consent Service
3
3
  *
4
4
  * Handles consent page rendering and approval handling.
5
- * Structure only - full implementation in Phase 0.
5
+ * Complete implementation for Phase 0.
6
+ *
7
+ * Related Spec: MCP-I Phase 0 Implementation Plan, Task B.5
6
8
  */
9
+ import type { CloudflareEnv } from '../types';
10
+ import type { CloudflareRuntime } from '../runtime';
7
11
  export declare class ConsentService {
12
+ private configService;
13
+ private renderer;
14
+ private env;
15
+ private runtime?;
16
+ constructor(env: CloudflareEnv, runtime?: CloudflareRuntime);
8
17
  /**
9
18
  * Handle consent requests
19
+ *
20
+ * Routes:
21
+ * - GET /consent - Render consent page
22
+ * - POST /consent/approve - Handle approval
23
+ * - GET /consent/success - Success page
24
+ *
10
25
  * @param request - Incoming request
11
26
  * @returns Response
12
27
  */
13
28
  handle(request: Request): Promise<Response>;
14
29
  /**
15
30
  * Render consent page
16
- * TODO: Implement in Phase 0
31
+ *
32
+ * Query parameters:
33
+ * - tool: Tool name
34
+ * - scopes: Comma-separated scopes
35
+ * - agent_did: Agent DID
36
+ * - session_id: Session ID
37
+ * - project_id: Project ID
38
+ *
39
+ * @param params - URL search parameters
40
+ * @param request - Original request (for extracting origin)
41
+ * @returns HTML response
17
42
  */
18
43
  private renderConsentPage;
19
44
  /**
20
45
  * Handle consent approval
21
- * TODO: Implement in Phase 0
46
+ *
47
+ * Validates request, creates delegation via AgentShield API,
48
+ * stores token in KV, and returns success response.
49
+ *
50
+ * @param request - Approval request
51
+ * @returns JSON response
22
52
  */
23
53
  private handleApproval;
54
+ /**
55
+ * Create delegation via AgentShield API
56
+ *
57
+ * @param request - Approval request
58
+ * @returns Delegation creation result
59
+ */
60
+ private createDelegation;
61
+ /**
62
+ * Store delegation token in KV
63
+ *
64
+ * Stores token using both session ID and agent DID keys for resilience.
65
+ *
66
+ * @param sessionId - Session ID
67
+ * @param agentDid - Agent DID
68
+ * @param token - Delegation token
69
+ * @param delegationId - Delegation ID
70
+ */
71
+ private storeDelegationToken;
72
+ /**
73
+ * Render success page
74
+ *
75
+ * @param params - URL search parameters (delegation_id)
76
+ * @returns HTML response
77
+ */
78
+ private renderSuccessPage;
24
79
  }
25
80
  //# sourceMappingURL=consent.service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"consent.service.d.ts","sourceRoot":"","sources":["../../src/services/consent.service.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,qBAAa,cAAc;IACzB;;;;OAIG;IACG,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC;IAgBjD;;;OAGG;YACW,iBAAiB;IAQ/B;;;OAGG;YACW,cAAc;CAO7B"}
1
+ {"version":3,"file":"consent.service.d.ts","sourceRoot":"","sources":["../../src/services/consent.service.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAgBpD,qBAAa,cAAc;IACzB,OAAO,CAAC,aAAa,CAAuB;IAC5C,OAAO,CAAC,QAAQ,CAAsB;IACtC,OAAO,CAAC,GAAG,CAAgB;IAC3B,OAAO,CAAC,OAAO,CAAC,CAAoB;gBAExB,GAAG,EAAE,aAAa,EAAE,OAAO,CAAC,EAAE,iBAAiB;IAO3D;;;;;;;;;;OAUG;IACG,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC;IAqBjD;;;;;;;;;;;;;OAaG;YACW,iBAAiB;IA2G/B;;;;;;;;OAQG;YACW,cAAc;IA2F5B;;;;;OAKG;YACW,gBAAgB;IAqG9B;;;;;;;;;OASG;YACW,oBAAoB;IA4ClC;;;;;OAKG;YACW,iBAAiB;CA+BhC"}