@kya-os/mcp-i-cloudflare 1.4.1-canary.1 → 1.4.1-canary.11
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 +120 -1
- package/dist/adapter.d.ts +6 -0
- package/dist/adapter.d.ts.map +1 -1
- package/dist/adapter.js +29 -0
- package/dist/adapter.js.map +1 -1
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +13 -0
- package/dist/agent.js.map +1 -1
- package/dist/app.d.ts +6 -3
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +14 -1
- package/dist/app.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +19 -2
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/runtime.d.ts +22 -8
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +130 -28
- package/dist/runtime.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +23 -4
- package/dist/server.js.map +1 -1
- package/dist/services/admin.service.d.ts.map +1 -1
- package/dist/services/admin.service.js +36 -3
- package/dist/services/admin.service.js.map +1 -1
- package/dist/services/consent-config.service.d.ts +46 -0
- package/dist/services/consent-config.service.d.ts.map +1 -0
- package/dist/services/consent-config.service.js +157 -0
- package/dist/services/consent-config.service.js.map +1 -0
- package/dist/services/consent-page-renderer.d.ts +137 -0
- package/dist/services/consent-page-renderer.d.ts.map +1 -0
- package/dist/services/consent-page-renderer.js +539 -0
- package/dist/services/consent-page-renderer.js.map +1 -0
- package/dist/services/consent.service.d.ts +58 -3
- package/dist/services/consent.service.d.ts.map +1 -1
- package/dist/services/consent.service.js +373 -18
- package/dist/services/consent.service.js.map +1 -1
- package/dist/services/proof-batch-queue.d.ts +104 -0
- package/dist/services/proof-batch-queue.d.ts.map +1 -0
- package/dist/services/proof-batch-queue.js +209 -0
- package/dist/services/proof-batch-queue.js.map +1 -0
- package/dist/services/proof.service.d.ts +38 -1
- package/dist/services/proof.service.d.ts.map +1 -1
- package/dist/services/proof.service.js +214 -21
- package/dist/services/proof.service.js.map +1 -1
- package/dist/services/transport.service.d.ts +47 -0
- package/dist/services/transport.service.d.ts.map +1 -0
- package/dist/services/transport.service.js +76 -0
- package/dist/services/transport.service.js.map +1 -0
- 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
|
+
"&": "&",
|
|
95
|
+
"<": "<",
|
|
96
|
+
">": ">",
|
|
97
|
+
'"': """,
|
|
98
|
+
"'": "'",
|
|
99
|
+
"/": "/",
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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
|
|
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"}
|