@muze-nl/metro-oidc 0.6.0 → 0.9.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/LICENSE +1 -1
- package/README.md +3 -50
- package/dist/browser.js +2336 -929
- package/dist/browser.js.map +4 -4
- package/dist/browser.min.js +3 -1
- package/dist/browser.min.js.map +4 -4
- package/docs/README.md +30 -0
- package/docs/reference.md +97 -0
- package/package.json +47 -14
- package/src/browser.mjs +9 -15
- package/src/index.mjs +20 -0
- package/src/oidc.discovery.mjs +4 -3
- package/src/oidc.jwt.mjs +65 -0
- package/src/oidc.mockserver.mjs +195 -0
- package/src/oidc.register.mjs +6 -5
- package/src/oidc.util.mjs +1 -1
- package/src/oidcmw.mjs +76 -25
- package/src/testing.mjs +4 -0
package/dist/browser.js
CHANGED
|
@@ -5,19 +5,19 @@
|
|
|
5
5
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
6
6
|
};
|
|
7
7
|
|
|
8
|
-
//
|
|
9
|
-
var
|
|
10
|
-
__export(
|
|
8
|
+
// ../metro-core/src/index.mjs
|
|
9
|
+
var src_exports = {};
|
|
10
|
+
__export(src_exports, {
|
|
11
11
|
Client: () => Client,
|
|
12
12
|
client: () => client,
|
|
13
13
|
deepClone: () => deepClone,
|
|
14
|
-
formdata: () => formdata,
|
|
15
14
|
metroError: () => metroError,
|
|
16
15
|
request: () => request,
|
|
17
16
|
response: () => response,
|
|
18
|
-
trace: () => trace,
|
|
19
17
|
url: () => url
|
|
20
18
|
});
|
|
19
|
+
|
|
20
|
+
// ../metro-core/src/metro.mjs
|
|
21
21
|
var metroURL = "https://metro.muze.nl/details/";
|
|
22
22
|
if (!Symbol.metroProxy) {
|
|
23
23
|
Symbol.metroProxy = /* @__PURE__ */ Symbol("isProxy");
|
|
@@ -65,11 +65,14 @@
|
|
|
65
65
|
}
|
|
66
66
|
for (const verb of this.clientOptions.verbs) {
|
|
67
67
|
this[verb] = async function(...options2) {
|
|
68
|
-
return this.fetch(
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
68
|
+
return this.fetch(
|
|
69
|
+
request(
|
|
70
|
+
this.clientOptions,
|
|
71
|
+
...options2,
|
|
72
|
+
{ method: verb.toUpperCase() }
|
|
73
|
+
),
|
|
74
|
+
fetchOptionsFrom(...options2)
|
|
75
|
+
);
|
|
73
76
|
};
|
|
74
77
|
}
|
|
75
78
|
}
|
|
@@ -113,23 +116,22 @@
|
|
|
113
116
|
};
|
|
114
117
|
let middlewares = [metrofetch].concat(this.clientOptions?.middlewares?.slice() || []);
|
|
115
118
|
options = Object.assign({}, this.clientOptions, options);
|
|
119
|
+
const traceContext = createTraceContext(req, options);
|
|
120
|
+
const middlewareContext = createMiddlewareContext(this, options, traceContext);
|
|
116
121
|
let next;
|
|
117
122
|
for (let middleware of middlewares) {
|
|
118
123
|
next = /* @__PURE__ */ (function(next2, middleware2) {
|
|
119
124
|
return async function(req2) {
|
|
120
125
|
let res;
|
|
121
|
-
let tracers =
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
for (let tracer of tracers) {
|
|
129
|
-
if (tracer.response) {
|
|
130
|
-
tracer.response.call(tracer, res, middleware2);
|
|
131
|
-
}
|
|
126
|
+
let tracers = traceContext.tracers;
|
|
127
|
+
callTracers(tracers, "request", req2, middleware2, traceContext);
|
|
128
|
+
try {
|
|
129
|
+
res = await middleware2(req2, next2, middlewareContext);
|
|
130
|
+
} catch (error2) {
|
|
131
|
+
callTracers(tracers, "error", error2, req2, middleware2, traceContext);
|
|
132
|
+
throw error2;
|
|
132
133
|
}
|
|
134
|
+
callTracers(tracers, "response", res, middleware2, traceContext);
|
|
133
135
|
return res;
|
|
134
136
|
};
|
|
135
137
|
})(next, middleware);
|
|
@@ -143,6 +145,146 @@
|
|
|
143
145
|
return this.clientOptions.url;
|
|
144
146
|
}
|
|
145
147
|
};
|
|
148
|
+
var traceContextId = 0;
|
|
149
|
+
var TRACE_OPTION_KEYS = ["trace", "tracer", "tracers"];
|
|
150
|
+
function fetchOptionsFrom(...options) {
|
|
151
|
+
const result = {};
|
|
152
|
+
for (const option of options) {
|
|
153
|
+
if (!isPlainObject(option)) {
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
for (const key of TRACE_OPTION_KEYS) {
|
|
157
|
+
if (key in option) {
|
|
158
|
+
result[key] = option[key];
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return result;
|
|
163
|
+
}
|
|
164
|
+
function createTraceContext(req, options = {}) {
|
|
165
|
+
const parent = traceParentFrom(options.trace || options.tracer || options.tracers);
|
|
166
|
+
let localTracers = [];
|
|
167
|
+
if (parent) {
|
|
168
|
+
localTracers = parent.localTracers || [];
|
|
169
|
+
} else {
|
|
170
|
+
localTracers = normalizeTracers(options.trace).concat(normalizeTracers(options.tracer)).concat(normalizeTracers(options.tracers));
|
|
171
|
+
}
|
|
172
|
+
const globalTracers = Object.values(Client.tracers || {});
|
|
173
|
+
const context = {
|
|
174
|
+
__metroTraceContext: true,
|
|
175
|
+
id: "metro-trace-context-" + ++traceContextId,
|
|
176
|
+
parent,
|
|
177
|
+
request: req,
|
|
178
|
+
options,
|
|
179
|
+
globalTracers,
|
|
180
|
+
localTracers,
|
|
181
|
+
tracers: globalTracers.concat(localTracers)
|
|
182
|
+
};
|
|
183
|
+
return context;
|
|
184
|
+
}
|
|
185
|
+
function traceParentFrom(value) {
|
|
186
|
+
if (!value) {
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
if (value.context?.__metroTraceContext) {
|
|
190
|
+
return value.context;
|
|
191
|
+
}
|
|
192
|
+
if (value.__metroTraceContext) {
|
|
193
|
+
return value;
|
|
194
|
+
}
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
function normalizeTracers(value) {
|
|
198
|
+
if (!value || value.__metroTraceContext || value.context?.__metroTraceContext) {
|
|
199
|
+
return [];
|
|
200
|
+
}
|
|
201
|
+
if (Array.isArray(value)) {
|
|
202
|
+
return value.flatMap(normalizeTracers);
|
|
203
|
+
}
|
|
204
|
+
if (isTracer(value)) {
|
|
205
|
+
return [value];
|
|
206
|
+
}
|
|
207
|
+
if (isPlainObject(value)) {
|
|
208
|
+
return Object.values(value).flatMap(normalizeTracers);
|
|
209
|
+
}
|
|
210
|
+
return [];
|
|
211
|
+
}
|
|
212
|
+
function isTracer(value) {
|
|
213
|
+
return value && typeof value == "object" && [
|
|
214
|
+
"request",
|
|
215
|
+
"response",
|
|
216
|
+
"error",
|
|
217
|
+
"event",
|
|
218
|
+
"diagnostic",
|
|
219
|
+
"span",
|
|
220
|
+
"link",
|
|
221
|
+
"current"
|
|
222
|
+
].some((name) => typeof value[name] == "function");
|
|
223
|
+
}
|
|
224
|
+
function createMiddlewareContext(client2, options, traceContext) {
|
|
225
|
+
const trace = createTraceAPI(traceContext);
|
|
226
|
+
return Object.freeze({
|
|
227
|
+
client: client2,
|
|
228
|
+
options,
|
|
229
|
+
trace,
|
|
230
|
+
fetch(req, fetchOptions = {}) {
|
|
231
|
+
return client2.fetch(req, Object.assign({}, fetchOptions, { trace }));
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
function createTraceAPI(context) {
|
|
236
|
+
const api = {
|
|
237
|
+
__metroTraceContext: true,
|
|
238
|
+
context,
|
|
239
|
+
event(name, data = {}) {
|
|
240
|
+
callTracers(context.tracers, "event", name, data, context);
|
|
241
|
+
},
|
|
242
|
+
diagnostic(diagnostic = {}) {
|
|
243
|
+
callTracers(context.tracers, "diagnostic", diagnostic, context);
|
|
244
|
+
},
|
|
245
|
+
current() {
|
|
246
|
+
for (const tracer of context.tracers) {
|
|
247
|
+
if (typeof tracer.current == "function") {
|
|
248
|
+
const current = tracer.current(context);
|
|
249
|
+
if (current) {
|
|
250
|
+
return current;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return { traceId: null, spanId: null };
|
|
255
|
+
},
|
|
256
|
+
async span(name, fn, data = {}) {
|
|
257
|
+
const tracer = context.tracers.find((tracer2) => typeof tracer2.span == "function");
|
|
258
|
+
if (!tracer) {
|
|
259
|
+
return fn();
|
|
260
|
+
}
|
|
261
|
+
return tracer.span(name, fn, data, context);
|
|
262
|
+
},
|
|
263
|
+
link(key) {
|
|
264
|
+
let traceId = null;
|
|
265
|
+
for (const tracer of context.tracers) {
|
|
266
|
+
if (typeof tracer.link == "function") {
|
|
267
|
+
traceId = tracer.link(key, void 0, context) || traceId;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return traceId;
|
|
271
|
+
},
|
|
272
|
+
options(extra = {}) {
|
|
273
|
+
return Object.assign({}, extra, { trace: api });
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
return api;
|
|
277
|
+
}
|
|
278
|
+
function callTracers(tracers, method, ...args) {
|
|
279
|
+
for (const tracer of tracers) {
|
|
280
|
+
if (tracer && typeof tracer[method] == "function") {
|
|
281
|
+
tracer[method].call(tracer, ...args);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
function isPlainObject(value) {
|
|
286
|
+
return value && typeof value == "object" && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);
|
|
287
|
+
}
|
|
146
288
|
function client(...options) {
|
|
147
289
|
return new Client(...deepClone(options));
|
|
148
290
|
}
|
|
@@ -215,7 +357,7 @@
|
|
|
215
357
|
let r = new Request(requestParams.url, requestParams);
|
|
216
358
|
let data = requestParams.body;
|
|
217
359
|
if (data) {
|
|
218
|
-
if (typeof data == "object" && !(data instanceof String) && !(data instanceof ReadableStream) && !(data instanceof Blob) && !(data instanceof ArrayBuffer) && !(data instanceof DataView) && !(data instanceof FormData) && !(data instanceof URLSearchParams) && (
|
|
360
|
+
if (typeof data == "object" && !(data instanceof String) && !(data instanceof ReadableStream) && !(data instanceof Blob) && !(data instanceof ArrayBuffer) && !(data instanceof DataView) && !(data instanceof FormData) && !(data instanceof URLSearchParams) && (globalThis.ArrayBuffer && ArrayBuffer.isView(data))) {
|
|
219
361
|
if (typeof data.toString == "function") {
|
|
220
362
|
requestParams.body = data.toString({ headers: r.headers });
|
|
221
363
|
r = new Request(requestParams.url, requestParams);
|
|
@@ -235,7 +377,7 @@
|
|
|
235
377
|
break;
|
|
236
378
|
case "with":
|
|
237
379
|
result = function(...options2) {
|
|
238
|
-
if (data) {
|
|
380
|
+
if (typeof data !== "undefined") {
|
|
239
381
|
options2.unshift({ body: data });
|
|
240
382
|
}
|
|
241
383
|
return request(target, ...options2);
|
|
@@ -247,8 +389,16 @@
|
|
|
247
389
|
default:
|
|
248
390
|
if (target[prop] instanceof Function) {
|
|
249
391
|
if (prop === "clone") {
|
|
392
|
+
result = function() {
|
|
393
|
+
const cloned = target.clone();
|
|
394
|
+
if (typeof data != "undefined" && !(typeof ReadableStream != "undefined" && data instanceof ReadableStream)) {
|
|
395
|
+
return request(cloned, { body: data });
|
|
396
|
+
}
|
|
397
|
+
return request(cloned);
|
|
398
|
+
};
|
|
399
|
+
} else {
|
|
400
|
+
result = target[prop].bind(target);
|
|
250
401
|
}
|
|
251
|
-
result = target[prop].bind(target);
|
|
252
402
|
} else {
|
|
253
403
|
result = target[prop];
|
|
254
404
|
}
|
|
@@ -329,7 +479,7 @@
|
|
|
329
479
|
result = data;
|
|
330
480
|
break;
|
|
331
481
|
case "ok":
|
|
332
|
-
result = target.status >= 200 && target.status <
|
|
482
|
+
result = target.status >= 200 && target.status < 300;
|
|
333
483
|
break;
|
|
334
484
|
default:
|
|
335
485
|
if (typeof target[prop] == "function") {
|
|
@@ -353,9 +503,19 @@
|
|
|
353
503
|
});
|
|
354
504
|
}
|
|
355
505
|
}
|
|
506
|
+
function appendHashParams(value, params) {
|
|
507
|
+
const target = value[Symbol.metroSource] || value;
|
|
508
|
+
if (!(params instanceof URLSearchParams)) {
|
|
509
|
+
params = new URLSearchParams(params);
|
|
510
|
+
}
|
|
511
|
+
let hash = target.hash || "#";
|
|
512
|
+
hash += "?" + params;
|
|
513
|
+
return url(target, { hash });
|
|
514
|
+
}
|
|
356
515
|
function url(...options) {
|
|
357
516
|
let validParams = [
|
|
358
517
|
"hash",
|
|
518
|
+
"fragment",
|
|
359
519
|
"host",
|
|
360
520
|
"hostname",
|
|
361
521
|
"href",
|
|
@@ -365,9 +525,11 @@
|
|
|
365
525
|
"protocol",
|
|
366
526
|
"username",
|
|
367
527
|
"search",
|
|
368
|
-
"searchParams"
|
|
528
|
+
"searchParams",
|
|
529
|
+
"hashParams"
|
|
369
530
|
];
|
|
370
531
|
let u = new URL("https://localhost/");
|
|
532
|
+
let hParams = null;
|
|
371
533
|
for (let option of options) {
|
|
372
534
|
if (typeof option == "string" || option instanceof String) {
|
|
373
535
|
u = new URL(option, u);
|
|
@@ -392,6 +554,16 @@
|
|
|
392
554
|
if (!validParams.includes(param)) {
|
|
393
555
|
throw metroError("metro.url: unknown url parameter " + metroURL + "url/unknown-param-name/", param);
|
|
394
556
|
}
|
|
557
|
+
if (param == "fragment") {
|
|
558
|
+
let fragment = option.fragment;
|
|
559
|
+
if (fragment && typeof fragment == "string" && fragment[0] != "#") {
|
|
560
|
+
fragment = "#" + fragment;
|
|
561
|
+
}
|
|
562
|
+
option.hash = fragment;
|
|
563
|
+
param = "hash";
|
|
564
|
+
} else if (param == "hashParams") {
|
|
565
|
+
hParams = option.hashParams;
|
|
566
|
+
}
|
|
395
567
|
if (typeof option[param] == "function") {
|
|
396
568
|
option[param](u[param], u);
|
|
397
569
|
} else if (typeof option[param] == "string" || option[param] instanceof String || typeof option[param] == "number" || option[param] instanceof Number || typeof option[param] == "boolean" || option[param] instanceof Boolean) {
|
|
@@ -408,6 +580,16 @@
|
|
|
408
580
|
throw metroError("metro.url: unsupported option value " + metroURL + "url/unsupported-option-value/", option);
|
|
409
581
|
}
|
|
410
582
|
}
|
|
583
|
+
if (hParams) {
|
|
584
|
+
if (!u.hash) {
|
|
585
|
+
u.hash = "#";
|
|
586
|
+
}
|
|
587
|
+
if (typeof hParams == "string") {
|
|
588
|
+
u.hash += hParams;
|
|
589
|
+
} else {
|
|
590
|
+
u = appendHashParams(u, hParams);
|
|
591
|
+
}
|
|
592
|
+
}
|
|
411
593
|
Object.freeze(u);
|
|
412
594
|
return new Proxy(u, {
|
|
413
595
|
get(target, prop) {
|
|
@@ -428,7 +610,7 @@
|
|
|
428
610
|
result = target.pathname.split("/").pop();
|
|
429
611
|
break;
|
|
430
612
|
case "folderpath":
|
|
431
|
-
result = target.pathname.substring(0, target.pathname.lastIndexOf("
|
|
613
|
+
result = target.pathname.substring(0, target.pathname.lastIndexOf("/") + 1);
|
|
432
614
|
break;
|
|
433
615
|
case "authority":
|
|
434
616
|
result = target.username ?? "";
|
|
@@ -439,11 +621,6 @@
|
|
|
439
621
|
result += "/";
|
|
440
622
|
result = target.protocol + "//" + result;
|
|
441
623
|
break;
|
|
442
|
-
case "origin":
|
|
443
|
-
result = target.protocol + "//" + target.hostname;
|
|
444
|
-
result += target.port ? ":" + target.port : "";
|
|
445
|
-
result += "/";
|
|
446
|
-
break;
|
|
447
624
|
case "fragment":
|
|
448
625
|
result = target.hash.substring(1);
|
|
449
626
|
break;
|
|
@@ -466,67 +643,12 @@
|
|
|
466
643
|
}
|
|
467
644
|
});
|
|
468
645
|
}
|
|
469
|
-
function formdata(...options) {
|
|
470
|
-
var params = new FormData();
|
|
471
|
-
for (let option of options) {
|
|
472
|
-
if (option instanceof HTMLFormElement) {
|
|
473
|
-
option = new FormData(option);
|
|
474
|
-
}
|
|
475
|
-
if (option instanceof FormData) {
|
|
476
|
-
for (let entry of option.entries()) {
|
|
477
|
-
params.append(entry[0], entry[1]);
|
|
478
|
-
}
|
|
479
|
-
} else if (option && typeof option == "object") {
|
|
480
|
-
for (let entry of Object.entries(option)) {
|
|
481
|
-
if (Array.isArray(entry[1])) {
|
|
482
|
-
for (let value of entry[1]) {
|
|
483
|
-
params.append(entry[0], value);
|
|
484
|
-
}
|
|
485
|
-
} else {
|
|
486
|
-
params.append(entry[0], entry[1]);
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
} else {
|
|
490
|
-
throw new metroError("metro.formdata: unknown option type " + metroURL + "formdata/unknown-option-value/", option);
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
Object.freeze(params);
|
|
494
|
-
return new Proxy(params, {
|
|
495
|
-
get(target, prop) {
|
|
496
|
-
let result;
|
|
497
|
-
switch (prop) {
|
|
498
|
-
case Symbol.metroProxy:
|
|
499
|
-
result = true;
|
|
500
|
-
break;
|
|
501
|
-
case Symbol.metroSource:
|
|
502
|
-
result = target;
|
|
503
|
-
break;
|
|
504
|
-
//TODO: add toString() that can check
|
|
505
|
-
//headers param: toString({headers:request.headers})
|
|
506
|
-
//for the content-type
|
|
507
|
-
case "with":
|
|
508
|
-
result = function(...options2) {
|
|
509
|
-
return formdata(target, ...options2);
|
|
510
|
-
};
|
|
511
|
-
break;
|
|
512
|
-
default:
|
|
513
|
-
if (target[prop] instanceof Function) {
|
|
514
|
-
result = target[prop].bind(target);
|
|
515
|
-
} else {
|
|
516
|
-
result = target[prop];
|
|
517
|
-
}
|
|
518
|
-
break;
|
|
519
|
-
}
|
|
520
|
-
return result;
|
|
521
|
-
}
|
|
522
|
-
});
|
|
523
|
-
}
|
|
524
646
|
var metroConsole = {
|
|
525
|
-
error: (
|
|
526
|
-
console.error("\u24C2\uFE0F ",
|
|
647
|
+
error: (message2, ...details) => {
|
|
648
|
+
console.error("\u24C2\uFE0F ", message2, ...details);
|
|
527
649
|
},
|
|
528
|
-
info: (
|
|
529
|
-
console.info("\u24C2\uFE0F ",
|
|
650
|
+
info: (message2, ...details) => {
|
|
651
|
+
console.info("\u24C2\uFE0F ", message2, ...details);
|
|
530
652
|
},
|
|
531
653
|
group: (name) => {
|
|
532
654
|
console.group("\u24C2\uFE0F " + name);
|
|
@@ -535,59 +657,16 @@
|
|
|
535
657
|
console.groupEnd("\u24C2\uFE0F " + name);
|
|
536
658
|
}
|
|
537
659
|
};
|
|
538
|
-
function metroError(
|
|
539
|
-
metroConsole.error(
|
|
540
|
-
return new Error(
|
|
660
|
+
function metroError(message2, ...details) {
|
|
661
|
+
metroConsole.error(message2, ...details);
|
|
662
|
+
return new Error(message2, ...details);
|
|
541
663
|
}
|
|
542
|
-
var trace = {
|
|
543
|
-
/**
|
|
544
|
-
* Adds a named tracer function
|
|
545
|
-
* @param {string} name - the name of the tracer
|
|
546
|
-
* @param {Function} tracer - the tracer function to call
|
|
547
|
-
*/
|
|
548
|
-
add(name, tracer) {
|
|
549
|
-
Client.tracers[name] = tracer;
|
|
550
|
-
},
|
|
551
|
-
/**
|
|
552
|
-
* Removes a named tracer function
|
|
553
|
-
* @param {string} name
|
|
554
|
-
*/
|
|
555
|
-
delete(name) {
|
|
556
|
-
delete Client.tracers[name];
|
|
557
|
-
},
|
|
558
|
-
/**
|
|
559
|
-
* Removes all tracer functions
|
|
560
|
-
*/
|
|
561
|
-
clear() {
|
|
562
|
-
Client.tracers = {};
|
|
563
|
-
},
|
|
564
|
-
/**
|
|
565
|
-
* Returns a set of request and response tracer functions that use the
|
|
566
|
-
* console.group feature to shows nested request/response pairs, with
|
|
567
|
-
* most commonly needed information for debugging
|
|
568
|
-
*/
|
|
569
|
-
group() {
|
|
570
|
-
let group = 0;
|
|
571
|
-
return {
|
|
572
|
-
request: (req, middleware) => {
|
|
573
|
-
group++;
|
|
574
|
-
metroConsole.group(group);
|
|
575
|
-
metroConsole.info(req?.url, req, middleware);
|
|
576
|
-
},
|
|
577
|
-
response: (res, middleware) => {
|
|
578
|
-
metroConsole.info(res?.body ? res.body[Symbol.metroSource] : null, res, middleware);
|
|
579
|
-
metroConsole.groupEnd(group);
|
|
580
|
-
group--;
|
|
581
|
-
}
|
|
582
|
-
};
|
|
583
|
-
}
|
|
584
|
-
};
|
|
585
664
|
function deepClone(object) {
|
|
586
665
|
if (Array.isArray(object)) {
|
|
587
666
|
return object.slice().map(deepClone);
|
|
588
667
|
}
|
|
589
668
|
if (object && typeof object === "object") {
|
|
590
|
-
if (object.__proto__
|
|
669
|
+
if (object.__proto__?.constructor == Object || !object.__proto__) {
|
|
591
670
|
let result = Object.assign({}, object);
|
|
592
671
|
Object.keys(result).forEach((key) => {
|
|
593
672
|
result[key] = deepClone(object[key]);
|
|
@@ -600,172 +679,250 @@
|
|
|
600
679
|
return object;
|
|
601
680
|
}
|
|
602
681
|
|
|
603
|
-
// node_modules/@muze-nl/
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
if (isJSON(req.headers.get("Content-Type"))) {
|
|
630
|
-
req = req.with({
|
|
631
|
-
body: JSON.stringify(req.data, options.replacer, options.space)
|
|
632
|
-
});
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
|
-
let res = await next(req);
|
|
637
|
-
if (res && isJSON(res.headers?.get("Content-Type"))) {
|
|
638
|
-
let tempRes = res.clone();
|
|
639
|
-
let body = await tempRes.text();
|
|
640
|
-
try {
|
|
641
|
-
let json2 = JSON.parse(body, options.reviver);
|
|
642
|
-
return res.with({
|
|
643
|
-
body: json2
|
|
644
|
-
});
|
|
645
|
-
} catch (e) {
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
return res;
|
|
649
|
-
};
|
|
682
|
+
// ../../node_modules/@muze-nl/assert/src/assert-core.mjs
|
|
683
|
+
var assert_core_exports = {};
|
|
684
|
+
__export(assert_core_exports, {
|
|
685
|
+
Optional: () => Optional,
|
|
686
|
+
Recommended: () => Recommended,
|
|
687
|
+
Required: () => Required,
|
|
688
|
+
allOf: () => allOf,
|
|
689
|
+
anyOf: () => anyOf,
|
|
690
|
+
assert: () => assert,
|
|
691
|
+
disable: () => disable,
|
|
692
|
+
enable: () => enable,
|
|
693
|
+
error: () => error,
|
|
694
|
+
fails: () => fails,
|
|
695
|
+
formatIssue: () => formatIssue,
|
|
696
|
+
formatIssues: () => formatIssues,
|
|
697
|
+
instanceOf: () => instanceOf,
|
|
698
|
+
issues: () => issues,
|
|
699
|
+
not: () => not,
|
|
700
|
+
oneOf: () => oneOf,
|
|
701
|
+
validEmail: () => validEmail,
|
|
702
|
+
validURL: () => validURL,
|
|
703
|
+
warn: () => warn
|
|
704
|
+
});
|
|
705
|
+
var assertEnabled = false;
|
|
706
|
+
function enable() {
|
|
707
|
+
assertEnabled = true;
|
|
650
708
|
}
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
return jsonRE.exec(contentType);
|
|
709
|
+
function disable() {
|
|
710
|
+
assertEnabled = false;
|
|
654
711
|
}
|
|
655
|
-
function
|
|
656
|
-
|
|
712
|
+
function appendPath(path = "", key) {
|
|
713
|
+
if (typeof path == "undefined" || path == null) {
|
|
714
|
+
path = "";
|
|
715
|
+
}
|
|
716
|
+
if (typeof key == "number") {
|
|
717
|
+
return `${path}[${key}]`;
|
|
718
|
+
}
|
|
719
|
+
return `${path}.${key}`;
|
|
657
720
|
}
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
721
|
+
function pathToArray(path = "") {
|
|
722
|
+
if (Array.isArray(path)) {
|
|
723
|
+
return path;
|
|
724
|
+
}
|
|
725
|
+
if (!path) {
|
|
726
|
+
return [];
|
|
727
|
+
}
|
|
728
|
+
let result = [];
|
|
729
|
+
let matcher = /(?:^|\.)([^.\[\]]+)|\[(\d+)\]/g;
|
|
730
|
+
let match;
|
|
731
|
+
while (match = matcher.exec(path)) {
|
|
732
|
+
if (typeof match[1] != "undefined") {
|
|
733
|
+
result.push(match[1]);
|
|
734
|
+
} else if (typeof match[2] != "undefined") {
|
|
735
|
+
result.push(Number(match[2]));
|
|
671
736
|
}
|
|
672
|
-
|
|
673
|
-
|
|
737
|
+
}
|
|
738
|
+
return result;
|
|
674
739
|
}
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
if (
|
|
681
|
-
return
|
|
740
|
+
function pathToString(path = []) {
|
|
741
|
+
if (typeof path == "string") {
|
|
742
|
+
return path.startsWith(".") ? path.slice(1) : path;
|
|
743
|
+
}
|
|
744
|
+
return path.map((part, index) => {
|
|
745
|
+
if (typeof part == "number") {
|
|
746
|
+
return `[${part}]`;
|
|
682
747
|
}
|
|
683
|
-
return
|
|
684
|
-
};
|
|
748
|
+
return `${index ? "." : ""}${part}`;
|
|
749
|
+
}).join("");
|
|
685
750
|
}
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
constructor(base, methods, bind = null) {
|
|
690
|
-
if (base instanceof Client) {
|
|
691
|
-
super(base.clientOptions, throwermw(), getdatamw());
|
|
692
|
-
} else {
|
|
693
|
-
super(base, throwermw(), getdatamw());
|
|
694
|
-
}
|
|
695
|
-
if (!bind) {
|
|
696
|
-
bind = this;
|
|
697
|
-
}
|
|
698
|
-
for (const methodName in methods) {
|
|
699
|
-
if (typeof methods[methodName] == "function") {
|
|
700
|
-
this[methodName] = methods[methodName].bind(bind);
|
|
701
|
-
} else if (methods[methodName] && typeof methods[methodName] == "object") {
|
|
702
|
-
this[methodName] = new this.constructor(base, methods[methodName], bind);
|
|
703
|
-
} else {
|
|
704
|
-
this[methodName] = methods[methodName];
|
|
705
|
-
}
|
|
706
|
-
}
|
|
751
|
+
function describeFunction(value) {
|
|
752
|
+
if (value === String) {
|
|
753
|
+
return "string";
|
|
707
754
|
}
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
755
|
+
if (value === Number) {
|
|
756
|
+
return "number";
|
|
757
|
+
}
|
|
758
|
+
if (value === Boolean) {
|
|
759
|
+
return "boolean";
|
|
760
|
+
}
|
|
761
|
+
return value.name || "function";
|
|
762
|
+
}
|
|
763
|
+
function clip(text, maxLength = 60) {
|
|
764
|
+
if (text.length <= maxLength) {
|
|
765
|
+
return text;
|
|
766
|
+
}
|
|
767
|
+
return text.slice(0, maxLength - 1) + "\u2026";
|
|
768
|
+
}
|
|
769
|
+
function quoteString(value) {
|
|
770
|
+
return `'${clip(String(value).replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\n/g, "\\n"))}'`;
|
|
771
|
+
}
|
|
772
|
+
function jsonSummary(value) {
|
|
773
|
+
try {
|
|
774
|
+
let json = JSON.stringify(value);
|
|
775
|
+
if (typeof json == "string") {
|
|
776
|
+
return clip(json);
|
|
715
777
|
}
|
|
778
|
+
} catch (e) {
|
|
716
779
|
}
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
780
|
+
let name = value?.constructor?.name;
|
|
781
|
+
if (name && name != "Object") {
|
|
782
|
+
return name;
|
|
783
|
+
}
|
|
784
|
+
return Object.prototype.toString.call(value);
|
|
720
785
|
}
|
|
721
|
-
function
|
|
722
|
-
|
|
786
|
+
function formatValue(value) {
|
|
787
|
+
if (typeof value == "string") {
|
|
788
|
+
return quoteString(value);
|
|
789
|
+
}
|
|
790
|
+
if (typeof value == "undefined") {
|
|
791
|
+
return "undefined";
|
|
792
|
+
}
|
|
793
|
+
if (value === null) {
|
|
794
|
+
return "null";
|
|
795
|
+
}
|
|
796
|
+
if (typeof value == "function") {
|
|
797
|
+
return describeFunction(value);
|
|
798
|
+
}
|
|
799
|
+
if (value instanceof RegExp) {
|
|
800
|
+
return value.toString();
|
|
801
|
+
}
|
|
802
|
+
if (typeof value == "number" || typeof value == "boolean" || typeof value == "bigint") {
|
|
803
|
+
return String(value);
|
|
804
|
+
}
|
|
805
|
+
if (typeof value == "symbol") {
|
|
806
|
+
return value.toString();
|
|
807
|
+
}
|
|
808
|
+
return jsonSummary(value);
|
|
723
809
|
}
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
810
|
+
function describeExpected(value) {
|
|
811
|
+
if (value === String || value === Number || value === Boolean) {
|
|
812
|
+
return describeFunction(value);
|
|
813
|
+
}
|
|
814
|
+
if (typeof value == "function") {
|
|
815
|
+
return describeFunction(value);
|
|
816
|
+
}
|
|
817
|
+
if (value instanceof RegExp) {
|
|
818
|
+
return value.toString();
|
|
819
|
+
}
|
|
820
|
+
if (Array.isArray(value)) {
|
|
821
|
+
return "[" + value.map(describeExpected).join(", ") + "]";
|
|
822
|
+
}
|
|
823
|
+
return formatValue(value);
|
|
737
824
|
}
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
// node_modules/@muze-nl/metro-oauth2/src/oauth2.mjs
|
|
741
|
-
var oauth2_exports = {};
|
|
742
|
-
__export(oauth2_exports, {
|
|
743
|
-
base64url_encode: () => base64url_encode,
|
|
744
|
-
createState: () => createState,
|
|
745
|
-
default: () => oauth2mw,
|
|
746
|
-
generateCodeChallenge: () => generateCodeChallenge,
|
|
747
|
-
generateCodeVerifier: () => generateCodeVerifier,
|
|
748
|
-
getExpires: () => getExpires,
|
|
749
|
-
isAuthorized: () => isAuthorized,
|
|
750
|
-
isExpired: () => isExpired,
|
|
751
|
-
isRedirected: () => isRedirected
|
|
752
|
-
});
|
|
753
|
-
|
|
754
|
-
// node_modules/@muze-nl/assert/src/assert.mjs
|
|
755
|
-
globalThis.assertEnabled = false;
|
|
756
|
-
function enable() {
|
|
757
|
-
globalThis.assertEnabled = true;
|
|
825
|
+
function describeOneOf(patterns) {
|
|
826
|
+
return patterns.map(describeExpected).join(", ");
|
|
758
827
|
}
|
|
759
|
-
function
|
|
760
|
-
|
|
828
|
+
function conciseMessage(message2, actual, expected) {
|
|
829
|
+
if (message2 == "data and pattern are not equal") {
|
|
830
|
+
return `expected ${formatValue(expected)}, found ${formatValue(actual)}`;
|
|
831
|
+
}
|
|
832
|
+
if (message2 == "data does not match pattern" || /^data\[\d+\] does not match pattern$/.test(message2)) {
|
|
833
|
+
return `expected ${describeExpected(expected)}, found ${formatValue(actual)}`;
|
|
834
|
+
}
|
|
835
|
+
if (message2 == "data is undefined, should match pattern") {
|
|
836
|
+
return `missing; expected ${describeExpected(expected)}`;
|
|
837
|
+
}
|
|
838
|
+
if (message2 == "data is required") {
|
|
839
|
+
return "required";
|
|
840
|
+
}
|
|
841
|
+
if (message2 == "data is an empty string, which is not allowed") {
|
|
842
|
+
return "empty string is not allowed";
|
|
843
|
+
}
|
|
844
|
+
if (message2 == "data is not an object, pattern is") {
|
|
845
|
+
return "data is not an object";
|
|
846
|
+
}
|
|
847
|
+
if (message2 == "data is not an instanceof pattern") {
|
|
848
|
+
return `expected instance of ${describeExpected(expected)}, found ${formatValue(actual)}`;
|
|
849
|
+
}
|
|
850
|
+
if (message2 == "data does not match oneOf patterns" || message2 == "data does not match anyOf patterns") {
|
|
851
|
+
return `expected one of ${describeOneOf(expected)}, found ${formatValue(actual)}`;
|
|
852
|
+
}
|
|
853
|
+
if (message2 == "data matches pattern, when required not to") {
|
|
854
|
+
return `must not match ${describeExpected(expected)}`;
|
|
855
|
+
}
|
|
856
|
+
return message2;
|
|
857
|
+
}
|
|
858
|
+
function formatIssue(issue, options = {}) {
|
|
859
|
+
if (!issue || typeof issue != "object") {
|
|
860
|
+
return String(issue);
|
|
861
|
+
}
|
|
862
|
+
let path = issue.pathString || pathToString(issue.path || []) || "value";
|
|
863
|
+
let indent = options.indent ?? "";
|
|
864
|
+
return `${indent}${path}: ${issue.message}`;
|
|
865
|
+
}
|
|
866
|
+
function formatIssues(issues2, options = {}) {
|
|
867
|
+
if (!issues2) {
|
|
868
|
+
return false;
|
|
869
|
+
}
|
|
870
|
+
let indent = options.indent ?? " - ";
|
|
871
|
+
return (Array.isArray(issues2) ? issues2 : [issues2]).map((issue) => formatIssue(issue, { ...options, indent }));
|
|
872
|
+
}
|
|
873
|
+
function issueFromProblem(problem) {
|
|
874
|
+
if (!problem || typeof problem != "object") {
|
|
875
|
+
return {
|
|
876
|
+
path: [],
|
|
877
|
+
pathString: "",
|
|
878
|
+
message: String(problem),
|
|
879
|
+
expected: void 0,
|
|
880
|
+
actual: void 0
|
|
881
|
+
};
|
|
882
|
+
}
|
|
883
|
+
let path = pathToArray(problem.path);
|
|
884
|
+
let pathString = pathToString(path);
|
|
885
|
+
let actual = problem.actual ?? problem.found;
|
|
886
|
+
let expected = describeExpected(problem.expected);
|
|
887
|
+
let message2 = conciseMessage(problem.message, actual, problem.expected);
|
|
888
|
+
return {
|
|
889
|
+
path,
|
|
890
|
+
pathString,
|
|
891
|
+
message: message2,
|
|
892
|
+
expected,
|
|
893
|
+
actual
|
|
894
|
+
};
|
|
895
|
+
}
|
|
896
|
+
function problemsToIssues(problems) {
|
|
897
|
+
if (!problems) {
|
|
898
|
+
return [];
|
|
899
|
+
}
|
|
900
|
+
let result = [];
|
|
901
|
+
for (let problem of Array.isArray(problems) ? problems : [problems]) {
|
|
902
|
+
if (!problem) {
|
|
903
|
+
continue;
|
|
904
|
+
}
|
|
905
|
+
if (problem && typeof problem == "object" && problem.problems) {
|
|
906
|
+
let nested = problemsToIssues(problem.problems);
|
|
907
|
+
if (nested.length) {
|
|
908
|
+
result = result.concat(nested);
|
|
909
|
+
continue;
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
result.push(issueFromProblem(problem));
|
|
913
|
+
}
|
|
914
|
+
return result;
|
|
761
915
|
}
|
|
762
916
|
function assert(source, test) {
|
|
763
|
-
if (
|
|
917
|
+
if (assertEnabled) {
|
|
764
918
|
let problems = fails(source, test);
|
|
765
919
|
if (problems) {
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
920
|
+
let assertionIssues = problemsToIssues(problems);
|
|
921
|
+
let formattedIssues = formatIssues(assertionIssues);
|
|
922
|
+
let message2 = "Assertions failed:\n" + formattedIssues.join("\n");
|
|
923
|
+
console.error("\u{1F170}\uFE0F " + message2);
|
|
924
|
+
throw new Error(message2, {
|
|
925
|
+
cause: { problems, issues: assertionIssues, source }
|
|
769
926
|
});
|
|
770
927
|
}
|
|
771
928
|
}
|
|
@@ -813,9 +970,10 @@
|
|
|
813
970
|
if (!Array.isArray(data)) {
|
|
814
971
|
return error("data is not an array", data, "anyOf", path);
|
|
815
972
|
}
|
|
816
|
-
for (let value of data) {
|
|
817
|
-
|
|
818
|
-
|
|
973
|
+
for (let [index, value] of data.entries()) {
|
|
974
|
+
let itemPath = appendPath(path, index);
|
|
975
|
+
if (oneOf(...patterns)(value, root, itemPath)) {
|
|
976
|
+
return error("data does not match anyOf patterns", value, patterns, itemPath);
|
|
819
977
|
}
|
|
820
978
|
}
|
|
821
979
|
return false;
|
|
@@ -867,8 +1025,15 @@
|
|
|
867
1025
|
}
|
|
868
1026
|
};
|
|
869
1027
|
}
|
|
1028
|
+
function issues(data, pattern, root) {
|
|
1029
|
+
let problems = fails(data, pattern, root);
|
|
1030
|
+
if (!problems) {
|
|
1031
|
+
return false;
|
|
1032
|
+
}
|
|
1033
|
+
return problemsToIssues(problems);
|
|
1034
|
+
}
|
|
870
1035
|
function fails(data, pattern, root, path = "") {
|
|
871
|
-
if (
|
|
1036
|
+
if (typeof root == "undefined") {
|
|
872
1037
|
root = data;
|
|
873
1038
|
}
|
|
874
1039
|
let problems = [];
|
|
@@ -889,9 +1054,9 @@
|
|
|
889
1054
|
}
|
|
890
1055
|
} else if (pattern instanceof RegExp) {
|
|
891
1056
|
if (Array.isArray(data)) {
|
|
892
|
-
let index = data.findIndex((element, index2) => fails(element, pattern, root, path
|
|
1057
|
+
let index = data.findIndex((element, index2) => fails(element, pattern, root, appendPath(path, index2)));
|
|
893
1058
|
if (index > -1) {
|
|
894
|
-
problems.push(error("data[" + index + "] does not match pattern", data[index], pattern, path
|
|
1059
|
+
problems.push(error("data[" + index + "] does not match pattern", data[index], pattern, appendPath(path, index)));
|
|
895
1060
|
}
|
|
896
1061
|
} else if (typeof data == "undefined") {
|
|
897
1062
|
problems.push(error("data is undefined, should match pattern", data, pattern, path));
|
|
@@ -910,22 +1075,23 @@
|
|
|
910
1075
|
} else if (Array.isArray(pattern)) {
|
|
911
1076
|
if (!Array.isArray(data)) {
|
|
912
1077
|
problems.push(error("data is not an array", data, [], path));
|
|
913
|
-
}
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
1078
|
+
} else {
|
|
1079
|
+
for (let p of pattern) {
|
|
1080
|
+
for (let index of data.keys()) {
|
|
1081
|
+
let problem = fails(data[index], p, root, appendPath(path, index));
|
|
1082
|
+
if (Array.isArray(problem)) {
|
|
1083
|
+
problems = problems.concat(problem);
|
|
1084
|
+
} else if (problem) {
|
|
1085
|
+
problems.push(problem);
|
|
1086
|
+
}
|
|
921
1087
|
}
|
|
922
1088
|
}
|
|
923
1089
|
}
|
|
924
1090
|
} else if (pattern && typeof pattern == "object") {
|
|
925
1091
|
if (Array.isArray(data)) {
|
|
926
|
-
let index = data.findIndex((element, index2) => fails(element, pattern, root, path
|
|
1092
|
+
let index = data.findIndex((element, index2) => fails(element, pattern, root, appendPath(path, index2)));
|
|
927
1093
|
if (index > -1) {
|
|
928
|
-
problems.push(error("data[" + index + "] does not match pattern", data[index], pattern, path
|
|
1094
|
+
problems.push(error("data[" + index + "] does not match pattern", data[index], pattern, appendPath(path, index)));
|
|
929
1095
|
}
|
|
930
1096
|
} else if (!data || typeof data != "object") {
|
|
931
1097
|
problems.push(error("data is not an object, pattern is", data, pattern, path));
|
|
@@ -940,7 +1106,7 @@
|
|
|
940
1106
|
}
|
|
941
1107
|
} else {
|
|
942
1108
|
for (const [patternKey, subpattern] of Object.entries(pattern)) {
|
|
943
|
-
let result = fails(data[patternKey], subpattern, root, path
|
|
1109
|
+
let result = fails(data[patternKey], subpattern, root, appendPath(path, patternKey));
|
|
944
1110
|
if (result) {
|
|
945
1111
|
problems = problems.concat(result);
|
|
946
1112
|
}
|
|
@@ -957,10 +1123,13 @@
|
|
|
957
1123
|
}
|
|
958
1124
|
return false;
|
|
959
1125
|
}
|
|
960
|
-
function error(
|
|
1126
|
+
function error(message2, found, expected, path = "", problems) {
|
|
1127
|
+
let pathParts = pathToArray(path);
|
|
961
1128
|
let result = {
|
|
962
1129
|
path,
|
|
963
|
-
|
|
1130
|
+
pathString: pathToString(pathParts),
|
|
1131
|
+
pathParts,
|
|
1132
|
+
message: message2,
|
|
964
1133
|
found,
|
|
965
1134
|
expected
|
|
966
1135
|
};
|
|
@@ -969,29 +1138,14 @@
|
|
|
969
1138
|
}
|
|
970
1139
|
return result;
|
|
971
1140
|
}
|
|
972
|
-
function warn(
|
|
973
|
-
console.warn("\u{1F170}\uFE0F Assert: " + path,
|
|
974
|
-
}
|
|
975
|
-
globalThis.assert = {
|
|
976
|
-
warn,
|
|
977
|
-
error,
|
|
978
|
-
assert,
|
|
979
|
-
enable,
|
|
980
|
-
disable,
|
|
981
|
-
Required,
|
|
982
|
-
Recommended,
|
|
983
|
-
Optional,
|
|
984
|
-
oneOf,
|
|
985
|
-
anyOf,
|
|
986
|
-
allOf,
|
|
987
|
-
validURL,
|
|
988
|
-
validEmail,
|
|
989
|
-
instanceOf,
|
|
990
|
-
not,
|
|
991
|
-
fails
|
|
992
|
-
};
|
|
1141
|
+
function warn(message2, data, pattern, path) {
|
|
1142
|
+
console.warn("\u{1F170}\uFE0F Assert: " + path, message2, pattern, data);
|
|
1143
|
+
}
|
|
993
1144
|
|
|
994
|
-
// node_modules/@muze-nl/
|
|
1145
|
+
// ../../node_modules/@muze-nl/assert/src/assert.mjs
|
|
1146
|
+
globalThis.assert = { ...assert_core_exports };
|
|
1147
|
+
|
|
1148
|
+
// ../metro-oauth2/src/tokenstore.mjs
|
|
995
1149
|
function tokenStore(site) {
|
|
996
1150
|
let localState, localTokens;
|
|
997
1151
|
if (typeof localStorage !== "undefined") {
|
|
@@ -999,7 +1153,7 @@
|
|
|
999
1153
|
get: () => localStorage.getItem("metro/state:" + site),
|
|
1000
1154
|
set: (value) => localStorage.setItem("metro/state:" + site, value),
|
|
1001
1155
|
has: () => localStorage.getItem("metro/state:" + site) !== null,
|
|
1002
|
-
delete: () => localStorage.
|
|
1156
|
+
delete: () => localStorage.removeItem("metro/state:" + site)
|
|
1003
1157
|
};
|
|
1004
1158
|
localTokens = {
|
|
1005
1159
|
get: (name) => JSON.parse(localStorage.getItem(site + ":" + name)),
|
|
@@ -1023,7 +1177,16 @@
|
|
|
1023
1177
|
};
|
|
1024
1178
|
}
|
|
1025
1179
|
|
|
1026
|
-
//
|
|
1180
|
+
// ../metro-oauth2/src/oauth2.mjs
|
|
1181
|
+
var SUPPORTED_TOKEN_TYPES = /* @__PURE__ */ new Map([
|
|
1182
|
+
["bearer", "Bearer"],
|
|
1183
|
+
["dpop", "DPoP"]
|
|
1184
|
+
]);
|
|
1185
|
+
var SUPPORTED_TOKEN_ENDPOINT_AUTH_METHODS = /* @__PURE__ */ new Set([
|
|
1186
|
+
"none",
|
|
1187
|
+
"client_secret_post",
|
|
1188
|
+
"client_secret_basic"
|
|
1189
|
+
]);
|
|
1027
1190
|
function oauth2mw(options) {
|
|
1028
1191
|
const defaultOptions = {
|
|
1029
1192
|
client: client(),
|
|
@@ -1044,9 +1207,9 @@
|
|
|
1044
1207
|
}
|
|
1045
1208
|
};
|
|
1046
1209
|
assert(options, {});
|
|
1047
|
-
const
|
|
1210
|
+
const oauth2 = Object.assign({}, defaultOptions.oauth2_configuration, options?.oauth2_configuration);
|
|
1048
1211
|
options = Object.assign({}, defaultOptions, options);
|
|
1049
|
-
options.oauth2_configuration =
|
|
1212
|
+
options.oauth2_configuration = oauth2;
|
|
1050
1213
|
const store = tokenStore(options.site);
|
|
1051
1214
|
if (!options.tokens) {
|
|
1052
1215
|
options.tokens = store.tokens;
|
|
@@ -1063,12 +1226,12 @@
|
|
|
1063
1226
|
redirect_uri: Required(validURL)
|
|
1064
1227
|
}
|
|
1065
1228
|
});
|
|
1066
|
-
for (let option in
|
|
1229
|
+
for (let option in oauth2) {
|
|
1067
1230
|
switch (option) {
|
|
1068
1231
|
case "access_token":
|
|
1069
1232
|
case "authorization_code":
|
|
1070
1233
|
case "refresh_token":
|
|
1071
|
-
options.tokens.set(option,
|
|
1234
|
+
options.tokens.set(option, normalizeInitialToken(option, oauth2[option]));
|
|
1072
1235
|
break;
|
|
1073
1236
|
}
|
|
1074
1237
|
}
|
|
@@ -1076,72 +1239,52 @@
|
|
|
1076
1239
|
if (options.force_authorization) {
|
|
1077
1240
|
return oauth2authorized(req, next);
|
|
1078
1241
|
}
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
res
|
|
1082
|
-
if (res.ok) {
|
|
1083
|
-
return res;
|
|
1084
|
-
}
|
|
1085
|
-
} catch (err) {
|
|
1086
|
-
switch (res?.status) {
|
|
1087
|
-
case 400:
|
|
1088
|
-
// Oauth2.1 RFC 3.2.4
|
|
1089
|
-
case 401:
|
|
1090
|
-
return oauth2authorized(req, next);
|
|
1091
|
-
break;
|
|
1092
|
-
}
|
|
1093
|
-
throw err;
|
|
1094
|
-
}
|
|
1095
|
-
if (!res.ok) {
|
|
1096
|
-
switch (res.status) {
|
|
1097
|
-
case 400:
|
|
1098
|
-
// Oauth2.1 RFC 3.2.4
|
|
1099
|
-
case 401:
|
|
1100
|
-
return oauth2authorized(req, next);
|
|
1101
|
-
break;
|
|
1102
|
-
}
|
|
1242
|
+
const res = await next(req);
|
|
1243
|
+
if (res.ok || !shouldAuthorizeResponse(res)) {
|
|
1244
|
+
return res;
|
|
1103
1245
|
}
|
|
1104
|
-
return
|
|
1246
|
+
return oauth2authorized(req, next);
|
|
1105
1247
|
};
|
|
1106
|
-
async function oauth2authorized(req, next) {
|
|
1248
|
+
async function oauth2authorized(req, next, retryState = {}) {
|
|
1107
1249
|
getTokensFromLocation();
|
|
1108
1250
|
const accessToken = options.tokens.get("access_token");
|
|
1109
1251
|
const refreshToken = options.tokens.get("refresh_token");
|
|
1110
1252
|
const tokenIsExpired = isExpired(accessToken);
|
|
1111
1253
|
if (!accessToken || tokenIsExpired && !refreshToken) {
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
return response("false");
|
|
1116
|
-
}
|
|
1117
|
-
} catch (e) {
|
|
1118
|
-
throw e;
|
|
1254
|
+
const token = await fetchAccessToken();
|
|
1255
|
+
if (!token) {
|
|
1256
|
+
return response("false");
|
|
1119
1257
|
}
|
|
1120
1258
|
return oauth2authorized(req, next);
|
|
1121
1259
|
} else if (tokenIsExpired && refreshToken) {
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
return response("false");
|
|
1126
|
-
}
|
|
1127
|
-
} catch (e) {
|
|
1128
|
-
throw e;
|
|
1260
|
+
const token = await refreshAccessToken();
|
|
1261
|
+
if (!token) {
|
|
1262
|
+
return response("false");
|
|
1129
1263
|
}
|
|
1130
1264
|
return oauth2authorized(req, next);
|
|
1131
1265
|
} else {
|
|
1132
|
-
|
|
1266
|
+
const authorizedReq = request(req, {
|
|
1133
1267
|
headers: {
|
|
1134
1268
|
Authorization: accessToken.type + " " + accessToken.value
|
|
1135
1269
|
}
|
|
1136
1270
|
});
|
|
1137
|
-
|
|
1271
|
+
const res = await next(authorizedReq);
|
|
1272
|
+
if (!shouldAuthorizeResponse(res) || retryState.handledRejectedToken) {
|
|
1273
|
+
return res;
|
|
1274
|
+
}
|
|
1275
|
+
options.tokens.delete("access_token");
|
|
1276
|
+
const token = refreshToken ? await refreshAccessToken() : await fetchAccessToken();
|
|
1277
|
+
if (!token) {
|
|
1278
|
+
return response("false");
|
|
1279
|
+
}
|
|
1280
|
+
return oauth2authorized(req, next, { handledRejectedToken: true });
|
|
1138
1281
|
}
|
|
1139
1282
|
}
|
|
1140
1283
|
function getTokensFromLocation() {
|
|
1141
1284
|
if (typeof window !== "undefined" && window?.location) {
|
|
1142
1285
|
let url2 = url(window.location);
|
|
1143
1286
|
let code, state, params;
|
|
1144
|
-
if (url2.searchParams.has("code")) {
|
|
1287
|
+
if (url2.searchParams.has("code") || url2.searchParams.has("error")) {
|
|
1145
1288
|
params = url2.searchParams;
|
|
1146
1289
|
url2 = url2.with({ search: "" });
|
|
1147
1290
|
history.pushState({}, "", url2.href);
|
|
@@ -1152,12 +1295,12 @@
|
|
|
1152
1295
|
history.pushState({}, "", url2.href);
|
|
1153
1296
|
}
|
|
1154
1297
|
if (params) {
|
|
1298
|
+
if (params.has("error")) {
|
|
1299
|
+
throw metroError("oauth2mw: authorization failed: " + params.get("error") + (params.get("error_description") ? " (" + params.get("error_description") + ")" : ""));
|
|
1300
|
+
}
|
|
1155
1301
|
code = params.get("code");
|
|
1156
1302
|
state = params.get("state");
|
|
1157
|
-
|
|
1158
|
-
if (!state || state !== storedState) {
|
|
1159
|
-
return;
|
|
1160
|
-
}
|
|
1303
|
+
validateState(state);
|
|
1161
1304
|
if (code) {
|
|
1162
1305
|
options.tokens.set("authorization_code", code);
|
|
1163
1306
|
}
|
|
@@ -1165,14 +1308,14 @@
|
|
|
1165
1308
|
}
|
|
1166
1309
|
}
|
|
1167
1310
|
async function fetchAccessToken() {
|
|
1168
|
-
if (
|
|
1311
|
+
if (oauth2.grant_type === "authorization_code" && !options.tokens.has("authorization_code")) {
|
|
1169
1312
|
let authReqURL = await getAuthorizationCodeURL();
|
|
1170
1313
|
if (!options.authorize_callback || typeof options.authorize_callback !== "function") {
|
|
1171
1314
|
throw metroError("oauth2mw: oauth2 with grant_type:authorization_code requires a callback function in client options.authorize_callback");
|
|
1172
1315
|
}
|
|
1173
|
-
let
|
|
1174
|
-
if (
|
|
1175
|
-
|
|
1316
|
+
let authorization = await options.authorize_callback(authReqURL);
|
|
1317
|
+
if (authorization) {
|
|
1318
|
+
storeAuthorizationResult(authorization);
|
|
1176
1319
|
} else {
|
|
1177
1320
|
return false;
|
|
1178
1321
|
}
|
|
@@ -1184,18 +1327,7 @@
|
|
|
1184
1327
|
throw metroError("OAuth2mw: fetch access_token: " + response2.status + ": " + response2.statusText + " (" + msg + ")", { cause: tokenReq });
|
|
1185
1328
|
}
|
|
1186
1329
|
let data = await response2.json();
|
|
1187
|
-
|
|
1188
|
-
value: data.access_token,
|
|
1189
|
-
expires: getExpires(data.expires_in),
|
|
1190
|
-
type: data.token_type,
|
|
1191
|
-
scope: data.scope
|
|
1192
|
-
});
|
|
1193
|
-
if (data.refresh_token) {
|
|
1194
|
-
let token = {
|
|
1195
|
-
value: data.refresh_token
|
|
1196
|
-
};
|
|
1197
|
-
options.tokens.set("refresh_token", token);
|
|
1198
|
-
}
|
|
1330
|
+
storeTokenResponse(data);
|
|
1199
1331
|
options.tokens.delete("authorization_code");
|
|
1200
1332
|
return data;
|
|
1201
1333
|
}
|
|
@@ -1203,88 +1335,72 @@
|
|
|
1203
1335
|
let refreshTokenReq = getAccessTokenRequest("refresh_token");
|
|
1204
1336
|
let response2 = await options.client.post(refreshTokenReq);
|
|
1205
1337
|
if (!response2.ok) {
|
|
1206
|
-
|
|
1338
|
+
let msg = await response2.text();
|
|
1339
|
+
throw metroError("OAuth2mw: refresh access_token: " + response2.status + ": " + response2.statusText + " (" + msg + ")", { cause: refreshTokenReq });
|
|
1207
1340
|
}
|
|
1208
1341
|
let data = await response2.json();
|
|
1209
|
-
|
|
1210
|
-
value: data.access_token,
|
|
1211
|
-
expires: getExpires(data.expires_in),
|
|
1212
|
-
type: data.token_type,
|
|
1213
|
-
scope: data.scope
|
|
1214
|
-
});
|
|
1215
|
-
if (data.refresh_token) {
|
|
1216
|
-
let token = {
|
|
1217
|
-
value: data.refresh_token
|
|
1218
|
-
};
|
|
1219
|
-
options.tokens.set("refresh_token", token);
|
|
1220
|
-
} else {
|
|
1221
|
-
return false;
|
|
1222
|
-
}
|
|
1342
|
+
storeTokenResponse(data);
|
|
1223
1343
|
return data;
|
|
1224
1344
|
}
|
|
1225
1345
|
async function getAuthorizationCodeURL() {
|
|
1226
|
-
if (!
|
|
1346
|
+
if (!oauth2.authorization_endpoint) {
|
|
1227
1347
|
throw metroError("oauth2mw: Missing options.oauth2_configuration.authorization_endpoint");
|
|
1228
1348
|
}
|
|
1229
|
-
let url2 = url(
|
|
1230
|
-
assert(
|
|
1349
|
+
let url2 = url(oauth2.authorization_endpoint, { hash: "" });
|
|
1350
|
+
assert(oauth2, {
|
|
1231
1351
|
client_id: /.+/,
|
|
1232
1352
|
redirect_uri: /.+/,
|
|
1233
1353
|
scope: /.*/
|
|
1234
1354
|
});
|
|
1235
1355
|
let search = {
|
|
1236
1356
|
response_type: "code",
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
state: oauth22.state || createState(40)
|
|
1241
|
-
// OAuth2.1 RFC says optional, but its a good idea to always add/check it
|
|
1357
|
+
client_id: oauth2.client_id,
|
|
1358
|
+
redirect_uri: oauth2.redirect_uri,
|
|
1359
|
+
state: oauth2.state || createState(40)
|
|
1242
1360
|
};
|
|
1243
|
-
if (
|
|
1244
|
-
search.response_type =
|
|
1361
|
+
if (oauth2.response_type) {
|
|
1362
|
+
search.response_type = oauth2.response_type;
|
|
1245
1363
|
}
|
|
1246
|
-
if (
|
|
1247
|
-
search.response_mode =
|
|
1364
|
+
if (oauth2.response_mode) {
|
|
1365
|
+
search.response_mode = oauth2.response_mode;
|
|
1248
1366
|
}
|
|
1249
1367
|
options.state.set(search.state);
|
|
1250
|
-
if (
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
if (oauth22.code_verifier) {
|
|
1254
|
-
options.tokens.set("code_verifier", oauth22.code_verifier);
|
|
1255
|
-
search.code_challenge = await generateCodeChallenge(oauth22.code_verifier);
|
|
1368
|
+
if (oauth2.code_verifier) {
|
|
1369
|
+
options.tokens.set("code_verifier", oauth2.code_verifier);
|
|
1370
|
+
search.code_challenge = await generateCodeChallenge(oauth2.code_verifier);
|
|
1256
1371
|
search.code_challenge_method = "S256";
|
|
1257
1372
|
}
|
|
1258
|
-
if (
|
|
1259
|
-
search.scope =
|
|
1373
|
+
if (oauth2.scope) {
|
|
1374
|
+
search.scope = oauth2.scope;
|
|
1375
|
+
}
|
|
1376
|
+
if (oauth2.prompt) {
|
|
1377
|
+
search.prompt = oauth2.prompt;
|
|
1260
1378
|
}
|
|
1261
|
-
if (
|
|
1262
|
-
search.
|
|
1379
|
+
if (oauth2.nonce) {
|
|
1380
|
+
search.nonce = oauth2.nonce;
|
|
1263
1381
|
}
|
|
1264
1382
|
return url(url2, { search });
|
|
1265
1383
|
}
|
|
1266
1384
|
function getAccessTokenRequest(grant_type = null) {
|
|
1267
|
-
assert(
|
|
1385
|
+
assert(oauth2, {
|
|
1268
1386
|
client_id: /.+/,
|
|
1269
1387
|
redirect_uri: /.+/
|
|
1270
1388
|
});
|
|
1271
|
-
if (!
|
|
1389
|
+
if (!oauth2.token_endpoint) {
|
|
1272
1390
|
throw metroError("oauth2mw: Missing options.endpoints.token url");
|
|
1273
1391
|
}
|
|
1274
|
-
let url2 = url(
|
|
1392
|
+
let url2 = url(oauth2.token_endpoint, { hash: "" });
|
|
1275
1393
|
let params = {
|
|
1276
|
-
grant_type: grant_type ||
|
|
1277
|
-
client_id: oauth22.client_id
|
|
1394
|
+
grant_type: grant_type || oauth2.grant_type
|
|
1278
1395
|
};
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
params.scope = oauth22.scope;
|
|
1396
|
+
let headers = {};
|
|
1397
|
+
applyTokenEndpointAuthentication(params, headers);
|
|
1398
|
+
if (oauth2.scope) {
|
|
1399
|
+
params.scope = oauth2.scope;
|
|
1284
1400
|
}
|
|
1285
1401
|
switch (params.grant_type) {
|
|
1286
1402
|
case "authorization_code":
|
|
1287
|
-
params.redirect_uri =
|
|
1403
|
+
params.redirect_uri = oauth2.redirect_uri;
|
|
1288
1404
|
params.code = options.tokens.get("authorization_code");
|
|
1289
1405
|
const code_verifier = options.tokens.get("code_verifier");
|
|
1290
1406
|
if (code_verifier) {
|
|
@@ -1294,19 +1410,141 @@
|
|
|
1294
1410
|
case "client_credentials":
|
|
1295
1411
|
break;
|
|
1296
1412
|
case "refresh_token":
|
|
1297
|
-
params.refresh_token = options.tokens.get("refresh_token");
|
|
1413
|
+
params.refresh_token = tokenValue(options.tokens.get("refresh_token"));
|
|
1298
1414
|
break;
|
|
1299
1415
|
default:
|
|
1300
|
-
throw new Error("Unknown grant_type: ".
|
|
1416
|
+
throw new Error("Unknown grant_type: " + params.grant_type);
|
|
1301
1417
|
break;
|
|
1302
1418
|
}
|
|
1303
|
-
return request(url2, { method: "POST", body: new URLSearchParams(params) });
|
|
1419
|
+
return request(url2, { method: "POST", headers, body: new URLSearchParams(params) });
|
|
1420
|
+
}
|
|
1421
|
+
function applyTokenEndpointAuthentication(params, headers) {
|
|
1422
|
+
const method = tokenEndpointAuthMethod(oauth2);
|
|
1423
|
+
if (method === "none") {
|
|
1424
|
+
params.client_id = oauth2.client_id;
|
|
1425
|
+
return;
|
|
1426
|
+
}
|
|
1427
|
+
if (!oauth2.client_secret) {
|
|
1428
|
+
throw metroError("oauth2mw: token_endpoint_auth_method " + method + " requires oauth2_configuration.client_secret");
|
|
1429
|
+
}
|
|
1430
|
+
if (method === "client_secret_post") {
|
|
1431
|
+
params.client_id = oauth2.client_id;
|
|
1432
|
+
params.client_secret = oauth2.client_secret;
|
|
1433
|
+
return;
|
|
1434
|
+
}
|
|
1435
|
+
if (method === "client_secret_basic") {
|
|
1436
|
+
headers.Authorization = basicAuth(oauth2.client_id, oauth2.client_secret);
|
|
1437
|
+
return;
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
function storeAuthorizationResult(authorization) {
|
|
1441
|
+
let code = authorization;
|
|
1442
|
+
if (authorization && typeof authorization === "object") {
|
|
1443
|
+
if (authorization.error) {
|
|
1444
|
+
throw metroError("oauth2mw: authorization failed: " + authorization.error);
|
|
1445
|
+
}
|
|
1446
|
+
validateState(authorization.state);
|
|
1447
|
+
code = authorization.authorization_code || authorization.code;
|
|
1448
|
+
}
|
|
1449
|
+
if (!code) {
|
|
1450
|
+
throw metroError("oauth2mw: authorization callback did not return an authorization code");
|
|
1451
|
+
}
|
|
1452
|
+
options.tokens.set("authorization_code", code);
|
|
1453
|
+
}
|
|
1454
|
+
function validateState(state) {
|
|
1455
|
+
let storedState = options.state.get();
|
|
1456
|
+
if (!state || state !== storedState) {
|
|
1457
|
+
throw metroError("oauth2mw: authorization state mismatch");
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
function storeTokenResponse(data) {
|
|
1461
|
+
const token = validateTokenResponse(data);
|
|
1462
|
+
options.tokens.set("access_token", token);
|
|
1463
|
+
if (data.refresh_token) {
|
|
1464
|
+
options.tokens.set("refresh_token", { value: data.refresh_token });
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
}
|
|
1468
|
+
function shouldAuthorizeResponse(res) {
|
|
1469
|
+
if (!res) {
|
|
1470
|
+
return false;
|
|
1471
|
+
}
|
|
1472
|
+
if (res.status === 400) {
|
|
1473
|
+
return true;
|
|
1304
1474
|
}
|
|
1475
|
+
const challenge = parseBearerChallenge(res.headers?.get("WWW-Authenticate"));
|
|
1476
|
+
if (challenge?.error === "insufficient_scope") {
|
|
1477
|
+
return false;
|
|
1478
|
+
}
|
|
1479
|
+
return res.status === 401;
|
|
1480
|
+
}
|
|
1481
|
+
function normalizeInitialToken(name, token) {
|
|
1482
|
+
if (name === "access_token" && token && typeof token === "object") {
|
|
1483
|
+
return token;
|
|
1484
|
+
}
|
|
1485
|
+
if (name === "access_token") {
|
|
1486
|
+
return { value: token, type: "Bearer", expires: null };
|
|
1487
|
+
}
|
|
1488
|
+
if (name === "refresh_token" && token && typeof token === "object") {
|
|
1489
|
+
return token;
|
|
1490
|
+
}
|
|
1491
|
+
return token;
|
|
1492
|
+
}
|
|
1493
|
+
function validateTokenResponse(data) {
|
|
1494
|
+
if (!data || typeof data !== "object") {
|
|
1495
|
+
throw metroError("OAuth2mw: token endpoint did not return a JSON object");
|
|
1496
|
+
}
|
|
1497
|
+
if (!data.access_token) {
|
|
1498
|
+
throw metroError("OAuth2mw: token response did not include access_token");
|
|
1499
|
+
}
|
|
1500
|
+
if (!data.token_type) {
|
|
1501
|
+
throw metroError("OAuth2mw: token response did not include token_type");
|
|
1502
|
+
}
|
|
1503
|
+
const tokenType = normalizeTokenType(data.token_type);
|
|
1504
|
+
return {
|
|
1505
|
+
value: data.access_token,
|
|
1506
|
+
expires: data.expires_in === void 0 ? null : getExpires(data.expires_in),
|
|
1507
|
+
type: tokenType,
|
|
1508
|
+
scope: data.scope
|
|
1509
|
+
};
|
|
1510
|
+
}
|
|
1511
|
+
function normalizeTokenType(type) {
|
|
1512
|
+
const normalized = SUPPORTED_TOKEN_TYPES.get(String(type).toLowerCase());
|
|
1513
|
+
if (!normalized) {
|
|
1514
|
+
throw metroError("OAuth2mw: unsupported token_type " + type);
|
|
1515
|
+
}
|
|
1516
|
+
return normalized;
|
|
1517
|
+
}
|
|
1518
|
+
function tokenEndpointAuthMethod(oauth2) {
|
|
1519
|
+
const method = oauth2.token_endpoint_auth_method || (oauth2.client_secret ? "client_secret_post" : "none");
|
|
1520
|
+
if (!SUPPORTED_TOKEN_ENDPOINT_AUTH_METHODS.has(method)) {
|
|
1521
|
+
throw metroError("oauth2mw: unsupported token_endpoint_auth_method " + method);
|
|
1522
|
+
}
|
|
1523
|
+
return method;
|
|
1524
|
+
}
|
|
1525
|
+
function basicAuth(clientId, clientSecret) {
|
|
1526
|
+
const value = formEncode(clientId) + ":" + formEncode(clientSecret);
|
|
1527
|
+
return "Basic " + base64_encode(value);
|
|
1528
|
+
}
|
|
1529
|
+
function formEncode(value) {
|
|
1530
|
+
return encodeURIComponent(value).replace(/%20/g, "+");
|
|
1531
|
+
}
|
|
1532
|
+
function base64_encode(value) {
|
|
1533
|
+
if (typeof btoa === "function") {
|
|
1534
|
+
return btoa(value);
|
|
1535
|
+
}
|
|
1536
|
+
return Buffer.from(value, "binary").toString("base64");
|
|
1537
|
+
}
|
|
1538
|
+
function tokenValue(token) {
|
|
1539
|
+
return token && typeof token === "object" ? token.value : token;
|
|
1305
1540
|
}
|
|
1306
1541
|
function isExpired(token) {
|
|
1307
1542
|
if (!token) {
|
|
1308
1543
|
return true;
|
|
1309
1544
|
}
|
|
1545
|
+
if (!token.expires) {
|
|
1546
|
+
return false;
|
|
1547
|
+
}
|
|
1310
1548
|
let expires = new Date(token.expires);
|
|
1311
1549
|
let now = /* @__PURE__ */ new Date();
|
|
1312
1550
|
return now.getTime() > expires.getTime();
|
|
@@ -1328,8 +1566,8 @@
|
|
|
1328
1566
|
return base64url_encode(code_verifier);
|
|
1329
1567
|
}
|
|
1330
1568
|
async function generateCodeChallenge(code_verifier) {
|
|
1331
|
-
const
|
|
1332
|
-
const data =
|
|
1569
|
+
const encoder3 = new TextEncoder();
|
|
1570
|
+
const data = encoder3.encode(code_verifier);
|
|
1333
1571
|
const challenge = await globalThis.crypto.subtle.digest("SHA-256", data);
|
|
1334
1572
|
return base64url_encode(challenge);
|
|
1335
1573
|
}
|
|
@@ -1338,6 +1576,11 @@
|
|
|
1338
1576
|
return btoa(byteString).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
1339
1577
|
}
|
|
1340
1578
|
function createState(length) {
|
|
1579
|
+
const bytes = new Uint8Array(Math.ceil(length * 3 / 4) + 1);
|
|
1580
|
+
if (globalThis.crypto?.getRandomValues) {
|
|
1581
|
+
globalThis.crypto.getRandomValues(bytes);
|
|
1582
|
+
return base64url_encode(bytes).slice(0, length);
|
|
1583
|
+
}
|
|
1341
1584
|
const validChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
1342
1585
|
let randomState = "";
|
|
1343
1586
|
let counter = 0;
|
|
@@ -1361,330 +1604,31 @@
|
|
|
1361
1604
|
}
|
|
1362
1605
|
return true;
|
|
1363
1606
|
}
|
|
1364
|
-
function
|
|
1365
|
-
if (typeof
|
|
1366
|
-
|
|
1367
|
-
}
|
|
1368
|
-
let accessToken = tokens.get("access_token");
|
|
1369
|
-
if (accessToken && !isExpired(accessToken)) {
|
|
1370
|
-
return true;
|
|
1371
|
-
}
|
|
1372
|
-
let refreshToken = tokens.get("refresh_token");
|
|
1373
|
-
if (refreshToken) {
|
|
1374
|
-
return true;
|
|
1375
|
-
}
|
|
1376
|
-
return false;
|
|
1377
|
-
}
|
|
1378
|
-
|
|
1379
|
-
// node_modules/@muze-nl/metro-oauth2/src/oauth2.mockserver.mjs
|
|
1380
|
-
var oauth2_mockserver_exports = {};
|
|
1381
|
-
__export(oauth2_mockserver_exports, {
|
|
1382
|
-
default: () => oauth2mockserver
|
|
1383
|
-
});
|
|
1384
|
-
var baseResponse = {
|
|
1385
|
-
status: 200,
|
|
1386
|
-
statusText: "OK",
|
|
1387
|
-
headers: {
|
|
1388
|
-
"Content-Type": "application/json"
|
|
1607
|
+
function parseBearerChallenge(value) {
|
|
1608
|
+
if (!value || typeof value !== "string") {
|
|
1609
|
+
return null;
|
|
1389
1610
|
}
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
"Content-Type": "application/json"
|
|
1397
|
-
},
|
|
1398
|
-
body: JSON.stringify({
|
|
1399
|
-
error: "invalid_request",
|
|
1400
|
-
error_description: error3
|
|
1401
|
-
})
|
|
1402
|
-
};
|
|
1403
|
-
};
|
|
1404
|
-
var error2;
|
|
1405
|
-
var pkce = {};
|
|
1406
|
-
function oauth2mockserver(options = {}) {
|
|
1407
|
-
const defaultOptions = {
|
|
1408
|
-
"PKCE": false,
|
|
1409
|
-
"DPoP": false
|
|
1410
|
-
};
|
|
1411
|
-
options = Object.assign({}, defaultOptions, options);
|
|
1412
|
-
return async (req, next) => {
|
|
1413
|
-
let url2 = everything_default.url(req.url);
|
|
1414
|
-
switch (url2.pathname) {
|
|
1415
|
-
case "/authorize/":
|
|
1416
|
-
if (error2 = fails(url2.searchParams, {
|
|
1417
|
-
response_type: "code",
|
|
1418
|
-
client_id: "mockClientId",
|
|
1419
|
-
state: Optional(/.*/)
|
|
1420
|
-
})) {
|
|
1421
|
-
return everything_default.response(badRequest(error2));
|
|
1422
|
-
}
|
|
1423
|
-
if (url2.searchParams.has("code_challenge")) {
|
|
1424
|
-
if (!url2.searchParams.has("code_challenge_method")) {
|
|
1425
|
-
return everything_default.response(badRequest("missing code_challenge_method"));
|
|
1426
|
-
}
|
|
1427
|
-
pkce.code_challenge = url2.searchParams.get("code_challenge");
|
|
1428
|
-
pkce.code_challenge_method = url2.searchParams.get("code_challenge_method");
|
|
1429
|
-
}
|
|
1430
|
-
return everything_default.response(baseResponse, {
|
|
1431
|
-
body: JSON.stringify({
|
|
1432
|
-
code: "mockAuthorizeToken",
|
|
1433
|
-
state: url2.searchParams.get("state")
|
|
1434
|
-
})
|
|
1435
|
-
});
|
|
1436
|
-
break;
|
|
1437
|
-
case "/token/":
|
|
1438
|
-
if (req.data instanceof URLSearchParams) {
|
|
1439
|
-
let body = {};
|
|
1440
|
-
req.data.forEach((value, key) => body[key] = value);
|
|
1441
|
-
req = req.with({ body });
|
|
1442
|
-
}
|
|
1443
|
-
if (error2 = fails(req, {
|
|
1444
|
-
method: "POST",
|
|
1445
|
-
data: {
|
|
1446
|
-
grant_type: oneOf("refresh_token", "authorization_code")
|
|
1447
|
-
}
|
|
1448
|
-
})) {
|
|
1449
|
-
return everything_default.response(badRequest(error2));
|
|
1450
|
-
}
|
|
1451
|
-
switch (req.data.grant_type) {
|
|
1452
|
-
case "refresh_token":
|
|
1453
|
-
if (error2 = fails(req.data, oneOf({
|
|
1454
|
-
refresh_token: "mockRefreshToken",
|
|
1455
|
-
client_id: "mockClientId",
|
|
1456
|
-
client_secret: "mockClientSecret"
|
|
1457
|
-
}, {
|
|
1458
|
-
refresh_token: "mockRefreshToken",
|
|
1459
|
-
client_id: "mockClientId",
|
|
1460
|
-
code_verifier: /.+/
|
|
1461
|
-
}))) {
|
|
1462
|
-
return everything_default.response(badRequest(error2));
|
|
1463
|
-
}
|
|
1464
|
-
break;
|
|
1465
|
-
case "access_token":
|
|
1466
|
-
if (error2 = fails(req.data, oneOf({
|
|
1467
|
-
client_id: "mockClientId",
|
|
1468
|
-
client_secret: "mockClientSecret"
|
|
1469
|
-
}, {
|
|
1470
|
-
client_id: "mockClientId",
|
|
1471
|
-
code_challenge: /.*/,
|
|
1472
|
-
//FIXME: check that this matches code_verifier
|
|
1473
|
-
code_challenge_method: "S256"
|
|
1474
|
-
}))) {
|
|
1475
|
-
return everything_default.response(badRequest(error2));
|
|
1476
|
-
}
|
|
1477
|
-
break;
|
|
1478
|
-
}
|
|
1479
|
-
return everything_default.response(baseResponse, {
|
|
1480
|
-
body: JSON.stringify({
|
|
1481
|
-
access_token: "mockAccessToken",
|
|
1482
|
-
token_type: "mockExample",
|
|
1483
|
-
expires_in: 3600,
|
|
1484
|
-
refresh_token: "mockRefreshToken",
|
|
1485
|
-
example_parameter: "mockExampleValue"
|
|
1486
|
-
})
|
|
1487
|
-
});
|
|
1488
|
-
break;
|
|
1489
|
-
case "/protected/":
|
|
1490
|
-
let auth = req.headers.get("Authorization");
|
|
1491
|
-
let [type, token] = auth ? auth.split(" ") : [];
|
|
1492
|
-
if (!token || token !== "mockAccessToken") {
|
|
1493
|
-
return everything_default.response({
|
|
1494
|
-
status: 401,
|
|
1495
|
-
statusText: "Forbidden",
|
|
1496
|
-
body: "401 Forbidden"
|
|
1497
|
-
});
|
|
1498
|
-
}
|
|
1499
|
-
return everything_default.response(baseResponse, {
|
|
1500
|
-
body: JSON.stringify({
|
|
1501
|
-
result: "Success"
|
|
1502
|
-
})
|
|
1503
|
-
});
|
|
1504
|
-
break;
|
|
1505
|
-
case "/public/":
|
|
1506
|
-
return everything_default.response(baseResponse, {
|
|
1507
|
-
body: JSON.stringify({
|
|
1508
|
-
result: "Success"
|
|
1509
|
-
})
|
|
1510
|
-
});
|
|
1511
|
-
break;
|
|
1512
|
-
default:
|
|
1513
|
-
return everything_default.response({
|
|
1514
|
-
status: 404,
|
|
1515
|
-
statusText: "not found",
|
|
1516
|
-
body: "404 Not Found " + url2
|
|
1517
|
-
});
|
|
1518
|
-
break;
|
|
1519
|
-
}
|
|
1520
|
-
};
|
|
1521
|
-
}
|
|
1522
|
-
|
|
1523
|
-
// node_modules/@muze-nl/metro-oauth2/src/oauth2.discovery.mjs
|
|
1524
|
-
var oauth2_discovery_exports = {};
|
|
1525
|
-
__export(oauth2_discovery_exports, {
|
|
1526
|
-
default: () => makeClient
|
|
1527
|
-
});
|
|
1528
|
-
var validAlgorithms = [
|
|
1529
|
-
"HS256",
|
|
1530
|
-
"HS384",
|
|
1531
|
-
"HS512",
|
|
1532
|
-
"RS256",
|
|
1533
|
-
"RS384",
|
|
1534
|
-
"RS512",
|
|
1535
|
-
"ES256",
|
|
1536
|
-
"ES384",
|
|
1537
|
-
"ES512"
|
|
1538
|
-
];
|
|
1539
|
-
var validAuthMethods = [
|
|
1540
|
-
"client_secret_post",
|
|
1541
|
-
"client_secret_base",
|
|
1542
|
-
"client_secret_jwt",
|
|
1543
|
-
"private_key_jwt"
|
|
1544
|
-
];
|
|
1545
|
-
var oauth_authorization_server_metadata = {
|
|
1546
|
-
issuer: Required(validURL),
|
|
1547
|
-
authorization_endpoint: Required(validURL),
|
|
1548
|
-
token_endpoint: Required(validURL),
|
|
1549
|
-
jwks_uri: Optional(validURL),
|
|
1550
|
-
registration_endpoint: Optional(validURL),
|
|
1551
|
-
scopes_supported: Recommended([]),
|
|
1552
|
-
response_types_supported: Required(anyOf("code", "token")),
|
|
1553
|
-
response_modes_supported: Optional([]),
|
|
1554
|
-
grant_types_supported: Optional([]),
|
|
1555
|
-
token_endpoint_auth_methods_supported: Optional([]),
|
|
1556
|
-
token_endpoint_auth_signing_alg_values_supported: Optional([]),
|
|
1557
|
-
service_documentation: Optional(validURL),
|
|
1558
|
-
ui_locales_supported: Optional([]),
|
|
1559
|
-
op_policy_uri: Optional(validURL),
|
|
1560
|
-
op_tos_uri: Optional(validURL),
|
|
1561
|
-
revocation_endpoint: Optional(validURL),
|
|
1562
|
-
revocation_endpoint_auth_methods_supported: Optional(validAuthMethods),
|
|
1563
|
-
revocation_endpoint_auth_signing_alg_values_supported: Optional(validAlgorithms),
|
|
1564
|
-
introspection_endpoint: Optional(validURL),
|
|
1565
|
-
introspection_endpoint_auth_methods_supported: Optional(validAuthMethods),
|
|
1566
|
-
introspection_endpoint_auth_signing_alg_values_supported: Optional(validAlgorithms),
|
|
1567
|
-
code_challendge_methods_supported: Optional([])
|
|
1568
|
-
};
|
|
1569
|
-
function makeClient(options = {}) {
|
|
1570
|
-
const defaultOptions = {
|
|
1571
|
-
client: everything_default.client()
|
|
1572
|
-
};
|
|
1573
|
-
options = Object.assign({}, defaultOptions, options);
|
|
1574
|
-
assert(options, {
|
|
1575
|
-
issuer: Required(validURL)
|
|
1576
|
-
});
|
|
1577
|
-
const oauth_authorization_server_configuration = fetchWellknownOauthAuthorizationServer(options.issuer);
|
|
1578
|
-
return options.client.with(options.issuer);
|
|
1579
|
-
}
|
|
1580
|
-
async function fetchWellknownOauthAuthorizationServer(issuer, client2) {
|
|
1581
|
-
let res = client2.get(everything_default.url(issuer, ".wellknown/oauth_authorization_server"));
|
|
1582
|
-
if (res.ok) {
|
|
1583
|
-
assert(res.headers.get("Content-Type"), /application\/json.*/);
|
|
1584
|
-
let configuration = await res.json();
|
|
1585
|
-
assert(configuration, oauth_authorization_server_metadata);
|
|
1586
|
-
return configuration;
|
|
1611
|
+
const trimmed = value.trim();
|
|
1612
|
+
const index = trimmed.search(/\s/);
|
|
1613
|
+
const scheme = index < 0 ? trimmed : trimmed.slice(0, index);
|
|
1614
|
+
const rest = index < 0 ? "" : trimmed.slice(index + 1);
|
|
1615
|
+
if (!["bearer", "dpop"].includes(scheme.toLowerCase())) {
|
|
1616
|
+
return null;
|
|
1587
1617
|
}
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
let params = new URLSearchParams(window.location.search);
|
|
1596
|
-
if (!params.has("code") && window.location.hash) {
|
|
1597
|
-
let query = window.location.hash.substr(1);
|
|
1598
|
-
params = new URLSearchParams("?" + query);
|
|
1599
|
-
}
|
|
1600
|
-
let parent = window.parent !== window ? window.parent : window.opener;
|
|
1601
|
-
if (!parent) {
|
|
1602
|
-
console.error("No parent window found, cannot post authorization code (or error)");
|
|
1603
|
-
} else {
|
|
1604
|
-
if (params.has("code")) {
|
|
1605
|
-
parent.postMessage({
|
|
1606
|
-
authorization_code: params.get("code")
|
|
1607
|
-
}, origin);
|
|
1608
|
-
success = true;
|
|
1609
|
-
} else if (params.has("error")) {
|
|
1610
|
-
parent.postMessage({
|
|
1611
|
-
error: params.get("error")
|
|
1612
|
-
}, origin);
|
|
1613
|
-
} else {
|
|
1614
|
-
parent.postMessage({
|
|
1615
|
-
error: "Could not find an authorization_code"
|
|
1616
|
-
}, origin);
|
|
1618
|
+
const result = { scheme };
|
|
1619
|
+
const pattern = /([A-Za-z][A-Za-z0-9_-]*)=("(?:[^"\\]|\\.)*"|[^,\s]*)/g;
|
|
1620
|
+
let match;
|
|
1621
|
+
while (match = pattern.exec(rest)) {
|
|
1622
|
+
let value2 = match[2];
|
|
1623
|
+
if (value2.startsWith('"') && value2.endsWith('"')) {
|
|
1624
|
+
value2 = value2.slice(1, -1).replace(/\\"/g, '"');
|
|
1617
1625
|
}
|
|
1626
|
+
result[match[1]] = value2;
|
|
1618
1627
|
}
|
|
1619
|
-
return
|
|
1620
|
-
}
|
|
1621
|
-
function authorizePopup(authorizationCodeURL) {
|
|
1622
|
-
return new Promise((resolve, reject) => {
|
|
1623
|
-
addEventListener("message", (event) => {
|
|
1624
|
-
if (event.data.authorization_code) {
|
|
1625
|
-
resolve(event.data.authorization_code);
|
|
1626
|
-
} else if (event.data.error) {
|
|
1627
|
-
reject(event.data.error);
|
|
1628
|
-
} else {
|
|
1629
|
-
reject("Unknown authorization error");
|
|
1630
|
-
}
|
|
1631
|
-
}, { once: true });
|
|
1632
|
-
window.open(authorizationCodeURL);
|
|
1633
|
-
});
|
|
1634
|
-
}
|
|
1635
|
-
|
|
1636
|
-
// node_modules/@muze-nl/metro-oauth2/src/keysstore.mjs
|
|
1637
|
-
function keysStore() {
|
|
1638
|
-
return new Promise((resolve, reject) => {
|
|
1639
|
-
const request2 = globalThis.indexedDB.open("metro", 1);
|
|
1640
|
-
request2.onupgradeneeded = () => request2.result.createObjectStore("keyPairs", { keyPath: "domain" });
|
|
1641
|
-
request2.onerror = (event) => {
|
|
1642
|
-
reject(event);
|
|
1643
|
-
};
|
|
1644
|
-
request2.onsuccess = (event) => {
|
|
1645
|
-
const db = event.target.result;
|
|
1646
|
-
resolve({
|
|
1647
|
-
set: function(value, key) {
|
|
1648
|
-
return new Promise((resolve2, reject2) => {
|
|
1649
|
-
const tx = db.transaction("keyPairs", "readwrite", { durability: "strict" });
|
|
1650
|
-
const objectStore = tx.objectStore("keyPairs");
|
|
1651
|
-
tx.oncomplete = () => {
|
|
1652
|
-
resolve2();
|
|
1653
|
-
};
|
|
1654
|
-
tx.onerror = reject2;
|
|
1655
|
-
objectStore.put(value, key);
|
|
1656
|
-
});
|
|
1657
|
-
},
|
|
1658
|
-
get: function(key) {
|
|
1659
|
-
return new Promise((resolve2, reject2) => {
|
|
1660
|
-
const tx = db.transaction("keyPairs", "readonly");
|
|
1661
|
-
const objectStore = tx.objectStore("keyPairs");
|
|
1662
|
-
const request3 = objectStore.get(key);
|
|
1663
|
-
request3.onsuccess = () => {
|
|
1664
|
-
resolve2(request3.result);
|
|
1665
|
-
};
|
|
1666
|
-
request3.onerror = reject2;
|
|
1667
|
-
tx.onerror = reject2;
|
|
1668
|
-
});
|
|
1669
|
-
},
|
|
1670
|
-
clear: function() {
|
|
1671
|
-
return new Promise((resolve2, reject2) => {
|
|
1672
|
-
const tx = db.transaction("keyPairs", "readwrite");
|
|
1673
|
-
const objectStore = tx.objectStore("keyPairs");
|
|
1674
|
-
const request3 = objectStore.clear();
|
|
1675
|
-
request3.onsuccess = () => {
|
|
1676
|
-
resolve2();
|
|
1677
|
-
};
|
|
1678
|
-
request3.onerror = reject2;
|
|
1679
|
-
tx.onerror = reject2;
|
|
1680
|
-
});
|
|
1681
|
-
}
|
|
1682
|
-
});
|
|
1683
|
-
};
|
|
1684
|
-
});
|
|
1628
|
+
return result;
|
|
1685
1629
|
}
|
|
1686
1630
|
|
|
1687
|
-
// node_modules/dpop/build/index.js
|
|
1631
|
+
// ../../node_modules/dpop/build/index.js
|
|
1688
1632
|
var encoder = new TextEncoder();
|
|
1689
1633
|
var decoder = new TextDecoder();
|
|
1690
1634
|
function buf(input) {
|
|
@@ -1749,17 +1693,17 @@
|
|
|
1749
1693
|
return encodeBase64Url(input);
|
|
1750
1694
|
}
|
|
1751
1695
|
var UnsupportedOperationError = class extends Error {
|
|
1752
|
-
constructor(
|
|
1696
|
+
constructor(message2) {
|
|
1753
1697
|
var _a;
|
|
1754
|
-
super(
|
|
1698
|
+
super(message2 !== null && message2 !== void 0 ? message2 : "operation not supported");
|
|
1755
1699
|
this.name = this.constructor.name;
|
|
1756
1700
|
(_a = Error.captureStackTrace) === null || _a === void 0 ? void 0 : _a.call(Error, this, this.constructor);
|
|
1757
1701
|
}
|
|
1758
1702
|
};
|
|
1759
1703
|
var OperationProcessingError = class extends Error {
|
|
1760
|
-
constructor(
|
|
1704
|
+
constructor(message2) {
|
|
1761
1705
|
var _a;
|
|
1762
|
-
super(
|
|
1706
|
+
super(message2);
|
|
1763
1707
|
this.name = this.constructor.name;
|
|
1764
1708
|
(_a = Error.captureStackTrace) === null || _a === void 0 ? void 0 : _a.call(Error, this, this.constructor);
|
|
1765
1709
|
}
|
|
@@ -1893,45 +1837,96 @@
|
|
|
1893
1837
|
return crypto.subtle.generateKey(algorithm, (_a = options === null || options === void 0 ? void 0 : options.extractable) !== null && _a !== void 0 ? _a : false, ["sign", "verify"]);
|
|
1894
1838
|
}
|
|
1895
1839
|
|
|
1896
|
-
//
|
|
1897
|
-
function
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1840
|
+
// ../metro-oauth2/src/keysstore.mjs
|
|
1841
|
+
function keysStore() {
|
|
1842
|
+
return new Promise((resolve, reject) => {
|
|
1843
|
+
const request2 = globalThis.indexedDB.open("metro", 1);
|
|
1844
|
+
request2.onupgradeneeded = () => request2.result.createObjectStore("keyPairs", { keyPath: "domain" });
|
|
1845
|
+
request2.onerror = (event) => {
|
|
1846
|
+
reject(event);
|
|
1847
|
+
};
|
|
1848
|
+
request2.onsuccess = (event) => {
|
|
1849
|
+
const db = event.target.result;
|
|
1850
|
+
resolve({
|
|
1851
|
+
set: function(value, key) {
|
|
1852
|
+
return new Promise((resolve2, reject2) => {
|
|
1853
|
+
const tx = db.transaction("keyPairs", "readwrite", { durability: "strict" });
|
|
1854
|
+
const objectStore = tx.objectStore("keyPairs");
|
|
1855
|
+
tx.oncomplete = () => {
|
|
1856
|
+
resolve2();
|
|
1857
|
+
};
|
|
1858
|
+
tx.onerror = reject2;
|
|
1859
|
+
objectStore.put(value, key);
|
|
1860
|
+
});
|
|
1861
|
+
},
|
|
1862
|
+
get: function(key) {
|
|
1863
|
+
return new Promise((resolve2, reject2) => {
|
|
1864
|
+
const tx = db.transaction("keyPairs", "readonly");
|
|
1865
|
+
const objectStore = tx.objectStore("keyPairs");
|
|
1866
|
+
const request3 = objectStore.get(key);
|
|
1867
|
+
request3.onsuccess = () => {
|
|
1868
|
+
resolve2(request3.result);
|
|
1869
|
+
};
|
|
1870
|
+
request3.onerror = reject2;
|
|
1871
|
+
tx.onerror = reject2;
|
|
1872
|
+
});
|
|
1873
|
+
},
|
|
1874
|
+
clear: function() {
|
|
1875
|
+
return new Promise((resolve2, reject2) => {
|
|
1876
|
+
const tx = db.transaction("keyPairs", "readwrite");
|
|
1877
|
+
const objectStore = tx.objectStore("keyPairs");
|
|
1878
|
+
const request3 = objectStore.clear();
|
|
1879
|
+
request3.onsuccess = () => {
|
|
1880
|
+
resolve2();
|
|
1881
|
+
};
|
|
1882
|
+
request3.onerror = reject2;
|
|
1883
|
+
tx.onerror = reject2;
|
|
1884
|
+
});
|
|
1885
|
+
}
|
|
1886
|
+
});
|
|
1887
|
+
};
|
|
1888
|
+
});
|
|
1889
|
+
}
|
|
1890
|
+
|
|
1891
|
+
// ../metro-oauth2/src/oauth2.dpop.mjs
|
|
1892
|
+
function dpopmw(options) {
|
|
1893
|
+
assert(options, {
|
|
1894
|
+
site: Required(validURL),
|
|
1895
|
+
authorization_endpoint: Required(validURL),
|
|
1896
|
+
token_endpoint: Required(validURL),
|
|
1897
|
+
dpop_signing_alg_values_supported: Optional([])
|
|
1898
|
+
// this property is unfortunately rarely supported
|
|
1899
|
+
});
|
|
1900
|
+
return async (req, next) => {
|
|
1901
|
+
const keys = await keysStore();
|
|
1902
|
+
let keyInfo = await keys.get(options.site);
|
|
1903
|
+
if (!keyInfo) {
|
|
1904
|
+
let keyPair = await generateKeyPair("ES256");
|
|
1905
|
+
keyInfo = { domain: options.site, keyPair };
|
|
1906
|
+
await keys.set(keyInfo);
|
|
1907
|
+
}
|
|
1908
|
+
const url2 = url(req.url);
|
|
1909
|
+
if (req.url.startsWith(options.authorization_endpoint)) {
|
|
1910
|
+
let params = req.body;
|
|
1911
|
+
if (params instanceof URLSearchParams || params instanceof FormData) {
|
|
1912
|
+
params.set("dpop_jkt", keyInfo.keyPair.publicKey);
|
|
1913
|
+
} else {
|
|
1914
|
+
params.dpop_jkt = keyInfo.keyPair.publicKey;
|
|
1915
|
+
}
|
|
1916
|
+
} else if (req.url.startsWith(options.token_endpoint)) {
|
|
1917
|
+
const dpopHeader = await generateProof(keyInfo.keyPair, req.url, req.method);
|
|
1918
|
+
req = req.with({
|
|
1919
|
+
headers: {
|
|
1920
|
+
"DPoP": dpopHeader
|
|
1921
|
+
}
|
|
1922
|
+
});
|
|
1923
|
+
} else if (req.headers.has("Authorization")) {
|
|
1924
|
+
const nonce = localStorage.getItem(url2.host + ":nonce") || void 0;
|
|
1925
|
+
const accessToken = req.headers.get("Authorization").split(" ")[1];
|
|
1926
|
+
const dpopHeader = await generateProof(keyInfo.keyPair, req.url, req.method, nonce, accessToken);
|
|
1927
|
+
req = req.with({
|
|
1928
|
+
headers: {
|
|
1929
|
+
"Authorization": "DPoP " + accessToken,
|
|
1935
1930
|
"DPoP": dpopHeader
|
|
1936
1931
|
}
|
|
1937
1932
|
});
|
|
@@ -1944,19 +1939,91 @@
|
|
|
1944
1939
|
};
|
|
1945
1940
|
}
|
|
1946
1941
|
|
|
1947
|
-
//
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1942
|
+
// ../metro-middleware/src/json.mjs
|
|
1943
|
+
function jsonmw(options) {
|
|
1944
|
+
options = Object.assign({
|
|
1945
|
+
contentType: "application/json",
|
|
1946
|
+
reviver: null,
|
|
1947
|
+
replacer: null,
|
|
1948
|
+
space: ""
|
|
1949
|
+
}, options);
|
|
1950
|
+
return async function json(req, next) {
|
|
1951
|
+
if (!req.headers.get("Accept")) {
|
|
1952
|
+
req = req.with({
|
|
1953
|
+
headers: {
|
|
1954
|
+
"Accept": options.accept ?? options.contentType
|
|
1955
|
+
}
|
|
1956
|
+
});
|
|
1957
|
+
}
|
|
1958
|
+
if (req.method !== "GET" && req.method !== "HEAD") {
|
|
1959
|
+
if (req.data && typeof req.data == "object" && !(req.data instanceof ReadableStream)) {
|
|
1960
|
+
const contentType = req.headers.get("Content-Type");
|
|
1961
|
+
if (!contentType || isPlainText(contentType)) {
|
|
1962
|
+
req = req.with({
|
|
1963
|
+
headers: {
|
|
1964
|
+
"Content-Type": options.contentType
|
|
1965
|
+
}
|
|
1966
|
+
});
|
|
1967
|
+
}
|
|
1968
|
+
if (isJSON(req.headers.get("Content-Type"))) {
|
|
1969
|
+
req = req.with({
|
|
1970
|
+
body: JSON.stringify(req.data, options.replacer, options.space)
|
|
1971
|
+
});
|
|
1972
|
+
}
|
|
1973
|
+
}
|
|
1974
|
+
}
|
|
1975
|
+
let res = await next(req);
|
|
1976
|
+
if (res && isJSON(res.headers?.get("Content-Type"))) {
|
|
1977
|
+
let tempRes = res.clone();
|
|
1978
|
+
let body = await tempRes.text();
|
|
1979
|
+
if (body === "") {
|
|
1980
|
+
return res;
|
|
1981
|
+
}
|
|
1982
|
+
try {
|
|
1983
|
+
let json2 = JSON.parse(body, options.reviver);
|
|
1984
|
+
return res.with({
|
|
1985
|
+
body: json2
|
|
1986
|
+
});
|
|
1987
|
+
} catch (error2) {
|
|
1988
|
+
if (!res.ok) {
|
|
1989
|
+
return res;
|
|
1990
|
+
}
|
|
1991
|
+
throw parseError(req, res, error2);
|
|
1992
|
+
}
|
|
1993
|
+
}
|
|
1994
|
+
return res;
|
|
1995
|
+
};
|
|
1996
|
+
}
|
|
1997
|
+
function parseError(req, res, cause) {
|
|
1998
|
+
const message2 = "jsonmw: could not parse " + res.headers.get("Content-Type") + " response from " + req.url;
|
|
1999
|
+
const error2 = new Error(message2, { cause });
|
|
2000
|
+
error2.request = req;
|
|
2001
|
+
error2.response = res;
|
|
2002
|
+
return error2;
|
|
2003
|
+
}
|
|
2004
|
+
var jsonRE = /^application\/([a-zA-Z0-9\-_]+\+)?json\b/;
|
|
2005
|
+
function isJSON(contentType) {
|
|
2006
|
+
return jsonRE.exec(contentType);
|
|
2007
|
+
}
|
|
2008
|
+
function isPlainText(contentType) {
|
|
2009
|
+
return /^text\/plain\b/.exec(contentType);
|
|
2010
|
+
}
|
|
2011
|
+
|
|
2012
|
+
// ../metro-middleware/src/thrower.mjs
|
|
2013
|
+
function throwermw(options) {
|
|
2014
|
+
return async function thrower(req, next) {
|
|
2015
|
+
let res = await next(req);
|
|
2016
|
+
if (!res.ok) {
|
|
2017
|
+
if (options && typeof options[res.status] == "function") {
|
|
2018
|
+
res = options[res.status].apply(res, req);
|
|
2019
|
+
} else {
|
|
2020
|
+
throw new Error(res.status + ": " + res.statusText, {
|
|
2021
|
+
cause: res
|
|
2022
|
+
});
|
|
2023
|
+
}
|
|
2024
|
+
}
|
|
2025
|
+
return res;
|
|
2026
|
+
};
|
|
1960
2027
|
}
|
|
1961
2028
|
|
|
1962
2029
|
// src/oidc.util.mjs
|
|
@@ -1984,7 +2051,8 @@
|
|
|
1984
2051
|
"ES384",
|
|
1985
2052
|
"ES512"
|
|
1986
2053
|
];
|
|
1987
|
-
var
|
|
2054
|
+
var validAuthMethods = [
|
|
2055
|
+
"none",
|
|
1988
2056
|
"client_secret_post",
|
|
1989
2057
|
"client_secret_basic",
|
|
1990
2058
|
"client_secret_jwt",
|
|
@@ -1994,14 +2062,15 @@
|
|
|
1994
2062
|
// src/oidc.discovery.mjs
|
|
1995
2063
|
async function oidcDiscovery(options = {}) {
|
|
1996
2064
|
assert(options, {
|
|
1997
|
-
client: Optional(instanceOf(
|
|
2065
|
+
client: Optional(instanceOf(client().constructor)),
|
|
1998
2066
|
issuer: Required(validURL)
|
|
1999
2067
|
});
|
|
2000
2068
|
const defaultOptions = {
|
|
2001
|
-
client:
|
|
2069
|
+
client: client().with(throwermw()).with(jsonmw()),
|
|
2002
2070
|
requireDynamicRegistration: false
|
|
2003
2071
|
};
|
|
2004
2072
|
options = Object.assign({}, defaultOptions, options);
|
|
2073
|
+
options.client = options.client.with(throwermw()).with(jsonmw());
|
|
2005
2074
|
const TestSucceeded = false;
|
|
2006
2075
|
function MustUseHTTPS(url2) {
|
|
2007
2076
|
return TestSucceeded;
|
|
@@ -2030,7 +2099,7 @@
|
|
|
2030
2099
|
// not testing for 'none'
|
|
2031
2100
|
request_object_encryption_alg_values_supported: Optional([]),
|
|
2032
2101
|
request_object_encryption_enc_values_supported: Optional([]),
|
|
2033
|
-
token_endpoint_auth_methods_supported: Optional(anyOf(...
|
|
2102
|
+
token_endpoint_auth_methods_supported: Optional(anyOf(...validAuthMethods)),
|
|
2034
2103
|
token_endpoint_auth_signing_alg_values_supported: Optional(MustInclude("RS256"), not(MustInclude("none"))),
|
|
2035
2104
|
display_values_supported: Optional(anyOf("page", "popup", "touch", "wap")),
|
|
2036
2105
|
claim_types_supported: Optional(anyOf("normal", "aggregated", "distributed")),
|
|
@@ -2044,7 +2113,7 @@
|
|
|
2044
2113
|
op_policy_uri: Optional(validURL),
|
|
2045
2114
|
op_tos_uri: Optional(validURL)
|
|
2046
2115
|
};
|
|
2047
|
-
const configURL =
|
|
2116
|
+
const configURL = url(options.issuer, ".well-known/openid-configuration");
|
|
2048
2117
|
const response2 = await options.client.get(
|
|
2049
2118
|
// https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationRequest
|
|
2050
2119
|
// note: this allows path components in the options.issuer url
|
|
@@ -2083,7 +2152,7 @@
|
|
|
2083
2152
|
request_object_signing_alg: Optional(oneOf(...validJWA)),
|
|
2084
2153
|
request_object_encryption_alg: Optional(oneOf(...validJWA)),
|
|
2085
2154
|
request_object_encryption_enc: Optional(oneOf(...validJWA)),
|
|
2086
|
-
token_endpoint_auth_method: Optional(oneOf(...
|
|
2155
|
+
token_endpoint_auth_method: Optional(oneOf(...validAuthMethods)),
|
|
2087
2156
|
token_endpoint_auth_signing_alg: Optional(oneOf(...validJWA)),
|
|
2088
2157
|
default_max_age: Optional(Number),
|
|
2089
2158
|
require_auth_time: Optional(Boolean),
|
|
@@ -2092,17 +2161,18 @@
|
|
|
2092
2161
|
request_uris: Optional([validURL])
|
|
2093
2162
|
};
|
|
2094
2163
|
assert(options, {
|
|
2095
|
-
client: Optional(instanceOf(
|
|
2164
|
+
client: Optional(instanceOf(client().constructor)),
|
|
2096
2165
|
registration_endpoint: validURL,
|
|
2097
2166
|
client_info: openid_client_metadata
|
|
2098
2167
|
});
|
|
2099
2168
|
const defaultOptions = {
|
|
2100
|
-
client:
|
|
2169
|
+
client: client().with(throwermw()).with(jsonmw()),
|
|
2101
2170
|
client_info: {
|
|
2102
2171
|
redirect_uris: [globalThis.document?.location.href]
|
|
2103
2172
|
}
|
|
2104
2173
|
};
|
|
2105
2174
|
options = Object.assign({}, defaultOptions, options);
|
|
2175
|
+
options.client = options.client.with(throwermw()).with(jsonmw());
|
|
2106
2176
|
if (!options.client_info) {
|
|
2107
2177
|
options.client_info = {};
|
|
2108
2178
|
}
|
|
@@ -2113,8 +2183,8 @@
|
|
|
2113
2183
|
body: options.client_info
|
|
2114
2184
|
});
|
|
2115
2185
|
let info = response2.data;
|
|
2116
|
-
if (!info.client_id
|
|
2117
|
-
throw
|
|
2186
|
+
if (!info.client_id) {
|
|
2187
|
+
throw metroError("metro.oidc: Error: dynamic registration of client failed, no client_id returned", response2);
|
|
2118
2188
|
}
|
|
2119
2189
|
options.client_info = Object.assign(options.client_info, info);
|
|
2120
2190
|
return options.client_info;
|
|
@@ -2140,110 +2210,1422 @@
|
|
|
2140
2210
|
return store;
|
|
2141
2211
|
}
|
|
2142
2212
|
|
|
2143
|
-
//
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2213
|
+
// ../../node_modules/jose/dist/webapi/lib/buffer_utils.js
|
|
2214
|
+
var encoder2 = new TextEncoder();
|
|
2215
|
+
var decoder2 = new TextDecoder();
|
|
2216
|
+
var MAX_INT32 = 2 ** 32;
|
|
2217
|
+
function concat(...buffers) {
|
|
2218
|
+
const size = buffers.reduce((acc, { length }) => acc + length, 0);
|
|
2219
|
+
const buf2 = new Uint8Array(size);
|
|
2220
|
+
let i = 0;
|
|
2221
|
+
for (const buffer of buffers) {
|
|
2222
|
+
buf2.set(buffer, i);
|
|
2223
|
+
i += buffer.length;
|
|
2224
|
+
}
|
|
2225
|
+
return buf2;
|
|
2226
|
+
}
|
|
2227
|
+
function encode(string) {
|
|
2228
|
+
const bytes = new Uint8Array(string.length);
|
|
2229
|
+
for (let i = 0; i < string.length; i++) {
|
|
2230
|
+
const code = string.charCodeAt(i);
|
|
2231
|
+
if (code > 127) {
|
|
2232
|
+
throw new TypeError("non-ASCII string encountered in encode()");
|
|
2233
|
+
}
|
|
2234
|
+
bytes[i] = code;
|
|
2235
|
+
}
|
|
2236
|
+
return bytes;
|
|
2237
|
+
}
|
|
2238
|
+
|
|
2239
|
+
// ../../node_modules/jose/dist/webapi/lib/base64.js
|
|
2240
|
+
function decodeBase64(encoded) {
|
|
2241
|
+
if (Uint8Array.fromBase64) {
|
|
2242
|
+
return Uint8Array.fromBase64(encoded);
|
|
2167
2243
|
}
|
|
2168
|
-
|
|
2169
|
-
|
|
2244
|
+
const binary = atob(encoded);
|
|
2245
|
+
const bytes = new Uint8Array(binary.length);
|
|
2246
|
+
for (let i = 0; i < binary.length; i++) {
|
|
2247
|
+
bytes[i] = binary.charCodeAt(i);
|
|
2170
2248
|
}
|
|
2171
|
-
|
|
2172
|
-
|
|
2249
|
+
return bytes;
|
|
2250
|
+
}
|
|
2251
|
+
|
|
2252
|
+
// ../../node_modules/jose/dist/webapi/util/base64url.js
|
|
2253
|
+
function decode(input) {
|
|
2254
|
+
if (Uint8Array.fromBase64) {
|
|
2255
|
+
return Uint8Array.fromBase64(typeof input === "string" ? input : decoder2.decode(input), {
|
|
2256
|
+
alphabet: "base64url"
|
|
2257
|
+
});
|
|
2173
2258
|
}
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2259
|
+
let encoded = input;
|
|
2260
|
+
if (encoded instanceof Uint8Array) {
|
|
2261
|
+
encoded = decoder2.decode(encoded);
|
|
2262
|
+
}
|
|
2263
|
+
encoded = encoded.replace(/-/g, "+").replace(/_/g, "/");
|
|
2264
|
+
try {
|
|
2265
|
+
return decodeBase64(encoded);
|
|
2266
|
+
} catch {
|
|
2267
|
+
throw new TypeError("The input to be decoded is not correctly encoded.");
|
|
2268
|
+
}
|
|
2269
|
+
}
|
|
2270
|
+
|
|
2271
|
+
// ../../node_modules/jose/dist/webapi/lib/crypto_key.js
|
|
2272
|
+
var unusable = (name, prop = "algorithm.name") => new TypeError(`CryptoKey does not support this operation, its ${prop} must be ${name}`);
|
|
2273
|
+
var isAlgorithm = (algorithm, name) => algorithm.name === name;
|
|
2274
|
+
function getHashLength(hash) {
|
|
2275
|
+
return parseInt(hash.name.slice(4), 10);
|
|
2276
|
+
}
|
|
2277
|
+
function checkHashLength(algorithm, expected) {
|
|
2278
|
+
const actual = getHashLength(algorithm.hash);
|
|
2279
|
+
if (actual !== expected)
|
|
2280
|
+
throw unusable(`SHA-${expected}`, "algorithm.hash");
|
|
2281
|
+
}
|
|
2282
|
+
function getNamedCurve(alg) {
|
|
2283
|
+
switch (alg) {
|
|
2284
|
+
case "ES256":
|
|
2285
|
+
return "P-256";
|
|
2286
|
+
case "ES384":
|
|
2287
|
+
return "P-384";
|
|
2288
|
+
case "ES512":
|
|
2289
|
+
return "P-521";
|
|
2290
|
+
default:
|
|
2291
|
+
throw new Error("unreachable");
|
|
2292
|
+
}
|
|
2293
|
+
}
|
|
2294
|
+
function checkUsage(key, usage) {
|
|
2295
|
+
if (usage && !key.usages.includes(usage)) {
|
|
2296
|
+
throw new TypeError(`CryptoKey does not support this operation, its usages must include ${usage}.`);
|
|
2297
|
+
}
|
|
2298
|
+
}
|
|
2299
|
+
function checkSigCryptoKey(key, alg, usage) {
|
|
2300
|
+
switch (alg) {
|
|
2301
|
+
case "HS256":
|
|
2302
|
+
case "HS384":
|
|
2303
|
+
case "HS512": {
|
|
2304
|
+
if (!isAlgorithm(key.algorithm, "HMAC"))
|
|
2305
|
+
throw unusable("HMAC");
|
|
2306
|
+
checkHashLength(key.algorithm, parseInt(alg.slice(2), 10));
|
|
2307
|
+
break;
|
|
2187
2308
|
}
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2309
|
+
case "RS256":
|
|
2310
|
+
case "RS384":
|
|
2311
|
+
case "RS512": {
|
|
2312
|
+
if (!isAlgorithm(key.algorithm, "RSASSA-PKCS1-v1_5"))
|
|
2313
|
+
throw unusable("RSASSA-PKCS1-v1_5");
|
|
2314
|
+
checkHashLength(key.algorithm, parseInt(alg.slice(2), 10));
|
|
2315
|
+
break;
|
|
2193
2316
|
}
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
});
|
|
2202
|
-
options.store.set("client_info", options.client_info);
|
|
2317
|
+
case "PS256":
|
|
2318
|
+
case "PS384":
|
|
2319
|
+
case "PS512": {
|
|
2320
|
+
if (!isAlgorithm(key.algorithm, "RSA-PSS"))
|
|
2321
|
+
throw unusable("RSA-PSS");
|
|
2322
|
+
checkHashLength(key.algorithm, parseInt(alg.slice(2), 10));
|
|
2323
|
+
break;
|
|
2203
2324
|
}
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2325
|
+
case "Ed25519":
|
|
2326
|
+
case "EdDSA": {
|
|
2327
|
+
if (!isAlgorithm(key.algorithm, "Ed25519"))
|
|
2328
|
+
throw unusable("Ed25519");
|
|
2329
|
+
break;
|
|
2330
|
+
}
|
|
2331
|
+
case "ML-DSA-44":
|
|
2332
|
+
case "ML-DSA-65":
|
|
2333
|
+
case "ML-DSA-87": {
|
|
2334
|
+
if (!isAlgorithm(key.algorithm, alg))
|
|
2335
|
+
throw unusable(alg);
|
|
2336
|
+
break;
|
|
2337
|
+
}
|
|
2338
|
+
case "ES256":
|
|
2339
|
+
case "ES384":
|
|
2340
|
+
case "ES512": {
|
|
2341
|
+
if (!isAlgorithm(key.algorithm, "ECDSA"))
|
|
2342
|
+
throw unusable("ECDSA");
|
|
2343
|
+
const expected = getNamedCurve(alg);
|
|
2344
|
+
const actual = key.algorithm.namedCurve;
|
|
2345
|
+
if (actual !== expected)
|
|
2346
|
+
throw unusable(expected, "algorithm.namedCurve");
|
|
2347
|
+
break;
|
|
2348
|
+
}
|
|
2349
|
+
default:
|
|
2350
|
+
throw new TypeError("CryptoKey does not support this operation");
|
|
2351
|
+
}
|
|
2352
|
+
checkUsage(key, usage);
|
|
2353
|
+
}
|
|
2354
|
+
|
|
2355
|
+
// ../../node_modules/jose/dist/webapi/lib/invalid_key_input.js
|
|
2356
|
+
function message(msg, actual, ...types) {
|
|
2357
|
+
types = types.filter(Boolean);
|
|
2358
|
+
if (types.length > 2) {
|
|
2359
|
+
const last = types.pop();
|
|
2360
|
+
msg += `one of type ${types.join(", ")}, or ${last}.`;
|
|
2361
|
+
} else if (types.length === 2) {
|
|
2362
|
+
msg += `one of type ${types[0]} or ${types[1]}.`;
|
|
2363
|
+
} else {
|
|
2364
|
+
msg += `of type ${types[0]}.`;
|
|
2365
|
+
}
|
|
2366
|
+
if (actual == null) {
|
|
2367
|
+
msg += ` Received ${actual}`;
|
|
2368
|
+
} else if (typeof actual === "function" && actual.name) {
|
|
2369
|
+
msg += ` Received function ${actual.name}`;
|
|
2370
|
+
} else if (typeof actual === "object" && actual != null) {
|
|
2371
|
+
if (actual.constructor?.name) {
|
|
2372
|
+
msg += ` Received an instance of ${actual.constructor.name}`;
|
|
2373
|
+
}
|
|
2374
|
+
}
|
|
2375
|
+
return msg;
|
|
2376
|
+
}
|
|
2377
|
+
var invalidKeyInput = (actual, ...types) => message("Key must be ", actual, ...types);
|
|
2378
|
+
var withAlg = (alg, actual, ...types) => message(`Key for the ${alg} algorithm must be `, actual, ...types);
|
|
2379
|
+
|
|
2380
|
+
// ../../node_modules/jose/dist/webapi/util/errors.js
|
|
2381
|
+
var JOSEError = class extends Error {
|
|
2382
|
+
static code = "ERR_JOSE_GENERIC";
|
|
2383
|
+
code = "ERR_JOSE_GENERIC";
|
|
2384
|
+
constructor(message2, options) {
|
|
2385
|
+
super(message2, options);
|
|
2386
|
+
this.name = this.constructor.name;
|
|
2387
|
+
Error.captureStackTrace?.(this, this.constructor);
|
|
2388
|
+
}
|
|
2389
|
+
};
|
|
2390
|
+
var JWTClaimValidationFailed = class extends JOSEError {
|
|
2391
|
+
static code = "ERR_JWT_CLAIM_VALIDATION_FAILED";
|
|
2392
|
+
code = "ERR_JWT_CLAIM_VALIDATION_FAILED";
|
|
2393
|
+
claim;
|
|
2394
|
+
reason;
|
|
2395
|
+
payload;
|
|
2396
|
+
constructor(message2, payload, claim = "unspecified", reason = "unspecified") {
|
|
2397
|
+
super(message2, { cause: { claim, reason, payload } });
|
|
2398
|
+
this.claim = claim;
|
|
2399
|
+
this.reason = reason;
|
|
2400
|
+
this.payload = payload;
|
|
2401
|
+
}
|
|
2402
|
+
};
|
|
2403
|
+
var JWTExpired = class extends JOSEError {
|
|
2404
|
+
static code = "ERR_JWT_EXPIRED";
|
|
2405
|
+
code = "ERR_JWT_EXPIRED";
|
|
2406
|
+
claim;
|
|
2407
|
+
reason;
|
|
2408
|
+
payload;
|
|
2409
|
+
constructor(message2, payload, claim = "unspecified", reason = "unspecified") {
|
|
2410
|
+
super(message2, { cause: { claim, reason, payload } });
|
|
2411
|
+
this.claim = claim;
|
|
2412
|
+
this.reason = reason;
|
|
2413
|
+
this.payload = payload;
|
|
2414
|
+
}
|
|
2415
|
+
};
|
|
2416
|
+
var JOSEAlgNotAllowed = class extends JOSEError {
|
|
2417
|
+
static code = "ERR_JOSE_ALG_NOT_ALLOWED";
|
|
2418
|
+
code = "ERR_JOSE_ALG_NOT_ALLOWED";
|
|
2419
|
+
};
|
|
2420
|
+
var JOSENotSupported = class extends JOSEError {
|
|
2421
|
+
static code = "ERR_JOSE_NOT_SUPPORTED";
|
|
2422
|
+
code = "ERR_JOSE_NOT_SUPPORTED";
|
|
2423
|
+
};
|
|
2424
|
+
var JWSInvalid = class extends JOSEError {
|
|
2425
|
+
static code = "ERR_JWS_INVALID";
|
|
2426
|
+
code = "ERR_JWS_INVALID";
|
|
2427
|
+
};
|
|
2428
|
+
var JWTInvalid = class extends JOSEError {
|
|
2429
|
+
static code = "ERR_JWT_INVALID";
|
|
2430
|
+
code = "ERR_JWT_INVALID";
|
|
2431
|
+
};
|
|
2432
|
+
var JWKSInvalid = class extends JOSEError {
|
|
2433
|
+
static code = "ERR_JWKS_INVALID";
|
|
2434
|
+
code = "ERR_JWKS_INVALID";
|
|
2435
|
+
};
|
|
2436
|
+
var JWKSNoMatchingKey = class extends JOSEError {
|
|
2437
|
+
static code = "ERR_JWKS_NO_MATCHING_KEY";
|
|
2438
|
+
code = "ERR_JWKS_NO_MATCHING_KEY";
|
|
2439
|
+
constructor(message2 = "no applicable key found in the JSON Web Key Set", options) {
|
|
2440
|
+
super(message2, options);
|
|
2441
|
+
}
|
|
2442
|
+
};
|
|
2443
|
+
var JWKSMultipleMatchingKeys = class extends JOSEError {
|
|
2444
|
+
[Symbol.asyncIterator];
|
|
2445
|
+
static code = "ERR_JWKS_MULTIPLE_MATCHING_KEYS";
|
|
2446
|
+
code = "ERR_JWKS_MULTIPLE_MATCHING_KEYS";
|
|
2447
|
+
constructor(message2 = "multiple matching keys found in the JSON Web Key Set", options) {
|
|
2448
|
+
super(message2, options);
|
|
2449
|
+
}
|
|
2450
|
+
};
|
|
2451
|
+
var JWSSignatureVerificationFailed = class extends JOSEError {
|
|
2452
|
+
static code = "ERR_JWS_SIGNATURE_VERIFICATION_FAILED";
|
|
2453
|
+
code = "ERR_JWS_SIGNATURE_VERIFICATION_FAILED";
|
|
2454
|
+
constructor(message2 = "signature verification failed", options) {
|
|
2455
|
+
super(message2, options);
|
|
2456
|
+
}
|
|
2457
|
+
};
|
|
2458
|
+
|
|
2459
|
+
// ../../node_modules/jose/dist/webapi/lib/is_key_like.js
|
|
2460
|
+
var isCryptoKey2 = (key) => {
|
|
2461
|
+
if (key?.[Symbol.toStringTag] === "CryptoKey")
|
|
2462
|
+
return true;
|
|
2463
|
+
try {
|
|
2464
|
+
return key instanceof CryptoKey;
|
|
2465
|
+
} catch {
|
|
2466
|
+
return false;
|
|
2467
|
+
}
|
|
2468
|
+
};
|
|
2469
|
+
var isKeyObject = (key) => key?.[Symbol.toStringTag] === "KeyObject";
|
|
2470
|
+
var isKeyLike = (key) => isCryptoKey2(key) || isKeyObject(key);
|
|
2471
|
+
|
|
2472
|
+
// ../../node_modules/jose/dist/webapi/lib/helpers.js
|
|
2473
|
+
function decodeBase64url(value, label, ErrorClass) {
|
|
2474
|
+
try {
|
|
2475
|
+
return decode(value);
|
|
2476
|
+
} catch {
|
|
2477
|
+
throw new ErrorClass(`Failed to base64url decode the ${label}`);
|
|
2478
|
+
}
|
|
2479
|
+
}
|
|
2480
|
+
|
|
2481
|
+
// ../../node_modules/jose/dist/webapi/lib/type_checks.js
|
|
2482
|
+
var isObjectLike = (value) => typeof value === "object" && value !== null;
|
|
2483
|
+
function isObject(input) {
|
|
2484
|
+
if (!isObjectLike(input) || Object.prototype.toString.call(input) !== "[object Object]") {
|
|
2485
|
+
return false;
|
|
2486
|
+
}
|
|
2487
|
+
if (Object.getPrototypeOf(input) === null) {
|
|
2488
|
+
return true;
|
|
2489
|
+
}
|
|
2490
|
+
let proto = input;
|
|
2491
|
+
while (Object.getPrototypeOf(proto) !== null) {
|
|
2492
|
+
proto = Object.getPrototypeOf(proto);
|
|
2493
|
+
}
|
|
2494
|
+
return Object.getPrototypeOf(input) === proto;
|
|
2495
|
+
}
|
|
2496
|
+
function isDisjoint(...headers) {
|
|
2497
|
+
const sources = headers.filter(Boolean);
|
|
2498
|
+
if (sources.length === 0 || sources.length === 1) {
|
|
2499
|
+
return true;
|
|
2500
|
+
}
|
|
2501
|
+
let acc;
|
|
2502
|
+
for (const header of sources) {
|
|
2503
|
+
const parameters = Object.keys(header);
|
|
2504
|
+
if (!acc || acc.size === 0) {
|
|
2505
|
+
acc = new Set(parameters);
|
|
2506
|
+
continue;
|
|
2507
|
+
}
|
|
2508
|
+
for (const parameter of parameters) {
|
|
2509
|
+
if (acc.has(parameter)) {
|
|
2510
|
+
return false;
|
|
2511
|
+
}
|
|
2512
|
+
acc.add(parameter);
|
|
2513
|
+
}
|
|
2514
|
+
}
|
|
2515
|
+
return true;
|
|
2516
|
+
}
|
|
2517
|
+
var isJWK = (key) => isObject(key) && typeof key.kty === "string";
|
|
2518
|
+
var isPrivateJWK = (key) => key.kty !== "oct" && (key.kty === "AKP" && typeof key.priv === "string" || typeof key.d === "string");
|
|
2519
|
+
var isPublicJWK = (key) => key.kty !== "oct" && key.d === void 0 && key.priv === void 0;
|
|
2520
|
+
var isSecretJWK = (key) => key.kty === "oct" && typeof key.k === "string";
|
|
2521
|
+
|
|
2522
|
+
// ../../node_modules/jose/dist/webapi/lib/signing.js
|
|
2523
|
+
function checkKeyLength(alg, key) {
|
|
2524
|
+
if (alg.startsWith("RS") || alg.startsWith("PS")) {
|
|
2525
|
+
const { modulusLength } = key.algorithm;
|
|
2526
|
+
if (typeof modulusLength !== "number" || modulusLength < 2048) {
|
|
2527
|
+
throw new TypeError(`${alg} requires key modulusLength to be 2048 bits or larger`);
|
|
2528
|
+
}
|
|
2529
|
+
}
|
|
2530
|
+
}
|
|
2531
|
+
function subtleAlgorithm2(alg, algorithm) {
|
|
2532
|
+
const hash = `SHA-${alg.slice(-3)}`;
|
|
2533
|
+
switch (alg) {
|
|
2534
|
+
case "HS256":
|
|
2535
|
+
case "HS384":
|
|
2536
|
+
case "HS512":
|
|
2537
|
+
return { hash, name: "HMAC" };
|
|
2538
|
+
case "PS256":
|
|
2539
|
+
case "PS384":
|
|
2540
|
+
case "PS512":
|
|
2541
|
+
return { hash, name: "RSA-PSS", saltLength: parseInt(alg.slice(-3), 10) >> 3 };
|
|
2542
|
+
case "RS256":
|
|
2543
|
+
case "RS384":
|
|
2544
|
+
case "RS512":
|
|
2545
|
+
return { hash, name: "RSASSA-PKCS1-v1_5" };
|
|
2546
|
+
case "ES256":
|
|
2547
|
+
case "ES384":
|
|
2548
|
+
case "ES512":
|
|
2549
|
+
return { hash, name: "ECDSA", namedCurve: algorithm.namedCurve };
|
|
2550
|
+
case "Ed25519":
|
|
2551
|
+
case "EdDSA":
|
|
2552
|
+
return { name: "Ed25519" };
|
|
2553
|
+
case "ML-DSA-44":
|
|
2554
|
+
case "ML-DSA-65":
|
|
2555
|
+
case "ML-DSA-87":
|
|
2556
|
+
return { name: alg };
|
|
2557
|
+
default:
|
|
2558
|
+
throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`);
|
|
2559
|
+
}
|
|
2560
|
+
}
|
|
2561
|
+
async function getSigKey(alg, key, usage) {
|
|
2562
|
+
if (key instanceof Uint8Array) {
|
|
2563
|
+
if (!alg.startsWith("HS")) {
|
|
2564
|
+
throw new TypeError(invalidKeyInput(key, "CryptoKey", "KeyObject", "JSON Web Key"));
|
|
2565
|
+
}
|
|
2566
|
+
return crypto.subtle.importKey("raw", key, { hash: `SHA-${alg.slice(-3)}`, name: "HMAC" }, false, [usage]);
|
|
2567
|
+
}
|
|
2568
|
+
checkSigCryptoKey(key, alg, usage);
|
|
2569
|
+
return key;
|
|
2570
|
+
}
|
|
2571
|
+
async function verify(alg, key, signature, data) {
|
|
2572
|
+
const cryptoKey = await getSigKey(alg, key, "verify");
|
|
2573
|
+
checkKeyLength(alg, cryptoKey);
|
|
2574
|
+
const algorithm = subtleAlgorithm2(alg, cryptoKey.algorithm);
|
|
2575
|
+
try {
|
|
2576
|
+
return await crypto.subtle.verify(algorithm, cryptoKey, signature, data);
|
|
2577
|
+
} catch {
|
|
2578
|
+
return false;
|
|
2579
|
+
}
|
|
2580
|
+
}
|
|
2581
|
+
|
|
2582
|
+
// ../../node_modules/jose/dist/webapi/lib/jwk_to_key.js
|
|
2583
|
+
var unsupportedAlg = 'Invalid or unsupported JWK "alg" (Algorithm) Parameter value';
|
|
2584
|
+
function subtleMapping(jwk) {
|
|
2585
|
+
let algorithm;
|
|
2586
|
+
let keyUsages;
|
|
2587
|
+
switch (jwk.kty) {
|
|
2588
|
+
case "AKP": {
|
|
2589
|
+
switch (jwk.alg) {
|
|
2590
|
+
case "ML-DSA-44":
|
|
2591
|
+
case "ML-DSA-65":
|
|
2592
|
+
case "ML-DSA-87":
|
|
2593
|
+
algorithm = { name: jwk.alg };
|
|
2594
|
+
keyUsages = jwk.priv ? ["sign"] : ["verify"];
|
|
2595
|
+
break;
|
|
2596
|
+
default:
|
|
2597
|
+
throw new JOSENotSupported(unsupportedAlg);
|
|
2598
|
+
}
|
|
2599
|
+
break;
|
|
2600
|
+
}
|
|
2601
|
+
case "RSA": {
|
|
2602
|
+
switch (jwk.alg) {
|
|
2603
|
+
case "PS256":
|
|
2604
|
+
case "PS384":
|
|
2605
|
+
case "PS512":
|
|
2606
|
+
algorithm = { name: "RSA-PSS", hash: `SHA-${jwk.alg.slice(-3)}` };
|
|
2607
|
+
keyUsages = jwk.d ? ["sign"] : ["verify"];
|
|
2608
|
+
break;
|
|
2609
|
+
case "RS256":
|
|
2610
|
+
case "RS384":
|
|
2611
|
+
case "RS512":
|
|
2612
|
+
algorithm = { name: "RSASSA-PKCS1-v1_5", hash: `SHA-${jwk.alg.slice(-3)}` };
|
|
2613
|
+
keyUsages = jwk.d ? ["sign"] : ["verify"];
|
|
2614
|
+
break;
|
|
2615
|
+
case "RSA-OAEP":
|
|
2616
|
+
case "RSA-OAEP-256":
|
|
2617
|
+
case "RSA-OAEP-384":
|
|
2618
|
+
case "RSA-OAEP-512":
|
|
2619
|
+
algorithm = {
|
|
2620
|
+
name: "RSA-OAEP",
|
|
2621
|
+
hash: `SHA-${parseInt(jwk.alg.slice(-3), 10) || 1}`
|
|
2622
|
+
};
|
|
2623
|
+
keyUsages = jwk.d ? ["decrypt", "unwrapKey"] : ["encrypt", "wrapKey"];
|
|
2624
|
+
break;
|
|
2625
|
+
default:
|
|
2626
|
+
throw new JOSENotSupported(unsupportedAlg);
|
|
2627
|
+
}
|
|
2628
|
+
break;
|
|
2629
|
+
}
|
|
2630
|
+
case "EC": {
|
|
2631
|
+
switch (jwk.alg) {
|
|
2632
|
+
case "ES256":
|
|
2633
|
+
case "ES384":
|
|
2634
|
+
case "ES512":
|
|
2635
|
+
algorithm = {
|
|
2636
|
+
name: "ECDSA",
|
|
2637
|
+
namedCurve: { ES256: "P-256", ES384: "P-384", ES512: "P-521" }[jwk.alg]
|
|
2638
|
+
};
|
|
2639
|
+
keyUsages = jwk.d ? ["sign"] : ["verify"];
|
|
2640
|
+
break;
|
|
2641
|
+
case "ECDH-ES":
|
|
2642
|
+
case "ECDH-ES+A128KW":
|
|
2643
|
+
case "ECDH-ES+A192KW":
|
|
2644
|
+
case "ECDH-ES+A256KW":
|
|
2645
|
+
algorithm = { name: "ECDH", namedCurve: jwk.crv };
|
|
2646
|
+
keyUsages = jwk.d ? ["deriveBits"] : [];
|
|
2647
|
+
break;
|
|
2648
|
+
default:
|
|
2649
|
+
throw new JOSENotSupported(unsupportedAlg);
|
|
2650
|
+
}
|
|
2651
|
+
break;
|
|
2652
|
+
}
|
|
2653
|
+
case "OKP": {
|
|
2654
|
+
switch (jwk.alg) {
|
|
2655
|
+
case "Ed25519":
|
|
2656
|
+
case "EdDSA":
|
|
2657
|
+
algorithm = { name: "Ed25519" };
|
|
2658
|
+
keyUsages = jwk.d ? ["sign"] : ["verify"];
|
|
2659
|
+
break;
|
|
2660
|
+
case "ECDH-ES":
|
|
2661
|
+
case "ECDH-ES+A128KW":
|
|
2662
|
+
case "ECDH-ES+A192KW":
|
|
2663
|
+
case "ECDH-ES+A256KW":
|
|
2664
|
+
algorithm = { name: jwk.crv };
|
|
2665
|
+
keyUsages = jwk.d ? ["deriveBits"] : [];
|
|
2666
|
+
break;
|
|
2667
|
+
default:
|
|
2668
|
+
throw new JOSENotSupported(unsupportedAlg);
|
|
2669
|
+
}
|
|
2670
|
+
break;
|
|
2671
|
+
}
|
|
2672
|
+
default:
|
|
2673
|
+
throw new JOSENotSupported('Invalid or unsupported JWK "kty" (Key Type) Parameter value');
|
|
2674
|
+
}
|
|
2675
|
+
return { algorithm, keyUsages };
|
|
2676
|
+
}
|
|
2677
|
+
async function jwkToKey(jwk) {
|
|
2678
|
+
if (!jwk.alg) {
|
|
2679
|
+
throw new TypeError('"alg" argument is required when "jwk.alg" is not present');
|
|
2680
|
+
}
|
|
2681
|
+
const { algorithm, keyUsages } = subtleMapping(jwk);
|
|
2682
|
+
const keyData = { ...jwk };
|
|
2683
|
+
if (keyData.kty !== "AKP") {
|
|
2684
|
+
delete keyData.alg;
|
|
2685
|
+
}
|
|
2686
|
+
delete keyData.use;
|
|
2687
|
+
return crypto.subtle.importKey("jwk", keyData, algorithm, jwk.ext ?? (jwk.d || jwk.priv ? false : true), jwk.key_ops ?? keyUsages);
|
|
2688
|
+
}
|
|
2689
|
+
|
|
2690
|
+
// ../../node_modules/jose/dist/webapi/lib/normalize_key.js
|
|
2691
|
+
var unusableForAlg = "given KeyObject instance cannot be used for this algorithm";
|
|
2692
|
+
var cache;
|
|
2693
|
+
var handleJWK = async (key, jwk, alg, freeze = false) => {
|
|
2694
|
+
cache ||= /* @__PURE__ */ new WeakMap();
|
|
2695
|
+
let cached = cache.get(key);
|
|
2696
|
+
if (cached?.[alg]) {
|
|
2697
|
+
return cached[alg];
|
|
2698
|
+
}
|
|
2699
|
+
const cryptoKey = await jwkToKey({ ...jwk, alg });
|
|
2700
|
+
if (freeze)
|
|
2701
|
+
Object.freeze(key);
|
|
2702
|
+
if (!cached) {
|
|
2703
|
+
cache.set(key, { [alg]: cryptoKey });
|
|
2704
|
+
} else {
|
|
2705
|
+
cached[alg] = cryptoKey;
|
|
2706
|
+
}
|
|
2707
|
+
return cryptoKey;
|
|
2708
|
+
};
|
|
2709
|
+
var handleKeyObject = (keyObject, alg) => {
|
|
2710
|
+
cache ||= /* @__PURE__ */ new WeakMap();
|
|
2711
|
+
let cached = cache.get(keyObject);
|
|
2712
|
+
if (cached?.[alg]) {
|
|
2713
|
+
return cached[alg];
|
|
2714
|
+
}
|
|
2715
|
+
const isPublic = keyObject.type === "public";
|
|
2716
|
+
const extractable = isPublic ? true : false;
|
|
2717
|
+
let cryptoKey;
|
|
2718
|
+
if (keyObject.asymmetricKeyType === "x25519") {
|
|
2719
|
+
switch (alg) {
|
|
2720
|
+
case "ECDH-ES":
|
|
2721
|
+
case "ECDH-ES+A128KW":
|
|
2722
|
+
case "ECDH-ES+A192KW":
|
|
2723
|
+
case "ECDH-ES+A256KW":
|
|
2724
|
+
break;
|
|
2725
|
+
default:
|
|
2726
|
+
throw new TypeError(unusableForAlg);
|
|
2727
|
+
}
|
|
2728
|
+
cryptoKey = keyObject.toCryptoKey(keyObject.asymmetricKeyType, extractable, isPublic ? [] : ["deriveBits"]);
|
|
2729
|
+
}
|
|
2730
|
+
if (keyObject.asymmetricKeyType === "ed25519") {
|
|
2731
|
+
if (alg !== "EdDSA" && alg !== "Ed25519") {
|
|
2732
|
+
throw new TypeError(unusableForAlg);
|
|
2733
|
+
}
|
|
2734
|
+
cryptoKey = keyObject.toCryptoKey(keyObject.asymmetricKeyType, extractable, [
|
|
2735
|
+
isPublic ? "verify" : "sign"
|
|
2736
|
+
]);
|
|
2737
|
+
}
|
|
2738
|
+
switch (keyObject.asymmetricKeyType) {
|
|
2739
|
+
case "ml-dsa-44":
|
|
2740
|
+
case "ml-dsa-65":
|
|
2741
|
+
case "ml-dsa-87": {
|
|
2742
|
+
if (alg !== keyObject.asymmetricKeyType.toUpperCase()) {
|
|
2743
|
+
throw new TypeError(unusableForAlg);
|
|
2744
|
+
}
|
|
2745
|
+
cryptoKey = keyObject.toCryptoKey(keyObject.asymmetricKeyType, extractable, [
|
|
2746
|
+
isPublic ? "verify" : "sign"
|
|
2747
|
+
]);
|
|
2748
|
+
}
|
|
2749
|
+
}
|
|
2750
|
+
if (keyObject.asymmetricKeyType === "rsa") {
|
|
2751
|
+
let hash;
|
|
2752
|
+
switch (alg) {
|
|
2753
|
+
case "RSA-OAEP":
|
|
2754
|
+
hash = "SHA-1";
|
|
2755
|
+
break;
|
|
2756
|
+
case "RS256":
|
|
2757
|
+
case "PS256":
|
|
2758
|
+
case "RSA-OAEP-256":
|
|
2759
|
+
hash = "SHA-256";
|
|
2760
|
+
break;
|
|
2761
|
+
case "RS384":
|
|
2762
|
+
case "PS384":
|
|
2763
|
+
case "RSA-OAEP-384":
|
|
2764
|
+
hash = "SHA-384";
|
|
2765
|
+
break;
|
|
2766
|
+
case "RS512":
|
|
2767
|
+
case "PS512":
|
|
2768
|
+
case "RSA-OAEP-512":
|
|
2769
|
+
hash = "SHA-512";
|
|
2770
|
+
break;
|
|
2771
|
+
default:
|
|
2772
|
+
throw new TypeError(unusableForAlg);
|
|
2773
|
+
}
|
|
2774
|
+
if (alg.startsWith("RSA-OAEP")) {
|
|
2775
|
+
return keyObject.toCryptoKey({
|
|
2776
|
+
name: "RSA-OAEP",
|
|
2777
|
+
hash
|
|
2778
|
+
}, extractable, isPublic ? ["encrypt"] : ["decrypt"]);
|
|
2779
|
+
}
|
|
2780
|
+
cryptoKey = keyObject.toCryptoKey({
|
|
2781
|
+
name: alg.startsWith("PS") ? "RSA-PSS" : "RSASSA-PKCS1-v1_5",
|
|
2782
|
+
hash
|
|
2783
|
+
}, extractable, [isPublic ? "verify" : "sign"]);
|
|
2784
|
+
}
|
|
2785
|
+
if (keyObject.asymmetricKeyType === "ec") {
|
|
2786
|
+
const nist = /* @__PURE__ */ new Map([
|
|
2787
|
+
["prime256v1", "P-256"],
|
|
2788
|
+
["secp384r1", "P-384"],
|
|
2789
|
+
["secp521r1", "P-521"]
|
|
2790
|
+
]);
|
|
2791
|
+
const namedCurve = nist.get(keyObject.asymmetricKeyDetails?.namedCurve);
|
|
2792
|
+
if (!namedCurve) {
|
|
2793
|
+
throw new TypeError(unusableForAlg);
|
|
2794
|
+
}
|
|
2795
|
+
const expectedCurve = { ES256: "P-256", ES384: "P-384", ES512: "P-521" };
|
|
2796
|
+
if (expectedCurve[alg] && namedCurve === expectedCurve[alg]) {
|
|
2797
|
+
cryptoKey = keyObject.toCryptoKey({
|
|
2798
|
+
name: "ECDSA",
|
|
2799
|
+
namedCurve
|
|
2800
|
+
}, extractable, [isPublic ? "verify" : "sign"]);
|
|
2801
|
+
}
|
|
2802
|
+
if (alg.startsWith("ECDH-ES")) {
|
|
2803
|
+
cryptoKey = keyObject.toCryptoKey({
|
|
2804
|
+
name: "ECDH",
|
|
2805
|
+
namedCurve
|
|
2806
|
+
}, extractable, isPublic ? [] : ["deriveBits"]);
|
|
2807
|
+
}
|
|
2808
|
+
}
|
|
2809
|
+
if (!cryptoKey) {
|
|
2810
|
+
throw new TypeError(unusableForAlg);
|
|
2811
|
+
}
|
|
2812
|
+
if (!cached) {
|
|
2813
|
+
cache.set(keyObject, { [alg]: cryptoKey });
|
|
2814
|
+
} else {
|
|
2815
|
+
cached[alg] = cryptoKey;
|
|
2816
|
+
}
|
|
2817
|
+
return cryptoKey;
|
|
2818
|
+
};
|
|
2819
|
+
async function normalizeKey(key, alg) {
|
|
2820
|
+
if (key instanceof Uint8Array) {
|
|
2821
|
+
return key;
|
|
2822
|
+
}
|
|
2823
|
+
if (isCryptoKey2(key)) {
|
|
2824
|
+
return key;
|
|
2825
|
+
}
|
|
2826
|
+
if (isKeyObject(key)) {
|
|
2827
|
+
if (key.type === "secret") {
|
|
2828
|
+
return key.export();
|
|
2829
|
+
}
|
|
2830
|
+
if ("toCryptoKey" in key && typeof key.toCryptoKey === "function") {
|
|
2831
|
+
try {
|
|
2832
|
+
return handleKeyObject(key, alg);
|
|
2833
|
+
} catch (err) {
|
|
2834
|
+
if (err instanceof TypeError) {
|
|
2835
|
+
throw err;
|
|
2836
|
+
}
|
|
2837
|
+
}
|
|
2838
|
+
}
|
|
2839
|
+
let jwk = key.export({ format: "jwk" });
|
|
2840
|
+
return handleJWK(key, jwk, alg);
|
|
2841
|
+
}
|
|
2842
|
+
if (isJWK(key)) {
|
|
2843
|
+
if (key.k) {
|
|
2844
|
+
return decode(key.k);
|
|
2845
|
+
}
|
|
2846
|
+
return handleJWK(key, key, alg, true);
|
|
2847
|
+
}
|
|
2848
|
+
throw new Error("unreachable");
|
|
2849
|
+
}
|
|
2850
|
+
|
|
2851
|
+
// ../../node_modules/jose/dist/webapi/key/import.js
|
|
2852
|
+
async function importJWK(jwk, alg, options) {
|
|
2853
|
+
if (!isObject(jwk)) {
|
|
2854
|
+
throw new TypeError("JWK must be an object");
|
|
2855
|
+
}
|
|
2856
|
+
let ext;
|
|
2857
|
+
alg ??= jwk.alg;
|
|
2858
|
+
ext ??= options?.extractable ?? jwk.ext;
|
|
2859
|
+
switch (jwk.kty) {
|
|
2860
|
+
case "oct":
|
|
2861
|
+
if (typeof jwk.k !== "string" || !jwk.k) {
|
|
2862
|
+
throw new TypeError('missing "k" (Key Value) Parameter value');
|
|
2863
|
+
}
|
|
2864
|
+
return decode(jwk.k);
|
|
2865
|
+
case "RSA":
|
|
2866
|
+
if ("oth" in jwk && jwk.oth !== void 0) {
|
|
2867
|
+
throw new JOSENotSupported('RSA JWK "oth" (Other Primes Info) Parameter value is not supported');
|
|
2868
|
+
}
|
|
2869
|
+
return jwkToKey({ ...jwk, alg, ext });
|
|
2870
|
+
case "AKP": {
|
|
2871
|
+
if (typeof jwk.alg !== "string" || !jwk.alg) {
|
|
2872
|
+
throw new TypeError('missing "alg" (Algorithm) Parameter value');
|
|
2873
|
+
}
|
|
2874
|
+
if (alg !== void 0 && alg !== jwk.alg) {
|
|
2875
|
+
throw new TypeError("JWK alg and alg option value mismatch");
|
|
2876
|
+
}
|
|
2877
|
+
return jwkToKey({ ...jwk, ext });
|
|
2878
|
+
}
|
|
2879
|
+
case "EC":
|
|
2880
|
+
case "OKP":
|
|
2881
|
+
return jwkToKey({ ...jwk, alg, ext });
|
|
2882
|
+
default:
|
|
2883
|
+
throw new JOSENotSupported('Unsupported "kty" (Key Type) Parameter value');
|
|
2884
|
+
}
|
|
2885
|
+
}
|
|
2886
|
+
|
|
2887
|
+
// ../../node_modules/jose/dist/webapi/lib/validate_crit.js
|
|
2888
|
+
function validateCrit(Err, recognizedDefault, recognizedOption, protectedHeader, joseHeader) {
|
|
2889
|
+
if (joseHeader.crit !== void 0 && protectedHeader?.crit === void 0) {
|
|
2890
|
+
throw new Err('"crit" (Critical) Header Parameter MUST be integrity protected');
|
|
2891
|
+
}
|
|
2892
|
+
if (!protectedHeader || protectedHeader.crit === void 0) {
|
|
2893
|
+
return /* @__PURE__ */ new Set();
|
|
2894
|
+
}
|
|
2895
|
+
if (!Array.isArray(protectedHeader.crit) || protectedHeader.crit.length === 0 || protectedHeader.crit.some((input) => typeof input !== "string" || input.length === 0)) {
|
|
2896
|
+
throw new Err('"crit" (Critical) Header Parameter MUST be an array of non-empty strings when present');
|
|
2897
|
+
}
|
|
2898
|
+
let recognized;
|
|
2899
|
+
if (recognizedOption !== void 0) {
|
|
2900
|
+
recognized = new Map([...Object.entries(recognizedOption), ...recognizedDefault.entries()]);
|
|
2901
|
+
} else {
|
|
2902
|
+
recognized = recognizedDefault;
|
|
2903
|
+
}
|
|
2904
|
+
for (const parameter of protectedHeader.crit) {
|
|
2905
|
+
if (!recognized.has(parameter)) {
|
|
2906
|
+
throw new JOSENotSupported(`Extension Header Parameter "${parameter}" is not recognized`);
|
|
2907
|
+
}
|
|
2908
|
+
if (joseHeader[parameter] === void 0) {
|
|
2909
|
+
throw new Err(`Extension Header Parameter "${parameter}" is missing`);
|
|
2910
|
+
}
|
|
2911
|
+
if (recognized.get(parameter) && protectedHeader[parameter] === void 0) {
|
|
2912
|
+
throw new Err(`Extension Header Parameter "${parameter}" MUST be integrity protected`);
|
|
2913
|
+
}
|
|
2914
|
+
}
|
|
2915
|
+
return new Set(protectedHeader.crit);
|
|
2916
|
+
}
|
|
2917
|
+
|
|
2918
|
+
// ../../node_modules/jose/dist/webapi/lib/validate_algorithms.js
|
|
2919
|
+
function validateAlgorithms(option, algorithms) {
|
|
2920
|
+
if (algorithms !== void 0 && (!Array.isArray(algorithms) || algorithms.some((s) => typeof s !== "string"))) {
|
|
2921
|
+
throw new TypeError(`"${option}" option must be an array of strings`);
|
|
2922
|
+
}
|
|
2923
|
+
if (!algorithms) {
|
|
2924
|
+
return void 0;
|
|
2925
|
+
}
|
|
2926
|
+
return new Set(algorithms);
|
|
2927
|
+
}
|
|
2928
|
+
|
|
2929
|
+
// ../../node_modules/jose/dist/webapi/lib/check_key_type.js
|
|
2930
|
+
var tag = (key) => key?.[Symbol.toStringTag];
|
|
2931
|
+
var jwkMatchesOp = (alg, key, usage) => {
|
|
2932
|
+
if (key.use !== void 0) {
|
|
2933
|
+
let expected;
|
|
2934
|
+
switch (usage) {
|
|
2935
|
+
case "sign":
|
|
2936
|
+
case "verify":
|
|
2937
|
+
expected = "sig";
|
|
2938
|
+
break;
|
|
2939
|
+
case "encrypt":
|
|
2940
|
+
case "decrypt":
|
|
2941
|
+
expected = "enc";
|
|
2942
|
+
break;
|
|
2943
|
+
}
|
|
2944
|
+
if (key.use !== expected) {
|
|
2945
|
+
throw new TypeError(`Invalid key for this operation, its "use" must be "${expected}" when present`);
|
|
2946
|
+
}
|
|
2947
|
+
}
|
|
2948
|
+
if (key.alg !== void 0 && key.alg !== alg) {
|
|
2949
|
+
throw new TypeError(`Invalid key for this operation, its "alg" must be "${alg}" when present`);
|
|
2950
|
+
}
|
|
2951
|
+
if (Array.isArray(key.key_ops)) {
|
|
2952
|
+
let expectedKeyOp;
|
|
2953
|
+
switch (true) {
|
|
2954
|
+
case (usage === "sign" || usage === "verify"):
|
|
2955
|
+
case alg === "dir":
|
|
2956
|
+
case alg.includes("CBC-HS"):
|
|
2957
|
+
expectedKeyOp = usage;
|
|
2958
|
+
break;
|
|
2959
|
+
case alg.startsWith("PBES2"):
|
|
2960
|
+
expectedKeyOp = "deriveBits";
|
|
2961
|
+
break;
|
|
2962
|
+
case /^A\d{3}(?:GCM)?(?:KW)?$/.test(alg):
|
|
2963
|
+
if (!alg.includes("GCM") && alg.endsWith("KW")) {
|
|
2964
|
+
expectedKeyOp = usage === "encrypt" ? "wrapKey" : "unwrapKey";
|
|
2965
|
+
} else {
|
|
2966
|
+
expectedKeyOp = usage;
|
|
2967
|
+
}
|
|
2968
|
+
break;
|
|
2969
|
+
case (usage === "encrypt" && alg.startsWith("RSA")):
|
|
2970
|
+
expectedKeyOp = "wrapKey";
|
|
2971
|
+
break;
|
|
2972
|
+
case usage === "decrypt":
|
|
2973
|
+
expectedKeyOp = alg.startsWith("RSA") ? "unwrapKey" : "deriveBits";
|
|
2974
|
+
break;
|
|
2975
|
+
}
|
|
2976
|
+
if (expectedKeyOp && key.key_ops?.includes?.(expectedKeyOp) === false) {
|
|
2977
|
+
throw new TypeError(`Invalid key for this operation, its "key_ops" must include "${expectedKeyOp}" when present`);
|
|
2978
|
+
}
|
|
2979
|
+
}
|
|
2980
|
+
return true;
|
|
2981
|
+
};
|
|
2982
|
+
var symmetricTypeCheck = (alg, key, usage) => {
|
|
2983
|
+
if (key instanceof Uint8Array)
|
|
2984
|
+
return;
|
|
2985
|
+
if (isJWK(key)) {
|
|
2986
|
+
if (isSecretJWK(key) && jwkMatchesOp(alg, key, usage))
|
|
2987
|
+
return;
|
|
2988
|
+
throw new TypeError(`JSON Web Key for symmetric algorithms must have JWK "kty" (Key Type) equal to "oct" and the JWK "k" (Key Value) present`);
|
|
2989
|
+
}
|
|
2990
|
+
if (!isKeyLike(key)) {
|
|
2991
|
+
throw new TypeError(withAlg(alg, key, "CryptoKey", "KeyObject", "JSON Web Key", "Uint8Array"));
|
|
2992
|
+
}
|
|
2993
|
+
if (key.type !== "secret") {
|
|
2994
|
+
throw new TypeError(`${tag(key)} instances for symmetric algorithms must be of type "secret"`);
|
|
2995
|
+
}
|
|
2996
|
+
};
|
|
2997
|
+
var asymmetricTypeCheck = (alg, key, usage) => {
|
|
2998
|
+
if (isJWK(key)) {
|
|
2999
|
+
switch (usage) {
|
|
3000
|
+
case "decrypt":
|
|
3001
|
+
case "sign":
|
|
3002
|
+
if (isPrivateJWK(key) && jwkMatchesOp(alg, key, usage))
|
|
3003
|
+
return;
|
|
3004
|
+
throw new TypeError(`JSON Web Key for this operation must be a private JWK`);
|
|
3005
|
+
case "encrypt":
|
|
3006
|
+
case "verify":
|
|
3007
|
+
if (isPublicJWK(key) && jwkMatchesOp(alg, key, usage))
|
|
3008
|
+
return;
|
|
3009
|
+
throw new TypeError(`JSON Web Key for this operation must be a public JWK`);
|
|
3010
|
+
}
|
|
3011
|
+
}
|
|
3012
|
+
if (!isKeyLike(key)) {
|
|
3013
|
+
throw new TypeError(withAlg(alg, key, "CryptoKey", "KeyObject", "JSON Web Key"));
|
|
3014
|
+
}
|
|
3015
|
+
if (key.type === "secret") {
|
|
3016
|
+
throw new TypeError(`${tag(key)} instances for asymmetric algorithms must not be of type "secret"`);
|
|
3017
|
+
}
|
|
3018
|
+
if (key.type === "public") {
|
|
3019
|
+
switch (usage) {
|
|
3020
|
+
case "sign":
|
|
3021
|
+
throw new TypeError(`${tag(key)} instances for asymmetric algorithm signing must be of type "private"`);
|
|
3022
|
+
case "decrypt":
|
|
3023
|
+
throw new TypeError(`${tag(key)} instances for asymmetric algorithm decryption must be of type "private"`);
|
|
3024
|
+
}
|
|
3025
|
+
}
|
|
3026
|
+
if (key.type === "private") {
|
|
3027
|
+
switch (usage) {
|
|
3028
|
+
case "verify":
|
|
3029
|
+
throw new TypeError(`${tag(key)} instances for asymmetric algorithm verifying must be of type "public"`);
|
|
3030
|
+
case "encrypt":
|
|
3031
|
+
throw new TypeError(`${tag(key)} instances for asymmetric algorithm encryption must be of type "public"`);
|
|
3032
|
+
}
|
|
3033
|
+
}
|
|
3034
|
+
};
|
|
3035
|
+
function checkKeyType(alg, key, usage) {
|
|
3036
|
+
switch (alg.substring(0, 2)) {
|
|
3037
|
+
case "A1":
|
|
3038
|
+
case "A2":
|
|
3039
|
+
case "di":
|
|
3040
|
+
case "HS":
|
|
3041
|
+
case "PB":
|
|
3042
|
+
symmetricTypeCheck(alg, key, usage);
|
|
3043
|
+
break;
|
|
3044
|
+
default:
|
|
3045
|
+
asymmetricTypeCheck(alg, key, usage);
|
|
3046
|
+
}
|
|
3047
|
+
}
|
|
3048
|
+
|
|
3049
|
+
// ../../node_modules/jose/dist/webapi/jws/flattened/verify.js
|
|
3050
|
+
async function flattenedVerify(jws, key, options) {
|
|
3051
|
+
if (!isObject(jws)) {
|
|
3052
|
+
throw new JWSInvalid("Flattened JWS must be an object");
|
|
3053
|
+
}
|
|
3054
|
+
if (jws.protected === void 0 && jws.header === void 0) {
|
|
3055
|
+
throw new JWSInvalid('Flattened JWS must have either of the "protected" or "header" members');
|
|
3056
|
+
}
|
|
3057
|
+
if (jws.protected !== void 0 && typeof jws.protected !== "string") {
|
|
3058
|
+
throw new JWSInvalid("JWS Protected Header incorrect type");
|
|
3059
|
+
}
|
|
3060
|
+
if (jws.payload === void 0) {
|
|
3061
|
+
throw new JWSInvalid("JWS Payload missing");
|
|
3062
|
+
}
|
|
3063
|
+
if (typeof jws.signature !== "string") {
|
|
3064
|
+
throw new JWSInvalid("JWS Signature missing or incorrect type");
|
|
3065
|
+
}
|
|
3066
|
+
if (jws.header !== void 0 && !isObject(jws.header)) {
|
|
3067
|
+
throw new JWSInvalid("JWS Unprotected Header incorrect type");
|
|
3068
|
+
}
|
|
3069
|
+
let parsedProt = {};
|
|
3070
|
+
if (jws.protected) {
|
|
3071
|
+
try {
|
|
3072
|
+
const protectedHeader = decode(jws.protected);
|
|
3073
|
+
parsedProt = JSON.parse(decoder2.decode(protectedHeader));
|
|
3074
|
+
} catch {
|
|
3075
|
+
throw new JWSInvalid("JWS Protected Header is invalid");
|
|
3076
|
+
}
|
|
3077
|
+
}
|
|
3078
|
+
if (!isDisjoint(parsedProt, jws.header)) {
|
|
3079
|
+
throw new JWSInvalid("JWS Protected and JWS Unprotected Header Parameter names must be disjoint");
|
|
3080
|
+
}
|
|
3081
|
+
const joseHeader = {
|
|
3082
|
+
...parsedProt,
|
|
3083
|
+
...jws.header
|
|
3084
|
+
};
|
|
3085
|
+
const extensions = validateCrit(JWSInvalid, /* @__PURE__ */ new Map([["b64", true]]), options?.crit, parsedProt, joseHeader);
|
|
3086
|
+
let b64 = true;
|
|
3087
|
+
if (extensions.has("b64")) {
|
|
3088
|
+
b64 = parsedProt.b64;
|
|
3089
|
+
if (typeof b64 !== "boolean") {
|
|
3090
|
+
throw new JWSInvalid('The "b64" (base64url-encode payload) Header Parameter must be a boolean');
|
|
3091
|
+
}
|
|
3092
|
+
}
|
|
3093
|
+
const { alg } = joseHeader;
|
|
3094
|
+
if (typeof alg !== "string" || !alg) {
|
|
3095
|
+
throw new JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid');
|
|
3096
|
+
}
|
|
3097
|
+
const algorithms = options && validateAlgorithms("algorithms", options.algorithms);
|
|
3098
|
+
if (algorithms && !algorithms.has(alg)) {
|
|
3099
|
+
throw new JOSEAlgNotAllowed('"alg" (Algorithm) Header Parameter value not allowed');
|
|
3100
|
+
}
|
|
3101
|
+
if (b64) {
|
|
3102
|
+
if (typeof jws.payload !== "string") {
|
|
3103
|
+
throw new JWSInvalid("JWS Payload must be a string");
|
|
3104
|
+
}
|
|
3105
|
+
} else if (typeof jws.payload !== "string" && !(jws.payload instanceof Uint8Array)) {
|
|
3106
|
+
throw new JWSInvalid("JWS Payload must be a string or an Uint8Array instance");
|
|
3107
|
+
}
|
|
3108
|
+
let resolvedKey = false;
|
|
3109
|
+
if (typeof key === "function") {
|
|
3110
|
+
key = await key(parsedProt, jws);
|
|
3111
|
+
resolvedKey = true;
|
|
3112
|
+
}
|
|
3113
|
+
checkKeyType(alg, key, "verify");
|
|
3114
|
+
const data = concat(jws.protected !== void 0 ? encode(jws.protected) : new Uint8Array(), encode("."), typeof jws.payload === "string" ? b64 ? encode(jws.payload) : encoder2.encode(jws.payload) : jws.payload);
|
|
3115
|
+
const signature = decodeBase64url(jws.signature, "signature", JWSInvalid);
|
|
3116
|
+
const k = await normalizeKey(key, alg);
|
|
3117
|
+
const verified = await verify(alg, k, signature, data);
|
|
3118
|
+
if (!verified) {
|
|
3119
|
+
throw new JWSSignatureVerificationFailed();
|
|
3120
|
+
}
|
|
3121
|
+
let payload;
|
|
3122
|
+
if (b64) {
|
|
3123
|
+
payload = decodeBase64url(jws.payload, "payload", JWSInvalid);
|
|
3124
|
+
} else if (typeof jws.payload === "string") {
|
|
3125
|
+
payload = encoder2.encode(jws.payload);
|
|
3126
|
+
} else {
|
|
3127
|
+
payload = jws.payload;
|
|
3128
|
+
}
|
|
3129
|
+
const result = { payload };
|
|
3130
|
+
if (jws.protected !== void 0) {
|
|
3131
|
+
result.protectedHeader = parsedProt;
|
|
3132
|
+
}
|
|
3133
|
+
if (jws.header !== void 0) {
|
|
3134
|
+
result.unprotectedHeader = jws.header;
|
|
3135
|
+
}
|
|
3136
|
+
if (resolvedKey) {
|
|
3137
|
+
return { ...result, key: k };
|
|
3138
|
+
}
|
|
3139
|
+
return result;
|
|
3140
|
+
}
|
|
3141
|
+
|
|
3142
|
+
// ../../node_modules/jose/dist/webapi/jws/compact/verify.js
|
|
3143
|
+
async function compactVerify(jws, key, options) {
|
|
3144
|
+
if (jws instanceof Uint8Array) {
|
|
3145
|
+
jws = decoder2.decode(jws);
|
|
3146
|
+
}
|
|
3147
|
+
if (typeof jws !== "string") {
|
|
3148
|
+
throw new JWSInvalid("Compact JWS must be a string or Uint8Array");
|
|
3149
|
+
}
|
|
3150
|
+
const { 0: protectedHeader, 1: payload, 2: signature, length } = jws.split(".");
|
|
3151
|
+
if (length !== 3) {
|
|
3152
|
+
throw new JWSInvalid("Invalid Compact JWS");
|
|
3153
|
+
}
|
|
3154
|
+
const verified = await flattenedVerify({ payload, protected: protectedHeader, signature }, key, options);
|
|
3155
|
+
const result = { payload: verified.payload, protectedHeader: verified.protectedHeader };
|
|
3156
|
+
if (typeof key === "function") {
|
|
3157
|
+
return { ...result, key: verified.key };
|
|
3158
|
+
}
|
|
3159
|
+
return result;
|
|
3160
|
+
}
|
|
3161
|
+
|
|
3162
|
+
// ../../node_modules/jose/dist/webapi/lib/jwt_claims_set.js
|
|
3163
|
+
var epoch = (date) => Math.floor(date.getTime() / 1e3);
|
|
3164
|
+
var minute = 60;
|
|
3165
|
+
var hour = minute * 60;
|
|
3166
|
+
var day = hour * 24;
|
|
3167
|
+
var week = day * 7;
|
|
3168
|
+
var year = day * 365.25;
|
|
3169
|
+
var REGEX = /^(\+|\-)? ?(\d+|\d+\.\d+) ?(seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)(?: (ago|from now))?$/i;
|
|
3170
|
+
function secs(str) {
|
|
3171
|
+
const matched = REGEX.exec(str);
|
|
3172
|
+
if (!matched || matched[4] && matched[1]) {
|
|
3173
|
+
throw new TypeError("Invalid time period format");
|
|
3174
|
+
}
|
|
3175
|
+
const value = parseFloat(matched[2]);
|
|
3176
|
+
const unit = matched[3].toLowerCase();
|
|
3177
|
+
let numericDate;
|
|
3178
|
+
switch (unit) {
|
|
3179
|
+
case "sec":
|
|
3180
|
+
case "secs":
|
|
3181
|
+
case "second":
|
|
3182
|
+
case "seconds":
|
|
3183
|
+
case "s":
|
|
3184
|
+
numericDate = Math.round(value);
|
|
3185
|
+
break;
|
|
3186
|
+
case "minute":
|
|
3187
|
+
case "minutes":
|
|
3188
|
+
case "min":
|
|
3189
|
+
case "mins":
|
|
3190
|
+
case "m":
|
|
3191
|
+
numericDate = Math.round(value * minute);
|
|
3192
|
+
break;
|
|
3193
|
+
case "hour":
|
|
3194
|
+
case "hours":
|
|
3195
|
+
case "hr":
|
|
3196
|
+
case "hrs":
|
|
3197
|
+
case "h":
|
|
3198
|
+
numericDate = Math.round(value * hour);
|
|
3199
|
+
break;
|
|
3200
|
+
case "day":
|
|
3201
|
+
case "days":
|
|
3202
|
+
case "d":
|
|
3203
|
+
numericDate = Math.round(value * day);
|
|
3204
|
+
break;
|
|
3205
|
+
case "week":
|
|
3206
|
+
case "weeks":
|
|
3207
|
+
case "w":
|
|
3208
|
+
numericDate = Math.round(value * week);
|
|
3209
|
+
break;
|
|
3210
|
+
default:
|
|
3211
|
+
numericDate = Math.round(value * year);
|
|
3212
|
+
break;
|
|
3213
|
+
}
|
|
3214
|
+
if (matched[1] === "-" || matched[4] === "ago") {
|
|
3215
|
+
return -numericDate;
|
|
3216
|
+
}
|
|
3217
|
+
return numericDate;
|
|
3218
|
+
}
|
|
3219
|
+
var normalizeTyp = (value) => {
|
|
3220
|
+
if (value.includes("/")) {
|
|
3221
|
+
return value.toLowerCase();
|
|
3222
|
+
}
|
|
3223
|
+
return `application/${value.toLowerCase()}`;
|
|
3224
|
+
};
|
|
3225
|
+
var checkAudiencePresence = (audPayload, audOption) => {
|
|
3226
|
+
if (typeof audPayload === "string") {
|
|
3227
|
+
return audOption.includes(audPayload);
|
|
3228
|
+
}
|
|
3229
|
+
if (Array.isArray(audPayload)) {
|
|
3230
|
+
return audOption.some(Set.prototype.has.bind(new Set(audPayload)));
|
|
3231
|
+
}
|
|
3232
|
+
return false;
|
|
3233
|
+
};
|
|
3234
|
+
function validateClaimsSet(protectedHeader, encodedPayload, options = {}) {
|
|
3235
|
+
let payload;
|
|
3236
|
+
try {
|
|
3237
|
+
payload = JSON.parse(decoder2.decode(encodedPayload));
|
|
3238
|
+
} catch {
|
|
3239
|
+
}
|
|
3240
|
+
if (!isObject(payload)) {
|
|
3241
|
+
throw new JWTInvalid("JWT Claims Set must be a top-level JSON object");
|
|
3242
|
+
}
|
|
3243
|
+
const { typ } = options;
|
|
3244
|
+
if (typ && (typeof protectedHeader.typ !== "string" || normalizeTyp(protectedHeader.typ) !== normalizeTyp(typ))) {
|
|
3245
|
+
throw new JWTClaimValidationFailed('unexpected "typ" JWT header value', payload, "typ", "check_failed");
|
|
3246
|
+
}
|
|
3247
|
+
const { requiredClaims = [], issuer, subject, audience, maxTokenAge } = options;
|
|
3248
|
+
const presenceCheck = [...requiredClaims];
|
|
3249
|
+
if (maxTokenAge !== void 0)
|
|
3250
|
+
presenceCheck.push("iat");
|
|
3251
|
+
if (audience !== void 0)
|
|
3252
|
+
presenceCheck.push("aud");
|
|
3253
|
+
if (subject !== void 0)
|
|
3254
|
+
presenceCheck.push("sub");
|
|
3255
|
+
if (issuer !== void 0)
|
|
3256
|
+
presenceCheck.push("iss");
|
|
3257
|
+
for (const claim of new Set(presenceCheck.reverse())) {
|
|
3258
|
+
if (!(claim in payload)) {
|
|
3259
|
+
throw new JWTClaimValidationFailed(`missing required "${claim}" claim`, payload, claim, "missing");
|
|
3260
|
+
}
|
|
3261
|
+
}
|
|
3262
|
+
if (issuer && !(Array.isArray(issuer) ? issuer : [issuer]).includes(payload.iss)) {
|
|
3263
|
+
throw new JWTClaimValidationFailed('unexpected "iss" claim value', payload, "iss", "check_failed");
|
|
3264
|
+
}
|
|
3265
|
+
if (subject && payload.sub !== subject) {
|
|
3266
|
+
throw new JWTClaimValidationFailed('unexpected "sub" claim value', payload, "sub", "check_failed");
|
|
3267
|
+
}
|
|
3268
|
+
if (audience && !checkAudiencePresence(payload.aud, typeof audience === "string" ? [audience] : audience)) {
|
|
3269
|
+
throw new JWTClaimValidationFailed('unexpected "aud" claim value', payload, "aud", "check_failed");
|
|
3270
|
+
}
|
|
3271
|
+
let tolerance;
|
|
3272
|
+
switch (typeof options.clockTolerance) {
|
|
3273
|
+
case "string":
|
|
3274
|
+
tolerance = secs(options.clockTolerance);
|
|
3275
|
+
break;
|
|
3276
|
+
case "number":
|
|
3277
|
+
tolerance = options.clockTolerance;
|
|
3278
|
+
break;
|
|
3279
|
+
case "undefined":
|
|
3280
|
+
tolerance = 0;
|
|
3281
|
+
break;
|
|
3282
|
+
default:
|
|
3283
|
+
throw new TypeError("Invalid clockTolerance option type");
|
|
3284
|
+
}
|
|
3285
|
+
const { currentDate } = options;
|
|
3286
|
+
const now = epoch(currentDate || /* @__PURE__ */ new Date());
|
|
3287
|
+
if ((payload.iat !== void 0 || maxTokenAge) && typeof payload.iat !== "number") {
|
|
3288
|
+
throw new JWTClaimValidationFailed('"iat" claim must be a number', payload, "iat", "invalid");
|
|
3289
|
+
}
|
|
3290
|
+
if (payload.nbf !== void 0) {
|
|
3291
|
+
if (typeof payload.nbf !== "number") {
|
|
3292
|
+
throw new JWTClaimValidationFailed('"nbf" claim must be a number', payload, "nbf", "invalid");
|
|
3293
|
+
}
|
|
3294
|
+
if (payload.nbf > now + tolerance) {
|
|
3295
|
+
throw new JWTClaimValidationFailed('"nbf" claim timestamp check failed', payload, "nbf", "check_failed");
|
|
3296
|
+
}
|
|
3297
|
+
}
|
|
3298
|
+
if (payload.exp !== void 0) {
|
|
3299
|
+
if (typeof payload.exp !== "number") {
|
|
3300
|
+
throw new JWTClaimValidationFailed('"exp" claim must be a number', payload, "exp", "invalid");
|
|
3301
|
+
}
|
|
3302
|
+
if (payload.exp <= now - tolerance) {
|
|
3303
|
+
throw new JWTExpired('"exp" claim timestamp check failed', payload, "exp", "check_failed");
|
|
3304
|
+
}
|
|
3305
|
+
}
|
|
3306
|
+
if (maxTokenAge) {
|
|
3307
|
+
const age = now - payload.iat;
|
|
3308
|
+
const max = typeof maxTokenAge === "number" ? maxTokenAge : secs(maxTokenAge);
|
|
3309
|
+
if (age - tolerance > max) {
|
|
3310
|
+
throw new JWTExpired('"iat" claim timestamp check failed (too far in the past)', payload, "iat", "check_failed");
|
|
3311
|
+
}
|
|
3312
|
+
if (age < 0 - tolerance) {
|
|
3313
|
+
throw new JWTClaimValidationFailed('"iat" claim timestamp check failed (it should be in the past)', payload, "iat", "check_failed");
|
|
3314
|
+
}
|
|
3315
|
+
}
|
|
3316
|
+
return payload;
|
|
3317
|
+
}
|
|
3318
|
+
|
|
3319
|
+
// ../../node_modules/jose/dist/webapi/jwt/verify.js
|
|
3320
|
+
async function jwtVerify(jwt2, key, options) {
|
|
3321
|
+
const verified = await compactVerify(jwt2, key, options);
|
|
3322
|
+
if (verified.protectedHeader.crit?.includes("b64") && verified.protectedHeader.b64 === false) {
|
|
3323
|
+
throw new JWTInvalid("JWTs MUST NOT use unencoded payload");
|
|
3324
|
+
}
|
|
3325
|
+
const payload = validateClaimsSet(verified.protectedHeader, verified.payload, options);
|
|
3326
|
+
const result = { payload, protectedHeader: verified.protectedHeader };
|
|
3327
|
+
if (typeof key === "function") {
|
|
3328
|
+
return { ...result, key: verified.key };
|
|
3329
|
+
}
|
|
3330
|
+
return result;
|
|
3331
|
+
}
|
|
3332
|
+
|
|
3333
|
+
// ../../node_modules/jose/dist/webapi/jwks/local.js
|
|
3334
|
+
function getKtyFromAlg(alg) {
|
|
3335
|
+
switch (typeof alg === "string" && alg.slice(0, 2)) {
|
|
3336
|
+
case "RS":
|
|
3337
|
+
case "PS":
|
|
3338
|
+
return "RSA";
|
|
3339
|
+
case "ES":
|
|
3340
|
+
return "EC";
|
|
3341
|
+
case "Ed":
|
|
3342
|
+
return "OKP";
|
|
3343
|
+
case "ML":
|
|
3344
|
+
return "AKP";
|
|
3345
|
+
default:
|
|
3346
|
+
throw new JOSENotSupported('Unsupported "alg" value for a JSON Web Key Set');
|
|
3347
|
+
}
|
|
3348
|
+
}
|
|
3349
|
+
function isJWKSLike(jwks) {
|
|
3350
|
+
return jwks && typeof jwks === "object" && Array.isArray(jwks.keys) && jwks.keys.every(isJWKLike);
|
|
3351
|
+
}
|
|
3352
|
+
function isJWKLike(key) {
|
|
3353
|
+
return isObject(key);
|
|
3354
|
+
}
|
|
3355
|
+
var LocalJWKSet = class {
|
|
3356
|
+
#jwks;
|
|
3357
|
+
#cached = /* @__PURE__ */ new WeakMap();
|
|
3358
|
+
constructor(jwks) {
|
|
3359
|
+
if (!isJWKSLike(jwks)) {
|
|
3360
|
+
throw new JWKSInvalid("JSON Web Key Set malformed");
|
|
3361
|
+
}
|
|
3362
|
+
this.#jwks = structuredClone(jwks);
|
|
3363
|
+
}
|
|
3364
|
+
jwks() {
|
|
3365
|
+
return this.#jwks;
|
|
3366
|
+
}
|
|
3367
|
+
async getKey(protectedHeader, token) {
|
|
3368
|
+
const { alg, kid } = { ...protectedHeader, ...token?.header };
|
|
3369
|
+
const kty = getKtyFromAlg(alg);
|
|
3370
|
+
const candidates = this.#jwks.keys.filter((jwk2) => {
|
|
3371
|
+
let candidate = kty === jwk2.kty;
|
|
3372
|
+
if (candidate && typeof kid === "string") {
|
|
3373
|
+
candidate = kid === jwk2.kid;
|
|
3374
|
+
}
|
|
3375
|
+
if (candidate && (typeof jwk2.alg === "string" || kty === "AKP")) {
|
|
3376
|
+
candidate = alg === jwk2.alg;
|
|
3377
|
+
}
|
|
3378
|
+
if (candidate && typeof jwk2.use === "string") {
|
|
3379
|
+
candidate = jwk2.use === "sig";
|
|
3380
|
+
}
|
|
3381
|
+
if (candidate && Array.isArray(jwk2.key_ops)) {
|
|
3382
|
+
candidate = jwk2.key_ops.includes("verify");
|
|
3383
|
+
}
|
|
3384
|
+
if (candidate) {
|
|
3385
|
+
switch (alg) {
|
|
3386
|
+
case "ES256":
|
|
3387
|
+
candidate = jwk2.crv === "P-256";
|
|
3388
|
+
break;
|
|
3389
|
+
case "ES384":
|
|
3390
|
+
candidate = jwk2.crv === "P-384";
|
|
3391
|
+
break;
|
|
3392
|
+
case "ES512":
|
|
3393
|
+
candidate = jwk2.crv === "P-521";
|
|
3394
|
+
break;
|
|
3395
|
+
case "Ed25519":
|
|
3396
|
+
case "EdDSA":
|
|
3397
|
+
candidate = jwk2.crv === "Ed25519";
|
|
3398
|
+
break;
|
|
3399
|
+
}
|
|
3400
|
+
}
|
|
3401
|
+
return candidate;
|
|
3402
|
+
});
|
|
3403
|
+
const { 0: jwk, length } = candidates;
|
|
3404
|
+
if (length === 0) {
|
|
3405
|
+
throw new JWKSNoMatchingKey();
|
|
3406
|
+
}
|
|
3407
|
+
if (length !== 1) {
|
|
3408
|
+
const error2 = new JWKSMultipleMatchingKeys();
|
|
3409
|
+
const _cached = this.#cached;
|
|
3410
|
+
error2[Symbol.asyncIterator] = async function* () {
|
|
3411
|
+
for (const jwk2 of candidates) {
|
|
3412
|
+
try {
|
|
3413
|
+
yield await importWithAlgCache(_cached, jwk2, alg);
|
|
3414
|
+
} catch {
|
|
3415
|
+
}
|
|
3416
|
+
}
|
|
3417
|
+
};
|
|
3418
|
+
throw error2;
|
|
3419
|
+
}
|
|
3420
|
+
return importWithAlgCache(this.#cached, jwk, alg);
|
|
3421
|
+
}
|
|
3422
|
+
};
|
|
3423
|
+
async function importWithAlgCache(cache2, jwk, alg) {
|
|
3424
|
+
const cached = cache2.get(jwk) || cache2.set(jwk, {}).get(jwk);
|
|
3425
|
+
if (cached[alg] === void 0) {
|
|
3426
|
+
const key = await importJWK({ ...jwk, ext: true }, alg);
|
|
3427
|
+
if (key instanceof Uint8Array || key.type !== "public") {
|
|
3428
|
+
throw new JWKSInvalid("JSON Web Key Set members must be public keys");
|
|
3429
|
+
}
|
|
3430
|
+
cached[alg] = key;
|
|
3431
|
+
}
|
|
3432
|
+
return cached[alg];
|
|
3433
|
+
}
|
|
3434
|
+
function createLocalJWKSet(jwks) {
|
|
3435
|
+
const set = new LocalJWKSet(jwks);
|
|
3436
|
+
const localJWKSet = async (protectedHeader, token) => set.getKey(protectedHeader, token);
|
|
3437
|
+
Object.defineProperties(localJWKSet, {
|
|
3438
|
+
jwks: {
|
|
3439
|
+
value: () => structuredClone(set.jwks()),
|
|
3440
|
+
enumerable: false,
|
|
3441
|
+
configurable: false,
|
|
3442
|
+
writable: false
|
|
3443
|
+
}
|
|
3444
|
+
});
|
|
3445
|
+
return localJWKSet;
|
|
3446
|
+
}
|
|
3447
|
+
|
|
3448
|
+
// src/oidc.jwt.mjs
|
|
3449
|
+
var jwksCache = /* @__PURE__ */ new WeakMap();
|
|
3450
|
+
function keySetFor(jwks) {
|
|
3451
|
+
if (!jwks || !Array.isArray(jwks.keys)) {
|
|
3452
|
+
throw metroError("metro.oidc: Error: jwks must be an object with a keys array");
|
|
3453
|
+
}
|
|
3454
|
+
if (!jwksCache.has(jwks)) {
|
|
3455
|
+
jwksCache.set(jwks, createLocalJWKSet(jwks));
|
|
3456
|
+
}
|
|
3457
|
+
return jwksCache.get(jwks);
|
|
3458
|
+
}
|
|
3459
|
+
function supportedAlgorithms(openidConfiguration = {}) {
|
|
3460
|
+
const algorithms = openidConfiguration.id_token_signing_alg_values_supported;
|
|
3461
|
+
if (Array.isArray(algorithms) && algorithms.length) {
|
|
3462
|
+
return algorithms.filter((algorithm) => algorithm !== "none");
|
|
3463
|
+
}
|
|
3464
|
+
return ["RS256"];
|
|
3465
|
+
}
|
|
3466
|
+
async function validateIdToken(idToken2, options = {}) {
|
|
3467
|
+
if (!idToken2) {
|
|
3468
|
+
throw metroError("metro.oidc: Error: token response did not include an id_token");
|
|
3469
|
+
}
|
|
3470
|
+
if (!options.jwks) {
|
|
3471
|
+
throw metroError("metro.oidc: Error: cannot validate id_token without jwks");
|
|
3472
|
+
}
|
|
3473
|
+
if (!options.issuer) {
|
|
3474
|
+
throw metroError("metro.oidc: Error: cannot validate id_token without issuer");
|
|
3475
|
+
}
|
|
3476
|
+
if (!options.client_id) {
|
|
3477
|
+
throw metroError("metro.oidc: Error: cannot validate id_token without client_id");
|
|
3478
|
+
}
|
|
3479
|
+
const { payload, protectedHeader } = await jwtVerify(
|
|
3480
|
+
idToken2,
|
|
3481
|
+
keySetFor(options.jwks),
|
|
3482
|
+
{
|
|
3483
|
+
issuer: options.issuer,
|
|
3484
|
+
audience: options.client_id,
|
|
3485
|
+
algorithms: options.algorithms || supportedAlgorithms(options.openid_configuration),
|
|
3486
|
+
clockTolerance: options.clockTolerance ?? 60,
|
|
3487
|
+
requiredClaims: ["iss", "sub", "aud", "exp", "iat"]
|
|
3488
|
+
}
|
|
3489
|
+
);
|
|
3490
|
+
if (options.nonce !== void 0 && payload.nonce !== options.nonce) {
|
|
3491
|
+
throw metroError("metro.oidc: Error: id_token nonce mismatch");
|
|
3492
|
+
}
|
|
3493
|
+
return {
|
|
3494
|
+
header: protectedHeader,
|
|
3495
|
+
claims: payload
|
|
3496
|
+
};
|
|
3497
|
+
}
|
|
3498
|
+
|
|
3499
|
+
// src/oidcmw.mjs
|
|
3500
|
+
function oidcmw(options = {}) {
|
|
3501
|
+
const defaultOptions = {
|
|
3502
|
+
client: client(),
|
|
3503
|
+
force_authorization: false,
|
|
3504
|
+
use_dpop: true,
|
|
3505
|
+
authorize_callback: async (url2) => {
|
|
3506
|
+
if (window.location.href != url2.href) {
|
|
3507
|
+
window.location.replace(url2.href);
|
|
3508
|
+
}
|
|
3509
|
+
return false;
|
|
3510
|
+
}
|
|
3511
|
+
};
|
|
3512
|
+
options = Object.assign({}, defaultOptions, options);
|
|
3513
|
+
const requestedClientInfo = options.client_info;
|
|
3514
|
+
assert(options, {
|
|
3515
|
+
client: Required(instanceOf(client().constructor)),
|
|
3516
|
+
// required because it is set in defaultOptions
|
|
3517
|
+
client_info: Required(),
|
|
3518
|
+
issuer: Required(validURL),
|
|
3519
|
+
oauth2: Optional({}),
|
|
3520
|
+
openid_configuration: Optional()
|
|
3521
|
+
});
|
|
3522
|
+
if (!options.store) {
|
|
3523
|
+
options.store = oidcStore(options.issuer);
|
|
3524
|
+
}
|
|
3525
|
+
if (!options.openid_configuration && options.store.has("openid_configuration")) {
|
|
3526
|
+
options.openid_configuration = options.store.get("openid_configuration");
|
|
3527
|
+
}
|
|
3528
|
+
if (!options.client_info?.client_id && options.store.has("client_info")) {
|
|
3529
|
+
const storedClientInfo = options.store.get("client_info");
|
|
3530
|
+
if (clientInfoMatchesRequest(storedClientInfo, requestedClientInfo)) {
|
|
3531
|
+
options.client_info = storedClientInfo;
|
|
3532
|
+
}
|
|
3533
|
+
}
|
|
3534
|
+
return async (req, next) => {
|
|
3535
|
+
let res;
|
|
3536
|
+
if (!options.force_authorization) {
|
|
3537
|
+
try {
|
|
3538
|
+
res = await next(req);
|
|
3539
|
+
} catch (err) {
|
|
3540
|
+
res = err?.cause;
|
|
3541
|
+
if (!res || res.status != 401 && res.status != 403) {
|
|
3542
|
+
throw err;
|
|
3543
|
+
}
|
|
3544
|
+
}
|
|
3545
|
+
if (res.ok || res.status != 401 && res.status != 403) {
|
|
3546
|
+
return res;
|
|
3547
|
+
}
|
|
3548
|
+
}
|
|
3549
|
+
if (!options.openid_configuration) {
|
|
3550
|
+
options.openid_configuration = await oidcDiscovery({
|
|
3551
|
+
issuer: options.issuer,
|
|
3552
|
+
client: options.client.with(options.issuer)
|
|
3553
|
+
});
|
|
3554
|
+
options.store.set("openid_configuration", options.openid_configuration);
|
|
3555
|
+
}
|
|
3556
|
+
if (!options.client_info?.client_id) {
|
|
3557
|
+
if (!options.openid_configuration.registration_endpoint) {
|
|
3558
|
+
throw metroError("metro.oidcmw: Error: issuer " + options.issuer + " does not support dynamic client registration, but you haven't specified a client_id");
|
|
3559
|
+
}
|
|
3560
|
+
options.client_info = await register({
|
|
3561
|
+
registration_endpoint: options.openid_configuration.registration_endpoint,
|
|
3562
|
+
client: options.client,
|
|
3563
|
+
client_info: options.client_info
|
|
3564
|
+
});
|
|
3565
|
+
options.store.set("client_info", options.client_info);
|
|
3566
|
+
}
|
|
3567
|
+
const scope = options.scope || "openid";
|
|
3568
|
+
const nonce = options.nonce || generateCodeVerifier(32);
|
|
3569
|
+
options.store.set("pending_nonce", nonce);
|
|
3570
|
+
const oauth2Options = Object.assign(
|
|
3571
|
+
{
|
|
3572
|
+
site: options.issuer,
|
|
3573
|
+
client: options.client,
|
|
3574
|
+
force_authorization: true,
|
|
3575
|
+
authorize_callback: options.authorize_callback,
|
|
3576
|
+
oauth2_configuration: {
|
|
3577
|
+
client_id: options.client_info?.client_id,
|
|
3578
|
+
client_secret: options.client_info?.client_secret,
|
|
3579
|
+
grant_type: "authorization_code",
|
|
3580
|
+
response_type: "code",
|
|
3581
|
+
response_mode: "query",
|
|
3582
|
+
authorization_endpoint: options.openid_configuration.authorization_endpoint,
|
|
3583
|
+
token_endpoint: options.openid_configuration.token_endpoint,
|
|
3584
|
+
scope,
|
|
3585
|
+
//FIXME: should only use scopes supported by server
|
|
3586
|
+
redirect_uri: options.client_info.redirect_uris[0],
|
|
3587
|
+
nonce
|
|
3588
|
+
}
|
|
3589
|
+
}
|
|
2224
3590
|
//...
|
|
2225
3591
|
);
|
|
2226
3592
|
const storeIdToken = async (req2, next2) => {
|
|
2227
3593
|
const res2 = await next2(req2);
|
|
3594
|
+
const tokenEndpoint = url(options.openid_configuration.token_endpoint, { hash: "" }).href;
|
|
3595
|
+
const requestUrl = url(req2.url, { hash: "" }).href;
|
|
3596
|
+
if (requestUrl !== tokenEndpoint) {
|
|
3597
|
+
return res2;
|
|
3598
|
+
}
|
|
2228
3599
|
const contentType = res2.headers.get("content-type");
|
|
2229
|
-
if (contentType?.startsWith("application/json")) {
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
id_token = data.id_token;
|
|
2237
|
-
}
|
|
2238
|
-
} catch (e) {
|
|
2239
|
-
}
|
|
2240
|
-
}
|
|
2241
|
-
if (id_token) {
|
|
2242
|
-
options.store.set("id_token", id_token);
|
|
2243
|
-
}
|
|
3600
|
+
if (!contentType?.startsWith("application/json")) {
|
|
3601
|
+
return res2;
|
|
3602
|
+
}
|
|
3603
|
+
let data = res2.data && typeof res2.data === "object" ? res2.data : null;
|
|
3604
|
+
if (!data) {
|
|
3605
|
+
const res22 = res2.clone();
|
|
3606
|
+
data = await res22.json();
|
|
2244
3607
|
}
|
|
3608
|
+
const id_token = data?.id_token;
|
|
3609
|
+
const jwks = await getJwks();
|
|
3610
|
+
const validation = await validateIdToken(id_token, {
|
|
3611
|
+
issuer: options.openid_configuration.issuer,
|
|
3612
|
+
client_id: options.client_info.client_id,
|
|
3613
|
+
jwks,
|
|
3614
|
+
openid_configuration: options.openid_configuration,
|
|
3615
|
+
nonce: options.store.get("pending_nonce")
|
|
3616
|
+
});
|
|
3617
|
+
options.store.set("id_token", id_token);
|
|
3618
|
+
options.store.set("id_token_claims", validation.claims);
|
|
2245
3619
|
return res2;
|
|
2246
3620
|
};
|
|
3621
|
+
const getJwks = async () => {
|
|
3622
|
+
if (!options.jwks) {
|
|
3623
|
+
const jwksClient = options.client.with(throwermw()).with(jsonmw());
|
|
3624
|
+
const response2 = await jwksClient.get(options.openid_configuration.jwks_uri);
|
|
3625
|
+
options.jwks = response2.data;
|
|
3626
|
+
}
|
|
3627
|
+
return options.jwks;
|
|
3628
|
+
};
|
|
2247
3629
|
let oauth2client = options.client.with(options.issuer).with(storeIdToken);
|
|
2248
3630
|
if (options.use_dpop) {
|
|
2249
3631
|
const dpopOptions = {
|
|
@@ -2253,13 +3635,23 @@
|
|
|
2253
3635
|
dpop_signing_alg_values_supported: options.openid_configuration.dpop_signing_alg_values_supported
|
|
2254
3636
|
};
|
|
2255
3637
|
oauth2client = oauth2client.with(dpopmw(dpopOptions));
|
|
2256
|
-
oauth2Options.client = oauth2client;
|
|
2257
3638
|
}
|
|
3639
|
+
oauth2Options.client = oauth2client;
|
|
2258
3640
|
oauth2client = oauth2client.with(oauth2mw(oauth2Options));
|
|
2259
3641
|
res = await oauth2client.fetch(req);
|
|
2260
3642
|
return res;
|
|
2261
3643
|
};
|
|
2262
3644
|
}
|
|
3645
|
+
function clientInfoMatchesRequest(storedClientInfo, requestedClientInfo) {
|
|
3646
|
+
if (!storedClientInfo?.client_id) {
|
|
3647
|
+
return false;
|
|
3648
|
+
}
|
|
3649
|
+
if (!Array.isArray(requestedClientInfo?.redirect_uris)) {
|
|
3650
|
+
return true;
|
|
3651
|
+
}
|
|
3652
|
+
const storedRedirectUris = new Set(storedClientInfo.redirect_uris || []);
|
|
3653
|
+
return requestedClientInfo.redirect_uris.every((uri) => storedRedirectUris.has(uri));
|
|
3654
|
+
}
|
|
2263
3655
|
function isRedirected2() {
|
|
2264
3656
|
return isRedirected();
|
|
2265
3657
|
}
|
|
@@ -2272,18 +3664,33 @@
|
|
|
2272
3664
|
}
|
|
2273
3665
|
return options.store.get("id_token");
|
|
2274
3666
|
}
|
|
3667
|
+
function idTokenClaims(options) {
|
|
3668
|
+
if (!options.store) {
|
|
3669
|
+
if (!options.issuer) {
|
|
3670
|
+
throw metroError("Must supply options.issuer or options.store to get the id_token claims");
|
|
3671
|
+
}
|
|
3672
|
+
options.store = oidcStore(options.issuer);
|
|
3673
|
+
}
|
|
3674
|
+
return options.store.get("id_token_claims");
|
|
3675
|
+
}
|
|
2275
3676
|
|
|
2276
|
-
// src/
|
|
3677
|
+
// src/index.mjs
|
|
2277
3678
|
var oidc = {
|
|
2278
3679
|
oidcmw,
|
|
2279
3680
|
discover: oidcDiscovery,
|
|
2280
3681
|
register,
|
|
2281
3682
|
isRedirected: isRedirected2,
|
|
2282
|
-
idToken
|
|
3683
|
+
idToken,
|
|
3684
|
+
idTokenClaims
|
|
2283
3685
|
};
|
|
2284
|
-
|
|
2285
|
-
|
|
3686
|
+
var index_default = oidc;
|
|
3687
|
+
|
|
3688
|
+
// src/browser.mjs
|
|
3689
|
+
var metro = Object.assign({}, src_exports, globalThis.metro || {});
|
|
3690
|
+
if (!metro.oidc) {
|
|
3691
|
+
metro.oidc = index_default;
|
|
2286
3692
|
}
|
|
2287
|
-
|
|
3693
|
+
globalThis.metro = metro;
|
|
3694
|
+
var browser_default = index_default;
|
|
2288
3695
|
})();
|
|
2289
3696
|
//# sourceMappingURL=browser.js.map
|