@axa-fr/oidc-client-service-worker 7.29.8 → 7.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +64 -0
- package/dist/OidcServiceWorker.d.ts +2 -1
- package/dist/OidcServiceWorker.d.ts.map +1 -0
- package/dist/OidcServiceWorker.js +995 -765
- package/dist/OidcServiceWorker.js.map +1 -1
- package/dist/constants.d.ts.map +1 -0
- package/dist/crypto.d.ts.map +1 -0
- package/dist/dpop.d.ts.map +1 -0
- package/dist/jwt.d.ts.map +1 -0
- package/dist/oidcConfig.d.ts.map +1 -0
- package/dist/protocol.d.ts +140 -2
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +50 -2
- package/dist/protocol.js.map +1 -1
- package/dist/resource.d.ts +22 -0
- package/dist/resource.d.ts.map +1 -0
- package/dist/tokenContexts.d.ts +5 -0
- package/dist/tokenContexts.d.ts.map +1 -0
- package/dist/{src/types.d.ts → types.d.ts} +26 -1
- package/dist/types.d.ts.map +1 -0
- package/dist/utils/codeVerifier.d.ts.map +1 -0
- package/dist/{src/utils → utils}/domains.d.ts +2 -2
- package/dist/utils/domains.d.ts.map +1 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/normalizeUrl.d.ts.map +1 -0
- package/dist/utils/serializeHeaders.d.ts.map +1 -0
- package/dist/utils/shouldBypassDestination.d.ts.map +1 -0
- package/dist/utils/sleep.d.ts.map +1 -0
- package/dist/utils/strings.d.ts.map +1 -0
- package/dist/{src/utils → utils}/tokens.d.ts +12 -3
- package/dist/utils/tokens.d.ts.map +1 -0
- package/dist/utils/waitForValidTokens.d.ts.map +1 -0
- package/dist/version.d.ts +3 -0
- package/dist/version.d.ts.map +1 -0
- package/package.json +3 -2
- package/src/OidcServiceWorker.ts +290 -34
- package/src/__tests__/jwt.spec.ts +17 -0
- package/src/__tests__/resource.spec.ts +98 -0
- package/src/__tests__/workerResource.spec.ts +919 -0
- package/src/jwt.ts +4 -1
- package/src/oidcConfig.ts +2 -1
- package/src/protocol.ts +16 -1
- package/src/resource.ts +104 -0
- package/src/tokenContexts.ts +39 -0
- package/src/types.ts +27 -1
- package/src/utils/domains.ts +20 -2
- package/src/utils/tokens.ts +155 -8
- package/src/version.ts +1 -1
- package/dist/src/OidcServiceWorker.d.ts +0 -2
- package/dist/src/OidcServiceWorker.d.ts.map +0 -1
- package/dist/src/__tests__/jwt.spec.d.ts +0 -2
- package/dist/src/__tests__/jwt.spec.d.ts.map +0 -1
- package/dist/src/__tests__/oidcConfig.spec.d.ts +0 -2
- package/dist/src/__tests__/oidcConfig.spec.d.ts.map +0 -1
- package/dist/src/__tests__/protocol.spec.d.ts +0 -2
- package/dist/src/__tests__/protocol.spec.d.ts.map +0 -1
- package/dist/src/constants.d.ts.map +0 -1
- package/dist/src/crypto.d.ts.map +0 -1
- package/dist/src/dpop.d.ts.map +0 -1
- package/dist/src/jwt.d.ts.map +0 -1
- package/dist/src/oidcConfig.d.ts.map +0 -1
- package/dist/src/protocol.d.ts +0 -134
- package/dist/src/protocol.d.ts.map +0 -1
- package/dist/src/types.d.ts.map +0 -1
- package/dist/src/utils/__tests__/codeVerifier.spec.d.ts +0 -2
- package/dist/src/utils/__tests__/codeVerifier.spec.d.ts.map +0 -1
- package/dist/src/utils/__tests__/domains.spec.d.ts +0 -2
- package/dist/src/utils/__tests__/domains.spec.d.ts.map +0 -1
- package/dist/src/utils/__tests__/normalizeUrl.spec.d.ts +0 -2
- package/dist/src/utils/__tests__/normalizeUrl.spec.d.ts.map +0 -1
- package/dist/src/utils/__tests__/serializeHeaders.spec.d.ts +0 -2
- package/dist/src/utils/__tests__/serializeHeaders.spec.d.ts.map +0 -1
- package/dist/src/utils/__tests__/shouldBypassDestination.spec.d.ts +0 -2
- package/dist/src/utils/__tests__/shouldBypassDestination.spec.d.ts.map +0 -1
- package/dist/src/utils/__tests__/strings.spec.d.ts +0 -2
- package/dist/src/utils/__tests__/strings.spec.d.ts.map +0 -1
- package/dist/src/utils/__tests__/testHelper.d.ts +0 -58
- package/dist/src/utils/__tests__/testHelper.d.ts.map +0 -1
- package/dist/src/utils/__tests__/tokens.spec.d.ts +0 -2
- package/dist/src/utils/__tests__/tokens.spec.d.ts.map +0 -1
- package/dist/src/utils/__tests__/waitForValidTokens.spec.d.ts +0 -2
- package/dist/src/utils/__tests__/waitForValidTokens.spec.d.ts.map +0 -1
- package/dist/src/utils/codeVerifier.d.ts.map +0 -1
- package/dist/src/utils/domains.d.ts.map +0 -1
- package/dist/src/utils/index.d.ts.map +0 -1
- package/dist/src/utils/normalizeUrl.d.ts.map +0 -1
- package/dist/src/utils/serializeHeaders.d.ts.map +0 -1
- package/dist/src/utils/shouldBypassDestination.d.ts.map +0 -1
- package/dist/src/utils/sleep.d.ts.map +0 -1
- package/dist/src/utils/strings.d.ts.map +0 -1
- package/dist/src/utils/tokens.d.ts.map +0 -1
- package/dist/src/utils/waitForValidTokens.d.ts.map +0 -1
- package/dist/src/version.d.ts +0 -3
- package/dist/src/version.d.ts.map +0 -1
- /package/dist/{src/constants.d.ts → constants.d.ts} +0 -0
- /package/dist/{src/crypto.d.ts → crypto.d.ts} +0 -0
- /package/dist/{src/dpop.d.ts → dpop.d.ts} +0 -0
- /package/dist/{src/jwt.d.ts → jwt.d.ts} +0 -0
- /package/dist/{src/oidcConfig.d.ts → oidcConfig.d.ts} +0 -0
- /package/dist/{src/utils → utils}/codeVerifier.d.ts +0 -0
- /package/dist/{src/utils → utils}/index.d.ts +0 -0
- /package/dist/{src/utils → utils}/normalizeUrl.d.ts +0 -0
- /package/dist/{src/utils → utils}/serializeHeaders.d.ts +0 -0
- /package/dist/{src/utils → utils}/shouldBypassDestination.d.ts +0 -0
- /package/dist/{src/utils → utils}/sleep.d.ts +0 -0
- /package/dist/{src/utils → utils}/strings.d.ts +0 -0
- /package/dist/{src/utils → utils}/waitForValidTokens.d.ts +0 -0
|
@@ -1,819 +1,1049 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
var
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
//#
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
function binToUrlBase64(bin) {
|
|
20
|
-
return btoa(bin).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+/g, "");
|
|
21
|
-
}
|
|
22
|
-
function utf8ToBinaryString(str) {
|
|
23
|
-
return encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function(match, p1) {
|
|
24
|
-
return String.fromCharCode(parseInt(p1, 16));
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
var uint8ToUrlBase64 = (uint8) => {
|
|
28
|
-
let bin = "";
|
|
29
|
-
uint8.forEach(function(code) {
|
|
30
|
-
bin += String.fromCharCode(code);
|
|
31
|
-
});
|
|
32
|
-
return binToUrlBase64(bin);
|
|
33
|
-
};
|
|
34
|
-
function strToUrlBase64(str) {
|
|
35
|
-
return binToUrlBase64(utf8ToBinaryString(str));
|
|
36
|
-
}
|
|
37
|
-
var defaultDemonstratingProofOfPossessionConfiguration = {
|
|
38
|
-
importKeyAlgorithm: {
|
|
39
|
-
name: "ECDSA",
|
|
40
|
-
namedCurve: "P-256",
|
|
41
|
-
hash: { name: "ES256" }
|
|
42
|
-
},
|
|
43
|
-
signAlgorithm: {
|
|
44
|
-
name: "ECDSA",
|
|
45
|
-
hash: { name: "SHA-256" }
|
|
46
|
-
},
|
|
47
|
-
generateKeyAlgorithm: {
|
|
48
|
-
name: "ECDSA",
|
|
49
|
-
namedCurve: "P-256"
|
|
50
|
-
},
|
|
51
|
-
digestAlgorithm: { name: "SHA-256" },
|
|
52
|
-
jwtHeaderAlgorithm: "ES256"
|
|
53
|
-
};
|
|
54
|
-
var sign = (w) => async (jwk, headers, claims, demonstratingProofOfPossessionConfiguration, jwtHeaderType = "dpop+jwt") => {
|
|
55
|
-
jwk = Object.assign({}, jwk);
|
|
56
|
-
headers.typ = jwtHeaderType;
|
|
57
|
-
headers.alg = demonstratingProofOfPossessionConfiguration.jwtHeaderAlgorithm;
|
|
58
|
-
switch (headers.alg) {
|
|
59
|
-
case "ES256":
|
|
60
|
-
headers.jwk = {
|
|
61
|
-
kty: jwk.kty,
|
|
62
|
-
crv: jwk.crv,
|
|
63
|
-
x: jwk.x,
|
|
64
|
-
y: jwk.y
|
|
65
|
-
};
|
|
66
|
-
break;
|
|
67
|
-
case "RS256":
|
|
68
|
-
headers.jwk = {
|
|
69
|
-
kty: jwk.kty,
|
|
70
|
-
n: jwk.n,
|
|
71
|
-
e: jwk.e,
|
|
72
|
-
kid: headers.kid
|
|
73
|
-
};
|
|
74
|
-
break;
|
|
75
|
-
default: throw new Error("Unknown or not implemented JWS algorithm");
|
|
1
|
+
(function() {
|
|
2
|
+
//#region src/constants.ts
|
|
3
|
+
var scriptFilename = "OidcTrustedDomains.js";
|
|
4
|
+
var TOKEN = {
|
|
5
|
+
REFRESH_TOKEN: "REFRESH_TOKEN_SECURED_BY_OIDC_SERVICE_WORKER",
|
|
6
|
+
ACCESS_TOKEN: "ACCESS_TOKEN_SECURED_BY_OIDC_SERVICE_WORKER",
|
|
7
|
+
NONCE_TOKEN: "NONCE_SECURED_BY_OIDC_SERVICE_WORKER",
|
|
8
|
+
CODE_VERIFIER: "CODE_VERIFIER_SECURED_BY_OIDC_SERVICE_WORKER"
|
|
9
|
+
};
|
|
10
|
+
var TokenRenewMode = {
|
|
11
|
+
access_token_or_id_token_invalid: "access_token_or_id_token_invalid",
|
|
12
|
+
access_token_invalid: "access_token_invalid",
|
|
13
|
+
id_token_invalid: "id_token_invalid"
|
|
14
|
+
};
|
|
15
|
+
//#endregion
|
|
16
|
+
//#region src/jwt.ts
|
|
17
|
+
function strToUint8(str) {
|
|
18
|
+
return new TextEncoder().encode(str);
|
|
76
19
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
payload: strToUrlBase64(JSON.stringify(claims))
|
|
80
|
-
};
|
|
81
|
-
const keyType = demonstratingProofOfPossessionConfiguration.importKeyAlgorithm;
|
|
82
|
-
const privateKey = await w.crypto.subtle.importKey("jwk", jwk, keyType, true, ["sign"]);
|
|
83
|
-
const data = strToUint8(`${jws.protected}.${jws.payload}`);
|
|
84
|
-
const signatureType = demonstratingProofOfPossessionConfiguration.signAlgorithm;
|
|
85
|
-
const signature = await w.crypto.subtle.sign(signatureType, privateKey, data);
|
|
86
|
-
jws.signature = uint8ToUrlBase64(new Uint8Array(signature));
|
|
87
|
-
return `${jws.protected}.${jws.payload}.${jws.signature}`;
|
|
88
|
-
};
|
|
89
|
-
var JWT = { sign };
|
|
90
|
-
var generate = (w) => async (generateKeyAlgorithm) => {
|
|
91
|
-
const keyType = generateKeyAlgorithm;
|
|
92
|
-
const key = await w.crypto.subtle.generateKey(keyType, true, ["sign", "verify"]);
|
|
93
|
-
return await w.crypto.subtle.exportKey("jwk", key.privateKey);
|
|
94
|
-
};
|
|
95
|
-
var neuter = (jwk) => {
|
|
96
|
-
const copy = Object.assign({}, jwk);
|
|
97
|
-
delete copy.d;
|
|
98
|
-
copy.key_ops = ["verify"];
|
|
99
|
-
return copy;
|
|
100
|
-
};
|
|
101
|
-
var EC = {
|
|
102
|
-
generate,
|
|
103
|
-
neuter
|
|
104
|
-
};
|
|
105
|
-
var thumbprint = (w) => async (jwk, digestAlgorithm) => {
|
|
106
|
-
let sortedPub;
|
|
107
|
-
switch (jwk.kty) {
|
|
108
|
-
case "EC":
|
|
109
|
-
sortedPub = "{\"crv\":\"CRV\",\"kty\":\"EC\",\"x\":\"X\",\"y\":\"Y\"}".replace("CRV", jwk.crv).replace("X", jwk.x).replace("Y", jwk.y);
|
|
110
|
-
break;
|
|
111
|
-
case "RSA":
|
|
112
|
-
sortedPub = "{\"e\":\"E\",\"kty\":\"RSA\",\"n\":\"N\"}".replace("E", jwk.e).replace("N", jwk.n);
|
|
113
|
-
break;
|
|
114
|
-
default: throw new Error("Unknown or not implemented JWK type");
|
|
20
|
+
function binToUrlBase64(bin) {
|
|
21
|
+
return btoa(bin).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+/g, "");
|
|
115
22
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
};
|
|
131
|
-
const kid = await JWK.thumbprint(w)(jwk, demonstratingProofOfPossessionConfiguration.digestAlgorithm);
|
|
132
|
-
return await JWT.sign(w)(jwk, { kid }, claims, demonstratingProofOfPossessionConfiguration);
|
|
133
|
-
};
|
|
134
|
-
//#endregion
|
|
135
|
-
//#region src/crypto.ts
|
|
136
|
-
function textEncodeLite(str) {
|
|
137
|
-
const buf = new ArrayBuffer(str.length);
|
|
138
|
-
const bufView = new Uint8Array(buf);
|
|
139
|
-
for (let i = 0; i < str.length; i++) bufView[i] = str.charCodeAt(i);
|
|
140
|
-
return bufView;
|
|
141
|
-
}
|
|
142
|
-
function base64urlOfHashOfASCIIEncodingAsync(code) {
|
|
143
|
-
return new Promise((resolve, reject) => {
|
|
144
|
-
crypto.subtle.digest("SHA-256", textEncodeLite(code)).then((buffer) => {
|
|
145
|
-
return resolve(uint8ToUrlBase64(new Uint8Array(buffer)));
|
|
146
|
-
}, (error) => reject(error));
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
//#endregion
|
|
150
|
-
//#region src/dpop.ts
|
|
151
|
-
var isDpop = (trustedDomain) => {
|
|
152
|
-
if (Array.isArray(trustedDomain)) return false;
|
|
153
|
-
return trustedDomain.demonstratingProofOfPossession ?? false;
|
|
154
|
-
};
|
|
155
|
-
var getDpopConfiguration = (trustedDomain) => {
|
|
156
|
-
if (!isDpop(trustedDomain)) return null;
|
|
157
|
-
if (Array.isArray(trustedDomain)) return null;
|
|
158
|
-
return trustedDomain.demonstratingProofOfPossessionConfiguration ?? defaultDemonstratingProofOfPossessionConfiguration;
|
|
159
|
-
};
|
|
160
|
-
var getDpopOnlyWhenDpopHeaderPresent = (trustedDomain) => {
|
|
161
|
-
if (!isDpop(trustedDomain)) return null;
|
|
162
|
-
if (Array.isArray(trustedDomain)) return null;
|
|
163
|
-
return trustedDomain.demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent ?? true;
|
|
164
|
-
};
|
|
165
|
-
//#endregion
|
|
166
|
-
//#region src/utils/normalizeUrl.ts
|
|
167
|
-
function normalizeUrl(url) {
|
|
168
|
-
try {
|
|
169
|
-
return new URL(url).toString();
|
|
170
|
-
} catch (error) {
|
|
171
|
-
console.error(`Failed to normalize url: ${url}`, error);
|
|
172
|
-
return url;
|
|
23
|
+
function utf8ToBinaryString(str) {
|
|
24
|
+
return encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function(match, p1) {
|
|
25
|
+
return String.fromCharCode(parseInt(p1, 16));
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
var uint8ToUrlBase64 = (uint8) => {
|
|
29
|
+
let bin = "";
|
|
30
|
+
uint8.forEach(function(code) {
|
|
31
|
+
bin += String.fromCharCode(code);
|
|
32
|
+
});
|
|
33
|
+
return binToUrlBase64(bin);
|
|
34
|
+
};
|
|
35
|
+
function strToUrlBase64(str) {
|
|
36
|
+
return binToUrlBase64(utf8ToBinaryString(str));
|
|
173
37
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
let domain = domainsToSendTokens[i];
|
|
204
|
-
if (typeof domain === "string") domain = new RegExp(`^${domain}`);
|
|
205
|
-
if (domain.test?.(url)) {
|
|
206
|
-
hasToSendToken = true;
|
|
38
|
+
var defaultDemonstratingProofOfPossessionConfiguration = {
|
|
39
|
+
importKeyAlgorithm: {
|
|
40
|
+
name: "ECDSA",
|
|
41
|
+
namedCurve: "P-256",
|
|
42
|
+
hash: { name: "ES256" }
|
|
43
|
+
},
|
|
44
|
+
signAlgorithm: {
|
|
45
|
+
name: "ECDSA",
|
|
46
|
+
hash: { name: "SHA-256" }
|
|
47
|
+
},
|
|
48
|
+
generateKeyAlgorithm: {
|
|
49
|
+
name: "ECDSA",
|
|
50
|
+
namedCurve: "P-256"
|
|
51
|
+
},
|
|
52
|
+
digestAlgorithm: { name: "SHA-256" },
|
|
53
|
+
jwtHeaderAlgorithm: "ES256"
|
|
54
|
+
};
|
|
55
|
+
var sign = (w) => async (jwk, headers, claims, demonstratingProofOfPossessionConfiguration, jwtHeaderType = "dpop+jwt") => {
|
|
56
|
+
jwk = Object.assign({}, jwk);
|
|
57
|
+
headers.typ = jwtHeaderType;
|
|
58
|
+
headers.alg = demonstratingProofOfPossessionConfiguration.jwtHeaderAlgorithm;
|
|
59
|
+
switch (headers.alg) {
|
|
60
|
+
case "ES256":
|
|
61
|
+
headers.jwk = {
|
|
62
|
+
kty: jwk.kty,
|
|
63
|
+
crv: jwk.crv,
|
|
64
|
+
x: jwk.x,
|
|
65
|
+
y: jwk.y
|
|
66
|
+
};
|
|
207
67
|
break;
|
|
208
|
-
|
|
68
|
+
case "RS256":
|
|
69
|
+
headers.jwk = {
|
|
70
|
+
kty: jwk.kty,
|
|
71
|
+
n: jwk.n,
|
|
72
|
+
e: jwk.e,
|
|
73
|
+
kid: headers.kid
|
|
74
|
+
};
|
|
75
|
+
break;
|
|
76
|
+
default: throw new Error("Unknown or not implemented JWS algorithm");
|
|
209
77
|
}
|
|
210
|
-
|
|
211
|
-
|
|
78
|
+
const jws = {
|
|
79
|
+
protected: strToUrlBase64(JSON.stringify(headers)),
|
|
80
|
+
payload: strToUrlBase64(JSON.stringify(claims))
|
|
81
|
+
};
|
|
82
|
+
const keyType = demonstratingProofOfPossessionConfiguration.importKeyAlgorithm;
|
|
83
|
+
const privateKey = await w.crypto.subtle.importKey("jwk", jwk, keyType, true, ["sign"]);
|
|
84
|
+
const data = strToUint8(`${jws.protected}.${jws.payload}`);
|
|
85
|
+
const signatureType = demonstratingProofOfPossessionConfiguration.signAlgorithm;
|
|
86
|
+
const signature = await w.crypto.subtle.sign(signatureType, privateKey, data);
|
|
87
|
+
jws.signature = uint8ToUrlBase64(new Uint8Array(signature));
|
|
88
|
+
return `${jws.protected}.${jws.payload}.${jws.signature}`;
|
|
89
|
+
};
|
|
90
|
+
var JWT = { sign };
|
|
91
|
+
var generate = (w) => async (generateKeyAlgorithm) => {
|
|
92
|
+
const keyType = generateKeyAlgorithm;
|
|
93
|
+
const key = await w.crypto.subtle.generateKey(keyType, true, ["sign", "verify"]);
|
|
94
|
+
return await w.crypto.subtle.exportKey("jwk", key.privateKey);
|
|
95
|
+
};
|
|
96
|
+
var neuter = (jwk) => {
|
|
97
|
+
const copy = Object.assign({}, jwk);
|
|
98
|
+
delete copy.d;
|
|
99
|
+
copy.key_ops = ["verify"];
|
|
100
|
+
return copy;
|
|
101
|
+
};
|
|
102
|
+
var EC = {
|
|
103
|
+
generate,
|
|
104
|
+
neuter
|
|
105
|
+
};
|
|
106
|
+
var thumbprint = (w) => async (jwk, digestAlgorithm) => {
|
|
107
|
+
let sortedPub;
|
|
108
|
+
switch (jwk.kty) {
|
|
109
|
+
case "EC":
|
|
110
|
+
sortedPub = "{\"crv\":\"CRV\",\"kty\":\"EC\",\"x\":\"X\",\"y\":\"Y\"}".replace("CRV", jwk.crv).replace("X", jwk.x).replace("Y", jwk.y);
|
|
111
|
+
break;
|
|
112
|
+
case "RSA":
|
|
113
|
+
sortedPub = "{\"e\":\"E\",\"kty\":\"RSA\",\"n\":\"N\"}".replace("E", jwk.e).replace("N", jwk.n);
|
|
114
|
+
break;
|
|
115
|
+
default: throw new Error("Unknown or not implemented JWK type");
|
|
212
116
|
}
|
|
117
|
+
const hash = await w.crypto.subtle.digest(digestAlgorithm, strToUint8(sortedPub));
|
|
118
|
+
return uint8ToUrlBase64(new Uint8Array(hash));
|
|
119
|
+
};
|
|
120
|
+
var JWK = { thumbprint };
|
|
121
|
+
var generateJwkAsync = (w) => async (generateKeyAlgorithm) => {
|
|
122
|
+
return await EC.generate(w)(generateKeyAlgorithm);
|
|
123
|
+
};
|
|
124
|
+
var generateJwtDemonstratingProofOfPossessionAsync = (w) => (demonstratingProofOfPossessionConfiguration) => async (jwk, method = "POST", url, extrasClaims = {}) => {
|
|
125
|
+
const target = new URL(url, w.location?.href);
|
|
126
|
+
target.search = "";
|
|
127
|
+
target.hash = "";
|
|
128
|
+
const claims = {
|
|
129
|
+
jti: btoa(w.crypto.randomUUID()),
|
|
130
|
+
htm: method,
|
|
131
|
+
htu: target.href,
|
|
132
|
+
iat: Math.round(Date.now() / 1e3),
|
|
133
|
+
...extrasClaims
|
|
134
|
+
};
|
|
135
|
+
const kid = await JWK.thumbprint(w)(jwk, demonstratingProofOfPossessionConfiguration.digestAlgorithm);
|
|
136
|
+
return await JWT.sign(w)(jwk, { kid }, claims, demonstratingProofOfPossessionConfiguration);
|
|
137
|
+
};
|
|
138
|
+
//#endregion
|
|
139
|
+
//#region src/crypto.ts
|
|
140
|
+
function textEncodeLite(str) {
|
|
141
|
+
const buf = new ArrayBuffer(str.length);
|
|
142
|
+
const bufView = new Uint8Array(buf);
|
|
143
|
+
for (let i = 0; i < str.length; i++) bufView[i] = str.charCodeAt(i);
|
|
144
|
+
return bufView;
|
|
213
145
|
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
for (const key of headers.keys()) {
|
|
221
|
-
const value = headers.get(key);
|
|
222
|
-
if (value !== null) headersObj[key] = value;
|
|
223
|
-
}
|
|
224
|
-
return headersObj;
|
|
225
|
-
}
|
|
226
|
-
//#endregion
|
|
227
|
-
//#region src/utils/shouldBypassDestination.ts
|
|
228
|
-
var bypassedDestinations = [
|
|
229
|
-
"image",
|
|
230
|
-
"font",
|
|
231
|
-
"media",
|
|
232
|
-
"document",
|
|
233
|
-
"iframe",
|
|
234
|
-
"script"
|
|
235
|
-
];
|
|
236
|
-
/**
|
|
237
|
-
* Determines whether a fetch event should be bypassed (not intercepted by the service worker).
|
|
238
|
-
* Navigation requests (mode === 'navigate') are never bypassed, even when their destination
|
|
239
|
-
* is in the bypassed list, so that access tokens can be injected into new-tab navigations.
|
|
240
|
-
*/
|
|
241
|
-
var shouldBypassDestination = (destination, mode) => {
|
|
242
|
-
return bypassedDestinations.includes(destination) && mode !== "navigate";
|
|
243
|
-
};
|
|
244
|
-
//#endregion
|
|
245
|
-
//#region src/utils/sleep.ts
|
|
246
|
-
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
247
|
-
//#endregion
|
|
248
|
-
//#region src/utils/tokens.ts
|
|
249
|
-
var parseJwt = (payload) => {
|
|
250
|
-
return JSON.parse(b64DecodeUnicode(payload.replaceAll(/-/g, "+").replaceAll(/_/g, "/")));
|
|
251
|
-
};
|
|
252
|
-
function b64DecodeUnicode(str) {
|
|
253
|
-
return decodeURIComponent(Array.prototype.map.call(atob(str), (c) => "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2)).join(""));
|
|
254
|
-
}
|
|
255
|
-
function computeTimeLeft(refreshTimeBeforeTokensExpirationInSecond, expiresAt) {
|
|
256
|
-
const currentTimeUnixSecond = (/* @__PURE__ */ new Date()).getTime() / 1e3;
|
|
257
|
-
return Math.round(expiresAt - refreshTimeBeforeTokensExpirationInSecond - currentTimeUnixSecond);
|
|
258
|
-
}
|
|
259
|
-
function isTokensValid(tokens) {
|
|
260
|
-
if (!tokens) return false;
|
|
261
|
-
return computeTimeLeft(0, tokens.expiresAt) > 0;
|
|
262
|
-
}
|
|
263
|
-
var extractTokenPayload = (token) => {
|
|
264
|
-
try {
|
|
265
|
-
if (!token) return null;
|
|
266
|
-
const parts = token.split(".");
|
|
267
|
-
return parts.length === 3 ? parseJwt(parts[1]) : null;
|
|
268
|
-
} catch (e) {
|
|
269
|
-
console.warn(e);
|
|
146
|
+
function base64urlOfHashOfASCIIEncodingAsync(code) {
|
|
147
|
+
return new Promise((resolve, reject) => {
|
|
148
|
+
crypto.subtle.digest("SHA-256", textEncodeLite(code)).then((buffer) => {
|
|
149
|
+
return resolve(uint8ToUrlBase64(new Uint8Array(buffer)));
|
|
150
|
+
}, (error) => reject(error));
|
|
151
|
+
});
|
|
270
152
|
}
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
var
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
153
|
+
//#endregion
|
|
154
|
+
//#region src/dpop.ts
|
|
155
|
+
var isDpop = (trustedDomain) => {
|
|
156
|
+
if (Array.isArray(trustedDomain)) return false;
|
|
157
|
+
return trustedDomain.demonstratingProofOfPossession ?? false;
|
|
158
|
+
};
|
|
159
|
+
var getDpopConfiguration = (trustedDomain) => {
|
|
160
|
+
if (!isDpop(trustedDomain)) return null;
|
|
161
|
+
if (Array.isArray(trustedDomain)) return null;
|
|
162
|
+
return trustedDomain.demonstratingProofOfPossessionConfiguration ?? defaultDemonstratingProofOfPossessionConfiguration;
|
|
163
|
+
};
|
|
164
|
+
var getDpopOnlyWhenDpopHeaderPresent = (trustedDomain) => {
|
|
165
|
+
if (!isDpop(trustedDomain)) return null;
|
|
166
|
+
if (Array.isArray(trustedDomain)) return null;
|
|
167
|
+
return trustedDomain.demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent ?? true;
|
|
168
|
+
};
|
|
169
|
+
//#endregion
|
|
170
|
+
//#region src/resource.ts
|
|
171
|
+
/** Worker-only resource refresh routing hint, removed before the provider request. */
|
|
172
|
+
var RESOURCE_TOKEN_REQUEST_HEADER = "x-oidc-resource";
|
|
173
|
+
/** Builds an isolated storage/worker context without creating another OIDC client. */
|
|
174
|
+
var getResourceContextName = (configurationName, resource) => `${configurationName}#resource=${encodeURIComponent(resource)}`;
|
|
175
|
+
/** Reads the exact resource identifier from an isolated context name. */
|
|
176
|
+
var getContextResource = (configurationName) => {
|
|
177
|
+
const index = configurationName.indexOf("#resource=");
|
|
178
|
+
return index < 0 ? void 0 : decodeURIComponent(configurationName.slice(index + 10));
|
|
179
|
+
};
|
|
180
|
+
/** Validates RFC 8707 identifiers without treating them as API URLs or scopes. */
|
|
181
|
+
var validateResourceIdentifier = (resource) => {
|
|
182
|
+
if (typeof resource !== "string" || !/^[a-z][a-z\d+.-]*:/i.test(resource) || resource.includes("#") || /\s/.test(resource)) throw new Error("A resource must be an absolute URI without whitespace or a fragment.");
|
|
183
|
+
new URL(resource);
|
|
184
|
+
};
|
|
185
|
+
var getApiUrl = (value) => {
|
|
186
|
+
const url = new URL(value);
|
|
187
|
+
if (url.protocol !== "https:" && url.protocol !== "http:" || url.username || url.password || url.hash || /%2f|%5c/i.test(url.pathname)) throw new Error("API destinations must be HTTP(S) URLs without credentials, fragments, or encoded separators.");
|
|
188
|
+
return url;
|
|
189
|
+
};
|
|
190
|
+
var getApiPrefixUrl = (value) => {
|
|
191
|
+
const prefix = getApiUrl(value);
|
|
192
|
+
if (prefix.search) throw new Error("An API URL prefix must not contain a query.");
|
|
193
|
+
return prefix;
|
|
194
|
+
};
|
|
195
|
+
/** Prevents default-token fallback anywhere on an explicitly managed API origin. */
|
|
196
|
+
var isResourceOriginManaged = (configurations, destination) => {
|
|
197
|
+
const origin = getApiUrl(destination).origin;
|
|
198
|
+
return configurations?.some((configuration) => configuration.allowedUrlPrefixes.some((value) => getApiPrefixUrl(value).origin === origin)) ?? false;
|
|
199
|
+
};
|
|
200
|
+
/** Matches API mappings by parsed origin and path boundaries, never by host suffix. */
|
|
201
|
+
var isResourceUrlAllowed = (configuration, destination) => {
|
|
202
|
+
const url = getApiUrl(destination);
|
|
203
|
+
return configuration.allowedUrlPrefixes.some((value) => {
|
|
204
|
+
const prefix = getApiPrefixUrl(value);
|
|
205
|
+
const path = prefix.pathname.replace(/\/+$/, "");
|
|
206
|
+
return url.origin === prefix.origin && (path === "" || url.pathname === path || url.pathname.startsWith(`${path}/`));
|
|
207
|
+
});
|
|
208
|
+
};
|
|
209
|
+
/** Validates and retrieves an explicitly registered resource. */
|
|
210
|
+
var getResourceConfiguration = (configurations, resource) => {
|
|
211
|
+
validateResourceIdentifier(resource);
|
|
212
|
+
const matches = configurations?.filter((configuration) => configuration.resource === resource) ?? [];
|
|
213
|
+
if (matches.length !== 1 || matches[0].allowedUrlPrefixes.length === 0) throw new Error("The resource must be registered exactly once with permitted API URL prefixes.");
|
|
214
|
+
for (const prefix of matches[0].allowedUrlPrefixes) isResourceUrlAllowed(matches[0], prefix);
|
|
215
|
+
return matches[0];
|
|
216
|
+
};
|
|
217
|
+
//#endregion
|
|
218
|
+
//#region src/tokenContexts.ts
|
|
219
|
+
var getTokenContextEntries = (database) => Object.entries(database).flatMap(([key, configuration]) => [[key, configuration], ...Object.entries(configuration.resourceEntries ?? {})]);
|
|
220
|
+
var getTokenContexts = (database) => getTokenContextEntries(database).map(([, configuration]) => configuration);
|
|
221
|
+
var getOrCreateResourceContext = (configuration, resource) => {
|
|
222
|
+
getResourceConfiguration(configuration.oidcConfiguration?.resources, resource);
|
|
223
|
+
configuration.resourceEntries ??= {};
|
|
224
|
+
const name = getResourceContextName(configuration.configurationName, resource);
|
|
225
|
+
configuration.resourceEntries[name] ??= {
|
|
226
|
+
...configuration,
|
|
227
|
+
configurationName: name,
|
|
228
|
+
resource,
|
|
229
|
+
parentConfiguration: configuration,
|
|
230
|
+
resourceEntries: void 0,
|
|
231
|
+
authorizationScope: void 0,
|
|
232
|
+
requestedScope: void 0,
|
|
233
|
+
demonstratingProofOfPossessionApiNonce: null,
|
|
234
|
+
refreshGrant: void 0,
|
|
235
|
+
tokens: null,
|
|
236
|
+
state: null,
|
|
237
|
+
codeVerifier: null,
|
|
238
|
+
nonce: null,
|
|
239
|
+
status: null,
|
|
240
|
+
hideAccessToken: true,
|
|
241
|
+
generation: 0
|
|
279
242
|
};
|
|
243
|
+
return configuration.resourceEntries[name];
|
|
244
|
+
};
|
|
245
|
+
//#endregion
|
|
246
|
+
//#region src/utils/normalizeUrl.ts
|
|
247
|
+
function normalizeUrl(url) {
|
|
248
|
+
try {
|
|
249
|
+
return new URL(url).toString();
|
|
250
|
+
} catch (error) {
|
|
251
|
+
console.error(`Failed to normalize url: ${url}`, error);
|
|
252
|
+
return url;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
//#endregion
|
|
256
|
+
//#region src/utils/domains.ts
|
|
257
|
+
function checkDomain(domains, endpoint) {
|
|
258
|
+
if (!endpoint) return;
|
|
259
|
+
if (!domains.find((domain) => {
|
|
260
|
+
let testable;
|
|
261
|
+
if (typeof domain === "string") testable = new RegExp(`^${domain}`);
|
|
262
|
+
else testable = domain;
|
|
263
|
+
return testable.test?.(endpoint);
|
|
264
|
+
})) throw new Error("Domain " + endpoint + " is not trusted, please add domain in " + scriptFilename);
|
|
265
|
+
}
|
|
266
|
+
var getDomains = (trustedDomain, type) => {
|
|
267
|
+
if (Array.isArray(trustedDomain)) return trustedDomain;
|
|
268
|
+
return trustedDomain[`${type}Domains`] ?? trustedDomain.domains ?? [];
|
|
269
|
+
};
|
|
270
|
+
var getCurrentDatabaseDomain = (database, url, trustedDomains) => {
|
|
271
|
+
if (url.endsWith("/.well-known/openid-configuration")) return null;
|
|
272
|
+
const datatases = [];
|
|
273
|
+
for (const [key, currentDatabase] of getTokenContextEntries(database)) {
|
|
274
|
+
const oidcServerConfiguration = currentDatabase.oidcServerConfiguration;
|
|
275
|
+
const resources = currentDatabase.oidcConfiguration?.resources;
|
|
276
|
+
if (currentDatabase.resource) {
|
|
277
|
+
if (!isResourceUrlAllowed(getResourceConfiguration(resources, currentDatabase.resource), url)) continue;
|
|
278
|
+
} else if (resources?.length && (!oidcServerConfiguration?.userInfoEndpoint || url !== normalizeUrl(oidcServerConfiguration.userInfoEndpoint)) && isResourceOriginManaged(resources, url)) continue;
|
|
279
|
+
if (!oidcServerConfiguration) continue;
|
|
280
|
+
if (oidcServerConfiguration.tokenEndpoint && url === normalizeUrl(oidcServerConfiguration.tokenEndpoint)) continue;
|
|
281
|
+
if (oidcServerConfiguration.revocationEndpoint && url === normalizeUrl(oidcServerConfiguration.revocationEndpoint)) continue;
|
|
282
|
+
const domains = getDomains(trustedDomains == null ? [] : trustedDomains[key.split("#")[0]], "accessToken");
|
|
283
|
+
const domainsToSendTokens = oidcServerConfiguration.userInfoEndpoint ? [normalizeUrl(oidcServerConfiguration.userInfoEndpoint), ...domains] : [...domains];
|
|
284
|
+
let hasToSendToken = false;
|
|
285
|
+
if (domainsToSendTokens.find((f) => f === "*")) hasToSendToken = true;
|
|
286
|
+
else for (let i = 0; i < domainsToSendTokens.length; i++) {
|
|
287
|
+
let domain = domainsToSendTokens[i];
|
|
288
|
+
if (typeof domain === "string") domain = new RegExp(`^${domain}`);
|
|
289
|
+
if (domain.test?.(url)) {
|
|
290
|
+
hasToSendToken = true;
|
|
291
|
+
break;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
if (hasToSendToken) {
|
|
295
|
+
if (currentDatabase.tokens) datatases.push(currentDatabase);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return datatases;
|
|
299
|
+
};
|
|
300
|
+
//#endregion
|
|
301
|
+
//#region src/utils/serializeHeaders.ts
|
|
302
|
+
function serializeHeaders(headers) {
|
|
303
|
+
const headersObj = {};
|
|
304
|
+
for (const key of headers.keys()) {
|
|
305
|
+
const value = headers.get(key);
|
|
306
|
+
if (value !== null) headersObj[key] = value;
|
|
307
|
+
}
|
|
308
|
+
return headersObj;
|
|
309
|
+
}
|
|
310
|
+
//#endregion
|
|
311
|
+
//#region src/utils/shouldBypassDestination.ts
|
|
312
|
+
var bypassedDestinations = [
|
|
313
|
+
"image",
|
|
314
|
+
"font",
|
|
315
|
+
"media",
|
|
316
|
+
"document",
|
|
317
|
+
"iframe",
|
|
318
|
+
"script"
|
|
319
|
+
];
|
|
320
|
+
/**
|
|
321
|
+
* Determines whether a fetch event should be bypassed (not intercepted by the service worker).
|
|
322
|
+
* Navigation requests (mode === 'navigate') are never bypassed, even when their destination
|
|
323
|
+
* is in the bypassed list, so that access tokens can be injected into new-tab navigations.
|
|
324
|
+
*/
|
|
325
|
+
var shouldBypassDestination = (destination, mode) => {
|
|
326
|
+
return bypassedDestinations.includes(destination) && mode !== "navigate";
|
|
327
|
+
};
|
|
328
|
+
//#endregion
|
|
329
|
+
//#region src/utils/sleep.ts
|
|
330
|
+
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
331
|
+
//#endregion
|
|
332
|
+
//#region src/utils/tokens.ts
|
|
333
|
+
var parseJwt = (payload) => {
|
|
334
|
+
return JSON.parse(b64DecodeUnicode(payload.replaceAll(/-/g, "+").replaceAll(/_/g, "/")));
|
|
335
|
+
};
|
|
336
|
+
function b64DecodeUnicode(str) {
|
|
337
|
+
return decodeURIComponent(Array.prototype.map.call(atob(str), (c) => "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2)).join(""));
|
|
338
|
+
}
|
|
339
|
+
function computeTimeLeft(refreshTimeBeforeTokensExpirationInSecond, expiresAt) {
|
|
280
340
|
const currentTimeUnixSecond = (/* @__PURE__ */ new Date()).getTime() / 1e3;
|
|
281
|
-
|
|
282
|
-
isValid: false,
|
|
283
|
-
reason: `Token expired at (idTokenPayload exp) ${idTokenPayload.exp} < (currentTimeUnixSecond) ${currentTimeUnixSecond}`
|
|
284
|
-
};
|
|
285
|
-
const timeInSevenDays = 604800;
|
|
286
|
-
if (idTokenPayload && idTokenPayload.iat && idTokenPayload.iat + timeInSevenDays < currentTimeUnixSecond) return {
|
|
287
|
-
isValid: false,
|
|
288
|
-
reason: `Token is used from too long time (idTokenPayload iat + timeInSevenDays) ${idTokenPayload.iat + timeInSevenDays} < (currentTimeUnixSecond) ${currentTimeUnixSecond}`
|
|
289
|
-
};
|
|
290
|
-
if (idTokenPayload && nonce && idTokenPayload.nonce && idTokenPayload.nonce !== nonce) return {
|
|
291
|
-
isValid: false,
|
|
292
|
-
reason: `Nonce does not match (nonce) ${nonce} !== (idTokenPayload nonce) ${idTokenPayload.nonce}`
|
|
293
|
-
};
|
|
341
|
+
return Math.round(expiresAt - refreshTimeBeforeTokensExpirationInSecond - currentTimeUnixSecond);
|
|
294
342
|
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
return tokens.issued_at;
|
|
307
|
-
}
|
|
308
|
-
function _hideTokens(tokens, currentDatabaseElement, configurationName) {
|
|
309
|
-
if (!tokens.issued_at) tokens.issued_at = (/* @__PURE__ */ new Date()).getTime() / 1e3;
|
|
310
|
-
else if (typeof tokens.issued_at == "string") tokens.issued_at = parseInt(tokens.issued_at, 10);
|
|
311
|
-
const accessTokenPayload = extractTokenPayload(tokens.access_token);
|
|
312
|
-
const secureTokens = {
|
|
313
|
-
...tokens,
|
|
314
|
-
accessTokenPayload
|
|
315
|
-
};
|
|
316
|
-
if (currentDatabaseElement.hideAccessToken) secureTokens.access_token = `${TOKEN.ACCESS_TOKEN}_${configurationName}`;
|
|
317
|
-
tokens.accessTokenPayload = accessTokenPayload;
|
|
318
|
-
const oldTokens = currentDatabaseElement.tokens;
|
|
319
|
-
let id_token;
|
|
320
|
-
if (oldTokens != null && "id_token" in oldTokens && !("id_token" in tokens)) id_token = oldTokens.id_token;
|
|
321
|
-
else id_token = tokens.id_token;
|
|
322
|
-
tokens.id_token = id_token;
|
|
323
|
-
let _idTokenPayload = null;
|
|
324
|
-
if (id_token) {
|
|
325
|
-
_idTokenPayload = extractTokenPayload(id_token);
|
|
326
|
-
tokens.idTokenPayload = _idTokenPayload != null ? { ..._idTokenPayload } : null;
|
|
327
|
-
if (_idTokenPayload && _idTokenPayload.nonce && currentDatabaseElement.nonce != null) {
|
|
328
|
-
const keyNonce = `${TOKEN.NONCE_TOKEN}_${currentDatabaseElement.configurationName}`;
|
|
329
|
-
_idTokenPayload.nonce = keyNonce;
|
|
343
|
+
function isTokensValid(tokens) {
|
|
344
|
+
if (!tokens) return false;
|
|
345
|
+
return computeTimeLeft(0, tokens.expiresAt) > 0;
|
|
346
|
+
}
|
|
347
|
+
var extractTokenPayload = (token) => {
|
|
348
|
+
try {
|
|
349
|
+
if (!token) return null;
|
|
350
|
+
const parts = token.split(".");
|
|
351
|
+
return parts.length === 3 ? parseJwt(parts[1]) : null;
|
|
352
|
+
} catch (e) {
|
|
353
|
+
console.warn(e);
|
|
330
354
|
}
|
|
331
|
-
|
|
355
|
+
return null;
|
|
356
|
+
};
|
|
357
|
+
var isTokensOidcValid = (tokens, nonce, oidcServerConfiguration) => {
|
|
358
|
+
if (tokens.idTokenPayload) {
|
|
359
|
+
const idTokenPayload = tokens.idTokenPayload;
|
|
360
|
+
if (idTokenPayload && oidcServerConfiguration.issuer !== idTokenPayload.iss) return {
|
|
361
|
+
isValid: false,
|
|
362
|
+
reason: `Issuer does not match (oidcServerConfiguration issuer) ${oidcServerConfiguration.issuer} !== (idTokenPayload issuer) ${idTokenPayload.iss}`
|
|
363
|
+
};
|
|
364
|
+
const currentTimeUnixSecond = (/* @__PURE__ */ new Date()).getTime() / 1e3;
|
|
365
|
+
if (idTokenPayload && idTokenPayload.exp && idTokenPayload.exp < currentTimeUnixSecond) return {
|
|
366
|
+
isValid: false,
|
|
367
|
+
reason: `Token expired at (idTokenPayload exp) ${idTokenPayload.exp} < (currentTimeUnixSecond) ${currentTimeUnixSecond}`
|
|
368
|
+
};
|
|
369
|
+
const timeInSevenDays = 604800;
|
|
370
|
+
if (idTokenPayload && idTokenPayload.iat && idTokenPayload.iat + timeInSevenDays < currentTimeUnixSecond) return {
|
|
371
|
+
isValid: false,
|
|
372
|
+
reason: `Token is used from too long time (idTokenPayload iat + timeInSevenDays) ${idTokenPayload.iat + timeInSevenDays} < (currentTimeUnixSecond) ${currentTimeUnixSecond}`
|
|
373
|
+
};
|
|
374
|
+
if (idTokenPayload && nonce && idTokenPayload.nonce && idTokenPayload.nonce !== nonce) return {
|
|
375
|
+
isValid: false,
|
|
376
|
+
reason: `Nonce does not match (nonce) ${nonce} !== (idTokenPayload nonce) ${idTokenPayload.nonce}`
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
return {
|
|
380
|
+
isValid: true,
|
|
381
|
+
reason: ""
|
|
382
|
+
};
|
|
383
|
+
};
|
|
384
|
+
function extractedIssueAt(tokens, accessTokenPayload, _idTokenPayload) {
|
|
385
|
+
if (!tokens.issued_at) {
|
|
386
|
+
if (accessTokenPayload && accessTokenPayload.iat) return accessTokenPayload.iat;
|
|
387
|
+
else if (_idTokenPayload && _idTokenPayload.iat) return _idTokenPayload.iat;
|
|
388
|
+
else return (/* @__PURE__ */ new Date()).getTime() / 1e3;
|
|
389
|
+
} else if (typeof tokens.issued_at == "string") return parseInt(tokens.issued_at, 10);
|
|
390
|
+
return tokens.issued_at;
|
|
332
391
|
}
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
else expiresAt = idTokenExpiresAt < accessTokenExpiresAt ? idTokenExpiresAt : accessTokenExpiresAt;
|
|
343
|
-
secureTokens.expiresAt = expiresAt;
|
|
344
|
-
tokens.expiresAt = expiresAt;
|
|
345
|
-
const { isValid, reason } = isTokensOidcValid(tokens, currentDatabaseElement.nonce ? currentDatabaseElement.nonce.nonce : null, currentDatabaseElement.oidcServerConfiguration);
|
|
346
|
-
if (!isValid) throw Error(`Tokens are not OpenID valid, reason: ${reason}`);
|
|
347
|
-
if (oldTokens != null && "refresh_token" in oldTokens && !("refresh_token" in tokens)) {
|
|
348
|
-
const refreshToken = oldTokens.refresh_token;
|
|
349
|
-
currentDatabaseElement.tokens = {
|
|
392
|
+
function _hideTokens(tokens, currentDatabaseElement, configurationName, isAuthorizationCode = false) {
|
|
393
|
+
const hasNewIdToken = typeof tokens.id_token === "string" && tokens.id_token.length > 0;
|
|
394
|
+
const parent = currentDatabaseElement.parentConfiguration;
|
|
395
|
+
if (currentDatabaseElement.resource && currentDatabaseElement.refreshGrant === currentDatabaseElement && tokens.refresh_token && tokens.refresh_token === parent?.tokens?.refresh_token) throw new Error("The provider reused a refresh token across separate authorization transactions; use a multi-resource authorization grant instead.");
|
|
396
|
+
if (!tokens.issued_at) tokens.issued_at = (/* @__PURE__ */ new Date()).getTime() / 1e3;
|
|
397
|
+
else if (typeof tokens.issued_at == "string") tokens.issued_at = parseInt(tokens.issued_at, 10);
|
|
398
|
+
const accessTokenPayload = extractTokenPayload(tokens.access_token);
|
|
399
|
+
if (currentDatabaseElement.resource || currentDatabaseElement.oidcConfiguration?.resources?.length) tokens.scope ??= currentDatabaseElement.requestedScope ?? currentDatabaseElement.tokens?.scope ?? currentDatabaseElement.oidcConfiguration?.scope;
|
|
400
|
+
const secureTokens = {
|
|
350
401
|
...tokens,
|
|
351
|
-
|
|
402
|
+
accessTokenPayload
|
|
352
403
|
};
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
if (
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
currentDatabaseElement.
|
|
365
|
-
|
|
404
|
+
if (currentDatabaseElement.hideAccessToken) secureTokens.access_token = `${TOKEN.ACCESS_TOKEN}_${configurationName}`;
|
|
405
|
+
tokens.accessTokenPayload = accessTokenPayload;
|
|
406
|
+
const oldTokens = currentDatabaseElement.tokens;
|
|
407
|
+
let id_token;
|
|
408
|
+
if (oldTokens != null && "id_token" in oldTokens && !("id_token" in tokens)) id_token = oldTokens.id_token;
|
|
409
|
+
else id_token = tokens.id_token;
|
|
410
|
+
tokens.id_token = id_token;
|
|
411
|
+
let _idTokenPayload = null;
|
|
412
|
+
if (id_token) {
|
|
413
|
+
_idTokenPayload = extractTokenPayload(id_token);
|
|
414
|
+
tokens.idTokenPayload = _idTokenPayload != null ? { ..._idTokenPayload } : null;
|
|
415
|
+
if (_idTokenPayload && _idTokenPayload.nonce && currentDatabaseElement.nonce != null) {
|
|
416
|
+
const keyNonce = `${TOKEN.NONCE_TOKEN}_${currentDatabaseElement.configurationName}`;
|
|
417
|
+
_idTokenPayload.nonce = keyNonce;
|
|
418
|
+
}
|
|
419
|
+
secureTokens.idTokenPayload = currentDatabaseElement.resource && !hasNewIdToken ? null : _idTokenPayload;
|
|
420
|
+
}
|
|
421
|
+
if (currentDatabaseElement.resource && isAuthorizationCode && (!hasNewIdToken || typeof tokens.idTokenPayload?.sub !== "string" || !tokens.idTokenPayload.sub || currentDatabaseElement.nonce && tokens.idTokenPayload.nonce !== currentDatabaseElement.nonce.nonce)) throw new Error("Resource authorization requires a fresh ID token with the expected subject and nonce.");
|
|
422
|
+
if (tokens.refresh_token) secureTokens.refresh_token = `${TOKEN.REFRESH_TOKEN}_${(currentDatabaseElement.refreshGrant ?? currentDatabaseElement).configurationName}`;
|
|
423
|
+
tokens.issued_at = extractedIssueAt(tokens, accessTokenPayload, _idTokenPayload);
|
|
424
|
+
const expireIn = typeof tokens.expires_in == "string" ? parseInt(tokens.expires_in, 10) : tokens.expires_in;
|
|
425
|
+
const idTokenExpiresAt = _idTokenPayload && _idTokenPayload.exp ? _idTokenPayload.exp : Number.MAX_VALUE;
|
|
426
|
+
const accessTokenExpiresAt = accessTokenPayload && accessTokenPayload.exp ? accessTokenPayload.exp : tokens.issued_at + expireIn;
|
|
427
|
+
let expiresAt;
|
|
428
|
+
const tokenRenewMode = currentDatabaseElement.resource ? TokenRenewMode.access_token_invalid : currentDatabaseElement.oidcConfiguration.token_renew_mode;
|
|
429
|
+
if (tokenRenewMode === TokenRenewMode.access_token_invalid) expiresAt = accessTokenExpiresAt;
|
|
430
|
+
else if (tokenRenewMode === TokenRenewMode.id_token_invalid) expiresAt = idTokenExpiresAt;
|
|
431
|
+
else expiresAt = idTokenExpiresAt < accessTokenExpiresAt ? idTokenExpiresAt : accessTokenExpiresAt;
|
|
432
|
+
secureTokens.expiresAt = expiresAt;
|
|
433
|
+
tokens.expiresAt = expiresAt;
|
|
434
|
+
const nonce = currentDatabaseElement.nonce ? currentDatabaseElement.nonce.nonce : null;
|
|
435
|
+
const { isValid, reason } = isTokensOidcValid(currentDatabaseElement.resource && !hasNewIdToken ? {
|
|
436
|
+
...tokens,
|
|
437
|
+
idTokenPayload: void 0
|
|
438
|
+
} : tokens, nonce, currentDatabaseElement.oidcServerConfiguration);
|
|
439
|
+
if (!isValid) throw Error(`Tokens are not OpenID valid, reason: ${reason}`);
|
|
440
|
+
if (currentDatabaseElement.resource) {
|
|
441
|
+
if (typeof tokens.access_token !== "string" || !tokens.access_token || !Number.isFinite(expiresAt) || !Number.isFinite(tokens.issued_at) || tokens.refresh_token != null && (typeof tokens.refresh_token !== "string" || !tokens.refresh_token)) throw new Error("The provider did not return a usable resource token response.");
|
|
442
|
+
const resource = getResourceConfiguration(currentDatabaseElement.oidcConfiguration?.resources, currentDatabaseElement.resource);
|
|
443
|
+
tokens.scope ??= currentDatabaseElement.requestedScope ?? resource.scope ?? currentDatabaseElement.oidcConfiguration?.scope;
|
|
444
|
+
secureTokens.scope = tokens.scope;
|
|
445
|
+
if (resource.scope && !resource.scope.split(/\s+/).filter(Boolean).every((scope) => (tokens.scope ?? "").split(/\s+/).includes(scope))) throw new Error("The provider did not grant the required resource scopes.");
|
|
446
|
+
const parentSubject = currentDatabaseElement.parentConfiguration?.tokens?.idTokenPayload?.sub;
|
|
447
|
+
const subject = tokens.idTokenPayload?.sub ?? oldTokens?.idTokenPayload?.sub ?? parentSubject;
|
|
448
|
+
if (typeof parentSubject !== "string" || subject !== parentSubject) throw new Error("Resource authorization must preserve the authenticated subject.");
|
|
449
|
+
if (accessTokenPayload?.iss !== void 0 && accessTokenPayload.iss !== currentDatabaseElement.oidcServerConfiguration?.issuer || accessTokenPayload && resource.audiences && !resource.audiences.some((audience) => (typeof accessTokenPayload.aud === "string" ? [accessTokenPayload.aud] : accessTokenPayload.aud ?? []).includes(audience))) throw new Error("Resource token issuer or configured audience does not match.");
|
|
450
|
+
}
|
|
451
|
+
if (oldTokens != null && "refresh_token" in oldTokens && !("refresh_token" in tokens)) {
|
|
452
|
+
const refreshToken = oldTokens.refresh_token;
|
|
453
|
+
currentDatabaseElement.tokens = {
|
|
454
|
+
...tokens,
|
|
455
|
+
refresh_token: refreshToken
|
|
456
|
+
};
|
|
457
|
+
} else currentDatabaseElement.tokens = tokens;
|
|
458
|
+
currentDatabaseElement.status = "LOGGED_IN";
|
|
459
|
+
if (currentDatabaseElement.resource) {
|
|
460
|
+
const grant = currentDatabaseElement.refreshGrant ?? currentDatabaseElement;
|
|
461
|
+
const subject = tokens.idTokenPayload?.sub ?? grant.tokens?.idTokenPayload?.sub ?? currentDatabaseElement.parentConfiguration?.tokens?.idTokenPayload?.sub;
|
|
462
|
+
if (typeof subject !== "string") throw new Error("Resource tokens require an authenticated OIDC subject.");
|
|
463
|
+
if (grant !== currentDatabaseElement && tokens.refresh_token && grant.tokens) grant.tokens.refresh_token = tokens.refresh_token;
|
|
464
|
+
const resourceContext = {
|
|
465
|
+
resource: currentDatabaseElement.resource,
|
|
466
|
+
issuer: currentDatabaseElement.oidcServerConfiguration.issuer,
|
|
467
|
+
clientId: currentDatabaseElement.oidcConfiguration.client_id,
|
|
468
|
+
configurationName: currentDatabaseElement.configurationName.split("#")[0],
|
|
469
|
+
subject,
|
|
470
|
+
grantResource: grant.resource ?? null
|
|
471
|
+
};
|
|
472
|
+
currentDatabaseElement.tokens.resourceContext = resourceContext;
|
|
473
|
+
secureTokens.resourceContext = resourceContext;
|
|
366
474
|
}
|
|
367
|
-
return
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
475
|
+
return secureTokens;
|
|
476
|
+
}
|
|
477
|
+
var demonstratingProofOfPossessionNonceResponseHeader = "DPoP-Nonce";
|
|
478
|
+
function hideTokens(currentDatabaseElement, isCurrent = () => true, isGrantCurrent = isCurrent, isAuthorizationCode = false) {
|
|
479
|
+
const configurationName = currentDatabaseElement.configurationName;
|
|
480
|
+
return (response) => {
|
|
481
|
+
if (response.status !== 200) return response;
|
|
482
|
+
const newHeaders = new Headers(response.headers);
|
|
483
|
+
if (response.headers.has(demonstratingProofOfPossessionNonceResponseHeader) && isGrantCurrent()) {
|
|
484
|
+
currentDatabaseElement.demonstratingProofOfPossessionNonce = response.headers.get(demonstratingProofOfPossessionNonceResponseHeader);
|
|
485
|
+
if (currentDatabaseElement.refreshGrant && currentDatabaseElement.refreshGrant !== currentDatabaseElement) currentDatabaseElement.refreshGrant.demonstratingProofOfPossessionNonce = currentDatabaseElement.demonstratingProofOfPossessionNonce;
|
|
486
|
+
newHeaders.delete(demonstratingProofOfPossessionNonceResponseHeader);
|
|
487
|
+
}
|
|
488
|
+
return response.json().then((tokens) => {
|
|
489
|
+
const grant = currentDatabaseElement.refreshGrant;
|
|
490
|
+
if (currentDatabaseElement.resource && grant && isGrantCurrent() && grant.tokens && typeof tokens.refresh_token === "string" && tokens.refresh_token && (grant !== currentDatabaseElement || tokens.refresh_token !== currentDatabaseElement.parentConfiguration?.tokens?.refresh_token)) grant.tokens.refresh_token = tokens.refresh_token;
|
|
491
|
+
if (!isCurrent()) throw new Error("The token transaction was cleared before its response.");
|
|
492
|
+
const secureTokens = _hideTokens(tokens, currentDatabaseElement, configurationName, isAuthorizationCode);
|
|
493
|
+
const body = JSON.stringify(secureTokens);
|
|
494
|
+
return new Response(body, {
|
|
495
|
+
status: response.status,
|
|
496
|
+
statusText: response.statusText,
|
|
497
|
+
headers: newHeaders
|
|
498
|
+
});
|
|
374
499
|
});
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
//#endregion
|
|
503
|
+
//#region src/utils/waitForValidTokens.ts
|
|
504
|
+
var TOKEN_RENEWAL_TIMEOUT_MS = 5e3;
|
|
505
|
+
/**
|
|
506
|
+
* Polls until the tokens in the given config are valid, or until a timeout elapses.
|
|
507
|
+
*
|
|
508
|
+
* @returns `null` when tokens become valid; a synthetic 401 `Response` on timeout or
|
|
509
|
+
* when the tokens are cleared while waiting (e.g. due to a parallel logout).
|
|
510
|
+
*/
|
|
511
|
+
async function waitForValidTokens(config, maxWaitMs = TOKEN_RENEWAL_TIMEOUT_MS, pollIntervalMs = 200) {
|
|
512
|
+
const startTime = Date.now();
|
|
513
|
+
while (config.tokens && !isTokensValid(config.tokens)) {
|
|
514
|
+
if (Date.now() - startTime >= maxWaitMs) return new Response(null, {
|
|
515
|
+
status: 401,
|
|
516
|
+
statusText: "Token expired - service worker renewal timeout"
|
|
517
|
+
});
|
|
518
|
+
await sleep(pollIntervalMs);
|
|
519
|
+
}
|
|
520
|
+
if (!config.tokens?.access_token) return new Response(null, {
|
|
521
|
+
status: 401,
|
|
522
|
+
statusText: "Missing access token"
|
|
375
523
|
});
|
|
524
|
+
return null;
|
|
525
|
+
}
|
|
526
|
+
//#endregion
|
|
527
|
+
//#region src/oidcConfig.ts
|
|
528
|
+
var getOidcServerUrls = (oidcServerConfiguration) => {
|
|
529
|
+
return [
|
|
530
|
+
oidcServerConfiguration.issuer,
|
|
531
|
+
oidcServerConfiguration.authorizationEndpoint,
|
|
532
|
+
oidcServerConfiguration.tokenEndpoint,
|
|
533
|
+
oidcServerConfiguration.revocationEndpoint,
|
|
534
|
+
oidcServerConfiguration.userInfoEndpoint
|
|
535
|
+
].filter(Boolean).map(normalizeUrl);
|
|
376
536
|
};
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
537
|
+
var isOidcServerRequest = (database, normalizedUrl) => {
|
|
538
|
+
return Object.values(database).some((config) => {
|
|
539
|
+
const { oidcServerConfiguration } = config || {};
|
|
540
|
+
if (!oidcServerConfiguration) return false;
|
|
541
|
+
return getOidcServerUrls(oidcServerConfiguration).some((oidcUrl) => normalizedUrl.startsWith(oidcUrl));
|
|
542
|
+
});
|
|
543
|
+
};
|
|
544
|
+
var isDomainMatchingUrl = (domain, normalizedUrl) => {
|
|
545
|
+
if (typeof domain === "string") domain = new RegExp(`^${domain}`);
|
|
546
|
+
return domain.test?.(normalizedUrl) ?? false;
|
|
547
|
+
};
|
|
548
|
+
var isAccessTokenDomainRequest = (database, normalizedUrl, trustedDomains) => {
|
|
549
|
+
return Object.entries(database).some(([key, currentDatabase]) => {
|
|
550
|
+
if (!currentDatabase.oidcServerConfiguration) return false;
|
|
551
|
+
const domains = getDomains(trustedDomains?.[key.split("#")[0]] ?? [], "accessToken");
|
|
552
|
+
if (domains.some((domain) => domain === "*")) return true;
|
|
553
|
+
return domains.some((domain) => isDomainMatchingUrl(domain, normalizedUrl));
|
|
393
554
|
});
|
|
394
|
-
|
|
555
|
+
};
|
|
556
|
+
var shouldBypassNonOidcRequest = (database, normalizedUrl, trustedDomains) => {
|
|
557
|
+
const configurations = Object.values(database);
|
|
558
|
+
if (configurations.length === 0) return false;
|
|
559
|
+
if (!configurations.every((config) => config.bypassAllNonOidcRequests)) return false;
|
|
560
|
+
if (!configurations.every((config) => config.oidcServerConfiguration != null)) return false;
|
|
561
|
+
return !isOidcServerRequest(database, normalizedUrl) && !isAccessTokenDomainRequest(database, normalizedUrl, trustedDomains);
|
|
562
|
+
};
|
|
563
|
+
var getMatchingOidcConfigurations = (database, url) => {
|
|
564
|
+
const normalizedUrl = normalizeUrl(url);
|
|
565
|
+
return getTokenContexts(database).filter((config) => {
|
|
566
|
+
const { oidcServerConfiguration } = config || {};
|
|
567
|
+
const { tokenEndpoint, revocationEndpoint } = oidcServerConfiguration || {};
|
|
568
|
+
return tokenEndpoint && normalizedUrl.startsWith(normalizeUrl(tokenEndpoint)) || revocationEndpoint && normalizedUrl.startsWith(normalizeUrl(revocationEndpoint));
|
|
569
|
+
});
|
|
570
|
+
};
|
|
571
|
+
//#endregion
|
|
572
|
+
//#region src/utils/codeVerifier.ts
|
|
573
|
+
function replaceCodeVerifier(codeVerifier, newCodeVerifier) {
|
|
574
|
+
return codeVerifier.replace(/[?&]code_verifier=([^&]+)/i, `&code_verifier=${newCodeVerifier}`);
|
|
395
575
|
}
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
//#
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
var
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
}
|
|
432
|
-
var shouldBypassNonOidcRequest = (database, normalizedUrl, trustedDomains) => {
|
|
433
|
-
const configurations = Object.values(database);
|
|
434
|
-
if (configurations.length === 0) return false;
|
|
435
|
-
if (!configurations.every((config) => config.bypassAllNonOidcRequests)) return false;
|
|
436
|
-
if (!configurations.every((config) => config.oidcServerConfiguration != null)) return false;
|
|
437
|
-
return !isOidcServerRequest(database, normalizedUrl) && !isAccessTokenDomainRequest(database, normalizedUrl, trustedDomains);
|
|
438
|
-
};
|
|
439
|
-
var getMatchingOidcConfigurations = (database, url) => {
|
|
440
|
-
const normalizedUrl = normalizeUrl(url);
|
|
441
|
-
return Object.values(database).filter((config) => {
|
|
442
|
-
const { oidcServerConfiguration } = config || {};
|
|
443
|
-
const { tokenEndpoint, revocationEndpoint } = oidcServerConfiguration || {};
|
|
444
|
-
return tokenEndpoint && normalizedUrl.startsWith(normalizeUrl(tokenEndpoint)) || revocationEndpoint && normalizedUrl.startsWith(normalizeUrl(revocationEndpoint));
|
|
445
|
-
});
|
|
446
|
-
};
|
|
447
|
-
//#endregion
|
|
448
|
-
//#region src/utils/codeVerifier.ts
|
|
449
|
-
function replaceCodeVerifier(codeVerifier, newCodeVerifier) {
|
|
450
|
-
return codeVerifier.replace(/[?&]code_verifier=([^&]+)/i, `&code_verifier=${newCodeVerifier}`);
|
|
451
|
-
}
|
|
452
|
-
var extractConfigurationNameFromCodeVerifier = (body) => {
|
|
453
|
-
const match = body.match(/[?&]code_verifier=CODE_VERIFIER_SECURED_BY_OIDC_SERVICE_WORKER_([^&]+)/);
|
|
454
|
-
return match ? decodeURIComponent(match[1]) : "";
|
|
455
|
-
};
|
|
456
|
-
//#endregion
|
|
457
|
-
//#region src/version.ts
|
|
458
|
-
var version_default = "7.29.8";
|
|
459
|
-
//#endregion
|
|
460
|
-
//#region src/OidcServiceWorker.ts
|
|
461
|
-
if (typeof trustedTypes !== "undefined" && typeof trustedTypes.createPolicy === "function") trustedTypes.createPolicy("default", { createScriptURL: function(url) {
|
|
462
|
-
if (url === "OidcTrustedDomains.js") return url;
|
|
463
|
-
else throw new Error("Untrusted script URL blocked: " + url);
|
|
464
|
-
} });
|
|
465
|
-
var _self = self;
|
|
466
|
-
_self.importScripts(scriptFilename);
|
|
467
|
-
var id = Math.round((/* @__PURE__ */ new Date()).getTime() / 1e3).toString();
|
|
468
|
-
console.log("init service worker with id", id);
|
|
469
|
-
var keepAliveJsonFilename = "OidcKeepAliveServiceWorker.json";
|
|
470
|
-
var database = {};
|
|
471
|
-
/**
|
|
472
|
-
* Keeps the service worker alive by responding with a cached response after a sleep.
|
|
473
|
-
*/
|
|
474
|
-
var keepAliveAsync = async (event) => {
|
|
475
|
-
const originalRequest = event.request;
|
|
476
|
-
const isFromVanilla = originalRequest.headers.has("oidc-vanilla");
|
|
477
|
-
const response = new Response("{}", {
|
|
478
|
-
status: 200,
|
|
479
|
-
statusText: "oidc-service-worker"
|
|
480
|
-
});
|
|
481
|
-
if (!isFromVanilla) {
|
|
482
|
-
const originalRequestUrl = new URL(originalRequest.url);
|
|
483
|
-
const minSleepSeconds = Number(originalRequestUrl.searchParams.get("minSleepSeconds")) || 240;
|
|
484
|
-
for (let i = 0; i < minSleepSeconds; i++) {
|
|
485
|
-
await sleep(1e3 + Math.floor(Math.random() * 1e3));
|
|
486
|
-
await (await caches.open("oidc_dummy_cache")).put(event.request, response.clone());
|
|
576
|
+
var extractConfigurationNameFromCodeVerifier = (body) => {
|
|
577
|
+
const match = body.match(/[?&]code_verifier=CODE_VERIFIER_SECURED_BY_OIDC_SERVICE_WORKER_([^&]+)/);
|
|
578
|
+
return match ? decodeURIComponent(match[1]) : "";
|
|
579
|
+
};
|
|
580
|
+
//#endregion
|
|
581
|
+
//#region src/version.ts
|
|
582
|
+
var version_default = "7.30.0";
|
|
583
|
+
//#endregion
|
|
584
|
+
//#region src/OidcServiceWorker.ts
|
|
585
|
+
if (typeof trustedTypes !== "undefined" && typeof trustedTypes.createPolicy === "function") trustedTypes.createPolicy("default", { createScriptURL: function(url) {
|
|
586
|
+
if (url === "OidcTrustedDomains.js") return url;
|
|
587
|
+
else throw new Error("Untrusted script URL blocked: " + url);
|
|
588
|
+
} });
|
|
589
|
+
var _self = self;
|
|
590
|
+
_self.importScripts(scriptFilename);
|
|
591
|
+
var id = Math.round((/* @__PURE__ */ new Date()).getTime() / 1e3).toString();
|
|
592
|
+
console.log("init service worker with id", id);
|
|
593
|
+
var keepAliveJsonFilename = "OidcKeepAliveServiceWorker.json";
|
|
594
|
+
var database = {};
|
|
595
|
+
/**
|
|
596
|
+
* Keeps the service worker alive by responding with a cached response after a sleep.
|
|
597
|
+
*/
|
|
598
|
+
var keepAliveAsync = async (event) => {
|
|
599
|
+
const originalRequest = event.request;
|
|
600
|
+
const isFromVanilla = originalRequest.headers.has("oidc-vanilla");
|
|
601
|
+
const response = new Response("{}", {
|
|
602
|
+
status: 200,
|
|
603
|
+
statusText: "oidc-service-worker"
|
|
604
|
+
});
|
|
605
|
+
if (!isFromVanilla) {
|
|
606
|
+
const originalRequestUrl = new URL(originalRequest.url);
|
|
607
|
+
const minSleepSeconds = Number(originalRequestUrl.searchParams.get("minSleepSeconds")) || 240;
|
|
608
|
+
for (let i = 0; i < minSleepSeconds; i++) {
|
|
609
|
+
await sleep(1e3 + Math.floor(Math.random() * 1e3));
|
|
610
|
+
await (await caches.open("oidc_dummy_cache")).put(event.request, response.clone());
|
|
611
|
+
}
|
|
487
612
|
}
|
|
613
|
+
return response;
|
|
614
|
+
};
|
|
615
|
+
/**
|
|
616
|
+
* Generates DPoP headers when a DPoP configuration is present.
|
|
617
|
+
*/
|
|
618
|
+
async function generateDpopAsync(originalRequest, currentDatabase, url, extrasClaims = {}) {
|
|
619
|
+
const headersExtras = serializeHeaders(originalRequest.headers);
|
|
620
|
+
if (currentDatabase?.demonstratingProofOfPossessionConfiguration && currentDatabase.demonstratingProofOfPossessionJwkJson && (!currentDatabase.demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent || currentDatabase.demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent && headersExtras.dpop)) {
|
|
621
|
+
const dpopConfiguration = currentDatabase.demonstratingProofOfPossessionConfiguration;
|
|
622
|
+
const jwk = currentDatabase.demonstratingProofOfPossessionJwkJson;
|
|
623
|
+
const method = originalRequest.method;
|
|
624
|
+
const resourceNonce = currentDatabase.resource ? url === normalizeUrl(currentDatabase.oidcServerConfiguration.tokenEndpoint) ? currentDatabase.demonstratingProofOfPossessionNonce : currentDatabase.demonstratingProofOfPossessionApiNonce : void 0;
|
|
625
|
+
headersExtras.dpop = await generateJwtDemonstratingProofOfPossessionAsync(self)(dpopConfiguration)(jwk, method, url, {
|
|
626
|
+
...extrasClaims,
|
|
627
|
+
...resourceNonce ? { nonce: resourceNonce } : {}
|
|
628
|
+
});
|
|
629
|
+
const nonceHeader = resourceNonce ?? (!currentDatabase.resource ? currentDatabase.demonstratingProofOfPossessionNonce : void 0);
|
|
630
|
+
if (nonceHeader) headersExtras.nonce = nonceHeader;
|
|
631
|
+
}
|
|
632
|
+
return headersExtras;
|
|
488
633
|
}
|
|
489
|
-
return response;
|
|
490
|
-
};
|
|
491
|
-
/**
|
|
492
|
-
* Generates DPoP headers when a DPoP configuration is present.
|
|
493
|
-
*/
|
|
494
|
-
async function generateDpopAsync(originalRequest, currentDatabase, url, extrasClaims = {}) {
|
|
495
|
-
const headersExtras = serializeHeaders(originalRequest.headers);
|
|
496
|
-
if (currentDatabase?.demonstratingProofOfPossessionConfiguration && currentDatabase.demonstratingProofOfPossessionJwkJson && (!currentDatabase.demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent || currentDatabase.demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent && headersExtras.dpop)) {
|
|
497
|
-
const dpopConfiguration = currentDatabase.demonstratingProofOfPossessionConfiguration;
|
|
498
|
-
const jwk = currentDatabase.demonstratingProofOfPossessionJwkJson;
|
|
499
|
-
const method = originalRequest.method;
|
|
500
|
-
headersExtras.dpop = await generateJwtDemonstratingProofOfPossessionAsync(self)(dpopConfiguration)(jwk, method, url, extrasClaims);
|
|
501
|
-
if (currentDatabase.demonstratingProofOfPossessionNonce != null) headersExtras.nonce = currentDatabase.demonstratingProofOfPossessionNonce;
|
|
502
|
-
}
|
|
503
|
-
return headersExtras;
|
|
504
|
-
}
|
|
505
|
-
/**
|
|
506
|
-
* Intercepts fetch requests to inject access tokens and handle token endpoints.
|
|
507
|
-
*/
|
|
508
|
-
var handleFetch = (event) => {
|
|
509
634
|
/**
|
|
510
|
-
*
|
|
635
|
+
* Intercepts fetch requests to inject access tokens and handle token endpoints.
|
|
511
636
|
*/
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
const
|
|
526
|
-
authenticationMode =
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
if (
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
headers
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
637
|
+
var handleFetch = (event) => {
|
|
638
|
+
/**
|
|
639
|
+
* Exit early for requests that do not need to have an auth token attached.
|
|
640
|
+
*/
|
|
641
|
+
if (shouldBypassDestination(event.request.destination, event.request.mode)) return;
|
|
642
|
+
const normalizedUrl = normalizeUrl(event.request.url);
|
|
643
|
+
if (!normalizedUrl.includes(keepAliveJsonFilename) && shouldBypassNonOidcRequest(database, normalizedUrl, trustedDomains)) return;
|
|
644
|
+
event.respondWith((async () => {
|
|
645
|
+
try {
|
|
646
|
+
const originalRequest = event.request;
|
|
647
|
+
const url = normalizedUrl;
|
|
648
|
+
if (url.includes(keepAliveJsonFilename)) return keepAliveAsync(event);
|
|
649
|
+
const currentDatabasesForRequestAccessToken = getCurrentDatabaseDomain(database, url, trustedDomains);
|
|
650
|
+
const authorization = originalRequest.headers.get("authorization");
|
|
651
|
+
let authenticationMode = "Bearer";
|
|
652
|
+
let key = "default";
|
|
653
|
+
if (authorization) {
|
|
654
|
+
const split = authorization.split(" ");
|
|
655
|
+
authenticationMode = split[0];
|
|
656
|
+
if (split[1]?.includes("ACCESS_TOKEN_SECURED_BY_OIDC_SERVICE_WORKER_")) key = split[1].split("ACCESS_TOKEN_SECURED_BY_OIDC_SERVICE_WORKER_")[1];
|
|
657
|
+
}
|
|
658
|
+
const currentDatabaseForRequestAccessToken = currentDatabasesForRequestAccessToken?.find((c) => key.includes("#resource=") ? c.configurationName === key : !c.resource && c.configurationName.endsWith(key));
|
|
659
|
+
if (key.includes("#resource=") && !currentDatabaseForRequestAccessToken) {
|
|
660
|
+
console.error("[OidcServiceWorker] Resource token destination or context is not permitted.");
|
|
661
|
+
return new Response("Resource token destination or context is not permitted.", { status: 403 });
|
|
662
|
+
}
|
|
663
|
+
if (currentDatabaseForRequestAccessToken?.tokens?.access_token) {
|
|
664
|
+
const tokenError = await waitForValidTokens(currentDatabaseForRequestAccessToken);
|
|
665
|
+
if (tokenError) return tokenError;
|
|
666
|
+
const accessToken = currentDatabaseForRequestAccessToken.tokens.access_token;
|
|
667
|
+
const generation = currentDatabaseForRequestAccessToken.generation;
|
|
668
|
+
const parentGeneration = currentDatabaseForRequestAccessToken.parentConfiguration?.generation;
|
|
669
|
+
let requestMode = originalRequest.mode;
|
|
670
|
+
if (originalRequest.mode !== "navigate" && currentDatabaseForRequestAccessToken.convertAllRequestsToCorsExceptNavigate) requestMode = "cors";
|
|
671
|
+
let headers;
|
|
672
|
+
if (originalRequest.mode === "navigate" && !currentDatabaseForRequestAccessToken.setAccessTokenToNavigateRequests) headers = { ...serializeHeaders(originalRequest.headers) };
|
|
673
|
+
else if (authenticationMode.toLowerCase() === "dpop" || !currentDatabaseForRequestAccessToken.demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent && currentDatabaseForRequestAccessToken.demonstratingProofOfPossessionConfiguration) headers = {
|
|
674
|
+
...await generateDpopAsync(originalRequest, currentDatabaseForRequestAccessToken, url, { ath: await base64urlOfHashOfASCIIEncodingAsync(accessToken) }),
|
|
675
|
+
authorization: `DPoP ${accessToken}`
|
|
676
|
+
};
|
|
677
|
+
else headers = {
|
|
678
|
+
...serializeHeaders(originalRequest.headers),
|
|
679
|
+
authorization: `${authenticationMode} ${accessToken}`
|
|
680
|
+
};
|
|
681
|
+
let init;
|
|
682
|
+
if (originalRequest.mode === "navigate") init = { headers };
|
|
683
|
+
else init = {
|
|
684
|
+
headers,
|
|
685
|
+
mode: requestMode
|
|
686
|
+
};
|
|
687
|
+
const newRequest = new Request(originalRequest, init);
|
|
688
|
+
if (currentDatabaseForRequestAccessToken.resource && (currentDatabaseForRequestAccessToken.generation !== generation || currentDatabaseForRequestAccessToken.parentConfiguration?.generation !== parentGeneration || currentDatabaseForRequestAccessToken.tokens?.access_token !== accessToken)) {
|
|
689
|
+
console.error("[OidcServiceWorker] The resource token changed before dispatch.");
|
|
690
|
+
return new Response("The resource token changed before dispatch.", { status: 403 });
|
|
691
|
+
}
|
|
692
|
+
const response = await fetch(newRequest, currentDatabaseForRequestAccessToken.resource ? { redirect: "error" } : void 0);
|
|
693
|
+
if (currentDatabaseForRequestAccessToken.resource && currentDatabaseForRequestAccessToken.generation === generation && currentDatabaseForRequestAccessToken.parentConfiguration?.generation === parentGeneration && response.headers.has("DPoP-Nonce")) currentDatabaseForRequestAccessToken.demonstratingProofOfPossessionApiNonce = response.headers.get("DPoP-Nonce");
|
|
694
|
+
return response;
|
|
695
|
+
}
|
|
696
|
+
if (event.request.method !== "POST") return fetch(originalRequest);
|
|
697
|
+
const currentDatabases = getMatchingOidcConfigurations(database, url);
|
|
698
|
+
const numberDatabase = currentDatabases.length;
|
|
699
|
+
if (numberDatabase > 0) return await new Promise((resolve, reject) => {
|
|
700
|
+
const clonedRequest = originalRequest.clone();
|
|
701
|
+
clonedRequest.text().then(async (actualBody) => {
|
|
702
|
+
let currentDatabase = null;
|
|
703
|
+
try {
|
|
704
|
+
if (actualBody.includes(TOKEN.REFRESH_TOKEN) || actualBody.includes(TOKEN.ACCESS_TOKEN)) {
|
|
705
|
+
let headers = serializeHeaders(originalRequest.headers);
|
|
706
|
+
let newBody = actualBody;
|
|
707
|
+
for (let i = 0; i < numberDatabase; i++) {
|
|
708
|
+
const currentDb = currentDatabases[i];
|
|
709
|
+
if (currentDb?.tokens) {
|
|
710
|
+
const claimsExtras = { ath: await base64urlOfHashOfASCIIEncodingAsync(currentDb.tokens.access_token) };
|
|
711
|
+
const keyRefreshToken = encodeURIComponent(`${TOKEN.REFRESH_TOKEN}_${currentDb.configurationName}`);
|
|
712
|
+
if ([new URLSearchParams(actualBody).get("refresh_token"), new URLSearchParams(actualBody).get("token")].includes(decodeURIComponent(keyRefreshToken))) {
|
|
713
|
+
const form = new URLSearchParams(actualBody);
|
|
714
|
+
const selected = form.getAll("resource");
|
|
715
|
+
const resourceHeader = originalRequest.headers.get(RESOURCE_TOKEN_REQUEST_HEADER);
|
|
716
|
+
if (currentDb.oidcServerConfiguration?.revocationEndpoint && url === normalizeUrl(currentDb.oidcServerConfiguration.revocationEndpoint) && form.has("token")) currentDatabase = currentDb;
|
|
717
|
+
else if (resourceHeader !== null) {
|
|
718
|
+
const resource = decodeURIComponent(resourceHeader);
|
|
719
|
+
if (selected.length !== 1 || selected[0] !== resource) throw new Error("The resource routing hint must match the request.");
|
|
720
|
+
if (!currentDb.oidcConfiguration) throw new Error("The resource grant configuration is unavailable.");
|
|
721
|
+
const resourceConfiguration = getResourceConfiguration(currentDb.oidcConfiguration.resources, resource);
|
|
722
|
+
const grantedScope = currentDb.tokens.scope ?? currentDb.authorizationScope ?? currentDb.oidcConfiguration.scope;
|
|
723
|
+
if ([form.get("scope"), resourceConfiguration.scope].filter((scope) => typeof scope === "string").some((scope) => !scope.split(/\s+/).filter(Boolean).every((value) => grantedScope?.split(/\s+/).includes(value)))) throw new Error("The resource scope is outside this refresh grant.");
|
|
724
|
+
if (currentDb.resource !== void 0 ? currentDb.resource !== resource : !(typeof currentDb.oidcConfiguration.resource === "string" ? [currentDb.oidcConfiguration.resource] : currentDb.oidcConfiguration.resource ?? []).includes(resource)) throw new Error("The resource is outside this refresh grant.");
|
|
725
|
+
currentDatabase = currentDb.resource ? currentDb : getOrCreateResourceContext(currentDb, resource);
|
|
726
|
+
currentDatabase.refreshGrant = currentDb;
|
|
727
|
+
currentDatabase.requestedScope = form.get("scope") ?? grantedScope;
|
|
728
|
+
currentDatabase.nonce = currentDb.nonce;
|
|
729
|
+
currentDatabase.demonstratingProofOfPossessionJwkJson = currentDb.demonstratingProofOfPossessionJwkJson;
|
|
730
|
+
currentDatabase.demonstratingProofOfPossessionConfiguration = currentDb.demonstratingProofOfPossessionConfiguration;
|
|
731
|
+
currentDatabase.demonstratingProofOfPossessionNonce = currentDb.demonstratingProofOfPossessionNonce;
|
|
732
|
+
} else if (currentDb.resource) throw new Error("A resource refresh must select exactly its own resource.");
|
|
733
|
+
else {
|
|
734
|
+
currentDatabase = currentDb;
|
|
735
|
+
currentDatabase.requestedScope = form.get("scope") ?? currentDb.tokens.scope;
|
|
736
|
+
}
|
|
737
|
+
headers = await generateDpopAsync(originalRequest, currentDatabase, url, claimsExtras);
|
|
738
|
+
newBody = newBody.replace(keyRefreshToken, encodeURIComponent(currentDb.tokens.refresh_token));
|
|
739
|
+
break;
|
|
740
|
+
}
|
|
741
|
+
const keyAccessToken = encodeURIComponent(`${TOKEN.ACCESS_TOKEN}_${currentDb.configurationName}`);
|
|
742
|
+
if (new URLSearchParams(actualBody).get("token") === decodeURIComponent(keyAccessToken)) {
|
|
743
|
+
headers = await generateDpopAsync(originalRequest, currentDb, url, claimsExtras);
|
|
744
|
+
newBody = newBody.replace(keyAccessToken, encodeURIComponent(currentDb.tokens.access_token));
|
|
745
|
+
currentDatabase = currentDb;
|
|
746
|
+
break;
|
|
747
|
+
}
|
|
581
748
|
}
|
|
582
749
|
}
|
|
750
|
+
if (!currentDatabase) throw new Error("The token placeholder does not identify an available grant.");
|
|
751
|
+
delete headers[RESOURCE_TOKEN_REQUEST_HEADER];
|
|
752
|
+
const generation = currentDatabase.generation;
|
|
753
|
+
const grant = currentDatabase.refreshGrant ?? currentDatabase;
|
|
754
|
+
const grantGeneration = grant.generation;
|
|
755
|
+
if (currentDatabase.resource && url !== normalizeUrl(currentDatabase.oidcServerConfiguration.tokenEndpoint) && url !== normalizeUrl(currentDatabase.oidcServerConfiguration.revocationEndpoint)) throw new Error("Resource tokens may only be sent to their exact token endpoint.");
|
|
756
|
+
const fetchPromise = fetch(originalRequest, {
|
|
757
|
+
body: newBody,
|
|
758
|
+
method: clonedRequest.method,
|
|
759
|
+
headers,
|
|
760
|
+
mode: clonedRequest.mode,
|
|
761
|
+
cache: clonedRequest.cache,
|
|
762
|
+
redirect: clonedRequest.redirect,
|
|
763
|
+
referrer: clonedRequest.referrer,
|
|
764
|
+
credentials: clonedRequest.credentials,
|
|
765
|
+
integrity: clonedRequest.integrity
|
|
766
|
+
});
|
|
767
|
+
if (currentDatabase?.oidcServerConfiguration?.revocationEndpoint && url.startsWith(normalizeUrl(currentDatabase.oidcServerConfiguration.revocationEndpoint))) {
|
|
768
|
+
const resp = await fetchPromise;
|
|
769
|
+
const txt = await resp.text();
|
|
770
|
+
resolve(new Response(txt, resp));
|
|
771
|
+
return;
|
|
772
|
+
}
|
|
773
|
+
resolve(await fetchPromise.then(hideTokens(currentDatabase, () => currentDatabase.generation === generation && grant.generation === grantGeneration, () => grant.generation === grantGeneration)));
|
|
774
|
+
return;
|
|
583
775
|
}
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
const
|
|
597
|
-
|
|
598
|
-
|
|
776
|
+
if (actualBody.includes("code_verifier=")) {
|
|
777
|
+
const currentLoginCallbackConfigurationName = extractConfigurationNameFromCodeVerifier(actualBody);
|
|
778
|
+
if (!currentLoginCallbackConfigurationName || currentLoginCallbackConfigurationName === "") throw new Error("No configuration name found in code_verifier");
|
|
779
|
+
currentDatabase = getTokenContexts(database).find((context) => context.configurationName === currentLoginCallbackConfigurationName) ?? null;
|
|
780
|
+
if (!currentDatabase) throw new Error("No available authorization transaction matches the code verifier.");
|
|
781
|
+
if (currentDatabase.resource) {
|
|
782
|
+
const selected = new URLSearchParams(actualBody).getAll("resource");
|
|
783
|
+
if (selected.length !== 1 || selected[0] !== currentDatabase.resource) throw new Error("Authorization resource mismatch.");
|
|
784
|
+
if (url !== normalizeUrl(currentDatabase.oidcServerConfiguration.tokenEndpoint)) throw new Error("Invalid resource token endpoint.");
|
|
785
|
+
currentDatabase.refreshGrant = currentDatabase;
|
|
786
|
+
}
|
|
787
|
+
currentDatabase.requestedScope = currentDatabase.authorizationScope ?? (currentDatabase.resource ? getResourceConfiguration(currentDatabase.oidcConfiguration?.resources, currentDatabase.resource).scope : currentDatabase.oidcConfiguration?.scope);
|
|
788
|
+
const generation = currentDatabase.generation;
|
|
789
|
+
let newBody = actualBody;
|
|
790
|
+
const codeVerifier = currentDatabase.codeVerifier;
|
|
791
|
+
if (codeVerifier != null) newBody = replaceCodeVerifier(newBody, codeVerifier);
|
|
792
|
+
const headersExtras = await generateDpopAsync(originalRequest, currentDatabase, url);
|
|
793
|
+
const resp = await fetch(originalRequest, {
|
|
794
|
+
body: newBody,
|
|
795
|
+
method: clonedRequest.method,
|
|
796
|
+
headers: headersExtras,
|
|
797
|
+
mode: clonedRequest.mode,
|
|
798
|
+
cache: clonedRequest.cache,
|
|
799
|
+
redirect: clonedRequest.redirect,
|
|
800
|
+
referrer: clonedRequest.referrer,
|
|
801
|
+
credentials: clonedRequest.credentials,
|
|
802
|
+
integrity: clonedRequest.integrity
|
|
803
|
+
});
|
|
804
|
+
resolve(await hideTokens(currentDatabase, () => currentDatabase.generation === generation, void 0, true)(resp));
|
|
599
805
|
return;
|
|
600
806
|
}
|
|
601
|
-
resolve(await
|
|
602
|
-
|
|
603
|
-
}
|
|
604
|
-
if (actualBody.includes("code_verifier=")) {
|
|
605
|
-
const currentLoginCallbackConfigurationName = extractConfigurationNameFromCodeVerifier(actualBody);
|
|
606
|
-
if (!currentLoginCallbackConfigurationName || currentLoginCallbackConfigurationName === "") throw new Error("No configuration name found in code_verifier");
|
|
607
|
-
currentDatabase = database[currentLoginCallbackConfigurationName];
|
|
608
|
-
let newBody = actualBody;
|
|
609
|
-
const codeVerifier = currentDatabase.codeVerifier;
|
|
610
|
-
if (codeVerifier != null) newBody = replaceCodeVerifier(newBody, codeVerifier);
|
|
611
|
-
const headersExtras = await generateDpopAsync(originalRequest, currentDatabase, url);
|
|
612
|
-
const resp = await fetch(originalRequest, {
|
|
613
|
-
body: newBody,
|
|
807
|
+
resolve(await fetch(originalRequest, {
|
|
808
|
+
body: actualBody,
|
|
614
809
|
method: clonedRequest.method,
|
|
615
|
-
headers:
|
|
810
|
+
headers: serializeHeaders(originalRequest.headers),
|
|
616
811
|
mode: clonedRequest.mode,
|
|
617
812
|
cache: clonedRequest.cache,
|
|
618
813
|
redirect: clonedRequest.redirect,
|
|
619
814
|
referrer: clonedRequest.referrer,
|
|
620
815
|
credentials: clonedRequest.credentials,
|
|
621
816
|
integrity: clonedRequest.integrity
|
|
622
|
-
});
|
|
623
|
-
|
|
624
|
-
|
|
817
|
+
}));
|
|
818
|
+
} catch (err) {
|
|
819
|
+
reject(err);
|
|
625
820
|
}
|
|
626
|
-
|
|
627
|
-
body: actualBody,
|
|
628
|
-
method: clonedRequest.method,
|
|
629
|
-
headers: serializeHeaders(originalRequest.headers),
|
|
630
|
-
mode: clonedRequest.mode,
|
|
631
|
-
cache: clonedRequest.cache,
|
|
632
|
-
redirect: clonedRequest.redirect,
|
|
633
|
-
referrer: clonedRequest.referrer,
|
|
634
|
-
credentials: clonedRequest.credentials,
|
|
635
|
-
integrity: clonedRequest.integrity
|
|
636
|
-
}));
|
|
637
|
-
} catch (err) {
|
|
638
|
-
reject(err);
|
|
639
|
-
}
|
|
640
|
-
}).catch(reject);
|
|
641
|
-
});
|
|
642
|
-
return fetch(originalRequest);
|
|
643
|
-
} catch (err) {
|
|
644
|
-
console.error("[OidcServiceWorker] handleFetch error:", err);
|
|
645
|
-
return new Response("Service Worker Error", { status: 500 });
|
|
646
|
-
}
|
|
647
|
-
})());
|
|
648
|
-
};
|
|
649
|
-
var handleMessage = async (event) => {
|
|
650
|
-
const port = event.ports[0];
|
|
651
|
-
const data = event.data;
|
|
652
|
-
if (event.data?.type === "SKIP_WAITING") {
|
|
653
|
-
await _self.skipWaiting();
|
|
654
|
-
port?.postMessage?.({});
|
|
655
|
-
return;
|
|
656
|
-
} else if (event.data.type === "claim") {
|
|
657
|
-
_self.clients.claim().then(() => port.postMessage({}));
|
|
658
|
-
return;
|
|
659
|
-
}
|
|
660
|
-
const configurationName = data.configurationName.split("#")[0];
|
|
661
|
-
if (trustedDomains == null) trustedDomains = {};
|
|
662
|
-
const trustedDomain = trustedDomains[configurationName];
|
|
663
|
-
const allowMultiTabLogin = Array.isArray(trustedDomain) ? false : trustedDomain.allowMultiTabLogin;
|
|
664
|
-
const tabId = allowMultiTabLogin ? data.tabId : "default";
|
|
665
|
-
const configurationNameWithTabId = `${configurationName}#tabId=${tabId}`;
|
|
666
|
-
let currentDatabase = database[configurationNameWithTabId];
|
|
667
|
-
if (!currentDatabase) {
|
|
668
|
-
const showAccessToken = Array.isArray(trustedDomain) ? false : trustedDomain.showAccessToken;
|
|
669
|
-
const doNotSetAccessTokenToNavigateRequests = Array.isArray(trustedDomain) ? true : trustedDomain.setAccessTokenToNavigateRequests;
|
|
670
|
-
const convertAllRequestsToCorsExceptNavigate = Array.isArray(trustedDomain) ? false : trustedDomain.convertAllRequestsToCorsExceptNavigate;
|
|
671
|
-
const bypassAllNonOidcRequests = Array.isArray(trustedDomain) ? false : trustedDomain.bypassAllNonOidcRequests;
|
|
672
|
-
database[configurationNameWithTabId] = {
|
|
673
|
-
tokens: null,
|
|
674
|
-
state: null,
|
|
675
|
-
codeVerifier: null,
|
|
676
|
-
oidcServerConfiguration: null,
|
|
677
|
-
oidcConfiguration: void 0,
|
|
678
|
-
nonce: null,
|
|
679
|
-
status: null,
|
|
680
|
-
configurationName: configurationNameWithTabId,
|
|
681
|
-
hideAccessToken: !showAccessToken,
|
|
682
|
-
setAccessTokenToNavigateRequests: doNotSetAccessTokenToNavigateRequests ?? true,
|
|
683
|
-
convertAllRequestsToCorsExceptNavigate: convertAllRequestsToCorsExceptNavigate ?? false,
|
|
684
|
-
demonstratingProofOfPossessionNonce: null,
|
|
685
|
-
demonstratingProofOfPossessionJwkJson: null,
|
|
686
|
-
demonstratingProofOfPossessionConfiguration: null,
|
|
687
|
-
demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent: false,
|
|
688
|
-
allowMultiTabLogin: allowMultiTabLogin ?? false,
|
|
689
|
-
bypassAllNonOidcRequests: bypassAllNonOidcRequests ?? false
|
|
690
|
-
};
|
|
691
|
-
currentDatabase = database[configurationNameWithTabId];
|
|
692
|
-
if (!trustedDomains[configurationName]) trustedDomains[configurationName] = [];
|
|
693
|
-
}
|
|
694
|
-
switch (data.type) {
|
|
695
|
-
case "clear":
|
|
696
|
-
currentDatabase.tokens = null;
|
|
697
|
-
currentDatabase.state = null;
|
|
698
|
-
currentDatabase.codeVerifier = null;
|
|
699
|
-
currentDatabase.nonce = null;
|
|
700
|
-
currentDatabase.demonstratingProofOfPossessionNonce = null;
|
|
701
|
-
currentDatabase.demonstratingProofOfPossessionJwkJson = null;
|
|
702
|
-
currentDatabase.demonstratingProofOfPossessionConfiguration = null;
|
|
703
|
-
currentDatabase.demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent = false;
|
|
704
|
-
currentDatabase.status = data.data.status;
|
|
705
|
-
port.postMessage({ configurationName });
|
|
706
|
-
return;
|
|
707
|
-
case "init": {
|
|
708
|
-
const oidcServerConfiguration = data.data.oidcServerConfiguration;
|
|
709
|
-
const domains = getDomains(trustedDomain, "oidc");
|
|
710
|
-
if (!domains.some((domain) => domain === "*")) [
|
|
711
|
-
oidcServerConfiguration.tokenEndpoint,
|
|
712
|
-
oidcServerConfiguration.revocationEndpoint,
|
|
713
|
-
oidcServerConfiguration.userInfoEndpoint,
|
|
714
|
-
oidcServerConfiguration.issuer
|
|
715
|
-
].forEach((u) => {
|
|
716
|
-
checkDomain(domains, u);
|
|
717
|
-
});
|
|
718
|
-
currentDatabase.oidcServerConfiguration = oidcServerConfiguration;
|
|
719
|
-
currentDatabase.oidcConfiguration = data.data.oidcConfiguration;
|
|
720
|
-
if (currentDatabase.demonstratingProofOfPossessionConfiguration == null) {
|
|
721
|
-
const demonstratingProofOfPossessionConfiguration = getDpopConfiguration(trustedDomain);
|
|
722
|
-
if (demonstratingProofOfPossessionConfiguration != null) {
|
|
723
|
-
if (currentDatabase.oidcConfiguration.demonstrating_proof_of_possession) console.warn("In service worker, demonstrating_proof_of_possession must be configured from trustedDomains file");
|
|
724
|
-
currentDatabase.demonstratingProofOfPossessionConfiguration = demonstratingProofOfPossessionConfiguration;
|
|
725
|
-
currentDatabase.demonstratingProofOfPossessionJwkJson = await generateJwkAsync(self)(demonstratingProofOfPossessionConfiguration.generateKeyAlgorithm);
|
|
726
|
-
currentDatabase.demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent = getDpopOnlyWhenDpopHeaderPresent(trustedDomain) ?? false;
|
|
727
|
-
}
|
|
728
|
-
}
|
|
729
|
-
if (!currentDatabase.tokens) port.postMessage({
|
|
730
|
-
tokens: null,
|
|
731
|
-
status: currentDatabase.status,
|
|
732
|
-
configurationName,
|
|
733
|
-
version: version_default
|
|
734
|
-
});
|
|
735
|
-
else {
|
|
736
|
-
const tokens = { ...currentDatabase.tokens };
|
|
737
|
-
if (currentDatabase.hideAccessToken) tokens.access_token = `${TOKEN.ACCESS_TOKEN}_${configurationName}#tabId=${tabId}`;
|
|
738
|
-
if (tokens.refresh_token) tokens.refresh_token = `${TOKEN.REFRESH_TOKEN}_${configurationName}#tabId=${tabId}`;
|
|
739
|
-
if (tokens?.idTokenPayload?.nonce && currentDatabase.nonce != null) tokens.idTokenPayload.nonce = `${TOKEN.NONCE_TOKEN}_${configurationName}#tabId=${tabId}`;
|
|
740
|
-
port.postMessage({
|
|
741
|
-
tokens,
|
|
742
|
-
status: currentDatabase.status,
|
|
743
|
-
configurationName,
|
|
744
|
-
version: version_default
|
|
821
|
+
}).catch(reject);
|
|
745
822
|
});
|
|
823
|
+
return fetch(originalRequest);
|
|
824
|
+
} catch (err) {
|
|
825
|
+
console.error("[OidcServiceWorker] handleFetch error:", err);
|
|
826
|
+
return new Response("Service Worker Error", { status: 500 });
|
|
746
827
|
}
|
|
828
|
+
})());
|
|
829
|
+
};
|
|
830
|
+
var handleMessageAsync = async (event) => {
|
|
831
|
+
const port = event.ports[0];
|
|
832
|
+
const data = event.data;
|
|
833
|
+
if (event.data?.type === "SKIP_WAITING") {
|
|
834
|
+
await _self.skipWaiting();
|
|
835
|
+
port?.postMessage?.({});
|
|
747
836
|
return;
|
|
748
|
-
}
|
|
749
|
-
|
|
750
|
-
currentDatabase.demonstratingProofOfPossessionNonce = data.data.demonstratingProofOfPossessionNonce;
|
|
751
|
-
port.postMessage({ configurationName });
|
|
752
|
-
return;
|
|
753
|
-
case "getDemonstratingProofOfPossessionNonce": {
|
|
754
|
-
const demonstratingProofOfPossessionNonce = currentDatabase.demonstratingProofOfPossessionNonce;
|
|
755
|
-
port.postMessage({
|
|
756
|
-
configurationName,
|
|
757
|
-
demonstratingProofOfPossessionNonce
|
|
758
|
-
});
|
|
759
|
-
return;
|
|
760
|
-
}
|
|
761
|
-
case "setState":
|
|
762
|
-
currentDatabase.state = data.data.state;
|
|
763
|
-
port.postMessage({ configurationName });
|
|
764
|
-
return;
|
|
765
|
-
case "getState": {
|
|
766
|
-
const state = currentDatabase.state;
|
|
767
|
-
port.postMessage({
|
|
768
|
-
configurationName,
|
|
769
|
-
state
|
|
770
|
-
});
|
|
837
|
+
} else if (event.data.type === "claim") {
|
|
838
|
+
_self.clients.claim().then(() => port.postMessage({}));
|
|
771
839
|
return;
|
|
772
840
|
}
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
841
|
+
const configurationName = data.configurationName.split("#")[0];
|
|
842
|
+
const resource = getContextResource(data.configurationName);
|
|
843
|
+
if (trustedDomains == null) trustedDomains = {};
|
|
844
|
+
const trustedDomain = trustedDomains[configurationName];
|
|
845
|
+
const allowMultiTabLogin = Array.isArray(trustedDomain) ? false : trustedDomain.allowMultiTabLogin;
|
|
846
|
+
const configurationNameWithTabId = `${configurationName}#tabId=${allowMultiTabLogin ? data.tabId : "default"}`;
|
|
847
|
+
let currentDatabase = database[configurationNameWithTabId];
|
|
848
|
+
if (!currentDatabase) {
|
|
849
|
+
const showAccessToken = Array.isArray(trustedDomain) ? false : trustedDomain.showAccessToken;
|
|
850
|
+
const doNotSetAccessTokenToNavigateRequests = Array.isArray(trustedDomain) ? true : trustedDomain.setAccessTokenToNavigateRequests;
|
|
851
|
+
const convertAllRequestsToCorsExceptNavigate = Array.isArray(trustedDomain) ? false : trustedDomain.convertAllRequestsToCorsExceptNavigate;
|
|
852
|
+
const bypassAllNonOidcRequests = Array.isArray(trustedDomain) ? false : trustedDomain.bypassAllNonOidcRequests;
|
|
853
|
+
database[configurationNameWithTabId] = {
|
|
854
|
+
tokens: null,
|
|
855
|
+
state: null,
|
|
856
|
+
codeVerifier: null,
|
|
857
|
+
oidcServerConfiguration: null,
|
|
858
|
+
oidcConfiguration: void 0,
|
|
859
|
+
nonce: null,
|
|
860
|
+
status: null,
|
|
861
|
+
configurationName: configurationNameWithTabId,
|
|
862
|
+
hideAccessToken: !showAccessToken,
|
|
863
|
+
setAccessTokenToNavigateRequests: doNotSetAccessTokenToNavigateRequests ?? true,
|
|
864
|
+
convertAllRequestsToCorsExceptNavigate: convertAllRequestsToCorsExceptNavigate ?? false,
|
|
865
|
+
demonstratingProofOfPossessionNonce: null,
|
|
866
|
+
demonstratingProofOfPossessionJwkJson: null,
|
|
867
|
+
demonstratingProofOfPossessionConfiguration: null,
|
|
868
|
+
demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent: false,
|
|
869
|
+
allowMultiTabLogin: allowMultiTabLogin ?? false,
|
|
870
|
+
bypassAllNonOidcRequests: bypassAllNonOidcRequests ?? false
|
|
871
|
+
};
|
|
872
|
+
currentDatabase = database[configurationNameWithTabId];
|
|
873
|
+
if (!trustedDomains[configurationName]) trustedDomains[configurationName] = [];
|
|
784
874
|
}
|
|
785
|
-
|
|
786
|
-
currentDatabase
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
case "getSessionState": {
|
|
790
|
-
const sessionState = currentDatabase.sessionState;
|
|
875
|
+
if (resource !== void 0) try {
|
|
876
|
+
currentDatabase = getOrCreateResourceContext(currentDatabase, resource);
|
|
877
|
+
} catch (error) {
|
|
878
|
+
console.error("[OidcServiceWorker] Invalid resource context:", error);
|
|
791
879
|
port.postMessage({
|
|
792
880
|
configurationName,
|
|
793
|
-
|
|
881
|
+
error: "The resource is not registered."
|
|
794
882
|
});
|
|
795
883
|
return;
|
|
796
884
|
}
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
885
|
+
switch (data.type) {
|
|
886
|
+
case "clear":
|
|
887
|
+
currentDatabase.generation = (currentDatabase.generation ?? 0) + 1;
|
|
888
|
+
for (const entry of Object.values(currentDatabase.resourceEntries ?? {})) entry.generation = (entry.generation ?? 0) + 1;
|
|
889
|
+
currentDatabase.resourceEntries = void 0;
|
|
890
|
+
currentDatabase.tokens = null;
|
|
891
|
+
currentDatabase.state = null;
|
|
892
|
+
currentDatabase.codeVerifier = null;
|
|
893
|
+
currentDatabase.nonce = null;
|
|
894
|
+
currentDatabase.demonstratingProofOfPossessionNonce = null;
|
|
895
|
+
currentDatabase.demonstratingProofOfPossessionJwkJson = null;
|
|
896
|
+
currentDatabase.demonstratingProofOfPossessionConfiguration = null;
|
|
897
|
+
currentDatabase.demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent = false;
|
|
898
|
+
currentDatabase.authorizationScope = void 0;
|
|
899
|
+
currentDatabase.requestedScope = void 0;
|
|
900
|
+
currentDatabase.demonstratingProofOfPossessionApiNonce = null;
|
|
901
|
+
currentDatabase.status = data.data.status;
|
|
902
|
+
port.postMessage({ configurationName });
|
|
903
|
+
return;
|
|
904
|
+
case "init": {
|
|
905
|
+
const oidcServerConfiguration = data.data.oidcServerConfiguration;
|
|
906
|
+
const domains = getDomains(trustedDomain, "oidc");
|
|
907
|
+
if (!domains.some((domain) => domain === "*")) [
|
|
908
|
+
oidcServerConfiguration.tokenEndpoint,
|
|
909
|
+
oidcServerConfiguration.revocationEndpoint,
|
|
910
|
+
oidcServerConfiguration.userInfoEndpoint,
|
|
911
|
+
oidcServerConfiguration.issuer
|
|
912
|
+
].forEach((u) => {
|
|
913
|
+
checkDomain(domains, u);
|
|
914
|
+
});
|
|
915
|
+
currentDatabase.oidcServerConfiguration = oidcServerConfiguration;
|
|
916
|
+
currentDatabase.oidcConfiguration = data.data.oidcConfiguration;
|
|
917
|
+
if (data.data.where === "loginAsync") currentDatabase.authorizationScope = currentDatabase.oidcConfiguration.scope;
|
|
918
|
+
if (resource !== void 0) getResourceConfiguration(currentDatabase.oidcConfiguration.resources, resource);
|
|
919
|
+
if (currentDatabase.demonstratingProofOfPossessionConfiguration == null) {
|
|
920
|
+
const parent = currentDatabase.parentConfiguration;
|
|
921
|
+
if (parent?.demonstratingProofOfPossessionJwkJson) {
|
|
922
|
+
currentDatabase.demonstratingProofOfPossessionJwkJson = parent.demonstratingProofOfPossessionJwkJson;
|
|
923
|
+
currentDatabase.demonstratingProofOfPossessionConfiguration = parent.demonstratingProofOfPossessionConfiguration;
|
|
924
|
+
}
|
|
925
|
+
const demonstratingProofOfPossessionConfiguration = getDpopConfiguration(trustedDomain);
|
|
926
|
+
if (demonstratingProofOfPossessionConfiguration != null && currentDatabase.demonstratingProofOfPossessionConfiguration == null) {
|
|
927
|
+
if (currentDatabase.oidcConfiguration.demonstrating_proof_of_possession) console.warn("In service worker, demonstrating_proof_of_possession must be configured from trustedDomains file");
|
|
928
|
+
currentDatabase.demonstratingProofOfPossessionConfiguration = demonstratingProofOfPossessionConfiguration;
|
|
929
|
+
currentDatabase.demonstratingProofOfPossessionJwkJson = await generateJwkAsync(self)(demonstratingProofOfPossessionConfiguration.generateKeyAlgorithm);
|
|
930
|
+
currentDatabase.demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent = getDpopOnlyWhenDpopHeaderPresent(trustedDomain) ?? false;
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
if (!currentDatabase.tokens) port.postMessage({
|
|
934
|
+
tokens: null,
|
|
935
|
+
status: currentDatabase.status,
|
|
936
|
+
configurationName,
|
|
937
|
+
version: version_default,
|
|
938
|
+
resourceTokenManagement: true,
|
|
939
|
+
resourceContexts: Object.keys(currentDatabase.resourceEntries ?? {})
|
|
940
|
+
});
|
|
941
|
+
else {
|
|
942
|
+
const tokens = {
|
|
943
|
+
...currentDatabase.tokens,
|
|
944
|
+
idTokenPayload: currentDatabase.tokens.idTokenPayload ? { ...currentDatabase.tokens.idTokenPayload } : void 0
|
|
945
|
+
};
|
|
946
|
+
if (currentDatabase.hideAccessToken) tokens.access_token = `${TOKEN.ACCESS_TOKEN}_${currentDatabase.configurationName}`;
|
|
947
|
+
if (tokens.refresh_token) tokens.refresh_token = `${TOKEN.REFRESH_TOKEN}_${(currentDatabase.refreshGrant ?? currentDatabase).configurationName}`;
|
|
948
|
+
if (tokens?.idTokenPayload?.nonce && currentDatabase.nonce != null) tokens.idTokenPayload.nonce = `${TOKEN.NONCE_TOKEN}_${currentDatabase.configurationName}`;
|
|
949
|
+
port.postMessage({
|
|
950
|
+
tokens,
|
|
951
|
+
status: currentDatabase.status,
|
|
952
|
+
configurationName,
|
|
953
|
+
version: version_default,
|
|
954
|
+
resourceTokenManagement: true,
|
|
955
|
+
resourceContexts: Object.keys(currentDatabase.resourceEntries ?? {})
|
|
956
|
+
});
|
|
957
|
+
}
|
|
958
|
+
return;
|
|
959
|
+
}
|
|
960
|
+
case "setDemonstratingProofOfPossessionNonce":
|
|
961
|
+
currentDatabase.demonstratingProofOfPossessionNonce = data.data.demonstratingProofOfPossessionNonce;
|
|
962
|
+
port.postMessage({ configurationName });
|
|
963
|
+
return;
|
|
964
|
+
case "getDemonstratingProofOfPossessionNonce": {
|
|
965
|
+
const demonstratingProofOfPossessionNonce = currentDatabase.demonstratingProofOfPossessionNonce;
|
|
966
|
+
port.postMessage({
|
|
967
|
+
configurationName,
|
|
968
|
+
demonstratingProofOfPossessionNonce
|
|
969
|
+
});
|
|
970
|
+
return;
|
|
971
|
+
}
|
|
972
|
+
case "setState":
|
|
973
|
+
currentDatabase.state = data.data.state;
|
|
974
|
+
port.postMessage({ configurationName });
|
|
975
|
+
return;
|
|
976
|
+
case "getState": {
|
|
977
|
+
const state = currentDatabase.state;
|
|
978
|
+
port.postMessage({
|
|
979
|
+
configurationName,
|
|
980
|
+
state
|
|
981
|
+
});
|
|
982
|
+
return;
|
|
983
|
+
}
|
|
984
|
+
case "setCodeVerifier":
|
|
985
|
+
currentDatabase.codeVerifier = data.data.codeVerifier;
|
|
986
|
+
port.postMessage({ configurationName });
|
|
987
|
+
return;
|
|
988
|
+
case "getCodeVerifier": {
|
|
989
|
+
const codeVerifier = currentDatabase.codeVerifier != null ? `${TOKEN.CODE_VERIFIER}_${currentDatabase.configurationName}` : null;
|
|
990
|
+
port.postMessage({
|
|
991
|
+
configurationName,
|
|
992
|
+
codeVerifier
|
|
993
|
+
});
|
|
994
|
+
return;
|
|
995
|
+
}
|
|
996
|
+
case "setSessionState":
|
|
997
|
+
currentDatabase.sessionState = data.data.sessionState;
|
|
998
|
+
port.postMessage({ configurationName });
|
|
999
|
+
return;
|
|
1000
|
+
case "getSessionState": {
|
|
1001
|
+
const sessionState = currentDatabase.sessionState;
|
|
1002
|
+
port.postMessage({
|
|
1003
|
+
configurationName,
|
|
1004
|
+
sessionState
|
|
1005
|
+
});
|
|
1006
|
+
return;
|
|
1007
|
+
}
|
|
1008
|
+
case "setNonce": {
|
|
1009
|
+
const nonce = data.data.nonce;
|
|
1010
|
+
if (nonce) {
|
|
1011
|
+
if (!currentDatabase.resource && currentDatabase.nonce && nonce.nonce !== currentDatabase.nonce.nonce) {
|
|
1012
|
+
currentDatabase.generation = (currentDatabase.generation ?? 0) + 1;
|
|
1013
|
+
for (const entry of Object.values(currentDatabase.resourceEntries ?? {})) entry.generation = (entry.generation ?? 0) + 1;
|
|
1014
|
+
currentDatabase.resourceEntries = void 0;
|
|
1015
|
+
}
|
|
1016
|
+
currentDatabase.nonce = nonce;
|
|
1017
|
+
}
|
|
1018
|
+
port.postMessage({ configurationName });
|
|
1019
|
+
return;
|
|
1020
|
+
}
|
|
1021
|
+
case "getNonce": {
|
|
1022
|
+
const keyNonce = `${TOKEN.NONCE_TOKEN}_${currentDatabase.configurationName}`;
|
|
1023
|
+
const nonce = currentDatabase.nonce ? keyNonce : null;
|
|
1024
|
+
port.postMessage({
|
|
1025
|
+
configurationName,
|
|
1026
|
+
nonce
|
|
1027
|
+
});
|
|
1028
|
+
return;
|
|
1029
|
+
}
|
|
1030
|
+
default: return;
|
|
802
1031
|
}
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
1032
|
+
};
|
|
1033
|
+
var handleMessage = async (event) => {
|
|
1034
|
+
try {
|
|
1035
|
+
await handleMessageAsync(event);
|
|
1036
|
+
} catch (error) {
|
|
1037
|
+
console.error("[OidcServiceWorker] Message failed:", error);
|
|
1038
|
+
event.ports?.[0]?.postMessage({
|
|
1039
|
+
configurationName: event.data?.configurationName,
|
|
1040
|
+
error: error instanceof Error ? error.message : "The worker could not process this message."
|
|
809
1041
|
});
|
|
810
|
-
return;
|
|
811
1042
|
}
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
//#endregion
|
|
1043
|
+
};
|
|
1044
|
+
_self.addEventListener("fetch", handleFetch);
|
|
1045
|
+
_self.addEventListener("message", handleMessage);
|
|
1046
|
+
//#endregion
|
|
1047
|
+
})();
|
|
818
1048
|
|
|
819
1049
|
//# sourceMappingURL=OidcServiceWorker.js.map
|