@arcblock/did-connect-service 4.1.19 → 4.1.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/access/rbac.d.ts +12 -0
- package/dist/access/rbac.d.ts.map +1 -1
- package/dist/access/rbac.js +20 -0
- package/dist/access/rbac.js.map +1 -1
- package/dist/handlers/access-key-connect-handler.d.ts +6 -0
- package/dist/handlers/access-key-connect-handler.d.ts.map +1 -1
- package/dist/handlers/access-key-connect-handler.js +40 -2
- package/dist/handlers/access-key-connect-handler.js.map +1 -1
- package/dist/handlers/auth-handler.d.ts +5 -0
- package/dist/handlers/auth-handler.d.ts.map +1 -1
- package/dist/handlers/auth-handler.js +1 -0
- package/dist/handlers/auth-handler.js.map +1 -1
- package/dist/handlers/cimd.d.ts +109 -0
- package/dist/handlers/cimd.d.ts.map +1 -0
- package/dist/handlers/cimd.js +370 -0
- package/dist/handlers/cimd.js.map +1 -0
- package/dist/handlers/oauth-as-handler.d.ts +107 -6
- package/dist/handlers/oauth-as-handler.d.ts.map +1 -1
- package/dist/handlers/oauth-as-handler.js +513 -101
- package/dist/handlers/oauth-as-handler.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/pages/brand-icons.d.ts +41 -0
- package/dist/pages/brand-icons.d.ts.map +1 -0
- package/dist/pages/brand-icons.js +76 -0
- package/dist/pages/brand-icons.js.map +1 -0
- package/dist/pages/gen-access-key-page.d.ts +9 -1
- package/dist/pages/gen-access-key-page.d.ts.map +1 -1
- package/dist/pages/gen-access-key-page.js +259 -40
- package/dist/pages/gen-access-key-page.js.map +1 -1
- package/dist/store/d1-store.d.ts +10 -0
- package/dist/store/d1-store.d.ts.map +1 -1
- package/dist/store/d1-store.js +26 -6
- package/dist/store/d1-store.js.map +1 -1
- package/migrations/0014_oauth_client_name.sql +8 -0
- package/package.json +3 -3
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OAuth Client ID Metadata Documents (CIMD) —
|
|
3
|
+
* draft-ietf-oauth-client-id-metadata-document-00.
|
|
4
|
+
*
|
|
5
|
+
* The client's `client_id` IS an https URL; the AS fetches that URL at
|
|
6
|
+
* authorization time to learn the client's name and redirect URIs. Unlike DCR
|
|
7
|
+
* (which the MCP spec now marks deprecated), the identity is bound to a domain
|
|
8
|
+
* the client demonstrably controls — which is what lets the consent screen show
|
|
9
|
+
* a name worth trusting instead of an opaque UUID.
|
|
10
|
+
*
|
|
11
|
+
* This module is deliberately paranoid: the AS is being told to make an
|
|
12
|
+
* outbound request to an attacker-chosen URL, so every guard below is load
|
|
13
|
+
* bearing. See {@link assertSafeCimdUrl} and {@link fetchCimdClient}.
|
|
14
|
+
*/
|
|
15
|
+
/** Spec §5: "The recommended maximum response size ... is 5 kilobytes." */
|
|
16
|
+
export const CIMD_MAX_BYTES = 5 * 1024;
|
|
17
|
+
/** Outbound fetch budget. A slow client host must not stall authorization. */
|
|
18
|
+
export const CIMD_FETCH_TIMEOUT_MS = 5_000;
|
|
19
|
+
/** Cache window when the document carries no usable Cache-Control. */
|
|
20
|
+
export const CIMD_DEFAULT_TTL_SECONDS = 60 * 60;
|
|
21
|
+
/** Clamp for a document-supplied max-age (spec: the AS MAY set its own bounds). */
|
|
22
|
+
export const CIMD_MIN_TTL_SECONDS = 5 * 60;
|
|
23
|
+
export const CIMD_MAX_TTL_SECONDS = 24 * 60 * 60;
|
|
24
|
+
const CACHE_PREFIX = "cimd:";
|
|
25
|
+
/** Shared-secret auth methods the spec forbids for CIMD clients. */
|
|
26
|
+
const FORBIDDEN_AUTH_METHODS = new Set([
|
|
27
|
+
"client_secret_post",
|
|
28
|
+
"client_secret_basic",
|
|
29
|
+
"client_secret_jwt",
|
|
30
|
+
]);
|
|
31
|
+
/**
|
|
32
|
+
* Cheap discriminator: does this client_id want the CIMD path at all?
|
|
33
|
+
* Anything else (UUID, hand-picked string) stays on the DCR / pre-registered
|
|
34
|
+
* path, so this must not throw or fetch.
|
|
35
|
+
*/
|
|
36
|
+
export function isCimdClientId(value) {
|
|
37
|
+
return value.startsWith("https://") || value.startsWith("http://");
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Spec §3 URL rules plus SSRF hardening (§6.1).
|
|
41
|
+
*
|
|
42
|
+
* Rejects: non-https, no path component, dot segments, fragment, userinfo, and
|
|
43
|
+
* hosts that are loopback/private/link-local IP literals or `localhost`.
|
|
44
|
+
*
|
|
45
|
+
* Residual risk, stated plainly: a hostname that resolves to a private address
|
|
46
|
+
* (DNS rebinding) cannot be caught here, because the runtime resolves DNS
|
|
47
|
+
* inside `fetch`. Literal-address filtering is the mitigation available to us;
|
|
48
|
+
* deployments that need more must egress-filter at the network layer.
|
|
49
|
+
*/
|
|
50
|
+
export function assertSafeCimdUrl(value) {
|
|
51
|
+
let url;
|
|
52
|
+
try {
|
|
53
|
+
url = new URL(value);
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
return { ok: false, reason: "client_id is not a valid URL" };
|
|
57
|
+
}
|
|
58
|
+
if (url.protocol !== "https:") {
|
|
59
|
+
return { ok: false, reason: "client_id URL must use https" };
|
|
60
|
+
}
|
|
61
|
+
if (url.username || url.password) {
|
|
62
|
+
return { ok: false, reason: "client_id URL must not contain userinfo" };
|
|
63
|
+
}
|
|
64
|
+
if (url.hash) {
|
|
65
|
+
return { ok: false, reason: "client_id URL must not contain a fragment" };
|
|
66
|
+
}
|
|
67
|
+
// "MUST contain a path component" — a bare origin carries no document.
|
|
68
|
+
if (url.pathname === "/" || url.pathname === "") {
|
|
69
|
+
return { ok: false, reason: "client_id URL must contain a path component" };
|
|
70
|
+
}
|
|
71
|
+
// Check the RAW string, not url.pathname: the URL parser already resolves
|
|
72
|
+
// `/a/../c.json` to `/c.json`, so inspecting the parsed path would always
|
|
73
|
+
// pass. The client_id is also compared byte-for-byte against the document's
|
|
74
|
+
// own client_id, so the literal form is what matters.
|
|
75
|
+
if (hasDotSegment(value)) {
|
|
76
|
+
return { ok: false, reason: "client_id URL must not contain dot path segments" };
|
|
77
|
+
}
|
|
78
|
+
if (isBlockedHost(url.hostname)) {
|
|
79
|
+
return { ok: false, reason: "client_id URL host is not publicly routable" };
|
|
80
|
+
}
|
|
81
|
+
return { ok: true, url };
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Dot-segment detection on the raw client_id, including the percent-encoded
|
|
85
|
+
* forms a server might still resolve (`%2e%2e`).
|
|
86
|
+
*/
|
|
87
|
+
function hasDotSegment(raw) {
|
|
88
|
+
const schemeEnd = raw.indexOf("://");
|
|
89
|
+
const pathStart = schemeEnd < 0 ? -1 : raw.indexOf("/", schemeEnd + 3);
|
|
90
|
+
if (pathStart < 0)
|
|
91
|
+
return false;
|
|
92
|
+
const path = raw.slice(pathStart).split(/[?#]/)[0] ?? "";
|
|
93
|
+
return path
|
|
94
|
+
.toLowerCase()
|
|
95
|
+
.split("/")
|
|
96
|
+
.some((seg) => {
|
|
97
|
+
const decoded = seg.replace(/%2e/g, ".");
|
|
98
|
+
return decoded === "." || decoded === "..";
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
function isBlockedHost(hostname) {
|
|
102
|
+
const host = hostname.replace(/^\[|\]$/g, "").toLowerCase();
|
|
103
|
+
if (host === "localhost" || host.endsWith(".localhost"))
|
|
104
|
+
return true;
|
|
105
|
+
// IPv4 literal → block loopback / private / link-local / CGNAT / unspecified.
|
|
106
|
+
const v4 = host.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/);
|
|
107
|
+
if (v4) {
|
|
108
|
+
const [a, b] = [Number(v4[1]), Number(v4[2])];
|
|
109
|
+
if (a === 10 || a === 127 || a === 0)
|
|
110
|
+
return true;
|
|
111
|
+
if (a === 172 && b >= 16 && b <= 31)
|
|
112
|
+
return true;
|
|
113
|
+
if (a === 192 && b === 168)
|
|
114
|
+
return true;
|
|
115
|
+
if (a === 169 && b === 254)
|
|
116
|
+
return true;
|
|
117
|
+
if (a === 100 && b >= 64 && b <= 127)
|
|
118
|
+
return true;
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
// IPv6 literal → block loopback / unspecified / ULA / link-local, and any
|
|
122
|
+
// IPv4-mapped form whose embedded address is itself blocked.
|
|
123
|
+
if (host.includes(":")) {
|
|
124
|
+
if (host === "::1" || host === "::")
|
|
125
|
+
return true;
|
|
126
|
+
if (/^f[cd][0-9a-f]{2}:/.test(host))
|
|
127
|
+
return true;
|
|
128
|
+
if (/^fe[89ab][0-9a-f]:/.test(host))
|
|
129
|
+
return true;
|
|
130
|
+
// Dotted IPv4-mapped form, e.g. ::ffff:169.254.169.254
|
|
131
|
+
const dotted = host.match(/::ffff:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/);
|
|
132
|
+
if (dotted)
|
|
133
|
+
return isBlockedHost(dotted[1]);
|
|
134
|
+
// ...and the hex form the URL parser normalises it to (::ffff:a9fe:a9fe).
|
|
135
|
+
const hex = host.match(/^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/);
|
|
136
|
+
if (hex) {
|
|
137
|
+
const high = Number.parseInt(hex[1], 16);
|
|
138
|
+
const low = Number.parseInt(hex[2], 16);
|
|
139
|
+
return isBlockedHost([high >> 8, high & 0xff, low >> 8, low & 0xff].join("."));
|
|
140
|
+
}
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Fetch + validate a Client ID Metadata Document.
|
|
147
|
+
*
|
|
148
|
+
* Spec compliance notes:
|
|
149
|
+
* - `client_id` inside the document MUST equal the URL (simple string
|
|
150
|
+
* comparison, RFC 3986 §6.2.1) — this is what stops one domain from
|
|
151
|
+
* impersonating another's document.
|
|
152
|
+
* - Redirects are refused. The document's `client_id` must equal the URL we
|
|
153
|
+
* were given, so a redirect either lands somewhere that fails that check or
|
|
154
|
+
* is an SSRF chain we have no reason to walk.
|
|
155
|
+
* - Errors and malformed documents are never cached (spec §5).
|
|
156
|
+
*/
|
|
157
|
+
export async function fetchCimdClient(clientId, redirectUriValidator, deps = {}) {
|
|
158
|
+
const checked = assertSafeCimdUrl(clientId);
|
|
159
|
+
if (!checked.ok)
|
|
160
|
+
return checked;
|
|
161
|
+
const cacheKey = `${CACHE_PREFIX}${clientId}`;
|
|
162
|
+
if (deps.cache) {
|
|
163
|
+
const hit = await deps.cache.get(cacheKey).catch(() => null);
|
|
164
|
+
if (hit) {
|
|
165
|
+
const parsed = parseCimdDocument(hit, clientId, redirectUriValidator);
|
|
166
|
+
// A poisoned/stale cache entry must not be fatal — fall through to a
|
|
167
|
+
// live fetch rather than locking the client out.
|
|
168
|
+
if (parsed.ok)
|
|
169
|
+
return parsed;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
173
|
+
const controller = new AbortController();
|
|
174
|
+
const timer = setTimeout(() => controller.abort(), CIMD_FETCH_TIMEOUT_MS);
|
|
175
|
+
let response;
|
|
176
|
+
try {
|
|
177
|
+
response = await fetchImpl(checked.url.toString(), {
|
|
178
|
+
method: "GET",
|
|
179
|
+
redirect: "error",
|
|
180
|
+
headers: { Accept: "application/json" },
|
|
181
|
+
signal: controller.signal,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
catch (err) {
|
|
185
|
+
deps.logger?.warn({
|
|
186
|
+
message: "cimd: metadata fetch failed",
|
|
187
|
+
mod: "oauth-as",
|
|
188
|
+
clientId,
|
|
189
|
+
err,
|
|
190
|
+
});
|
|
191
|
+
return { ok: false, reason: "client_id metadata document could not be fetched" };
|
|
192
|
+
}
|
|
193
|
+
finally {
|
|
194
|
+
clearTimeout(timer);
|
|
195
|
+
}
|
|
196
|
+
if (!response.ok) {
|
|
197
|
+
return { ok: false, reason: `client_id metadata document returned HTTP ${response.status}` };
|
|
198
|
+
}
|
|
199
|
+
const declared = Number(response.headers.get("content-length") ?? "");
|
|
200
|
+
if (Number.isFinite(declared) && declared > CIMD_MAX_BYTES) {
|
|
201
|
+
return { ok: false, reason: "client_id metadata document is too large" };
|
|
202
|
+
}
|
|
203
|
+
const body = await readCapped(response, CIMD_MAX_BYTES);
|
|
204
|
+
if (body === null) {
|
|
205
|
+
return { ok: false, reason: "client_id metadata document is too large" };
|
|
206
|
+
}
|
|
207
|
+
const parsed = parseCimdDocument(body, clientId, redirectUriValidator);
|
|
208
|
+
if (!parsed.ok)
|
|
209
|
+
return parsed;
|
|
210
|
+
if (deps.cache) {
|
|
211
|
+
const ttl = cacheTtlFrom(response.headers.get("cache-control"));
|
|
212
|
+
await deps.cache.put(cacheKey, body, ttl).catch(() => { });
|
|
213
|
+
}
|
|
214
|
+
return parsed;
|
|
215
|
+
}
|
|
216
|
+
/** Reads at most `max` bytes; returns null if the body exceeds it. */
|
|
217
|
+
async function readCapped(response, max) {
|
|
218
|
+
if (!response.body) {
|
|
219
|
+
const text = await response.text().catch(() => "");
|
|
220
|
+
return text.length > max ? null : text;
|
|
221
|
+
}
|
|
222
|
+
const reader = response.body.getReader();
|
|
223
|
+
const chunks = [];
|
|
224
|
+
let total = 0;
|
|
225
|
+
try {
|
|
226
|
+
while (true) {
|
|
227
|
+
const { done, value } = await reader.read();
|
|
228
|
+
if (done)
|
|
229
|
+
break;
|
|
230
|
+
if (!value)
|
|
231
|
+
continue;
|
|
232
|
+
total += value.byteLength;
|
|
233
|
+
if (total > max) {
|
|
234
|
+
await reader.cancel().catch(() => { });
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
chunks.push(value);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
catch {
|
|
241
|
+
return null;
|
|
242
|
+
}
|
|
243
|
+
const merged = new Uint8Array(total);
|
|
244
|
+
let offset = 0;
|
|
245
|
+
for (const chunk of chunks) {
|
|
246
|
+
merged.set(chunk, offset);
|
|
247
|
+
offset += chunk.byteLength;
|
|
248
|
+
}
|
|
249
|
+
return new TextDecoder().decode(merged);
|
|
250
|
+
}
|
|
251
|
+
/** Honour Cache-Control max-age, clamped to our own bounds (spec allows this). */
|
|
252
|
+
function cacheTtlFrom(cacheControl) {
|
|
253
|
+
if (!cacheControl)
|
|
254
|
+
return CIMD_DEFAULT_TTL_SECONDS;
|
|
255
|
+
const lowered = cacheControl.toLowerCase();
|
|
256
|
+
if (lowered.includes("no-store") || lowered.includes("no-cache"))
|
|
257
|
+
return CIMD_MIN_TTL_SECONDS;
|
|
258
|
+
const match = lowered.match(/max-age\s*=\s*(\d+)/);
|
|
259
|
+
if (!match)
|
|
260
|
+
return CIMD_DEFAULT_TTL_SECONDS;
|
|
261
|
+
const seconds = Number(match[1]);
|
|
262
|
+
if (!Number.isFinite(seconds))
|
|
263
|
+
return CIMD_DEFAULT_TTL_SECONDS;
|
|
264
|
+
return Math.min(CIMD_MAX_TTL_SECONDS, Math.max(CIMD_MIN_TTL_SECONDS, seconds));
|
|
265
|
+
}
|
|
266
|
+
export function parseCimdDocument(body, clientId, redirectUriValidator) {
|
|
267
|
+
let doc;
|
|
268
|
+
try {
|
|
269
|
+
doc = JSON.parse(body);
|
|
270
|
+
}
|
|
271
|
+
catch {
|
|
272
|
+
return { ok: false, reason: "client_id metadata document is not valid JSON" };
|
|
273
|
+
}
|
|
274
|
+
if (!doc || typeof doc !== "object" || Array.isArray(doc)) {
|
|
275
|
+
return { ok: false, reason: "client_id metadata document must be a JSON object" };
|
|
276
|
+
}
|
|
277
|
+
const rec = doc;
|
|
278
|
+
// The anchor of the whole scheme: the document must claim the exact URL it
|
|
279
|
+
// was served from, so example.com cannot publish a document for another.
|
|
280
|
+
if (rec.client_id !== clientId) {
|
|
281
|
+
return { ok: false, reason: "client_id in metadata document does not match its URL" };
|
|
282
|
+
}
|
|
283
|
+
if ("client_secret" in rec || "client_secret_expires_at" in rec) {
|
|
284
|
+
return { ok: false, reason: "client_id metadata document must not carry a client_secret" };
|
|
285
|
+
}
|
|
286
|
+
if (typeof rec.token_endpoint_auth_method === "string" &&
|
|
287
|
+
FORBIDDEN_AUTH_METHODS.has(rec.token_endpoint_auth_method)) {
|
|
288
|
+
return { ok: false, reason: "client_id metadata document requests a shared-secret auth method" };
|
|
289
|
+
}
|
|
290
|
+
const clientName = sanitizeDisplayText(rec.client_name);
|
|
291
|
+
if (!clientName) {
|
|
292
|
+
return { ok: false, reason: "client_id metadata document is missing client_name" };
|
|
293
|
+
}
|
|
294
|
+
if (!Array.isArray(rec.redirect_uris) || rec.redirect_uris.length === 0) {
|
|
295
|
+
return { ok: false, reason: "client_id metadata document is missing redirect_uris" };
|
|
296
|
+
}
|
|
297
|
+
const redirectUris = [];
|
|
298
|
+
for (const uri of rec.redirect_uris) {
|
|
299
|
+
if (typeof uri !== "string" || !redirectUriValidator(uri)) {
|
|
300
|
+
return { ok: false, reason: "client_id metadata document has an unusable redirect_uri" };
|
|
301
|
+
}
|
|
302
|
+
redirectUris.push(uri);
|
|
303
|
+
}
|
|
304
|
+
const clientUri = typeof rec.client_uri === "string" ? rec.client_uri : undefined;
|
|
305
|
+
// logo_uri is only honoured when it is served from the same host as the
|
|
306
|
+
// metadata document, so a client cannot point at someone else's brand.
|
|
307
|
+
const logoUri = sameHostHttps(rec.logo_uri, clientId);
|
|
308
|
+
return {
|
|
309
|
+
ok: true,
|
|
310
|
+
client: {
|
|
311
|
+
clientId,
|
|
312
|
+
clientName,
|
|
313
|
+
...(clientUri && sameHostHttps(clientUri, clientId) ? { clientUri } : {}),
|
|
314
|
+
...(logoUri ? { logoUri } : {}),
|
|
315
|
+
redirectUris,
|
|
316
|
+
},
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
/** Max length of a client-supplied display name on the consent screen. */
|
|
320
|
+
export const CIMD_NAME_MAX = 64;
|
|
321
|
+
/**
|
|
322
|
+
* A client-supplied name is rendered next to an Authorize button, so strip
|
|
323
|
+
* anything that can fake structure: control characters and the bidi overrides
|
|
324
|
+
* used to make "…gpj.exe" read as "…exe.jpg". Rendering is still textContent
|
|
325
|
+
* only — this is defence in depth, not the only guard.
|
|
326
|
+
*/
|
|
327
|
+
export function sanitizeDisplayText(value) {
|
|
328
|
+
if (typeof value !== "string")
|
|
329
|
+
return undefined;
|
|
330
|
+
const cleaned = value
|
|
331
|
+
// biome-ignore lint/suspicious/noControlCharactersInRegex: stripping them is the point
|
|
332
|
+
.replace(/[\u0000-\u001F\u007F]/g, "")
|
|
333
|
+
// Zero-width + bidi overrides: the trick that renders one string as another.
|
|
334
|
+
.replace(/[\u200B-\u200F\u202A-\u202E\u2066-\u2069\uFEFF]/g, "")
|
|
335
|
+
.trim();
|
|
336
|
+
if (!cleaned)
|
|
337
|
+
return undefined;
|
|
338
|
+
return cleaned.length > CIMD_NAME_MAX
|
|
339
|
+
? cleaned.slice(0, CIMD_NAME_MAX) + "\u2026"
|
|
340
|
+
: cleaned;
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* A branding URL is only honoured when it is https and lives on the same host
|
|
344
|
+
* as the metadata document, so a client cannot point at someone else's assets.
|
|
345
|
+
*
|
|
346
|
+
* Exported because it is re-applied every time the value is read back out of
|
|
347
|
+
* storage, not just at fetch time: the consent screen must never render a logo
|
|
348
|
+
* from a host that is not the client's own, whatever wrote the row.
|
|
349
|
+
*
|
|
350
|
+
* It bounds impersonation, it does not eliminate it — a client that controls
|
|
351
|
+
* evil.test can still host a copy of someone else's artwork there. That is why
|
|
352
|
+
* the consent screen keeps showing the destination and the trust badge.
|
|
353
|
+
*/
|
|
354
|
+
export function sameHostHttps(value, clientId) {
|
|
355
|
+
if (typeof value !== "string" || !value)
|
|
356
|
+
return undefined;
|
|
357
|
+
try {
|
|
358
|
+
const candidate = new URL(value);
|
|
359
|
+
const base = new URL(clientId);
|
|
360
|
+
if (candidate.protocol !== "https:")
|
|
361
|
+
return undefined;
|
|
362
|
+
if (candidate.hostname !== base.hostname)
|
|
363
|
+
return undefined;
|
|
364
|
+
return value;
|
|
365
|
+
}
|
|
366
|
+
catch {
|
|
367
|
+
return undefined;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
//# sourceMappingURL=cimd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cimd.js","sourceRoot":"","sources":["../../src/handlers/cimd.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,2EAA2E;AAC3E,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,GAAG,IAAI,CAAC;AACvC,8EAA8E;AAC9E,MAAM,CAAC,MAAM,qBAAqB,GAAG,KAAK,CAAC;AAC3C,sEAAsE;AACtE,MAAM,CAAC,MAAM,wBAAwB,GAAG,EAAE,GAAG,EAAE,CAAC;AAChD,mFAAmF;AACnF,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,GAAG,EAAE,CAAC;AAC3C,MAAM,CAAC,MAAM,oBAAoB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;AAEjD,MAAM,YAAY,GAAG,OAAO,CAAC;AAE7B,oEAAoE;AACpE,MAAM,sBAAsB,GAAG,IAAI,GAAG,CAAC;IACrC,oBAAoB;IACpB,qBAAqB;IACrB,mBAAmB;CACpB,CAAC,CAAC;AAuBH;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,KAAa;IAC1C,OAAO,KAAK,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;AACrE,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAa;IAC7C,IAAI,GAAQ,CAAC;IACb,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,8BAA8B,EAAE,CAAC;IAC/D,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,8BAA8B,EAAE,CAAC;IAC/D,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;QACjC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,yCAAyC,EAAE,CAAC;IAC1E,CAAC;IACD,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;QACb,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,2CAA2C,EAAE,CAAC;IAC5E,CAAC;IACD,uEAAuE;IACvE,IAAI,GAAG,CAAC,QAAQ,KAAK,GAAG,IAAI,GAAG,CAAC,QAAQ,KAAK,EAAE,EAAE,CAAC;QAChD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,6CAA6C,EAAE,CAAC;IAC9E,CAAC;IACD,0EAA0E;IAC1E,0EAA0E;IAC1E,4EAA4E;IAC5E,sDAAsD;IACtD,IAAI,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,kDAAkD,EAAE,CAAC;IACnF,CAAC;IACD,IAAI,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QAChC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,6CAA6C,EAAE,CAAC;IAC9E,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;AAC3B,CAAC;AAED;;;GAGG;AACH,SAAS,aAAa,CAAC,GAAW;IAChC,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACrC,MAAM,SAAS,GAAG,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE,SAAS,GAAG,CAAC,CAAC,CAAC;IACvE,IAAI,SAAS,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IAChC,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACzD,OAAO,IAAI;SACR,WAAW,EAAE;SACb,KAAK,CAAC,GAAG,CAAC;SACV,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE;QACZ,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QACzC,OAAO,OAAO,KAAK,GAAG,IAAI,OAAO,KAAK,IAAI,CAAC;IAC7C,CAAC,CAAC,CAAC;AACP,CAAC;AAED,SAAS,aAAa,CAAC,QAAgB;IACrC,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IAC5D,IAAI,IAAI,KAAK,WAAW,IAAI,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC;QAAE,OAAO,IAAI,CAAC;IAErE,8EAA8E;IAC9E,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,8CAA8C,CAAC,CAAC;IACtE,IAAI,EAAE,EAAE,CAAC;QACP,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9C,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QAClD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE;YAAE,OAAO,IAAI,CAAC;QACjD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG;YAAE,OAAO,IAAI,CAAC;QACxC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG;YAAE,OAAO,IAAI,CAAC;QACxC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,GAAG;YAAE,OAAO,IAAI,CAAC;QAClD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,0EAA0E;IAC1E,6DAA6D;IAC7D,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACvB,IAAI,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC;QACjD,IAAI,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QACjD,IAAI,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QACjD,uDAAuD;QACvD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,8CAA8C,CAAC,CAAC;QAC1E,IAAI,MAAM;YAAE,OAAO,aAAa,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,CAAC;QAC7C,0EAA0E;QAC1E,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAC;QACnE,IAAI,GAAG,EAAE,CAAC;YACR,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAE,EAAE,EAAE,CAAC,CAAC;YAC1C,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAE,EAAE,EAAE,CAAC,CAAC;YACzC,OAAO,aAAa,CAClB,CAAC,IAAI,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC,EAAE,GAAG,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CACzD,CAAC;QACJ,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,QAAgB,EAChB,oBAA8C,EAC9C,OAAiB,EAAE;IAEnB,MAAM,OAAO,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IAC5C,IAAI,CAAC,OAAO,CAAC,EAAE;QAAE,OAAO,OAAO,CAAC;IAEhC,MAAM,QAAQ,GAAG,GAAG,YAAY,GAAG,QAAQ,EAAE,CAAC;IAC9C,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QAC7D,IAAI,GAAG,EAAE,CAAC;YACR,MAAM,MAAM,GAAG,iBAAiB,CAAC,GAAG,EAAE,QAAQ,EAAE,oBAAoB,CAAC,CAAC;YACtE,qEAAqE;YACrE,iDAAiD;YACjD,IAAI,MAAM,CAAC,EAAE;gBAAE,OAAO,MAAM,CAAC;QAC/B,CAAC;IACH,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,KAAK,CAAC;IAC1C,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,qBAAqB,CAAC,CAAC;IAE1E,IAAI,QAAkB,CAAC;IACvB,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE;YACjD,MAAM,EAAE,KAAK;YACb,QAAQ,EAAE,OAAO;YACjB,OAAO,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE;YACvC,MAAM,EAAE,UAAU,CAAC,MAAM;SAC1B,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;YAChB,OAAO,EAAE,6BAA6B;YACtC,GAAG,EAAE,UAAU;YACf,QAAQ;YACR,GAAG;SACJ,CAAC,CAAC;QACH,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,kDAAkD,EAAE,CAAC;IACnF,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,6CAA6C,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;IAC/F,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,IAAI,EAAE,CAAC,CAAC;IACtE,IAAI,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,QAAQ,GAAG,cAAc,EAAE,CAAC;QAC3D,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,0CAA0C,EAAE,CAAC;IAC3E,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;IACxD,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QAClB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,0CAA0C,EAAE,CAAC;IAC3E,CAAC;IAED,MAAM,MAAM,GAAG,iBAAiB,CAAC,IAAI,EAAE,QAAQ,EAAE,oBAAoB,CAAC,CAAC;IACvE,IAAI,CAAC,MAAM,CAAC,EAAE;QAAE,OAAO,MAAM,CAAC;IAE9B,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,MAAM,GAAG,GAAG,YAAY,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC;QAChE,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAC5D,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,sEAAsE;AACtE,KAAK,UAAU,UAAU,CAAC,QAAkB,EAAE,GAAW;IACvD,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;QACnB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;QACnD,OAAO,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IACzC,CAAC;IACD,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;IACzC,MAAM,MAAM,GAAiB,EAAE,CAAC;IAChC,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,CAAC;QACH,OAAO,IAAI,EAAE,CAAC;YACZ,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;YAC5C,IAAI,IAAI;gBAAE,MAAM;YAChB,IAAI,CAAC,KAAK;gBAAE,SAAS;YACrB,KAAK,IAAI,KAAK,CAAC,UAAU,CAAC;YAC1B,IAAI,KAAK,GAAG,GAAG,EAAE,CAAC;gBAChB,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;gBACtC,OAAO,IAAI,CAAC;YACd,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC;IACrC,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,UAAU,CAAC;IAC7B,CAAC;IACD,OAAO,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AAC1C,CAAC;AAED,kFAAkF;AAClF,SAAS,YAAY,CAAC,YAA2B;IAC/C,IAAI,CAAC,YAAY;QAAE,OAAO,wBAAwB,CAAC;IACnD,MAAM,OAAO,GAAG,YAAY,CAAC,WAAW,EAAE,CAAC;IAC3C,IAAI,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;QAAE,OAAO,oBAAoB,CAAC;IAC9F,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;IACnD,IAAI,CAAC,KAAK;QAAE,OAAO,wBAAwB,CAAC;IAC5C,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACjC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC;QAAE,OAAO,wBAAwB,CAAC;IAC/D,OAAO,IAAI,CAAC,GAAG,CAAC,oBAAoB,EAAE,IAAI,CAAC,GAAG,CAAC,oBAAoB,EAAE,OAAO,CAAC,CAAC,CAAC;AACjF,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,IAAY,EACZ,QAAgB,EAChB,oBAA8C;IAE9C,IAAI,GAAY,CAAC;IACjB,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,+CAA+C,EAAE,CAAC;IAChF,CAAC;IACD,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1D,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,mDAAmD,EAAE,CAAC;IACpF,CAAC;IACD,MAAM,GAAG,GAAG,GAA8B,CAAC;IAE3C,2EAA2E;IAC3E,yEAAyE;IACzE,IAAI,GAAG,CAAC,SAAS,KAAK,QAAQ,EAAE,CAAC;QAC/B,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,uDAAuD,EAAE,CAAC;IACxF,CAAC;IACD,IAAI,eAAe,IAAI,GAAG,IAAI,0BAA0B,IAAI,GAAG,EAAE,CAAC;QAChE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,4DAA4D,EAAE,CAAC;IAC7F,CAAC;IACD,IACE,OAAO,GAAG,CAAC,0BAA0B,KAAK,QAAQ;QAClD,sBAAsB,CAAC,GAAG,CAAC,GAAG,CAAC,0BAA0B,CAAC,EAC1D,CAAC;QACD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,kEAAkE,EAAE,CAAC;IACnG,CAAC;IAED,MAAM,UAAU,GAAG,mBAAmB,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IACxD,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,oDAAoD,EAAE,CAAC;IACrF,CAAC;IAED,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,GAAG,CAAC,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,sDAAsD,EAAE,CAAC;IACvF,CAAC;IACD,MAAM,YAAY,GAAa,EAAE,CAAC;IAClC,KAAK,MAAM,GAAG,IAAI,GAAG,CAAC,aAAa,EAAE,CAAC;QACpC,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1D,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,0DAA0D,EAAE,CAAC;QAC3F,CAAC;QACD,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;IAED,MAAM,SAAS,GAAG,OAAO,GAAG,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC;IAClF,wEAAwE;IACxE,uEAAuE;IACvE,MAAM,OAAO,GAAG,aAAa,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAEtD,OAAO;QACL,EAAE,EAAE,IAAI;QACR,MAAM,EAAE;YACN,QAAQ;YACR,UAAU;YACV,GAAG,CAAC,SAAS,IAAI,aAAa,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACzE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/B,YAAY;SACb;KACF,CAAC;AACJ,CAAC;AAED,0EAA0E;AAC1E,MAAM,CAAC,MAAM,aAAa,GAAG,EAAE,CAAC;AAEhC;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAc;IAChD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IAChD,MAAM,OAAO,GAAG,KAAK;QACnB,uFAAuF;SACtF,OAAO,CAAC,wBAAwB,EAAE,EAAE,CAAC;QACtC,6EAA6E;SAC5E,OAAO,CAAC,kDAAkD,EAAE,EAAE,CAAC;SAC/D,IAAI,EAAE,CAAC;IACV,IAAI,CAAC,OAAO;QAAE,OAAO,SAAS,CAAC;IAC/B,OAAO,OAAO,CAAC,MAAM,GAAG,aAAa;QACnC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,aAAa,CAAC,GAAG,QAAQ;QAC5C,CAAC,CAAC,OAAO,CAAC;AACd,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,aAAa,CAAC,KAAc,EAAE,QAAgB;IAC5D,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC1D,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;QACjC,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC/B,IAAI,SAAS,CAAC,QAAQ,KAAK,QAAQ;YAAE,OAAO,SAAS,CAAC;QACtD,IAAI,SAAS,CAAC,QAAQ,KAAK,IAAI,CAAC,QAAQ;YAAE,OAAO,SAAS,CAAC;QAC3D,OAAO,KAAK,CAAC;IACf,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC"}
|
|
@@ -39,10 +39,16 @@
|
|
|
39
39
|
import { type Logger } from "../logger.js";
|
|
40
40
|
import { type D1Store, type StoredOAuthClient } from "../store/d1-store.js";
|
|
41
41
|
import type { AccessKeyHandler } from "./access-key-handler.js";
|
|
42
|
+
import { type CimdDeps } from "./cimd.js";
|
|
42
43
|
import type { Auth } from "./passkey-handler.js";
|
|
43
44
|
/** Unverified estimate aligned with the epic: 1 hour OAuth access TTL. */
|
|
44
45
|
export declare const OAUTH_ACCESS_TTL_SECONDS: number;
|
|
45
|
-
/**
|
|
46
|
+
/**
|
|
47
|
+
* Grace period for an *unused* DCR registration — a drive-by or abandoned
|
|
48
|
+
* `POST /register` is swept after 7 days. Once a user actually consents to the
|
|
49
|
+
* client, {@link D1Store.clearOAuthClientExpiry} drops the TTL for good, so a
|
|
50
|
+
* connector in real use never expires out from under its owner.
|
|
51
|
+
*/
|
|
46
52
|
export declare const OAUTH_DCR_TTL_SECONDS: number;
|
|
47
53
|
/** Unverified estimate: DCR registrations per IP per window. */
|
|
48
54
|
export declare const OAUTH_DCR_RATE_LIMIT = 20;
|
|
@@ -57,6 +63,11 @@ export interface OAuthAsHandlerOptions {
|
|
|
57
63
|
accessKeyHandler?: AccessKeyHandler;
|
|
58
64
|
/** Override DCR per-IP rate limit (tests). Default {@link OAUTH_DCR_RATE_LIMIT}. */
|
|
59
65
|
dcrRateLimit?: number;
|
|
66
|
+
/**
|
|
67
|
+
* Outbound fetch used to retrieve Client ID Metadata Documents. Injectable so
|
|
68
|
+
* tests never touch the network; defaults to the global `fetch`.
|
|
69
|
+
*/
|
|
70
|
+
cimdFetch?: typeof fetch;
|
|
60
71
|
}
|
|
61
72
|
export type OAuthClientRecord = StoredOAuthClient;
|
|
62
73
|
export declare class OAuthAsHandler {
|
|
@@ -65,7 +76,37 @@ export declare class OAuthAsHandler {
|
|
|
65
76
|
private auth?;
|
|
66
77
|
private accessKeyHandler?;
|
|
67
78
|
private dcrRateLimit;
|
|
79
|
+
private cimdFetch?;
|
|
68
80
|
constructor(options: OAuthAsHandlerOptions);
|
|
81
|
+
/**
|
|
82
|
+
* Deps for the CIMD path: the injectable fetch plus a document cache backed
|
|
83
|
+
* by the existing kv_cache table (spec: respect HTTP cache headers, never
|
|
84
|
+
* cache an error or a malformed document).
|
|
85
|
+
*/
|
|
86
|
+
private cimdDeps;
|
|
87
|
+
/**
|
|
88
|
+
* Durable record of an OAuth lifecycle event.
|
|
89
|
+
*
|
|
90
|
+
* Denial logs answer "why did this fail?" but roll away; this answers "who
|
|
91
|
+
* authorised which client, when, and what was minted" months later. Never
|
|
92
|
+
* carries a code, verifier, token secret, or refresh token — access key IDs
|
|
93
|
+
* are identifiers, not credentials.
|
|
94
|
+
*
|
|
95
|
+
* Audit failure must not fail the authorization it describes, but it must be
|
|
96
|
+
* visible: a silent catch here would defeat the point of having an audit.
|
|
97
|
+
*/
|
|
98
|
+
private audit;
|
|
99
|
+
/**
|
|
100
|
+
* Single funnel for every rejection this handler emits. Before this existed
|
|
101
|
+
* the AS had 51 error returns and 5 log lines, so a client that stopped
|
|
102
|
+
* working ("invalid_client", "Invalid redirect_uri") left no server-side
|
|
103
|
+
* trace and had to be diagnosed by guesswork. One structured record per
|
|
104
|
+
* denial, carrying stage + error + reason + non-secret request identity.
|
|
105
|
+
*
|
|
106
|
+
* Deliberately never logs a code, code_verifier, access/refresh token, or
|
|
107
|
+
* session secret — {@link DenyContext} is the allowlist.
|
|
108
|
+
*/
|
|
109
|
+
private deny;
|
|
69
110
|
fetch(request: Request, instanceDid?: string): Promise<Response | null>;
|
|
70
111
|
/** GET /.well-known/oauth-authorization-server — RFC 8414 */
|
|
71
112
|
private metadata;
|
|
@@ -108,10 +149,70 @@ export declare class OAuthAsHandler {
|
|
|
108
149
|
private refreshTokenGrant;
|
|
109
150
|
}
|
|
110
151
|
/**
|
|
111
|
-
*
|
|
112
|
-
*
|
|
152
|
+
* A client the AS is willing to run an authorization for, from any of the
|
|
153
|
+
* three MCP registration mechanisms. `clientName` is populated for CIMD (and
|
|
154
|
+
* for DCR clients that supplied one) so the consent screen can show something
|
|
155
|
+
* a human recognises instead of an opaque id.
|
|
156
|
+
*/
|
|
157
|
+
export interface ResolvedOAuthClient {
|
|
158
|
+
clientId: string;
|
|
159
|
+
redirectUris: string[];
|
|
160
|
+
source: "dcr" | "pre-registered" | "cimd";
|
|
161
|
+
/** null = no TTL (pre-registered, consented DCR, or CIMD). */
|
|
162
|
+
expiresAt: string | null;
|
|
163
|
+
clientName?: string;
|
|
164
|
+
clientUri?: string;
|
|
165
|
+
logoUri?: string;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Stored row (pre-registered ∪ DCR) first, then CIMD for URL-shaped client_ids.
|
|
169
|
+
* Expired DCR rows are treated as unknown. Device grant must NOT call this
|
|
170
|
+
* (unregistered client_id stays valid there).
|
|
171
|
+
*/
|
|
172
|
+
export declare function resolveOAuthClient(store: D1Store, clientId: string, deps?: CimdDeps): Promise<ResolvedOAuthClient | null>;
|
|
173
|
+
/**
|
|
174
|
+
* CIMD (Client ID Metadata Document) — draft-ietf-oauth-client-id-metadata-document-00.
|
|
175
|
+
* The MCP spec now prefers this over DCR: the client_id is an https URL the AS
|
|
176
|
+
* fetches, so the displayed identity is bound to a domain the client controls.
|
|
177
|
+
*/
|
|
178
|
+
export declare function resolveCimdClient(clientId: string, deps?: CimdDeps): Promise<ResolvedOAuthClient | null>;
|
|
179
|
+
/** What the consent screen shows about the requesting client. */
|
|
180
|
+
export interface OAuthConsentDisplay {
|
|
181
|
+
/** Human-readable name, when the client supplied a usable one. */
|
|
182
|
+
clientName?: string;
|
|
183
|
+
/**
|
|
184
|
+
* https logo on the client's own host (CIMD only). Same-host binding limits
|
|
185
|
+
* impersonation but does not remove it — a client can host a copy of anyone's
|
|
186
|
+
* artwork on its own domain — so the destination and badge stay authoritative.
|
|
187
|
+
*/
|
|
188
|
+
logoUri?: string;
|
|
189
|
+
/** Raw client_id, for support/debugging — never the headline. */
|
|
190
|
+
clientId: string;
|
|
191
|
+
/**
|
|
192
|
+
* Where the authorization code will actually be delivered. This is the
|
|
193
|
+
* anti-phishing anchor: a client can claim any name, but it cannot claim a
|
|
194
|
+
* destination it does not control.
|
|
195
|
+
*/
|
|
196
|
+
destination: {
|
|
197
|
+
kind: "web" | "device" | "app";
|
|
198
|
+
label: string;
|
|
199
|
+
};
|
|
200
|
+
/**
|
|
201
|
+
* The domain the identity is bound to, for CIMD clients. The whole point of
|
|
202
|
+
* CIMD is this binding, and the spec asks the AS to show the client_id's
|
|
203
|
+
* hostname on the authorization interface — so it must reach the screen.
|
|
204
|
+
*/
|
|
205
|
+
verifiedHost?: string;
|
|
206
|
+
/**
|
|
207
|
+
* cimd = identity bound to a domain the client proved it controls.
|
|
208
|
+
* pre-registered = an operator vouched for it.
|
|
209
|
+
* dcr = self-asserted; the name means nothing on its own.
|
|
210
|
+
*/
|
|
211
|
+
trust: "cimd" | "pre-registered" | "dcr";
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Build the consent-screen descriptor from a stored authorization session.
|
|
215
|
+
* Server-side only — the page must never assemble this from its query string.
|
|
113
216
|
*/
|
|
114
|
-
export declare function
|
|
115
|
-
/** CIMD (Client ID Metadata Document) — stub only this wave. */
|
|
116
|
-
export declare function resolveCimdClient(_clientId: string): Promise<OAuthClientRecord | null>;
|
|
217
|
+
export declare function describeOAuthConsent(source: string): OAuthConsentDisplay | null;
|
|
117
218
|
//# sourceMappingURL=oauth-as-handler.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth-as-handler.d.ts","sourceRoot":"","sources":["../../src/handlers/oauth-as-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;
|
|
1
|
+
{"version":3,"file":"oauth-as-handler.d.ts","sourceRoot":"","sources":["../../src/handlers/oauth-as-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAMH,OAAO,EAAiB,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAE1D,OAAO,EAAE,KAAK,OAAO,EAA6B,KAAK,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAEvG,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EACL,KAAK,QAAQ,EAKd,MAAM,WAAW,CAAC;AACnB,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAgBjD,0EAA0E;AAC1E,eAAO,MAAM,wBAAwB,QAAU,CAAC;AAEhD;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,QAAmB,CAAC;AACtD,gEAAgE;AAChE,eAAO,MAAM,oBAAoB,KAAK,CAAC;AACvC,eAAO,MAAM,wBAAwB,QAAiB,CAAC;AAmBvD,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,OAAO,CAAC;IACf,qDAAqD;IACrD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wDAAwD;IACxD,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,iEAAiE;IACjE,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,oFAAoF;IACpF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AAED,MAAM,MAAM,iBAAiB,GAAG,iBAAiB,CAAC;AA0ElD,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAAU;IACvB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,IAAI,CAAC,CAAO;IACpB,OAAO,CAAC,gBAAgB,CAAC,CAAmB;IAC5C,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,SAAS,CAAC,CAAe;gBAErB,OAAO,EAAE,qBAAqB;IAS1C;;;;OAIG;IACH,OAAO,CAAC,QAAQ;IAWhB;;;;;;;;;;OAUG;YACW,KAAK;IAyBnB;;;;;;;;;OASG;IACH,OAAO,CAAC,IAAI;IAgBN,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;IAsC7E,6DAA6D;IAC7D,OAAO,CAAC,QAAQ;IAoBhB;;;;OAIG;YACW,QAAQ;IAwDtB;;;;OAIG;YACW,YAAY;IA+E1B;;;;OAIG;YACW,aAAa;IAgK3B;;;OAGG;YACW,mBAAmB;IAkCjC;;;OAGG;YACW,KAAK;IA8FnB;;OAEG;YACW,sBAAsB;IAwMpC;;;OAGG;YACW,iBAAiB;CA8GhC;AA6KD;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,MAAM,EAAE,KAAK,GAAG,gBAAgB,GAAG,MAAM,CAAC;IAC1C,8DAA8D;IAC9D,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE,QAAQ,GACd,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAiBrC;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE,QAAQ,GACd,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAqBrC;AA4LD,iEAAiE;AACjE,MAAM,WAAW,mBAAmB;IAClC,kEAAkE;IAClE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iEAAiE;IACjE,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,WAAW,EAAE;QAAE,IAAI,EAAE,KAAK,GAAG,QAAQ,GAAG,KAAK,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/D;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,KAAK,EAAE,MAAM,GAAG,gBAAgB,GAAG,KAAK,CAAC;CAC1C;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,mBAAmB,GAAG,IAAI,CAY/E"}
|