mcp-trellis 2.2.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +61 -52
- package/dist/adapters/node-request.d.ts +5 -0
- package/dist/adapters/node-request.d.ts.map +1 -1
- package/dist/adapters/node-request.js +17 -1
- package/dist/adapters/node-request.js.map +1 -1
- package/dist/adapters/node.d.ts +15 -0
- package/dist/adapters/node.d.ts.map +1 -1
- package/dist/adapters/node.js +38 -0
- package/dist/adapters/node.js.map +1 -1
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +1 -0
- package/dist/app.js.map +1 -1
- package/dist/audit.d.ts.map +1 -1
- package/dist/audit.js +63 -6
- package/dist/audit.js.map +1 -1
- package/dist/auth/signed/payload.d.ts +31 -0
- package/dist/auth/signed/payload.d.ts.map +1 -0
- package/dist/auth/signed/payload.js +85 -0
- package/dist/auth/signed/payload.js.map +1 -0
- package/dist/auth/signed/refresh.d.ts +34 -0
- package/dist/auth/signed/refresh.d.ts.map +1 -0
- package/dist/auth/signed/refresh.js +95 -0
- package/dist/auth/signed/refresh.js.map +1 -0
- package/dist/auth/signed/token.d.ts +41 -0
- package/dist/auth/signed/token.d.ts.map +1 -0
- package/dist/auth/signed/token.js +103 -0
- package/dist/auth/signed/token.js.map +1 -0
- package/dist/clients.js +2 -2
- package/dist/clients.js.map +1 -1
- package/dist/deprecated.d.ts +15 -15
- package/dist/deprecated.d.ts.map +1 -1
- package/dist/deprecated.js +15 -15
- package/dist/deprecated.js.map +1 -1
- package/dist/http/body.d.ts +4 -0
- package/dist/http/body.d.ts.map +1 -1
- package/dist/http/body.js +9 -2
- package/dist/http/body.js.map +1 -1
- package/dist/http/origins.d.ts.map +1 -1
- package/dist/http/origins.js +13 -2
- package/dist/http/origins.js.map +1 -1
- package/dist/mcp/dispatch.d.ts.map +1 -1
- package/dist/mcp/dispatch.js +2 -1
- package/dist/mcp/dispatch.js.map +1 -1
- package/dist/mcp/methods.d.ts +8 -0
- package/dist/mcp/methods.d.ts.map +1 -1
- package/dist/mcp/methods.js +14 -1
- package/dist/mcp/methods.js.map +1 -1
- package/dist/mcp/registry.d.ts.map +1 -1
- package/dist/mcp/registry.js +15 -3
- package/dist/mcp/registry.js.map +1 -1
- package/dist/mcp/rpc-handlers.d.ts.map +1 -1
- package/dist/mcp/rpc-handlers.js +60 -13
- package/dist/mcp/rpc-handlers.js.map +1 -1
- package/dist/mcp/tools.d.ts +14 -0
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +118 -23
- package/dist/mcp/tools.js.map +1 -1
- package/dist/mcp/validate.d.ts +7 -1
- package/dist/mcp/validate.d.ts.map +1 -1
- package/dist/mcp/validate.js +58 -24
- package/dist/mcp/validate.js.map +1 -1
- package/dist/oauth/audit.d.ts +10 -0
- package/dist/oauth/audit.d.ts.map +1 -1
- package/dist/oauth/audit.js +25 -1
- package/dist/oauth/audit.js.map +1 -1
- package/dist/oauth/cimd/cimd-parse.d.ts.map +1 -1
- package/dist/oauth/cimd/cimd-parse.js +27 -14
- package/dist/oauth/cimd/cimd-parse.js.map +1 -1
- package/dist/oauth/cimd/cimd-ssrf.d.ts +8 -4
- package/dist/oauth/cimd/cimd-ssrf.d.ts.map +1 -1
- package/dist/oauth/cimd/cimd-ssrf.js +13 -39
- package/dist/oauth/cimd/cimd-ssrf.js.map +1 -1
- package/dist/oauth/cimd/cimd.d.ts +14 -18
- package/dist/oauth/cimd/cimd.d.ts.map +1 -1
- package/dist/oauth/cimd/cimd.js +53 -37
- package/dist/oauth/cimd/cimd.js.map +1 -1
- package/dist/oauth/cimd/dns.d.ts +4 -0
- package/dist/oauth/cimd/dns.d.ts.map +1 -0
- package/dist/oauth/cimd/dns.js +45 -0
- package/dist/oauth/cimd/dns.js.map +1 -0
- package/dist/oauth/cimd/failure.d.ts +19 -0
- package/dist/oauth/cimd/failure.d.ts.map +1 -0
- package/dist/oauth/cimd/failure.js +31 -0
- package/dist/oauth/cimd/failure.js.map +1 -0
- package/dist/oauth/cimd/types.d.ts +15 -1
- package/dist/oauth/cimd/types.d.ts.map +1 -1
- package/dist/oauth/cimd/types.js +1 -1
- package/dist/oauth/cimd/types.js.map +1 -1
- package/dist/oauth/cimd/url-guard.d.ts +5 -0
- package/dist/oauth/cimd/url-guard.d.ts.map +1 -0
- package/dist/oauth/cimd/url-guard.js +53 -0
- package/dist/oauth/cimd/url-guard.js.map +1 -0
- package/dist/oauth/config.d.ts +3 -0
- package/dist/oauth/config.d.ts.map +1 -1
- package/dist/oauth/config.js +5 -1
- package/dist/oauth/config.js.map +1 -1
- package/dist/oauth/crypto/clientauth.d.ts.map +1 -1
- package/dist/oauth/crypto/clientauth.js +7 -6
- package/dist/oauth/crypto/clientauth.js.map +1 -1
- package/dist/oauth/deprecated.d.ts +22 -22
- package/dist/oauth/deprecated.d.ts.map +1 -1
- package/dist/oauth/deprecated.js +22 -22
- package/dist/oauth/deprecated.js.map +1 -1
- package/dist/oauth/endpoints/authorize.d.ts.map +1 -1
- package/dist/oauth/endpoints/authorize.js +25 -7
- package/dist/oauth/endpoints/authorize.js.map +1 -1
- package/dist/oauth/endpoints/consent/error-page.d.ts +6 -0
- package/dist/oauth/endpoints/consent/error-page.d.ts.map +1 -0
- package/dist/oauth/endpoints/consent/error-page.js +60 -0
- package/dist/oauth/endpoints/consent/error-page.js.map +1 -0
- package/dist/oauth/endpoints/{consent.d.ts → consent/handler.d.ts} +2 -2
- package/dist/oauth/endpoints/consent/handler.d.ts.map +1 -0
- package/dist/oauth/endpoints/{consent.js → consent/handler.js} +20 -13
- package/dist/oauth/endpoints/consent/handler.js.map +1 -0
- package/dist/oauth/endpoints/{consent-page.d.ts → consent/page.d.ts} +2 -2
- package/dist/oauth/endpoints/consent/page.d.ts.map +1 -0
- package/dist/oauth/endpoints/consent/page.js +106 -0
- package/dist/oauth/endpoints/consent/page.js.map +1 -0
- package/dist/oauth/endpoints/metadata.d.ts +0 -1
- package/dist/oauth/endpoints/metadata.d.ts.map +1 -1
- package/dist/oauth/endpoints/metadata.js.map +1 -1
- package/dist/oauth/endpoints/register.js +3 -3
- package/dist/oauth/endpoints/register.js.map +1 -1
- package/dist/oauth/endpoints/token.d.ts.map +1 -1
- package/dist/oauth/endpoints/token.js +9 -6
- package/dist/oauth/endpoints/token.js.map +1 -1
- package/dist/oauth/endpoints/wellknown.d.ts.map +1 -1
- package/dist/oauth/endpoints/wellknown.js +2 -9
- package/dist/oauth/endpoints/wellknown.js.map +1 -1
- package/dist/oauth/policy/redirect.d.ts +4 -0
- package/dist/oauth/policy/redirect.d.ts.map +1 -1
- package/dist/oauth/policy/redirect.js +15 -1
- package/dist/oauth/policy/redirect.js.map +1 -1
- package/dist/oauth/policy/reqbody.d.ts +6 -1
- package/dist/oauth/policy/reqbody.d.ts.map +1 -1
- package/dist/oauth/policy/reqbody.js +8 -3
- package/dist/oauth/policy/reqbody.js.map +1 -1
- package/dist/oauth/router.js +1 -1
- package/dist/oauth/router.js.map +1 -1
- package/dist/oauth/types.d.ts +3 -1
- package/dist/oauth/types.d.ts.map +1 -1
- package/dist/server.d.ts +1 -1
- package/dist/server.js +1 -1
- package/dist/util/clip.d.ts +7 -0
- package/dist/util/clip.d.ts.map +1 -0
- package/dist/util/clip.js +13 -0
- package/dist/util/clip.js.map +1 -0
- package/dist/util/json.d.ts +5 -0
- package/dist/util/json.d.ts.map +1 -1
- package/dist/util/json.js +21 -0
- package/dist/util/json.js.map +1 -1
- package/dist/util/own.d.ts +8 -0
- package/dist/util/own.d.ts.map +1 -0
- package/dist/util/own.js +8 -0
- package/dist/util/own.js.map +1 -0
- package/docs/ROADMAP.md +17 -229
- package/docs/compatibility.md +15 -3
- package/docs/guide.md +15 -4
- package/docs/reference.md +5 -3
- package/docs/security.md +63 -7
- package/docs/troubleshooting.md +4 -0
- package/package.json +7 -4
- package/dist/auth/signed-token.d.ts +0 -26
- package/dist/auth/signed-token.d.ts.map +0 -1
- package/dist/auth/signed-token.js +0 -96
- package/dist/auth/signed-token.js.map +0 -1
- package/dist/oauth/endpoints/consent-page.d.ts.map +0 -1
- package/dist/oauth/endpoints/consent-page.js +0 -63
- package/dist/oauth/endpoints/consent-page.js.map +0 -1
- package/dist/oauth/endpoints/consent.d.ts.map +0 -1
- package/dist/oauth/endpoints/consent.js.map +0 -1
- package/docs/diagrams/demo-tool-result.png +0 -0
- package/docs/diagrams/mcp-trellis-architecture.html +0 -305
package/dist/mcp/tools.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* an arbitrary Standard Schema validator. `input`, when supplied, is what
|
|
8
8
|
* actually parses and types `args` at call time — keep the two in sync.
|
|
9
9
|
*/
|
|
10
|
-
import { BodyTooLargeError, DEFAULT_MCP_BODY_LIMIT, readBoundedBytes } from "../http/body.js";
|
|
10
|
+
import { BodyReadAbortedError, BodyTooLargeError, DEFAULT_MCP_BODY_LIMIT, readBoundedBytes, } from "../http/body.js";
|
|
11
11
|
import { pickDefined } from "../util/defined.js";
|
|
12
12
|
const pathToString = (path) => (path ?? [])
|
|
13
13
|
.map((segment) => segment && typeof segment === "object" && "key" in segment
|
|
@@ -59,34 +59,117 @@ const defaultRespond = (res) => res.text();
|
|
|
59
59
|
*/
|
|
60
60
|
const defaultErrorResult = (res) => {
|
|
61
61
|
const status = [res.status, res.statusText].filter(Boolean).join(" ");
|
|
62
|
+
// A redirect is not followed by default; an opaque one (some runtimes) has
|
|
63
|
+
// status 0. Say so, or a previously working http→https hop just "fails".
|
|
64
|
+
const isRedirect = res.type === "opaqueredirect" || (res.status >= 300 && res.status < 400);
|
|
65
|
+
const hint = isRedirect ? ' (redirect not followed; set redirect: "follow" to allow it)' : "";
|
|
62
66
|
return {
|
|
63
|
-
content: [{ type: "text", text: `Request failed: ${status}` }],
|
|
67
|
+
content: [{ type: "text", text: `Request failed: ${status}${hint}` }],
|
|
64
68
|
isError: true,
|
|
65
69
|
};
|
|
66
70
|
};
|
|
67
71
|
const DEFAULT_API_TOOL_TIMEOUT_MS = 30_000;
|
|
68
72
|
const isTimeoutError = (caught) => {
|
|
69
|
-
if (
|
|
70
|
-
return
|
|
71
|
-
return (caught.name === "TimeoutError" ||
|
|
72
|
-
caught.name === "AbortError" ||
|
|
73
|
-
caught.message === "body read aborted");
|
|
73
|
+
if (caught instanceof BodyReadAbortedError)
|
|
74
|
+
return true;
|
|
75
|
+
return (caught instanceof Error && (caught.name === "TimeoutError" || caught.name === "AbortError"));
|
|
74
76
|
};
|
|
75
77
|
const timedOutResult = (timeoutMs) => ({
|
|
76
|
-
content: [
|
|
78
|
+
content: [
|
|
79
|
+
{
|
|
80
|
+
type: "text",
|
|
81
|
+
text: timeoutMs === false ? "Request timed out" : `Request timed out after ${timeoutMs}ms`,
|
|
82
|
+
},
|
|
83
|
+
],
|
|
77
84
|
isError: true,
|
|
78
85
|
});
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
86
|
+
const cancelledResult = () => ({
|
|
87
|
+
content: [{ type: "text", text: "Request was cancelled" }],
|
|
88
|
+
isError: true,
|
|
89
|
+
});
|
|
90
|
+
/**
|
|
91
|
+
* The `ToolResult` for a caller abort or a timeout, or `null` for any other
|
|
92
|
+
* error. A caller abort is checked first and by signal state, not by error
|
|
93
|
+
* shape: `fetch` rejects with the abort *reason*, which is whatever the
|
|
94
|
+
* caller passed to `abort(...)` — not necessarily an `AbortError`.
|
|
95
|
+
*/
|
|
96
|
+
const abortResult = (caught, timeoutMs, callerSignal) => {
|
|
97
|
+
if (callerSignal?.aborted)
|
|
98
|
+
return cancelledResult();
|
|
99
|
+
return isTimeoutError(caught) ? timedOutResult(timeoutMs) : null;
|
|
100
|
+
};
|
|
101
|
+
const NOOP = () => { };
|
|
102
|
+
/**
|
|
103
|
+
* `AbortSignal.any` is Node >= 20.3; `engines` allows 20.0. The fallback
|
|
104
|
+
* follows whichever signal fires first and removes its listeners on
|
|
105
|
+
* `dispose` — a long-lived caller signal shared across many calls must not
|
|
106
|
+
* accumulate one listener per call.
|
|
107
|
+
*/
|
|
108
|
+
const anySignal = (signals) => {
|
|
109
|
+
if (typeof AbortSignal.any === "function") {
|
|
110
|
+
return { signal: AbortSignal.any(signals), dispose: NOOP };
|
|
111
|
+
}
|
|
112
|
+
const controller = new AbortController();
|
|
113
|
+
const listeners = [];
|
|
114
|
+
const dispose = () => {
|
|
115
|
+
for (const [signal, listener] of listeners)
|
|
116
|
+
signal.removeEventListener("abort", listener);
|
|
117
|
+
listeners.length = 0;
|
|
118
|
+
};
|
|
119
|
+
for (const signal of signals) {
|
|
120
|
+
if (signal.aborted) {
|
|
121
|
+
controller.abort(signal.reason);
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
const listener = () => {
|
|
125
|
+
controller.abort(signal.reason);
|
|
126
|
+
dispose();
|
|
127
|
+
};
|
|
128
|
+
signal.addEventListener("abort", listener, { once: true });
|
|
129
|
+
listeners.push([signal, listener]);
|
|
130
|
+
}
|
|
131
|
+
return { signal: controller.signal, dispose };
|
|
132
|
+
};
|
|
133
|
+
/** An aborted or timed-out fetch becomes a `ToolResult`; every other throw still propagates. */
|
|
134
|
+
const fetchWithTimeout = async ({ fetchImpl, input, timeoutMs, redirect, }) => {
|
|
135
|
+
const callerSignal = input instanceof Request ? input.signal : undefined;
|
|
136
|
+
if (timeoutMs === false) {
|
|
137
|
+
// Nothing to combine: `fetch` keeps the `Request`'s own signal, and the
|
|
138
|
+
// same signal is handed to the body read so a later abort stops it too.
|
|
139
|
+
try {
|
|
140
|
+
return {
|
|
141
|
+
response: await fetchImpl(input, { redirect }),
|
|
142
|
+
signal: callerSignal,
|
|
143
|
+
callerSignal,
|
|
144
|
+
dispose: NOOP,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
catch (caught) {
|
|
148
|
+
const aborted = abortResult(caught, timeoutMs, callerSignal);
|
|
149
|
+
if (aborted)
|
|
150
|
+
return aborted;
|
|
151
|
+
throw caught;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
// `init.signal` replaces a `Request`'s own signal — combine both so a
|
|
155
|
+
// caller's abort still cancels the call.
|
|
156
|
+
const timeoutSignal = AbortSignal.timeout(timeoutMs);
|
|
157
|
+
const combined = callerSignal
|
|
158
|
+
? anySignal([timeoutSignal, callerSignal])
|
|
159
|
+
: { signal: timeoutSignal, dispose: NOOP };
|
|
84
160
|
try {
|
|
85
|
-
return {
|
|
161
|
+
return {
|
|
162
|
+
response: await fetchImpl(input, { signal: combined.signal, redirect }),
|
|
163
|
+
signal: combined.signal,
|
|
164
|
+
callerSignal,
|
|
165
|
+
dispose: combined.dispose,
|
|
166
|
+
};
|
|
86
167
|
}
|
|
87
168
|
catch (caught) {
|
|
88
|
-
|
|
89
|
-
|
|
169
|
+
combined.dispose();
|
|
170
|
+
const aborted = abortResult(caught, timeoutMs, callerSignal);
|
|
171
|
+
if (aborted)
|
|
172
|
+
return aborted;
|
|
90
173
|
throw caught;
|
|
91
174
|
}
|
|
92
175
|
};
|
|
@@ -97,10 +180,10 @@ const fetchWithTimeout = async (fetchImpl, input, timeoutMs) => {
|
|
|
97
180
|
* raw bytes — not decoded text — so `respond`/`onError` can still call
|
|
98
181
|
* res.arrayBuffer()/res.blob() on binary bodies as well as res.text()/
|
|
99
182
|
* res.json(), exactly as if they'd read the original response themselves.
|
|
100
|
-
* An oversized body, or the timeout signal firing mid-body, becomes
|
|
101
|
-
* `ToolResult`; every other throw still propagates.
|
|
183
|
+
* An oversized body, or the timeout or caller signal firing mid-body, becomes
|
|
184
|
+
* a `ToolResult`; every other throw still propagates.
|
|
102
185
|
*/
|
|
103
|
-
const boundResponse = async (res, maxResponseBytes, timeoutMs, signal) => {
|
|
186
|
+
const boundResponse = async (res, maxResponseBytes, timeoutMs, { signal, callerSignal }) => {
|
|
104
187
|
let bytes;
|
|
105
188
|
try {
|
|
106
189
|
bytes = (await readBoundedBytes(res, maxResponseBytes, signal));
|
|
@@ -112,8 +195,9 @@ const boundResponse = async (res, maxResponseBytes, timeoutMs, signal) => {
|
|
|
112
195
|
isError: true,
|
|
113
196
|
};
|
|
114
197
|
}
|
|
115
|
-
|
|
116
|
-
|
|
198
|
+
const aborted = abortResult(caught, timeoutMs, callerSignal);
|
|
199
|
+
if (aborted)
|
|
200
|
+
return aborted;
|
|
117
201
|
throw caught;
|
|
118
202
|
}
|
|
119
203
|
// The buffered body is already decoded and re-framed — the upstream
|
|
@@ -127,11 +211,22 @@ const runApi = async (options, ctx, args) => {
|
|
|
127
211
|
const fetchImpl = options.fetch ?? fetch;
|
|
128
212
|
const input = await options.request(ctx, args);
|
|
129
213
|
const timeoutMs = options.timeoutMs ?? DEFAULT_API_TOOL_TIMEOUT_MS;
|
|
130
|
-
const fetched = await fetchWithTimeout(
|
|
214
|
+
const fetched = await fetchWithTimeout({
|
|
215
|
+
fetchImpl,
|
|
216
|
+
input,
|
|
217
|
+
timeoutMs,
|
|
218
|
+
redirect: options.redirect ?? "manual",
|
|
219
|
+
});
|
|
131
220
|
if (!("response" in fetched))
|
|
132
221
|
return fetched;
|
|
133
222
|
const maxResponseBytes = options.maxResponseBytes ?? DEFAULT_MCP_BODY_LIMIT;
|
|
134
|
-
|
|
223
|
+
let bounded;
|
|
224
|
+
try {
|
|
225
|
+
bounded = await boundResponse(fetched.response, maxResponseBytes, timeoutMs, fetched);
|
|
226
|
+
}
|
|
227
|
+
finally {
|
|
228
|
+
fetched.dispose();
|
|
229
|
+
}
|
|
135
230
|
if (!(bounded instanceof Response))
|
|
136
231
|
return bounded;
|
|
137
232
|
if (!bounded.ok)
|
package/dist/mcp/tools.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/mcp/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/mcp/tools.ts"],"names":[],"mappings":"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"}
|
package/dist/mcp/validate.d.ts
CHANGED
|
@@ -44,6 +44,12 @@ export declare const unsupportedKeywords: (schema: JsonSchema, path?: string) =>
|
|
|
44
44
|
* reach validation unchecked.
|
|
45
45
|
*/
|
|
46
46
|
export declare const missingObjectType: (schema: JsonSchema, path?: string) => string[];
|
|
47
|
-
/**
|
|
47
|
+
/** Errors reported for one value before validation stops looking for more. */
|
|
48
|
+
export declare const MAX_VALIDATION_ERRORS = 20;
|
|
49
|
+
/**
|
|
50
|
+
* Minimal JSON Schema subset used by MCP tool inputSchema. Empty = valid.
|
|
51
|
+
* Reports at most `MAX_VALIDATION_ERRORS` violations — enough to fix a call,
|
|
52
|
+
* bounded however large or hostile the arguments are.
|
|
53
|
+
*/
|
|
48
54
|
export declare const validateAgainstSchema: (value: unknown, schema: JsonSchema) => string[];
|
|
49
55
|
//# sourceMappingURL=validate.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/mcp/validate.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/mcp/validate.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,UAAU,GAAG;IACvB,6EAA6E;IAC7E,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACxC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC;IACjB,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+EAA+E;IAC/E,oBAAoB,CAAC,EAAE,OAAO,GAAG,UAAU,CAAC;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAEF,eAAO,MAAM,iBAAiB;;;;;;;;CAQpB,CAAC;AAkBX,2DAA2D;AAC3D,eAAO,MAAM,yBAAyB,EAAE,WAAW,CAAC,MAAM,CASxD,CAAC;AAUH;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,EAAE,WAAW,CAAC,MAAM,CAYtD,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,mBAAmB,GAAI,QAAQ,UAAU,EAAE,aAAa,KAAG,MAAM,EAU7E,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,GAAI,QAAQ,UAAU,EAAE,aAAa,KAAG,MAAM,EAS3E,CAAC;AAEF,8EAA8E;AAC9E,eAAO,MAAM,qBAAqB,KAAK,CAAC;AAoJxC;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,GAAI,OAAO,OAAO,EAAE,QAAQ,UAAU,KAAG,MAAM,EAQhF,CAAC"}
|
package/dist/mcp/validate.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { areJsonValuesEqual } from "../util/json.js";
|
|
1
2
|
export const JSON_SCHEMA_TYPES = {
|
|
2
3
|
string: "string",
|
|
3
4
|
number: "number",
|
|
@@ -81,6 +82,13 @@ export const missingObjectType = (schema, path = "args") => {
|
|
|
81
82
|
...childSchemas(schema, path).flatMap(([child, childPath]) => missingObjectType(child, childPath)),
|
|
82
83
|
];
|
|
83
84
|
};
|
|
85
|
+
/** Errors reported for one value before validation stops looking for more. */
|
|
86
|
+
export const MAX_VALIDATION_ERRORS = 20;
|
|
87
|
+
const spend = (budget, errors) => {
|
|
88
|
+
const kept = errors.slice(0, Math.max(0, budget.remaining));
|
|
89
|
+
budget.remaining -= kept.length;
|
|
90
|
+
return kept;
|
|
91
|
+
};
|
|
84
92
|
const runtimeTypeOf = (value) => {
|
|
85
93
|
if (value === null)
|
|
86
94
|
return JSON_SCHEMA_TYPES.null;
|
|
@@ -101,7 +109,7 @@ const typeMismatch = (value, schema, path) => {
|
|
|
101
109
|
return matches ? [] : [`${path}: expected ${declared.join(" | ")}, got ${actual}`];
|
|
102
110
|
};
|
|
103
111
|
const enumErrors = (value, schema, path) => {
|
|
104
|
-
if (!schema.enum || schema.enum.
|
|
112
|
+
if (!schema.enum || schema.enum.some((entry) => areJsonValuesEqual(entry, value)))
|
|
105
113
|
return [];
|
|
106
114
|
return [`${path}: value not in enum`];
|
|
107
115
|
};
|
|
@@ -117,17 +125,17 @@ const RANGE_BOUNDS = [
|
|
|
117
125
|
message: (path, bound) => `${path}: above maximum ${bound}`,
|
|
118
126
|
},
|
|
119
127
|
];
|
|
120
|
-
const rangeErrors = (value, schema, path) => {
|
|
128
|
+
const rangeErrors = (value, schema, path, budget) => {
|
|
121
129
|
if (typeof value !== "number")
|
|
122
130
|
return [];
|
|
123
|
-
return RANGE_BOUNDS.flatMap(({ key, fails, message }) => {
|
|
131
|
+
return spend(budget, RANGE_BOUNDS.flatMap(({ key, fails, message }) => {
|
|
124
132
|
const bound = schema[key];
|
|
125
133
|
if (bound === undefined || !fails(value, bound))
|
|
126
134
|
return [];
|
|
127
135
|
return [message(path, bound)];
|
|
128
|
-
});
|
|
136
|
+
}));
|
|
129
137
|
};
|
|
130
|
-
const objectErrors = (value, schema, path) => {
|
|
138
|
+
const objectErrors = (value, schema, path, budget) => {
|
|
131
139
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
132
140
|
return [];
|
|
133
141
|
const record = value;
|
|
@@ -137,24 +145,38 @@ const objectErrors = (value, schema, path) => {
|
|
|
137
145
|
// `properties: { constructor: {...} }` entry would validate against the
|
|
138
146
|
// prototype's own `constructor`, neither of which is an actual argument
|
|
139
147
|
// the caller supplied.
|
|
140
|
-
const
|
|
148
|
+
const errors = spend(budget, (schema.required ?? [])
|
|
141
149
|
.filter((key) => !Object.hasOwn(record, key))
|
|
142
|
-
.map((key) => `${path}.${key}: required`);
|
|
143
|
-
const
|
|
144
|
-
.
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
150
|
+
.map((key) => `${path}.${key}: required`));
|
|
151
|
+
for (const [key, propSchema] of Object.entries(schema.properties ?? {})) {
|
|
152
|
+
if (budget.remaining <= 0)
|
|
153
|
+
return errors;
|
|
154
|
+
if (Object.hasOwn(record, key)) {
|
|
155
|
+
errors.push(...validateNode(record[key], propSchema, `${path}.${key}`, budget));
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
if (schema.additionalProperties === false) {
|
|
159
|
+
for (const key of Object.keys(record)) {
|
|
160
|
+
if (budget.remaining <= 0)
|
|
161
|
+
return errors;
|
|
162
|
+
if (!Object.hasOwn(schema.properties ?? {}, key)) {
|
|
163
|
+
errors.push(...spend(budget, [`${path}.${key}: not allowed`]));
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return errors;
|
|
152
168
|
};
|
|
153
|
-
const arrayErrors = (value, schema, path) => {
|
|
169
|
+
const arrayErrors = (value, schema, path, budget) => {
|
|
154
170
|
const items = schema.items;
|
|
155
171
|
if (!Array.isArray(value) || !items)
|
|
156
172
|
return [];
|
|
157
|
-
|
|
173
|
+
const errors = [];
|
|
174
|
+
for (const [index, entry] of value.entries()) {
|
|
175
|
+
if (budget.remaining <= 0)
|
|
176
|
+
break;
|
|
177
|
+
errors.push(...validateNode(entry, items, `${path}[${index}]`, budget));
|
|
178
|
+
}
|
|
179
|
+
return errors;
|
|
158
180
|
};
|
|
159
181
|
const TYPE_CHECKERS = {
|
|
160
182
|
[JSON_SCHEMA_TYPES.object]: objectErrors,
|
|
@@ -162,10 +184,10 @@ const TYPE_CHECKERS = {
|
|
|
162
184
|
[JSON_SCHEMA_TYPES.number]: rangeErrors,
|
|
163
185
|
[JSON_SCHEMA_TYPES.integer]: rangeErrors,
|
|
164
186
|
};
|
|
165
|
-
const validateNode = (value, schema, path) => {
|
|
187
|
+
const validateNode = (value, schema, path, budget) => {
|
|
166
188
|
const typeErrors = typeMismatch(value, schema, path);
|
|
167
189
|
if (typeErrors.length > 0)
|
|
168
|
-
return typeErrors;
|
|
190
|
+
return spend(budget, typeErrors);
|
|
169
191
|
// Dispatch on the value's own runtime shape, not the declared type
|
|
170
192
|
// string(s). By this point `typeMismatch` has already confirmed `value`
|
|
171
193
|
// is consistent with whatever was declared (or nothing was declared at
|
|
@@ -177,10 +199,22 @@ const validateNode = (value, schema, path) => {
|
|
|
177
199
|
// backstop for a schema that reaches validation unchecked).
|
|
178
200
|
const actual = runtimeTypeOf(value);
|
|
179
201
|
return [
|
|
180
|
-
...enumErrors(value, schema, path),
|
|
181
|
-
...(TYPE_CHECKERS[actual]?.(value, schema, path) ?? []),
|
|
202
|
+
...spend(budget, enumErrors(value, schema, path)),
|
|
203
|
+
...(TYPE_CHECKERS[actual]?.(value, schema, path, budget) ?? []),
|
|
182
204
|
];
|
|
183
205
|
};
|
|
184
|
-
/**
|
|
185
|
-
|
|
206
|
+
/**
|
|
207
|
+
* Minimal JSON Schema subset used by MCP tool inputSchema. Empty = valid.
|
|
208
|
+
* Reports at most `MAX_VALIDATION_ERRORS` violations — enough to fix a call,
|
|
209
|
+
* bounded however large or hostile the arguments are.
|
|
210
|
+
*/
|
|
211
|
+
export const validateAgainstSchema = (value, schema) => {
|
|
212
|
+
const budget = { remaining: MAX_VALIDATION_ERRORS };
|
|
213
|
+
const errors = validateNode(value, schema, "args", budget);
|
|
214
|
+
// A spent budget means the walk stopped early: say so, so a caller does not
|
|
215
|
+
// read the list as complete and loop on "fix these, find more".
|
|
216
|
+
return budget.remaining <= 0
|
|
217
|
+
? [...errors, `(stopped after ${MAX_VALIDATION_ERRORS} errors; more may follow)`]
|
|
218
|
+
: errors;
|
|
219
|
+
};
|
|
186
220
|
//# sourceMappingURL=validate.js.map
|
package/dist/mcp/validate.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/mcp/validate.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/mcp/validate.ts"],"names":[],"mappings":"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"}
|
package/dist/oauth/audit.d.ts
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* `auditTimeoutMs` — the OAuth-side twin of `methods.ts`'s `safeAudit`.
|
|
4
4
|
* A hanging sink must not stall `/token` or `/authorize` error responses.
|
|
5
5
|
*/
|
|
6
|
+
import { type CimdFailure } from "./cimd/failure.js";
|
|
6
7
|
import type { OAuthAuditEntry, OAuthRouterOptions } from "./types.js";
|
|
7
8
|
export declare const safeOAuthAudit: (options: OAuthRouterOptions, entry: OAuthAuditEntry) => Promise<void>;
|
|
8
9
|
/**
|
|
@@ -17,4 +18,13 @@ export declare const auditLegacyKeyUsage: (options: OAuthRouterOptions, usage: {
|
|
|
17
18
|
keyIndex: number | null | undefined;
|
|
18
19
|
source: string;
|
|
19
20
|
}) => Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* Operator-only record of why a CIMD `client_id` did not resolve; the connector
|
|
23
|
+
* is always answered with the same generic `unauthorized_client`.
|
|
24
|
+
*/
|
|
25
|
+
export declare const auditCimdFailure: (options: OAuthRouterOptions, input: {
|
|
26
|
+
clientId: string;
|
|
27
|
+
endpoint: "authorize" | "token/revoke";
|
|
28
|
+
failure: CimdFailure;
|
|
29
|
+
}) => Promise<void>;
|
|
20
30
|
//# sourceMappingURL=audit.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../src/oauth/audit.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../src/oauth/audit.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EAAE,KAAK,WAAW,EAAqB,MAAM,mBAAmB,CAAC;AACxE,OAAO,KAAK,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAYtE,eAAO,MAAM,cAAc,GACzB,SAAS,kBAAkB,EAC3B,OAAO,eAAe,KACrB,OAAO,CAAC,IAAI,CAUd,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,GAC9B,SAAS,kBAAkB,EAC3B,OAAO;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,KAC/E,OAAO,CAAC,IAAI,CAOd,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,gBAAgB,GAC3B,SAAS,kBAAkB,EAC3B,OAAO;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,WAAW,GAAG,cAAc,CAAC;IAAC,OAAO,EAAE,WAAW,CAAA;CAAE,KACxF,OAAO,CAAC,IAAI,CAKX,CAAC"}
|
package/dist/oauth/audit.js
CHANGED
|
@@ -4,11 +4,26 @@
|
|
|
4
4
|
* A hanging sink must not stall `/token` or `/authorize` error responses.
|
|
5
5
|
*/
|
|
6
6
|
import { DEFAULT_AUDIT_TIMEOUT_MS, runAuditBounded } from "../http/http.js";
|
|
7
|
+
import { clipText } from "../util/clip.js";
|
|
8
|
+
import { formatCimdFailure } from "./cimd/failure.js";
|
|
9
|
+
/**
|
|
10
|
+
* Longest `clientId` / `reason` an audit sink is handed. Both can carry
|
|
11
|
+
* caller-chosen text (`client_id` is read straight off an unauthenticated
|
|
12
|
+
* request, up to the 64 KiB body cap), and a sink writing to a database or log
|
|
13
|
+
* pipeline should not have to defend itself against that.
|
|
14
|
+
*/
|
|
15
|
+
const MAX_AUDIT_FIELD_LENGTH = 512;
|
|
16
|
+
const clip = (value) => clipText(value, MAX_AUDIT_FIELD_LENGTH, "…");
|
|
7
17
|
export const safeOAuthAudit = async (options, entry) => {
|
|
8
18
|
const audit = options.ports.audit;
|
|
9
19
|
if (!audit)
|
|
10
20
|
return;
|
|
11
|
-
|
|
21
|
+
const bounded = {
|
|
22
|
+
...entry,
|
|
23
|
+
...(entry.clientId !== undefined ? { clientId: clip(entry.clientId) } : {}),
|
|
24
|
+
reason: clip(entry.reason),
|
|
25
|
+
};
|
|
26
|
+
await runAuditBounded(() => audit(bounded), options.auditTimeoutMs ?? DEFAULT_AUDIT_TIMEOUT_MS);
|
|
12
27
|
};
|
|
13
28
|
/**
|
|
14
29
|
* Fires `legacy_code_secret_used` when a value was recovered with a
|
|
@@ -26,4 +41,13 @@ export const auditLegacyKeyUsage = async (options, usage) => {
|
|
|
26
41
|
reason: `${usage.source} with codeSecret[${usage.keyIndex}]`,
|
|
27
42
|
});
|
|
28
43
|
};
|
|
44
|
+
/**
|
|
45
|
+
* Operator-only record of why a CIMD `client_id` did not resolve; the connector
|
|
46
|
+
* is always answered with the same generic `unauthorized_client`.
|
|
47
|
+
*/
|
|
48
|
+
export const auditCimdFailure = (options, input) => safeOAuthAudit(options, {
|
|
49
|
+
event: "cimd_resolve_failed",
|
|
50
|
+
clientId: input.clientId,
|
|
51
|
+
reason: `${formatCimdFailure(input.failure)} (${input.endpoint})`,
|
|
52
|
+
});
|
|
29
53
|
//# sourceMappingURL=audit.js.map
|
package/dist/oauth/audit.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/oauth/audit.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,wBAAwB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/oauth/audit.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,wBAAwB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAC5E,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAoB,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAGxE;;;;;GAKG;AACH,MAAM,sBAAsB,GAAG,GAAG,CAAC;AAEnC,MAAM,IAAI,GAAG,CAAC,KAAa,EAAU,EAAE,CAAC,QAAQ,CAAC,KAAK,EAAE,sBAAsB,EAAE,GAAG,CAAC,CAAC;AAErF,MAAM,CAAC,MAAM,cAAc,GAAG,KAAK,EACjC,OAA2B,EAC3B,KAAsB,EACP,EAAE;IACjB,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;IAClC,IAAI,CAAC,KAAK;QAAE,OAAO;IAEnB,MAAM,OAAO,GAAoB;QAC/B,GAAG,KAAK;QACR,GAAG,CAAC,KAAK,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3E,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;KAC3B,CAAC;IACF,MAAM,eAAe,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,cAAc,IAAI,wBAAwB,CAAC,CAAC;AAClG,CAAC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,KAAK,EACtC,OAA2B,EAC3B,KAAgF,EACjE,EAAE;IACjB,IAAI,CAAC,KAAK,CAAC,QAAQ;QAAE,OAAO;IAC5B,MAAM,cAAc,CAAC,OAAO,EAAE;QAC5B,KAAK,EAAE,yBAAyB;QAChC,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,MAAM,EAAE,GAAG,KAAK,CAAC,MAAM,oBAAoB,KAAK,CAAC,QAAQ,GAAG;KAC7D,CAAC,CAAC;AACL,CAAC,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC9B,OAA2B,EAC3B,KAAyF,EAC1E,EAAE,CACjB,cAAc,CAAC,OAAO,EAAE;IACtB,KAAK,EAAE,qBAAqB;IAC5B,QAAQ,EAAE,KAAK,CAAC,QAAQ;IACxB,MAAM,EAAE,GAAG,iBAAiB,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,KAAK,CAAC,QAAQ,GAAG;CAClE,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cimd-parse.d.ts","sourceRoot":"","sources":["../../../src/oauth/cimd/cimd-parse.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cimd-parse.d.ts","sourceRoot":"","sources":["../../../src/oauth/cimd/cimd-parse.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAK/C,eAAO,MAAM,gBAAgB,GAAI,QAAQ,MAAM,GAAG,IAAI,KAAG,MAGxD,CAAC;AAkEF,eAAO,MAAM,aAAa,GAAI,UAAU,MAAM,EAAE,MAAM,MAAM,KAAG,YA4B9D,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { isJsonObject } from "../../util/json.js";
|
|
2
2
|
import { MAX_CLIENT_REDIRECT_URIS } from "../constants.js";
|
|
3
3
|
import { isLoopbackHostname } from "./cimd-ssrf.js";
|
|
4
|
+
import { CimdError } from "./failure.js";
|
|
4
5
|
const DEFAULT_CACHE_SECONDS = 300;
|
|
5
6
|
const MAX_CACHE_SECONDS = 3600;
|
|
6
7
|
export const parseCacheMaxAge = (header) => {
|
|
@@ -13,58 +14,70 @@ const assertHttpRedirectUri = (uri) => {
|
|
|
13
14
|
parsed = new URL(uri);
|
|
14
15
|
}
|
|
15
16
|
catch {
|
|
16
|
-
throw new
|
|
17
|
+
throw new CimdError("redirect_uris_invalid", "CIMD redirect_uris entries must be absolute URLs");
|
|
17
18
|
}
|
|
18
19
|
if (parsed.username || parsed.password || parsed.hash) {
|
|
19
|
-
throw new
|
|
20
|
+
throw new CimdError("redirect_uris_invalid", "CIMD redirect_uris must not carry credentials or a fragment");
|
|
20
21
|
}
|
|
21
22
|
if (parsed.protocol === "https:")
|
|
22
23
|
return;
|
|
23
24
|
if (parsed.protocol === "http:") {
|
|
24
25
|
if (!isLoopbackHostname(parsed.hostname)) {
|
|
25
|
-
throw new
|
|
26
|
+
throw new CimdError("redirect_uris_invalid", "CIMD http redirect_uris must be loopback (127.0.0.1 / ::1)");
|
|
26
27
|
}
|
|
27
28
|
return;
|
|
28
29
|
}
|
|
29
|
-
throw new
|
|
30
|
+
throw new CimdError("redirect_uris_invalid", "CIMD redirect_uris must be http(s)");
|
|
30
31
|
};
|
|
31
32
|
const parseRedirectUris = (rawUris) => {
|
|
32
33
|
if (!Array.isArray(rawUris) || rawUris.length === 0) {
|
|
33
|
-
throw new
|
|
34
|
+
throw new CimdError("redirect_uris_invalid", "CIMD document must include a non-empty redirect_uris array");
|
|
34
35
|
}
|
|
35
36
|
if (rawUris.length > MAX_CLIENT_REDIRECT_URIS) {
|
|
36
|
-
throw new
|
|
37
|
+
throw new CimdError("redirect_uris_invalid", `CIMD redirect_uris must have at most ${MAX_CLIENT_REDIRECT_URIS} entries`);
|
|
37
38
|
}
|
|
38
39
|
return rawUris.map((u) => {
|
|
39
40
|
if (typeof u !== "string" || !u)
|
|
40
|
-
throw new
|
|
41
|
+
throw new CimdError("redirect_uris_invalid", "CIMD redirect_uris entries must be strings");
|
|
41
42
|
assertHttpRedirectUri(u);
|
|
42
43
|
return u;
|
|
43
44
|
});
|
|
44
45
|
};
|
|
46
|
+
const PUBLIC_AUTH_METHOD = "none";
|
|
47
|
+
/**
|
|
48
|
+
* Methods the client can use. The plural field is authoritative; the
|
|
49
|
+
* singular one is only a preference (ChatGPT publishes `private_key_jwt`
|
|
50
|
+
* there beside `["none", "private_key_jwt"]`), so it counts only when the
|
|
51
|
+
* plural is absent.
|
|
52
|
+
*/
|
|
53
|
+
const supportedAuthMethods = (record) => {
|
|
54
|
+
const plural = record.token_endpoint_auth_methods_supported;
|
|
55
|
+
if (Array.isArray(plural))
|
|
56
|
+
return plural;
|
|
57
|
+
return [record.token_endpoint_auth_method ?? PUBLIC_AUTH_METHOD];
|
|
58
|
+
};
|
|
45
59
|
export const parseDocument = (clientId, text) => {
|
|
46
60
|
let parsed;
|
|
47
61
|
try {
|
|
48
62
|
parsed = JSON.parse(text);
|
|
49
63
|
}
|
|
50
64
|
catch {
|
|
51
|
-
throw new
|
|
65
|
+
throw new CimdError("not_json", "CIMD document is not JSON");
|
|
52
66
|
}
|
|
53
67
|
if (!isJsonObject(parsed))
|
|
54
|
-
throw new
|
|
68
|
+
throw new CimdError("document_invalid", "CIMD document must be a JSON object");
|
|
55
69
|
const record = parsed;
|
|
56
70
|
if (record.client_id !== clientId) {
|
|
57
|
-
throw new
|
|
71
|
+
throw new CimdError("client_id_mismatch", "CIMD document client_id must equal the request URL exactly");
|
|
58
72
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
throw new Error("CIMD clients must be public (token_endpoint_auth_method none)");
|
|
73
|
+
if (!supportedAuthMethods(record).includes(PUBLIC_AUTH_METHOD)) {
|
|
74
|
+
throw new CimdError("auth_method_unsupported", "CIMD clients must support the public method (token_endpoint_auth_method none)");
|
|
62
75
|
}
|
|
63
76
|
return {
|
|
64
77
|
client_id: clientId,
|
|
65
78
|
redirect_uris: parseRedirectUris(record.redirect_uris),
|
|
66
79
|
...(typeof record.client_name === "string" ? { client_name: record.client_name } : {}),
|
|
67
|
-
token_endpoint_auth_method:
|
|
80
|
+
token_endpoint_auth_method: PUBLIC_AUTH_METHOD,
|
|
68
81
|
};
|
|
69
82
|
};
|
|
70
83
|
//# sourceMappingURL=cimd-parse.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cimd-parse.js","sourceRoot":"","sources":["../../../src/oauth/cimd/cimd-parse.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"cimd-parse.js","sourceRoot":"","sources":["../../../src/oauth/cimd/cimd-parse.ts"],"names":[],"mappings":"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"}
|