@muze-nl/metro-oidc 0.5.6 → 0.8.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 +1942 -498
- 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 -15
- 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 +60 -24
- 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,144 +679,7 @@
|
|
|
600
679
|
return object;
|
|
601
680
|
}
|
|
602
681
|
|
|
603
|
-
// node_modules/@muze-nl/
|
|
604
|
-
function jsonmw(options) {
|
|
605
|
-
options = Object.assign({
|
|
606
|
-
contentType: "application/json",
|
|
607
|
-
reviver: null,
|
|
608
|
-
replacer: null,
|
|
609
|
-
space: ""
|
|
610
|
-
}, options);
|
|
611
|
-
return async function json(req, next) {
|
|
612
|
-
if (!req.headers.get("Accept")) {
|
|
613
|
-
req = req.with({
|
|
614
|
-
headers: {
|
|
615
|
-
"Accept": options.accept ?? options.contentType
|
|
616
|
-
}
|
|
617
|
-
});
|
|
618
|
-
}
|
|
619
|
-
if (req.method !== "GET" && req.method !== "HEAD") {
|
|
620
|
-
if (req.data && typeof req.data == "object" && !(req.data instanceof ReadableStream)) {
|
|
621
|
-
const contentType = req.headers.get("Content-Type");
|
|
622
|
-
if (!contentType || isPlainText(contentType)) {
|
|
623
|
-
req = req.with({
|
|
624
|
-
headers: {
|
|
625
|
-
"Content-Type": options.contentType
|
|
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
|
-
};
|
|
650
|
-
}
|
|
651
|
-
var jsonRE = /^application\/([a-zA-Z0-9\-_]+\+)?json\b/;
|
|
652
|
-
function isJSON(contentType) {
|
|
653
|
-
return jsonRE.exec(contentType);
|
|
654
|
-
}
|
|
655
|
-
function isPlainText(contentType) {
|
|
656
|
-
return /^text\/plain\b/.exec(contentType);
|
|
657
|
-
}
|
|
658
|
-
|
|
659
|
-
// node_modules/@muze-nl/metro/src/mw/thrower.mjs
|
|
660
|
-
function throwermw(options) {
|
|
661
|
-
return async function thrower(req, next) {
|
|
662
|
-
let res = await next(req);
|
|
663
|
-
if (!res.ok) {
|
|
664
|
-
if (options && typeof options[res.status] == "function") {
|
|
665
|
-
res = options[res.status].apply(res, req);
|
|
666
|
-
} else {
|
|
667
|
-
throw new Error(res.status + ": " + res.statusText, {
|
|
668
|
-
cause: res
|
|
669
|
-
});
|
|
670
|
-
}
|
|
671
|
-
}
|
|
672
|
-
return res;
|
|
673
|
-
};
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
// node_modules/@muze-nl/metro/src/mw/getdata.mjs
|
|
677
|
-
function getdatamw() {
|
|
678
|
-
return async function getdata(req, next) {
|
|
679
|
-
let res = await next(req);
|
|
680
|
-
if (res.ok && res.data) {
|
|
681
|
-
return res.data;
|
|
682
|
-
}
|
|
683
|
-
return res;
|
|
684
|
-
};
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
// node_modules/@muze-nl/metro/src/api.mjs
|
|
688
|
-
var API = class extends Client {
|
|
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
|
-
}
|
|
707
|
-
}
|
|
708
|
-
};
|
|
709
|
-
var JsonAPI = class extends API {
|
|
710
|
-
constructor(base, methods, bind = null) {
|
|
711
|
-
if (base instanceof Client) {
|
|
712
|
-
super(base.with(jsonmw()), methods, bind);
|
|
713
|
-
} else {
|
|
714
|
-
super(client(base, jsonmw()), methods, bind);
|
|
715
|
-
}
|
|
716
|
-
}
|
|
717
|
-
};
|
|
718
|
-
function api(...options) {
|
|
719
|
-
return new API(...deepClone(options));
|
|
720
|
-
}
|
|
721
|
-
function jsonApi(...options) {
|
|
722
|
-
return new JsonAPI(...deepClone(options));
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
// node_modules/@muze-nl/metro/src/everything.mjs
|
|
726
|
-
var metro = Object.assign({}, metro_exports, {
|
|
727
|
-
mw: {
|
|
728
|
-
json: jsonmw,
|
|
729
|
-
thrower: throwermw,
|
|
730
|
-
getdata: getdatamw
|
|
731
|
-
},
|
|
732
|
-
api,
|
|
733
|
-
jsonApi
|
|
734
|
-
});
|
|
735
|
-
if (!globalThis.metro) {
|
|
736
|
-
globalThis.metro = metro;
|
|
737
|
-
}
|
|
738
|
-
var everything_default = metro;
|
|
739
|
-
|
|
740
|
-
// node_modules/@muze-nl/assert/src/assert.mjs
|
|
682
|
+
// ../../node_modules/@muze-nl/assert/src/assert.mjs
|
|
741
683
|
globalThis.assertEnabled = false;
|
|
742
684
|
function enable() {
|
|
743
685
|
globalThis.assertEnabled = true;
|
|
@@ -943,10 +885,10 @@
|
|
|
943
885
|
}
|
|
944
886
|
return false;
|
|
945
887
|
}
|
|
946
|
-
function error(
|
|
888
|
+
function error(message2, found, expected, path, problems) {
|
|
947
889
|
let result = {
|
|
948
890
|
path,
|
|
949
|
-
message,
|
|
891
|
+
message: message2,
|
|
950
892
|
found,
|
|
951
893
|
expected
|
|
952
894
|
};
|
|
@@ -955,8 +897,8 @@
|
|
|
955
897
|
}
|
|
956
898
|
return result;
|
|
957
899
|
}
|
|
958
|
-
function warn(
|
|
959
|
-
console.warn("\u{1F170}\uFE0F Assert: " + path,
|
|
900
|
+
function warn(message2, data, pattern, path) {
|
|
901
|
+
console.warn("\u{1F170}\uFE0F Assert: " + path, message2, pattern, data);
|
|
960
902
|
}
|
|
961
903
|
globalThis.assert = {
|
|
962
904
|
warn,
|
|
@@ -977,7 +919,7 @@
|
|
|
977
919
|
fails
|
|
978
920
|
};
|
|
979
921
|
|
|
980
|
-
//
|
|
922
|
+
// ../metro-oauth2/src/tokenstore.mjs
|
|
981
923
|
function tokenStore(site) {
|
|
982
924
|
let localState, localTokens;
|
|
983
925
|
if (typeof localStorage !== "undefined") {
|
|
@@ -985,7 +927,7 @@
|
|
|
985
927
|
get: () => localStorage.getItem("metro/state:" + site),
|
|
986
928
|
set: (value) => localStorage.setItem("metro/state:" + site, value),
|
|
987
929
|
has: () => localStorage.getItem("metro/state:" + site) !== null,
|
|
988
|
-
delete: () => localStorage.
|
|
930
|
+
delete: () => localStorage.removeItem("metro/state:" + site)
|
|
989
931
|
};
|
|
990
932
|
localTokens = {
|
|
991
933
|
get: (name) => JSON.parse(localStorage.getItem(site + ":" + name)),
|
|
@@ -1009,7 +951,16 @@
|
|
|
1009
951
|
};
|
|
1010
952
|
}
|
|
1011
953
|
|
|
1012
|
-
//
|
|
954
|
+
// ../metro-oauth2/src/oauth2.mjs
|
|
955
|
+
var SUPPORTED_TOKEN_TYPES = /* @__PURE__ */ new Map([
|
|
956
|
+
["bearer", "Bearer"],
|
|
957
|
+
["dpop", "DPoP"]
|
|
958
|
+
]);
|
|
959
|
+
var SUPPORTED_TOKEN_ENDPOINT_AUTH_METHODS = /* @__PURE__ */ new Set([
|
|
960
|
+
"none",
|
|
961
|
+
"client_secret_post",
|
|
962
|
+
"client_secret_basic"
|
|
963
|
+
]);
|
|
1013
964
|
function oauth2mw(options) {
|
|
1014
965
|
const defaultOptions = {
|
|
1015
966
|
client: client(),
|
|
@@ -1054,7 +1005,7 @@
|
|
|
1054
1005
|
case "access_token":
|
|
1055
1006
|
case "authorization_code":
|
|
1056
1007
|
case "refresh_token":
|
|
1057
|
-
options.tokens.set(option, oauth2[option]);
|
|
1008
|
+
options.tokens.set(option, normalizeInitialToken(option, oauth2[option]));
|
|
1058
1009
|
break;
|
|
1059
1010
|
}
|
|
1060
1011
|
}
|
|
@@ -1062,32 +1013,11 @@
|
|
|
1062
1013
|
if (options.force_authorization) {
|
|
1063
1014
|
return oauth2authorized(req, next);
|
|
1064
1015
|
}
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
res
|
|
1068
|
-
if (res.ok) {
|
|
1069
|
-
return res;
|
|
1070
|
-
}
|
|
1071
|
-
} catch (err) {
|
|
1072
|
-
switch (res?.status) {
|
|
1073
|
-
case 400:
|
|
1074
|
-
// Oauth2.1 RFC 3.2.4
|
|
1075
|
-
case 401:
|
|
1076
|
-
return oauth2authorized(req, next);
|
|
1077
|
-
break;
|
|
1078
|
-
}
|
|
1079
|
-
throw err;
|
|
1080
|
-
}
|
|
1081
|
-
if (!res.ok) {
|
|
1082
|
-
switch (res.status) {
|
|
1083
|
-
case 400:
|
|
1084
|
-
// Oauth2.1 RFC 3.2.4
|
|
1085
|
-
case 401:
|
|
1086
|
-
return oauth2authorized(req, next);
|
|
1087
|
-
break;
|
|
1088
|
-
}
|
|
1016
|
+
const res = await next(req);
|
|
1017
|
+
if (res.ok || !shouldAuthorizeResponse(res)) {
|
|
1018
|
+
return res;
|
|
1089
1019
|
}
|
|
1090
|
-
return
|
|
1020
|
+
return oauth2authorized(req, next);
|
|
1091
1021
|
};
|
|
1092
1022
|
async function oauth2authorized(req, next) {
|
|
1093
1023
|
getTokensFromLocation();
|
|
@@ -1095,23 +1025,15 @@
|
|
|
1095
1025
|
const refreshToken = options.tokens.get("refresh_token");
|
|
1096
1026
|
const tokenIsExpired = isExpired(accessToken);
|
|
1097
1027
|
if (!accessToken || tokenIsExpired && !refreshToken) {
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
return response("false");
|
|
1102
|
-
}
|
|
1103
|
-
} catch (e) {
|
|
1104
|
-
throw e;
|
|
1028
|
+
const token = await fetchAccessToken();
|
|
1029
|
+
if (!token) {
|
|
1030
|
+
return response("false");
|
|
1105
1031
|
}
|
|
1106
1032
|
return oauth2authorized(req, next);
|
|
1107
1033
|
} else if (tokenIsExpired && refreshToken) {
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
return response("false");
|
|
1112
|
-
}
|
|
1113
|
-
} catch (e) {
|
|
1114
|
-
throw e;
|
|
1034
|
+
const token = await refreshAccessToken();
|
|
1035
|
+
if (!token) {
|
|
1036
|
+
return response("false");
|
|
1115
1037
|
}
|
|
1116
1038
|
return oauth2authorized(req, next);
|
|
1117
1039
|
} else {
|
|
@@ -1127,7 +1049,7 @@
|
|
|
1127
1049
|
if (typeof window !== "undefined" && window?.location) {
|
|
1128
1050
|
let url2 = url(window.location);
|
|
1129
1051
|
let code, state, params;
|
|
1130
|
-
if (url2.searchParams.has("code")) {
|
|
1052
|
+
if (url2.searchParams.has("code") || url2.searchParams.has("error")) {
|
|
1131
1053
|
params = url2.searchParams;
|
|
1132
1054
|
url2 = url2.with({ search: "" });
|
|
1133
1055
|
history.pushState({}, "", url2.href);
|
|
@@ -1138,12 +1060,12 @@
|
|
|
1138
1060
|
history.pushState({}, "", url2.href);
|
|
1139
1061
|
}
|
|
1140
1062
|
if (params) {
|
|
1063
|
+
if (params.has("error")) {
|
|
1064
|
+
throw metroError("oauth2mw: authorization failed: " + params.get("error") + (params.get("error_description") ? " (" + params.get("error_description") + ")" : ""));
|
|
1065
|
+
}
|
|
1141
1066
|
code = params.get("code");
|
|
1142
1067
|
state = params.get("state");
|
|
1143
|
-
|
|
1144
|
-
if (!state || state !== storedState) {
|
|
1145
|
-
return;
|
|
1146
|
-
}
|
|
1068
|
+
validateState(state);
|
|
1147
1069
|
if (code) {
|
|
1148
1070
|
options.tokens.set("authorization_code", code);
|
|
1149
1071
|
}
|
|
@@ -1156,9 +1078,9 @@
|
|
|
1156
1078
|
if (!options.authorize_callback || typeof options.authorize_callback !== "function") {
|
|
1157
1079
|
throw metroError("oauth2mw: oauth2 with grant_type:authorization_code requires a callback function in client options.authorize_callback");
|
|
1158
1080
|
}
|
|
1159
|
-
let
|
|
1160
|
-
if (
|
|
1161
|
-
|
|
1081
|
+
let authorization = await options.authorize_callback(authReqURL);
|
|
1082
|
+
if (authorization) {
|
|
1083
|
+
storeAuthorizationResult(authorization);
|
|
1162
1084
|
} else {
|
|
1163
1085
|
return false;
|
|
1164
1086
|
}
|
|
@@ -1170,18 +1092,7 @@
|
|
|
1170
1092
|
throw metroError("OAuth2mw: fetch access_token: " + response2.status + ": " + response2.statusText + " (" + msg + ")", { cause: tokenReq });
|
|
1171
1093
|
}
|
|
1172
1094
|
let data = await response2.json();
|
|
1173
|
-
|
|
1174
|
-
value: data.access_token,
|
|
1175
|
-
expires: getExpires(data.expires_in),
|
|
1176
|
-
type: data.token_type,
|
|
1177
|
-
scope: data.scope
|
|
1178
|
-
});
|
|
1179
|
-
if (data.refresh_token) {
|
|
1180
|
-
let token = {
|
|
1181
|
-
value: data.refresh_token
|
|
1182
|
-
};
|
|
1183
|
-
options.tokens.set("refresh_token", token);
|
|
1184
|
-
}
|
|
1095
|
+
storeTokenResponse(data);
|
|
1185
1096
|
options.tokens.delete("authorization_code");
|
|
1186
1097
|
return data;
|
|
1187
1098
|
}
|
|
@@ -1189,23 +1100,11 @@
|
|
|
1189
1100
|
let refreshTokenReq = getAccessTokenRequest("refresh_token");
|
|
1190
1101
|
let response2 = await options.client.post(refreshTokenReq);
|
|
1191
1102
|
if (!response2.ok) {
|
|
1192
|
-
|
|
1103
|
+
let msg = await response2.text();
|
|
1104
|
+
throw metroError("OAuth2mw: refresh access_token: " + response2.status + ": " + response2.statusText + " (" + msg + ")", { cause: refreshTokenReq });
|
|
1193
1105
|
}
|
|
1194
1106
|
let data = await response2.json();
|
|
1195
|
-
|
|
1196
|
-
value: data.access_token,
|
|
1197
|
-
expires: getExpires(data.expires_in),
|
|
1198
|
-
type: data.token_type,
|
|
1199
|
-
scope: data.scope
|
|
1200
|
-
});
|
|
1201
|
-
if (data.refresh_token) {
|
|
1202
|
-
let token = {
|
|
1203
|
-
value: data.refresh_token
|
|
1204
|
-
};
|
|
1205
|
-
options.tokens.set("refresh_token", token);
|
|
1206
|
-
} else {
|
|
1207
|
-
return false;
|
|
1208
|
-
}
|
|
1107
|
+
storeTokenResponse(data);
|
|
1209
1108
|
return data;
|
|
1210
1109
|
}
|
|
1211
1110
|
async function getAuthorizationCodeURL() {
|
|
@@ -1220,11 +1119,9 @@
|
|
|
1220
1119
|
});
|
|
1221
1120
|
let search = {
|
|
1222
1121
|
response_type: "code",
|
|
1223
|
-
// implicit flow uses 'token' here, but is not considered safe, so not supported
|
|
1224
1122
|
client_id: oauth2.client_id,
|
|
1225
1123
|
redirect_uri: oauth2.redirect_uri,
|
|
1226
1124
|
state: oauth2.state || createState(40)
|
|
1227
|
-
// OAuth2.1 RFC says optional, but its a good idea to always add/check it
|
|
1228
1125
|
};
|
|
1229
1126
|
if (oauth2.response_type) {
|
|
1230
1127
|
search.response_type = oauth2.response_type;
|
|
@@ -1233,9 +1130,6 @@
|
|
|
1233
1130
|
search.response_mode = oauth2.response_mode;
|
|
1234
1131
|
}
|
|
1235
1132
|
options.state.set(search.state);
|
|
1236
|
-
if (oauth2.client_secret) {
|
|
1237
|
-
search.client_secret = oauth2.client_secret;
|
|
1238
|
-
}
|
|
1239
1133
|
if (oauth2.code_verifier) {
|
|
1240
1134
|
options.tokens.set("code_verifier", oauth2.code_verifier);
|
|
1241
1135
|
search.code_challenge = await generateCodeChallenge(oauth2.code_verifier);
|
|
@@ -1247,6 +1141,9 @@
|
|
|
1247
1141
|
if (oauth2.prompt) {
|
|
1248
1142
|
search.prompt = oauth2.prompt;
|
|
1249
1143
|
}
|
|
1144
|
+
if (oauth2.nonce) {
|
|
1145
|
+
search.nonce = oauth2.nonce;
|
|
1146
|
+
}
|
|
1250
1147
|
return url(url2, { search });
|
|
1251
1148
|
}
|
|
1252
1149
|
function getAccessTokenRequest(grant_type = null) {
|
|
@@ -1259,12 +1156,10 @@
|
|
|
1259
1156
|
}
|
|
1260
1157
|
let url2 = url(oauth2.token_endpoint, { hash: "" });
|
|
1261
1158
|
let params = {
|
|
1262
|
-
grant_type: grant_type || oauth2.grant_type
|
|
1263
|
-
client_id: oauth2.client_id
|
|
1159
|
+
grant_type: grant_type || oauth2.grant_type
|
|
1264
1160
|
};
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
}
|
|
1161
|
+
let headers = {};
|
|
1162
|
+
applyTokenEndpointAuthentication(params, headers);
|
|
1268
1163
|
if (oauth2.scope) {
|
|
1269
1164
|
params.scope = oauth2.scope;
|
|
1270
1165
|
}
|
|
@@ -1280,24 +1175,146 @@
|
|
|
1280
1175
|
case "client_credentials":
|
|
1281
1176
|
break;
|
|
1282
1177
|
case "refresh_token":
|
|
1283
|
-
params.refresh_token = options.tokens.get("refresh_token");
|
|
1178
|
+
params.refresh_token = tokenValue(options.tokens.get("refresh_token"));
|
|
1284
1179
|
break;
|
|
1285
1180
|
default:
|
|
1286
|
-
throw new Error("Unknown grant_type: ".
|
|
1181
|
+
throw new Error("Unknown grant_type: " + params.grant_type);
|
|
1287
1182
|
break;
|
|
1288
1183
|
}
|
|
1289
|
-
return request(url2, { method: "POST", body: new URLSearchParams(params) });
|
|
1184
|
+
return request(url2, { method: "POST", headers, body: new URLSearchParams(params) });
|
|
1290
1185
|
}
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1186
|
+
function applyTokenEndpointAuthentication(params, headers) {
|
|
1187
|
+
const method = tokenEndpointAuthMethod(oauth2);
|
|
1188
|
+
if (method === "none") {
|
|
1189
|
+
params.client_id = oauth2.client_id;
|
|
1190
|
+
return;
|
|
1191
|
+
}
|
|
1192
|
+
if (!oauth2.client_secret) {
|
|
1193
|
+
throw metroError("oauth2mw: token_endpoint_auth_method " + method + " requires oauth2_configuration.client_secret");
|
|
1194
|
+
}
|
|
1195
|
+
if (method === "client_secret_post") {
|
|
1196
|
+
params.client_id = oauth2.client_id;
|
|
1197
|
+
params.client_secret = oauth2.client_secret;
|
|
1198
|
+
return;
|
|
1199
|
+
}
|
|
1200
|
+
if (method === "client_secret_basic") {
|
|
1201
|
+
headers.Authorization = basicAuth(oauth2.client_id, oauth2.client_secret);
|
|
1202
|
+
return;
|
|
1203
|
+
}
|
|
1295
1204
|
}
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1205
|
+
function storeAuthorizationResult(authorization) {
|
|
1206
|
+
let code = authorization;
|
|
1207
|
+
if (authorization && typeof authorization === "object") {
|
|
1208
|
+
if (authorization.error) {
|
|
1209
|
+
throw metroError("oauth2mw: authorization failed: " + authorization.error);
|
|
1210
|
+
}
|
|
1211
|
+
validateState(authorization.state);
|
|
1212
|
+
code = authorization.authorization_code || authorization.code;
|
|
1213
|
+
}
|
|
1214
|
+
if (!code) {
|
|
1215
|
+
throw metroError("oauth2mw: authorization callback did not return an authorization code");
|
|
1216
|
+
}
|
|
1217
|
+
options.tokens.set("authorization_code", code);
|
|
1218
|
+
}
|
|
1219
|
+
function validateState(state) {
|
|
1220
|
+
let storedState = options.state.get();
|
|
1221
|
+
if (!state || state !== storedState) {
|
|
1222
|
+
throw metroError("oauth2mw: authorization state mismatch");
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
function storeTokenResponse(data) {
|
|
1226
|
+
const token = validateTokenResponse(data);
|
|
1227
|
+
options.tokens.set("access_token", token);
|
|
1228
|
+
if (data.refresh_token) {
|
|
1229
|
+
options.tokens.set("refresh_token", { value: data.refresh_token });
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
function shouldAuthorizeResponse(res) {
|
|
1234
|
+
if (!res) {
|
|
1235
|
+
return false;
|
|
1236
|
+
}
|
|
1237
|
+
if (res.status === 400) {
|
|
1238
|
+
return true;
|
|
1239
|
+
}
|
|
1240
|
+
const challenge = parseBearerChallenge(res.headers?.get("WWW-Authenticate"));
|
|
1241
|
+
if (challenge?.error === "insufficient_scope") {
|
|
1242
|
+
return false;
|
|
1243
|
+
}
|
|
1244
|
+
return res.status === 401;
|
|
1245
|
+
}
|
|
1246
|
+
function normalizeInitialToken(name, token) {
|
|
1247
|
+
if (name === "access_token" && token && typeof token === "object") {
|
|
1248
|
+
return token;
|
|
1249
|
+
}
|
|
1250
|
+
if (name === "access_token") {
|
|
1251
|
+
return { value: token, type: "Bearer", expires: null };
|
|
1252
|
+
}
|
|
1253
|
+
if (name === "refresh_token" && token && typeof token === "object") {
|
|
1254
|
+
return token;
|
|
1255
|
+
}
|
|
1256
|
+
return token;
|
|
1257
|
+
}
|
|
1258
|
+
function validateTokenResponse(data) {
|
|
1259
|
+
if (!data || typeof data !== "object") {
|
|
1260
|
+
throw metroError("OAuth2mw: token endpoint did not return a JSON object");
|
|
1261
|
+
}
|
|
1262
|
+
if (!data.access_token) {
|
|
1263
|
+
throw metroError("OAuth2mw: token response did not include access_token");
|
|
1264
|
+
}
|
|
1265
|
+
if (!data.token_type) {
|
|
1266
|
+
throw metroError("OAuth2mw: token response did not include token_type");
|
|
1267
|
+
}
|
|
1268
|
+
const tokenType = normalizeTokenType(data.token_type);
|
|
1269
|
+
return {
|
|
1270
|
+
value: data.access_token,
|
|
1271
|
+
expires: data.expires_in === void 0 ? null : getExpires(data.expires_in),
|
|
1272
|
+
type: tokenType,
|
|
1273
|
+
scope: data.scope
|
|
1274
|
+
};
|
|
1275
|
+
}
|
|
1276
|
+
function normalizeTokenType(type) {
|
|
1277
|
+
const normalized = SUPPORTED_TOKEN_TYPES.get(String(type).toLowerCase());
|
|
1278
|
+
if (!normalized) {
|
|
1279
|
+
throw metroError("OAuth2mw: unsupported token_type " + type);
|
|
1280
|
+
}
|
|
1281
|
+
return normalized;
|
|
1282
|
+
}
|
|
1283
|
+
function tokenEndpointAuthMethod(oauth2) {
|
|
1284
|
+
const method = oauth2.token_endpoint_auth_method || (oauth2.client_secret ? "client_secret_post" : "none");
|
|
1285
|
+
if (!SUPPORTED_TOKEN_ENDPOINT_AUTH_METHODS.has(method)) {
|
|
1286
|
+
throw metroError("oauth2mw: unsupported token_endpoint_auth_method " + method);
|
|
1287
|
+
}
|
|
1288
|
+
return method;
|
|
1289
|
+
}
|
|
1290
|
+
function basicAuth(clientId, clientSecret) {
|
|
1291
|
+
const value = formEncode(clientId) + ":" + formEncode(clientSecret);
|
|
1292
|
+
return "Basic " + base64_encode(value);
|
|
1293
|
+
}
|
|
1294
|
+
function formEncode(value) {
|
|
1295
|
+
return encodeURIComponent(value).replace(/%20/g, "+");
|
|
1296
|
+
}
|
|
1297
|
+
function base64_encode(value) {
|
|
1298
|
+
if (typeof btoa === "function") {
|
|
1299
|
+
return btoa(value);
|
|
1300
|
+
}
|
|
1301
|
+
return Buffer.from(value, "binary").toString("base64");
|
|
1302
|
+
}
|
|
1303
|
+
function tokenValue(token) {
|
|
1304
|
+
return token && typeof token === "object" ? token.value : token;
|
|
1305
|
+
}
|
|
1306
|
+
function isExpired(token) {
|
|
1307
|
+
if (!token) {
|
|
1308
|
+
return true;
|
|
1309
|
+
}
|
|
1310
|
+
if (!token.expires) {
|
|
1311
|
+
return false;
|
|
1312
|
+
}
|
|
1313
|
+
let expires = new Date(token.expires);
|
|
1314
|
+
let now = /* @__PURE__ */ new Date();
|
|
1315
|
+
return now.getTime() > expires.getTime();
|
|
1316
|
+
}
|
|
1317
|
+
function getExpires(duration) {
|
|
1301
1318
|
if (duration instanceof Date) {
|
|
1302
1319
|
return new Date(duration.getTime());
|
|
1303
1320
|
}
|
|
@@ -1314,8 +1331,8 @@
|
|
|
1314
1331
|
return base64url_encode(code_verifier);
|
|
1315
1332
|
}
|
|
1316
1333
|
async function generateCodeChallenge(code_verifier) {
|
|
1317
|
-
const
|
|
1318
|
-
const data =
|
|
1334
|
+
const encoder3 = new TextEncoder();
|
|
1335
|
+
const data = encoder3.encode(code_verifier);
|
|
1319
1336
|
const challenge = await globalThis.crypto.subtle.digest("SHA-256", data);
|
|
1320
1337
|
return base64url_encode(challenge);
|
|
1321
1338
|
}
|
|
@@ -1324,6 +1341,11 @@
|
|
|
1324
1341
|
return btoa(byteString).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
1325
1342
|
}
|
|
1326
1343
|
function createState(length) {
|
|
1344
|
+
const bytes = new Uint8Array(Math.ceil(length * 3 / 4) + 1);
|
|
1345
|
+
if (globalThis.crypto?.getRandomValues) {
|
|
1346
|
+
globalThis.crypto.getRandomValues(bytes);
|
|
1347
|
+
return base64url_encode(bytes).slice(0, length);
|
|
1348
|
+
}
|
|
1327
1349
|
const validChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
1328
1350
|
let randomState = "";
|
|
1329
1351
|
let counter = 0;
|
|
@@ -1347,59 +1369,31 @@
|
|
|
1347
1369
|
}
|
|
1348
1370
|
return true;
|
|
1349
1371
|
}
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
},
|
|
1373
|
-
get: function(key) {
|
|
1374
|
-
return new Promise((resolve2, reject2) => {
|
|
1375
|
-
const tx = db.transaction("keyPairs", "readonly");
|
|
1376
|
-
const objectStore = tx.objectStore("keyPairs");
|
|
1377
|
-
const request3 = objectStore.get(key);
|
|
1378
|
-
request3.onsuccess = () => {
|
|
1379
|
-
resolve2(request3.result);
|
|
1380
|
-
};
|
|
1381
|
-
request3.onerror = reject2;
|
|
1382
|
-
tx.onerror = reject2;
|
|
1383
|
-
});
|
|
1384
|
-
},
|
|
1385
|
-
clear: function() {
|
|
1386
|
-
return new Promise((resolve2, reject2) => {
|
|
1387
|
-
const tx = db.transaction("keyPairs", "readwrite");
|
|
1388
|
-
const objectStore = tx.objectStore("keyPairs");
|
|
1389
|
-
const request3 = objectStore.clear();
|
|
1390
|
-
request3.onsuccess = () => {
|
|
1391
|
-
resolve2();
|
|
1392
|
-
};
|
|
1393
|
-
request3.onerror = reject2;
|
|
1394
|
-
tx.onerror = reject2;
|
|
1395
|
-
});
|
|
1396
|
-
}
|
|
1397
|
-
});
|
|
1398
|
-
};
|
|
1399
|
-
});
|
|
1372
|
+
function parseBearerChallenge(value) {
|
|
1373
|
+
if (!value || typeof value !== "string") {
|
|
1374
|
+
return null;
|
|
1375
|
+
}
|
|
1376
|
+
const trimmed = value.trim();
|
|
1377
|
+
const index = trimmed.search(/\s/);
|
|
1378
|
+
const scheme = index < 0 ? trimmed : trimmed.slice(0, index);
|
|
1379
|
+
const rest = index < 0 ? "" : trimmed.slice(index + 1);
|
|
1380
|
+
if (!["bearer", "dpop"].includes(scheme.toLowerCase())) {
|
|
1381
|
+
return null;
|
|
1382
|
+
}
|
|
1383
|
+
const result = { scheme };
|
|
1384
|
+
const pattern = /([A-Za-z][A-Za-z0-9_-]*)=("(?:[^"\\]|\\.)*"|[^,\s]*)/g;
|
|
1385
|
+
let match;
|
|
1386
|
+
while (match = pattern.exec(rest)) {
|
|
1387
|
+
let value2 = match[2];
|
|
1388
|
+
if (value2.startsWith('"') && value2.endsWith('"')) {
|
|
1389
|
+
value2 = value2.slice(1, -1).replace(/\\"/g, '"');
|
|
1390
|
+
}
|
|
1391
|
+
result[match[1]] = value2;
|
|
1392
|
+
}
|
|
1393
|
+
return result;
|
|
1400
1394
|
}
|
|
1401
1395
|
|
|
1402
|
-
// node_modules/dpop/build/index.js
|
|
1396
|
+
// ../../node_modules/dpop/build/index.js
|
|
1403
1397
|
var encoder = new TextEncoder();
|
|
1404
1398
|
var decoder = new TextDecoder();
|
|
1405
1399
|
function buf(input) {
|
|
@@ -1464,17 +1458,17 @@
|
|
|
1464
1458
|
return encodeBase64Url(input);
|
|
1465
1459
|
}
|
|
1466
1460
|
var UnsupportedOperationError = class extends Error {
|
|
1467
|
-
constructor(
|
|
1461
|
+
constructor(message2) {
|
|
1468
1462
|
var _a;
|
|
1469
|
-
super(
|
|
1463
|
+
super(message2 !== null && message2 !== void 0 ? message2 : "operation not supported");
|
|
1470
1464
|
this.name = this.constructor.name;
|
|
1471
1465
|
(_a = Error.captureStackTrace) === null || _a === void 0 ? void 0 : _a.call(Error, this, this.constructor);
|
|
1472
1466
|
}
|
|
1473
1467
|
};
|
|
1474
1468
|
var OperationProcessingError = class extends Error {
|
|
1475
|
-
constructor(
|
|
1469
|
+
constructor(message2) {
|
|
1476
1470
|
var _a;
|
|
1477
|
-
super(
|
|
1471
|
+
super(message2);
|
|
1478
1472
|
this.name = this.constructor.name;
|
|
1479
1473
|
(_a = Error.captureStackTrace) === null || _a === void 0 ? void 0 : _a.call(Error, this, this.constructor);
|
|
1480
1474
|
}
|
|
@@ -1608,7 +1602,58 @@
|
|
|
1608
1602
|
return crypto.subtle.generateKey(algorithm, (_a = options === null || options === void 0 ? void 0 : options.extractable) !== null && _a !== void 0 ? _a : false, ["sign", "verify"]);
|
|
1609
1603
|
}
|
|
1610
1604
|
|
|
1611
|
-
//
|
|
1605
|
+
// ../metro-oauth2/src/keysstore.mjs
|
|
1606
|
+
function keysStore() {
|
|
1607
|
+
return new Promise((resolve, reject) => {
|
|
1608
|
+
const request2 = globalThis.indexedDB.open("metro", 1);
|
|
1609
|
+
request2.onupgradeneeded = () => request2.result.createObjectStore("keyPairs", { keyPath: "domain" });
|
|
1610
|
+
request2.onerror = (event) => {
|
|
1611
|
+
reject(event);
|
|
1612
|
+
};
|
|
1613
|
+
request2.onsuccess = (event) => {
|
|
1614
|
+
const db = event.target.result;
|
|
1615
|
+
resolve({
|
|
1616
|
+
set: function(value, key) {
|
|
1617
|
+
return new Promise((resolve2, reject2) => {
|
|
1618
|
+
const tx = db.transaction("keyPairs", "readwrite", { durability: "strict" });
|
|
1619
|
+
const objectStore = tx.objectStore("keyPairs");
|
|
1620
|
+
tx.oncomplete = () => {
|
|
1621
|
+
resolve2();
|
|
1622
|
+
};
|
|
1623
|
+
tx.onerror = reject2;
|
|
1624
|
+
objectStore.put(value, key);
|
|
1625
|
+
});
|
|
1626
|
+
},
|
|
1627
|
+
get: function(key) {
|
|
1628
|
+
return new Promise((resolve2, reject2) => {
|
|
1629
|
+
const tx = db.transaction("keyPairs", "readonly");
|
|
1630
|
+
const objectStore = tx.objectStore("keyPairs");
|
|
1631
|
+
const request3 = objectStore.get(key);
|
|
1632
|
+
request3.onsuccess = () => {
|
|
1633
|
+
resolve2(request3.result);
|
|
1634
|
+
};
|
|
1635
|
+
request3.onerror = reject2;
|
|
1636
|
+
tx.onerror = reject2;
|
|
1637
|
+
});
|
|
1638
|
+
},
|
|
1639
|
+
clear: function() {
|
|
1640
|
+
return new Promise((resolve2, reject2) => {
|
|
1641
|
+
const tx = db.transaction("keyPairs", "readwrite");
|
|
1642
|
+
const objectStore = tx.objectStore("keyPairs");
|
|
1643
|
+
const request3 = objectStore.clear();
|
|
1644
|
+
request3.onsuccess = () => {
|
|
1645
|
+
resolve2();
|
|
1646
|
+
};
|
|
1647
|
+
request3.onerror = reject2;
|
|
1648
|
+
tx.onerror = reject2;
|
|
1649
|
+
});
|
|
1650
|
+
}
|
|
1651
|
+
});
|
|
1652
|
+
};
|
|
1653
|
+
});
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1656
|
+
// ../metro-oauth2/src/oauth2.dpop.mjs
|
|
1612
1657
|
function dpopmw(options) {
|
|
1613
1658
|
assert(options, {
|
|
1614
1659
|
site: Required(validURL),
|
|
@@ -1625,7 +1670,7 @@
|
|
|
1625
1670
|
keyInfo = { domain: options.site, keyPair };
|
|
1626
1671
|
await keys.set(keyInfo);
|
|
1627
1672
|
}
|
|
1628
|
-
const url2 =
|
|
1673
|
+
const url2 = url(req.url);
|
|
1629
1674
|
if (req.url.startsWith(options.authorization_endpoint)) {
|
|
1630
1675
|
let params = req.body;
|
|
1631
1676
|
if (params instanceof URLSearchParams || params instanceof FormData) {
|
|
@@ -1659,6 +1704,79 @@
|
|
|
1659
1704
|
};
|
|
1660
1705
|
}
|
|
1661
1706
|
|
|
1707
|
+
// ../metro-middleware/src/json.mjs
|
|
1708
|
+
function jsonmw(options) {
|
|
1709
|
+
options = Object.assign({
|
|
1710
|
+
contentType: "application/json",
|
|
1711
|
+
reviver: null,
|
|
1712
|
+
replacer: null,
|
|
1713
|
+
space: ""
|
|
1714
|
+
}, options);
|
|
1715
|
+
return async function json(req, next) {
|
|
1716
|
+
if (!req.headers.get("Accept")) {
|
|
1717
|
+
req = req.with({
|
|
1718
|
+
headers: {
|
|
1719
|
+
"Accept": options.accept ?? options.contentType
|
|
1720
|
+
}
|
|
1721
|
+
});
|
|
1722
|
+
}
|
|
1723
|
+
if (req.method !== "GET" && req.method !== "HEAD") {
|
|
1724
|
+
if (req.data && typeof req.data == "object" && !(req.data instanceof ReadableStream)) {
|
|
1725
|
+
const contentType = req.headers.get("Content-Type");
|
|
1726
|
+
if (!contentType || isPlainText(contentType)) {
|
|
1727
|
+
req = req.with({
|
|
1728
|
+
headers: {
|
|
1729
|
+
"Content-Type": options.contentType
|
|
1730
|
+
}
|
|
1731
|
+
});
|
|
1732
|
+
}
|
|
1733
|
+
if (isJSON(req.headers.get("Content-Type"))) {
|
|
1734
|
+
req = req.with({
|
|
1735
|
+
body: JSON.stringify(req.data, options.replacer, options.space)
|
|
1736
|
+
});
|
|
1737
|
+
}
|
|
1738
|
+
}
|
|
1739
|
+
}
|
|
1740
|
+
let res = await next(req);
|
|
1741
|
+
if (res && isJSON(res.headers?.get("Content-Type"))) {
|
|
1742
|
+
let tempRes = res.clone();
|
|
1743
|
+
let body = await tempRes.text();
|
|
1744
|
+
try {
|
|
1745
|
+
let json2 = JSON.parse(body, options.reviver);
|
|
1746
|
+
return res.with({
|
|
1747
|
+
body: json2
|
|
1748
|
+
});
|
|
1749
|
+
} catch (e) {
|
|
1750
|
+
}
|
|
1751
|
+
}
|
|
1752
|
+
return res;
|
|
1753
|
+
};
|
|
1754
|
+
}
|
|
1755
|
+
var jsonRE = /^application\/([a-zA-Z0-9\-_]+\+)?json\b/;
|
|
1756
|
+
function isJSON(contentType) {
|
|
1757
|
+
return jsonRE.exec(contentType);
|
|
1758
|
+
}
|
|
1759
|
+
function isPlainText(contentType) {
|
|
1760
|
+
return /^text\/plain\b/.exec(contentType);
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
// ../metro-middleware/src/thrower.mjs
|
|
1764
|
+
function throwermw(options) {
|
|
1765
|
+
return async function thrower(req, next) {
|
|
1766
|
+
let res = await next(req);
|
|
1767
|
+
if (!res.ok) {
|
|
1768
|
+
if (options && typeof options[res.status] == "function") {
|
|
1769
|
+
res = options[res.status].apply(res, req);
|
|
1770
|
+
} else {
|
|
1771
|
+
throw new Error(res.status + ": " + res.statusText, {
|
|
1772
|
+
cause: res
|
|
1773
|
+
});
|
|
1774
|
+
}
|
|
1775
|
+
}
|
|
1776
|
+
return res;
|
|
1777
|
+
};
|
|
1778
|
+
}
|
|
1779
|
+
|
|
1662
1780
|
// src/oidc.util.mjs
|
|
1663
1781
|
var MustHave = (...options) => (value, root) => {
|
|
1664
1782
|
if (options.filter((o) => root.hasOwnKey(o)).length > 0) {
|
|
@@ -1685,6 +1803,7 @@
|
|
|
1685
1803
|
"ES512"
|
|
1686
1804
|
];
|
|
1687
1805
|
var validAuthMethods = [
|
|
1806
|
+
"none",
|
|
1688
1807
|
"client_secret_post",
|
|
1689
1808
|
"client_secret_basic",
|
|
1690
1809
|
"client_secret_jwt",
|
|
@@ -1694,14 +1813,15 @@
|
|
|
1694
1813
|
// src/oidc.discovery.mjs
|
|
1695
1814
|
async function oidcDiscovery(options = {}) {
|
|
1696
1815
|
assert(options, {
|
|
1697
|
-
client: Optional(instanceOf(
|
|
1816
|
+
client: Optional(instanceOf(client().constructor)),
|
|
1698
1817
|
issuer: Required(validURL)
|
|
1699
1818
|
});
|
|
1700
1819
|
const defaultOptions = {
|
|
1701
|
-
client:
|
|
1820
|
+
client: client().with(throwermw()).with(jsonmw()),
|
|
1702
1821
|
requireDynamicRegistration: false
|
|
1703
1822
|
};
|
|
1704
1823
|
options = Object.assign({}, defaultOptions, options);
|
|
1824
|
+
options.client = options.client.with(throwermw()).with(jsonmw());
|
|
1705
1825
|
const TestSucceeded = false;
|
|
1706
1826
|
function MustUseHTTPS(url2) {
|
|
1707
1827
|
return TestSucceeded;
|
|
@@ -1744,7 +1864,7 @@
|
|
|
1744
1864
|
op_policy_uri: Optional(validURL),
|
|
1745
1865
|
op_tos_uri: Optional(validURL)
|
|
1746
1866
|
};
|
|
1747
|
-
const configURL =
|
|
1867
|
+
const configURL = url(options.issuer, ".well-known/openid-configuration");
|
|
1748
1868
|
const response2 = await options.client.get(
|
|
1749
1869
|
// https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationRequest
|
|
1750
1870
|
// note: this allows path components in the options.issuer url
|
|
@@ -1792,17 +1912,18 @@
|
|
|
1792
1912
|
request_uris: Optional([validURL])
|
|
1793
1913
|
};
|
|
1794
1914
|
assert(options, {
|
|
1795
|
-
client: Optional(instanceOf(
|
|
1915
|
+
client: Optional(instanceOf(client().constructor)),
|
|
1796
1916
|
registration_endpoint: validURL,
|
|
1797
1917
|
client_info: openid_client_metadata
|
|
1798
1918
|
});
|
|
1799
1919
|
const defaultOptions = {
|
|
1800
|
-
client:
|
|
1920
|
+
client: client().with(throwermw()).with(jsonmw()),
|
|
1801
1921
|
client_info: {
|
|
1802
1922
|
redirect_uris: [globalThis.document?.location.href]
|
|
1803
1923
|
}
|
|
1804
1924
|
};
|
|
1805
1925
|
options = Object.assign({}, defaultOptions, options);
|
|
1926
|
+
options.client = options.client.with(throwermw()).with(jsonmw());
|
|
1806
1927
|
if (!options.client_info) {
|
|
1807
1928
|
options.client_info = {};
|
|
1808
1929
|
}
|
|
@@ -1813,8 +1934,8 @@
|
|
|
1813
1934
|
body: options.client_info
|
|
1814
1935
|
});
|
|
1815
1936
|
let info = response2.data;
|
|
1816
|
-
if (!info.client_id
|
|
1817
|
-
throw
|
|
1937
|
+
if (!info.client_id) {
|
|
1938
|
+
throw metroError("metro.oidc: Error: dynamic registration of client failed, no client_id returned", response2);
|
|
1818
1939
|
}
|
|
1819
1940
|
options.client_info = Object.assign(options.client_info, info);
|
|
1820
1941
|
return options.client_info;
|
|
@@ -1840,36 +1961,1322 @@
|
|
|
1840
1961
|
return store;
|
|
1841
1962
|
}
|
|
1842
1963
|
|
|
1843
|
-
//
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1964
|
+
// ../../node_modules/jose/dist/webapi/lib/buffer_utils.js
|
|
1965
|
+
var encoder2 = new TextEncoder();
|
|
1966
|
+
var decoder2 = new TextDecoder();
|
|
1967
|
+
var MAX_INT32 = 2 ** 32;
|
|
1968
|
+
function concat(...buffers) {
|
|
1969
|
+
const size = buffers.reduce((acc, { length }) => acc + length, 0);
|
|
1970
|
+
const buf2 = new Uint8Array(size);
|
|
1971
|
+
let i = 0;
|
|
1972
|
+
for (const buffer of buffers) {
|
|
1973
|
+
buf2.set(buffer, i);
|
|
1974
|
+
i += buffer.length;
|
|
1975
|
+
}
|
|
1976
|
+
return buf2;
|
|
1977
|
+
}
|
|
1978
|
+
function encode(string) {
|
|
1979
|
+
const bytes = new Uint8Array(string.length);
|
|
1980
|
+
for (let i = 0; i < string.length; i++) {
|
|
1981
|
+
const code = string.charCodeAt(i);
|
|
1982
|
+
if (code > 127) {
|
|
1983
|
+
throw new TypeError("non-ASCII string encountered in encode()");
|
|
1984
|
+
}
|
|
1985
|
+
bytes[i] = code;
|
|
1986
|
+
}
|
|
1987
|
+
return bytes;
|
|
1988
|
+
}
|
|
1989
|
+
|
|
1990
|
+
// ../../node_modules/jose/dist/webapi/lib/base64.js
|
|
1991
|
+
function decodeBase64(encoded) {
|
|
1992
|
+
if (Uint8Array.fromBase64) {
|
|
1993
|
+
return Uint8Array.fromBase64(encoded);
|
|
1867
1994
|
}
|
|
1868
|
-
|
|
1869
|
-
|
|
1995
|
+
const binary = atob(encoded);
|
|
1996
|
+
const bytes = new Uint8Array(binary.length);
|
|
1997
|
+
for (let i = 0; i < binary.length; i++) {
|
|
1998
|
+
bytes[i] = binary.charCodeAt(i);
|
|
1870
1999
|
}
|
|
1871
|
-
|
|
1872
|
-
|
|
2000
|
+
return bytes;
|
|
2001
|
+
}
|
|
2002
|
+
|
|
2003
|
+
// ../../node_modules/jose/dist/webapi/util/base64url.js
|
|
2004
|
+
function decode(input) {
|
|
2005
|
+
if (Uint8Array.fromBase64) {
|
|
2006
|
+
return Uint8Array.fromBase64(typeof input === "string" ? input : decoder2.decode(input), {
|
|
2007
|
+
alphabet: "base64url"
|
|
2008
|
+
});
|
|
2009
|
+
}
|
|
2010
|
+
let encoded = input;
|
|
2011
|
+
if (encoded instanceof Uint8Array) {
|
|
2012
|
+
encoded = decoder2.decode(encoded);
|
|
2013
|
+
}
|
|
2014
|
+
encoded = encoded.replace(/-/g, "+").replace(/_/g, "/");
|
|
2015
|
+
try {
|
|
2016
|
+
return decodeBase64(encoded);
|
|
2017
|
+
} catch {
|
|
2018
|
+
throw new TypeError("The input to be decoded is not correctly encoded.");
|
|
2019
|
+
}
|
|
2020
|
+
}
|
|
2021
|
+
|
|
2022
|
+
// ../../node_modules/jose/dist/webapi/lib/crypto_key.js
|
|
2023
|
+
var unusable = (name, prop = "algorithm.name") => new TypeError(`CryptoKey does not support this operation, its ${prop} must be ${name}`);
|
|
2024
|
+
var isAlgorithm = (algorithm, name) => algorithm.name === name;
|
|
2025
|
+
function getHashLength(hash) {
|
|
2026
|
+
return parseInt(hash.name.slice(4), 10);
|
|
2027
|
+
}
|
|
2028
|
+
function checkHashLength(algorithm, expected) {
|
|
2029
|
+
const actual = getHashLength(algorithm.hash);
|
|
2030
|
+
if (actual !== expected)
|
|
2031
|
+
throw unusable(`SHA-${expected}`, "algorithm.hash");
|
|
2032
|
+
}
|
|
2033
|
+
function getNamedCurve(alg) {
|
|
2034
|
+
switch (alg) {
|
|
2035
|
+
case "ES256":
|
|
2036
|
+
return "P-256";
|
|
2037
|
+
case "ES384":
|
|
2038
|
+
return "P-384";
|
|
2039
|
+
case "ES512":
|
|
2040
|
+
return "P-521";
|
|
2041
|
+
default:
|
|
2042
|
+
throw new Error("unreachable");
|
|
2043
|
+
}
|
|
2044
|
+
}
|
|
2045
|
+
function checkUsage(key, usage) {
|
|
2046
|
+
if (usage && !key.usages.includes(usage)) {
|
|
2047
|
+
throw new TypeError(`CryptoKey does not support this operation, its usages must include ${usage}.`);
|
|
2048
|
+
}
|
|
2049
|
+
}
|
|
2050
|
+
function checkSigCryptoKey(key, alg, usage) {
|
|
2051
|
+
switch (alg) {
|
|
2052
|
+
case "HS256":
|
|
2053
|
+
case "HS384":
|
|
2054
|
+
case "HS512": {
|
|
2055
|
+
if (!isAlgorithm(key.algorithm, "HMAC"))
|
|
2056
|
+
throw unusable("HMAC");
|
|
2057
|
+
checkHashLength(key.algorithm, parseInt(alg.slice(2), 10));
|
|
2058
|
+
break;
|
|
2059
|
+
}
|
|
2060
|
+
case "RS256":
|
|
2061
|
+
case "RS384":
|
|
2062
|
+
case "RS512": {
|
|
2063
|
+
if (!isAlgorithm(key.algorithm, "RSASSA-PKCS1-v1_5"))
|
|
2064
|
+
throw unusable("RSASSA-PKCS1-v1_5");
|
|
2065
|
+
checkHashLength(key.algorithm, parseInt(alg.slice(2), 10));
|
|
2066
|
+
break;
|
|
2067
|
+
}
|
|
2068
|
+
case "PS256":
|
|
2069
|
+
case "PS384":
|
|
2070
|
+
case "PS512": {
|
|
2071
|
+
if (!isAlgorithm(key.algorithm, "RSA-PSS"))
|
|
2072
|
+
throw unusable("RSA-PSS");
|
|
2073
|
+
checkHashLength(key.algorithm, parseInt(alg.slice(2), 10));
|
|
2074
|
+
break;
|
|
2075
|
+
}
|
|
2076
|
+
case "Ed25519":
|
|
2077
|
+
case "EdDSA": {
|
|
2078
|
+
if (!isAlgorithm(key.algorithm, "Ed25519"))
|
|
2079
|
+
throw unusable("Ed25519");
|
|
2080
|
+
break;
|
|
2081
|
+
}
|
|
2082
|
+
case "ML-DSA-44":
|
|
2083
|
+
case "ML-DSA-65":
|
|
2084
|
+
case "ML-DSA-87": {
|
|
2085
|
+
if (!isAlgorithm(key.algorithm, alg))
|
|
2086
|
+
throw unusable(alg);
|
|
2087
|
+
break;
|
|
2088
|
+
}
|
|
2089
|
+
case "ES256":
|
|
2090
|
+
case "ES384":
|
|
2091
|
+
case "ES512": {
|
|
2092
|
+
if (!isAlgorithm(key.algorithm, "ECDSA"))
|
|
2093
|
+
throw unusable("ECDSA");
|
|
2094
|
+
const expected = getNamedCurve(alg);
|
|
2095
|
+
const actual = key.algorithm.namedCurve;
|
|
2096
|
+
if (actual !== expected)
|
|
2097
|
+
throw unusable(expected, "algorithm.namedCurve");
|
|
2098
|
+
break;
|
|
2099
|
+
}
|
|
2100
|
+
default:
|
|
2101
|
+
throw new TypeError("CryptoKey does not support this operation");
|
|
2102
|
+
}
|
|
2103
|
+
checkUsage(key, usage);
|
|
2104
|
+
}
|
|
2105
|
+
|
|
2106
|
+
// ../../node_modules/jose/dist/webapi/lib/invalid_key_input.js
|
|
2107
|
+
function message(msg, actual, ...types) {
|
|
2108
|
+
types = types.filter(Boolean);
|
|
2109
|
+
if (types.length > 2) {
|
|
2110
|
+
const last = types.pop();
|
|
2111
|
+
msg += `one of type ${types.join(", ")}, or ${last}.`;
|
|
2112
|
+
} else if (types.length === 2) {
|
|
2113
|
+
msg += `one of type ${types[0]} or ${types[1]}.`;
|
|
2114
|
+
} else {
|
|
2115
|
+
msg += `of type ${types[0]}.`;
|
|
2116
|
+
}
|
|
2117
|
+
if (actual == null) {
|
|
2118
|
+
msg += ` Received ${actual}`;
|
|
2119
|
+
} else if (typeof actual === "function" && actual.name) {
|
|
2120
|
+
msg += ` Received function ${actual.name}`;
|
|
2121
|
+
} else if (typeof actual === "object" && actual != null) {
|
|
2122
|
+
if (actual.constructor?.name) {
|
|
2123
|
+
msg += ` Received an instance of ${actual.constructor.name}`;
|
|
2124
|
+
}
|
|
2125
|
+
}
|
|
2126
|
+
return msg;
|
|
2127
|
+
}
|
|
2128
|
+
var invalidKeyInput = (actual, ...types) => message("Key must be ", actual, ...types);
|
|
2129
|
+
var withAlg = (alg, actual, ...types) => message(`Key for the ${alg} algorithm must be `, actual, ...types);
|
|
2130
|
+
|
|
2131
|
+
// ../../node_modules/jose/dist/webapi/util/errors.js
|
|
2132
|
+
var JOSEError = class extends Error {
|
|
2133
|
+
static code = "ERR_JOSE_GENERIC";
|
|
2134
|
+
code = "ERR_JOSE_GENERIC";
|
|
2135
|
+
constructor(message2, options) {
|
|
2136
|
+
super(message2, options);
|
|
2137
|
+
this.name = this.constructor.name;
|
|
2138
|
+
Error.captureStackTrace?.(this, this.constructor);
|
|
2139
|
+
}
|
|
2140
|
+
};
|
|
2141
|
+
var JWTClaimValidationFailed = class extends JOSEError {
|
|
2142
|
+
static code = "ERR_JWT_CLAIM_VALIDATION_FAILED";
|
|
2143
|
+
code = "ERR_JWT_CLAIM_VALIDATION_FAILED";
|
|
2144
|
+
claim;
|
|
2145
|
+
reason;
|
|
2146
|
+
payload;
|
|
2147
|
+
constructor(message2, payload, claim = "unspecified", reason = "unspecified") {
|
|
2148
|
+
super(message2, { cause: { claim, reason, payload } });
|
|
2149
|
+
this.claim = claim;
|
|
2150
|
+
this.reason = reason;
|
|
2151
|
+
this.payload = payload;
|
|
2152
|
+
}
|
|
2153
|
+
};
|
|
2154
|
+
var JWTExpired = class extends JOSEError {
|
|
2155
|
+
static code = "ERR_JWT_EXPIRED";
|
|
2156
|
+
code = "ERR_JWT_EXPIRED";
|
|
2157
|
+
claim;
|
|
2158
|
+
reason;
|
|
2159
|
+
payload;
|
|
2160
|
+
constructor(message2, payload, claim = "unspecified", reason = "unspecified") {
|
|
2161
|
+
super(message2, { cause: { claim, reason, payload } });
|
|
2162
|
+
this.claim = claim;
|
|
2163
|
+
this.reason = reason;
|
|
2164
|
+
this.payload = payload;
|
|
2165
|
+
}
|
|
2166
|
+
};
|
|
2167
|
+
var JOSEAlgNotAllowed = class extends JOSEError {
|
|
2168
|
+
static code = "ERR_JOSE_ALG_NOT_ALLOWED";
|
|
2169
|
+
code = "ERR_JOSE_ALG_NOT_ALLOWED";
|
|
2170
|
+
};
|
|
2171
|
+
var JOSENotSupported = class extends JOSEError {
|
|
2172
|
+
static code = "ERR_JOSE_NOT_SUPPORTED";
|
|
2173
|
+
code = "ERR_JOSE_NOT_SUPPORTED";
|
|
2174
|
+
};
|
|
2175
|
+
var JWSInvalid = class extends JOSEError {
|
|
2176
|
+
static code = "ERR_JWS_INVALID";
|
|
2177
|
+
code = "ERR_JWS_INVALID";
|
|
2178
|
+
};
|
|
2179
|
+
var JWTInvalid = class extends JOSEError {
|
|
2180
|
+
static code = "ERR_JWT_INVALID";
|
|
2181
|
+
code = "ERR_JWT_INVALID";
|
|
2182
|
+
};
|
|
2183
|
+
var JWKSInvalid = class extends JOSEError {
|
|
2184
|
+
static code = "ERR_JWKS_INVALID";
|
|
2185
|
+
code = "ERR_JWKS_INVALID";
|
|
2186
|
+
};
|
|
2187
|
+
var JWKSNoMatchingKey = class extends JOSEError {
|
|
2188
|
+
static code = "ERR_JWKS_NO_MATCHING_KEY";
|
|
2189
|
+
code = "ERR_JWKS_NO_MATCHING_KEY";
|
|
2190
|
+
constructor(message2 = "no applicable key found in the JSON Web Key Set", options) {
|
|
2191
|
+
super(message2, options);
|
|
2192
|
+
}
|
|
2193
|
+
};
|
|
2194
|
+
var JWKSMultipleMatchingKeys = class extends JOSEError {
|
|
2195
|
+
[Symbol.asyncIterator];
|
|
2196
|
+
static code = "ERR_JWKS_MULTIPLE_MATCHING_KEYS";
|
|
2197
|
+
code = "ERR_JWKS_MULTIPLE_MATCHING_KEYS";
|
|
2198
|
+
constructor(message2 = "multiple matching keys found in the JSON Web Key Set", options) {
|
|
2199
|
+
super(message2, options);
|
|
2200
|
+
}
|
|
2201
|
+
};
|
|
2202
|
+
var JWSSignatureVerificationFailed = class extends JOSEError {
|
|
2203
|
+
static code = "ERR_JWS_SIGNATURE_VERIFICATION_FAILED";
|
|
2204
|
+
code = "ERR_JWS_SIGNATURE_VERIFICATION_FAILED";
|
|
2205
|
+
constructor(message2 = "signature verification failed", options) {
|
|
2206
|
+
super(message2, options);
|
|
2207
|
+
}
|
|
2208
|
+
};
|
|
2209
|
+
|
|
2210
|
+
// ../../node_modules/jose/dist/webapi/lib/is_key_like.js
|
|
2211
|
+
var isCryptoKey2 = (key) => {
|
|
2212
|
+
if (key?.[Symbol.toStringTag] === "CryptoKey")
|
|
2213
|
+
return true;
|
|
2214
|
+
try {
|
|
2215
|
+
return key instanceof CryptoKey;
|
|
2216
|
+
} catch {
|
|
2217
|
+
return false;
|
|
2218
|
+
}
|
|
2219
|
+
};
|
|
2220
|
+
var isKeyObject = (key) => key?.[Symbol.toStringTag] === "KeyObject";
|
|
2221
|
+
var isKeyLike = (key) => isCryptoKey2(key) || isKeyObject(key);
|
|
2222
|
+
|
|
2223
|
+
// ../../node_modules/jose/dist/webapi/lib/helpers.js
|
|
2224
|
+
function decodeBase64url(value, label, ErrorClass) {
|
|
2225
|
+
try {
|
|
2226
|
+
return decode(value);
|
|
2227
|
+
} catch {
|
|
2228
|
+
throw new ErrorClass(`Failed to base64url decode the ${label}`);
|
|
2229
|
+
}
|
|
2230
|
+
}
|
|
2231
|
+
|
|
2232
|
+
// ../../node_modules/jose/dist/webapi/lib/type_checks.js
|
|
2233
|
+
var isObjectLike = (value) => typeof value === "object" && value !== null;
|
|
2234
|
+
function isObject(input) {
|
|
2235
|
+
if (!isObjectLike(input) || Object.prototype.toString.call(input) !== "[object Object]") {
|
|
2236
|
+
return false;
|
|
2237
|
+
}
|
|
2238
|
+
if (Object.getPrototypeOf(input) === null) {
|
|
2239
|
+
return true;
|
|
2240
|
+
}
|
|
2241
|
+
let proto = input;
|
|
2242
|
+
while (Object.getPrototypeOf(proto) !== null) {
|
|
2243
|
+
proto = Object.getPrototypeOf(proto);
|
|
2244
|
+
}
|
|
2245
|
+
return Object.getPrototypeOf(input) === proto;
|
|
2246
|
+
}
|
|
2247
|
+
function isDisjoint(...headers) {
|
|
2248
|
+
const sources = headers.filter(Boolean);
|
|
2249
|
+
if (sources.length === 0 || sources.length === 1) {
|
|
2250
|
+
return true;
|
|
2251
|
+
}
|
|
2252
|
+
let acc;
|
|
2253
|
+
for (const header of sources) {
|
|
2254
|
+
const parameters = Object.keys(header);
|
|
2255
|
+
if (!acc || acc.size === 0) {
|
|
2256
|
+
acc = new Set(parameters);
|
|
2257
|
+
continue;
|
|
2258
|
+
}
|
|
2259
|
+
for (const parameter of parameters) {
|
|
2260
|
+
if (acc.has(parameter)) {
|
|
2261
|
+
return false;
|
|
2262
|
+
}
|
|
2263
|
+
acc.add(parameter);
|
|
2264
|
+
}
|
|
2265
|
+
}
|
|
2266
|
+
return true;
|
|
2267
|
+
}
|
|
2268
|
+
var isJWK = (key) => isObject(key) && typeof key.kty === "string";
|
|
2269
|
+
var isPrivateJWK = (key) => key.kty !== "oct" && (key.kty === "AKP" && typeof key.priv === "string" || typeof key.d === "string");
|
|
2270
|
+
var isPublicJWK = (key) => key.kty !== "oct" && key.d === void 0 && key.priv === void 0;
|
|
2271
|
+
var isSecretJWK = (key) => key.kty === "oct" && typeof key.k === "string";
|
|
2272
|
+
|
|
2273
|
+
// ../../node_modules/jose/dist/webapi/lib/signing.js
|
|
2274
|
+
function checkKeyLength(alg, key) {
|
|
2275
|
+
if (alg.startsWith("RS") || alg.startsWith("PS")) {
|
|
2276
|
+
const { modulusLength } = key.algorithm;
|
|
2277
|
+
if (typeof modulusLength !== "number" || modulusLength < 2048) {
|
|
2278
|
+
throw new TypeError(`${alg} requires key modulusLength to be 2048 bits or larger`);
|
|
2279
|
+
}
|
|
2280
|
+
}
|
|
2281
|
+
}
|
|
2282
|
+
function subtleAlgorithm2(alg, algorithm) {
|
|
2283
|
+
const hash = `SHA-${alg.slice(-3)}`;
|
|
2284
|
+
switch (alg) {
|
|
2285
|
+
case "HS256":
|
|
2286
|
+
case "HS384":
|
|
2287
|
+
case "HS512":
|
|
2288
|
+
return { hash, name: "HMAC" };
|
|
2289
|
+
case "PS256":
|
|
2290
|
+
case "PS384":
|
|
2291
|
+
case "PS512":
|
|
2292
|
+
return { hash, name: "RSA-PSS", saltLength: parseInt(alg.slice(-3), 10) >> 3 };
|
|
2293
|
+
case "RS256":
|
|
2294
|
+
case "RS384":
|
|
2295
|
+
case "RS512":
|
|
2296
|
+
return { hash, name: "RSASSA-PKCS1-v1_5" };
|
|
2297
|
+
case "ES256":
|
|
2298
|
+
case "ES384":
|
|
2299
|
+
case "ES512":
|
|
2300
|
+
return { hash, name: "ECDSA", namedCurve: algorithm.namedCurve };
|
|
2301
|
+
case "Ed25519":
|
|
2302
|
+
case "EdDSA":
|
|
2303
|
+
return { name: "Ed25519" };
|
|
2304
|
+
case "ML-DSA-44":
|
|
2305
|
+
case "ML-DSA-65":
|
|
2306
|
+
case "ML-DSA-87":
|
|
2307
|
+
return { name: alg };
|
|
2308
|
+
default:
|
|
2309
|
+
throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`);
|
|
2310
|
+
}
|
|
2311
|
+
}
|
|
2312
|
+
async function getSigKey(alg, key, usage) {
|
|
2313
|
+
if (key instanceof Uint8Array) {
|
|
2314
|
+
if (!alg.startsWith("HS")) {
|
|
2315
|
+
throw new TypeError(invalidKeyInput(key, "CryptoKey", "KeyObject", "JSON Web Key"));
|
|
2316
|
+
}
|
|
2317
|
+
return crypto.subtle.importKey("raw", key, { hash: `SHA-${alg.slice(-3)}`, name: "HMAC" }, false, [usage]);
|
|
2318
|
+
}
|
|
2319
|
+
checkSigCryptoKey(key, alg, usage);
|
|
2320
|
+
return key;
|
|
2321
|
+
}
|
|
2322
|
+
async function verify(alg, key, signature, data) {
|
|
2323
|
+
const cryptoKey = await getSigKey(alg, key, "verify");
|
|
2324
|
+
checkKeyLength(alg, cryptoKey);
|
|
2325
|
+
const algorithm = subtleAlgorithm2(alg, cryptoKey.algorithm);
|
|
2326
|
+
try {
|
|
2327
|
+
return await crypto.subtle.verify(algorithm, cryptoKey, signature, data);
|
|
2328
|
+
} catch {
|
|
2329
|
+
return false;
|
|
2330
|
+
}
|
|
2331
|
+
}
|
|
2332
|
+
|
|
2333
|
+
// ../../node_modules/jose/dist/webapi/lib/jwk_to_key.js
|
|
2334
|
+
var unsupportedAlg = 'Invalid or unsupported JWK "alg" (Algorithm) Parameter value';
|
|
2335
|
+
function subtleMapping(jwk) {
|
|
2336
|
+
let algorithm;
|
|
2337
|
+
let keyUsages;
|
|
2338
|
+
switch (jwk.kty) {
|
|
2339
|
+
case "AKP": {
|
|
2340
|
+
switch (jwk.alg) {
|
|
2341
|
+
case "ML-DSA-44":
|
|
2342
|
+
case "ML-DSA-65":
|
|
2343
|
+
case "ML-DSA-87":
|
|
2344
|
+
algorithm = { name: jwk.alg };
|
|
2345
|
+
keyUsages = jwk.priv ? ["sign"] : ["verify"];
|
|
2346
|
+
break;
|
|
2347
|
+
default:
|
|
2348
|
+
throw new JOSENotSupported(unsupportedAlg);
|
|
2349
|
+
}
|
|
2350
|
+
break;
|
|
2351
|
+
}
|
|
2352
|
+
case "RSA": {
|
|
2353
|
+
switch (jwk.alg) {
|
|
2354
|
+
case "PS256":
|
|
2355
|
+
case "PS384":
|
|
2356
|
+
case "PS512":
|
|
2357
|
+
algorithm = { name: "RSA-PSS", hash: `SHA-${jwk.alg.slice(-3)}` };
|
|
2358
|
+
keyUsages = jwk.d ? ["sign"] : ["verify"];
|
|
2359
|
+
break;
|
|
2360
|
+
case "RS256":
|
|
2361
|
+
case "RS384":
|
|
2362
|
+
case "RS512":
|
|
2363
|
+
algorithm = { name: "RSASSA-PKCS1-v1_5", hash: `SHA-${jwk.alg.slice(-3)}` };
|
|
2364
|
+
keyUsages = jwk.d ? ["sign"] : ["verify"];
|
|
2365
|
+
break;
|
|
2366
|
+
case "RSA-OAEP":
|
|
2367
|
+
case "RSA-OAEP-256":
|
|
2368
|
+
case "RSA-OAEP-384":
|
|
2369
|
+
case "RSA-OAEP-512":
|
|
2370
|
+
algorithm = {
|
|
2371
|
+
name: "RSA-OAEP",
|
|
2372
|
+
hash: `SHA-${parseInt(jwk.alg.slice(-3), 10) || 1}`
|
|
2373
|
+
};
|
|
2374
|
+
keyUsages = jwk.d ? ["decrypt", "unwrapKey"] : ["encrypt", "wrapKey"];
|
|
2375
|
+
break;
|
|
2376
|
+
default:
|
|
2377
|
+
throw new JOSENotSupported(unsupportedAlg);
|
|
2378
|
+
}
|
|
2379
|
+
break;
|
|
2380
|
+
}
|
|
2381
|
+
case "EC": {
|
|
2382
|
+
switch (jwk.alg) {
|
|
2383
|
+
case "ES256":
|
|
2384
|
+
case "ES384":
|
|
2385
|
+
case "ES512":
|
|
2386
|
+
algorithm = {
|
|
2387
|
+
name: "ECDSA",
|
|
2388
|
+
namedCurve: { ES256: "P-256", ES384: "P-384", ES512: "P-521" }[jwk.alg]
|
|
2389
|
+
};
|
|
2390
|
+
keyUsages = jwk.d ? ["sign"] : ["verify"];
|
|
2391
|
+
break;
|
|
2392
|
+
case "ECDH-ES":
|
|
2393
|
+
case "ECDH-ES+A128KW":
|
|
2394
|
+
case "ECDH-ES+A192KW":
|
|
2395
|
+
case "ECDH-ES+A256KW":
|
|
2396
|
+
algorithm = { name: "ECDH", namedCurve: jwk.crv };
|
|
2397
|
+
keyUsages = jwk.d ? ["deriveBits"] : [];
|
|
2398
|
+
break;
|
|
2399
|
+
default:
|
|
2400
|
+
throw new JOSENotSupported(unsupportedAlg);
|
|
2401
|
+
}
|
|
2402
|
+
break;
|
|
2403
|
+
}
|
|
2404
|
+
case "OKP": {
|
|
2405
|
+
switch (jwk.alg) {
|
|
2406
|
+
case "Ed25519":
|
|
2407
|
+
case "EdDSA":
|
|
2408
|
+
algorithm = { name: "Ed25519" };
|
|
2409
|
+
keyUsages = jwk.d ? ["sign"] : ["verify"];
|
|
2410
|
+
break;
|
|
2411
|
+
case "ECDH-ES":
|
|
2412
|
+
case "ECDH-ES+A128KW":
|
|
2413
|
+
case "ECDH-ES+A192KW":
|
|
2414
|
+
case "ECDH-ES+A256KW":
|
|
2415
|
+
algorithm = { name: jwk.crv };
|
|
2416
|
+
keyUsages = jwk.d ? ["deriveBits"] : [];
|
|
2417
|
+
break;
|
|
2418
|
+
default:
|
|
2419
|
+
throw new JOSENotSupported(unsupportedAlg);
|
|
2420
|
+
}
|
|
2421
|
+
break;
|
|
2422
|
+
}
|
|
2423
|
+
default:
|
|
2424
|
+
throw new JOSENotSupported('Invalid or unsupported JWK "kty" (Key Type) Parameter value');
|
|
2425
|
+
}
|
|
2426
|
+
return { algorithm, keyUsages };
|
|
2427
|
+
}
|
|
2428
|
+
async function jwkToKey(jwk) {
|
|
2429
|
+
if (!jwk.alg) {
|
|
2430
|
+
throw new TypeError('"alg" argument is required when "jwk.alg" is not present');
|
|
2431
|
+
}
|
|
2432
|
+
const { algorithm, keyUsages } = subtleMapping(jwk);
|
|
2433
|
+
const keyData = { ...jwk };
|
|
2434
|
+
if (keyData.kty !== "AKP") {
|
|
2435
|
+
delete keyData.alg;
|
|
2436
|
+
}
|
|
2437
|
+
delete keyData.use;
|
|
2438
|
+
return crypto.subtle.importKey("jwk", keyData, algorithm, jwk.ext ?? (jwk.d || jwk.priv ? false : true), jwk.key_ops ?? keyUsages);
|
|
2439
|
+
}
|
|
2440
|
+
|
|
2441
|
+
// ../../node_modules/jose/dist/webapi/lib/normalize_key.js
|
|
2442
|
+
var unusableForAlg = "given KeyObject instance cannot be used for this algorithm";
|
|
2443
|
+
var cache;
|
|
2444
|
+
var handleJWK = async (key, jwk, alg, freeze = false) => {
|
|
2445
|
+
cache ||= /* @__PURE__ */ new WeakMap();
|
|
2446
|
+
let cached = cache.get(key);
|
|
2447
|
+
if (cached?.[alg]) {
|
|
2448
|
+
return cached[alg];
|
|
2449
|
+
}
|
|
2450
|
+
const cryptoKey = await jwkToKey({ ...jwk, alg });
|
|
2451
|
+
if (freeze)
|
|
2452
|
+
Object.freeze(key);
|
|
2453
|
+
if (!cached) {
|
|
2454
|
+
cache.set(key, { [alg]: cryptoKey });
|
|
2455
|
+
} else {
|
|
2456
|
+
cached[alg] = cryptoKey;
|
|
2457
|
+
}
|
|
2458
|
+
return cryptoKey;
|
|
2459
|
+
};
|
|
2460
|
+
var handleKeyObject = (keyObject, alg) => {
|
|
2461
|
+
cache ||= /* @__PURE__ */ new WeakMap();
|
|
2462
|
+
let cached = cache.get(keyObject);
|
|
2463
|
+
if (cached?.[alg]) {
|
|
2464
|
+
return cached[alg];
|
|
2465
|
+
}
|
|
2466
|
+
const isPublic = keyObject.type === "public";
|
|
2467
|
+
const extractable = isPublic ? true : false;
|
|
2468
|
+
let cryptoKey;
|
|
2469
|
+
if (keyObject.asymmetricKeyType === "x25519") {
|
|
2470
|
+
switch (alg) {
|
|
2471
|
+
case "ECDH-ES":
|
|
2472
|
+
case "ECDH-ES+A128KW":
|
|
2473
|
+
case "ECDH-ES+A192KW":
|
|
2474
|
+
case "ECDH-ES+A256KW":
|
|
2475
|
+
break;
|
|
2476
|
+
default:
|
|
2477
|
+
throw new TypeError(unusableForAlg);
|
|
2478
|
+
}
|
|
2479
|
+
cryptoKey = keyObject.toCryptoKey(keyObject.asymmetricKeyType, extractable, isPublic ? [] : ["deriveBits"]);
|
|
2480
|
+
}
|
|
2481
|
+
if (keyObject.asymmetricKeyType === "ed25519") {
|
|
2482
|
+
if (alg !== "EdDSA" && alg !== "Ed25519") {
|
|
2483
|
+
throw new TypeError(unusableForAlg);
|
|
2484
|
+
}
|
|
2485
|
+
cryptoKey = keyObject.toCryptoKey(keyObject.asymmetricKeyType, extractable, [
|
|
2486
|
+
isPublic ? "verify" : "sign"
|
|
2487
|
+
]);
|
|
2488
|
+
}
|
|
2489
|
+
switch (keyObject.asymmetricKeyType) {
|
|
2490
|
+
case "ml-dsa-44":
|
|
2491
|
+
case "ml-dsa-65":
|
|
2492
|
+
case "ml-dsa-87": {
|
|
2493
|
+
if (alg !== keyObject.asymmetricKeyType.toUpperCase()) {
|
|
2494
|
+
throw new TypeError(unusableForAlg);
|
|
2495
|
+
}
|
|
2496
|
+
cryptoKey = keyObject.toCryptoKey(keyObject.asymmetricKeyType, extractable, [
|
|
2497
|
+
isPublic ? "verify" : "sign"
|
|
2498
|
+
]);
|
|
2499
|
+
}
|
|
2500
|
+
}
|
|
2501
|
+
if (keyObject.asymmetricKeyType === "rsa") {
|
|
2502
|
+
let hash;
|
|
2503
|
+
switch (alg) {
|
|
2504
|
+
case "RSA-OAEP":
|
|
2505
|
+
hash = "SHA-1";
|
|
2506
|
+
break;
|
|
2507
|
+
case "RS256":
|
|
2508
|
+
case "PS256":
|
|
2509
|
+
case "RSA-OAEP-256":
|
|
2510
|
+
hash = "SHA-256";
|
|
2511
|
+
break;
|
|
2512
|
+
case "RS384":
|
|
2513
|
+
case "PS384":
|
|
2514
|
+
case "RSA-OAEP-384":
|
|
2515
|
+
hash = "SHA-384";
|
|
2516
|
+
break;
|
|
2517
|
+
case "RS512":
|
|
2518
|
+
case "PS512":
|
|
2519
|
+
case "RSA-OAEP-512":
|
|
2520
|
+
hash = "SHA-512";
|
|
2521
|
+
break;
|
|
2522
|
+
default:
|
|
2523
|
+
throw new TypeError(unusableForAlg);
|
|
2524
|
+
}
|
|
2525
|
+
if (alg.startsWith("RSA-OAEP")) {
|
|
2526
|
+
return keyObject.toCryptoKey({
|
|
2527
|
+
name: "RSA-OAEP",
|
|
2528
|
+
hash
|
|
2529
|
+
}, extractable, isPublic ? ["encrypt"] : ["decrypt"]);
|
|
2530
|
+
}
|
|
2531
|
+
cryptoKey = keyObject.toCryptoKey({
|
|
2532
|
+
name: alg.startsWith("PS") ? "RSA-PSS" : "RSASSA-PKCS1-v1_5",
|
|
2533
|
+
hash
|
|
2534
|
+
}, extractable, [isPublic ? "verify" : "sign"]);
|
|
2535
|
+
}
|
|
2536
|
+
if (keyObject.asymmetricKeyType === "ec") {
|
|
2537
|
+
const nist = /* @__PURE__ */ new Map([
|
|
2538
|
+
["prime256v1", "P-256"],
|
|
2539
|
+
["secp384r1", "P-384"],
|
|
2540
|
+
["secp521r1", "P-521"]
|
|
2541
|
+
]);
|
|
2542
|
+
const namedCurve = nist.get(keyObject.asymmetricKeyDetails?.namedCurve);
|
|
2543
|
+
if (!namedCurve) {
|
|
2544
|
+
throw new TypeError(unusableForAlg);
|
|
2545
|
+
}
|
|
2546
|
+
const expectedCurve = { ES256: "P-256", ES384: "P-384", ES512: "P-521" };
|
|
2547
|
+
if (expectedCurve[alg] && namedCurve === expectedCurve[alg]) {
|
|
2548
|
+
cryptoKey = keyObject.toCryptoKey({
|
|
2549
|
+
name: "ECDSA",
|
|
2550
|
+
namedCurve
|
|
2551
|
+
}, extractable, [isPublic ? "verify" : "sign"]);
|
|
2552
|
+
}
|
|
2553
|
+
if (alg.startsWith("ECDH-ES")) {
|
|
2554
|
+
cryptoKey = keyObject.toCryptoKey({
|
|
2555
|
+
name: "ECDH",
|
|
2556
|
+
namedCurve
|
|
2557
|
+
}, extractable, isPublic ? [] : ["deriveBits"]);
|
|
2558
|
+
}
|
|
2559
|
+
}
|
|
2560
|
+
if (!cryptoKey) {
|
|
2561
|
+
throw new TypeError(unusableForAlg);
|
|
2562
|
+
}
|
|
2563
|
+
if (!cached) {
|
|
2564
|
+
cache.set(keyObject, { [alg]: cryptoKey });
|
|
2565
|
+
} else {
|
|
2566
|
+
cached[alg] = cryptoKey;
|
|
2567
|
+
}
|
|
2568
|
+
return cryptoKey;
|
|
2569
|
+
};
|
|
2570
|
+
async function normalizeKey(key, alg) {
|
|
2571
|
+
if (key instanceof Uint8Array) {
|
|
2572
|
+
return key;
|
|
2573
|
+
}
|
|
2574
|
+
if (isCryptoKey2(key)) {
|
|
2575
|
+
return key;
|
|
2576
|
+
}
|
|
2577
|
+
if (isKeyObject(key)) {
|
|
2578
|
+
if (key.type === "secret") {
|
|
2579
|
+
return key.export();
|
|
2580
|
+
}
|
|
2581
|
+
if ("toCryptoKey" in key && typeof key.toCryptoKey === "function") {
|
|
2582
|
+
try {
|
|
2583
|
+
return handleKeyObject(key, alg);
|
|
2584
|
+
} catch (err) {
|
|
2585
|
+
if (err instanceof TypeError) {
|
|
2586
|
+
throw err;
|
|
2587
|
+
}
|
|
2588
|
+
}
|
|
2589
|
+
}
|
|
2590
|
+
let jwk = key.export({ format: "jwk" });
|
|
2591
|
+
return handleJWK(key, jwk, alg);
|
|
2592
|
+
}
|
|
2593
|
+
if (isJWK(key)) {
|
|
2594
|
+
if (key.k) {
|
|
2595
|
+
return decode(key.k);
|
|
2596
|
+
}
|
|
2597
|
+
return handleJWK(key, key, alg, true);
|
|
2598
|
+
}
|
|
2599
|
+
throw new Error("unreachable");
|
|
2600
|
+
}
|
|
2601
|
+
|
|
2602
|
+
// ../../node_modules/jose/dist/webapi/key/import.js
|
|
2603
|
+
async function importJWK(jwk, alg, options) {
|
|
2604
|
+
if (!isObject(jwk)) {
|
|
2605
|
+
throw new TypeError("JWK must be an object");
|
|
2606
|
+
}
|
|
2607
|
+
let ext;
|
|
2608
|
+
alg ??= jwk.alg;
|
|
2609
|
+
ext ??= options?.extractable ?? jwk.ext;
|
|
2610
|
+
switch (jwk.kty) {
|
|
2611
|
+
case "oct":
|
|
2612
|
+
if (typeof jwk.k !== "string" || !jwk.k) {
|
|
2613
|
+
throw new TypeError('missing "k" (Key Value) Parameter value');
|
|
2614
|
+
}
|
|
2615
|
+
return decode(jwk.k);
|
|
2616
|
+
case "RSA":
|
|
2617
|
+
if ("oth" in jwk && jwk.oth !== void 0) {
|
|
2618
|
+
throw new JOSENotSupported('RSA JWK "oth" (Other Primes Info) Parameter value is not supported');
|
|
2619
|
+
}
|
|
2620
|
+
return jwkToKey({ ...jwk, alg, ext });
|
|
2621
|
+
case "AKP": {
|
|
2622
|
+
if (typeof jwk.alg !== "string" || !jwk.alg) {
|
|
2623
|
+
throw new TypeError('missing "alg" (Algorithm) Parameter value');
|
|
2624
|
+
}
|
|
2625
|
+
if (alg !== void 0 && alg !== jwk.alg) {
|
|
2626
|
+
throw new TypeError("JWK alg and alg option value mismatch");
|
|
2627
|
+
}
|
|
2628
|
+
return jwkToKey({ ...jwk, ext });
|
|
2629
|
+
}
|
|
2630
|
+
case "EC":
|
|
2631
|
+
case "OKP":
|
|
2632
|
+
return jwkToKey({ ...jwk, alg, ext });
|
|
2633
|
+
default:
|
|
2634
|
+
throw new JOSENotSupported('Unsupported "kty" (Key Type) Parameter value');
|
|
2635
|
+
}
|
|
2636
|
+
}
|
|
2637
|
+
|
|
2638
|
+
// ../../node_modules/jose/dist/webapi/lib/validate_crit.js
|
|
2639
|
+
function validateCrit(Err, recognizedDefault, recognizedOption, protectedHeader, joseHeader) {
|
|
2640
|
+
if (joseHeader.crit !== void 0 && protectedHeader?.crit === void 0) {
|
|
2641
|
+
throw new Err('"crit" (Critical) Header Parameter MUST be integrity protected');
|
|
2642
|
+
}
|
|
2643
|
+
if (!protectedHeader || protectedHeader.crit === void 0) {
|
|
2644
|
+
return /* @__PURE__ */ new Set();
|
|
2645
|
+
}
|
|
2646
|
+
if (!Array.isArray(protectedHeader.crit) || protectedHeader.crit.length === 0 || protectedHeader.crit.some((input) => typeof input !== "string" || input.length === 0)) {
|
|
2647
|
+
throw new Err('"crit" (Critical) Header Parameter MUST be an array of non-empty strings when present');
|
|
2648
|
+
}
|
|
2649
|
+
let recognized;
|
|
2650
|
+
if (recognizedOption !== void 0) {
|
|
2651
|
+
recognized = new Map([...Object.entries(recognizedOption), ...recognizedDefault.entries()]);
|
|
2652
|
+
} else {
|
|
2653
|
+
recognized = recognizedDefault;
|
|
2654
|
+
}
|
|
2655
|
+
for (const parameter of protectedHeader.crit) {
|
|
2656
|
+
if (!recognized.has(parameter)) {
|
|
2657
|
+
throw new JOSENotSupported(`Extension Header Parameter "${parameter}" is not recognized`);
|
|
2658
|
+
}
|
|
2659
|
+
if (joseHeader[parameter] === void 0) {
|
|
2660
|
+
throw new Err(`Extension Header Parameter "${parameter}" is missing`);
|
|
2661
|
+
}
|
|
2662
|
+
if (recognized.get(parameter) && protectedHeader[parameter] === void 0) {
|
|
2663
|
+
throw new Err(`Extension Header Parameter "${parameter}" MUST be integrity protected`);
|
|
2664
|
+
}
|
|
2665
|
+
}
|
|
2666
|
+
return new Set(protectedHeader.crit);
|
|
2667
|
+
}
|
|
2668
|
+
|
|
2669
|
+
// ../../node_modules/jose/dist/webapi/lib/validate_algorithms.js
|
|
2670
|
+
function validateAlgorithms(option, algorithms) {
|
|
2671
|
+
if (algorithms !== void 0 && (!Array.isArray(algorithms) || algorithms.some((s) => typeof s !== "string"))) {
|
|
2672
|
+
throw new TypeError(`"${option}" option must be an array of strings`);
|
|
2673
|
+
}
|
|
2674
|
+
if (!algorithms) {
|
|
2675
|
+
return void 0;
|
|
2676
|
+
}
|
|
2677
|
+
return new Set(algorithms);
|
|
2678
|
+
}
|
|
2679
|
+
|
|
2680
|
+
// ../../node_modules/jose/dist/webapi/lib/check_key_type.js
|
|
2681
|
+
var tag = (key) => key?.[Symbol.toStringTag];
|
|
2682
|
+
var jwkMatchesOp = (alg, key, usage) => {
|
|
2683
|
+
if (key.use !== void 0) {
|
|
2684
|
+
let expected;
|
|
2685
|
+
switch (usage) {
|
|
2686
|
+
case "sign":
|
|
2687
|
+
case "verify":
|
|
2688
|
+
expected = "sig";
|
|
2689
|
+
break;
|
|
2690
|
+
case "encrypt":
|
|
2691
|
+
case "decrypt":
|
|
2692
|
+
expected = "enc";
|
|
2693
|
+
break;
|
|
2694
|
+
}
|
|
2695
|
+
if (key.use !== expected) {
|
|
2696
|
+
throw new TypeError(`Invalid key for this operation, its "use" must be "${expected}" when present`);
|
|
2697
|
+
}
|
|
2698
|
+
}
|
|
2699
|
+
if (key.alg !== void 0 && key.alg !== alg) {
|
|
2700
|
+
throw new TypeError(`Invalid key for this operation, its "alg" must be "${alg}" when present`);
|
|
2701
|
+
}
|
|
2702
|
+
if (Array.isArray(key.key_ops)) {
|
|
2703
|
+
let expectedKeyOp;
|
|
2704
|
+
switch (true) {
|
|
2705
|
+
case (usage === "sign" || usage === "verify"):
|
|
2706
|
+
case alg === "dir":
|
|
2707
|
+
case alg.includes("CBC-HS"):
|
|
2708
|
+
expectedKeyOp = usage;
|
|
2709
|
+
break;
|
|
2710
|
+
case alg.startsWith("PBES2"):
|
|
2711
|
+
expectedKeyOp = "deriveBits";
|
|
2712
|
+
break;
|
|
2713
|
+
case /^A\d{3}(?:GCM)?(?:KW)?$/.test(alg):
|
|
2714
|
+
if (!alg.includes("GCM") && alg.endsWith("KW")) {
|
|
2715
|
+
expectedKeyOp = usage === "encrypt" ? "wrapKey" : "unwrapKey";
|
|
2716
|
+
} else {
|
|
2717
|
+
expectedKeyOp = usage;
|
|
2718
|
+
}
|
|
2719
|
+
break;
|
|
2720
|
+
case (usage === "encrypt" && alg.startsWith("RSA")):
|
|
2721
|
+
expectedKeyOp = "wrapKey";
|
|
2722
|
+
break;
|
|
2723
|
+
case usage === "decrypt":
|
|
2724
|
+
expectedKeyOp = alg.startsWith("RSA") ? "unwrapKey" : "deriveBits";
|
|
2725
|
+
break;
|
|
2726
|
+
}
|
|
2727
|
+
if (expectedKeyOp && key.key_ops?.includes?.(expectedKeyOp) === false) {
|
|
2728
|
+
throw new TypeError(`Invalid key for this operation, its "key_ops" must include "${expectedKeyOp}" when present`);
|
|
2729
|
+
}
|
|
2730
|
+
}
|
|
2731
|
+
return true;
|
|
2732
|
+
};
|
|
2733
|
+
var symmetricTypeCheck = (alg, key, usage) => {
|
|
2734
|
+
if (key instanceof Uint8Array)
|
|
2735
|
+
return;
|
|
2736
|
+
if (isJWK(key)) {
|
|
2737
|
+
if (isSecretJWK(key) && jwkMatchesOp(alg, key, usage))
|
|
2738
|
+
return;
|
|
2739
|
+
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`);
|
|
2740
|
+
}
|
|
2741
|
+
if (!isKeyLike(key)) {
|
|
2742
|
+
throw new TypeError(withAlg(alg, key, "CryptoKey", "KeyObject", "JSON Web Key", "Uint8Array"));
|
|
2743
|
+
}
|
|
2744
|
+
if (key.type !== "secret") {
|
|
2745
|
+
throw new TypeError(`${tag(key)} instances for symmetric algorithms must be of type "secret"`);
|
|
2746
|
+
}
|
|
2747
|
+
};
|
|
2748
|
+
var asymmetricTypeCheck = (alg, key, usage) => {
|
|
2749
|
+
if (isJWK(key)) {
|
|
2750
|
+
switch (usage) {
|
|
2751
|
+
case "decrypt":
|
|
2752
|
+
case "sign":
|
|
2753
|
+
if (isPrivateJWK(key) && jwkMatchesOp(alg, key, usage))
|
|
2754
|
+
return;
|
|
2755
|
+
throw new TypeError(`JSON Web Key for this operation must be a private JWK`);
|
|
2756
|
+
case "encrypt":
|
|
2757
|
+
case "verify":
|
|
2758
|
+
if (isPublicJWK(key) && jwkMatchesOp(alg, key, usage))
|
|
2759
|
+
return;
|
|
2760
|
+
throw new TypeError(`JSON Web Key for this operation must be a public JWK`);
|
|
2761
|
+
}
|
|
2762
|
+
}
|
|
2763
|
+
if (!isKeyLike(key)) {
|
|
2764
|
+
throw new TypeError(withAlg(alg, key, "CryptoKey", "KeyObject", "JSON Web Key"));
|
|
2765
|
+
}
|
|
2766
|
+
if (key.type === "secret") {
|
|
2767
|
+
throw new TypeError(`${tag(key)} instances for asymmetric algorithms must not be of type "secret"`);
|
|
2768
|
+
}
|
|
2769
|
+
if (key.type === "public") {
|
|
2770
|
+
switch (usage) {
|
|
2771
|
+
case "sign":
|
|
2772
|
+
throw new TypeError(`${tag(key)} instances for asymmetric algorithm signing must be of type "private"`);
|
|
2773
|
+
case "decrypt":
|
|
2774
|
+
throw new TypeError(`${tag(key)} instances for asymmetric algorithm decryption must be of type "private"`);
|
|
2775
|
+
}
|
|
2776
|
+
}
|
|
2777
|
+
if (key.type === "private") {
|
|
2778
|
+
switch (usage) {
|
|
2779
|
+
case "verify":
|
|
2780
|
+
throw new TypeError(`${tag(key)} instances for asymmetric algorithm verifying must be of type "public"`);
|
|
2781
|
+
case "encrypt":
|
|
2782
|
+
throw new TypeError(`${tag(key)} instances for asymmetric algorithm encryption must be of type "public"`);
|
|
2783
|
+
}
|
|
2784
|
+
}
|
|
2785
|
+
};
|
|
2786
|
+
function checkKeyType(alg, key, usage) {
|
|
2787
|
+
switch (alg.substring(0, 2)) {
|
|
2788
|
+
case "A1":
|
|
2789
|
+
case "A2":
|
|
2790
|
+
case "di":
|
|
2791
|
+
case "HS":
|
|
2792
|
+
case "PB":
|
|
2793
|
+
symmetricTypeCheck(alg, key, usage);
|
|
2794
|
+
break;
|
|
2795
|
+
default:
|
|
2796
|
+
asymmetricTypeCheck(alg, key, usage);
|
|
2797
|
+
}
|
|
2798
|
+
}
|
|
2799
|
+
|
|
2800
|
+
// ../../node_modules/jose/dist/webapi/jws/flattened/verify.js
|
|
2801
|
+
async function flattenedVerify(jws, key, options) {
|
|
2802
|
+
if (!isObject(jws)) {
|
|
2803
|
+
throw new JWSInvalid("Flattened JWS must be an object");
|
|
2804
|
+
}
|
|
2805
|
+
if (jws.protected === void 0 && jws.header === void 0) {
|
|
2806
|
+
throw new JWSInvalid('Flattened JWS must have either of the "protected" or "header" members');
|
|
2807
|
+
}
|
|
2808
|
+
if (jws.protected !== void 0 && typeof jws.protected !== "string") {
|
|
2809
|
+
throw new JWSInvalid("JWS Protected Header incorrect type");
|
|
2810
|
+
}
|
|
2811
|
+
if (jws.payload === void 0) {
|
|
2812
|
+
throw new JWSInvalid("JWS Payload missing");
|
|
2813
|
+
}
|
|
2814
|
+
if (typeof jws.signature !== "string") {
|
|
2815
|
+
throw new JWSInvalid("JWS Signature missing or incorrect type");
|
|
2816
|
+
}
|
|
2817
|
+
if (jws.header !== void 0 && !isObject(jws.header)) {
|
|
2818
|
+
throw new JWSInvalid("JWS Unprotected Header incorrect type");
|
|
2819
|
+
}
|
|
2820
|
+
let parsedProt = {};
|
|
2821
|
+
if (jws.protected) {
|
|
2822
|
+
try {
|
|
2823
|
+
const protectedHeader = decode(jws.protected);
|
|
2824
|
+
parsedProt = JSON.parse(decoder2.decode(protectedHeader));
|
|
2825
|
+
} catch {
|
|
2826
|
+
throw new JWSInvalid("JWS Protected Header is invalid");
|
|
2827
|
+
}
|
|
2828
|
+
}
|
|
2829
|
+
if (!isDisjoint(parsedProt, jws.header)) {
|
|
2830
|
+
throw new JWSInvalid("JWS Protected and JWS Unprotected Header Parameter names must be disjoint");
|
|
2831
|
+
}
|
|
2832
|
+
const joseHeader = {
|
|
2833
|
+
...parsedProt,
|
|
2834
|
+
...jws.header
|
|
2835
|
+
};
|
|
2836
|
+
const extensions = validateCrit(JWSInvalid, /* @__PURE__ */ new Map([["b64", true]]), options?.crit, parsedProt, joseHeader);
|
|
2837
|
+
let b64 = true;
|
|
2838
|
+
if (extensions.has("b64")) {
|
|
2839
|
+
b64 = parsedProt.b64;
|
|
2840
|
+
if (typeof b64 !== "boolean") {
|
|
2841
|
+
throw new JWSInvalid('The "b64" (base64url-encode payload) Header Parameter must be a boolean');
|
|
2842
|
+
}
|
|
2843
|
+
}
|
|
2844
|
+
const { alg } = joseHeader;
|
|
2845
|
+
if (typeof alg !== "string" || !alg) {
|
|
2846
|
+
throw new JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid');
|
|
2847
|
+
}
|
|
2848
|
+
const algorithms = options && validateAlgorithms("algorithms", options.algorithms);
|
|
2849
|
+
if (algorithms && !algorithms.has(alg)) {
|
|
2850
|
+
throw new JOSEAlgNotAllowed('"alg" (Algorithm) Header Parameter value not allowed');
|
|
2851
|
+
}
|
|
2852
|
+
if (b64) {
|
|
2853
|
+
if (typeof jws.payload !== "string") {
|
|
2854
|
+
throw new JWSInvalid("JWS Payload must be a string");
|
|
2855
|
+
}
|
|
2856
|
+
} else if (typeof jws.payload !== "string" && !(jws.payload instanceof Uint8Array)) {
|
|
2857
|
+
throw new JWSInvalid("JWS Payload must be a string or an Uint8Array instance");
|
|
2858
|
+
}
|
|
2859
|
+
let resolvedKey = false;
|
|
2860
|
+
if (typeof key === "function") {
|
|
2861
|
+
key = await key(parsedProt, jws);
|
|
2862
|
+
resolvedKey = true;
|
|
2863
|
+
}
|
|
2864
|
+
checkKeyType(alg, key, "verify");
|
|
2865
|
+
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);
|
|
2866
|
+
const signature = decodeBase64url(jws.signature, "signature", JWSInvalid);
|
|
2867
|
+
const k = await normalizeKey(key, alg);
|
|
2868
|
+
const verified = await verify(alg, k, signature, data);
|
|
2869
|
+
if (!verified) {
|
|
2870
|
+
throw new JWSSignatureVerificationFailed();
|
|
2871
|
+
}
|
|
2872
|
+
let payload;
|
|
2873
|
+
if (b64) {
|
|
2874
|
+
payload = decodeBase64url(jws.payload, "payload", JWSInvalid);
|
|
2875
|
+
} else if (typeof jws.payload === "string") {
|
|
2876
|
+
payload = encoder2.encode(jws.payload);
|
|
2877
|
+
} else {
|
|
2878
|
+
payload = jws.payload;
|
|
2879
|
+
}
|
|
2880
|
+
const result = { payload };
|
|
2881
|
+
if (jws.protected !== void 0) {
|
|
2882
|
+
result.protectedHeader = parsedProt;
|
|
2883
|
+
}
|
|
2884
|
+
if (jws.header !== void 0) {
|
|
2885
|
+
result.unprotectedHeader = jws.header;
|
|
2886
|
+
}
|
|
2887
|
+
if (resolvedKey) {
|
|
2888
|
+
return { ...result, key: k };
|
|
2889
|
+
}
|
|
2890
|
+
return result;
|
|
2891
|
+
}
|
|
2892
|
+
|
|
2893
|
+
// ../../node_modules/jose/dist/webapi/jws/compact/verify.js
|
|
2894
|
+
async function compactVerify(jws, key, options) {
|
|
2895
|
+
if (jws instanceof Uint8Array) {
|
|
2896
|
+
jws = decoder2.decode(jws);
|
|
2897
|
+
}
|
|
2898
|
+
if (typeof jws !== "string") {
|
|
2899
|
+
throw new JWSInvalid("Compact JWS must be a string or Uint8Array");
|
|
2900
|
+
}
|
|
2901
|
+
const { 0: protectedHeader, 1: payload, 2: signature, length } = jws.split(".");
|
|
2902
|
+
if (length !== 3) {
|
|
2903
|
+
throw new JWSInvalid("Invalid Compact JWS");
|
|
2904
|
+
}
|
|
2905
|
+
const verified = await flattenedVerify({ payload, protected: protectedHeader, signature }, key, options);
|
|
2906
|
+
const result = { payload: verified.payload, protectedHeader: verified.protectedHeader };
|
|
2907
|
+
if (typeof key === "function") {
|
|
2908
|
+
return { ...result, key: verified.key };
|
|
2909
|
+
}
|
|
2910
|
+
return result;
|
|
2911
|
+
}
|
|
2912
|
+
|
|
2913
|
+
// ../../node_modules/jose/dist/webapi/lib/jwt_claims_set.js
|
|
2914
|
+
var epoch = (date) => Math.floor(date.getTime() / 1e3);
|
|
2915
|
+
var minute = 60;
|
|
2916
|
+
var hour = minute * 60;
|
|
2917
|
+
var day = hour * 24;
|
|
2918
|
+
var week = day * 7;
|
|
2919
|
+
var year = day * 365.25;
|
|
2920
|
+
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;
|
|
2921
|
+
function secs(str) {
|
|
2922
|
+
const matched = REGEX.exec(str);
|
|
2923
|
+
if (!matched || matched[4] && matched[1]) {
|
|
2924
|
+
throw new TypeError("Invalid time period format");
|
|
2925
|
+
}
|
|
2926
|
+
const value = parseFloat(matched[2]);
|
|
2927
|
+
const unit = matched[3].toLowerCase();
|
|
2928
|
+
let numericDate;
|
|
2929
|
+
switch (unit) {
|
|
2930
|
+
case "sec":
|
|
2931
|
+
case "secs":
|
|
2932
|
+
case "second":
|
|
2933
|
+
case "seconds":
|
|
2934
|
+
case "s":
|
|
2935
|
+
numericDate = Math.round(value);
|
|
2936
|
+
break;
|
|
2937
|
+
case "minute":
|
|
2938
|
+
case "minutes":
|
|
2939
|
+
case "min":
|
|
2940
|
+
case "mins":
|
|
2941
|
+
case "m":
|
|
2942
|
+
numericDate = Math.round(value * minute);
|
|
2943
|
+
break;
|
|
2944
|
+
case "hour":
|
|
2945
|
+
case "hours":
|
|
2946
|
+
case "hr":
|
|
2947
|
+
case "hrs":
|
|
2948
|
+
case "h":
|
|
2949
|
+
numericDate = Math.round(value * hour);
|
|
2950
|
+
break;
|
|
2951
|
+
case "day":
|
|
2952
|
+
case "days":
|
|
2953
|
+
case "d":
|
|
2954
|
+
numericDate = Math.round(value * day);
|
|
2955
|
+
break;
|
|
2956
|
+
case "week":
|
|
2957
|
+
case "weeks":
|
|
2958
|
+
case "w":
|
|
2959
|
+
numericDate = Math.round(value * week);
|
|
2960
|
+
break;
|
|
2961
|
+
default:
|
|
2962
|
+
numericDate = Math.round(value * year);
|
|
2963
|
+
break;
|
|
2964
|
+
}
|
|
2965
|
+
if (matched[1] === "-" || matched[4] === "ago") {
|
|
2966
|
+
return -numericDate;
|
|
2967
|
+
}
|
|
2968
|
+
return numericDate;
|
|
2969
|
+
}
|
|
2970
|
+
var normalizeTyp = (value) => {
|
|
2971
|
+
if (value.includes("/")) {
|
|
2972
|
+
return value.toLowerCase();
|
|
2973
|
+
}
|
|
2974
|
+
return `application/${value.toLowerCase()}`;
|
|
2975
|
+
};
|
|
2976
|
+
var checkAudiencePresence = (audPayload, audOption) => {
|
|
2977
|
+
if (typeof audPayload === "string") {
|
|
2978
|
+
return audOption.includes(audPayload);
|
|
2979
|
+
}
|
|
2980
|
+
if (Array.isArray(audPayload)) {
|
|
2981
|
+
return audOption.some(Set.prototype.has.bind(new Set(audPayload)));
|
|
2982
|
+
}
|
|
2983
|
+
return false;
|
|
2984
|
+
};
|
|
2985
|
+
function validateClaimsSet(protectedHeader, encodedPayload, options = {}) {
|
|
2986
|
+
let payload;
|
|
2987
|
+
try {
|
|
2988
|
+
payload = JSON.parse(decoder2.decode(encodedPayload));
|
|
2989
|
+
} catch {
|
|
2990
|
+
}
|
|
2991
|
+
if (!isObject(payload)) {
|
|
2992
|
+
throw new JWTInvalid("JWT Claims Set must be a top-level JSON object");
|
|
2993
|
+
}
|
|
2994
|
+
const { typ } = options;
|
|
2995
|
+
if (typ && (typeof protectedHeader.typ !== "string" || normalizeTyp(protectedHeader.typ) !== normalizeTyp(typ))) {
|
|
2996
|
+
throw new JWTClaimValidationFailed('unexpected "typ" JWT header value', payload, "typ", "check_failed");
|
|
2997
|
+
}
|
|
2998
|
+
const { requiredClaims = [], issuer, subject, audience, maxTokenAge } = options;
|
|
2999
|
+
const presenceCheck = [...requiredClaims];
|
|
3000
|
+
if (maxTokenAge !== void 0)
|
|
3001
|
+
presenceCheck.push("iat");
|
|
3002
|
+
if (audience !== void 0)
|
|
3003
|
+
presenceCheck.push("aud");
|
|
3004
|
+
if (subject !== void 0)
|
|
3005
|
+
presenceCheck.push("sub");
|
|
3006
|
+
if (issuer !== void 0)
|
|
3007
|
+
presenceCheck.push("iss");
|
|
3008
|
+
for (const claim of new Set(presenceCheck.reverse())) {
|
|
3009
|
+
if (!(claim in payload)) {
|
|
3010
|
+
throw new JWTClaimValidationFailed(`missing required "${claim}" claim`, payload, claim, "missing");
|
|
3011
|
+
}
|
|
3012
|
+
}
|
|
3013
|
+
if (issuer && !(Array.isArray(issuer) ? issuer : [issuer]).includes(payload.iss)) {
|
|
3014
|
+
throw new JWTClaimValidationFailed('unexpected "iss" claim value', payload, "iss", "check_failed");
|
|
3015
|
+
}
|
|
3016
|
+
if (subject && payload.sub !== subject) {
|
|
3017
|
+
throw new JWTClaimValidationFailed('unexpected "sub" claim value', payload, "sub", "check_failed");
|
|
3018
|
+
}
|
|
3019
|
+
if (audience && !checkAudiencePresence(payload.aud, typeof audience === "string" ? [audience] : audience)) {
|
|
3020
|
+
throw new JWTClaimValidationFailed('unexpected "aud" claim value', payload, "aud", "check_failed");
|
|
3021
|
+
}
|
|
3022
|
+
let tolerance;
|
|
3023
|
+
switch (typeof options.clockTolerance) {
|
|
3024
|
+
case "string":
|
|
3025
|
+
tolerance = secs(options.clockTolerance);
|
|
3026
|
+
break;
|
|
3027
|
+
case "number":
|
|
3028
|
+
tolerance = options.clockTolerance;
|
|
3029
|
+
break;
|
|
3030
|
+
case "undefined":
|
|
3031
|
+
tolerance = 0;
|
|
3032
|
+
break;
|
|
3033
|
+
default:
|
|
3034
|
+
throw new TypeError("Invalid clockTolerance option type");
|
|
3035
|
+
}
|
|
3036
|
+
const { currentDate } = options;
|
|
3037
|
+
const now = epoch(currentDate || /* @__PURE__ */ new Date());
|
|
3038
|
+
if ((payload.iat !== void 0 || maxTokenAge) && typeof payload.iat !== "number") {
|
|
3039
|
+
throw new JWTClaimValidationFailed('"iat" claim must be a number', payload, "iat", "invalid");
|
|
3040
|
+
}
|
|
3041
|
+
if (payload.nbf !== void 0) {
|
|
3042
|
+
if (typeof payload.nbf !== "number") {
|
|
3043
|
+
throw new JWTClaimValidationFailed('"nbf" claim must be a number', payload, "nbf", "invalid");
|
|
3044
|
+
}
|
|
3045
|
+
if (payload.nbf > now + tolerance) {
|
|
3046
|
+
throw new JWTClaimValidationFailed('"nbf" claim timestamp check failed', payload, "nbf", "check_failed");
|
|
3047
|
+
}
|
|
3048
|
+
}
|
|
3049
|
+
if (payload.exp !== void 0) {
|
|
3050
|
+
if (typeof payload.exp !== "number") {
|
|
3051
|
+
throw new JWTClaimValidationFailed('"exp" claim must be a number', payload, "exp", "invalid");
|
|
3052
|
+
}
|
|
3053
|
+
if (payload.exp <= now - tolerance) {
|
|
3054
|
+
throw new JWTExpired('"exp" claim timestamp check failed', payload, "exp", "check_failed");
|
|
3055
|
+
}
|
|
3056
|
+
}
|
|
3057
|
+
if (maxTokenAge) {
|
|
3058
|
+
const age = now - payload.iat;
|
|
3059
|
+
const max = typeof maxTokenAge === "number" ? maxTokenAge : secs(maxTokenAge);
|
|
3060
|
+
if (age - tolerance > max) {
|
|
3061
|
+
throw new JWTExpired('"iat" claim timestamp check failed (too far in the past)', payload, "iat", "check_failed");
|
|
3062
|
+
}
|
|
3063
|
+
if (age < 0 - tolerance) {
|
|
3064
|
+
throw new JWTClaimValidationFailed('"iat" claim timestamp check failed (it should be in the past)', payload, "iat", "check_failed");
|
|
3065
|
+
}
|
|
3066
|
+
}
|
|
3067
|
+
return payload;
|
|
3068
|
+
}
|
|
3069
|
+
|
|
3070
|
+
// ../../node_modules/jose/dist/webapi/jwt/verify.js
|
|
3071
|
+
async function jwtVerify(jwt2, key, options) {
|
|
3072
|
+
const verified = await compactVerify(jwt2, key, options);
|
|
3073
|
+
if (verified.protectedHeader.crit?.includes("b64") && verified.protectedHeader.b64 === false) {
|
|
3074
|
+
throw new JWTInvalid("JWTs MUST NOT use unencoded payload");
|
|
3075
|
+
}
|
|
3076
|
+
const payload = validateClaimsSet(verified.protectedHeader, verified.payload, options);
|
|
3077
|
+
const result = { payload, protectedHeader: verified.protectedHeader };
|
|
3078
|
+
if (typeof key === "function") {
|
|
3079
|
+
return { ...result, key: verified.key };
|
|
3080
|
+
}
|
|
3081
|
+
return result;
|
|
3082
|
+
}
|
|
3083
|
+
|
|
3084
|
+
// ../../node_modules/jose/dist/webapi/jwks/local.js
|
|
3085
|
+
function getKtyFromAlg(alg) {
|
|
3086
|
+
switch (typeof alg === "string" && alg.slice(0, 2)) {
|
|
3087
|
+
case "RS":
|
|
3088
|
+
case "PS":
|
|
3089
|
+
return "RSA";
|
|
3090
|
+
case "ES":
|
|
3091
|
+
return "EC";
|
|
3092
|
+
case "Ed":
|
|
3093
|
+
return "OKP";
|
|
3094
|
+
case "ML":
|
|
3095
|
+
return "AKP";
|
|
3096
|
+
default:
|
|
3097
|
+
throw new JOSENotSupported('Unsupported "alg" value for a JSON Web Key Set');
|
|
3098
|
+
}
|
|
3099
|
+
}
|
|
3100
|
+
function isJWKSLike(jwks) {
|
|
3101
|
+
return jwks && typeof jwks === "object" && Array.isArray(jwks.keys) && jwks.keys.every(isJWKLike);
|
|
3102
|
+
}
|
|
3103
|
+
function isJWKLike(key) {
|
|
3104
|
+
return isObject(key);
|
|
3105
|
+
}
|
|
3106
|
+
var LocalJWKSet = class {
|
|
3107
|
+
#jwks;
|
|
3108
|
+
#cached = /* @__PURE__ */ new WeakMap();
|
|
3109
|
+
constructor(jwks) {
|
|
3110
|
+
if (!isJWKSLike(jwks)) {
|
|
3111
|
+
throw new JWKSInvalid("JSON Web Key Set malformed");
|
|
3112
|
+
}
|
|
3113
|
+
this.#jwks = structuredClone(jwks);
|
|
3114
|
+
}
|
|
3115
|
+
jwks() {
|
|
3116
|
+
return this.#jwks;
|
|
3117
|
+
}
|
|
3118
|
+
async getKey(protectedHeader, token) {
|
|
3119
|
+
const { alg, kid } = { ...protectedHeader, ...token?.header };
|
|
3120
|
+
const kty = getKtyFromAlg(alg);
|
|
3121
|
+
const candidates = this.#jwks.keys.filter((jwk2) => {
|
|
3122
|
+
let candidate = kty === jwk2.kty;
|
|
3123
|
+
if (candidate && typeof kid === "string") {
|
|
3124
|
+
candidate = kid === jwk2.kid;
|
|
3125
|
+
}
|
|
3126
|
+
if (candidate && (typeof jwk2.alg === "string" || kty === "AKP")) {
|
|
3127
|
+
candidate = alg === jwk2.alg;
|
|
3128
|
+
}
|
|
3129
|
+
if (candidate && typeof jwk2.use === "string") {
|
|
3130
|
+
candidate = jwk2.use === "sig";
|
|
3131
|
+
}
|
|
3132
|
+
if (candidate && Array.isArray(jwk2.key_ops)) {
|
|
3133
|
+
candidate = jwk2.key_ops.includes("verify");
|
|
3134
|
+
}
|
|
3135
|
+
if (candidate) {
|
|
3136
|
+
switch (alg) {
|
|
3137
|
+
case "ES256":
|
|
3138
|
+
candidate = jwk2.crv === "P-256";
|
|
3139
|
+
break;
|
|
3140
|
+
case "ES384":
|
|
3141
|
+
candidate = jwk2.crv === "P-384";
|
|
3142
|
+
break;
|
|
3143
|
+
case "ES512":
|
|
3144
|
+
candidate = jwk2.crv === "P-521";
|
|
3145
|
+
break;
|
|
3146
|
+
case "Ed25519":
|
|
3147
|
+
case "EdDSA":
|
|
3148
|
+
candidate = jwk2.crv === "Ed25519";
|
|
3149
|
+
break;
|
|
3150
|
+
}
|
|
3151
|
+
}
|
|
3152
|
+
return candidate;
|
|
3153
|
+
});
|
|
3154
|
+
const { 0: jwk, length } = candidates;
|
|
3155
|
+
if (length === 0) {
|
|
3156
|
+
throw new JWKSNoMatchingKey();
|
|
3157
|
+
}
|
|
3158
|
+
if (length !== 1) {
|
|
3159
|
+
const error2 = new JWKSMultipleMatchingKeys();
|
|
3160
|
+
const _cached = this.#cached;
|
|
3161
|
+
error2[Symbol.asyncIterator] = async function* () {
|
|
3162
|
+
for (const jwk2 of candidates) {
|
|
3163
|
+
try {
|
|
3164
|
+
yield await importWithAlgCache(_cached, jwk2, alg);
|
|
3165
|
+
} catch {
|
|
3166
|
+
}
|
|
3167
|
+
}
|
|
3168
|
+
};
|
|
3169
|
+
throw error2;
|
|
3170
|
+
}
|
|
3171
|
+
return importWithAlgCache(this.#cached, jwk, alg);
|
|
3172
|
+
}
|
|
3173
|
+
};
|
|
3174
|
+
async function importWithAlgCache(cache2, jwk, alg) {
|
|
3175
|
+
const cached = cache2.get(jwk) || cache2.set(jwk, {}).get(jwk);
|
|
3176
|
+
if (cached[alg] === void 0) {
|
|
3177
|
+
const key = await importJWK({ ...jwk, ext: true }, alg);
|
|
3178
|
+
if (key instanceof Uint8Array || key.type !== "public") {
|
|
3179
|
+
throw new JWKSInvalid("JSON Web Key Set members must be public keys");
|
|
3180
|
+
}
|
|
3181
|
+
cached[alg] = key;
|
|
3182
|
+
}
|
|
3183
|
+
return cached[alg];
|
|
3184
|
+
}
|
|
3185
|
+
function createLocalJWKSet(jwks) {
|
|
3186
|
+
const set = new LocalJWKSet(jwks);
|
|
3187
|
+
const localJWKSet = async (protectedHeader, token) => set.getKey(protectedHeader, token);
|
|
3188
|
+
Object.defineProperties(localJWKSet, {
|
|
3189
|
+
jwks: {
|
|
3190
|
+
value: () => structuredClone(set.jwks()),
|
|
3191
|
+
enumerable: false,
|
|
3192
|
+
configurable: false,
|
|
3193
|
+
writable: false
|
|
3194
|
+
}
|
|
3195
|
+
});
|
|
3196
|
+
return localJWKSet;
|
|
3197
|
+
}
|
|
3198
|
+
|
|
3199
|
+
// src/oidc.jwt.mjs
|
|
3200
|
+
var jwksCache = /* @__PURE__ */ new WeakMap();
|
|
3201
|
+
function keySetFor(jwks) {
|
|
3202
|
+
if (!jwks || !Array.isArray(jwks.keys)) {
|
|
3203
|
+
throw metroError("metro.oidc: Error: jwks must be an object with a keys array");
|
|
3204
|
+
}
|
|
3205
|
+
if (!jwksCache.has(jwks)) {
|
|
3206
|
+
jwksCache.set(jwks, createLocalJWKSet(jwks));
|
|
3207
|
+
}
|
|
3208
|
+
return jwksCache.get(jwks);
|
|
3209
|
+
}
|
|
3210
|
+
function supportedAlgorithms(openidConfiguration = {}) {
|
|
3211
|
+
const algorithms = openidConfiguration.id_token_signing_alg_values_supported;
|
|
3212
|
+
if (Array.isArray(algorithms) && algorithms.length) {
|
|
3213
|
+
return algorithms.filter((algorithm) => algorithm !== "none");
|
|
3214
|
+
}
|
|
3215
|
+
return ["RS256"];
|
|
3216
|
+
}
|
|
3217
|
+
async function validateIdToken(idToken2, options = {}) {
|
|
3218
|
+
if (!idToken2) {
|
|
3219
|
+
throw metroError("metro.oidc: Error: token response did not include an id_token");
|
|
3220
|
+
}
|
|
3221
|
+
if (!options.jwks) {
|
|
3222
|
+
throw metroError("metro.oidc: Error: cannot validate id_token without jwks");
|
|
3223
|
+
}
|
|
3224
|
+
if (!options.issuer) {
|
|
3225
|
+
throw metroError("metro.oidc: Error: cannot validate id_token without issuer");
|
|
3226
|
+
}
|
|
3227
|
+
if (!options.client_id) {
|
|
3228
|
+
throw metroError("metro.oidc: Error: cannot validate id_token without client_id");
|
|
3229
|
+
}
|
|
3230
|
+
const { payload, protectedHeader } = await jwtVerify(
|
|
3231
|
+
idToken2,
|
|
3232
|
+
keySetFor(options.jwks),
|
|
3233
|
+
{
|
|
3234
|
+
issuer: options.issuer,
|
|
3235
|
+
audience: options.client_id,
|
|
3236
|
+
algorithms: options.algorithms || supportedAlgorithms(options.openid_configuration),
|
|
3237
|
+
clockTolerance: options.clockTolerance ?? 60,
|
|
3238
|
+
requiredClaims: ["iss", "sub", "aud", "exp", "iat"]
|
|
3239
|
+
}
|
|
3240
|
+
);
|
|
3241
|
+
if (options.nonce !== void 0 && payload.nonce !== options.nonce) {
|
|
3242
|
+
throw metroError("metro.oidc: Error: id_token nonce mismatch");
|
|
3243
|
+
}
|
|
3244
|
+
return {
|
|
3245
|
+
header: protectedHeader,
|
|
3246
|
+
claims: payload
|
|
3247
|
+
};
|
|
3248
|
+
}
|
|
3249
|
+
|
|
3250
|
+
// src/oidcmw.mjs
|
|
3251
|
+
function oidcmw(options = {}) {
|
|
3252
|
+
const defaultOptions = {
|
|
3253
|
+
client: client(),
|
|
3254
|
+
force_authorization: false,
|
|
3255
|
+
use_dpop: true,
|
|
3256
|
+
authorize_callback: async (url2) => {
|
|
3257
|
+
if (window.location.href != url2.href) {
|
|
3258
|
+
window.location.replace(url2.href);
|
|
3259
|
+
}
|
|
3260
|
+
return false;
|
|
3261
|
+
}
|
|
3262
|
+
};
|
|
3263
|
+
options = Object.assign({}, defaultOptions, options);
|
|
3264
|
+
assert(options, {
|
|
3265
|
+
client: Required(instanceOf(client().constructor)),
|
|
3266
|
+
// required because it is set in defaultOptions
|
|
3267
|
+
client_info: Required(),
|
|
3268
|
+
issuer: Required(validURL),
|
|
3269
|
+
oauth2: Optional({}),
|
|
3270
|
+
openid_configuration: Optional()
|
|
3271
|
+
});
|
|
3272
|
+
if (!options.store) {
|
|
3273
|
+
options.store = oidcStore(options.issuer);
|
|
3274
|
+
}
|
|
3275
|
+
if (!options.openid_configuration && options.store.has("openid_configuration")) {
|
|
3276
|
+
options.openid_configuration = options.store.get("openid_configuration");
|
|
3277
|
+
}
|
|
3278
|
+
if (!options.client_info?.client_id && options.store.has("client_info")) {
|
|
3279
|
+
options.client_info = options.store.get("client_info");
|
|
1873
3280
|
}
|
|
1874
3281
|
return async (req, next) => {
|
|
1875
3282
|
let res;
|
|
@@ -1877,7 +3284,8 @@
|
|
|
1877
3284
|
try {
|
|
1878
3285
|
res = await next(req);
|
|
1879
3286
|
} catch (err) {
|
|
1880
|
-
|
|
3287
|
+
res = err?.cause;
|
|
3288
|
+
if (!res || res.status != 401 && res.status != 403) {
|
|
1881
3289
|
throw err;
|
|
1882
3290
|
}
|
|
1883
3291
|
}
|
|
@@ -1887,7 +3295,8 @@
|
|
|
1887
3295
|
}
|
|
1888
3296
|
if (!options.openid_configuration) {
|
|
1889
3297
|
options.openid_configuration = await oidcDiscovery({
|
|
1890
|
-
issuer: options.issuer
|
|
3298
|
+
issuer: options.issuer,
|
|
3299
|
+
client: options.client.with(options.issuer)
|
|
1891
3300
|
});
|
|
1892
3301
|
options.store.set("openid_configuration", options.openid_configuration);
|
|
1893
3302
|
}
|
|
@@ -1897,11 +3306,14 @@
|
|
|
1897
3306
|
}
|
|
1898
3307
|
options.client_info = await register({
|
|
1899
3308
|
registration_endpoint: options.openid_configuration.registration_endpoint,
|
|
3309
|
+
client: options.client,
|
|
1900
3310
|
client_info: options.client_info
|
|
1901
3311
|
});
|
|
1902
3312
|
options.store.set("client_info", options.client_info);
|
|
1903
3313
|
}
|
|
1904
3314
|
const scope = options.scope || "openid";
|
|
3315
|
+
const nonce = options.nonce || generateCodeVerifier(32);
|
|
3316
|
+
options.store.set("pending_nonce", nonce);
|
|
1905
3317
|
const oauth2Options = Object.assign(
|
|
1906
3318
|
{
|
|
1907
3319
|
site: options.issuer,
|
|
@@ -1918,32 +3330,49 @@
|
|
|
1918
3330
|
token_endpoint: options.openid_configuration.token_endpoint,
|
|
1919
3331
|
scope,
|
|
1920
3332
|
//FIXME: should only use scopes supported by server
|
|
1921
|
-
redirect_uri: options.client_info.redirect_uris[0]
|
|
3333
|
+
redirect_uri: options.client_info.redirect_uris[0],
|
|
3334
|
+
nonce
|
|
1922
3335
|
}
|
|
1923
3336
|
}
|
|
1924
3337
|
//...
|
|
1925
3338
|
);
|
|
1926
3339
|
const storeIdToken = async (req2, next2) => {
|
|
1927
3340
|
const res2 = await next2(req2);
|
|
3341
|
+
const tokenEndpoint = url(options.openid_configuration.token_endpoint, { hash: "" }).href;
|
|
3342
|
+
const requestUrl = url(req2.url, { hash: "" }).href;
|
|
3343
|
+
if (requestUrl !== tokenEndpoint) {
|
|
3344
|
+
return res2;
|
|
3345
|
+
}
|
|
1928
3346
|
const contentType = res2.headers.get("content-type");
|
|
1929
|
-
if (contentType?.startsWith("application/json")) {
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
id_token = data.id_token;
|
|
1937
|
-
}
|
|
1938
|
-
} catch (e) {
|
|
1939
|
-
}
|
|
1940
|
-
}
|
|
1941
|
-
if (id_token) {
|
|
1942
|
-
options.store.set("id_token", id_token);
|
|
1943
|
-
}
|
|
3347
|
+
if (!contentType?.startsWith("application/json")) {
|
|
3348
|
+
return res2;
|
|
3349
|
+
}
|
|
3350
|
+
let data = res2.data && typeof res2.data === "object" ? res2.data : null;
|
|
3351
|
+
if (!data) {
|
|
3352
|
+
const res22 = res2.clone();
|
|
3353
|
+
data = await res22.json();
|
|
1944
3354
|
}
|
|
3355
|
+
const id_token = data?.id_token;
|
|
3356
|
+
const jwks = await getJwks();
|
|
3357
|
+
const validation = await validateIdToken(id_token, {
|
|
3358
|
+
issuer: options.openid_configuration.issuer,
|
|
3359
|
+
client_id: options.client_info.client_id,
|
|
3360
|
+
jwks,
|
|
3361
|
+
openid_configuration: options.openid_configuration,
|
|
3362
|
+
nonce: options.store.get("pending_nonce")
|
|
3363
|
+
});
|
|
3364
|
+
options.store.set("id_token", id_token);
|
|
3365
|
+
options.store.set("id_token_claims", validation.claims);
|
|
1945
3366
|
return res2;
|
|
1946
3367
|
};
|
|
3368
|
+
const getJwks = async () => {
|
|
3369
|
+
if (!options.jwks) {
|
|
3370
|
+
const jwksClient = options.client.with(throwermw()).with(jsonmw());
|
|
3371
|
+
const response2 = await jwksClient.get(options.openid_configuration.jwks_uri);
|
|
3372
|
+
options.jwks = response2.data;
|
|
3373
|
+
}
|
|
3374
|
+
return options.jwks;
|
|
3375
|
+
};
|
|
1947
3376
|
let oauth2client = options.client.with(options.issuer).with(storeIdToken);
|
|
1948
3377
|
if (options.use_dpop) {
|
|
1949
3378
|
const dpopOptions = {
|
|
@@ -1953,8 +3382,8 @@
|
|
|
1953
3382
|
dpop_signing_alg_values_supported: options.openid_configuration.dpop_signing_alg_values_supported
|
|
1954
3383
|
};
|
|
1955
3384
|
oauth2client = oauth2client.with(dpopmw(dpopOptions));
|
|
1956
|
-
oauth2Options.client = oauth2client;
|
|
1957
3385
|
}
|
|
3386
|
+
oauth2Options.client = oauth2client;
|
|
1958
3387
|
oauth2client = oauth2client.with(oauth2mw(oauth2Options));
|
|
1959
3388
|
res = await oauth2client.fetch(req);
|
|
1960
3389
|
return res;
|
|
@@ -1972,18 +3401,33 @@
|
|
|
1972
3401
|
}
|
|
1973
3402
|
return options.store.get("id_token");
|
|
1974
3403
|
}
|
|
3404
|
+
function idTokenClaims(options) {
|
|
3405
|
+
if (!options.store) {
|
|
3406
|
+
if (!options.issuer) {
|
|
3407
|
+
throw metroError("Must supply options.issuer or options.store to get the id_token claims");
|
|
3408
|
+
}
|
|
3409
|
+
options.store = oidcStore(options.issuer);
|
|
3410
|
+
}
|
|
3411
|
+
return options.store.get("id_token_claims");
|
|
3412
|
+
}
|
|
1975
3413
|
|
|
1976
|
-
// src/
|
|
3414
|
+
// src/index.mjs
|
|
1977
3415
|
var oidc = {
|
|
1978
3416
|
oidcmw,
|
|
1979
3417
|
discover: oidcDiscovery,
|
|
1980
3418
|
register,
|
|
1981
3419
|
isRedirected: isRedirected2,
|
|
1982
|
-
idToken
|
|
3420
|
+
idToken,
|
|
3421
|
+
idTokenClaims
|
|
1983
3422
|
};
|
|
1984
|
-
|
|
1985
|
-
|
|
3423
|
+
var index_default = oidc;
|
|
3424
|
+
|
|
3425
|
+
// src/browser.mjs
|
|
3426
|
+
var metro = Object.assign({}, src_exports, globalThis.metro || {});
|
|
3427
|
+
if (!metro.oidc) {
|
|
3428
|
+
metro.oidc = index_default;
|
|
1986
3429
|
}
|
|
1987
|
-
|
|
3430
|
+
globalThis.metro = metro;
|
|
3431
|
+
var browser_default = index_default;
|
|
1988
3432
|
})();
|
|
1989
3433
|
//# sourceMappingURL=browser.js.map
|