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