@muze-nl/metro-oidc 0.3.0 → 0.3.2
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 +21 -0
- package/README.md +34 -0
- package/dist/browser.js +820 -771
- package/dist/browser.js.map +4 -4
- package/dist/browser.min.js +1 -1
- package/dist/browser.min.js.map +4 -4
- package/package.json +3 -3
- package/src/browser.mjs +10 -3
- package/src/oidcmw.mjs +43 -27
package/dist/browser.js
CHANGED
|
@@ -520,38 +520,52 @@
|
|
|
520
520
|
// node_modules/@muze-nl/metro/src/mw/json.mjs
|
|
521
521
|
function jsonmw(options) {
|
|
522
522
|
options = Object.assign({
|
|
523
|
+
mimetype: "application/json",
|
|
523
524
|
reviver: null,
|
|
524
525
|
replacer: null,
|
|
525
526
|
space: ""
|
|
526
527
|
}, options);
|
|
527
528
|
return async (req, next) => {
|
|
528
|
-
if (
|
|
529
|
+
if (!isJSON(req.headers.get("Accept"))) {
|
|
529
530
|
req = req.with({
|
|
530
531
|
headers: {
|
|
531
|
-
"
|
|
532
|
-
"Accept": "application/json"
|
|
532
|
+
"Accept": options.mimetype
|
|
533
533
|
}
|
|
534
534
|
});
|
|
535
|
+
}
|
|
536
|
+
if (["POST", "PUT", "PATCH", "QUERY"].includes(req.method)) {
|
|
535
537
|
if (req.data && typeof req.data == "object" && !(req.data instanceof ReadableStream)) {
|
|
538
|
+
if (!isJSON(req.headers.get("content-type"))) {
|
|
539
|
+
req = req.with({
|
|
540
|
+
headers: {
|
|
541
|
+
"Content-Type": options.mimetype
|
|
542
|
+
}
|
|
543
|
+
});
|
|
544
|
+
}
|
|
536
545
|
req = req.with({
|
|
537
546
|
body: JSON.stringify(req.data, options.replacer, options.space)
|
|
538
547
|
});
|
|
539
548
|
}
|
|
540
|
-
} else {
|
|
541
|
-
req = req.with({
|
|
542
|
-
headers: {
|
|
543
|
-
"Accept": "application/json"
|
|
544
|
-
}
|
|
545
|
-
});
|
|
546
549
|
}
|
|
547
550
|
let res = await next(req);
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
551
|
+
if (isJSON(res.headers.get("content-type"))) {
|
|
552
|
+
let tempRes = res.clone();
|
|
553
|
+
let body = await tempRes.text();
|
|
554
|
+
try {
|
|
555
|
+
let json = JSON.parse(body, options.reviver);
|
|
556
|
+
return res.with({
|
|
557
|
+
body: json
|
|
558
|
+
});
|
|
559
|
+
} catch (e) {
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
return res;
|
|
553
563
|
};
|
|
554
564
|
}
|
|
565
|
+
var jsonRE = /^application\/([a-zA-Z0-9\-_]+\+)?json\b/;
|
|
566
|
+
function isJSON(contentType) {
|
|
567
|
+
return jsonRE.exec(contentType);
|
|
568
|
+
}
|
|
555
569
|
|
|
556
570
|
// node_modules/@muze-nl/metro/src/mw/thrower.mjs
|
|
557
571
|
function thrower(options) {
|
|
@@ -577,202 +591,139 @@
|
|
|
577
591
|
thrower
|
|
578
592
|
}
|
|
579
593
|
});
|
|
580
|
-
globalThis.metro
|
|
594
|
+
if (!globalThis.metro) {
|
|
595
|
+
globalThis.metro = metro;
|
|
596
|
+
}
|
|
581
597
|
var everything_default = metro;
|
|
582
598
|
|
|
583
|
-
// node_modules/@muze-nl/
|
|
599
|
+
// node_modules/@muze-nl/metro-oauth2/src/oauth2.mjs
|
|
600
|
+
var oauth2_exports = {};
|
|
601
|
+
__export(oauth2_exports, {
|
|
602
|
+
authorizePopup: () => authorizePopup,
|
|
603
|
+
base64url_encode: () => base64url_encode,
|
|
604
|
+
createState: () => createState,
|
|
605
|
+
default: () => oauth2mw,
|
|
606
|
+
generateCodeChallenge: () => generateCodeChallenge,
|
|
607
|
+
generateCodeVerifier: () => generateCodeVerifier,
|
|
608
|
+
getExpires: () => getExpires,
|
|
609
|
+
isExpired: () => isExpired,
|
|
610
|
+
isRedirected: () => isRedirected
|
|
611
|
+
});
|
|
612
|
+
|
|
613
|
+
// node_modules/@muze-nl/metro-oauth2/node_modules/@muze-nl/assert/src/assert.mjs
|
|
584
614
|
globalThis.assertEnabled = false;
|
|
585
|
-
|
|
615
|
+
var assert = (source, test) => {
|
|
586
616
|
if (globalThis.assertEnabled) {
|
|
587
617
|
let problems = fails(source, test);
|
|
588
618
|
if (problems) {
|
|
589
|
-
|
|
590
|
-
throw new Error("Assertions failed", {
|
|
591
|
-
cause: { problems, source }
|
|
592
|
-
});
|
|
619
|
+
throw new assertError("Assertions failed", problems, source);
|
|
593
620
|
}
|
|
594
621
|
}
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
if (data == null || typeof data == "undefined") {
|
|
606
|
-
return error("data is required", data, pattern || "any value", path);
|
|
607
|
-
} else if (typeof pattern != "undefined") {
|
|
608
|
-
return fails(data, pattern, root, path);
|
|
609
|
-
} else {
|
|
610
|
-
return false;
|
|
611
|
-
}
|
|
612
|
-
};
|
|
613
|
-
}
|
|
614
|
-
function Recommended(pattern) {
|
|
615
|
-
return function _Recommended(data, root, path) {
|
|
616
|
-
if (data == null || typeof data == "undefined") {
|
|
617
|
-
console.warn("data does not contain recommended value", data, pattern, path);
|
|
622
|
+
};
|
|
623
|
+
var Optional = (pattern) => (data) => data == null || typeof data == "undefined" ? false : fails(data, pattern);
|
|
624
|
+
var Required = (pattern) => (data) => fails(data, pattern);
|
|
625
|
+
var Recommended = (pattern) => (data) => data == null || typeof data == "undefined" ? (() => {
|
|
626
|
+
console.warning("data does not contain recommended value", data, pattern);
|
|
627
|
+
return false;
|
|
628
|
+
})() : fails(data, pattern);
|
|
629
|
+
var oneOf = (...patterns) => (data) => {
|
|
630
|
+
for (let pattern of patterns) {
|
|
631
|
+
if (!fails(data, pattern)) {
|
|
618
632
|
return false;
|
|
619
|
-
} else {
|
|
620
|
-
return fails(data, pattern, root, path);
|
|
621
|
-
}
|
|
622
|
-
};
|
|
623
|
-
}
|
|
624
|
-
function oneOf(...patterns) {
|
|
625
|
-
return function _oneOf(data, root, path) {
|
|
626
|
-
for (let pattern of patterns) {
|
|
627
|
-
if (!fails(data, pattern, root, path)) {
|
|
628
|
-
return false;
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
return error("data does not match oneOf patterns", data, patterns, path);
|
|
632
|
-
};
|
|
633
|
-
}
|
|
634
|
-
function anyOf(...patterns) {
|
|
635
|
-
return function _anyOf(data, root, path) {
|
|
636
|
-
if (!Array.isArray(data)) {
|
|
637
|
-
return error("data is not an array", data, "anyOf", path);
|
|
638
|
-
}
|
|
639
|
-
for (let value of data) {
|
|
640
|
-
if (oneOf(...patterns)(value)) {
|
|
641
|
-
return error("data does not match anyOf patterns", value, patterns, path);
|
|
642
|
-
}
|
|
643
|
-
}
|
|
644
|
-
return false;
|
|
645
|
-
};
|
|
646
|
-
}
|
|
647
|
-
function allOf(...patterns) {
|
|
648
|
-
return function _allOf(data, root, path) {
|
|
649
|
-
let problems = [];
|
|
650
|
-
for (let pattern of patterns) {
|
|
651
|
-
problems = problems.concat(fails(data, pattern, root, path));
|
|
652
633
|
}
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
634
|
+
}
|
|
635
|
+
return error("data does not match oneOf patterns", data, patterns);
|
|
636
|
+
};
|
|
637
|
+
var anyOf = (...patterns) => (data) => {
|
|
638
|
+
if (!Array.isArray(data)) {
|
|
639
|
+
return error("data is not an array", data, "anyOf");
|
|
640
|
+
}
|
|
641
|
+
for (let value of data) {
|
|
642
|
+
if (oneOf(...patterns)(value)) {
|
|
643
|
+
return error("data does not match anyOf patterns", value, patterns);
|
|
656
644
|
}
|
|
657
|
-
}
|
|
658
|
-
|
|
659
|
-
|
|
645
|
+
}
|
|
646
|
+
return false;
|
|
647
|
+
};
|
|
648
|
+
function validURL(data) {
|
|
660
649
|
try {
|
|
661
650
|
if (data instanceof URL) {
|
|
662
651
|
data = data.href;
|
|
663
652
|
}
|
|
664
653
|
let url2 = new URL(data);
|
|
665
654
|
if (url2.href != data) {
|
|
666
|
-
|
|
667
|
-
return error("data is not a valid url", data, "validURL", path);
|
|
668
|
-
}
|
|
655
|
+
return error("data is not a valid url", data, "validURL");
|
|
669
656
|
}
|
|
670
657
|
} catch (e) {
|
|
671
|
-
return error("data is not a valid url", data, "validURL"
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
|
-
function validEmail(data, root, path) {
|
|
675
|
-
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(data)) {
|
|
676
|
-
return error("data is not a valid email", data, "validEmail", path);
|
|
658
|
+
return error("data is not a valid url", data, "validURL");
|
|
677
659
|
}
|
|
660
|
+
return false;
|
|
678
661
|
}
|
|
679
|
-
function
|
|
680
|
-
return function _instanceOf(data, root, path) {
|
|
681
|
-
if (!(data instanceof constructor)) {
|
|
682
|
-
return error("data is not an instanceof pattern", data, constructor, path);
|
|
683
|
-
}
|
|
684
|
-
};
|
|
685
|
-
}
|
|
686
|
-
function not(pattern) {
|
|
687
|
-
return function _not(data, root, path) {
|
|
688
|
-
if (!fails(data, pattern, root, path)) {
|
|
689
|
-
return error("data matches pattern, when required not to", data, pattern, path);
|
|
690
|
-
}
|
|
691
|
-
};
|
|
692
|
-
}
|
|
693
|
-
function fails(data, pattern, root, path = "") {
|
|
662
|
+
function fails(data, pattern, root) {
|
|
694
663
|
if (!root) {
|
|
695
664
|
root = data;
|
|
696
665
|
}
|
|
697
666
|
let problems = [];
|
|
698
667
|
if (pattern === Boolean) {
|
|
699
|
-
if (typeof data != "boolean"
|
|
700
|
-
problems.push(error("data is not a boolean", data, pattern
|
|
668
|
+
if (typeof data != "boolean") {
|
|
669
|
+
problems.push(error("data is not a boolean", data, pattern));
|
|
701
670
|
}
|
|
702
671
|
} else if (pattern === Number) {
|
|
703
|
-
if (typeof data != "number"
|
|
704
|
-
problems.push(error("data is not a number", data, pattern
|
|
705
|
-
}
|
|
706
|
-
} else if (pattern === String) {
|
|
707
|
-
if (typeof data != "string" && !(data instanceof String)) {
|
|
708
|
-
problems.push(error("data is not a string", data, pattern, path));
|
|
709
|
-
}
|
|
710
|
-
if (data == "") {
|
|
711
|
-
problems.push(error("data is an empty string, which is not allowed", data, pattern, path));
|
|
672
|
+
if (typeof data != "number") {
|
|
673
|
+
problems.push(error("data is not a number", data, pattern));
|
|
712
674
|
}
|
|
713
675
|
} else if (pattern instanceof RegExp) {
|
|
714
676
|
if (Array.isArray(data)) {
|
|
715
|
-
let index = data.findIndex((element
|
|
677
|
+
let index = data.findIndex((element) => fails(element, pattern, root));
|
|
716
678
|
if (index > -1) {
|
|
717
|
-
problems.push(error("data[" + index + "] does not match pattern", data[index], pattern
|
|
679
|
+
problems.push(error("data[" + index + "] does not match pattern", data[index], pattern));
|
|
718
680
|
}
|
|
719
|
-
} else if (typeof data == "undefined") {
|
|
720
|
-
problems.push(error("data is undefined, should match pattern", data, pattern, path));
|
|
721
681
|
} else if (!pattern.test(data)) {
|
|
722
|
-
problems.push(error("data does not match pattern", data, pattern
|
|
682
|
+
problems.push(error("data does not match pattern", data, pattern));
|
|
723
683
|
}
|
|
724
684
|
} else if (pattern instanceof Function) {
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
if (Array.isArray(problem)) {
|
|
728
|
-
problems = problems.concat(problem);
|
|
729
|
-
} else {
|
|
730
|
-
problems.push(problem);
|
|
731
|
-
}
|
|
685
|
+
if (pattern(data, root)) {
|
|
686
|
+
problems.push(error("data does not match function", data, pattern));
|
|
732
687
|
}
|
|
733
688
|
} else if (Array.isArray(pattern)) {
|
|
734
689
|
if (!Array.isArray(data)) {
|
|
735
|
-
problems.push(error("data is not an array", data, []
|
|
690
|
+
problems.push(error("data is not an array", data, []));
|
|
736
691
|
}
|
|
737
|
-
for (
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
problems.push(problem);
|
|
744
|
-
}
|
|
692
|
+
for (p of pattern) {
|
|
693
|
+
let problem = fails(data, p, root);
|
|
694
|
+
if (Array.isArray(problem)) {
|
|
695
|
+
problems.concat(problem);
|
|
696
|
+
} else if (problem) {
|
|
697
|
+
problems.push(problem);
|
|
745
698
|
}
|
|
746
699
|
}
|
|
747
700
|
} else if (pattern && typeof pattern == "object") {
|
|
748
701
|
if (Array.isArray(data)) {
|
|
749
|
-
let index = data.findIndex((element
|
|
702
|
+
let index = data.findIndex((element) => fails(element, pattern, root));
|
|
750
703
|
if (index > -1) {
|
|
751
|
-
problems.push(error("data[" + index + "] does not match pattern", data[index], pattern
|
|
704
|
+
problems.push(error("data[" + index + "] does not match pattern", data[index], pattern));
|
|
752
705
|
}
|
|
753
706
|
} else if (!data || typeof data != "object") {
|
|
754
|
-
problems.push(error("data is not an object, pattern is", data, pattern
|
|
707
|
+
problems.push(error("data is not an object, pattern is", data, pattern));
|
|
755
708
|
} else {
|
|
756
709
|
if (data instanceof URLSearchParams) {
|
|
757
710
|
data = Object.fromEntries(data);
|
|
758
711
|
}
|
|
759
|
-
|
|
760
|
-
|
|
712
|
+
let p2 = problems[problems.length - 1];
|
|
713
|
+
for (const [wKey, wVal] of Object.entries(pattern)) {
|
|
714
|
+
let result = fails(data[wKey], wVal, root);
|
|
761
715
|
if (result) {
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
for (const [wKey, wVal] of Object.entries(pattern)) {
|
|
766
|
-
let result = fails(data[wKey], wVal, root, path + "." + wKey);
|
|
767
|
-
if (result) {
|
|
768
|
-
problems = problems.concat(result);
|
|
716
|
+
if (!p2 || typeof p2 == "string") {
|
|
717
|
+
p2 = {};
|
|
718
|
+
problems.push(error(p2, data[wKey], wVal));
|
|
769
719
|
}
|
|
720
|
+
p2[wKey] = result.problems;
|
|
770
721
|
}
|
|
771
722
|
}
|
|
772
723
|
}
|
|
773
724
|
} else {
|
|
774
725
|
if (pattern != data) {
|
|
775
|
-
problems.push(error("data and pattern are not equal", data, pattern
|
|
726
|
+
problems.push(error("data and pattern are not equal", data, pattern));
|
|
776
727
|
}
|
|
777
728
|
}
|
|
778
729
|
if (problems.length) {
|
|
@@ -780,389 +731,88 @@
|
|
|
780
731
|
}
|
|
781
732
|
return false;
|
|
782
733
|
}
|
|
783
|
-
|
|
784
|
-
|
|
734
|
+
var assertError = class extends Error {
|
|
735
|
+
constructor(message, problems, ...details) {
|
|
736
|
+
super(message);
|
|
737
|
+
this.problems = problems;
|
|
738
|
+
this.details = details;
|
|
739
|
+
}
|
|
740
|
+
};
|
|
741
|
+
function error(message, found, expected) {
|
|
742
|
+
return {
|
|
785
743
|
message,
|
|
786
744
|
found,
|
|
787
|
-
expected
|
|
788
|
-
path
|
|
745
|
+
expected
|
|
789
746
|
};
|
|
790
|
-
if (problems) {
|
|
791
|
-
result.problems = problems;
|
|
792
|
-
}
|
|
793
|
-
return result;
|
|
794
747
|
}
|
|
795
748
|
|
|
796
|
-
// src/
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
749
|
+
// node_modules/@muze-nl/metro-oauth2/src/tokenstore.mjs
|
|
750
|
+
function tokenStore(site) {
|
|
751
|
+
let localState, localTokens;
|
|
752
|
+
if (typeof localStorage !== "undefined") {
|
|
753
|
+
localState = {
|
|
754
|
+
get: () => localStorage.getItem("metro/state:" + site),
|
|
755
|
+
set: (value) => localStorage.setItem("metro/state:" + site, value),
|
|
756
|
+
has: () => localStorage.getItem("metro/state:" + site) !== null
|
|
757
|
+
};
|
|
758
|
+
localTokens = {
|
|
759
|
+
get: (name) => JSON.parse(localStorage.getItem(site + ":" + name)),
|
|
760
|
+
set: (name, value) => localStorage.setItem(site + ":" + name, JSON.stringify(value)),
|
|
761
|
+
has: (name) => localStorage.getItem(site + ":" + name) !== null
|
|
762
|
+
};
|
|
806
763
|
} else {
|
|
807
|
-
|
|
764
|
+
let stateMap = /* @__PURE__ */ new Map();
|
|
765
|
+
localState = {
|
|
766
|
+
get: () => stateMap.get("metro/state:" + site),
|
|
767
|
+
set: (value) => stateMap.set("metro/state:" + site, value),
|
|
768
|
+
has: () => stateMap.has("metro/state:" + site)
|
|
769
|
+
};
|
|
770
|
+
localTokens = /* @__PURE__ */ new Map();
|
|
808
771
|
}
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
"RS256",
|
|
815
|
-
"RS384",
|
|
816
|
-
"RS512",
|
|
817
|
-
"ES256",
|
|
818
|
-
"ES384",
|
|
819
|
-
"ES512"
|
|
820
|
-
];
|
|
821
|
-
var validAuthMethods = [
|
|
822
|
-
"client_secret_post",
|
|
823
|
-
"client_secret_basic",
|
|
824
|
-
"client_secret_jwt",
|
|
825
|
-
"private_key_jwt"
|
|
826
|
-
];
|
|
772
|
+
return {
|
|
773
|
+
state: localState,
|
|
774
|
+
tokens: localTokens
|
|
775
|
+
};
|
|
776
|
+
}
|
|
827
777
|
|
|
828
|
-
// src/
|
|
829
|
-
|
|
830
|
-
assert(options, {
|
|
831
|
-
client: Optional(instanceOf(everything_default.client().constructor)),
|
|
832
|
-
issuer: Required(validURL)
|
|
833
|
-
});
|
|
778
|
+
// node_modules/@muze-nl/metro-oauth2/src/oauth2.mjs
|
|
779
|
+
function oauth2mw(options) {
|
|
834
780
|
const defaultOptions = {
|
|
835
|
-
client:
|
|
836
|
-
|
|
781
|
+
client: client(),
|
|
782
|
+
force_authorization: false,
|
|
783
|
+
site: "default",
|
|
784
|
+
oauth2_configuration: {
|
|
785
|
+
authorization_endpoint: "/authorize",
|
|
786
|
+
token_endpoint: "/token",
|
|
787
|
+
redirect_uri: globalThis.document?.location.href,
|
|
788
|
+
grant_type: "authorization_code",
|
|
789
|
+
code_verifier: generateCodeVerifier(64)
|
|
790
|
+
},
|
|
791
|
+
authorize_callback: async (url2) => {
|
|
792
|
+
if (window.location.href != url2.href) {
|
|
793
|
+
window.location.replace(url2.href);
|
|
794
|
+
}
|
|
795
|
+
return false;
|
|
796
|
+
}
|
|
837
797
|
};
|
|
798
|
+
assert(options, {});
|
|
799
|
+
const oauth22 = Object.assign({}, defaultOptions.oauth2_configuration, options?.oauth2_configuration);
|
|
838
800
|
options = Object.assign({}, defaultOptions, options);
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
const openid_provider_metadata = {
|
|
844
|
-
issuer: Required(allOf(options.issuer, MustUseHTTPS)),
|
|
845
|
-
authorization_endpoint: Required(validURL),
|
|
846
|
-
token_endpoint: Required(validURL),
|
|
847
|
-
userinfo_endpoint: Recommended(validURL),
|
|
848
|
-
// todo: test for https protocol
|
|
849
|
-
jwks_uri: Required(validURL),
|
|
850
|
-
registration_endpoint: options.requireDynamicRegistration ? Required(validURL) : Recommended(validURL),
|
|
851
|
-
scopes_supported: Recommended(MustInclude("openid")),
|
|
852
|
-
response_types_supported: options.requireDynamicRegistration ? Required(MustInclude("code", "id_token", "id_token token")) : Required([]),
|
|
853
|
-
response_modes_supported: Optional([]),
|
|
854
|
-
grant_types_supported: options.requireDynamicRegistration ? Optional(MustInclude("authorization_code")) : Optional([]),
|
|
855
|
-
acr_values_supported: Optional([]),
|
|
856
|
-
subject_types_supported: Required([]),
|
|
857
|
-
id_token_signing_alg_values_supported: Required(MustInclude("RS256")),
|
|
858
|
-
id_token_encryption_alg_values_supported: Optional([]),
|
|
859
|
-
id_token_encryption_enc_values_supported: Optional([]),
|
|
860
|
-
userinfo_signing_alg_values_supported: Optional([]),
|
|
861
|
-
userinfo_encryption_alg_values_supported: Optional([]),
|
|
862
|
-
userinfo_encryption_enc_values_supported: Optional([]),
|
|
863
|
-
request_object_signing_alg_values_supported: Optional(MustInclude("RS256")),
|
|
864
|
-
// not testing for 'none'
|
|
865
|
-
request_object_encryption_alg_values_supported: Optional([]),
|
|
866
|
-
request_object_encryption_enc_values_supported: Optional([]),
|
|
867
|
-
token_endpoint_auth_methods_supported: Optional(anyOf(...validAuthMethods)),
|
|
868
|
-
token_endpoint_auth_signing_alg_values_supported: Optional(MustInclude("RS256"), not(MustInclude("none"))),
|
|
869
|
-
display_values_supported: Optional(anyOf("page", "popup", "touch", "wap")),
|
|
870
|
-
claim_types_supported: Optional(anyOf("normal", "aggregated", "distributed")),
|
|
871
|
-
claims_supported: Recommended([]),
|
|
872
|
-
service_documentation: Optional(validURL),
|
|
873
|
-
claims_locales_supported: Optional([]),
|
|
874
|
-
ui_locales_supported: Optional([]),
|
|
875
|
-
claims_parameter_supported: Optional(Boolean),
|
|
876
|
-
request_parameter_supported: Optional(Boolean),
|
|
877
|
-
request_uri_parameter_supported: Optional(Boolean),
|
|
878
|
-
op_policy_uri: Optional(validURL),
|
|
879
|
-
op_tos_uri: Optional(validURL)
|
|
880
|
-
};
|
|
881
|
-
const configURL = everything_default.url(options.issuer, ".well-known/openid-configuration");
|
|
882
|
-
const response2 = await options.client.get(
|
|
883
|
-
// https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationRequest
|
|
884
|
-
// note: this allows path components in the options.issuer url
|
|
885
|
-
configURL
|
|
886
|
-
);
|
|
887
|
-
const openid_config = response2.data;
|
|
888
|
-
assert(openid_config, openid_provider_metadata);
|
|
889
|
-
assert(openid_config.issuer, options.issuer);
|
|
890
|
-
return openid_config;
|
|
891
|
-
}
|
|
892
|
-
|
|
893
|
-
// src/oidc.register.mjs
|
|
894
|
-
async function register(options) {
|
|
895
|
-
const openid_client_metadata = {
|
|
896
|
-
redirect_uris: Required([validURL]),
|
|
897
|
-
response_types: Optional([]),
|
|
898
|
-
grant_types: Optional(anyOf("authorization_code", "refresh_token")),
|
|
899
|
-
//TODO: match response_types with grant_types
|
|
900
|
-
application_type: Optional(oneOf("native", "web")),
|
|
901
|
-
contacts: Optional([validEmail]),
|
|
902
|
-
client_name: Optional(String),
|
|
903
|
-
logo_uri: Optional(validURL),
|
|
904
|
-
client_uri: Optional(validURL),
|
|
905
|
-
policy_uri: Optional(validURL),
|
|
906
|
-
tos_uri: Optional(validURL),
|
|
907
|
-
jwks_uri: Optional(validURL, not(MustHave("jwks"))),
|
|
908
|
-
jwks: Optional(validURL, not(MustHave("jwks_uri"))),
|
|
909
|
-
sector_identifier_uri: Optional(validURL),
|
|
910
|
-
subject_type: Optional(String),
|
|
911
|
-
id_token_signed_response_alg: Optional(oneOf(...validJWA)),
|
|
912
|
-
id_token_encrypted_response_alg: Optional(oneOf(...validJWA)),
|
|
913
|
-
id_token_encrypted_response_enc: Optional(oneOf(...validJWA), MustHave("id_token_encrypted_response_alg")),
|
|
914
|
-
userinfo_signed_response_alg: Optional(oneOf(...validJWA)),
|
|
915
|
-
userinfo_encrypted_response_alg: Optional(oneOf(...validJWA)),
|
|
916
|
-
userinfo_encrypted_response_enc: Optional(oneOf(...validJWA), MustHave("userinfo_encrypted_response_alg")),
|
|
917
|
-
request_object_signing_alg: Optional(oneOf(...validJWA)),
|
|
918
|
-
request_object_encryption_alg: Optional(oneOf(...validJWA)),
|
|
919
|
-
request_object_encryption_enc: Optional(oneOf(...validJWA)),
|
|
920
|
-
token_endpoint_auth_method: Optional(oneOf(...validAuthMethods)),
|
|
921
|
-
token_endpoint_auth_signing_alg: Optional(oneOf(...validJWA)),
|
|
922
|
-
default_max_age: Optional(Number),
|
|
923
|
-
require_auth_time: Optional(Boolean),
|
|
924
|
-
default_acr_values: Optional([String]),
|
|
925
|
-
initiate_login_uri: Optional([validURL]),
|
|
926
|
-
request_uris: Optional([validURL])
|
|
927
|
-
};
|
|
928
|
-
assert(options, {
|
|
929
|
-
client: Optional(instanceOf(everything_default.client().constructor)),
|
|
930
|
-
registration_endpoint: validURL,
|
|
931
|
-
client_info: openid_client_metadata
|
|
932
|
-
});
|
|
933
|
-
const defaultOptions = {
|
|
934
|
-
client: everything_default.client().with(thrower()).with(jsonmw())
|
|
935
|
-
};
|
|
936
|
-
options = Object.assign({}, defaultOptions, options);
|
|
937
|
-
let response2 = await options.client.post(options.registration_endpoint, {
|
|
938
|
-
body: options.client_info
|
|
939
|
-
});
|
|
940
|
-
let info = response2.data;
|
|
941
|
-
if (!info.client_id || !info.client_secret) {
|
|
942
|
-
throw everything_default.metroError("metro.oidc: Error: dynamic registration of client failed, no client_id or client_secret returned", response2);
|
|
943
|
-
}
|
|
944
|
-
options.client_info = Object.assign(options.client_info, info);
|
|
945
|
-
return options.client_info;
|
|
946
|
-
}
|
|
947
|
-
|
|
948
|
-
// node_modules/@muze-nl/metro-oauth2/src/oauth2.mjs
|
|
949
|
-
var oauth2_exports = {};
|
|
950
|
-
__export(oauth2_exports, {
|
|
951
|
-
base64url_encode: () => base64url_encode,
|
|
952
|
-
createState: () => createState,
|
|
953
|
-
default: () => oauth2mw,
|
|
954
|
-
generateCodeChallenge: () => generateCodeChallenge,
|
|
955
|
-
generateCodeVerifier: () => generateCodeVerifier,
|
|
956
|
-
getExpires: () => getExpires,
|
|
957
|
-
isExpired: () => isExpired,
|
|
958
|
-
isRedirected: () => isRedirected
|
|
959
|
-
});
|
|
960
|
-
|
|
961
|
-
// node_modules/@muze-nl/metro-oauth2/node_modules/@muze-nl/assert/src/assert.mjs
|
|
962
|
-
globalThis.assertEnabled = false;
|
|
963
|
-
var assert2 = (source, test) => {
|
|
964
|
-
if (globalThis.assertEnabled) {
|
|
965
|
-
let problems = fails2(source, test);
|
|
966
|
-
if (problems) {
|
|
967
|
-
throw new assertError("Assertions failed", problems, source);
|
|
968
|
-
}
|
|
969
|
-
}
|
|
970
|
-
};
|
|
971
|
-
var Optional2 = (pattern) => (data) => data == null || typeof data == "undefined" ? false : fails2(data, pattern);
|
|
972
|
-
var Required2 = (pattern) => (data) => fails2(data, pattern);
|
|
973
|
-
var Recommended2 = (pattern) => (data) => data == null || typeof data == "undefined" ? (() => {
|
|
974
|
-
console.warning("data does not contain recommended value", data, pattern);
|
|
975
|
-
return false;
|
|
976
|
-
})() : fails2(data, pattern);
|
|
977
|
-
var oneOf2 = (...patterns) => (data) => {
|
|
978
|
-
for (let pattern of patterns) {
|
|
979
|
-
if (!fails2(data, pattern)) {
|
|
980
|
-
return false;
|
|
981
|
-
}
|
|
982
|
-
}
|
|
983
|
-
return error2("data does not match oneOf patterns", data, patterns);
|
|
984
|
-
};
|
|
985
|
-
var anyOf2 = (...patterns) => (data) => {
|
|
986
|
-
if (!Array.isArray(data)) {
|
|
987
|
-
return error2("data is not an array", data, "anyOf");
|
|
988
|
-
}
|
|
989
|
-
for (let value of data) {
|
|
990
|
-
if (oneOf2(...patterns)(value)) {
|
|
991
|
-
return error2("data does not match anyOf patterns", value, patterns);
|
|
992
|
-
}
|
|
993
|
-
}
|
|
994
|
-
return false;
|
|
995
|
-
};
|
|
996
|
-
function validURL2(data) {
|
|
997
|
-
try {
|
|
998
|
-
if (data instanceof URL) {
|
|
999
|
-
data = data.href;
|
|
1000
|
-
}
|
|
1001
|
-
let url2 = new URL(data);
|
|
1002
|
-
if (url2.href != data) {
|
|
1003
|
-
return error2("data is not a valid url", data, "validURL");
|
|
1004
|
-
}
|
|
1005
|
-
} catch (e) {
|
|
1006
|
-
return error2("data is not a valid url", data, "validURL");
|
|
1007
|
-
}
|
|
1008
|
-
return false;
|
|
1009
|
-
}
|
|
1010
|
-
function fails2(data, pattern, root) {
|
|
1011
|
-
if (!root) {
|
|
1012
|
-
root = data;
|
|
1013
|
-
}
|
|
1014
|
-
let problems = [];
|
|
1015
|
-
if (pattern === Boolean) {
|
|
1016
|
-
if (typeof data != "boolean") {
|
|
1017
|
-
problems.push(error2("data is not a boolean", data, pattern));
|
|
1018
|
-
}
|
|
1019
|
-
} else if (pattern === Number) {
|
|
1020
|
-
if (typeof data != "number") {
|
|
1021
|
-
problems.push(error2("data is not a number", data, pattern));
|
|
1022
|
-
}
|
|
1023
|
-
} else if (pattern instanceof RegExp) {
|
|
1024
|
-
if (Array.isArray(data)) {
|
|
1025
|
-
let index = data.findIndex((element) => fails2(element, pattern, root));
|
|
1026
|
-
if (index > -1) {
|
|
1027
|
-
problems.push(error2("data[" + index + "] does not match pattern", data[index], pattern));
|
|
1028
|
-
}
|
|
1029
|
-
} else if (!pattern.test(data)) {
|
|
1030
|
-
problems.push(error2("data does not match pattern", data, pattern));
|
|
1031
|
-
}
|
|
1032
|
-
} else if (pattern instanceof Function) {
|
|
1033
|
-
if (pattern(data, root)) {
|
|
1034
|
-
problems.push(error2("data does not match function", data, pattern));
|
|
1035
|
-
}
|
|
1036
|
-
} else if (Array.isArray(pattern)) {
|
|
1037
|
-
if (!Array.isArray(data)) {
|
|
1038
|
-
problems.push(error2("data is not an array", data, []));
|
|
1039
|
-
}
|
|
1040
|
-
for (p of pattern) {
|
|
1041
|
-
let problem = fails2(data, p, root);
|
|
1042
|
-
if (Array.isArray(problem)) {
|
|
1043
|
-
problems.concat(problem);
|
|
1044
|
-
} else if (problem) {
|
|
1045
|
-
problems.push(problem);
|
|
1046
|
-
}
|
|
1047
|
-
}
|
|
1048
|
-
} else if (pattern && typeof pattern == "object") {
|
|
1049
|
-
if (Array.isArray(data)) {
|
|
1050
|
-
let index = data.findIndex((element) => fails2(element, pattern, root));
|
|
1051
|
-
if (index > -1) {
|
|
1052
|
-
problems.push(error2("data[" + index + "] does not match pattern", data[index], pattern));
|
|
1053
|
-
}
|
|
1054
|
-
} else if (!data || typeof data != "object") {
|
|
1055
|
-
problems.push(error2("data is not an object, pattern is", data, pattern));
|
|
1056
|
-
} else {
|
|
1057
|
-
if (data instanceof URLSearchParams) {
|
|
1058
|
-
data = Object.fromEntries(data);
|
|
1059
|
-
}
|
|
1060
|
-
let p2 = problems[problems.length - 1];
|
|
1061
|
-
for (const [wKey, wVal] of Object.entries(pattern)) {
|
|
1062
|
-
let result = fails2(data[wKey], wVal, root);
|
|
1063
|
-
if (result) {
|
|
1064
|
-
if (!p2 || typeof p2 == "string") {
|
|
1065
|
-
p2 = {};
|
|
1066
|
-
problems.push(error2(p2, data[wKey], wVal));
|
|
1067
|
-
}
|
|
1068
|
-
p2[wKey] = result.problems;
|
|
1069
|
-
}
|
|
1070
|
-
}
|
|
1071
|
-
}
|
|
1072
|
-
} else {
|
|
1073
|
-
if (pattern != data) {
|
|
1074
|
-
problems.push(error2("data and pattern are not equal", data, pattern));
|
|
1075
|
-
}
|
|
1076
|
-
}
|
|
1077
|
-
if (problems.length) {
|
|
1078
|
-
return problems;
|
|
1079
|
-
}
|
|
1080
|
-
return false;
|
|
1081
|
-
}
|
|
1082
|
-
var assertError = class extends Error {
|
|
1083
|
-
constructor(message, problems, ...details) {
|
|
1084
|
-
super(message);
|
|
1085
|
-
this.problems = problems;
|
|
1086
|
-
this.details = details;
|
|
1087
|
-
}
|
|
1088
|
-
};
|
|
1089
|
-
function error2(message, found, expected) {
|
|
1090
|
-
return {
|
|
1091
|
-
message,
|
|
1092
|
-
found,
|
|
1093
|
-
expected
|
|
1094
|
-
};
|
|
1095
|
-
}
|
|
1096
|
-
|
|
1097
|
-
// node_modules/@muze-nl/metro-oauth2/src/tokenstore.mjs
|
|
1098
|
-
function tokenStore(site) {
|
|
1099
|
-
let localState, localTokens;
|
|
1100
|
-
if (typeof localStorage !== "undefined") {
|
|
1101
|
-
localState = {
|
|
1102
|
-
get: () => localStorage.getItem("metro/state:" + site),
|
|
1103
|
-
set: (value) => localStorage.setItem("metro/state:" + site, value),
|
|
1104
|
-
has: () => localStorage.getItem("metro/state:" + site) !== null
|
|
1105
|
-
};
|
|
1106
|
-
localTokens = {
|
|
1107
|
-
get: (name) => JSON.parse(localStorage.getItem(site + ":" + name)),
|
|
1108
|
-
set: (name, value) => localStorage.setItem(site + ":" + name, JSON.stringify(value)),
|
|
1109
|
-
has: (name) => localStorage.getItem(site + ":" + name) !== null
|
|
1110
|
-
};
|
|
1111
|
-
} else {
|
|
1112
|
-
let stateMap = /* @__PURE__ */ new Map();
|
|
1113
|
-
localState = {
|
|
1114
|
-
get: () => stateMap.get("metro/state:" + site),
|
|
1115
|
-
set: (value) => stateMap.set("metro/state:" + site, value),
|
|
1116
|
-
has: () => stateMap.has("metro/state:" + site)
|
|
1117
|
-
};
|
|
1118
|
-
localTokens = /* @__PURE__ */ new Map();
|
|
1119
|
-
}
|
|
1120
|
-
return {
|
|
1121
|
-
state: localState,
|
|
1122
|
-
tokens: localTokens
|
|
1123
|
-
};
|
|
1124
|
-
}
|
|
1125
|
-
|
|
1126
|
-
// node_modules/@muze-nl/metro-oauth2/src/oauth2.mjs
|
|
1127
|
-
function oauth2mw(options) {
|
|
1128
|
-
const defaultOptions = {
|
|
1129
|
-
client: everything_default.client(),
|
|
1130
|
-
force_authorization: false,
|
|
1131
|
-
site: "default",
|
|
1132
|
-
oauth2_configuration: {
|
|
1133
|
-
authorization_endpoint: "/authorize",
|
|
1134
|
-
token_endpoint: "/token",
|
|
1135
|
-
redirect_uri: globalThis.document?.location.href,
|
|
1136
|
-
grant_type: "authorization_code",
|
|
1137
|
-
code_verifier: generateCodeVerifier(64)
|
|
1138
|
-
},
|
|
1139
|
-
callbacks: {
|
|
1140
|
-
authorize: async (url2) => {
|
|
1141
|
-
if (window.location.href != url2.href) {
|
|
1142
|
-
window.location.replace(url2.href);
|
|
1143
|
-
}
|
|
1144
|
-
return false;
|
|
1145
|
-
}
|
|
1146
|
-
}
|
|
1147
|
-
};
|
|
1148
|
-
assert2(options, {});
|
|
1149
|
-
const oauth22 = Object.assign({}, defaultOptions.oauth2_configuration, options?.oauth2_configuration);
|
|
1150
|
-
options = Object.assign({}, defaultOptions, options);
|
|
1151
|
-
options.oauth2_configuration = oauth22;
|
|
1152
|
-
const store = tokenStore(options.site);
|
|
1153
|
-
if (!options.tokens) {
|
|
1154
|
-
options.tokens = store.tokens;
|
|
801
|
+
options.oauth2_configuration = oauth22;
|
|
802
|
+
const store = tokenStore(options.site);
|
|
803
|
+
if (!options.tokens) {
|
|
804
|
+
options.tokens = store.tokens;
|
|
1155
805
|
}
|
|
1156
806
|
if (!options.state) {
|
|
1157
807
|
options.state = store.state;
|
|
1158
808
|
}
|
|
1159
|
-
|
|
809
|
+
assert(options, {
|
|
1160
810
|
oauth2_configuration: {
|
|
1161
|
-
client_id:
|
|
811
|
+
client_id: Required(/.+/),
|
|
1162
812
|
grant_type: "authorization_code",
|
|
1163
|
-
authorization_endpoint:
|
|
1164
|
-
token_endpoint:
|
|
1165
|
-
redirect_uri:
|
|
813
|
+
authorization_endpoint: Required(validURL),
|
|
814
|
+
token_endpoint: Required(validURL),
|
|
815
|
+
redirect_uri: Required(validURL)
|
|
1166
816
|
}
|
|
1167
817
|
});
|
|
1168
818
|
for (let option in oauth22) {
|
|
@@ -1212,7 +862,7 @@
|
|
|
1212
862
|
try {
|
|
1213
863
|
let token = await fetchAccessToken();
|
|
1214
864
|
if (!token) {
|
|
1215
|
-
return
|
|
865
|
+
return response("false");
|
|
1216
866
|
}
|
|
1217
867
|
} catch (e) {
|
|
1218
868
|
throw e;
|
|
@@ -1222,14 +872,14 @@
|
|
|
1222
872
|
try {
|
|
1223
873
|
let token = await fetchRefreshToken();
|
|
1224
874
|
if (!token) {
|
|
1225
|
-
return
|
|
875
|
+
return response("false");
|
|
1226
876
|
}
|
|
1227
877
|
} catch (e) {
|
|
1228
878
|
throw e;
|
|
1229
879
|
}
|
|
1230
880
|
return oauth2authorized(req, next);
|
|
1231
881
|
} else {
|
|
1232
|
-
req =
|
|
882
|
+
req = request(req, {
|
|
1233
883
|
headers: {
|
|
1234
884
|
Authorization: accessToken.type + " " + accessToken.value
|
|
1235
885
|
}
|
|
@@ -1239,7 +889,7 @@
|
|
|
1239
889
|
}
|
|
1240
890
|
function getTokensFromLocation() {
|
|
1241
891
|
if (typeof window !== "undefined" && window?.location) {
|
|
1242
|
-
let url2 =
|
|
892
|
+
let url2 = url(window.location);
|
|
1243
893
|
let code, state, params2;
|
|
1244
894
|
if (url2.searchParams.has("code")) {
|
|
1245
895
|
params2 = url2.searchParams;
|
|
@@ -1267,10 +917,10 @@
|
|
|
1267
917
|
async function fetchAccessToken() {
|
|
1268
918
|
if (oauth22.grant_type === "authorization_code" && !options.tokens.has("authorization_code")) {
|
|
1269
919
|
let authReqURL = await getAuthorizationCodeURL();
|
|
1270
|
-
if (!options.
|
|
1271
|
-
throw
|
|
920
|
+
if (!options.authorize_callback || typeof options.authorize_callback !== "function") {
|
|
921
|
+
throw metroError("oauth2mw: oauth2 with grant_type:authorization_code requires a callback function in client options.authorize_callback");
|
|
1272
922
|
}
|
|
1273
|
-
let token = await options.
|
|
923
|
+
let token = await options.authorize_callback(authReqURL);
|
|
1274
924
|
if (token) {
|
|
1275
925
|
options.tokens.set("authorization_code", token);
|
|
1276
926
|
} else {
|
|
@@ -1281,7 +931,7 @@
|
|
|
1281
931
|
let response2 = await options.client.post(tokenReq);
|
|
1282
932
|
if (!response2.ok) {
|
|
1283
933
|
let msg = await response2.text();
|
|
1284
|
-
throw
|
|
934
|
+
throw metroError("OAuth2mw: fetch access_token: " + response2.status + ": " + response2.statusText, { cause: tokenReq });
|
|
1285
935
|
}
|
|
1286
936
|
let data = await response2.json();
|
|
1287
937
|
options.tokens.set("access_token", {
|
|
@@ -1302,7 +952,7 @@
|
|
|
1302
952
|
let refreshTokenReq = getAccessTokenRequest("refresh_token");
|
|
1303
953
|
let response2 = await options.client.post(refreshTokenReq);
|
|
1304
954
|
if (!response2.ok) {
|
|
1305
|
-
throw
|
|
955
|
+
throw metroError("OAuth2mw: refresh access_token: " + response2.status + ": " + response2.statusText, { cause: refreshTokenReq });
|
|
1306
956
|
}
|
|
1307
957
|
let data = await response2.json();
|
|
1308
958
|
options.tokens.set("access_token", {
|
|
@@ -1323,10 +973,10 @@
|
|
|
1323
973
|
}
|
|
1324
974
|
async function getAuthorizationCodeURL() {
|
|
1325
975
|
if (!oauth22.authorization_endpoint) {
|
|
1326
|
-
throw
|
|
976
|
+
throw metroError("oauth2mw: Missing options.oauth2_configuration.authorization_endpoint");
|
|
1327
977
|
}
|
|
1328
|
-
let url2 =
|
|
1329
|
-
|
|
978
|
+
let url2 = url(oauth22.authorization_endpoint, { hash: "" });
|
|
979
|
+
assert(oauth22, {
|
|
1330
980
|
client_id: /.+/,
|
|
1331
981
|
redirect_uri: /.+/,
|
|
1332
982
|
scope: /.*/
|
|
@@ -1350,7 +1000,7 @@
|
|
|
1350
1000
|
search.client_secret = oauth22.client_secret;
|
|
1351
1001
|
}
|
|
1352
1002
|
if (oauth22.code_verifier) {
|
|
1353
|
-
search.code_challenge =
|
|
1003
|
+
search.code_challenge = await generateCodeChallenge(oauth22.code_verifier);
|
|
1354
1004
|
search.code_challenge_method = "S256";
|
|
1355
1005
|
}
|
|
1356
1006
|
if (oauth22.scope) {
|
|
@@ -1359,23 +1009,23 @@
|
|
|
1359
1009
|
if (oauth22.prompt) {
|
|
1360
1010
|
search.prompt = oauth22.prompt;
|
|
1361
1011
|
}
|
|
1362
|
-
return
|
|
1012
|
+
return url(url2, { search });
|
|
1363
1013
|
}
|
|
1364
1014
|
function getAccessTokenRequest(grant_type = null) {
|
|
1365
|
-
|
|
1015
|
+
assert(oauth22, {
|
|
1366
1016
|
client_id: /.+/,
|
|
1367
1017
|
redirect_uri: /.+/
|
|
1368
1018
|
});
|
|
1369
1019
|
if (!oauth22.token_endpoint) {
|
|
1370
|
-
throw
|
|
1020
|
+
throw metroError("oauth2mw: Missing options.endpoints.token url");
|
|
1371
1021
|
}
|
|
1372
|
-
let url2 =
|
|
1022
|
+
let url2 = url(oauth22.token_endpoint, { hash: "" });
|
|
1373
1023
|
let params2 = {
|
|
1374
1024
|
grant_type: grant_type || oauth22.grant_type,
|
|
1375
1025
|
client_id: oauth22.client_id
|
|
1376
1026
|
};
|
|
1377
1027
|
if (oauth22.code_verifier) {
|
|
1378
|
-
params2.code_verifier =
|
|
1028
|
+
params2.code_verifier = oauth22.code_verifier;
|
|
1379
1029
|
}
|
|
1380
1030
|
if (oauth22.client_secret) {
|
|
1381
1031
|
params2.client_secret = oauth22.client_secret;
|
|
@@ -1387,10 +1037,6 @@
|
|
|
1387
1037
|
case "authorization_code":
|
|
1388
1038
|
params2.redirect_uri = oauth22.redirect_uri;
|
|
1389
1039
|
params2.code = options.tokens.get("authorization_code");
|
|
1390
|
-
if (options.dpop) {
|
|
1391
|
-
const keyPair = options.tokens.get("keyPair");
|
|
1392
|
-
params2.dpop_jkt = keyPair.publicKey;
|
|
1393
|
-
}
|
|
1394
1040
|
break;
|
|
1395
1041
|
case "client_credentials":
|
|
1396
1042
|
break;
|
|
@@ -1401,7 +1047,7 @@
|
|
|
1401
1047
|
throw new Error("Unknown grant_type: ".oauth2.grant_type);
|
|
1402
1048
|
break;
|
|
1403
1049
|
}
|
|
1404
|
-
return
|
|
1050
|
+
return request(url2, { method: "POST", body: new URLSearchParams(params2) });
|
|
1405
1051
|
}
|
|
1406
1052
|
}
|
|
1407
1053
|
function isExpired(token) {
|
|
@@ -1426,13 +1072,13 @@
|
|
|
1426
1072
|
function generateCodeVerifier(size = 64) {
|
|
1427
1073
|
const code_verifier = new Uint8Array(size);
|
|
1428
1074
|
globalThis.crypto.getRandomValues(code_verifier);
|
|
1429
|
-
return code_verifier;
|
|
1075
|
+
return base64url_encode(code_verifier);
|
|
1430
1076
|
}
|
|
1431
1077
|
async function generateCodeChallenge(code_verifier) {
|
|
1432
|
-
const b64encoded = base64url_encode(code_verifier);
|
|
1433
1078
|
const encoder2 = new TextEncoder();
|
|
1434
|
-
const data = encoder2.encode(
|
|
1435
|
-
|
|
1079
|
+
const data = encoder2.encode(code_verifier);
|
|
1080
|
+
const challenge = await globalThis.crypto.subtle.digest("SHA-256", data);
|
|
1081
|
+
return base64url_encode(challenge);
|
|
1436
1082
|
}
|
|
1437
1083
|
function base64url_encode(buffer) {
|
|
1438
1084
|
const byteString = Array.from(new Uint8Array(buffer), (b) => String.fromCharCode(b)).join("");
|
|
@@ -1462,6 +1108,14 @@
|
|
|
1462
1108
|
}
|
|
1463
1109
|
return true;
|
|
1464
1110
|
}
|
|
1111
|
+
async function authorizePopup(authorizationCodeURL) {
|
|
1112
|
+
return new Promise((resolve, reject) => {
|
|
1113
|
+
addEventListener("oauth2authorized", (evt) => {
|
|
1114
|
+
resolve(event.authorization_code);
|
|
1115
|
+
}, { once: true });
|
|
1116
|
+
window.open(authorizationCodeURL);
|
|
1117
|
+
});
|
|
1118
|
+
}
|
|
1465
1119
|
|
|
1466
1120
|
// node_modules/@muze-nl/metro-oauth2/src/oauth2.mockserver.mjs
|
|
1467
1121
|
var oauth2_mockserver_exports = {};
|
|
@@ -1488,7 +1142,7 @@
|
|
|
1488
1142
|
})
|
|
1489
1143
|
};
|
|
1490
1144
|
};
|
|
1491
|
-
var
|
|
1145
|
+
var error2;
|
|
1492
1146
|
var pkce = {};
|
|
1493
1147
|
function oauth2mockserver(options = {}) {
|
|
1494
1148
|
const defaultOptions = {
|
|
@@ -1500,12 +1154,12 @@
|
|
|
1500
1154
|
let url2 = everything_default.url(req.url);
|
|
1501
1155
|
switch (url2.pathname) {
|
|
1502
1156
|
case "/authorize/":
|
|
1503
|
-
if (
|
|
1157
|
+
if (error2 = fails(url2.searchParams, {
|
|
1504
1158
|
response_type: "code",
|
|
1505
1159
|
client_id: "mockClientId",
|
|
1506
|
-
state:
|
|
1160
|
+
state: Optional(/.*/)
|
|
1507
1161
|
})) {
|
|
1508
|
-
return everything_default.response(badRequest(
|
|
1162
|
+
return everything_default.response(badRequest(error2));
|
|
1509
1163
|
}
|
|
1510
1164
|
if (url2.searchParams.has("code_challenge")) {
|
|
1511
1165
|
if (!url2.searchParams.has("code_challenge_method")) {
|
|
@@ -1527,17 +1181,17 @@
|
|
|
1527
1181
|
req.data.forEach((value, key) => body[key] = value);
|
|
1528
1182
|
req = req.with({ body });
|
|
1529
1183
|
}
|
|
1530
|
-
if (
|
|
1184
|
+
if (error2 = fails(req, {
|
|
1531
1185
|
method: "POST",
|
|
1532
1186
|
data: {
|
|
1533
|
-
grant_type:
|
|
1187
|
+
grant_type: oneOf("refresh_token", "authorization_code")
|
|
1534
1188
|
}
|
|
1535
1189
|
})) {
|
|
1536
|
-
return everything_default.response(badRequest(
|
|
1190
|
+
return everything_default.response(badRequest(error2));
|
|
1537
1191
|
}
|
|
1538
1192
|
switch (req.data.grant_type) {
|
|
1539
1193
|
case "refresh_token":
|
|
1540
|
-
if (
|
|
1194
|
+
if (error2 = fails(req.data, oneOf({
|
|
1541
1195
|
refresh_token: "mockRefreshToken",
|
|
1542
1196
|
client_id: "mockClientId",
|
|
1543
1197
|
client_secret: "mockClientSecret"
|
|
@@ -1546,11 +1200,11 @@
|
|
|
1546
1200
|
client_id: "mockClientId",
|
|
1547
1201
|
code_verifier: /.+/
|
|
1548
1202
|
}))) {
|
|
1549
|
-
return everything_default.response(badRequest(
|
|
1203
|
+
return everything_default.response(badRequest(error2));
|
|
1550
1204
|
}
|
|
1551
1205
|
break;
|
|
1552
1206
|
case "access_token":
|
|
1553
|
-
if (
|
|
1207
|
+
if (error2 = fails(req.data, oneOf({
|
|
1554
1208
|
client_id: "mockClientId",
|
|
1555
1209
|
client_secret: "mockClientSecret"
|
|
1556
1210
|
}, {
|
|
@@ -1559,7 +1213,7 @@
|
|
|
1559
1213
|
//FIXME: check that this matches code_verifier
|
|
1560
1214
|
code_challenge_method: "S256"
|
|
1561
1215
|
}))) {
|
|
1562
|
-
return everything_default.response(badRequest(
|
|
1216
|
+
return everything_default.response(badRequest(error2));
|
|
1563
1217
|
}
|
|
1564
1218
|
break;
|
|
1565
1219
|
}
|
|
@@ -1623,43 +1277,43 @@
|
|
|
1623
1277
|
"ES384",
|
|
1624
1278
|
"ES512"
|
|
1625
1279
|
];
|
|
1626
|
-
var
|
|
1280
|
+
var validAuthMethods = [
|
|
1627
1281
|
"client_secret_post",
|
|
1628
1282
|
"client_secret_base",
|
|
1629
1283
|
"client_secret_jwt",
|
|
1630
1284
|
"private_key_jwt"
|
|
1631
1285
|
];
|
|
1632
1286
|
var oauth_authorization_server_metadata = {
|
|
1633
|
-
issuer:
|
|
1634
|
-
authorization_endpoint:
|
|
1635
|
-
token_endpoint:
|
|
1636
|
-
jwks_uri:
|
|
1637
|
-
registration_endpoint:
|
|
1638
|
-
scopes_supported:
|
|
1639
|
-
response_types_supported:
|
|
1640
|
-
response_modes_supported:
|
|
1641
|
-
grant_types_supported:
|
|
1642
|
-
token_endpoint_auth_methods_supported:
|
|
1643
|
-
token_endpoint_auth_signing_alg_values_supported:
|
|
1644
|
-
service_documentation:
|
|
1645
|
-
ui_locales_supported:
|
|
1646
|
-
op_policy_uri:
|
|
1647
|
-
op_tos_uri:
|
|
1648
|
-
revocation_endpoint:
|
|
1649
|
-
revocation_endpoint_auth_methods_supported:
|
|
1650
|
-
revocation_endpoint_auth_signing_alg_values_supported:
|
|
1651
|
-
introspection_endpoint:
|
|
1652
|
-
introspection_endpoint_auth_methods_supported:
|
|
1653
|
-
introspection_endpoint_auth_signing_alg_values_supported:
|
|
1654
|
-
code_challendge_methods_supported:
|
|
1287
|
+
issuer: Required(validURL),
|
|
1288
|
+
authorization_endpoint: Required(validURL),
|
|
1289
|
+
token_endpoint: Required(validURL),
|
|
1290
|
+
jwks_uri: Optional(validURL),
|
|
1291
|
+
registration_endpoint: Optional(validURL),
|
|
1292
|
+
scopes_supported: Recommended([]),
|
|
1293
|
+
response_types_supported: Required(anyOf("code", "token")),
|
|
1294
|
+
response_modes_supported: Optional([]),
|
|
1295
|
+
grant_types_supported: Optional([]),
|
|
1296
|
+
token_endpoint_auth_methods_supported: Optional([]),
|
|
1297
|
+
token_endpoint_auth_signing_alg_values_supported: Optional([]),
|
|
1298
|
+
service_documentation: Optional(validURL),
|
|
1299
|
+
ui_locales_supported: Optional([]),
|
|
1300
|
+
op_policy_uri: Optional(validURL),
|
|
1301
|
+
op_tos_uri: Optional(validURL),
|
|
1302
|
+
revocation_endpoint: Optional(validURL),
|
|
1303
|
+
revocation_endpoint_auth_methods_supported: Optional(validAuthMethods),
|
|
1304
|
+
revocation_endpoint_auth_signing_alg_values_supported: Optional(validAlgorithms),
|
|
1305
|
+
introspection_endpoint: Optional(validURL),
|
|
1306
|
+
introspection_endpoint_auth_methods_supported: Optional(validAuthMethods),
|
|
1307
|
+
introspection_endpoint_auth_signing_alg_values_supported: Optional(validAlgorithms),
|
|
1308
|
+
code_challendge_methods_supported: Optional([])
|
|
1655
1309
|
};
|
|
1656
1310
|
function makeClient(options = {}) {
|
|
1657
1311
|
const defaultOptions = {
|
|
1658
1312
|
client: everything_default.client()
|
|
1659
1313
|
};
|
|
1660
1314
|
options = Object.assign({}, defaultOptions, options);
|
|
1661
|
-
|
|
1662
|
-
issuer:
|
|
1315
|
+
assert(options, {
|
|
1316
|
+
issuer: Required(validURL)
|
|
1663
1317
|
});
|
|
1664
1318
|
const oauth_authorization_server_configuration = fetchWellknownOauthAuthorizationServer(options.issuer);
|
|
1665
1319
|
let client2 = options.client.with(options.issuer);
|
|
@@ -1667,9 +1321,9 @@
|
|
|
1667
1321
|
async function fetchWellknownOauthAuthorizationServer(issuer, client2) {
|
|
1668
1322
|
let res = client2.get(everything_default.url(issuer, ".wellknown/oauth_authorization_server"));
|
|
1669
1323
|
if (res.ok) {
|
|
1670
|
-
|
|
1324
|
+
assert(res.headers.get("Content-Type"), /application\/json.*/);
|
|
1671
1325
|
let configuration = await res.json();
|
|
1672
|
-
|
|
1326
|
+
assert(configuration, oauth_authorization_server_metadata);
|
|
1673
1327
|
return configuration;
|
|
1674
1328
|
}
|
|
1675
1329
|
throw everything_default.metroError("metro.oidcmw: Error while fetching " + issuer + ".wellknown/oauth_authorization_server", res);
|
|
@@ -1680,11 +1334,11 @@
|
|
|
1680
1334
|
return new Promise((resolve, reject) => {
|
|
1681
1335
|
const request2 = globalThis.indexedDB.open("metro", 1);
|
|
1682
1336
|
request2.onupgradeneeded = () => request2.result.createObjectStore("keyPairs", { keyPath: "domain" });
|
|
1683
|
-
request2.onerror = (
|
|
1684
|
-
reject(
|
|
1337
|
+
request2.onerror = (event2) => {
|
|
1338
|
+
reject(event2);
|
|
1685
1339
|
};
|
|
1686
|
-
request2.onsuccess = (
|
|
1687
|
-
const db =
|
|
1340
|
+
request2.onsuccess = (event2) => {
|
|
1341
|
+
const db = event2.target.result;
|
|
1688
1342
|
resolve({
|
|
1689
1343
|
set: function(value, key) {
|
|
1690
1344
|
return new Promise((resolve2, reject2) => {
|
|
@@ -1812,175 +1466,549 @@
|
|
|
1812
1466
|
default:
|
|
1813
1467
|
throw new UnsupportedOperationError("unsupported RsaHashedKeyAlgorithm hash name");
|
|
1814
1468
|
}
|
|
1815
|
-
}
|
|
1816
|
-
function esAlg(key) {
|
|
1817
|
-
switch (key.algorithm.namedCurve) {
|
|
1818
|
-
case "P-256":
|
|
1819
|
-
return "ES256";
|
|
1820
|
-
default:
|
|
1821
|
-
throw new UnsupportedOperationError("unsupported EcKeyAlgorithm namedCurve");
|
|
1469
|
+
}
|
|
1470
|
+
function esAlg(key) {
|
|
1471
|
+
switch (key.algorithm.namedCurve) {
|
|
1472
|
+
case "P-256":
|
|
1473
|
+
return "ES256";
|
|
1474
|
+
default:
|
|
1475
|
+
throw new UnsupportedOperationError("unsupported EcKeyAlgorithm namedCurve");
|
|
1476
|
+
}
|
|
1477
|
+
}
|
|
1478
|
+
function determineJWSAlgorithm(key) {
|
|
1479
|
+
switch (key.algorithm.name) {
|
|
1480
|
+
case "RSA-PSS":
|
|
1481
|
+
return psAlg(key);
|
|
1482
|
+
case "RSASSA-PKCS1-v1_5":
|
|
1483
|
+
return rsAlg(key);
|
|
1484
|
+
case "ECDSA":
|
|
1485
|
+
return esAlg(key);
|
|
1486
|
+
case "Ed25519":
|
|
1487
|
+
return "EdDSA";
|
|
1488
|
+
default:
|
|
1489
|
+
throw new UnsupportedOperationError("unsupported CryptoKey algorithm name");
|
|
1490
|
+
}
|
|
1491
|
+
}
|
|
1492
|
+
function isCryptoKey(key) {
|
|
1493
|
+
return key instanceof CryptoKey;
|
|
1494
|
+
}
|
|
1495
|
+
function isPrivateKey(key) {
|
|
1496
|
+
return isCryptoKey(key) && key.type === "private";
|
|
1497
|
+
}
|
|
1498
|
+
function isPublicKey(key) {
|
|
1499
|
+
return isCryptoKey(key) && key.type === "public";
|
|
1500
|
+
}
|
|
1501
|
+
function epochTime() {
|
|
1502
|
+
return Math.floor(Date.now() / 1e3);
|
|
1503
|
+
}
|
|
1504
|
+
async function DPoP(keypair, htu, htm, nonce, accessToken, additional) {
|
|
1505
|
+
const privateKey = keypair?.privateKey;
|
|
1506
|
+
const publicKey = keypair?.publicKey;
|
|
1507
|
+
if (!isPrivateKey(privateKey)) {
|
|
1508
|
+
throw new TypeError('"keypair.privateKey" must be a private CryptoKey');
|
|
1509
|
+
}
|
|
1510
|
+
if (!isPublicKey(publicKey)) {
|
|
1511
|
+
throw new TypeError('"keypair.publicKey" must be a public CryptoKey');
|
|
1512
|
+
}
|
|
1513
|
+
if (publicKey.extractable !== true) {
|
|
1514
|
+
throw new TypeError('"keypair.publicKey.extractable" must be true');
|
|
1515
|
+
}
|
|
1516
|
+
if (typeof htu !== "string") {
|
|
1517
|
+
throw new TypeError('"htu" must be a string');
|
|
1518
|
+
}
|
|
1519
|
+
if (typeof htm !== "string") {
|
|
1520
|
+
throw new TypeError('"htm" must be a string');
|
|
1521
|
+
}
|
|
1522
|
+
if (nonce !== void 0 && typeof nonce !== "string") {
|
|
1523
|
+
throw new TypeError('"nonce" must be a string or undefined');
|
|
1524
|
+
}
|
|
1525
|
+
if (accessToken !== void 0 && typeof accessToken !== "string") {
|
|
1526
|
+
throw new TypeError('"accessToken" must be a string or undefined');
|
|
1527
|
+
}
|
|
1528
|
+
if (additional !== void 0 && (typeof additional !== "object" || additional === null || Array.isArray(additional))) {
|
|
1529
|
+
throw new TypeError('"additional" must be an object');
|
|
1530
|
+
}
|
|
1531
|
+
return jwt({
|
|
1532
|
+
alg: determineJWSAlgorithm(privateKey),
|
|
1533
|
+
typ: "dpop+jwt",
|
|
1534
|
+
jwk: await publicJwk(publicKey)
|
|
1535
|
+
}, {
|
|
1536
|
+
...additional,
|
|
1537
|
+
iat: epochTime(),
|
|
1538
|
+
jti: randomBytes(),
|
|
1539
|
+
htm,
|
|
1540
|
+
nonce,
|
|
1541
|
+
htu,
|
|
1542
|
+
ath: accessToken ? b64u(await crypto.subtle.digest("SHA-256", buf(accessToken))) : void 0
|
|
1543
|
+
}, privateKey);
|
|
1544
|
+
}
|
|
1545
|
+
async function publicJwk(key) {
|
|
1546
|
+
const { kty, e, n, x, y, crv } = await crypto.subtle.exportKey("jwk", key);
|
|
1547
|
+
return { kty, crv, e, n, x, y };
|
|
1548
|
+
}
|
|
1549
|
+
async function generateKeyPair(alg, options) {
|
|
1550
|
+
let algorithm;
|
|
1551
|
+
if (typeof alg !== "string" || alg.length === 0) {
|
|
1552
|
+
throw new TypeError('"alg" must be a non-empty string');
|
|
1553
|
+
}
|
|
1554
|
+
switch (alg) {
|
|
1555
|
+
case "PS256":
|
|
1556
|
+
algorithm = {
|
|
1557
|
+
name: "RSA-PSS",
|
|
1558
|
+
hash: "SHA-256",
|
|
1559
|
+
modulusLength: options?.modulusLength ?? 2048,
|
|
1560
|
+
publicExponent: new Uint8Array([1, 0, 1])
|
|
1561
|
+
};
|
|
1562
|
+
break;
|
|
1563
|
+
case "RS256":
|
|
1564
|
+
algorithm = {
|
|
1565
|
+
name: "RSASSA-PKCS1-v1_5",
|
|
1566
|
+
hash: "SHA-256",
|
|
1567
|
+
modulusLength: options?.modulusLength ?? 2048,
|
|
1568
|
+
publicExponent: new Uint8Array([1, 0, 1])
|
|
1569
|
+
};
|
|
1570
|
+
break;
|
|
1571
|
+
case "ES256":
|
|
1572
|
+
algorithm = { name: "ECDSA", namedCurve: "P-256" };
|
|
1573
|
+
break;
|
|
1574
|
+
case "EdDSA":
|
|
1575
|
+
algorithm = { name: "Ed25519" };
|
|
1576
|
+
break;
|
|
1577
|
+
default:
|
|
1578
|
+
throw new UnsupportedOperationError();
|
|
1579
|
+
}
|
|
1580
|
+
return crypto.subtle.generateKey(algorithm, options?.extractable ?? false, ["sign", "verify"]);
|
|
1581
|
+
}
|
|
1582
|
+
|
|
1583
|
+
// node_modules/@muze-nl/metro-oauth2/src/oauth2.dpop.mjs
|
|
1584
|
+
function dpopmw(options) {
|
|
1585
|
+
assert(options, {
|
|
1586
|
+
site: Required(validURL),
|
|
1587
|
+
authorization_endpoint: Required(validURL),
|
|
1588
|
+
token_endpoint: Required(validURL),
|
|
1589
|
+
dpop_signing_alg_values_supported: Optional([])
|
|
1590
|
+
// this property is unfortunately rarely supported
|
|
1591
|
+
});
|
|
1592
|
+
return async (req, next) => {
|
|
1593
|
+
const keys = await keysStore();
|
|
1594
|
+
let keyInfo = await keys.get(options.site);
|
|
1595
|
+
if (!keyInfo) {
|
|
1596
|
+
let keyPair = await generateKeyPair("ES256");
|
|
1597
|
+
keyInfo = { domain: options.site, keyPair };
|
|
1598
|
+
await keys.set(keyInfo);
|
|
1599
|
+
}
|
|
1600
|
+
const url2 = everything_default.url(req.url);
|
|
1601
|
+
if (req.url.startsWith(options.authorization_endpoint)) {
|
|
1602
|
+
let params2 = req.body;
|
|
1603
|
+
if (params2 instanceof URLSearchParams || params2 instanceof FormData) {
|
|
1604
|
+
params2.set("dpop_jkt", keyInfo.keyPair.publicKey);
|
|
1605
|
+
} else {
|
|
1606
|
+
params2.dpop_jkt = keyInfo.keyPair.publicKey;
|
|
1607
|
+
}
|
|
1608
|
+
} else if (req.url.startsWith(options.token_endpoint)) {
|
|
1609
|
+
const dpopHeader = await DPoP(keyInfo.keyPair, req.url, req.method);
|
|
1610
|
+
req = req.with({
|
|
1611
|
+
headers: {
|
|
1612
|
+
"DPoP": dpopHeader
|
|
1613
|
+
}
|
|
1614
|
+
});
|
|
1615
|
+
} else if (req.headers.has("Authorization")) {
|
|
1616
|
+
const nonce = localStorage.getItem(url2.host + ":nonce") || void 0;
|
|
1617
|
+
const accessToken = req.headers.get("Authorization").split(" ")[1];
|
|
1618
|
+
const dpopHeader = await DPoP(keyInfo.keyPair, req.url, req.method, nonce, accessToken);
|
|
1619
|
+
req = req.with({
|
|
1620
|
+
headers: {
|
|
1621
|
+
"Authorization": "DPoP " + accessToken,
|
|
1622
|
+
"DPoP": dpopHeader
|
|
1623
|
+
}
|
|
1624
|
+
});
|
|
1625
|
+
}
|
|
1626
|
+
let response2 = await next(req);
|
|
1627
|
+
if (response2.headers.get("DPoP-Nonce")) {
|
|
1628
|
+
localStorage.setItem(url2.host + ":nonce", response2.headers.get("DPoP-Nonce"));
|
|
1629
|
+
}
|
|
1630
|
+
return response2;
|
|
1631
|
+
};
|
|
1632
|
+
}
|
|
1633
|
+
|
|
1634
|
+
// node_modules/@muze-nl/metro-oauth2/src/browser.mjs
|
|
1635
|
+
var oauth2 = Object.assign(oauth2_exports, {
|
|
1636
|
+
oauth2mw,
|
|
1637
|
+
mockserver: oauth2_mockserver_exports,
|
|
1638
|
+
discover: oauth2_discovery_exports,
|
|
1639
|
+
tokenstore: tokenStore,
|
|
1640
|
+
dpopmw,
|
|
1641
|
+
keysstore: keysStore
|
|
1642
|
+
});
|
|
1643
|
+
if (!globalThis.metro.oauth2) {
|
|
1644
|
+
globalThis.metro.oauth2 = oauth2;
|
|
1645
|
+
}
|
|
1646
|
+
|
|
1647
|
+
// node_modules/@muze-nl/assert/src/assert.mjs
|
|
1648
|
+
globalThis.assertEnabled = false;
|
|
1649
|
+
function assert2(source, test) {
|
|
1650
|
+
if (globalThis.assertEnabled) {
|
|
1651
|
+
let problems = fails2(source, test);
|
|
1652
|
+
if (problems) {
|
|
1653
|
+
console.error("\u{1F170}\uFE0F Assertions failed because of:", problems, "in this source:", source);
|
|
1654
|
+
throw new Error("Assertions failed", {
|
|
1655
|
+
cause: { problems, source }
|
|
1656
|
+
});
|
|
1657
|
+
}
|
|
1658
|
+
}
|
|
1659
|
+
}
|
|
1660
|
+
function Optional2(pattern) {
|
|
1661
|
+
return function _Optional(data, root, path) {
|
|
1662
|
+
if (typeof data != "undefined" && data != null && typeof pattern != "undefined") {
|
|
1663
|
+
return fails2(data, pattern, root, path);
|
|
1664
|
+
}
|
|
1665
|
+
};
|
|
1666
|
+
}
|
|
1667
|
+
function Required2(pattern) {
|
|
1668
|
+
return function _Required(data, root, path) {
|
|
1669
|
+
if (data == null || typeof data == "undefined") {
|
|
1670
|
+
return error3("data is required", data, pattern || "any value", path);
|
|
1671
|
+
} else if (typeof pattern != "undefined") {
|
|
1672
|
+
return fails2(data, pattern, root, path);
|
|
1673
|
+
} else {
|
|
1674
|
+
return false;
|
|
1675
|
+
}
|
|
1676
|
+
};
|
|
1677
|
+
}
|
|
1678
|
+
function Recommended2(pattern) {
|
|
1679
|
+
return function _Recommended(data, root, path) {
|
|
1680
|
+
if (data == null || typeof data == "undefined") {
|
|
1681
|
+
console.warn("data does not contain recommended value", data, pattern, path);
|
|
1682
|
+
return false;
|
|
1683
|
+
} else {
|
|
1684
|
+
return fails2(data, pattern, root, path);
|
|
1685
|
+
}
|
|
1686
|
+
};
|
|
1687
|
+
}
|
|
1688
|
+
function oneOf2(...patterns) {
|
|
1689
|
+
return function _oneOf(data, root, path) {
|
|
1690
|
+
for (let pattern of patterns) {
|
|
1691
|
+
if (!fails2(data, pattern, root, path)) {
|
|
1692
|
+
return false;
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
return error3("data does not match oneOf patterns", data, patterns, path);
|
|
1696
|
+
};
|
|
1697
|
+
}
|
|
1698
|
+
function anyOf2(...patterns) {
|
|
1699
|
+
return function _anyOf(data, root, path) {
|
|
1700
|
+
if (!Array.isArray(data)) {
|
|
1701
|
+
return error3("data is not an array", data, "anyOf", path);
|
|
1702
|
+
}
|
|
1703
|
+
for (let value of data) {
|
|
1704
|
+
if (oneOf2(...patterns)(value)) {
|
|
1705
|
+
return error3("data does not match anyOf patterns", value, patterns, path);
|
|
1706
|
+
}
|
|
1707
|
+
}
|
|
1708
|
+
return false;
|
|
1709
|
+
};
|
|
1710
|
+
}
|
|
1711
|
+
function allOf(...patterns) {
|
|
1712
|
+
return function _allOf(data, root, path) {
|
|
1713
|
+
let problems = [];
|
|
1714
|
+
for (let pattern of patterns) {
|
|
1715
|
+
problems = problems.concat(fails2(data, pattern, root, path));
|
|
1716
|
+
}
|
|
1717
|
+
problems = problems.filter(Boolean);
|
|
1718
|
+
if (problems.length) {
|
|
1719
|
+
return error3("data does not match all given patterns", data, patterns, path, problems);
|
|
1720
|
+
}
|
|
1721
|
+
};
|
|
1722
|
+
}
|
|
1723
|
+
function validURL2(data, root, path) {
|
|
1724
|
+
try {
|
|
1725
|
+
if (data instanceof URL) {
|
|
1726
|
+
data = data.href;
|
|
1727
|
+
}
|
|
1728
|
+
let url2 = new URL(data);
|
|
1729
|
+
if (url2.href != data) {
|
|
1730
|
+
if (!(url2.href + "/" == data || url2.href == data + "/")) {
|
|
1731
|
+
return error3("data is not a valid url", data, "validURL", path);
|
|
1732
|
+
}
|
|
1733
|
+
}
|
|
1734
|
+
} catch (e) {
|
|
1735
|
+
return error3("data is not a valid url", data, "validURL", path);
|
|
1736
|
+
}
|
|
1737
|
+
}
|
|
1738
|
+
function validEmail(data, root, path) {
|
|
1739
|
+
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(data)) {
|
|
1740
|
+
return error3("data is not a valid email", data, "validEmail", path);
|
|
1741
|
+
}
|
|
1742
|
+
}
|
|
1743
|
+
function instanceOf(constructor) {
|
|
1744
|
+
return function _instanceOf(data, root, path) {
|
|
1745
|
+
if (!(data instanceof constructor)) {
|
|
1746
|
+
return error3("data is not an instanceof pattern", data, constructor, path);
|
|
1747
|
+
}
|
|
1748
|
+
};
|
|
1749
|
+
}
|
|
1750
|
+
function not(pattern) {
|
|
1751
|
+
return function _not(data, root, path) {
|
|
1752
|
+
if (!fails2(data, pattern, root, path)) {
|
|
1753
|
+
return error3("data matches pattern, when required not to", data, pattern, path);
|
|
1754
|
+
}
|
|
1755
|
+
};
|
|
1756
|
+
}
|
|
1757
|
+
function fails2(data, pattern, root, path = "") {
|
|
1758
|
+
if (!root) {
|
|
1759
|
+
root = data;
|
|
1760
|
+
}
|
|
1761
|
+
let problems = [];
|
|
1762
|
+
if (pattern === Boolean) {
|
|
1763
|
+
if (typeof data != "boolean" && !(data instanceof Boolean)) {
|
|
1764
|
+
problems.push(error3("data is not a boolean", data, pattern, path));
|
|
1765
|
+
}
|
|
1766
|
+
} else if (pattern === Number) {
|
|
1767
|
+
if (typeof data != "number" && !(data instanceof Number)) {
|
|
1768
|
+
problems.push(error3("data is not a number", data, pattern, path));
|
|
1769
|
+
}
|
|
1770
|
+
} else if (pattern === String) {
|
|
1771
|
+
if (typeof data != "string" && !(data instanceof String)) {
|
|
1772
|
+
problems.push(error3("data is not a string", data, pattern, path));
|
|
1773
|
+
}
|
|
1774
|
+
if (data == "") {
|
|
1775
|
+
problems.push(error3("data is an empty string, which is not allowed", data, pattern, path));
|
|
1776
|
+
}
|
|
1777
|
+
} else if (pattern instanceof RegExp) {
|
|
1778
|
+
if (Array.isArray(data)) {
|
|
1779
|
+
let index = data.findIndex((element, index2) => fails2(element, pattern, root, path + "[" + index2 + "]"));
|
|
1780
|
+
if (index > -1) {
|
|
1781
|
+
problems.push(error3("data[" + index + "] does not match pattern", data[index], pattern, path + "[" + index + "]"));
|
|
1782
|
+
}
|
|
1783
|
+
} else if (typeof data == "undefined") {
|
|
1784
|
+
problems.push(error3("data is undefined, should match pattern", data, pattern, path));
|
|
1785
|
+
} else if (!pattern.test(data)) {
|
|
1786
|
+
problems.push(error3("data does not match pattern", data, pattern, path));
|
|
1787
|
+
}
|
|
1788
|
+
} else if (pattern instanceof Function) {
|
|
1789
|
+
let problem = pattern(data, root, path);
|
|
1790
|
+
if (problem) {
|
|
1791
|
+
if (Array.isArray(problem)) {
|
|
1792
|
+
problems = problems.concat(problem);
|
|
1793
|
+
} else {
|
|
1794
|
+
problems.push(problem);
|
|
1795
|
+
}
|
|
1796
|
+
}
|
|
1797
|
+
} else if (Array.isArray(pattern)) {
|
|
1798
|
+
if (!Array.isArray(data)) {
|
|
1799
|
+
problems.push(error3("data is not an array", data, [], path));
|
|
1800
|
+
}
|
|
1801
|
+
for (let p2 of pattern) {
|
|
1802
|
+
for (let index of data.keys()) {
|
|
1803
|
+
let problem = fails2(data[index], p2, root, path + "[" + index + "]");
|
|
1804
|
+
if (Array.isArray(problem)) {
|
|
1805
|
+
problems = problems.concat(problem);
|
|
1806
|
+
} else if (problem) {
|
|
1807
|
+
problems.push(problem);
|
|
1808
|
+
}
|
|
1809
|
+
}
|
|
1810
|
+
}
|
|
1811
|
+
} else if (pattern && typeof pattern == "object") {
|
|
1812
|
+
if (Array.isArray(data)) {
|
|
1813
|
+
let index = data.findIndex((element, index2) => fails2(element, pattern, root, path + "[" + index2 + "]"));
|
|
1814
|
+
if (index > -1) {
|
|
1815
|
+
problems.push(error3("data[" + index + "] does not match pattern", data[index], pattern, path + "[" + index + "]"));
|
|
1816
|
+
}
|
|
1817
|
+
} else if (!data || typeof data != "object") {
|
|
1818
|
+
problems.push(error3("data is not an object, pattern is", data, pattern, path));
|
|
1819
|
+
} else {
|
|
1820
|
+
if (data instanceof URLSearchParams) {
|
|
1821
|
+
data = Object.fromEntries(data);
|
|
1822
|
+
}
|
|
1823
|
+
if (pattern instanceof Function) {
|
|
1824
|
+
let result = fails2(data, pattern, root, path);
|
|
1825
|
+
if (result) {
|
|
1826
|
+
problems = problems.concat(result);
|
|
1827
|
+
}
|
|
1828
|
+
} else {
|
|
1829
|
+
for (const [wKey, wVal] of Object.entries(pattern)) {
|
|
1830
|
+
let result = fails2(data[wKey], wVal, root, path + "." + wKey);
|
|
1831
|
+
if (result) {
|
|
1832
|
+
problems = problems.concat(result);
|
|
1833
|
+
}
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1837
|
+
} else {
|
|
1838
|
+
if (pattern != data) {
|
|
1839
|
+
problems.push(error3("data and pattern are not equal", data, pattern, path));
|
|
1840
|
+
}
|
|
1841
|
+
}
|
|
1842
|
+
if (problems.length) {
|
|
1843
|
+
return problems;
|
|
1822
1844
|
}
|
|
1845
|
+
return false;
|
|
1823
1846
|
}
|
|
1824
|
-
function
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
return "EdDSA";
|
|
1834
|
-
default:
|
|
1835
|
-
throw new UnsupportedOperationError("unsupported CryptoKey algorithm name");
|
|
1847
|
+
function error3(message, found, expected, path, problems) {
|
|
1848
|
+
let result = {
|
|
1849
|
+
message,
|
|
1850
|
+
found,
|
|
1851
|
+
expected,
|
|
1852
|
+
path
|
|
1853
|
+
};
|
|
1854
|
+
if (problems) {
|
|
1855
|
+
result.problems = problems;
|
|
1836
1856
|
}
|
|
1857
|
+
return result;
|
|
1837
1858
|
}
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
}
|
|
1844
|
-
function isPublicKey(key) {
|
|
1845
|
-
return isCryptoKey(key) && key.type === "public";
|
|
1846
|
-
}
|
|
1847
|
-
function epochTime() {
|
|
1848
|
-
return Math.floor(Date.now() / 1e3);
|
|
1849
|
-
}
|
|
1850
|
-
async function DPoP(keypair, htu, htm, nonce, accessToken, additional) {
|
|
1851
|
-
const privateKey = keypair?.privateKey;
|
|
1852
|
-
const publicKey = keypair?.publicKey;
|
|
1853
|
-
if (!isPrivateKey(privateKey)) {
|
|
1854
|
-
throw new TypeError('"keypair.privateKey" must be a private CryptoKey');
|
|
1855
|
-
}
|
|
1856
|
-
if (!isPublicKey(publicKey)) {
|
|
1857
|
-
throw new TypeError('"keypair.publicKey" must be a public CryptoKey');
|
|
1858
|
-
}
|
|
1859
|
-
if (publicKey.extractable !== true) {
|
|
1860
|
-
throw new TypeError('"keypair.publicKey.extractable" must be true');
|
|
1861
|
-
}
|
|
1862
|
-
if (typeof htu !== "string") {
|
|
1863
|
-
throw new TypeError('"htu" must be a string');
|
|
1864
|
-
}
|
|
1865
|
-
if (typeof htm !== "string") {
|
|
1866
|
-
throw new TypeError('"htm" must be a string');
|
|
1867
|
-
}
|
|
1868
|
-
if (nonce !== void 0 && typeof nonce !== "string") {
|
|
1869
|
-
throw new TypeError('"nonce" must be a string or undefined');
|
|
1870
|
-
}
|
|
1871
|
-
if (accessToken !== void 0 && typeof accessToken !== "string") {
|
|
1872
|
-
throw new TypeError('"accessToken" must be a string or undefined');
|
|
1873
|
-
}
|
|
1874
|
-
if (additional !== void 0 && (typeof additional !== "object" || additional === null || Array.isArray(additional))) {
|
|
1875
|
-
throw new TypeError('"additional" must be an object');
|
|
1859
|
+
|
|
1860
|
+
// src/oidc.util.mjs
|
|
1861
|
+
var MustHave = (...options) => (value, root) => {
|
|
1862
|
+
if (options.filter((o) => root.hasOwnKey(o)).length > 0) {
|
|
1863
|
+
return false;
|
|
1876
1864
|
}
|
|
1877
|
-
return
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
jti: randomBytes(),
|
|
1885
|
-
htm,
|
|
1886
|
-
nonce,
|
|
1887
|
-
htu,
|
|
1888
|
-
ath: accessToken ? b64u(await crypto.subtle.digest("SHA-256", buf(accessToken))) : void 0
|
|
1889
|
-
}, privateKey);
|
|
1890
|
-
}
|
|
1891
|
-
async function publicJwk(key) {
|
|
1892
|
-
const { kty, e, n, x, y, crv } = await crypto.subtle.exportKey("jwk", key);
|
|
1893
|
-
return { kty, crv, e, n, x, y };
|
|
1894
|
-
}
|
|
1895
|
-
async function generateKeyPair(alg, options) {
|
|
1896
|
-
let algorithm;
|
|
1897
|
-
if (typeof alg !== "string" || alg.length === 0) {
|
|
1898
|
-
throw new TypeError('"alg" must be a non-empty string');
|
|
1865
|
+
return error3("root data must have all of", root, options);
|
|
1866
|
+
};
|
|
1867
|
+
var MustInclude = (...options) => (value) => {
|
|
1868
|
+
if (Array.isArray(value) && options.filter((o) => !value.includes(o)).length == 0) {
|
|
1869
|
+
return false;
|
|
1870
|
+
} else {
|
|
1871
|
+
return error3("data must be an array which includes", value, options);
|
|
1899
1872
|
}
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1873
|
+
};
|
|
1874
|
+
var validJWA = [
|
|
1875
|
+
"HS256",
|
|
1876
|
+
"HS384",
|
|
1877
|
+
"HS512",
|
|
1878
|
+
"RS256",
|
|
1879
|
+
"RS384",
|
|
1880
|
+
"RS512",
|
|
1881
|
+
"ES256",
|
|
1882
|
+
"ES384",
|
|
1883
|
+
"ES512"
|
|
1884
|
+
];
|
|
1885
|
+
var validAuthMethods2 = [
|
|
1886
|
+
"client_secret_post",
|
|
1887
|
+
"client_secret_basic",
|
|
1888
|
+
"client_secret_jwt",
|
|
1889
|
+
"private_key_jwt"
|
|
1890
|
+
];
|
|
1891
|
+
|
|
1892
|
+
// src/oidc.discovery.mjs
|
|
1893
|
+
async function oidcDiscovery(options = {}) {
|
|
1894
|
+
assert2(options, {
|
|
1895
|
+
client: Optional2(instanceOf(everything_default.client().constructor)),
|
|
1896
|
+
issuer: Required2(validURL2)
|
|
1897
|
+
});
|
|
1898
|
+
const defaultOptions = {
|
|
1899
|
+
client: everything_default.client().with(thrower()).with(jsonmw()),
|
|
1900
|
+
requireDynamicRegistration: false
|
|
1901
|
+
};
|
|
1902
|
+
options = Object.assign({}, defaultOptions, options);
|
|
1903
|
+
const TestSucceeded = false;
|
|
1904
|
+
function MustUseHTTPS(url2) {
|
|
1905
|
+
return TestSucceeded;
|
|
1925
1906
|
}
|
|
1926
|
-
|
|
1907
|
+
const openid_provider_metadata = {
|
|
1908
|
+
issuer: Required2(allOf(options.issuer, MustUseHTTPS)),
|
|
1909
|
+
authorization_endpoint: Required2(validURL2),
|
|
1910
|
+
token_endpoint: Required2(validURL2),
|
|
1911
|
+
userinfo_endpoint: Recommended2(validURL2),
|
|
1912
|
+
// todo: test for https protocol
|
|
1913
|
+
jwks_uri: Required2(validURL2),
|
|
1914
|
+
registration_endpoint: options.requireDynamicRegistration ? Required2(validURL2) : Recommended2(validURL2),
|
|
1915
|
+
scopes_supported: Recommended2(MustInclude("openid")),
|
|
1916
|
+
response_types_supported: options.requireDynamicRegistration ? Required2(MustInclude("code", "id_token", "id_token token")) : Required2([]),
|
|
1917
|
+
response_modes_supported: Optional2([]),
|
|
1918
|
+
grant_types_supported: options.requireDynamicRegistration ? Optional2(MustInclude("authorization_code")) : Optional2([]),
|
|
1919
|
+
acr_values_supported: Optional2([]),
|
|
1920
|
+
subject_types_supported: Required2([]),
|
|
1921
|
+
id_token_signing_alg_values_supported: Required2(MustInclude("RS256")),
|
|
1922
|
+
id_token_encryption_alg_values_supported: Optional2([]),
|
|
1923
|
+
id_token_encryption_enc_values_supported: Optional2([]),
|
|
1924
|
+
userinfo_signing_alg_values_supported: Optional2([]),
|
|
1925
|
+
userinfo_encryption_alg_values_supported: Optional2([]),
|
|
1926
|
+
userinfo_encryption_enc_values_supported: Optional2([]),
|
|
1927
|
+
request_object_signing_alg_values_supported: Optional2(MustInclude("RS256")),
|
|
1928
|
+
// not testing for 'none'
|
|
1929
|
+
request_object_encryption_alg_values_supported: Optional2([]),
|
|
1930
|
+
request_object_encryption_enc_values_supported: Optional2([]),
|
|
1931
|
+
token_endpoint_auth_methods_supported: Optional2(anyOf2(...validAuthMethods2)),
|
|
1932
|
+
token_endpoint_auth_signing_alg_values_supported: Optional2(MustInclude("RS256"), not(MustInclude("none"))),
|
|
1933
|
+
display_values_supported: Optional2(anyOf2("page", "popup", "touch", "wap")),
|
|
1934
|
+
claim_types_supported: Optional2(anyOf2("normal", "aggregated", "distributed")),
|
|
1935
|
+
claims_supported: Recommended2([]),
|
|
1936
|
+
service_documentation: Optional2(validURL2),
|
|
1937
|
+
claims_locales_supported: Optional2([]),
|
|
1938
|
+
ui_locales_supported: Optional2([]),
|
|
1939
|
+
claims_parameter_supported: Optional2(Boolean),
|
|
1940
|
+
request_parameter_supported: Optional2(Boolean),
|
|
1941
|
+
request_uri_parameter_supported: Optional2(Boolean),
|
|
1942
|
+
op_policy_uri: Optional2(validURL2),
|
|
1943
|
+
op_tos_uri: Optional2(validURL2)
|
|
1944
|
+
};
|
|
1945
|
+
const configURL = everything_default.url(options.issuer, ".well-known/openid-configuration");
|
|
1946
|
+
const response2 = await options.client.get(
|
|
1947
|
+
// https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationRequest
|
|
1948
|
+
// note: this allows path components in the options.issuer url
|
|
1949
|
+
configURL
|
|
1950
|
+
);
|
|
1951
|
+
const openid_config = response2.data;
|
|
1952
|
+
assert2(openid_config, openid_provider_metadata);
|
|
1953
|
+
assert2(openid_config.issuer, options.issuer);
|
|
1954
|
+
return openid_config;
|
|
1927
1955
|
}
|
|
1928
1956
|
|
|
1929
|
-
//
|
|
1930
|
-
function
|
|
1957
|
+
// src/oidc.register.mjs
|
|
1958
|
+
async function register(options) {
|
|
1959
|
+
const openid_client_metadata = {
|
|
1960
|
+
redirect_uris: Required2([validURL2]),
|
|
1961
|
+
response_types: Optional2([]),
|
|
1962
|
+
grant_types: Optional2(anyOf2("authorization_code", "refresh_token")),
|
|
1963
|
+
//TODO: match response_types with grant_types
|
|
1964
|
+
application_type: Optional2(oneOf2("native", "web")),
|
|
1965
|
+
contacts: Optional2([validEmail]),
|
|
1966
|
+
client_name: Optional2(String),
|
|
1967
|
+
logo_uri: Optional2(validURL2),
|
|
1968
|
+
client_uri: Optional2(validURL2),
|
|
1969
|
+
policy_uri: Optional2(validURL2),
|
|
1970
|
+
tos_uri: Optional2(validURL2),
|
|
1971
|
+
jwks_uri: Optional2(validURL2, not(MustHave("jwks"))),
|
|
1972
|
+
jwks: Optional2(validURL2, not(MustHave("jwks_uri"))),
|
|
1973
|
+
sector_identifier_uri: Optional2(validURL2),
|
|
1974
|
+
subject_type: Optional2(String),
|
|
1975
|
+
id_token_signed_response_alg: Optional2(oneOf2(...validJWA)),
|
|
1976
|
+
id_token_encrypted_response_alg: Optional2(oneOf2(...validJWA)),
|
|
1977
|
+
id_token_encrypted_response_enc: Optional2(oneOf2(...validJWA), MustHave("id_token_encrypted_response_alg")),
|
|
1978
|
+
userinfo_signed_response_alg: Optional2(oneOf2(...validJWA)),
|
|
1979
|
+
userinfo_encrypted_response_alg: Optional2(oneOf2(...validJWA)),
|
|
1980
|
+
userinfo_encrypted_response_enc: Optional2(oneOf2(...validJWA), MustHave("userinfo_encrypted_response_alg")),
|
|
1981
|
+
request_object_signing_alg: Optional2(oneOf2(...validJWA)),
|
|
1982
|
+
request_object_encryption_alg: Optional2(oneOf2(...validJWA)),
|
|
1983
|
+
request_object_encryption_enc: Optional2(oneOf2(...validJWA)),
|
|
1984
|
+
token_endpoint_auth_method: Optional2(oneOf2(...validAuthMethods2)),
|
|
1985
|
+
token_endpoint_auth_signing_alg: Optional2(oneOf2(...validJWA)),
|
|
1986
|
+
default_max_age: Optional2(Number),
|
|
1987
|
+
require_auth_time: Optional2(Boolean),
|
|
1988
|
+
default_acr_values: Optional2([String]),
|
|
1989
|
+
initiate_login_uri: Optional2([validURL2]),
|
|
1990
|
+
request_uris: Optional2([validURL2])
|
|
1991
|
+
};
|
|
1931
1992
|
assert2(options, {
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
// dpop_signing_alg_values_supported: Required([]) // this property is unfortunately rarely supported
|
|
1993
|
+
client: Optional2(instanceOf(everything_default.client().constructor)),
|
|
1994
|
+
registration_endpoint: validURL2,
|
|
1995
|
+
client_info: openid_client_metadata
|
|
1936
1996
|
});
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
let keyInfo = await keys.get(options.site);
|
|
1940
|
-
if (!keyInfo) {
|
|
1941
|
-
let keyPair = await generateKeyPair("ES256");
|
|
1942
|
-
keyInfo = { domain: options.site, keyPair };
|
|
1943
|
-
await keys.set(keyInfo);
|
|
1944
|
-
}
|
|
1945
|
-
const url2 = everything_default.url(req.url);
|
|
1946
|
-
if (req.url.startsWith(options.authorization_endpoint) || req.url.startsWith(options.token_endpoint)) {
|
|
1947
|
-
const dpopHeader = await DPoP(keyInfo.keyPair, req.url, req.method);
|
|
1948
|
-
req = req.with({
|
|
1949
|
-
headers: {
|
|
1950
|
-
"DPoP": dpopHeader
|
|
1951
|
-
}
|
|
1952
|
-
});
|
|
1953
|
-
} else if (req.headers.has("Authorization")) {
|
|
1954
|
-
const nonce = localStorage.getItem(url2.host + ":nonce") || void 0;
|
|
1955
|
-
const accessToken = req.headers.get("Authorization").split(" ")[1];
|
|
1956
|
-
const dpopHeader = await DPoP(keyInfo.keyPair, req.url, req.method, nonce, accessToken);
|
|
1957
|
-
req = req.with({
|
|
1958
|
-
headers: {
|
|
1959
|
-
"Authorization": "DPoP " + accessToken,
|
|
1960
|
-
//solidcommunity server sends accesstoken with type Bearer
|
|
1961
|
-
"DPoP": dpopHeader
|
|
1962
|
-
}
|
|
1963
|
-
});
|
|
1964
|
-
}
|
|
1965
|
-
let response2 = await next(req);
|
|
1966
|
-
if (response2.headers.get("DPoP-Nonce")) {
|
|
1967
|
-
localStorage.setItem(url2.host + ":nonce", response2.headers.get("DPoP-Nonce"));
|
|
1968
|
-
}
|
|
1969
|
-
return response2;
|
|
1997
|
+
const defaultOptions = {
|
|
1998
|
+
client: everything_default.client().with(thrower()).with(jsonmw())
|
|
1970
1999
|
};
|
|
2000
|
+
options = Object.assign({}, defaultOptions, options);
|
|
2001
|
+
let response2 = await options.client.post(options.registration_endpoint, {
|
|
2002
|
+
body: options.client_info
|
|
2003
|
+
});
|
|
2004
|
+
let info = response2.data;
|
|
2005
|
+
if (!info.client_id || !info.client_secret) {
|
|
2006
|
+
throw everything_default.metroError("metro.oidc: Error: dynamic registration of client failed, no client_id or client_secret returned", response2);
|
|
2007
|
+
}
|
|
2008
|
+
options.client_info = Object.assign(options.client_info, info);
|
|
2009
|
+
return options.client_info;
|
|
1971
2010
|
}
|
|
1972
2011
|
|
|
1973
|
-
// node_modules/@muze-nl/metro-oauth2/src/browser.mjs
|
|
1974
|
-
var oauth2 = Object.assign(oauth2mw, oauth2_exports, {
|
|
1975
|
-
mockserver: oauth2_mockserver_exports,
|
|
1976
|
-
discovery: oauth2_discovery_exports,
|
|
1977
|
-
tokenstore: tokenStore,
|
|
1978
|
-
dpopmw,
|
|
1979
|
-
keysstore: keysStore
|
|
1980
|
-
});
|
|
1981
|
-
globalThis.oauth2 = oauth2;
|
|
1982
|
-
var browser_default = oauth2;
|
|
1983
|
-
|
|
1984
2012
|
// src/oidc.store.mjs
|
|
1985
2013
|
function oidcStore(site) {
|
|
1986
2014
|
let store;
|
|
@@ -2004,17 +2032,24 @@
|
|
|
2004
2032
|
// src/oidcmw.mjs
|
|
2005
2033
|
function oidcmw(options = {}) {
|
|
2006
2034
|
const defaultOptions = {
|
|
2007
|
-
client:
|
|
2008
|
-
force_authorization: false
|
|
2035
|
+
client: client(),
|
|
2036
|
+
force_authorization: false,
|
|
2037
|
+
use_dpop: true,
|
|
2038
|
+
authorize_callback: async (url2) => {
|
|
2039
|
+
if (window.location.href != url2.href) {
|
|
2040
|
+
window.location.replace(url2.href);
|
|
2041
|
+
}
|
|
2042
|
+
return false;
|
|
2043
|
+
}
|
|
2009
2044
|
};
|
|
2010
2045
|
options = Object.assign({}, defaultOptions, options);
|
|
2011
|
-
|
|
2012
|
-
client:
|
|
2046
|
+
assert2(options, {
|
|
2047
|
+
client: Required2(instanceOf(client().constructor)),
|
|
2013
2048
|
// required because it is set in defaultOptions
|
|
2014
|
-
client_info:
|
|
2015
|
-
issuer:
|
|
2016
|
-
oauth2:
|
|
2017
|
-
openid_configuration:
|
|
2049
|
+
client_info: Required2(),
|
|
2050
|
+
issuer: Required2(validURL2),
|
|
2051
|
+
oauth2: Optional2({}),
|
|
2052
|
+
openid_configuration: Optional2()
|
|
2018
2053
|
});
|
|
2019
2054
|
if (!options.store) {
|
|
2020
2055
|
options.store = oidcStore(options.issuer);
|
|
@@ -2046,9 +2081,9 @@
|
|
|
2046
2081
|
options.store.set("openid_configuration", options.openid_configuration);
|
|
2047
2082
|
}
|
|
2048
2083
|
if (!options.client_info?.client_id) {
|
|
2049
|
-
|
|
2084
|
+
assert2(options.client_info?.client_name, Required2());
|
|
2050
2085
|
if (!options.openid_configuration.registration_endpoint) {
|
|
2051
|
-
throw
|
|
2086
|
+
throw metroError("metro.oidcmw: Error: issuer " + options.issuer + " does not support dynamic client registration, but you haven't specified a client_id");
|
|
2052
2087
|
}
|
|
2053
2088
|
options.client_info = await register({
|
|
2054
2089
|
registration_endpoint: options.openid_configuration.registration_endpoint,
|
|
@@ -2062,6 +2097,7 @@
|
|
|
2062
2097
|
site: options.issuer,
|
|
2063
2098
|
client: options.client,
|
|
2064
2099
|
force_authorization: true,
|
|
2100
|
+
authorize_callback: options.authorize_callback,
|
|
2065
2101
|
oauth2_configuration: {
|
|
2066
2102
|
client_id: options.client_info.client_id,
|
|
2067
2103
|
client_secret: options.client_info.client_secret,
|
|
@@ -2078,48 +2114,61 @@
|
|
|
2078
2114
|
}
|
|
2079
2115
|
//...
|
|
2080
2116
|
);
|
|
2081
|
-
const dpopOptions = {
|
|
2082
|
-
site: options.issuer,
|
|
2083
|
-
authorization_endpoint: options.openid_configuration.authorization_endpoint,
|
|
2084
|
-
token_endpoint: options.openid_configuration.token_endpoint,
|
|
2085
|
-
dpop_signing_alg_values_supported: options.openid_configuration.dpop_signing_alg_values_supported
|
|
2086
|
-
};
|
|
2087
2117
|
const storeIdToken = async (req2, next2) => {
|
|
2088
2118
|
const res2 = await next2(req2);
|
|
2089
2119
|
const contentType = res2.headers.get("content-type");
|
|
2090
2120
|
if (contentType?.startsWith("application/json")) {
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2121
|
+
let id_token = res2.data?.id_token;
|
|
2122
|
+
if (!id_token) {
|
|
2123
|
+
const res22 = res2.clone();
|
|
2124
|
+
try {
|
|
2125
|
+
let data = await res22.json();
|
|
2126
|
+
if (data && data.id_token) {
|
|
2127
|
+
id_token = data.id_token;
|
|
2128
|
+
}
|
|
2129
|
+
} catch (e) {
|
|
2096
2130
|
}
|
|
2097
|
-
}
|
|
2131
|
+
}
|
|
2132
|
+
if (id_token) {
|
|
2133
|
+
options.store.set("id_token", id_token);
|
|
2098
2134
|
}
|
|
2099
2135
|
}
|
|
2100
2136
|
return res2;
|
|
2101
2137
|
};
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2138
|
+
let oauth2client = options.client.with(options.issuer).with(storeIdToken);
|
|
2139
|
+
if (options.use_dpop) {
|
|
2140
|
+
const dpopOptions = {
|
|
2141
|
+
site: options.issuer,
|
|
2142
|
+
authorization_endpoint: options.openid_configuration.authorization_endpoint,
|
|
2143
|
+
token_endpoint: options.openid_configuration.token_endpoint,
|
|
2144
|
+
dpop_signing_alg_values_supported: options.openid_configuration.dpop_signing_alg_values_supported
|
|
2145
|
+
};
|
|
2146
|
+
oauth2client = oauth2client.with(dpopmw(dpopOptions));
|
|
2147
|
+
oauth2Options.client = oauth2client;
|
|
2148
|
+
}
|
|
2149
|
+
oauth2client = oauth2client.with(oauth2mw(oauth2Options));
|
|
2105
2150
|
res = await oauth2client.fetch(req);
|
|
2106
2151
|
return res;
|
|
2107
2152
|
};
|
|
2108
2153
|
}
|
|
2109
2154
|
function isRedirected2() {
|
|
2110
|
-
return
|
|
2155
|
+
return isRedirected();
|
|
2111
2156
|
}
|
|
2112
2157
|
function idToken(options) {
|
|
2113
2158
|
return options.store.get("id_token");
|
|
2114
2159
|
}
|
|
2115
2160
|
|
|
2116
2161
|
// src/browser.mjs
|
|
2117
|
-
var oidc =
|
|
2162
|
+
var oidc = {
|
|
2163
|
+
oidcmw,
|
|
2118
2164
|
discover: oidcDiscovery,
|
|
2119
2165
|
register,
|
|
2120
2166
|
isRedirected: isRedirected2,
|
|
2121
2167
|
idToken
|
|
2122
|
-
}
|
|
2123
|
-
globalThis.oidc
|
|
2168
|
+
};
|
|
2169
|
+
if (!globalThis.metro.oidc) {
|
|
2170
|
+
globalThis.metro.oidc = oidc;
|
|
2171
|
+
}
|
|
2172
|
+
var browser_default2 = oidc;
|
|
2124
2173
|
})();
|
|
2125
2174
|
//# sourceMappingURL=browser.js.map
|