@axa-fr/oidc-client-service-worker 7.29.3 → 7.29.5

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 ADDED
@@ -0,0 +1,147 @@
1
+ # @axa-fr/oidc-client-service-worker
2
+
3
+ The service worker used by [`@axa-fr/oidc-client`](../oidc-client/README.md) and
4
+ [`@axa-fr/react-oidc`](../react-oidc/README.md). It intercepts OIDC token responses,
5
+ keeps access and refresh tokens in worker memory by default, and adds access
6
+ tokens to requests that match your trusted-domain configuration.
7
+
8
+ Most applications should install one of the client packages rather than use this
9
+ package directly. The clients handle worker registration and communication.
10
+
11
+ - [How it works](#how-it-works)
12
+ - [Getting started](#getting-started)
13
+ - [Trusted domains](#trusted-domains)
14
+ - [Deployment and troubleshooting](#deployment-and-troubleshooting)
15
+ - [Protocol reference](#protocol-reference)
16
+
17
+ ## How it works
18
+
19
+ ```mermaid
20
+ flowchart LR
21
+ App["Browser application"] --> Client["OIDC client or React bindings"]
22
+ Client <-->|"Messages and token placeholders"| Worker["OIDC service worker"]
23
+ Worker <-->|"Token requests and responses"| Provider["OIDC provider"]
24
+ App -->|"API request"| Worker
25
+ Worker -->|"Access token on trusted requests"| API["Trusted API"]
26
+ Config["OidcTrustedDomains.js"] --> Worker
27
+ ```
28
+
29
+ The application can use token metadata without receiving the real access or
30
+ refresh token. `showAccessToken: true` explicitly exposes the access token to
31
+ application JavaScript while keeping the refresh token in the worker.
32
+
33
+ > [!IMPORTANT]
34
+ > Token isolation does not prevent XSS or CSRF. Injected code can still make
35
+ > authenticated requests from the application. Use a restrictive Content Security
36
+ > Policy, prevent script injection, and enforce authorization on your APIs.
37
+
38
+ ## Getting started
39
+
40
+ 1. Install and configure the [vanilla client](../oidc-client/README.md#getting-started)
41
+ or [React bindings](../react-oidc/README.md#getting-started).
42
+ 2. Create your application's public-assets directory if it does not exist, then
43
+ run the copy command for the client you installed:
44
+
45
+ ```sh
46
+ # Vanilla client
47
+ node ./node_modules/@axa-fr/oidc-client/bin/copy-service-worker-files.mjs public
48
+
49
+ # React — use this instead
50
+ node ./node_modules/@axa-fr/react-oidc/bin/copy-service-worker-files.mjs public
51
+ ```
52
+
53
+ Replace `public` if your framework serves static files from another directory.
54
+ The command overwrites `OidcServiceWorker.js` but preserves an existing
55
+ `OidcTrustedDomains.js`.
56
+
57
+ 3. Replace the sample entries in `public/OidcTrustedDomains.js` with your provider
58
+ and API URLs, as described below.
59
+ 4. Add these fields to your OIDC client configuration:
60
+
61
+ ```js
62
+ const configuration = {
63
+ ...oidcConfiguration,
64
+ service_worker_relative_url: '/OidcServiceWorker.js',
65
+ service_worker_only: true,
66
+ };
67
+ ```
68
+
69
+ With `service_worker_only: true`, authentication requires worker support.
70
+ Set it to `false` only if you accept fallback to JavaScript-accessible browser
71
+ storage when the worker is unavailable.
72
+
73
+ 5. Add the appropriate copy command to your application's `postinstall` script.
74
+ For example, for React:
75
+
76
+ ```json
77
+ {
78
+ "scripts": {
79
+ "postinstall": "node ./node_modules/@axa-fr/react-oidc/bin/copy-service-worker-files.mjs public"
80
+ }
81
+ }
82
+ ```
83
+
84
+ Merge this with existing installation steps rather than replacing them.
85
+ Deploy the copied worker with every client upgrade.
86
+
87
+ ## Trusted domains
88
+
89
+ Keep provider endpoints and API destinations separate:
90
+
91
+ ```js
92
+ const trustedDomains = {
93
+ default: {
94
+ oidcDomains: [/^https:\/\/identity\.example\.com(?:\/|$)/],
95
+ accessTokenDomains: [/^https:\/\/api\.example\.com(?:\/|$)/],
96
+ },
97
+ };
98
+ ```
99
+
100
+ `default` is the default client configuration name. Add a matching entry for
101
+ every named client or `OidcProvider`. These rules use regular-expression matching,
102
+ including when rules are strings. Anchor patterns, escape hostname dots, and
103
+ include a host or path boundary so that lookalike URLs do not match.
104
+ Include the actual OIDC endpoint origins
105
+ if your provider serves discovery, tokens, or user information from different
106
+ hosts. Allow only the API destinations that should receive this configuration's
107
+ access token; do not copy the demo allowlist into production.
108
+
109
+ Use `oidcClient.fetchWithTokens(fetch)` in vanilla applications or `useOidcFetch()`
110
+ in React. In particular, `allowMultiTabLogin: true` **requires** the OIDC fetch
111
+ wrapper: its placeholder identifies the tab whose token the worker must inject.
112
+ A plain `fetch` cannot supply that information.
113
+
114
+ See the [client's service-worker guide](../oidc-client/README.md#service-worker-support)
115
+ for additional options, including DPoP, access-token visibility, and request
116
+ handling.
117
+
118
+ ## Deployment and troubleshooting
119
+
120
+ - Serve both JavaScript files from your application's origin over HTTPS
121
+ (localhost is supported for development).
122
+ - The worker must control the pages that use it. Serving it at the origin root
123
+ is the simplest setup; account for worker scope when hosting under a subpath.
124
+ - Serve the files as JavaScript, not the HTML fallback used for SPA routes.
125
+ Check the Network and Application panels in browser developer tools if
126
+ registration fails.
127
+ - Keep the worker version aligned with the client. Edit the trusted-domain file,
128
+ not the generated `OidcServiceWorker.js`.
129
+ - If API requests return 401, check the active configuration name, the matching
130
+ `accessTokenDomains` entry, and whether you are using the OIDC fetch wrapper.
131
+ The API must also accept the token's issuer, audience, and scopes.
132
+ - After changing worker assets, check which worker version controls your page;
133
+ an already-open tab may still be controlled by an older worker.
134
+
135
+ The [FAQ](../../FAQ.md) covers broader security and integration questions.
136
+
137
+ ## Protocol reference
138
+
139
+ Most applications do not need to send worker messages directly. For custom
140
+ integrations, [`PROTOCOL.md`](./PROTOCOL.md) describes the versioned message
141
+ envelope, payloads, token placeholders, storage keys, and compatibility guarantees.
142
+
143
+ Protocol constants and types are exported from
144
+ `@axa-fr/oidc-client-service-worker/protocol` and re-exported by
145
+ `@axa-fr/oidc-client`.
146
+
147
+ [Back to the project overview](../../README.md)
@@ -217,7 +217,10 @@ var getCurrentDatabaseDomain = (database, url, trustedDomains) => {
217
217
  //#region src/utils/serializeHeaders.ts
218
218
  function serializeHeaders(headers) {
219
219
  const headersObj = {};
220
- for (const key of headers.keys()) if (headers.has(key)) headersObj[key] = headers.get(key);
220
+ for (const key of headers.keys()) {
221
+ const value = headers.get(key);
222
+ if (value !== null) headersObj[key] = value;
223
+ }
221
224
  return headersObj;
222
225
  }
223
226
  //#endregion
@@ -242,17 +245,6 @@ var shouldBypassDestination = (destination, mode) => {
242
245
  //#region src/utils/sleep.ts
243
246
  var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
244
247
  //#endregion
245
- //#region src/utils/strings.ts
246
- /**
247
- * Count occurances of letter in string
248
- * @param str
249
- * @param find
250
- * @returns
251
- */
252
- function countLetter(str, find) {
253
- return str.split(find).length - 1;
254
- }
255
- //#endregion
256
248
  //#region src/utils/tokens.ts
257
249
  var parseJwt = (payload) => {
258
250
  return JSON.parse(b64DecodeUnicode(payload.replaceAll(/-/g, "+").replaceAll(/_/g, "/")));
@@ -271,8 +263,8 @@ function isTokensValid(tokens) {
271
263
  var extractTokenPayload = (token) => {
272
264
  try {
273
265
  if (!token) return null;
274
- if (countLetter(token, ".") === 2) return parseJwt(token.split(".")[1]);
275
- else return null;
266
+ const parts = token.split(".");
267
+ return parts.length === 3 ? parseJwt(parts[1]) : null;
276
268
  } catch (e) {
277
269
  console.warn(e);
278
270
  }
@@ -290,7 +282,7 @@ var isTokensOidcValid = (tokens, nonce, oidcServerConfiguration) => {
290
282
  isValid: false,
291
283
  reason: `Token expired at (idTokenPayload exp) ${idTokenPayload.exp} < (currentTimeUnixSecond) ${currentTimeUnixSecond}`
292
284
  };
293
- const timeInSevenDays = 3600 * 24 * 7;
285
+ const timeInSevenDays = 604800;
294
286
  if (idTokenPayload && idTokenPayload.iat && idTokenPayload.iat + timeInSevenDays < currentTimeUnixSecond) return {
295
287
  isValid: false,
296
288
  reason: `Token is used from too long time (idTokenPayload iat + timeInSevenDays) ${idTokenPayload.iat + timeInSevenDays} < (currentTimeUnixSecond) ${currentTimeUnixSecond}`
@@ -306,10 +298,11 @@ var isTokensOidcValid = (tokens, nonce, oidcServerConfiguration) => {
306
298
  };
307
299
  };
308
300
  function extractedIssueAt(tokens, accessTokenPayload, _idTokenPayload) {
309
- if (!tokens.issued_at) if (accessTokenPayload && accessTokenPayload.iat) return accessTokenPayload.iat;
310
- else if (_idTokenPayload && _idTokenPayload.iat) return _idTokenPayload.iat;
311
- else return (/* @__PURE__ */ new Date()).getTime() / 1e3;
312
- else if (typeof tokens.issued_at == "string") return parseInt(tokens.issued_at, 10);
301
+ if (!tokens.issued_at) {
302
+ if (accessTokenPayload && accessTokenPayload.iat) return accessTokenPayload.iat;
303
+ else if (_idTokenPayload && _idTokenPayload.iat) return _idTokenPayload.iat;
304
+ else return (/* @__PURE__ */ new Date()).getTime() / 1e3;
305
+ } else if (typeof tokens.issued_at == "string") return parseInt(tokens.issued_at, 10);
313
306
  return tokens.issued_at;
314
307
  }
315
308
  function _hideTokens(tokens, currentDatabaseElement, configurationName) {
@@ -444,10 +437,10 @@ var shouldBypassNonOidcRequest = (database, normalizedUrl, trustedDomains) => {
444
437
  return !isOidcServerRequest(database, normalizedUrl) && !isAccessTokenDomainRequest(database, normalizedUrl, trustedDomains);
445
438
  };
446
439
  var getMatchingOidcConfigurations = (database, url) => {
440
+ const normalizedUrl = normalizeUrl(url);
447
441
  return Object.values(database).filter((config) => {
448
442
  const { oidcServerConfiguration } = config || {};
449
443
  const { tokenEndpoint, revocationEndpoint } = oidcServerConfiguration || {};
450
- const normalizedUrl = normalizeUrl(url);
451
444
  return tokenEndpoint && normalizedUrl.startsWith(normalizeUrl(tokenEndpoint)) || revocationEndpoint && normalizedUrl.startsWith(normalizeUrl(revocationEndpoint));
452
445
  });
453
446
  };
@@ -456,14 +449,13 @@ var getMatchingOidcConfigurations = (database, url) => {
456
449
  function replaceCodeVerifier(codeVerifier, newCodeVerifier) {
457
450
  return codeVerifier.replace(/[?&]code_verifier=([^&]+)/i, `&code_verifier=${newCodeVerifier}`);
458
451
  }
459
- var extractConfigurationNameFromCodeVerifier = (chaine) => {
460
- const match = chaine.match(/[?&]code_verifier=CODE_VERIFIER_SECURED_BY_OIDC_SERVICE_WORKER_([^&]+)/);
461
- if (match && match.length > 0) return decodeURIComponent(match[1]);
462
- else return "";
452
+ var extractConfigurationNameFromCodeVerifier = (body) => {
453
+ const match = body.match(/[?&]code_verifier=CODE_VERIFIER_SECURED_BY_OIDC_SERVICE_WORKER_([^&]+)/);
454
+ return match ? decodeURIComponent(match[1]) : "";
463
455
  };
464
456
  //#endregion
465
457
  //#region src/version.ts
466
- var version_default = "7.29.3";
458
+ var version_default = "7.29.5";
467
459
  //#endregion
468
460
  //#region src/OidcServiceWorker.ts
469
461
  if (typeof trustedTypes !== "undefined" && typeof trustedTypes.createPolicy === "function") trustedTypes.createPolicy("default", { createScriptURL: function(url) {
@@ -573,7 +565,8 @@ var handleFetch = (event) => {
573
565
  for (let i = 0; i < numberDatabase; i++) {
574
566
  const currentDb = currentDatabases[i];
575
567
  if (currentDb?.tokens) {
576
- headers = await generateDpopAsync(originalRequest, currentDb, url, { ath: await base64urlOfHashOfASCIIEncodingAsync(currentDb.tokens.access_token) });
568
+ const claimsExtras = { ath: await base64urlOfHashOfASCIIEncodingAsync(currentDb.tokens.access_token) };
569
+ headers = await generateDpopAsync(originalRequest, currentDb, url, claimsExtras);
577
570
  const keyRefreshToken = encodeURIComponent(`${TOKEN.REFRESH_TOKEN}_${currentDb.configurationName}`);
578
571
  if (actualBody.includes(keyRefreshToken)) {
579
572
  newBody = newBody.replace(keyRefreshToken, encodeURIComponent(currentDb.tokens.refresh_token));
@@ -1 +1 @@
1
- {"version":3,"file":"OidcServiceWorker.js","names":[],"sources":["../src/constants.ts","../src/jwt.ts","../src/crypto.ts","../src/dpop.ts","../src/utils/normalizeUrl.ts","../src/utils/domains.ts","../src/utils/serializeHeaders.ts","../src/utils/shouldBypassDestination.ts","../src/utils/sleep.ts","../src/utils/strings.ts","../src/utils/tokens.ts","../src/utils/waitForValidTokens.ts","../src/oidcConfig.ts","../src/utils/codeVerifier.ts","../src/version.ts","../src/OidcServiceWorker.ts"],"sourcesContent":["const scriptFilename = 'OidcTrustedDomains.js';\nconst acceptAnyDomainToken = '*';\n\ntype TokenType = {\n readonly REFRESH_TOKEN: string;\n readonly ACCESS_TOKEN: string;\n readonly NONCE_TOKEN: string;\n readonly CODE_VERIFIER: string;\n};\n\nconst TOKEN: TokenType = {\n REFRESH_TOKEN: 'REFRESH_TOKEN_SECURED_BY_OIDC_SERVICE_WORKER',\n ACCESS_TOKEN: 'ACCESS_TOKEN_SECURED_BY_OIDC_SERVICE_WORKER',\n NONCE_TOKEN: 'NONCE_SECURED_BY_OIDC_SERVICE_WORKER',\n CODE_VERIFIER: 'CODE_VERIFIER_SECURED_BY_OIDC_SERVICE_WORKER',\n};\n\ntype TokenRenewModeType = {\n readonly access_token_or_id_token_invalid: string;\n readonly access_token_invalid: string;\n readonly id_token_invalid: string;\n};\n\nconst TokenRenewMode: TokenRenewModeType = {\n access_token_or_id_token_invalid: 'access_token_or_id_token_invalid',\n access_token_invalid: 'access_token_invalid',\n id_token_invalid: 'id_token_invalid',\n};\n\nconst openidWellknownUrlEndWith = '/.well-known/openid-configuration';\n\nexport { acceptAnyDomainToken, openidWellknownUrlEndWith, scriptFilename, TOKEN, TokenRenewMode };\n","// code base on https://coolaj86.com/articles/sign-jwt-webcrypto-vanilla-js/\n\n// String (UCS-2) to Uint8Array\n//\n// because... JavaScript, Strings, and Buffers\n// @ts-ignore\nimport { DemonstratingProofOfPossessionConfiguration } from './types';\n\nfunction strToUint8(str: string) {\n return new TextEncoder().encode(str);\n}\n\n// Binary String to URL-Safe Base64\n//\n// btoa (Binary-to-Ascii) means \"binary string\" to base64\n// @ts-ignore\nfunction binToUrlBase64(bin) {\n return btoa(bin).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+/g, '');\n}\n\n// UTF-8 to Binary String\n//\n// Because JavaScript has a strange relationship with strings\n// https://coolaj86.com/articles/base64-unicode-utf-8-javascript-and-you/\n// @ts-ignore\nfunction utf8ToBinaryString(str) {\n const escstr = encodeURIComponent(str);\n // replaces any uri escape sequence, such as %0A,\n // with binary escape, such as 0x0A\n // @ts-ignore\n return escstr.replace(/%([0-9A-F]{2})/g, function (match: string, p1) {\n return String.fromCharCode(parseInt(p1, 16));\n });\n}\n\n// Uint8Array to URL Safe Base64\n//\n// the shortest distant between two encodings... binary string\n// @ts-ignore\nexport const uint8ToUrlBase64 = (uint8: Uint8Array) => {\n let bin = '';\n // @ts-ignore\n uint8.forEach(function (code) {\n bin += String.fromCharCode(code);\n });\n return binToUrlBase64(bin);\n};\n\n// UCS-2 String to URL-Safe Base64\n//\n// btoa doesn't work on UTF-8 strings\n// @ts-ignore\nfunction strToUrlBase64(str) {\n return binToUrlBase64(utf8ToBinaryString(str));\n}\n\nexport const defaultDemonstratingProofOfPossessionConfiguration: DemonstratingProofOfPossessionConfiguration =\n {\n importKeyAlgorithm: {\n name: 'ECDSA',\n namedCurve: 'P-256',\n hash: { name: 'ES256' },\n },\n signAlgorithm: { name: 'ECDSA', hash: { name: 'SHA-256' } },\n generateKeyAlgorithm: {\n name: 'ECDSA',\n namedCurve: 'P-256',\n },\n digestAlgorithm: { name: 'SHA-256' },\n jwtHeaderAlgorithm: 'ES256',\n };\n\n// @ts-ignore\nconst sign =\n (w: any) =>\n async (\n jwk: any,\n headers: any,\n claims: any,\n demonstratingProofOfPossessionConfiguration: DemonstratingProofOfPossessionConfiguration,\n jwtHeaderType = 'dpop+jwt',\n ) => {\n // Make a shallow copy of the key\n // (to set ext if it wasn't already set)\n jwk = Object.assign({}, jwk);\n\n // The headers should probably be empty\n headers.typ = jwtHeaderType;\n headers.alg = demonstratingProofOfPossessionConfiguration.jwtHeaderAlgorithm;\n switch (headers.alg) {\n case 'ES256': //if (!headers.kid) {\n // alternate: see thumbprint function below\n headers.jwk = { kty: jwk.kty, crv: jwk.crv, x: jwk.x, y: jwk.y };\n //}\n break;\n case 'RS256':\n headers.jwk = { kty: jwk.kty, n: jwk.n, e: jwk.e, kid: headers.kid };\n break;\n default:\n throw new Error('Unknown or not implemented JWS algorithm');\n }\n\n const jws = {\n // @ts-ignore\n // JWT \"headers\" really means JWS \"protected headers\"\n protected: strToUrlBase64(JSON.stringify(headers)),\n // @ts-ignore\n // JWT \"claims\" are really a JSON-defined JWS \"payload\"\n payload: strToUrlBase64(JSON.stringify(claims)),\n };\n\n // To import as EC (ECDSA, P-256, SHA-256, ES256)\n const keyType = demonstratingProofOfPossessionConfiguration.importKeyAlgorithm;\n\n // To make re-exportable as JSON (or DER/PEM)\n const exportable = true;\n\n // Import as a private key that isn't black-listed from signing\n const privileges = ['sign'];\n\n // Actually do the import, which comes out as an abstract key type\n // @ts-ignore\n const privateKey = await w.crypto.subtle.importKey('jwk', jwk, keyType, exportable, privileges);\n // Convert UTF-8 to Uint8Array ArrayBuffer\n // @ts-ignore\n const data = strToUint8(`${jws.protected}.${jws.payload}`);\n\n // The signature and hash should match the bit-entropy of the key\n // https://tools.ietf.org/html/rfc7518#section-3\n const signatureType = demonstratingProofOfPossessionConfiguration.signAlgorithm;\n\n const signature = await w.crypto.subtle.sign(signatureType, privateKey, data);\n // returns an ArrayBuffer containing a JOSE (not X509) signature,\n // which must be converted to Uint8 to be useful\n // @ts-ignore\n jws.signature = uint8ToUrlBase64(new Uint8Array(signature));\n // JWT is just a \"compressed\", \"protected\" JWS\n // @ts-ignore\n return `${jws.protected}.${jws.payload}.${jws.signature}`;\n };\n\nexport const JWT = { sign };\n\n// @ts-ignore\nconst generate =\n (w: any) => async (generateKeyAlgorithm: RsaHashedKeyGenParams | EcKeyGenParams) => {\n const keyType = generateKeyAlgorithm;\n const exportable = true;\n const privileges = ['sign', 'verify'];\n // @ts-ignore\n const key = await w.crypto.subtle.generateKey(keyType, exportable, privileges);\n // returns an abstract and opaque WebCrypto object,\n // which in most cases you'll want to export as JSON to be able to save\n return await w.crypto.subtle.exportKey('jwk', key.privateKey);\n };\n\n// Create a Public Key from a Private Key\n//\n// chops off the private parts\n// @ts-ignore\nconst neuter = jwk => {\n const copy = Object.assign({}, jwk);\n delete copy.d;\n copy.key_ops = ['verify'];\n return copy;\n};\n\nconst EC = {\n generate,\n neuter,\n};\n// @ts-ignore\nconst thumbprint = (w: any) => async (jwk, digestAlgorithm: AlgorithmIdentifier) => {\n let sortedPub;\n // lexigraphically sorted, no spaces\n switch (jwk.kty) {\n case 'EC':\n sortedPub = '{\"crv\":\"CRV\",\"kty\":\"EC\",\"x\":\"X\",\"y\":\"Y\"}'\n .replace('CRV', jwk.crv)\n .replace('X', jwk.x)\n .replace('Y', jwk.y);\n break;\n case 'RSA':\n sortedPub = '{\"e\":\"E\",\"kty\":\"RSA\",\"n\":\"N\"}'.replace('E', jwk.e).replace('N', jwk.n);\n break;\n default:\n throw new Error('Unknown or not implemented JWK type');\n }\n // The hash should match the size of the key,\n // but we're only dealing with P-256\n const hash = await w.crypto.subtle.digest(digestAlgorithm, strToUint8(sortedPub));\n return uint8ToUrlBase64(new Uint8Array(hash));\n};\n\nexport const JWK = { thumbprint };\n\nexport const generateJwkAsync =\n (w: any) => async (generateKeyAlgorithm: RsaHashedKeyGenParams | EcKeyGenParams) => {\n // @ts-ignore\n const jwk = await EC.generate(w)(generateKeyAlgorithm);\n // console.info('Private Key:', JSON.stringify(jwk));\n // @ts-ignore\n // console.info('Public Key:', JSON.stringify(EC.neuter(jwk)));\n return jwk;\n };\n\nexport const generateJwtDemonstratingProofOfPossessionAsync =\n (w: any) =>\n (demonstratingProofOfPossessionConfiguration: DemonstratingProofOfPossessionConfiguration) =>\n async (jwk: any, method = 'POST', url: string, extrasClaims = {}) => {\n const claims = {\n // https://www.rfc-editor.org/rfc/rfc9449.html#name-concept\n jti: btoa(w.crypto.randomUUID()),\n htm: method,\n htu: url,\n iat: Math.round(Date.now() / 1000),\n ...extrasClaims,\n };\n // @ts-ignore\n const kid = await JWK.thumbprint(w)(\n jwk,\n demonstratingProofOfPossessionConfiguration.digestAlgorithm,\n );\n // @ts-ignore\n const jwt = await JWT.sign(w)(\n jwk,\n { kid: kid },\n claims,\n demonstratingProofOfPossessionConfiguration,\n );\n // console.info('JWT:', jwt);\n return jwt;\n };\n","import { uint8ToUrlBase64 } from './jwt';\n\nexport function textEncodeLite(str: string) {\n const buf = new ArrayBuffer(str.length);\n const bufView = new Uint8Array(buf);\n\n for (let i = 0; i < str.length; i++) {\n bufView[i] = str.charCodeAt(i);\n }\n return bufView;\n}\n\nexport function base64urlOfHashOfASCIIEncodingAsync(code: string): Promise<string> {\n return new Promise((resolve, reject) => {\n crypto.subtle.digest('SHA-256', textEncodeLite(code)).then(\n buffer => {\n return resolve(uint8ToUrlBase64(new Uint8Array(buffer)));\n },\n error => reject(error),\n );\n });\n}\n","import { defaultDemonstratingProofOfPossessionConfiguration } from './jwt';\nimport { Domain, DomainDetails } from './types.js';\n\nconst isDpop = (trustedDomain: Domain[] | DomainDetails): boolean => {\n if (Array.isArray(trustedDomain)) {\n return false;\n }\n return trustedDomain.demonstratingProofOfPossession ?? false;\n};\n\nexport const getDpopConfiguration = (trustedDomain: Domain[] | DomainDetails) => {\n if (!isDpop(trustedDomain)) {\n return null;\n }\n\n if (Array.isArray(trustedDomain)) {\n return null;\n }\n\n return (\n trustedDomain.demonstratingProofOfPossessionConfiguration ??\n defaultDemonstratingProofOfPossessionConfiguration\n );\n};\n\nexport const getDpopOnlyWhenDpopHeaderPresent = (trustedDomain: Domain[] | DomainDetails) => {\n if (!isDpop(trustedDomain)) {\n return null;\n }\n\n if (Array.isArray(trustedDomain)) {\n return null;\n }\n\n return trustedDomain.demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent ?? true;\n};\n","export function normalizeUrl(url: string) {\n try {\n return new URL(url).toString();\n } catch (error) {\n console.error(`Failed to normalize url: ${url}`, error);\n return url;\n }\n}\n","import { acceptAnyDomainToken, openidWellknownUrlEndWith, scriptFilename } from '../constants';\nimport { Database, Domain, DomainDetails, OidcConfig, TrustedDomains } from '../types';\nimport { normalizeUrl } from './normalizeUrl';\n\nexport function checkDomain(domains: Domain[], endpoint: string) {\n if (!endpoint) {\n return;\n }\n\n const domain = domains.find(domain => {\n let testable: RegExp;\n\n if (typeof domain === 'string') {\n testable = new RegExp(`^${domain}`);\n } else {\n testable = domain;\n }\n\n return testable.test?.(endpoint);\n });\n if (!domain) {\n throw new Error(\n 'Domain ' + endpoint + ' is not trusted, please add domain in ' + scriptFilename,\n );\n }\n}\n\nexport const getDomains = (\n trustedDomain: Domain[] | DomainDetails,\n type: 'oidc' | 'accessToken',\n) => {\n if (Array.isArray(trustedDomain)) {\n return trustedDomain;\n }\n\n return trustedDomain[`${type}Domains`] ?? trustedDomain.domains ?? [];\n};\n\nexport const getCurrentDatabaseDomain = (\n database: Database,\n url: string,\n trustedDomains: TrustedDomains,\n) => {\n if (url.endsWith(openidWellknownUrlEndWith)) {\n return null;\n }\n const datatases = [];\n for (const [key, currentDatabase] of Object.entries<OidcConfig>(database)) {\n const oidcServerConfiguration = currentDatabase.oidcServerConfiguration;\n\n if (!oidcServerConfiguration) {\n continue;\n }\n\n if (\n oidcServerConfiguration.tokenEndpoint &&\n url === normalizeUrl(oidcServerConfiguration.tokenEndpoint)\n ) {\n continue;\n }\n if (\n oidcServerConfiguration.revocationEndpoint &&\n url === normalizeUrl(oidcServerConfiguration.revocationEndpoint)\n ) {\n continue;\n }\n const trustedDomain = trustedDomains == null ? [] : trustedDomains[key.split('#')[0]];\n\n const domains = getDomains(trustedDomain, 'accessToken');\n const domainsToSendTokens = oidcServerConfiguration.userInfoEndpoint\n ? [normalizeUrl(oidcServerConfiguration.userInfoEndpoint), ...domains]\n : [...domains];\n\n let hasToSendToken = false;\n if (domainsToSendTokens.find(f => f === acceptAnyDomainToken)) {\n hasToSendToken = true;\n } else {\n for (let i = 0; i < domainsToSendTokens.length; i++) {\n let domain = domainsToSendTokens[i];\n\n if (typeof domain === 'string') {\n domain = new RegExp(`^${domain}`);\n }\n\n if (domain.test?.(url)) {\n hasToSendToken = true;\n break;\n }\n }\n }\n\n if (hasToSendToken) {\n if (currentDatabase.tokens) {\n datatases.push(currentDatabase);\n }\n }\n }\n return datatases;\n};\n","function serializeHeaders(headers: Headers) {\n const headersObj: Record<string, string> = {};\n for (const key of headers.keys()) {\n if (headers.has(key)) {\n headersObj[key] = headers.get(key) as string;\n }\n }\n return headersObj;\n}\nexport { serializeHeaders };\n","const bypassedDestinations = ['image', 'font', 'media', 'document', 'iframe', 'script'];\n\n/**\n * Determines whether a fetch event should be bypassed (not intercepted by the service worker).\n * Navigation requests (mode === 'navigate') are never bypassed, even when their destination\n * is in the bypassed list, so that access tokens can be injected into new-tab navigations.\n */\nexport const shouldBypassDestination = (destination: string, mode: string): boolean => {\n return bypassedDestinations.includes(destination) && mode !== 'navigate';\n};\n","const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));\nexport { sleep };\n","/**\n * Count occurances of letter in string\n * @param str\n * @param find\n * @returns\n */\nexport function countLetter(str: string, find: string) {\n return str.split(find).length - 1;\n}\n","/* eslint-disable simple-import-sort/exports */\nimport { TOKEN, TokenRenewMode } from '../constants';\nimport {\n AccessTokenPayload,\n IdTokenPayload,\n OidcConfig,\n OidcConfiguration,\n OidcServerConfiguration,\n Tokens,\n} from '../types';\nimport { countLetter } from './strings';\n\nexport const parseJwt = (payload: string) => {\n return JSON.parse(b64DecodeUnicode(payload.replaceAll(/-/g, '+').replaceAll(/_/g, '/')));\n};\nfunction b64DecodeUnicode(str: string) {\n return decodeURIComponent(\n Array.prototype.map\n .call(atob(str), c => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))\n .join(''),\n );\n}\n\nfunction computeTimeLeft(refreshTimeBeforeTokensExpirationInSecond: number, expiresAt: number) {\n const currentTimeUnixSecond = new Date().getTime() / 1000;\n return Math.round(expiresAt - refreshTimeBeforeTokensExpirationInSecond - currentTimeUnixSecond);\n}\n\nfunction isTokensValid(tokens: Tokens | null) {\n if (!tokens) {\n return false;\n }\n return computeTimeLeft(0, tokens.expiresAt) > 0;\n}\n\nconst extractTokenPayload = (token?: string) => {\n try {\n if (!token) {\n return null;\n }\n if (countLetter(token, '.') === 2) {\n return parseJwt(token.split('.')[1]);\n } else {\n return null;\n }\n } catch (e) {\n console.warn(e);\n }\n return null;\n};\n\n// https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation (excluding rules #1, #4, #5, #7, #8, #12, and #13 which did not apply).\n// https://github.com/openid/AppAuth-JS/issues/65\nconst isTokensOidcValid = (\n tokens: Tokens,\n nonce: string | null,\n oidcServerConfiguration: OidcServerConfiguration,\n): { isValid: boolean; reason: string } => {\n if (tokens.idTokenPayload) {\n const idTokenPayload = tokens.idTokenPayload;\n // 2: The Issuer Identifier for the OpenID Provider (which is typically obtained during Discovery) MUST exactly match the value of the iss (issuer) Claim.\n if (idTokenPayload && oidcServerConfiguration.issuer !== idTokenPayload.iss) {\n return {\n isValid: false,\n reason: `Issuer does not match (oidcServerConfiguration issuer) ${oidcServerConfiguration.issuer} !== (idTokenPayload issuer) ${idTokenPayload.iss}`,\n };\n }\n // 3: The Client MUST validate that the aud (audience) Claim contains its client_id value registered at the Issuer identified by the iss (issuer) Claim as an audience. The aud (audience) Claim MAY contain an array with more than one element. The ID Token MUST be rejected if the ID Token does not list the Client as a valid audience, or if it contains additional audiences not trusted by the Client.\n\n // 6: If the ID Token is received via direct communication between the Client and the Token Endpoint (which it is in this flow), the TLS server validation MAY be used to validate the issuer in place of checking the token signature. The Client MUST validate the signature of all other ID Tokens according to JWS [JWS] using the algorithm specified in the JWT alg Header Parameter. The Client MUST use the keys provided by the Issuer.\n\n // 9: The current time MUST be before the time represented by the exp Claim.\n const currentTimeUnixSecond = new Date().getTime() / 1000;\n if (idTokenPayload && idTokenPayload.exp && idTokenPayload.exp < currentTimeUnixSecond) {\n return {\n isValid: false,\n reason: `Token expired at (idTokenPayload exp) ${idTokenPayload.exp} < (currentTimeUnixSecond) ${currentTimeUnixSecond}`,\n };\n }\n // 10: The iat Claim can be used to reject tokens that were issued too far away from the current time, limiting the amount of time that nonces need to be stored to prevent attacks. The acceptable range is Client specific.\n const timeInSevenDays = 60 * 60 * 24 * 7;\n if (\n idTokenPayload &&\n idTokenPayload.iat &&\n idTokenPayload.iat + timeInSevenDays < currentTimeUnixSecond\n ) {\n return {\n isValid: false,\n reason: `Token is used from too long time (idTokenPayload iat + timeInSevenDays) ${idTokenPayload.iat + timeInSevenDays} < (currentTimeUnixSecond) ${currentTimeUnixSecond}`,\n };\n }\n // 11: If a nonce value was sent in the Authentication Request, a nonce Claim MUST be present and its value checked to verify that it is the same value as the one that was sent in the Authentication Request. The Client SHOULD check the nonce value for replay attacks. The precise method for detecting replay attacks is Client specific.\n if (idTokenPayload && nonce && idTokenPayload.nonce && idTokenPayload.nonce !== nonce) {\n return {\n isValid: false,\n reason: `Nonce does not match (nonce) ${nonce} !== (idTokenPayload nonce) ${idTokenPayload.nonce}`,\n };\n }\n }\n return { isValid: true, reason: '' };\n};\n\nfunction extractedIssueAt(\n tokens: Tokens,\n accessTokenPayload: AccessTokenPayload | null,\n _idTokenPayload: IdTokenPayload,\n) {\n if (!tokens.issued_at) {\n if (accessTokenPayload && accessTokenPayload.iat) {\n return accessTokenPayload.iat;\n } else if (_idTokenPayload && _idTokenPayload.iat) {\n return _idTokenPayload.iat;\n } else {\n const currentTimeUnixSecond = new Date().getTime() / 1000;\n return currentTimeUnixSecond;\n }\n } else if (typeof tokens.issued_at == 'string') {\n return parseInt(tokens.issued_at, 10);\n }\n return tokens.issued_at;\n}\n\nfunction _hideTokens(\n tokens: Tokens,\n currentDatabaseElement: OidcConfig,\n configurationName: string,\n) {\n if (!tokens.issued_at) {\n const currentTimeUnixSecond = new Date().getTime() / 1000;\n tokens.issued_at = currentTimeUnixSecond;\n } else if (typeof tokens.issued_at == 'string') {\n tokens.issued_at = parseInt(tokens.issued_at, 10);\n }\n\n const accessTokenPayload = extractTokenPayload(tokens.access_token);\n const secureTokens = {\n ...tokens,\n accessTokenPayload,\n };\n if (currentDatabaseElement.hideAccessToken) {\n secureTokens.access_token = `${TOKEN.ACCESS_TOKEN}_${configurationName}`;\n }\n tokens.accessTokenPayload = accessTokenPayload;\n\n // When id_token is not rotated we reuse old id_token\n const oldTokens = currentDatabaseElement.tokens;\n let id_token: string | null;\n if (oldTokens != null && 'id_token' in oldTokens && !('id_token' in tokens)) {\n id_token = oldTokens.id_token;\n } else {\n id_token = tokens.id_token;\n }\n tokens.id_token = id_token;\n\n let _idTokenPayload = null;\n if (id_token) {\n _idTokenPayload = extractTokenPayload(id_token);\n tokens.idTokenPayload = _idTokenPayload != null ? { ..._idTokenPayload } : null;\n if (_idTokenPayload && _idTokenPayload.nonce && currentDatabaseElement.nonce != null) {\n const keyNonce = `${TOKEN.NONCE_TOKEN}_${currentDatabaseElement.configurationName}`;\n _idTokenPayload.nonce = keyNonce;\n }\n secureTokens.idTokenPayload = _idTokenPayload;\n }\n if (tokens.refresh_token) {\n secureTokens.refresh_token = `${TOKEN.REFRESH_TOKEN}_${configurationName}`;\n }\n\n tokens.issued_at = extractedIssueAt(tokens, accessTokenPayload, _idTokenPayload);\n\n const expireIn =\n typeof tokens.expires_in == 'string' ? parseInt(tokens.expires_in, 10) : tokens.expires_in;\n\n const idTokenExpiresAt =\n _idTokenPayload && _idTokenPayload.exp ? _idTokenPayload.exp : Number.MAX_VALUE;\n const accessTokenExpiresAt =\n accessTokenPayload && accessTokenPayload.exp\n ? accessTokenPayload.exp\n : tokens.issued_at + expireIn;\n\n let expiresAt: number;\n const tokenRenewMode = (currentDatabaseElement.oidcConfiguration as OidcConfiguration)\n .token_renew_mode;\n if (tokenRenewMode === TokenRenewMode.access_token_invalid) {\n expiresAt = accessTokenExpiresAt;\n } else if (tokenRenewMode === TokenRenewMode.id_token_invalid) {\n expiresAt = idTokenExpiresAt;\n } else {\n expiresAt = idTokenExpiresAt < accessTokenExpiresAt ? idTokenExpiresAt : accessTokenExpiresAt;\n }\n secureTokens.expiresAt = expiresAt;\n\n tokens.expiresAt = expiresAt;\n const nonce = currentDatabaseElement.nonce ? currentDatabaseElement.nonce.nonce : null;\n const { isValid, reason } = isTokensOidcValid(\n tokens,\n nonce as string,\n currentDatabaseElement.oidcServerConfiguration as OidcServerConfiguration,\n ); // TODO: Type assertion, could be null.\n if (!isValid) {\n throw Error(`Tokens are not OpenID valid, reason: ${reason}`);\n }\n\n // When refresh_token is not rotated we reuse old refresh_token\n if (oldTokens != null && 'refresh_token' in oldTokens && !('refresh_token' in tokens)) {\n const refreshToken = oldTokens.refresh_token;\n\n currentDatabaseElement.tokens = {\n ...tokens,\n refresh_token: refreshToken,\n };\n } else {\n currentDatabaseElement.tokens = tokens;\n }\n\n currentDatabaseElement.status = 'LOGGED_IN';\n return secureTokens;\n}\n\nconst demonstratingProofOfPossessionNonceResponseHeader = 'DPoP-Nonce';\nfunction hideTokens(currentDatabaseElement: OidcConfig) {\n const configurationName = currentDatabaseElement.configurationName;\n return (response: Response) => {\n if (response.status !== 200) {\n return response;\n }\n const newHeaders = new Headers(response.headers);\n if (response.headers.has(demonstratingProofOfPossessionNonceResponseHeader)) {\n currentDatabaseElement.demonstratingProofOfPossessionNonce = response.headers.get(\n demonstratingProofOfPossessionNonceResponseHeader,\n );\n newHeaders.delete(demonstratingProofOfPossessionNonceResponseHeader);\n }\n\n return response.json().then<Response>((tokens: Tokens) => {\n const secureTokens = _hideTokens(tokens, currentDatabaseElement, configurationName);\n const body = JSON.stringify(secureTokens);\n return new Response(body, {\n status: response.status,\n statusText: response.statusText,\n headers: newHeaders,\n });\n });\n };\n}\n\nexport {\n b64DecodeUnicode,\n computeTimeLeft,\n isTokensValid,\n extractTokenPayload,\n isTokensOidcValid,\n hideTokens,\n _hideTokens,\n};\n","import { OidcConfig } from '../types';\nimport { sleep } from './sleep';\nimport { isTokensValid } from './tokens';\n\nexport const TOKEN_RENEWAL_TIMEOUT_MS = 5000;\nexport const TOKEN_RENEWAL_POLL_INTERVAL_MS = 200;\n\n/**\n * Polls until the tokens in the given config are valid, or until a timeout elapses.\n *\n * @returns `null` when tokens become valid; a synthetic 401 `Response` on timeout or\n * when the tokens are cleared while waiting (e.g. due to a parallel logout).\n */\nexport async function waitForValidTokens(\n config: OidcConfig,\n maxWaitMs = TOKEN_RENEWAL_TIMEOUT_MS,\n pollIntervalMs = TOKEN_RENEWAL_POLL_INTERVAL_MS,\n): Promise<Response | null> {\n const startTime = Date.now();\n while (config.tokens && !isTokensValid(config.tokens)) {\n if (Date.now() - startTime >= maxWaitMs) {\n return new Response(null, {\n status: 401,\n statusText: 'Token expired - service worker renewal timeout',\n });\n }\n await sleep(pollIntervalMs);\n }\n\n if (!config.tokens?.access_token) {\n return new Response(null, {\n status: 401,\n statusText: 'Missing access token',\n });\n }\n\n return null;\n}\n","import { acceptAnyDomainToken } from './constants';\nimport { Database, Domain, OidcConfig, OidcServerConfiguration, TrustedDomains } from './types';\nimport { getDomains, normalizeUrl } from './utils';\n\nconst getOidcServerUrls = (oidcServerConfiguration: OidcServerConfiguration): string[] => {\n return [\n oidcServerConfiguration.issuer,\n oidcServerConfiguration.authorizationEndpoint,\n oidcServerConfiguration.tokenEndpoint,\n oidcServerConfiguration.revocationEndpoint,\n oidcServerConfiguration.userInfoEndpoint,\n ]\n .filter(Boolean)\n .map(normalizeUrl);\n};\n\nconst isOidcServerRequest = (database: Database, normalizedUrl: string): boolean => {\n return Object.values(database).some(config => {\n const { oidcServerConfiguration } = config || {};\n if (!oidcServerConfiguration) {\n return false;\n }\n\n return getOidcServerUrls(oidcServerConfiguration).some(oidcUrl =>\n normalizedUrl.startsWith(oidcUrl),\n );\n });\n};\n\nconst isDomainMatchingUrl = (domain: Domain, normalizedUrl: string): boolean => {\n if (typeof domain === 'string') {\n domain = new RegExp(`^${domain}`);\n }\n\n return domain.test?.(normalizedUrl) ?? false;\n};\n\nconst isAccessTokenDomainRequest = (\n database: Database,\n normalizedUrl: string,\n trustedDomains: TrustedDomains,\n): boolean => {\n return Object.entries(database).some(([key, currentDatabase]) => {\n if (!currentDatabase.oidcServerConfiguration) {\n return false;\n }\n\n const trustedDomain = trustedDomains?.[key.split('#')[0]] ?? [];\n const domains = getDomains(trustedDomain, 'accessToken');\n\n if (domains.some(domain => domain === acceptAnyDomainToken)) {\n return true;\n }\n\n return domains.some(domain => isDomainMatchingUrl(domain, normalizedUrl));\n });\n};\n\nconst shouldBypassNonOidcRequest = (\n database: Database,\n normalizedUrl: string,\n trustedDomains: TrustedDomains,\n): boolean => {\n const configurations = Object.values(database);\n\n if (configurations.length === 0) {\n return false;\n }\n\n if (!configurations.every(config => config.bypassAllNonOidcRequests)) {\n return false;\n }\n\n if (!configurations.every(config => config.oidcServerConfiguration != null)) {\n return false;\n }\n\n return (\n !isOidcServerRequest(database, normalizedUrl) &&\n !isAccessTokenDomainRequest(database, normalizedUrl, trustedDomains)\n );\n};\n\nconst getMatchingOidcConfigurations = (database: Database, url: string): OidcConfig[] => {\n return Object.values(database).filter(config => {\n const { oidcServerConfiguration } = config || {};\n const { tokenEndpoint, revocationEndpoint } = oidcServerConfiguration || {};\n\n const normalizedUrl = normalizeUrl(url);\n return (\n (tokenEndpoint && normalizedUrl.startsWith(normalizeUrl(tokenEndpoint))) ||\n (revocationEndpoint && normalizedUrl.startsWith(normalizeUrl(revocationEndpoint)))\n );\n });\n};\n\nexport {\n getMatchingOidcConfigurations as getCurrentDatabasesTokenEndpoint,\n isAccessTokenDomainRequest,\n isOidcServerRequest,\n shouldBypassNonOidcRequest,\n};\n","export function replaceCodeVerifier(codeVerifier: string, newCodeVerifier: string): string {\n const regex = /[?&]code_verifier=([^&]+)/i;\n return codeVerifier.replace(regex, `&code_verifier=${newCodeVerifier}`);\n}\n\nexport const extractConfigurationNameFromCodeVerifier = (chaine: string): string => {\n const regex = /[?&]code_verifier=CODE_VERIFIER_SECURED_BY_OIDC_SERVICE_WORKER_([^&]+)/;\n const match = chaine.match(regex);\n\n if (match && match.length > 0) {\n return decodeURIComponent(match[1]);\n } else {\n return '';\n }\n};\n","export default '7.29.3';\n","import { acceptAnyDomainToken, scriptFilename, TOKEN } from './constants';\nimport { base64urlOfHashOfASCIIEncodingAsync } from './crypto';\nimport { getDpopConfiguration, getDpopOnlyWhenDpopHeaderPresent } from './dpop';\nimport { generateJwkAsync, generateJwtDemonstratingProofOfPossessionAsync } from './jwt';\nimport { getCurrentDatabasesTokenEndpoint, shouldBypassNonOidcRequest } from './oidcConfig';\nimport { Database, MessageEventData, OidcConfig, TrustedDomains } from './types';\nimport {\n checkDomain,\n getCurrentDatabaseDomain,\n getDomains,\n hideTokens,\n normalizeUrl,\n serializeHeaders,\n shouldBypassDestination,\n sleep,\n waitForValidTokens,\n} from './utils';\nimport {\n extractConfigurationNameFromCodeVerifier,\n replaceCodeVerifier,\n} from './utils/codeVerifier';\nimport version from './version';\n\n// @ts-ignore\nif (typeof trustedTypes !== 'undefined' && typeof trustedTypes.createPolicy === 'function') {\n // @ts-ignore\n trustedTypes.createPolicy('default', {\n createScriptURL: function (url: string) {\n if (url === scriptFilename) {\n return url;\n } else {\n throw new Error('Untrusted script URL blocked: ' + url);\n }\n },\n });\n}\n\nconst _self = self as ServiceWorkerGlobalScope & typeof globalThis;\n\n// `trustedDomains` is declared in the externally loaded script (OidcTrustedDomains.js)\ndeclare let trustedDomains: TrustedDomains;\n\n_self.importScripts(scriptFilename);\n\nconst id = Math.round(new Date().getTime() / 1000).toString();\nconsole.log('init service worker with id', id);\nconst keepAliveJsonFilename = 'OidcKeepAliveServiceWorker.json';\nconst database: Database = {};\n\n/**\n * Keeps the service worker alive by responding with a cached response after a sleep.\n */\nconst keepAliveAsync = async (event: FetchEvent) => {\n const originalRequest = event.request;\n const isFromVanilla = originalRequest.headers.has('oidc-vanilla');\n const init = { status: 200, statusText: 'oidc-service-worker' };\n const response = new Response('{}', init);\n\n if (!isFromVanilla) {\n const originalRequestUrl = new URL(originalRequest.url);\n const minSleepSeconds = Number(originalRequestUrl.searchParams.get('minSleepSeconds')) || 240;\n for (let i = 0; i < minSleepSeconds; i++) {\n await sleep(1000 + Math.floor(Math.random() * 1000));\n const cache = await caches.open('oidc_dummy_cache');\n await cache.put(event.request, response.clone());\n }\n }\n return response;\n};\n\n/**\n * Generates DPoP headers when a DPoP configuration is present.\n */\nasync function generateDpopAsync(\n originalRequest: Request,\n currentDatabase: OidcConfig | null,\n url: string,\n extrasClaims = {},\n) {\n const headersExtras = serializeHeaders(originalRequest.headers);\n if (\n currentDatabase?.demonstratingProofOfPossessionConfiguration &&\n currentDatabase.demonstratingProofOfPossessionJwkJson &&\n (!currentDatabase.demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent ||\n (currentDatabase.demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent &&\n headersExtras.dpop))\n ) {\n const dpopConfiguration = currentDatabase.demonstratingProofOfPossessionConfiguration;\n const jwk = currentDatabase.demonstratingProofOfPossessionJwkJson;\n const method = originalRequest.method;\n const dpop = await generateJwtDemonstratingProofOfPossessionAsync(self)(dpopConfiguration)(\n jwk,\n method,\n url,\n extrasClaims,\n );\n\n headersExtras.dpop = dpop;\n if (currentDatabase.demonstratingProofOfPossessionNonce != null) {\n headersExtras.nonce = currentDatabase.demonstratingProofOfPossessionNonce;\n }\n }\n return headersExtras;\n}\n\n/**\n * Intercepts fetch requests to inject access tokens and handle token endpoints.\n */\nconst handleFetch = (event: FetchEvent): void => {\n /**\n * Exit early for requests that do not need to have an auth token attached.\n */\n if (shouldBypassDestination(event.request.destination, event.request.mode)) {\n return; // Don't call event.respondWith() - let browser handle naturally\n }\n\n const normalizedUrl = normalizeUrl(event.request.url);\n if (\n !normalizedUrl.includes(keepAliveJsonFilename) &&\n shouldBypassNonOidcRequest(database, normalizedUrl, trustedDomains)\n ) {\n return; // Don't call event.respondWith() - let browser handle naturally\n }\n\n event.respondWith(\n (async (): Promise<Response> => {\n try {\n const originalRequest = event.request;\n const url = normalizedUrl;\n\n // 1) Handle keep-alive requests\n if (url.includes(keepAliveJsonFilename)) {\n return keepAliveAsync(event);\n }\n\n // Check if an access token is available for this request\n const currentDatabasesForRequestAccessToken = getCurrentDatabaseDomain(\n database,\n url,\n trustedDomains,\n );\n\n const authorization = originalRequest.headers.get('authorization');\n let authenticationMode = 'Bearer';\n let key = 'default';\n\n if (authorization) {\n const split = authorization.split(' ');\n authenticationMode = split[0];\n if (split[1]?.includes('ACCESS_TOKEN_SECURED_BY_OIDC_SERVICE_WORKER_')) {\n key = split[1].split('ACCESS_TOKEN_SECURED_BY_OIDC_SERVICE_WORKER_')[1];\n }\n }\n\n const currentDatabaseForRequestAccessToken = currentDatabasesForRequestAccessToken?.find(\n c => c.configurationName.endsWith(key),\n );\n\n // Inject the access token into the request if one is available\n if (currentDatabaseForRequestAccessToken?.tokens?.access_token) {\n // Wait for token to become valid (a parallel refresh may be in progress)\n const tokenError = await waitForValidTokens(currentDatabaseForRequestAccessToken);\n if (tokenError) {\n return tokenError;\n }\n\n // Adjust request mode for CORS if configured\n let requestMode = originalRequest.mode;\n if (\n originalRequest.mode !== 'navigate' &&\n currentDatabaseForRequestAccessToken.convertAllRequestsToCorsExceptNavigate\n ) {\n requestMode = 'cors';\n }\n\n // Build request headers\n let headers: { [p: string]: string };\n\n // Skip the access token for navigate requests when setAccessTokenToNavigateRequests is false\n if (\n originalRequest.mode === 'navigate' &&\n !currentDatabaseForRequestAccessToken.setAccessTokenToNavigateRequests\n ) {\n headers = {\n ...serializeHeaders(originalRequest.headers),\n };\n } else {\n if (\n authenticationMode.toLowerCase() === 'dpop' ||\n (!currentDatabaseForRequestAccessToken.demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent &&\n currentDatabaseForRequestAccessToken.demonstratingProofOfPossessionConfiguration)\n ) {\n // DPoP mode\n const claimsExtras = {\n ath: await base64urlOfHashOfASCIIEncodingAsync(\n currentDatabaseForRequestAccessToken.tokens.access_token,\n ),\n };\n const dpopHeaders = await generateDpopAsync(\n originalRequest,\n currentDatabaseForRequestAccessToken,\n url,\n claimsExtras,\n );\n headers = {\n ...dpopHeaders,\n authorization: `DPoP ${currentDatabaseForRequestAccessToken.tokens.access_token}`,\n };\n } else {\n // Bearer mode\n headers = {\n ...serializeHeaders(originalRequest.headers),\n authorization: `${authenticationMode} ${currentDatabaseForRequestAccessToken.tokens.access_token}`,\n };\n }\n }\n\n let init: RequestInit;\n if (originalRequest.mode === 'navigate') {\n init = {\n headers: headers,\n };\n } else {\n init = {\n headers: headers,\n mode: requestMode,\n };\n }\n\n const newRequest = new Request(originalRequest, init);\n return fetch(newRequest);\n }\n\n // Pass through non-POST requests without modification\n if (event.request.method !== 'POST') {\n return fetch(originalRequest);\n }\n\n // Handle POST requests to known token/revocation endpoints\n const currentDatabases = getCurrentDatabasesTokenEndpoint(database, url);\n const numberDatabase = currentDatabases.length;\n\n if (numberDatabase > 0) {\n const responsePromise = new Promise<Response>((resolve, reject) => {\n const clonedRequest = originalRequest.clone();\n clonedRequest\n .text()\n .then(async actualBody => {\n let currentDatabase: OidcConfig | null = null;\n try {\n // Replace hidden token placeholders with the real token values\n if (\n actualBody.includes(TOKEN.REFRESH_TOKEN) ||\n actualBody.includes(TOKEN.ACCESS_TOKEN)\n ) {\n let headers = serializeHeaders(originalRequest.headers);\n let newBody = actualBody;\n\n for (let i = 0; i < numberDatabase; i++) {\n const currentDb = currentDatabases[i];\n if (currentDb?.tokens) {\n const claimsExtras = {\n ath: await base64urlOfHashOfASCIIEncodingAsync(\n currentDb.tokens.access_token,\n ),\n };\n headers = await generateDpopAsync(\n originalRequest,\n currentDb,\n url,\n claimsExtras,\n );\n\n const keyRefreshToken = encodeURIComponent(\n `${TOKEN.REFRESH_TOKEN}_${currentDb.configurationName}`,\n );\n if (actualBody.includes(keyRefreshToken)) {\n newBody = newBody.replace(\n keyRefreshToken,\n encodeURIComponent(currentDb.tokens.refresh_token as string),\n );\n currentDatabase = currentDb;\n break;\n }\n\n const keyAccessToken = encodeURIComponent(\n `${TOKEN.ACCESS_TOKEN}_${currentDb.configurationName}`,\n );\n if (actualBody.includes(keyAccessToken)) {\n newBody = newBody.replace(\n keyAccessToken,\n encodeURIComponent(currentDb.tokens.access_token),\n );\n currentDatabase = currentDb;\n break;\n }\n }\n }\n\n const fetchPromise = fetch(originalRequest, {\n body: newBody,\n method: clonedRequest.method,\n headers,\n mode: clonedRequest.mode,\n cache: clonedRequest.cache,\n redirect: clonedRequest.redirect,\n referrer: clonedRequest.referrer,\n credentials: clonedRequest.credentials,\n integrity: clonedRequest.integrity,\n });\n\n // Forward revocation requests without modifying the response body\n if (\n currentDatabase?.oidcServerConfiguration?.revocationEndpoint &&\n url.startsWith(\n normalizeUrl(currentDatabase.oidcServerConfiguration.revocationEndpoint),\n )\n ) {\n const resp = await fetchPromise;\n const txt = await resp.text();\n resolve(new Response(txt, resp));\n return;\n }\n\n // Hide real token values in the response\n const hidden = await fetchPromise.then(\n hideTokens(currentDatabase as OidcConfig),\n );\n resolve(hidden);\n return;\n }\n\n // Handle authorization code exchange: replace the PKCE code_verifier placeholder\n const isCodeVerifier = actualBody.includes('code_verifier=');\n if (isCodeVerifier) {\n const currentLoginCallbackConfigurationName =\n extractConfigurationNameFromCodeVerifier(actualBody);\n if (\n !currentLoginCallbackConfigurationName ||\n currentLoginCallbackConfigurationName === ''\n ) {\n throw new Error('No configuration name found in code_verifier');\n }\n currentDatabase = database[currentLoginCallbackConfigurationName];\n let newBody = actualBody;\n const codeVerifier = currentDatabase.codeVerifier;\n if (codeVerifier != null) {\n newBody = replaceCodeVerifier(newBody, codeVerifier);\n }\n\n const headersExtras = await generateDpopAsync(\n originalRequest,\n currentDatabase,\n url,\n );\n const resp = await fetch(originalRequest, {\n body: newBody,\n method: clonedRequest.method,\n headers: headersExtras,\n mode: clonedRequest.mode,\n cache: clonedRequest.cache,\n redirect: clonedRequest.redirect,\n referrer: clonedRequest.referrer,\n credentials: clonedRequest.credentials,\n integrity: clonedRequest.integrity,\n });\n const hidden = await hideTokens(currentDatabase)(resp);\n resolve(hidden);\n return;\n }\n\n // Pass through all other POST requests unchanged\n const normalResp = await fetch(originalRequest, {\n body: actualBody,\n method: clonedRequest.method,\n headers: serializeHeaders(originalRequest.headers),\n mode: clonedRequest.mode,\n cache: clonedRequest.cache,\n redirect: clonedRequest.redirect,\n referrer: clonedRequest.referrer,\n credentials: clonedRequest.credentials,\n integrity: clonedRequest.integrity,\n });\n resolve(normalResp);\n } catch (err) {\n reject(err);\n }\n })\n .catch(reject);\n });\n\n return responsePromise;\n }\n\n // Default: pass through the request unchanged\n return fetch(originalRequest);\n } catch (err) {\n // Surface unexpected errors as a 500 rather than silently hanging\n console.error('[OidcServiceWorker] handleFetch error:', err);\n return new Response('Service Worker Error', { status: 500 });\n }\n })(),\n );\n};\n\nconst handleMessage = async (event: ExtendableMessageEvent) => {\n const port = event.ports[0];\n const data = event.data as MessageEventData;\n\n if (event.data?.type === 'SKIP_WAITING') {\n await _self.skipWaiting();\n port?.postMessage?.({});\n return;\n } else if (event.data.type === 'claim') {\n _self.clients.claim().then(() => port.postMessage({}));\n return;\n }\n\n const configurationName = data.configurationName.split('#')[0];\n\n if (trustedDomains == null) {\n trustedDomains = {};\n }\n\n const trustedDomain = trustedDomains[configurationName];\n const allowMultiTabLogin = Array.isArray(trustedDomain)\n ? false\n : trustedDomain.allowMultiTabLogin;\n\n const tabId = allowMultiTabLogin ? data.tabId : 'default';\n const configurationNameWithTabId = `${configurationName}#tabId=${tabId}`;\n\n let currentDatabase = database[configurationNameWithTabId];\n if (!currentDatabase) {\n const showAccessToken = Array.isArray(trustedDomain) ? false : trustedDomain.showAccessToken;\n const doNotSetAccessTokenToNavigateRequests = Array.isArray(trustedDomain)\n ? true\n : trustedDomain.setAccessTokenToNavigateRequests;\n const convertAllRequestsToCorsExceptNavigate = Array.isArray(trustedDomain)\n ? false\n : trustedDomain.convertAllRequestsToCorsExceptNavigate;\n const bypassAllNonOidcRequests = Array.isArray(trustedDomain)\n ? false\n : trustedDomain.bypassAllNonOidcRequests;\n\n database[configurationNameWithTabId] = {\n tokens: null,\n state: null,\n codeVerifier: null,\n oidcServerConfiguration: null,\n oidcConfiguration: undefined,\n nonce: null,\n status: null,\n configurationName: configurationNameWithTabId,\n hideAccessToken: !showAccessToken,\n setAccessTokenToNavigateRequests: doNotSetAccessTokenToNavigateRequests ?? true,\n convertAllRequestsToCorsExceptNavigate: convertAllRequestsToCorsExceptNavigate ?? false,\n demonstratingProofOfPossessionNonce: null,\n demonstratingProofOfPossessionJwkJson: null,\n demonstratingProofOfPossessionConfiguration: null,\n demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent: false,\n allowMultiTabLogin: allowMultiTabLogin ?? false,\n bypassAllNonOidcRequests: bypassAllNonOidcRequests ?? false,\n };\n currentDatabase = database[configurationNameWithTabId];\n\n if (!trustedDomains[configurationName]) {\n trustedDomains[configurationName] = [];\n }\n }\n\n switch (data.type) {\n case 'clear':\n currentDatabase.tokens = null;\n currentDatabase.state = null;\n currentDatabase.codeVerifier = null;\n currentDatabase.nonce = null;\n currentDatabase.demonstratingProofOfPossessionNonce = null;\n currentDatabase.demonstratingProofOfPossessionJwkJson = null;\n currentDatabase.demonstratingProofOfPossessionConfiguration = null;\n currentDatabase.demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent = false;\n currentDatabase.status = data.data.status;\n port.postMessage({ configurationName });\n return;\n\n case 'init': {\n const oidcServerConfiguration = data.data.oidcServerConfiguration;\n const domains = getDomains(trustedDomain, 'oidc');\n\n if (!domains.some(domain => domain === acceptAnyDomainToken)) {\n [\n oidcServerConfiguration.tokenEndpoint,\n oidcServerConfiguration.revocationEndpoint,\n oidcServerConfiguration.userInfoEndpoint,\n oidcServerConfiguration.issuer,\n ].forEach(u => {\n checkDomain(domains, u);\n });\n }\n\n currentDatabase.oidcServerConfiguration = oidcServerConfiguration;\n currentDatabase.oidcConfiguration = data.data.oidcConfiguration;\n\n if (currentDatabase.demonstratingProofOfPossessionConfiguration == null) {\n const demonstratingProofOfPossessionConfiguration = getDpopConfiguration(trustedDomain);\n if (demonstratingProofOfPossessionConfiguration != null) {\n if (currentDatabase.oidcConfiguration.demonstrating_proof_of_possession) {\n console.warn(\n 'In service worker, demonstrating_proof_of_possession must be configured from trustedDomains file',\n );\n }\n currentDatabase.demonstratingProofOfPossessionConfiguration =\n demonstratingProofOfPossessionConfiguration;\n currentDatabase.demonstratingProofOfPossessionJwkJson = await generateJwkAsync(self)(\n demonstratingProofOfPossessionConfiguration.generateKeyAlgorithm,\n );\n currentDatabase.demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent =\n getDpopOnlyWhenDpopHeaderPresent(trustedDomain) ?? false;\n }\n }\n\n if (!currentDatabase.tokens) {\n port.postMessage({\n tokens: null,\n status: currentDatabase.status,\n configurationName,\n version,\n });\n } else {\n const tokens = { ...currentDatabase.tokens };\n if (currentDatabase.hideAccessToken) {\n tokens.access_token = `${TOKEN.ACCESS_TOKEN}_${configurationName}#tabId=${tabId}`;\n }\n if (tokens.refresh_token) {\n tokens.refresh_token = `${TOKEN.REFRESH_TOKEN}_${configurationName}#tabId=${tabId}`;\n }\n if (tokens?.idTokenPayload?.nonce && currentDatabase.nonce != null) {\n tokens.idTokenPayload.nonce = `${TOKEN.NONCE_TOKEN}_${configurationName}#tabId=${tabId}`;\n }\n port.postMessage({\n tokens,\n status: currentDatabase.status,\n configurationName,\n version,\n });\n }\n return;\n }\n\n case 'setDemonstratingProofOfPossessionNonce': {\n currentDatabase.demonstratingProofOfPossessionNonce =\n data.data.demonstratingProofOfPossessionNonce;\n port.postMessage({ configurationName });\n return;\n }\n\n case 'getDemonstratingProofOfPossessionNonce': {\n const demonstratingProofOfPossessionNonce =\n currentDatabase.demonstratingProofOfPossessionNonce;\n port.postMessage({\n configurationName,\n demonstratingProofOfPossessionNonce,\n });\n return;\n }\n\n case 'setState': {\n currentDatabase.state = data.data.state;\n port.postMessage({ configurationName });\n return;\n }\n\n case 'getState': {\n const state = currentDatabase.state;\n port.postMessage({ configurationName, state });\n return;\n }\n\n case 'setCodeVerifier': {\n currentDatabase.codeVerifier = data.data.codeVerifier;\n port.postMessage({ configurationName });\n return;\n }\n\n case 'getCodeVerifier': {\n const codeVerifier =\n currentDatabase.codeVerifier != null\n ? `${TOKEN.CODE_VERIFIER}_${configurationName}#tabId=${tabId}`\n : null;\n port.postMessage({\n configurationName,\n codeVerifier,\n });\n return;\n }\n\n case 'setSessionState': {\n currentDatabase.sessionState = data.data.sessionState;\n port.postMessage({ configurationName });\n return;\n }\n\n case 'getSessionState': {\n const sessionState = currentDatabase.sessionState;\n port.postMessage({ configurationName, sessionState });\n return;\n }\n\n case 'setNonce': {\n const nonce = data.data.nonce;\n if (nonce) {\n currentDatabase.nonce = nonce;\n }\n port.postMessage({ configurationName });\n return;\n }\n\n case 'getNonce': {\n const keyNonce = `${TOKEN.NONCE_TOKEN}_${configurationName}#tabId=${tabId}`;\n const nonce = currentDatabase.nonce ? keyNonce : null;\n port.postMessage({ configurationName, nonce });\n return;\n }\n\n default:\n return;\n }\n};\n\n// Event listeners\n_self.addEventListener('fetch', handleFetch);\n_self.addEventListener('message', handleMessage);\n"],"mappings":"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"}
1
+ {"version":3,"file":"OidcServiceWorker.js","names":[],"sources":["../src/constants.ts","../src/jwt.ts","../src/crypto.ts","../src/dpop.ts","../src/utils/normalizeUrl.ts","../src/utils/domains.ts","../src/utils/serializeHeaders.ts","../src/utils/shouldBypassDestination.ts","../src/utils/sleep.ts","../src/utils/tokens.ts","../src/utils/waitForValidTokens.ts","../src/oidcConfig.ts","../src/utils/codeVerifier.ts","../src/version.ts","../src/OidcServiceWorker.ts"],"sourcesContent":["const scriptFilename = 'OidcTrustedDomains.js';\nconst acceptAnyDomainToken = '*';\n\ntype TokenType = {\n readonly REFRESH_TOKEN: string;\n readonly ACCESS_TOKEN: string;\n readonly NONCE_TOKEN: string;\n readonly CODE_VERIFIER: string;\n};\n\nconst TOKEN: TokenType = {\n REFRESH_TOKEN: 'REFRESH_TOKEN_SECURED_BY_OIDC_SERVICE_WORKER',\n ACCESS_TOKEN: 'ACCESS_TOKEN_SECURED_BY_OIDC_SERVICE_WORKER',\n NONCE_TOKEN: 'NONCE_SECURED_BY_OIDC_SERVICE_WORKER',\n CODE_VERIFIER: 'CODE_VERIFIER_SECURED_BY_OIDC_SERVICE_WORKER',\n};\n\ntype TokenRenewModeType = {\n readonly access_token_or_id_token_invalid: string;\n readonly access_token_invalid: string;\n readonly id_token_invalid: string;\n};\n\nconst TokenRenewMode: TokenRenewModeType = {\n access_token_or_id_token_invalid: 'access_token_or_id_token_invalid',\n access_token_invalid: 'access_token_invalid',\n id_token_invalid: 'id_token_invalid',\n};\n\nconst openidWellknownUrlEndWith = '/.well-known/openid-configuration';\n\nexport { acceptAnyDomainToken, openidWellknownUrlEndWith, scriptFilename, TOKEN, TokenRenewMode };\n","// code base on https://coolaj86.com/articles/sign-jwt-webcrypto-vanilla-js/\n\n// String (UCS-2) to Uint8Array\n//\n// because... JavaScript, Strings, and Buffers\n// @ts-ignore\nimport { DemonstratingProofOfPossessionConfiguration } from './types';\n\nfunction strToUint8(str: string) {\n return new TextEncoder().encode(str);\n}\n\n// Binary String to URL-Safe Base64\n//\n// btoa (Binary-to-Ascii) means \"binary string\" to base64\n// @ts-ignore\nfunction binToUrlBase64(bin) {\n return btoa(bin).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+/g, '');\n}\n\n// UTF-8 to Binary String\n//\n// Because JavaScript has a strange relationship with strings\n// https://coolaj86.com/articles/base64-unicode-utf-8-javascript-and-you/\n// @ts-ignore\nfunction utf8ToBinaryString(str) {\n const escstr = encodeURIComponent(str);\n // replaces any uri escape sequence, such as %0A,\n // with binary escape, such as 0x0A\n // @ts-ignore\n return escstr.replace(/%([0-9A-F]{2})/g, function (match: string, p1) {\n return String.fromCharCode(parseInt(p1, 16));\n });\n}\n\n// Uint8Array to URL Safe Base64\n//\n// the shortest distant between two encodings... binary string\n// @ts-ignore\nexport const uint8ToUrlBase64 = (uint8: Uint8Array) => {\n let bin = '';\n // @ts-ignore\n uint8.forEach(function (code) {\n bin += String.fromCharCode(code);\n });\n return binToUrlBase64(bin);\n};\n\n// UCS-2 String to URL-Safe Base64\n//\n// btoa doesn't work on UTF-8 strings\n// @ts-ignore\nfunction strToUrlBase64(str) {\n return binToUrlBase64(utf8ToBinaryString(str));\n}\n\nexport const defaultDemonstratingProofOfPossessionConfiguration: DemonstratingProofOfPossessionConfiguration =\n {\n importKeyAlgorithm: {\n name: 'ECDSA',\n namedCurve: 'P-256',\n hash: { name: 'ES256' },\n },\n signAlgorithm: { name: 'ECDSA', hash: { name: 'SHA-256' } },\n generateKeyAlgorithm: {\n name: 'ECDSA',\n namedCurve: 'P-256',\n },\n digestAlgorithm: { name: 'SHA-256' },\n jwtHeaderAlgorithm: 'ES256',\n };\n\n// @ts-ignore\nconst sign =\n (w: any) =>\n async (\n jwk: any,\n headers: any,\n claims: any,\n demonstratingProofOfPossessionConfiguration: DemonstratingProofOfPossessionConfiguration,\n jwtHeaderType = 'dpop+jwt',\n ) => {\n // Make a shallow copy of the key\n // (to set ext if it wasn't already set)\n jwk = Object.assign({}, jwk);\n\n // The headers should probably be empty\n headers.typ = jwtHeaderType;\n headers.alg = demonstratingProofOfPossessionConfiguration.jwtHeaderAlgorithm;\n switch (headers.alg) {\n case 'ES256': //if (!headers.kid) {\n // alternate: see thumbprint function below\n headers.jwk = { kty: jwk.kty, crv: jwk.crv, x: jwk.x, y: jwk.y };\n //}\n break;\n case 'RS256':\n headers.jwk = { kty: jwk.kty, n: jwk.n, e: jwk.e, kid: headers.kid };\n break;\n default:\n throw new Error('Unknown or not implemented JWS algorithm');\n }\n\n const jws = {\n // @ts-ignore\n // JWT \"headers\" really means JWS \"protected headers\"\n protected: strToUrlBase64(JSON.stringify(headers)),\n // @ts-ignore\n // JWT \"claims\" are really a JSON-defined JWS \"payload\"\n payload: strToUrlBase64(JSON.stringify(claims)),\n };\n\n // To import as EC (ECDSA, P-256, SHA-256, ES256)\n const keyType = demonstratingProofOfPossessionConfiguration.importKeyAlgorithm;\n\n // To make re-exportable as JSON (or DER/PEM)\n const exportable = true;\n\n // Import as a private key that isn't black-listed from signing\n const privileges = ['sign'];\n\n // Actually do the import, which comes out as an abstract key type\n // @ts-ignore\n const privateKey = await w.crypto.subtle.importKey('jwk', jwk, keyType, exportable, privileges);\n // Convert UTF-8 to Uint8Array ArrayBuffer\n // @ts-ignore\n const data = strToUint8(`${jws.protected}.${jws.payload}`);\n\n // The signature and hash should match the bit-entropy of the key\n // https://tools.ietf.org/html/rfc7518#section-3\n const signatureType = demonstratingProofOfPossessionConfiguration.signAlgorithm;\n\n const signature = await w.crypto.subtle.sign(signatureType, privateKey, data);\n // returns an ArrayBuffer containing a JOSE (not X509) signature,\n // which must be converted to Uint8 to be useful\n // @ts-ignore\n jws.signature = uint8ToUrlBase64(new Uint8Array(signature));\n // JWT is just a \"compressed\", \"protected\" JWS\n // @ts-ignore\n return `${jws.protected}.${jws.payload}.${jws.signature}`;\n };\n\nexport const JWT = { sign };\n\n// @ts-ignore\nconst generate =\n (w: any) => async (generateKeyAlgorithm: RsaHashedKeyGenParams | EcKeyGenParams) => {\n const keyType = generateKeyAlgorithm;\n const exportable = true;\n const privileges = ['sign', 'verify'];\n // @ts-ignore\n const key = await w.crypto.subtle.generateKey(keyType, exportable, privileges);\n // returns an abstract and opaque WebCrypto object,\n // which in most cases you'll want to export as JSON to be able to save\n return await w.crypto.subtle.exportKey('jwk', key.privateKey);\n };\n\n// Create a Public Key from a Private Key\n//\n// chops off the private parts\n// @ts-ignore\nconst neuter = jwk => {\n const copy = Object.assign({}, jwk);\n delete copy.d;\n copy.key_ops = ['verify'];\n return copy;\n};\n\nconst EC = {\n generate,\n neuter,\n};\n// @ts-ignore\nconst thumbprint = (w: any) => async (jwk, digestAlgorithm: AlgorithmIdentifier) => {\n let sortedPub;\n // lexigraphically sorted, no spaces\n switch (jwk.kty) {\n case 'EC':\n sortedPub = '{\"crv\":\"CRV\",\"kty\":\"EC\",\"x\":\"X\",\"y\":\"Y\"}'\n .replace('CRV', jwk.crv)\n .replace('X', jwk.x)\n .replace('Y', jwk.y);\n break;\n case 'RSA':\n sortedPub = '{\"e\":\"E\",\"kty\":\"RSA\",\"n\":\"N\"}'.replace('E', jwk.e).replace('N', jwk.n);\n break;\n default:\n throw new Error('Unknown or not implemented JWK type');\n }\n // The hash should match the size of the key,\n // but we're only dealing with P-256\n const hash = await w.crypto.subtle.digest(digestAlgorithm, strToUint8(sortedPub));\n return uint8ToUrlBase64(new Uint8Array(hash));\n};\n\nexport const JWK = { thumbprint };\n\nexport const generateJwkAsync =\n (w: any) => async (generateKeyAlgorithm: RsaHashedKeyGenParams | EcKeyGenParams) => {\n // @ts-ignore\n const jwk = await EC.generate(w)(generateKeyAlgorithm);\n // console.info('Private Key:', JSON.stringify(jwk));\n // @ts-ignore\n // console.info('Public Key:', JSON.stringify(EC.neuter(jwk)));\n return jwk;\n };\n\nexport const generateJwtDemonstratingProofOfPossessionAsync =\n (w: any) =>\n (demonstratingProofOfPossessionConfiguration: DemonstratingProofOfPossessionConfiguration) =>\n async (jwk: any, method = 'POST', url: string, extrasClaims = {}) => {\n const claims = {\n // https://www.rfc-editor.org/rfc/rfc9449.html#name-concept\n jti: btoa(w.crypto.randomUUID()),\n htm: method,\n htu: url,\n iat: Math.round(Date.now() / 1000),\n ...extrasClaims,\n };\n // @ts-ignore\n const kid = await JWK.thumbprint(w)(\n jwk,\n demonstratingProofOfPossessionConfiguration.digestAlgorithm,\n );\n // @ts-ignore\n const jwt = await JWT.sign(w)(\n jwk,\n { kid: kid },\n claims,\n demonstratingProofOfPossessionConfiguration,\n );\n // console.info('JWT:', jwt);\n return jwt;\n };\n","import { uint8ToUrlBase64 } from './jwt';\n\nexport function textEncodeLite(str: string) {\n const buf = new ArrayBuffer(str.length);\n const bufView = new Uint8Array(buf);\n\n for (let i = 0; i < str.length; i++) {\n bufView[i] = str.charCodeAt(i);\n }\n return bufView;\n}\n\nexport function base64urlOfHashOfASCIIEncodingAsync(code: string): Promise<string> {\n return new Promise((resolve, reject) => {\n crypto.subtle.digest('SHA-256', textEncodeLite(code)).then(\n buffer => {\n return resolve(uint8ToUrlBase64(new Uint8Array(buffer)));\n },\n error => reject(error),\n );\n });\n}\n","import { defaultDemonstratingProofOfPossessionConfiguration } from './jwt';\nimport { Domain, DomainDetails } from './types.js';\n\nconst isDpop = (trustedDomain: Domain[] | DomainDetails): boolean => {\n if (Array.isArray(trustedDomain)) {\n return false;\n }\n return trustedDomain.demonstratingProofOfPossession ?? false;\n};\n\nexport const getDpopConfiguration = (trustedDomain: Domain[] | DomainDetails) => {\n if (!isDpop(trustedDomain)) {\n return null;\n }\n\n if (Array.isArray(trustedDomain)) {\n return null;\n }\n\n return (\n trustedDomain.demonstratingProofOfPossessionConfiguration ??\n defaultDemonstratingProofOfPossessionConfiguration\n );\n};\n\nexport const getDpopOnlyWhenDpopHeaderPresent = (trustedDomain: Domain[] | DomainDetails) => {\n if (!isDpop(trustedDomain)) {\n return null;\n }\n\n if (Array.isArray(trustedDomain)) {\n return null;\n }\n\n return trustedDomain.demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent ?? true;\n};\n","export function normalizeUrl(url: string) {\n try {\n return new URL(url).toString();\n } catch (error) {\n console.error(`Failed to normalize url: ${url}`, error);\n return url;\n }\n}\n","import { acceptAnyDomainToken, openidWellknownUrlEndWith, scriptFilename } from '../constants';\nimport { Database, Domain, DomainDetails, OidcConfig, TrustedDomains } from '../types';\nimport { normalizeUrl } from './normalizeUrl';\n\nexport function checkDomain(domains: Domain[], endpoint: string) {\n if (!endpoint) {\n return;\n }\n\n const domain = domains.find(domain => {\n let testable: RegExp;\n\n if (typeof domain === 'string') {\n testable = new RegExp(`^${domain}`);\n } else {\n testable = domain;\n }\n\n return testable.test?.(endpoint);\n });\n if (!domain) {\n throw new Error(\n 'Domain ' + endpoint + ' is not trusted, please add domain in ' + scriptFilename,\n );\n }\n}\n\nexport const getDomains = (\n trustedDomain: Domain[] | DomainDetails,\n type: 'oidc' | 'accessToken',\n) => {\n if (Array.isArray(trustedDomain)) {\n return trustedDomain;\n }\n\n return trustedDomain[`${type}Domains`] ?? trustedDomain.domains ?? [];\n};\n\nexport const getCurrentDatabaseDomain = (\n database: Database,\n url: string,\n trustedDomains: TrustedDomains,\n) => {\n if (url.endsWith(openidWellknownUrlEndWith)) {\n return null;\n }\n const datatases = [];\n for (const [key, currentDatabase] of Object.entries<OidcConfig>(database)) {\n const oidcServerConfiguration = currentDatabase.oidcServerConfiguration;\n\n if (!oidcServerConfiguration) {\n continue;\n }\n\n if (\n oidcServerConfiguration.tokenEndpoint &&\n url === normalizeUrl(oidcServerConfiguration.tokenEndpoint)\n ) {\n continue;\n }\n if (\n oidcServerConfiguration.revocationEndpoint &&\n url === normalizeUrl(oidcServerConfiguration.revocationEndpoint)\n ) {\n continue;\n }\n const trustedDomain = trustedDomains == null ? [] : trustedDomains[key.split('#')[0]];\n\n const domains = getDomains(trustedDomain, 'accessToken');\n const domainsToSendTokens = oidcServerConfiguration.userInfoEndpoint\n ? [normalizeUrl(oidcServerConfiguration.userInfoEndpoint), ...domains]\n : [...domains];\n\n let hasToSendToken = false;\n if (domainsToSendTokens.find(f => f === acceptAnyDomainToken)) {\n hasToSendToken = true;\n } else {\n for (let i = 0; i < domainsToSendTokens.length; i++) {\n let domain = domainsToSendTokens[i];\n\n if (typeof domain === 'string') {\n domain = new RegExp(`^${domain}`);\n }\n\n if (domain.test?.(url)) {\n hasToSendToken = true;\n break;\n }\n }\n }\n\n if (hasToSendToken) {\n if (currentDatabase.tokens) {\n datatases.push(currentDatabase);\n }\n }\n }\n return datatases;\n};\n","function serializeHeaders(headers: Headers): Record<string, string> {\n const headersObj: Record<string, string> = {};\n for (const key of headers.keys()) {\n const value = headers.get(key);\n if (value !== null) {\n headersObj[key] = value;\n }\n }\n return headersObj;\n}\nexport { serializeHeaders };\n","const bypassedDestinations = ['image', 'font', 'media', 'document', 'iframe', 'script'];\n\n/**\n * Determines whether a fetch event should be bypassed (not intercepted by the service worker).\n * Navigation requests (mode === 'navigate') are never bypassed, even when their destination\n * is in the bypassed list, so that access tokens can be injected into new-tab navigations.\n */\nexport const shouldBypassDestination = (destination: string, mode: string): boolean => {\n return bypassedDestinations.includes(destination) && mode !== 'navigate';\n};\n","const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));\nexport { sleep };\n","/* eslint-disable simple-import-sort/exports */\nimport { TOKEN, TokenRenewMode } from '../constants';\nimport {\n AccessTokenPayload,\n IdTokenPayload,\n OidcConfig,\n OidcConfiguration,\n OidcServerConfiguration,\n Tokens,\n} from '../types';\n\nexport const parseJwt = (payload: string) => {\n return JSON.parse(b64DecodeUnicode(payload.replaceAll(/-/g, '+').replaceAll(/_/g, '/')));\n};\nfunction b64DecodeUnicode(str: string) {\n return decodeURIComponent(\n Array.prototype.map\n .call(atob(str), c => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))\n .join(''),\n );\n}\n\nfunction computeTimeLeft(refreshTimeBeforeTokensExpirationInSecond: number, expiresAt: number) {\n const currentTimeUnixSecond = new Date().getTime() / 1000;\n return Math.round(expiresAt - refreshTimeBeforeTokensExpirationInSecond - currentTimeUnixSecond);\n}\n\nfunction isTokensValid(tokens: Tokens | null) {\n if (!tokens) {\n return false;\n }\n return computeTimeLeft(0, tokens.expiresAt) > 0;\n}\n\nconst extractTokenPayload = (token?: string) => {\n try {\n if (!token) {\n return null;\n }\n const parts = token.split('.');\n return parts.length === 3 ? parseJwt(parts[1]) : null;\n } catch (e) {\n console.warn(e);\n }\n return null;\n};\n\n// https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation (excluding rules #1, #4, #5, #7, #8, #12, and #13 which did not apply).\n// https://github.com/openid/AppAuth-JS/issues/65\nconst isTokensOidcValid = (\n tokens: Tokens,\n nonce: string | null,\n oidcServerConfiguration: OidcServerConfiguration,\n): { isValid: boolean; reason: string } => {\n if (tokens.idTokenPayload) {\n const idTokenPayload = tokens.idTokenPayload;\n // 2: The Issuer Identifier for the OpenID Provider (which is typically obtained during Discovery) MUST exactly match the value of the iss (issuer) Claim.\n if (idTokenPayload && oidcServerConfiguration.issuer !== idTokenPayload.iss) {\n return {\n isValid: false,\n reason: `Issuer does not match (oidcServerConfiguration issuer) ${oidcServerConfiguration.issuer} !== (idTokenPayload issuer) ${idTokenPayload.iss}`,\n };\n }\n // 3: The Client MUST validate that the aud (audience) Claim contains its client_id value registered at the Issuer identified by the iss (issuer) Claim as an audience. The aud (audience) Claim MAY contain an array with more than one element. The ID Token MUST be rejected if the ID Token does not list the Client as a valid audience, or if it contains additional audiences not trusted by the Client.\n\n // 6: If the ID Token is received via direct communication between the Client and the Token Endpoint (which it is in this flow), the TLS server validation MAY be used to validate the issuer in place of checking the token signature. The Client MUST validate the signature of all other ID Tokens according to JWS [JWS] using the algorithm specified in the JWT alg Header Parameter. The Client MUST use the keys provided by the Issuer.\n\n // 9: The current time MUST be before the time represented by the exp Claim.\n const currentTimeUnixSecond = new Date().getTime() / 1000;\n if (idTokenPayload && idTokenPayload.exp && idTokenPayload.exp < currentTimeUnixSecond) {\n return {\n isValid: false,\n reason: `Token expired at (idTokenPayload exp) ${idTokenPayload.exp} < (currentTimeUnixSecond) ${currentTimeUnixSecond}`,\n };\n }\n // 10: The iat Claim can be used to reject tokens that were issued too far away from the current time, limiting the amount of time that nonces need to be stored to prevent attacks. The acceptable range is Client specific.\n const timeInSevenDays = 60 * 60 * 24 * 7;\n if (\n idTokenPayload &&\n idTokenPayload.iat &&\n idTokenPayload.iat + timeInSevenDays < currentTimeUnixSecond\n ) {\n return {\n isValid: false,\n reason: `Token is used from too long time (idTokenPayload iat + timeInSevenDays) ${idTokenPayload.iat + timeInSevenDays} < (currentTimeUnixSecond) ${currentTimeUnixSecond}`,\n };\n }\n // 11: If a nonce value was sent in the Authentication Request, a nonce Claim MUST be present and its value checked to verify that it is the same value as the one that was sent in the Authentication Request. The Client SHOULD check the nonce value for replay attacks. The precise method for detecting replay attacks is Client specific.\n if (idTokenPayload && nonce && idTokenPayload.nonce && idTokenPayload.nonce !== nonce) {\n return {\n isValid: false,\n reason: `Nonce does not match (nonce) ${nonce} !== (idTokenPayload nonce) ${idTokenPayload.nonce}`,\n };\n }\n }\n return { isValid: true, reason: '' };\n};\n\nfunction extractedIssueAt(\n tokens: Tokens,\n accessTokenPayload: AccessTokenPayload | null,\n _idTokenPayload: IdTokenPayload,\n) {\n if (!tokens.issued_at) {\n if (accessTokenPayload && accessTokenPayload.iat) {\n return accessTokenPayload.iat;\n } else if (_idTokenPayload && _idTokenPayload.iat) {\n return _idTokenPayload.iat;\n } else {\n const currentTimeUnixSecond = new Date().getTime() / 1000;\n return currentTimeUnixSecond;\n }\n } else if (typeof tokens.issued_at == 'string') {\n return parseInt(tokens.issued_at, 10);\n }\n return tokens.issued_at;\n}\n\nfunction _hideTokens(\n tokens: Tokens,\n currentDatabaseElement: OidcConfig,\n configurationName: string,\n) {\n if (!tokens.issued_at) {\n const currentTimeUnixSecond = new Date().getTime() / 1000;\n tokens.issued_at = currentTimeUnixSecond;\n } else if (typeof tokens.issued_at == 'string') {\n tokens.issued_at = parseInt(tokens.issued_at, 10);\n }\n\n const accessTokenPayload = extractTokenPayload(tokens.access_token);\n const secureTokens = {\n ...tokens,\n accessTokenPayload,\n };\n if (currentDatabaseElement.hideAccessToken) {\n secureTokens.access_token = `${TOKEN.ACCESS_TOKEN}_${configurationName}`;\n }\n tokens.accessTokenPayload = accessTokenPayload;\n\n // When id_token is not rotated we reuse old id_token\n const oldTokens = currentDatabaseElement.tokens;\n let id_token: string | null;\n if (oldTokens != null && 'id_token' in oldTokens && !('id_token' in tokens)) {\n id_token = oldTokens.id_token;\n } else {\n id_token = tokens.id_token;\n }\n tokens.id_token = id_token;\n\n let _idTokenPayload = null;\n if (id_token) {\n _idTokenPayload = extractTokenPayload(id_token);\n tokens.idTokenPayload = _idTokenPayload != null ? { ..._idTokenPayload } : null;\n if (_idTokenPayload && _idTokenPayload.nonce && currentDatabaseElement.nonce != null) {\n const keyNonce = `${TOKEN.NONCE_TOKEN}_${currentDatabaseElement.configurationName}`;\n _idTokenPayload.nonce = keyNonce;\n }\n secureTokens.idTokenPayload = _idTokenPayload;\n }\n if (tokens.refresh_token) {\n secureTokens.refresh_token = `${TOKEN.REFRESH_TOKEN}_${configurationName}`;\n }\n\n tokens.issued_at = extractedIssueAt(tokens, accessTokenPayload, _idTokenPayload);\n\n const expireIn =\n typeof tokens.expires_in == 'string' ? parseInt(tokens.expires_in, 10) : tokens.expires_in;\n\n const idTokenExpiresAt =\n _idTokenPayload && _idTokenPayload.exp ? _idTokenPayload.exp : Number.MAX_VALUE;\n const accessTokenExpiresAt =\n accessTokenPayload && accessTokenPayload.exp\n ? accessTokenPayload.exp\n : tokens.issued_at + expireIn;\n\n let expiresAt: number;\n const tokenRenewMode = (currentDatabaseElement.oidcConfiguration as OidcConfiguration)\n .token_renew_mode;\n if (tokenRenewMode === TokenRenewMode.access_token_invalid) {\n expiresAt = accessTokenExpiresAt;\n } else if (tokenRenewMode === TokenRenewMode.id_token_invalid) {\n expiresAt = idTokenExpiresAt;\n } else {\n expiresAt = idTokenExpiresAt < accessTokenExpiresAt ? idTokenExpiresAt : accessTokenExpiresAt;\n }\n secureTokens.expiresAt = expiresAt;\n\n tokens.expiresAt = expiresAt;\n const nonce = currentDatabaseElement.nonce ? currentDatabaseElement.nonce.nonce : null;\n const { isValid, reason } = isTokensOidcValid(\n tokens,\n nonce as string,\n currentDatabaseElement.oidcServerConfiguration as OidcServerConfiguration,\n ); // TODO: Type assertion, could be null.\n if (!isValid) {\n throw Error(`Tokens are not OpenID valid, reason: ${reason}`);\n }\n\n // When refresh_token is not rotated we reuse old refresh_token\n if (oldTokens != null && 'refresh_token' in oldTokens && !('refresh_token' in tokens)) {\n const refreshToken = oldTokens.refresh_token;\n\n currentDatabaseElement.tokens = {\n ...tokens,\n refresh_token: refreshToken,\n };\n } else {\n currentDatabaseElement.tokens = tokens;\n }\n\n currentDatabaseElement.status = 'LOGGED_IN';\n return secureTokens;\n}\n\nconst demonstratingProofOfPossessionNonceResponseHeader = 'DPoP-Nonce';\nfunction hideTokens(currentDatabaseElement: OidcConfig) {\n const configurationName = currentDatabaseElement.configurationName;\n return (response: Response) => {\n if (response.status !== 200) {\n return response;\n }\n const newHeaders = new Headers(response.headers);\n if (response.headers.has(demonstratingProofOfPossessionNonceResponseHeader)) {\n currentDatabaseElement.demonstratingProofOfPossessionNonce = response.headers.get(\n demonstratingProofOfPossessionNonceResponseHeader,\n );\n newHeaders.delete(demonstratingProofOfPossessionNonceResponseHeader);\n }\n\n return response.json().then<Response>((tokens: Tokens) => {\n const secureTokens = _hideTokens(tokens, currentDatabaseElement, configurationName);\n const body = JSON.stringify(secureTokens);\n return new Response(body, {\n status: response.status,\n statusText: response.statusText,\n headers: newHeaders,\n });\n });\n };\n}\n\nexport {\n b64DecodeUnicode,\n computeTimeLeft,\n isTokensValid,\n extractTokenPayload,\n isTokensOidcValid,\n hideTokens,\n _hideTokens,\n};\n","import { OidcConfig } from '../types';\nimport { sleep } from './sleep';\nimport { isTokensValid } from './tokens';\n\nexport const TOKEN_RENEWAL_TIMEOUT_MS = 5000;\nexport const TOKEN_RENEWAL_POLL_INTERVAL_MS = 200;\n\n/**\n * Polls until the tokens in the given config are valid, or until a timeout elapses.\n *\n * @returns `null` when tokens become valid; a synthetic 401 `Response` on timeout or\n * when the tokens are cleared while waiting (e.g. due to a parallel logout).\n */\nexport async function waitForValidTokens(\n config: OidcConfig,\n maxWaitMs = TOKEN_RENEWAL_TIMEOUT_MS,\n pollIntervalMs = TOKEN_RENEWAL_POLL_INTERVAL_MS,\n): Promise<Response | null> {\n const startTime = Date.now();\n while (config.tokens && !isTokensValid(config.tokens)) {\n if (Date.now() - startTime >= maxWaitMs) {\n return new Response(null, {\n status: 401,\n statusText: 'Token expired - service worker renewal timeout',\n });\n }\n await sleep(pollIntervalMs);\n }\n\n if (!config.tokens?.access_token) {\n return new Response(null, {\n status: 401,\n statusText: 'Missing access token',\n });\n }\n\n return null;\n}\n","import { acceptAnyDomainToken } from './constants';\nimport { Database, Domain, OidcConfig, OidcServerConfiguration, TrustedDomains } from './types';\nimport { getDomains, normalizeUrl } from './utils';\n\nconst getOidcServerUrls = (oidcServerConfiguration: OidcServerConfiguration): string[] => {\n return [\n oidcServerConfiguration.issuer,\n oidcServerConfiguration.authorizationEndpoint,\n oidcServerConfiguration.tokenEndpoint,\n oidcServerConfiguration.revocationEndpoint,\n oidcServerConfiguration.userInfoEndpoint,\n ]\n .filter(Boolean)\n .map(normalizeUrl);\n};\n\nconst isOidcServerRequest = (database: Database, normalizedUrl: string): boolean => {\n return Object.values(database).some(config => {\n const { oidcServerConfiguration } = config || {};\n if (!oidcServerConfiguration) {\n return false;\n }\n\n return getOidcServerUrls(oidcServerConfiguration).some(oidcUrl =>\n normalizedUrl.startsWith(oidcUrl),\n );\n });\n};\n\nconst isDomainMatchingUrl = (domain: Domain, normalizedUrl: string): boolean => {\n if (typeof domain === 'string') {\n domain = new RegExp(`^${domain}`);\n }\n\n return domain.test?.(normalizedUrl) ?? false;\n};\n\nconst isAccessTokenDomainRequest = (\n database: Database,\n normalizedUrl: string,\n trustedDomains: TrustedDomains,\n): boolean => {\n return Object.entries(database).some(([key, currentDatabase]) => {\n if (!currentDatabase.oidcServerConfiguration) {\n return false;\n }\n\n const trustedDomain = trustedDomains?.[key.split('#')[0]] ?? [];\n const domains = getDomains(trustedDomain, 'accessToken');\n\n if (domains.some(domain => domain === acceptAnyDomainToken)) {\n return true;\n }\n\n return domains.some(domain => isDomainMatchingUrl(domain, normalizedUrl));\n });\n};\n\nconst shouldBypassNonOidcRequest = (\n database: Database,\n normalizedUrl: string,\n trustedDomains: TrustedDomains,\n): boolean => {\n const configurations = Object.values(database);\n\n if (configurations.length === 0) {\n return false;\n }\n\n if (!configurations.every(config => config.bypassAllNonOidcRequests)) {\n return false;\n }\n\n if (!configurations.every(config => config.oidcServerConfiguration != null)) {\n return false;\n }\n\n return (\n !isOidcServerRequest(database, normalizedUrl) &&\n !isAccessTokenDomainRequest(database, normalizedUrl, trustedDomains)\n );\n};\n\nconst getMatchingOidcConfigurations = (database: Database, url: string): OidcConfig[] => {\n const normalizedUrl = normalizeUrl(url);\n return Object.values(database).filter(config => {\n const { oidcServerConfiguration } = config || {};\n const { tokenEndpoint, revocationEndpoint } = oidcServerConfiguration || {};\n\n return (\n (tokenEndpoint && normalizedUrl.startsWith(normalizeUrl(tokenEndpoint))) ||\n (revocationEndpoint && normalizedUrl.startsWith(normalizeUrl(revocationEndpoint)))\n );\n });\n};\n\nexport {\n getMatchingOidcConfigurations as getCurrentDatabasesTokenEndpoint,\n isAccessTokenDomainRequest,\n isOidcServerRequest,\n shouldBypassNonOidcRequest,\n};\n","export function replaceCodeVerifier(codeVerifier: string, newCodeVerifier: string): string {\n const regex = /[?&]code_verifier=([^&]+)/i;\n return codeVerifier.replace(regex, `&code_verifier=${newCodeVerifier}`);\n}\n\nexport const extractConfigurationNameFromCodeVerifier = (body: string): string => {\n const regex = /[?&]code_verifier=CODE_VERIFIER_SECURED_BY_OIDC_SERVICE_WORKER_([^&]+)/;\n const match = body.match(regex);\n\n return match ? decodeURIComponent(match[1]) : '';\n};\n","export default '7.29.5';\n","import { acceptAnyDomainToken, scriptFilename, TOKEN } from './constants';\nimport { base64urlOfHashOfASCIIEncodingAsync } from './crypto';\nimport { getDpopConfiguration, getDpopOnlyWhenDpopHeaderPresent } from './dpop';\nimport { generateJwkAsync, generateJwtDemonstratingProofOfPossessionAsync } from './jwt';\nimport { getCurrentDatabasesTokenEndpoint, shouldBypassNonOidcRequest } from './oidcConfig';\nimport { Database, MessageEventData, OidcConfig, TrustedDomains } from './types';\nimport {\n checkDomain,\n getCurrentDatabaseDomain,\n getDomains,\n hideTokens,\n normalizeUrl,\n serializeHeaders,\n shouldBypassDestination,\n sleep,\n waitForValidTokens,\n} from './utils';\nimport {\n extractConfigurationNameFromCodeVerifier,\n replaceCodeVerifier,\n} from './utils/codeVerifier';\nimport version from './version';\n\n// @ts-ignore\nif (typeof trustedTypes !== 'undefined' && typeof trustedTypes.createPolicy === 'function') {\n // @ts-ignore\n trustedTypes.createPolicy('default', {\n createScriptURL: function (url: string) {\n if (url === scriptFilename) {\n return url;\n } else {\n throw new Error('Untrusted script URL blocked: ' + url);\n }\n },\n });\n}\n\nconst _self = self as ServiceWorkerGlobalScope & typeof globalThis;\n\n// `trustedDomains` is declared in the externally loaded script (OidcTrustedDomains.js)\ndeclare let trustedDomains: TrustedDomains;\n\n_self.importScripts(scriptFilename);\n\nconst id = Math.round(new Date().getTime() / 1000).toString();\nconsole.log('init service worker with id', id);\nconst keepAliveJsonFilename = 'OidcKeepAliveServiceWorker.json';\nconst database: Database = {};\n\n/**\n * Keeps the service worker alive by responding with a cached response after a sleep.\n */\nconst keepAliveAsync = async (event: FetchEvent) => {\n const originalRequest = event.request;\n const isFromVanilla = originalRequest.headers.has('oidc-vanilla');\n const init = { status: 200, statusText: 'oidc-service-worker' };\n const response = new Response('{}', init);\n\n if (!isFromVanilla) {\n const originalRequestUrl = new URL(originalRequest.url);\n const minSleepSeconds = Number(originalRequestUrl.searchParams.get('minSleepSeconds')) || 240;\n for (let i = 0; i < minSleepSeconds; i++) {\n await sleep(1000 + Math.floor(Math.random() * 1000));\n const cache = await caches.open('oidc_dummy_cache');\n await cache.put(event.request, response.clone());\n }\n }\n return response;\n};\n\n/**\n * Generates DPoP headers when a DPoP configuration is present.\n */\nasync function generateDpopAsync(\n originalRequest: Request,\n currentDatabase: OidcConfig | null,\n url: string,\n extrasClaims = {},\n) {\n const headersExtras = serializeHeaders(originalRequest.headers);\n if (\n currentDatabase?.demonstratingProofOfPossessionConfiguration &&\n currentDatabase.demonstratingProofOfPossessionJwkJson &&\n (!currentDatabase.demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent ||\n (currentDatabase.demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent &&\n headersExtras.dpop))\n ) {\n const dpopConfiguration = currentDatabase.demonstratingProofOfPossessionConfiguration;\n const jwk = currentDatabase.demonstratingProofOfPossessionJwkJson;\n const method = originalRequest.method;\n const dpop = await generateJwtDemonstratingProofOfPossessionAsync(self)(dpopConfiguration)(\n jwk,\n method,\n url,\n extrasClaims,\n );\n\n headersExtras.dpop = dpop;\n if (currentDatabase.demonstratingProofOfPossessionNonce != null) {\n headersExtras.nonce = currentDatabase.demonstratingProofOfPossessionNonce;\n }\n }\n return headersExtras;\n}\n\n/**\n * Intercepts fetch requests to inject access tokens and handle token endpoints.\n */\nconst handleFetch = (event: FetchEvent): void => {\n /**\n * Exit early for requests that do not need to have an auth token attached.\n */\n if (shouldBypassDestination(event.request.destination, event.request.mode)) {\n return; // Don't call event.respondWith() - let browser handle naturally\n }\n\n const normalizedUrl = normalizeUrl(event.request.url);\n if (\n !normalizedUrl.includes(keepAliveJsonFilename) &&\n shouldBypassNonOidcRequest(database, normalizedUrl, trustedDomains)\n ) {\n return; // Don't call event.respondWith() - let browser handle naturally\n }\n\n event.respondWith(\n (async (): Promise<Response> => {\n try {\n const originalRequest = event.request;\n const url = normalizedUrl;\n\n // 1) Handle keep-alive requests\n if (url.includes(keepAliveJsonFilename)) {\n return keepAliveAsync(event);\n }\n\n // Check if an access token is available for this request\n const currentDatabasesForRequestAccessToken = getCurrentDatabaseDomain(\n database,\n url,\n trustedDomains,\n );\n\n const authorization = originalRequest.headers.get('authorization');\n let authenticationMode = 'Bearer';\n let key = 'default';\n\n if (authorization) {\n const split = authorization.split(' ');\n authenticationMode = split[0];\n if (split[1]?.includes('ACCESS_TOKEN_SECURED_BY_OIDC_SERVICE_WORKER_')) {\n key = split[1].split('ACCESS_TOKEN_SECURED_BY_OIDC_SERVICE_WORKER_')[1];\n }\n }\n\n const currentDatabaseForRequestAccessToken = currentDatabasesForRequestAccessToken?.find(\n c => c.configurationName.endsWith(key),\n );\n\n // Inject the access token into the request if one is available\n if (currentDatabaseForRequestAccessToken?.tokens?.access_token) {\n // Wait for token to become valid (a parallel refresh may be in progress)\n const tokenError = await waitForValidTokens(currentDatabaseForRequestAccessToken);\n if (tokenError) {\n return tokenError;\n }\n\n // Adjust request mode for CORS if configured\n let requestMode = originalRequest.mode;\n if (\n originalRequest.mode !== 'navigate' &&\n currentDatabaseForRequestAccessToken.convertAllRequestsToCorsExceptNavigate\n ) {\n requestMode = 'cors';\n }\n\n // Build request headers\n let headers: { [p: string]: string };\n\n // Skip the access token for navigate requests when setAccessTokenToNavigateRequests is false\n if (\n originalRequest.mode === 'navigate' &&\n !currentDatabaseForRequestAccessToken.setAccessTokenToNavigateRequests\n ) {\n headers = {\n ...serializeHeaders(originalRequest.headers),\n };\n } else {\n if (\n authenticationMode.toLowerCase() === 'dpop' ||\n (!currentDatabaseForRequestAccessToken.demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent &&\n currentDatabaseForRequestAccessToken.demonstratingProofOfPossessionConfiguration)\n ) {\n // DPoP mode\n const claimsExtras = {\n ath: await base64urlOfHashOfASCIIEncodingAsync(\n currentDatabaseForRequestAccessToken.tokens.access_token,\n ),\n };\n const dpopHeaders = await generateDpopAsync(\n originalRequest,\n currentDatabaseForRequestAccessToken,\n url,\n claimsExtras,\n );\n headers = {\n ...dpopHeaders,\n authorization: `DPoP ${currentDatabaseForRequestAccessToken.tokens.access_token}`,\n };\n } else {\n // Bearer mode\n headers = {\n ...serializeHeaders(originalRequest.headers),\n authorization: `${authenticationMode} ${currentDatabaseForRequestAccessToken.tokens.access_token}`,\n };\n }\n }\n\n let init: RequestInit;\n if (originalRequest.mode === 'navigate') {\n init = {\n headers: headers,\n };\n } else {\n init = {\n headers: headers,\n mode: requestMode,\n };\n }\n\n const newRequest = new Request(originalRequest, init);\n return fetch(newRequest);\n }\n\n // Pass through non-POST requests without modification\n if (event.request.method !== 'POST') {\n return fetch(originalRequest);\n }\n\n // Handle POST requests to known token/revocation endpoints\n const currentDatabases = getCurrentDatabasesTokenEndpoint(database, url);\n const numberDatabase = currentDatabases.length;\n\n if (numberDatabase > 0) {\n const responsePromise = new Promise<Response>((resolve, reject) => {\n const clonedRequest = originalRequest.clone();\n clonedRequest\n .text()\n .then(async actualBody => {\n let currentDatabase: OidcConfig | null = null;\n try {\n // Replace hidden token placeholders with the real token values\n if (\n actualBody.includes(TOKEN.REFRESH_TOKEN) ||\n actualBody.includes(TOKEN.ACCESS_TOKEN)\n ) {\n let headers = serializeHeaders(originalRequest.headers);\n let newBody = actualBody;\n\n for (let i = 0; i < numberDatabase; i++) {\n const currentDb = currentDatabases[i];\n if (currentDb?.tokens) {\n const claimsExtras = {\n ath: await base64urlOfHashOfASCIIEncodingAsync(\n currentDb.tokens.access_token,\n ),\n };\n headers = await generateDpopAsync(\n originalRequest,\n currentDb,\n url,\n claimsExtras,\n );\n\n const keyRefreshToken = encodeURIComponent(\n `${TOKEN.REFRESH_TOKEN}_${currentDb.configurationName}`,\n );\n if (actualBody.includes(keyRefreshToken)) {\n newBody = newBody.replace(\n keyRefreshToken,\n encodeURIComponent(currentDb.tokens.refresh_token as string),\n );\n currentDatabase = currentDb;\n break;\n }\n\n const keyAccessToken = encodeURIComponent(\n `${TOKEN.ACCESS_TOKEN}_${currentDb.configurationName}`,\n );\n if (actualBody.includes(keyAccessToken)) {\n newBody = newBody.replace(\n keyAccessToken,\n encodeURIComponent(currentDb.tokens.access_token),\n );\n currentDatabase = currentDb;\n break;\n }\n }\n }\n\n const fetchPromise = fetch(originalRequest, {\n body: newBody,\n method: clonedRequest.method,\n headers,\n mode: clonedRequest.mode,\n cache: clonedRequest.cache,\n redirect: clonedRequest.redirect,\n referrer: clonedRequest.referrer,\n credentials: clonedRequest.credentials,\n integrity: clonedRequest.integrity,\n });\n\n // Forward revocation requests without modifying the response body\n if (\n currentDatabase?.oidcServerConfiguration?.revocationEndpoint &&\n url.startsWith(\n normalizeUrl(currentDatabase.oidcServerConfiguration.revocationEndpoint),\n )\n ) {\n const resp = await fetchPromise;\n const txt = await resp.text();\n resolve(new Response(txt, resp));\n return;\n }\n\n // Hide real token values in the response\n const hidden = await fetchPromise.then(\n hideTokens(currentDatabase as OidcConfig),\n );\n resolve(hidden);\n return;\n }\n\n // Handle authorization code exchange: replace the PKCE code_verifier placeholder\n const isCodeVerifier = actualBody.includes('code_verifier=');\n if (isCodeVerifier) {\n const currentLoginCallbackConfigurationName =\n extractConfigurationNameFromCodeVerifier(actualBody);\n if (\n !currentLoginCallbackConfigurationName ||\n currentLoginCallbackConfigurationName === ''\n ) {\n throw new Error('No configuration name found in code_verifier');\n }\n currentDatabase = database[currentLoginCallbackConfigurationName];\n let newBody = actualBody;\n const codeVerifier = currentDatabase.codeVerifier;\n if (codeVerifier != null) {\n newBody = replaceCodeVerifier(newBody, codeVerifier);\n }\n\n const headersExtras = await generateDpopAsync(\n originalRequest,\n currentDatabase,\n url,\n );\n const resp = await fetch(originalRequest, {\n body: newBody,\n method: clonedRequest.method,\n headers: headersExtras,\n mode: clonedRequest.mode,\n cache: clonedRequest.cache,\n redirect: clonedRequest.redirect,\n referrer: clonedRequest.referrer,\n credentials: clonedRequest.credentials,\n integrity: clonedRequest.integrity,\n });\n const hidden = await hideTokens(currentDatabase)(resp);\n resolve(hidden);\n return;\n }\n\n // Pass through all other POST requests unchanged\n const normalResp = await fetch(originalRequest, {\n body: actualBody,\n method: clonedRequest.method,\n headers: serializeHeaders(originalRequest.headers),\n mode: clonedRequest.mode,\n cache: clonedRequest.cache,\n redirect: clonedRequest.redirect,\n referrer: clonedRequest.referrer,\n credentials: clonedRequest.credentials,\n integrity: clonedRequest.integrity,\n });\n resolve(normalResp);\n } catch (err) {\n reject(err);\n }\n })\n .catch(reject);\n });\n\n return responsePromise;\n }\n\n // Default: pass through the request unchanged\n return fetch(originalRequest);\n } catch (err) {\n // Surface unexpected errors as a 500 rather than silently hanging\n console.error('[OidcServiceWorker] handleFetch error:', err);\n return new Response('Service Worker Error', { status: 500 });\n }\n })(),\n );\n};\n\nconst handleMessage = async (event: ExtendableMessageEvent) => {\n const port = event.ports[0];\n const data = event.data as MessageEventData;\n\n if (event.data?.type === 'SKIP_WAITING') {\n await _self.skipWaiting();\n port?.postMessage?.({});\n return;\n } else if (event.data.type === 'claim') {\n _self.clients.claim().then(() => port.postMessage({}));\n return;\n }\n\n const configurationName = data.configurationName.split('#')[0];\n\n if (trustedDomains == null) {\n trustedDomains = {};\n }\n\n const trustedDomain = trustedDomains[configurationName];\n const allowMultiTabLogin = Array.isArray(trustedDomain)\n ? false\n : trustedDomain.allowMultiTabLogin;\n\n const tabId = allowMultiTabLogin ? data.tabId : 'default';\n const configurationNameWithTabId = `${configurationName}#tabId=${tabId}`;\n\n let currentDatabase = database[configurationNameWithTabId];\n if (!currentDatabase) {\n const showAccessToken = Array.isArray(trustedDomain) ? false : trustedDomain.showAccessToken;\n const doNotSetAccessTokenToNavigateRequests = Array.isArray(trustedDomain)\n ? true\n : trustedDomain.setAccessTokenToNavigateRequests;\n const convertAllRequestsToCorsExceptNavigate = Array.isArray(trustedDomain)\n ? false\n : trustedDomain.convertAllRequestsToCorsExceptNavigate;\n const bypassAllNonOidcRequests = Array.isArray(trustedDomain)\n ? false\n : trustedDomain.bypassAllNonOidcRequests;\n\n database[configurationNameWithTabId] = {\n tokens: null,\n state: null,\n codeVerifier: null,\n oidcServerConfiguration: null,\n oidcConfiguration: undefined,\n nonce: null,\n status: null,\n configurationName: configurationNameWithTabId,\n hideAccessToken: !showAccessToken,\n setAccessTokenToNavigateRequests: doNotSetAccessTokenToNavigateRequests ?? true,\n convertAllRequestsToCorsExceptNavigate: convertAllRequestsToCorsExceptNavigate ?? false,\n demonstratingProofOfPossessionNonce: null,\n demonstratingProofOfPossessionJwkJson: null,\n demonstratingProofOfPossessionConfiguration: null,\n demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent: false,\n allowMultiTabLogin: allowMultiTabLogin ?? false,\n bypassAllNonOidcRequests: bypassAllNonOidcRequests ?? false,\n };\n currentDatabase = database[configurationNameWithTabId];\n\n if (!trustedDomains[configurationName]) {\n trustedDomains[configurationName] = [];\n }\n }\n\n switch (data.type) {\n case 'clear':\n currentDatabase.tokens = null;\n currentDatabase.state = null;\n currentDatabase.codeVerifier = null;\n currentDatabase.nonce = null;\n currentDatabase.demonstratingProofOfPossessionNonce = null;\n currentDatabase.demonstratingProofOfPossessionJwkJson = null;\n currentDatabase.demonstratingProofOfPossessionConfiguration = null;\n currentDatabase.demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent = false;\n currentDatabase.status = data.data.status;\n port.postMessage({ configurationName });\n return;\n\n case 'init': {\n const oidcServerConfiguration = data.data.oidcServerConfiguration;\n const domains = getDomains(trustedDomain, 'oidc');\n\n if (!domains.some(domain => domain === acceptAnyDomainToken)) {\n [\n oidcServerConfiguration.tokenEndpoint,\n oidcServerConfiguration.revocationEndpoint,\n oidcServerConfiguration.userInfoEndpoint,\n oidcServerConfiguration.issuer,\n ].forEach(u => {\n checkDomain(domains, u);\n });\n }\n\n currentDatabase.oidcServerConfiguration = oidcServerConfiguration;\n currentDatabase.oidcConfiguration = data.data.oidcConfiguration;\n\n if (currentDatabase.demonstratingProofOfPossessionConfiguration == null) {\n const demonstratingProofOfPossessionConfiguration = getDpopConfiguration(trustedDomain);\n if (demonstratingProofOfPossessionConfiguration != null) {\n if (currentDatabase.oidcConfiguration.demonstrating_proof_of_possession) {\n console.warn(\n 'In service worker, demonstrating_proof_of_possession must be configured from trustedDomains file',\n );\n }\n currentDatabase.demonstratingProofOfPossessionConfiguration =\n demonstratingProofOfPossessionConfiguration;\n currentDatabase.demonstratingProofOfPossessionJwkJson = await generateJwkAsync(self)(\n demonstratingProofOfPossessionConfiguration.generateKeyAlgorithm,\n );\n currentDatabase.demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent =\n getDpopOnlyWhenDpopHeaderPresent(trustedDomain) ?? false;\n }\n }\n\n if (!currentDatabase.tokens) {\n port.postMessage({\n tokens: null,\n status: currentDatabase.status,\n configurationName,\n version,\n });\n } else {\n const tokens = { ...currentDatabase.tokens };\n if (currentDatabase.hideAccessToken) {\n tokens.access_token = `${TOKEN.ACCESS_TOKEN}_${configurationName}#tabId=${tabId}`;\n }\n if (tokens.refresh_token) {\n tokens.refresh_token = `${TOKEN.REFRESH_TOKEN}_${configurationName}#tabId=${tabId}`;\n }\n if (tokens?.idTokenPayload?.nonce && currentDatabase.nonce != null) {\n tokens.idTokenPayload.nonce = `${TOKEN.NONCE_TOKEN}_${configurationName}#tabId=${tabId}`;\n }\n port.postMessage({\n tokens,\n status: currentDatabase.status,\n configurationName,\n version,\n });\n }\n return;\n }\n\n case 'setDemonstratingProofOfPossessionNonce': {\n currentDatabase.demonstratingProofOfPossessionNonce =\n data.data.demonstratingProofOfPossessionNonce;\n port.postMessage({ configurationName });\n return;\n }\n\n case 'getDemonstratingProofOfPossessionNonce': {\n const demonstratingProofOfPossessionNonce =\n currentDatabase.demonstratingProofOfPossessionNonce;\n port.postMessage({\n configurationName,\n demonstratingProofOfPossessionNonce,\n });\n return;\n }\n\n case 'setState': {\n currentDatabase.state = data.data.state;\n port.postMessage({ configurationName });\n return;\n }\n\n case 'getState': {\n const state = currentDatabase.state;\n port.postMessage({ configurationName, state });\n return;\n }\n\n case 'setCodeVerifier': {\n currentDatabase.codeVerifier = data.data.codeVerifier;\n port.postMessage({ configurationName });\n return;\n }\n\n case 'getCodeVerifier': {\n const codeVerifier =\n currentDatabase.codeVerifier != null\n ? `${TOKEN.CODE_VERIFIER}_${configurationName}#tabId=${tabId}`\n : null;\n port.postMessage({\n configurationName,\n codeVerifier,\n });\n return;\n }\n\n case 'setSessionState': {\n currentDatabase.sessionState = data.data.sessionState;\n port.postMessage({ configurationName });\n return;\n }\n\n case 'getSessionState': {\n const sessionState = currentDatabase.sessionState;\n port.postMessage({ configurationName, sessionState });\n return;\n }\n\n case 'setNonce': {\n const nonce = data.data.nonce;\n if (nonce) {\n currentDatabase.nonce = nonce;\n }\n port.postMessage({ configurationName });\n return;\n }\n\n case 'getNonce': {\n const keyNonce = `${TOKEN.NONCE_TOKEN}_${configurationName}#tabId=${tabId}`;\n const nonce = currentDatabase.nonce ? keyNonce : null;\n port.postMessage({ configurationName, nonce });\n return;\n }\n\n default:\n return;\n }\n};\n\n// Event listeners\n_self.addEventListener('fetch', handleFetch);\n_self.addEventListener('message', handleMessage);\n"],"mappings":";AAAA,IAAM,iBAAiB;AAUvB,IAAM,QAAmB;CACvB,eAAe;CACf,cAAc;CACd,aAAa;CACb,eAAe;AACjB;AAQA,IAAM,iBAAqC;CACzC,kCAAkC;CAClC,sBAAsB;CACtB,kBAAkB;AACpB;;;ACnBA,SAAS,WAAW,KAAa;CAC/B,OAAO,IAAI,YAAY,CAAC,CAAC,OAAO,GAAG;AACrC;AAMA,SAAS,eAAe,KAAK;CAC3B,OAAO,KAAK,GAAG,CAAC,CAAC,QAAQ,OAAO,GAAG,CAAC,CAAC,QAAQ,OAAO,GAAG,CAAC,CAAC,QAAQ,OAAO,EAAE;AAC5E;AAOA,SAAS,mBAAmB,KAAK;CAK/B,OAJe,mBAAmB,GAI3B,CAAA,CAAO,QAAQ,mBAAmB,SAAU,OAAe,IAAI;EACpE,OAAO,OAAO,aAAa,SAAS,IAAI,EAAE,CAAC;CAC7C,CAAC;AACH;AAMA,IAAa,oBAAoB,UAAsB;CACrD,IAAI,MAAM;CAEV,MAAM,QAAQ,SAAU,MAAM;EAC5B,OAAO,OAAO,aAAa,IAAI;CACjC,CAAC;CACD,OAAO,eAAe,GAAG;AAC3B;AAMA,SAAS,eAAe,KAAK;CAC3B,OAAO,eAAe,mBAAmB,GAAG,CAAC;AAC/C;AAEA,IAAa,qDACX;CACE,oBAAoB;EAClB,MAAM;EACN,YAAY;EACZ,MAAM,EAAE,MAAM,QAAQ;CACxB;CACA,eAAe;EAAE,MAAM;EAAS,MAAM,EAAE,MAAM,UAAU;CAAE;CAC1D,sBAAsB;EACpB,MAAM;EACN,YAAY;CACd;CACA,iBAAiB,EAAE,MAAM,UAAU;CACnC,oBAAoB;AACtB;AAGF,IAAM,QACH,MACD,OACE,KACA,SACA,QACA,6CACA,gBAAgB,eACb;CAGH,MAAM,OAAO,OAAO,CAAC,GAAG,GAAG;CAG3B,QAAQ,MAAM;CACd,QAAQ,MAAM,4CAA4C;CAC1D,QAAQ,QAAQ,KAAhB;EACE,KAAK;GAEH,QAAQ,MAAM;IAAE,KAAK,IAAI;IAAK,KAAK,IAAI;IAAK,GAAG,IAAI;IAAG,GAAG,IAAI;GAAE;GAE/D;EACF,KAAK;GACH,QAAQ,MAAM;IAAE,KAAK,IAAI;IAAK,GAAG,IAAI;IAAG,GAAG,IAAI;IAAG,KAAK,QAAQ;GAAI;GACnE;EACF,SACE,MAAM,IAAI,MAAM,0CAA0C;CAC9D;CAEA,MAAM,MAAM;EAGV,WAAW,eAAe,KAAK,UAAU,OAAO,CAAC;EAGjD,SAAS,eAAe,KAAK,UAAU,MAAM,CAAC;CAChD;CAGA,MAAM,UAAU,4CAA4C;CAU5D,MAAM,aAAa,MAAM,EAAE,OAAO,OAAO,UAAU,OAAO,KAAK,SAAS,MAAY,CAJhE,MAIgE,CAAU;CAG9F,MAAM,OAAO,WAAW,GAAG,IAAI,UAAU,GAAG,IAAI,SAAS;CAIzD,MAAM,gBAAgB,4CAA4C;CAElE,MAAM,YAAY,MAAM,EAAE,OAAO,OAAO,KAAK,eAAe,YAAY,IAAI;CAI5E,IAAI,YAAY,iBAAiB,IAAI,WAAW,SAAS,CAAC;CAG1D,OAAO,GAAG,IAAI,UAAU,GAAG,IAAI,QAAQ,GAAG,IAAI;AAChD;AAEF,IAAa,MAAM,EAAE,KAAK;AAG1B,IAAM,YACH,MAAW,OAAO,yBAAiE;CAClF,MAAM,UAAU;CAIhB,MAAM,MAAM,MAAM,EAAE,OAAO,OAAO,YAAY,SAAS,MAAY,CAF/C,QAAQ,QAEuC,CAAU;CAG7E,OAAO,MAAM,EAAE,OAAO,OAAO,UAAU,OAAO,IAAI,UAAU;AAC9D;AAMF,IAAM,UAAS,QAAO;CACpB,MAAM,OAAO,OAAO,OAAO,CAAC,GAAG,GAAG;CAClC,OAAO,KAAK;CACZ,KAAK,UAAU,CAAC,QAAQ;CACxB,OAAO;AACT;AAEA,IAAM,KAAK;CACT;CACA;AACF;AAEA,IAAM,cAAc,MAAW,OAAO,KAAK,oBAAyC;CAClF,IAAI;CAEJ,QAAQ,IAAI,KAAZ;EACE,KAAK;GACH,YAAY,2DACT,QAAQ,OAAO,IAAI,GAAG,CAAC,CACvB,QAAQ,KAAK,IAAI,CAAC,CAAC,CACnB,QAAQ,KAAK,IAAI,CAAC;GACrB;EACF,KAAK;GACH,YAAY,4CAAgC,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,QAAQ,KAAK,IAAI,CAAC;GAClF;EACF,SACE,MAAM,IAAI,MAAM,qCAAqC;CACzD;CAGA,MAAM,OAAO,MAAM,EAAE,OAAO,OAAO,OAAO,iBAAiB,WAAW,SAAS,CAAC;CAChF,OAAO,iBAAiB,IAAI,WAAW,IAAI,CAAC;AAC9C;AAEA,IAAa,MAAM,EAAE,WAAW;AAEhC,IAAa,oBACV,MAAW,OAAO,yBAAiE;CAMlF,OAAO,MAJW,GAAG,SAAS,CAAC,CAAC,CAAC,oBAAoB;AAKvD;AAEF,IAAa,kDACV,OACA,gDACD,OAAO,KAAU,SAAS,QAAQ,KAAa,eAAe,CAAC,MAAM;CACnE,MAAM,SAAS;EAEb,KAAK,KAAK,EAAE,OAAO,WAAW,CAAC;EAC/B,KAAK;EACL,KAAK;EACL,KAAK,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;EACjC,GAAG;CACL;CAEA,MAAM,MAAM,MAAM,IAAI,WAAW,CAAC,CAAC,CACjC,KACA,4CAA4C,eAC9C;CASA,OAAO,MAPW,IAAI,KAAK,CAAC,CAAC,CAC3B,KACA,EAAO,IAAI,GACX,QACA,2CACF;AAGF;;;ACtOF,SAAgB,eAAe,KAAa;CAC1C,MAAM,MAAM,IAAI,YAAY,IAAI,MAAM;CACtC,MAAM,UAAU,IAAI,WAAW,GAAG;CAElC,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,KAC9B,QAAQ,KAAK,IAAI,WAAW,CAAC;CAE/B,OAAO;AACT;AAEA,SAAgB,oCAAoC,MAA+B;CACjF,OAAO,IAAI,SAAS,SAAS,WAAW;EACtC,OAAO,OAAO,OAAO,WAAW,eAAe,IAAI,CAAC,CAAC,CAAC,MACpD,WAAU;GACR,OAAO,QAAQ,iBAAiB,IAAI,WAAW,MAAM,CAAC,CAAC;EACzD,IACA,UAAS,OAAO,KAAK,CACvB;CACF,CAAC;AACH;;;AClBA,IAAM,UAAU,kBAAqD;CACnE,IAAI,MAAM,QAAQ,aAAa,GAC7B,OAAO;CAET,OAAO,cAAc,kCAAkC;AACzD;AAEA,IAAa,wBAAwB,kBAA4C;CAC/E,IAAI,CAAC,OAAO,aAAa,GACvB,OAAO;CAGT,IAAI,MAAM,QAAQ,aAAa,GAC7B,OAAO;CAGT,OACE,cAAc,+CACd;AAEJ;AAEA,IAAa,oCAAoC,kBAA4C;CAC3F,IAAI,CAAC,OAAO,aAAa,GACvB,OAAO;CAGT,IAAI,MAAM,QAAQ,aAAa,GAC7B,OAAO;CAGT,OAAO,cAAc,2DAA2D;AAClF;;;ACnCA,SAAgB,aAAa,KAAa;CACxC,IAAI;EACF,OAAO,IAAI,IAAI,GAAG,CAAC,CAAC,SAAS;CAC/B,SAAS,OAAO;EACd,QAAQ,MAAM,4BAA4B,OAAO,KAAK;EACtD,OAAO;CACT;AACF;;;ACHA,SAAgB,YAAY,SAAmB,UAAkB;CAC/D,IAAI,CAAC,UACH;CAcF,IAAI,CAXW,QAAQ,MAAK,WAAU;EACpC,IAAI;EAEJ,IAAI,OAAO,WAAW,UACpB,WAAW,IAAI,OAAO,IAAI,QAAQ;OAElC,WAAW;EAGb,OAAO,SAAS,OAAO,QAAQ;CACjC,CACK,GACH,MAAM,IAAI,MACR,YAAY,WAAW,2CAA2C,cACpE;AAEJ;AAEA,IAAa,cACX,eACA,SACG;CACH,IAAI,MAAM,QAAQ,aAAa,GAC7B,OAAO;CAGT,OAAO,cAAc,GAAG,KAAK,aAAa,cAAc,WAAW,CAAC;AACtE;AAEA,IAAa,4BACX,UACA,KACA,mBACG;CACH,IAAI,IAAI,SAAA,mCAAkC,GACxC,OAAO;CAET,MAAM,YAAY,CAAC;CACnB,KAAK,MAAM,CAAC,KAAK,oBAAoB,OAAO,QAAoB,QAAQ,GAAG;EACzE,MAAM,0BAA0B,gBAAgB;EAEhD,IAAI,CAAC,yBACH;EAGF,IACE,wBAAwB,iBACxB,QAAQ,aAAa,wBAAwB,aAAa,GAE1D;EAEF,IACE,wBAAwB,sBACxB,QAAQ,aAAa,wBAAwB,kBAAkB,GAE/D;EAIF,MAAM,UAAU,WAFM,kBAAkB,OAAO,CAAC,IAAI,eAAe,IAAI,MAAM,GAAG,CAAC,CAAC,KAExC,aAAa;EACvD,MAAM,sBAAsB,wBAAwB,mBAChD,CAAC,aAAa,wBAAwB,gBAAgB,GAAG,GAAG,OAAO,IACnE,CAAC,GAAG,OAAO;EAEf,IAAI,iBAAiB;EACrB,IAAI,oBAAoB,MAAK,MAAK,MAAA,GAA0B,GAC1D,iBAAiB;OAEjB,KAAK,IAAI,IAAI,GAAG,IAAI,oBAAoB,QAAQ,KAAK;GACnD,IAAI,SAAS,oBAAoB;GAEjC,IAAI,OAAO,WAAW,UACpB,SAAS,IAAI,OAAO,IAAI,QAAQ;GAGlC,IAAI,OAAO,OAAO,GAAG,GAAG;IACtB,iBAAiB;IACjB;GACF;EACF;EAGF,IAAI,gBACE;OAAA,gBAAgB,QAClB,UAAU,KAAK,eAAe;EAAA;CAGpC;CACA,OAAO;AACT;;;AClGA,SAAS,iBAAiB,SAA0C;CAClE,MAAM,aAAqC,CAAC;CAC5C,KAAK,MAAM,OAAO,QAAQ,KAAK,GAAG;EAChC,MAAM,QAAQ,QAAQ,IAAI,GAAG;EAC7B,IAAI,UAAU,MACZ,WAAW,OAAO;CAEtB;CACA,OAAO;AACT;;;ACTA,IAAM,uBAAuB;CAAC;CAAS;CAAQ;CAAS;CAAY;CAAU;AAAQ;;;;;;AAOtF,IAAa,2BAA2B,aAAqB,SAA0B;CACrF,OAAO,qBAAqB,SAAS,WAAW,KAAK,SAAS;AAChE;;;ACTA,IAAM,SAAS,OAAe,IAAI,SAAQ,YAAW,WAAW,SAAS,EAAE,CAAC;;;ACW5E,IAAa,YAAY,YAAoB;CAC3C,OAAO,KAAK,MAAM,iBAAiB,QAAQ,WAAW,MAAM,GAAG,CAAC,CAAC,WAAW,MAAM,GAAG,CAAC,CAAC;AACzF;AACA,SAAS,iBAAiB,KAAa;CACrC,OAAO,mBACL,MAAM,UAAU,IACb,KAAK,KAAK,GAAG,IAAG,MAAK,OAAO,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,SAAS,EAAE,EAAA,CAAG,MAAM,EAAE,CAAC,CAAC,CAC3E,KAAK,EAAE,CACZ;AACF;AAEA,SAAS,gBAAgB,2CAAmD,WAAmB;CAC7F,MAAM,yCAAwB,IAAI,KAAK,EAAA,CAAE,QAAQ,IAAI;CACrD,OAAO,KAAK,MAAM,YAAY,4CAA4C,qBAAqB;AACjG;AAEA,SAAS,cAAc,QAAuB;CAC5C,IAAI,CAAC,QACH,OAAO;CAET,OAAO,gBAAgB,GAAG,OAAO,SAAS,IAAI;AAChD;AAEA,IAAM,uBAAuB,UAAmB;CAC9C,IAAI;EACF,IAAI,CAAC,OACH,OAAO;EAET,MAAM,QAAQ,MAAM,MAAM,GAAG;EAC7B,OAAO,MAAM,WAAW,IAAI,SAAS,MAAM,EAAE,IAAI;CACnD,SAAS,GAAG;EACV,QAAQ,KAAK,CAAC;CAChB;CACA,OAAO;AACT;AAIA,IAAM,qBACJ,QACA,OACA,4BACyC;CACzC,IAAI,OAAO,gBAAgB;EACzB,MAAM,iBAAiB,OAAO;EAE9B,IAAI,kBAAkB,wBAAwB,WAAW,eAAe,KACtE,OAAO;GACL,SAAS;GACT,QAAQ,0DAA0D,wBAAwB,OAAO,+BAA+B,eAAe;EACjJ;EAOF,MAAM,yCAAwB,IAAI,KAAK,EAAA,CAAE,QAAQ,IAAI;EACrD,IAAI,kBAAkB,eAAe,OAAO,eAAe,MAAM,uBAC/D,OAAO;GACL,SAAS;GACT,QAAQ,yCAAyC,eAAe,IAAI,6BAA6B;EACnG;EAGF,MAAM,kBAAkB;EACxB,IACE,kBACA,eAAe,OACf,eAAe,MAAM,kBAAkB,uBAEvC,OAAO;GACL,SAAS;GACT,QAAQ,2EAA2E,eAAe,MAAM,gBAAgB,6BAA6B;EACvJ;EAGF,IAAI,kBAAkB,SAAS,eAAe,SAAS,eAAe,UAAU,OAC9E,OAAO;GACL,SAAS;GACT,QAAQ,gCAAgC,MAAM,8BAA8B,eAAe;EAC7F;CAEJ;CACA,OAAO;EAAE,SAAS;EAAM,QAAQ;CAAG;AACrC;AAEA,SAAS,iBACP,QACA,oBACA,iBACA;CACA,IAAI,CAAC,OAAO,WAAW;EACrB,IAAI,sBAAsB,mBAAmB,KAC3C,OAAO,mBAAmB;OACrB,IAAI,mBAAmB,gBAAgB,KAC5C,OAAO,gBAAgB;OAGvB,wBAD8B,IAAI,KAAK,EAAA,CAAE,QAAQ,IAAI;CAGzD,OAAO,IAAI,OAAO,OAAO,aAAa,UACpC,OAAO,SAAS,OAAO,WAAW,EAAE;CAEtC,OAAO,OAAO;AAChB;AAEA,SAAS,YACP,QACA,wBACA,mBACA;CACA,IAAI,CAAC,OAAO,WAEV,OAAO,6BADuB,IAAI,KAAK,EAAA,CAAE,QAAQ,IAAI;MAEhD,IAAI,OAAO,OAAO,aAAa,UACpC,OAAO,YAAY,SAAS,OAAO,WAAW,EAAE;CAGlD,MAAM,qBAAqB,oBAAoB,OAAO,YAAY;CAClE,MAAM,eAAe;EACnB,GAAG;EACH;CACF;CACA,IAAI,uBAAuB,iBACzB,aAAa,eAAe,GAAG,MAAM,aAAa,GAAG;CAEvD,OAAO,qBAAqB;CAG5B,MAAM,YAAY,uBAAuB;CACzC,IAAI;CACJ,IAAI,aAAa,QAAQ,cAAc,aAAa,EAAE,cAAc,SAClE,WAAW,UAAU;MAErB,WAAW,OAAO;CAEpB,OAAO,WAAW;CAElB,IAAI,kBAAkB;CACtB,IAAI,UAAU;EACZ,kBAAkB,oBAAoB,QAAQ;EAC9C,OAAO,iBAAiB,mBAAmB,OAAO,EAAE,GAAG,gBAAgB,IAAI;EAC3E,IAAI,mBAAmB,gBAAgB,SAAS,uBAAuB,SAAS,MAAM;GACpF,MAAM,WAAW,GAAG,MAAM,YAAY,GAAG,uBAAuB;GAChE,gBAAgB,QAAQ;EAC1B;EACA,aAAa,iBAAiB;CAChC;CACA,IAAI,OAAO,eACT,aAAa,gBAAgB,GAAG,MAAM,cAAc,GAAG;CAGzD,OAAO,YAAY,iBAAiB,QAAQ,oBAAoB,eAAe;CAE/E,MAAM,WACJ,OAAO,OAAO,cAAc,WAAW,SAAS,OAAO,YAAY,EAAE,IAAI,OAAO;CAElF,MAAM,mBACJ,mBAAmB,gBAAgB,MAAM,gBAAgB,MAAM,OAAO;CACxE,MAAM,uBACJ,sBAAsB,mBAAmB,MACrC,mBAAmB,MACnB,OAAO,YAAY;CAEzB,IAAI;CACJ,MAAM,iBAAkB,uBAAuB,kBAC5C;CACH,IAAI,mBAAmB,eAAe,sBACpC,YAAY;MACP,IAAI,mBAAmB,eAAe,kBAC3C,YAAY;MAEZ,YAAY,mBAAmB,uBAAuB,mBAAmB;CAE3E,aAAa,YAAY;CAEzB,OAAO,YAAY;CAEnB,MAAM,EAAE,SAAS,WAAW,kBAC1B,QAFY,uBAAuB,QAAQ,uBAAuB,MAAM,QAAQ,MAIhF,uBAAuB,uBACzB;CACA,IAAI,CAAC,SACH,MAAM,MAAM,wCAAwC,QAAQ;CAI9D,IAAI,aAAa,QAAQ,mBAAmB,aAAa,EAAE,mBAAmB,SAAS;EACrF,MAAM,eAAe,UAAU;EAE/B,uBAAuB,SAAS;GAC9B,GAAG;GACH,eAAe;EACjB;CACF,OACE,uBAAuB,SAAS;CAGlC,uBAAuB,SAAS;CAChC,OAAO;AACT;AAEA,IAAM,oDAAoD;AAC1D,SAAS,WAAW,wBAAoC;CACtD,MAAM,oBAAoB,uBAAuB;CACjD,QAAQ,aAAuB;EAC7B,IAAI,SAAS,WAAW,KACtB,OAAO;EAET,MAAM,aAAa,IAAI,QAAQ,SAAS,OAAO;EAC/C,IAAI,SAAS,QAAQ,IAAI,iDAAiD,GAAG;GAC3E,uBAAuB,sCAAsC,SAAS,QAAQ,IAC5E,iDACF;GACA,WAAW,OAAO,iDAAiD;EACrE;EAEA,OAAO,SAAS,KAAK,CAAC,CAAC,MAAgB,WAAmB;GACxD,MAAM,eAAe,YAAY,QAAQ,wBAAwB,iBAAiB;GAClF,MAAM,OAAO,KAAK,UAAU,YAAY;GACxC,OAAO,IAAI,SAAS,MAAM;IACxB,QAAQ,SAAS;IACjB,YAAY,SAAS;IACrB,SAAS;GACX,CAAC;EACH,CAAC;CACH;AACF;;;AC5OA,IAAa,2BAA2B;;;;;;;AASxC,eAAsB,mBACpB,QACA,YAAY,0BACZ,iBAAA,KAC0B;CAC1B,MAAM,YAAY,KAAK,IAAI;CAC3B,OAAO,OAAO,UAAU,CAAC,cAAc,OAAO,MAAM,GAAG;EACrD,IAAI,KAAK,IAAI,IAAI,aAAa,WAC5B,OAAO,IAAI,SAAS,MAAM;GACxB,QAAQ;GACR,YAAY;EACd,CAAC;EAEH,MAAM,MAAM,cAAc;CAC5B;CAEA,IAAI,CAAC,OAAO,QAAQ,cAClB,OAAO,IAAI,SAAS,MAAM;EACxB,QAAQ;EACR,YAAY;CACd,CAAC;CAGH,OAAO;AACT;;;ACjCA,IAAM,qBAAqB,4BAA+D;CACxF,OAAO;EACL,wBAAwB;EACxB,wBAAwB;EACxB,wBAAwB;EACxB,wBAAwB;EACxB,wBAAwB;CAC1B,CAAC,CACE,OAAO,OAAO,CAAC,CACf,IAAI,YAAY;AACrB;AAEA,IAAM,uBAAuB,UAAoB,kBAAmC;CAClF,OAAO,OAAO,OAAO,QAAQ,CAAC,CAAC,MAAK,WAAU;EAC5C,MAAM,EAAE,4BAA4B,UAAU,CAAC;EAC/C,IAAI,CAAC,yBACH,OAAO;EAGT,OAAO,kBAAkB,uBAAuB,CAAC,CAAC,MAAK,YACrD,cAAc,WAAW,OAAO,CAClC;CACF,CAAC;AACH;AAEA,IAAM,uBAAuB,QAAgB,kBAAmC;CAC9E,IAAI,OAAO,WAAW,UACpB,SAAS,IAAI,OAAO,IAAI,QAAQ;CAGlC,OAAO,OAAO,OAAO,aAAa,KAAK;AACzC;AAEA,IAAM,8BACJ,UACA,eACA,mBACY;CACZ,OAAO,OAAO,QAAQ,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,qBAAqB;EAC/D,IAAI,CAAC,gBAAgB,yBACnB,OAAO;EAIT,MAAM,UAAU,WADM,iBAAiB,IAAI,MAAM,GAAG,CAAC,CAAC,OAAO,CAAC,GACpB,aAAa;EAEvD,IAAI,QAAQ,MAAK,WAAU,WAAA,GAA+B,GACxD,OAAO;EAGT,OAAO,QAAQ,MAAK,WAAU,oBAAoB,QAAQ,aAAa,CAAC;CAC1E,CAAC;AACH;AAEA,IAAM,8BACJ,UACA,eACA,mBACY;CACZ,MAAM,iBAAiB,OAAO,OAAO,QAAQ;CAE7C,IAAI,eAAe,WAAW,GAC5B,OAAO;CAGT,IAAI,CAAC,eAAe,OAAM,WAAU,OAAO,wBAAwB,GACjE,OAAO;CAGT,IAAI,CAAC,eAAe,OAAM,WAAU,OAAO,2BAA2B,IAAI,GACxE,OAAO;CAGT,OACE,CAAC,oBAAoB,UAAU,aAAa,KAC5C,CAAC,2BAA2B,UAAU,eAAe,cAAc;AAEvE;AAEA,IAAM,iCAAiC,UAAoB,QAA8B;CACvF,MAAM,gBAAgB,aAAa,GAAG;CACtC,OAAO,OAAO,OAAO,QAAQ,CAAC,CAAC,QAAO,WAAU;EAC9C,MAAM,EAAE,4BAA4B,UAAU,CAAC;EAC/C,MAAM,EAAE,eAAe,uBAAuB,2BAA2B,CAAC;EAE1E,OACG,iBAAiB,cAAc,WAAW,aAAa,aAAa,CAAC,KACrE,sBAAsB,cAAc,WAAW,aAAa,kBAAkB,CAAC;CAEpF,CAAC;AACH;;;AC9FA,SAAgB,oBAAoB,cAAsB,iBAAiC;CAEzF,OAAO,aAAa,QAAQ,8BAAO,kBAAkB,iBAAiB;AACxE;AAEA,IAAa,4CAA4C,SAAyB;CAEhF,MAAM,QAAQ,KAAK,MAAM,wEAAK;CAE9B,OAAO,QAAQ,mBAAmB,MAAM,EAAE,IAAI;AAChD;;;ACVA,IAAA,kBAAe;;;ACwBf,IAAI,OAAO,iBAAiB,eAAe,OAAO,aAAa,iBAAiB,YAE9E,aAAa,aAAa,WAAW,EACnC,iBAAiB,SAAU,KAAa;CACtC,IAAI,QAAA,yBACF,OAAO;MAEP,MAAM,IAAI,MAAM,mCAAmC,GAAG;AAE1D,EACF,CAAC;AAGH,IAAM,QAAQ;AAKd,MAAM,cAAc,cAAc;AAElC,IAAM,KAAK,KAAK,uBAAM,IAAI,KAAK,EAAA,CAAE,QAAQ,IAAI,GAAI,CAAC,CAAC,SAAS;AAC5D,QAAQ,IAAI,+BAA+B,EAAE;AAC7C,IAAM,wBAAwB;AAC9B,IAAM,WAAqB,CAAC;;;;AAK5B,IAAM,iBAAiB,OAAO,UAAsB;CAClD,MAAM,kBAAkB,MAAM;CAC9B,MAAM,gBAAgB,gBAAgB,QAAQ,IAAI,cAAc;CAEhE,MAAM,WAAW,IAAI,SAAS,MAAM;EADrB,QAAQ;EAAK,YAAY;CACJ,CAAI;CAExC,IAAI,CAAC,eAAe;EAClB,MAAM,qBAAqB,IAAI,IAAI,gBAAgB,GAAG;EACtD,MAAM,kBAAkB,OAAO,mBAAmB,aAAa,IAAI,iBAAiB,CAAC,KAAK;EAC1F,KAAK,IAAI,IAAI,GAAG,IAAI,iBAAiB,KAAK;GACxC,MAAM,MAAM,MAAO,KAAK,MAAM,KAAK,OAAO,IAAI,GAAI,CAAC;GAEnD,OAAM,MADc,OAAO,KAAK,kBAAkB,EAAA,CACtC,IAAI,MAAM,SAAS,SAAS,MAAM,CAAC;EACjD;CACF;CACA,OAAO;AACT;;;;AAKA,eAAe,kBACb,iBACA,iBACA,KACA,eAAe,CAAC,GAChB;CACA,MAAM,gBAAgB,iBAAiB,gBAAgB,OAAO;CAC9D,IACE,iBAAiB,+CACjB,gBAAgB,0CACf,CAAC,gBAAgB,2DACf,gBAAgB,2DACf,cAAc,OAClB;EACA,MAAM,oBAAoB,gBAAgB;EAC1C,MAAM,MAAM,gBAAgB;EAC5B,MAAM,SAAS,gBAAgB;EAQ/B,cAAc,OAAO,MAPF,+CAA+C,IAAI,CAAC,CAAC,iBAAiB,CAAC,CACxF,KACA,QACA,KACA,YACF;EAGA,IAAI,gBAAgB,uCAAuC,MACzD,cAAc,QAAQ,gBAAgB;CAE1C;CACA,OAAO;AACT;;;;AAKA,IAAM,eAAe,UAA4B;;;;CAI/C,IAAI,wBAAwB,MAAM,QAAQ,aAAa,MAAM,QAAQ,IAAI,GACvE;CAGF,MAAM,gBAAgB,aAAa,MAAM,QAAQ,GAAG;CACpD,IACE,CAAC,cAAc,SAAS,qBAAqB,KAC7C,2BAA2B,UAAU,eAAe,cAAc,GAElE;CAGF,MAAM,aACH,YAA+B;EAC9B,IAAI;GACF,MAAM,kBAAkB,MAAM;GAC9B,MAAM,MAAM;GAGZ,IAAI,IAAI,SAAS,qBAAqB,GACpC,OAAO,eAAe,KAAK;GAI7B,MAAM,wCAAwC,yBAC5C,UACA,KACA,cACF;GAEA,MAAM,gBAAgB,gBAAgB,QAAQ,IAAI,eAAe;GACjE,IAAI,qBAAqB;GACzB,IAAI,MAAM;GAEV,IAAI,eAAe;IACjB,MAAM,QAAQ,cAAc,MAAM,GAAG;IACrC,qBAAqB,MAAM;IAC3B,IAAI,MAAM,EAAE,EAAE,SAAS,8CAA8C,GACnE,MAAM,MAAM,EAAE,CAAC,MAAM,8CAA8C,CAAC,CAAC;GAEzE;GAEA,MAAM,uCAAuC,uCAAuC,MAClF,MAAK,EAAE,kBAAkB,SAAS,GAAG,CACvC;GAGA,IAAI,sCAAsC,QAAQ,cAAc;IAE9D,MAAM,aAAa,MAAM,mBAAmB,oCAAoC;IAChF,IAAI,YACF,OAAO;IAIT,IAAI,cAAc,gBAAgB;IAClC,IACE,gBAAgB,SAAS,cACzB,qCAAqC,wCAErC,cAAc;IAIhB,IAAI;IAGJ,IACE,gBAAgB,SAAS,cACzB,CAAC,qCAAqC,kCAEtC,UAAU,EACR,GAAG,iBAAiB,gBAAgB,OAAO,EAC7C;SAEA,IACE,mBAAmB,YAAY,MAAM,UACpC,CAAC,qCAAqC,2DACrC,qCAAqC,6CAcvC,UAAU;KACR,GAAG,MAPqB,kBACxB,iBACA,sCACA,KACA,EARA,KAAK,MAAM,oCACT,qCAAqC,OAAO,YAC9C,EAMA,CACF;KAGE,eAAe,QAAQ,qCAAqC,OAAO;IACrE;SAGA,UAAU;KACR,GAAG,iBAAiB,gBAAgB,OAAO;KAC3C,eAAe,GAAG,mBAAmB,GAAG,qCAAqC,OAAO;IACtF;IAIJ,IAAI;IACJ,IAAI,gBAAgB,SAAS,YAC3B,OAAO,EACI,QACX;SAEA,OAAO;KACI;KACT,MAAM;IACR;IAGF,MAAM,aAAa,IAAI,QAAQ,iBAAiB,IAAI;IACpD,OAAO,MAAM,UAAU;GACzB;GAGA,IAAI,MAAM,QAAQ,WAAW,QAC3B,OAAO,MAAM,eAAe;GAI9B,MAAM,mBAAmB,8BAAiC,UAAU,GAAG;GACvE,MAAM,iBAAiB,iBAAiB;GAExC,IAAI,iBAAiB,GAqJnB,OAAO,IApJqB,SAAmB,SAAS,WAAW;IACjE,MAAM,gBAAgB,gBAAgB,MAAM;IAC5C,cACG,KAAK,CAAC,CACN,KAAK,OAAM,eAAc;KACxB,IAAI,kBAAqC;KACzC,IAAI;MAEF,IACE,WAAW,SAAS,MAAM,aAAa,KACvC,WAAW,SAAS,MAAM,YAAY,GACtC;OACA,IAAI,UAAU,iBAAiB,gBAAgB,OAAO;OACtD,IAAI,UAAU;OAEd,KAAK,IAAI,IAAI,GAAG,IAAI,gBAAgB,KAAK;QACvC,MAAM,YAAY,iBAAiB;QACnC,IAAI,WAAW,QAAQ;SACrB,MAAM,eAAe,EACnB,KAAK,MAAM,oCACT,UAAU,OAAO,YACnB,EACF;SACA,UAAU,MAAM,kBACd,iBACA,WACA,KACA,YACF;SAEA,MAAM,kBAAkB,mBACtB,GAAG,MAAM,cAAc,GAAG,UAAU,mBACtC;SACA,IAAI,WAAW,SAAS,eAAe,GAAG;UACxC,UAAU,QAAQ,QAChB,iBACA,mBAAmB,UAAU,OAAO,aAAuB,CAC7D;UACA,kBAAkB;UAClB;SACF;SAEA,MAAM,iBAAiB,mBACrB,GAAG,MAAM,aAAa,GAAG,UAAU,mBACrC;SACA,IAAI,WAAW,SAAS,cAAc,GAAG;UACvC,UAAU,QAAQ,QAChB,gBACA,mBAAmB,UAAU,OAAO,YAAY,CAClD;UACA,kBAAkB;UAClB;SACF;QACF;OACF;OAEA,MAAM,eAAe,MAAM,iBAAiB;QAC1C,MAAM;QACN,QAAQ,cAAc;QACtB;QACA,MAAM,cAAc;QACpB,OAAO,cAAc;QACrB,UAAU,cAAc;QACxB,UAAU,cAAc;QACxB,aAAa,cAAc;QAC3B,WAAW,cAAc;OAC3B,CAAC;OAGD,IACE,iBAAiB,yBAAyB,sBAC1C,IAAI,WACF,aAAa,gBAAgB,wBAAwB,kBAAkB,CACzE,GACA;QACA,MAAM,OAAO,MAAM;QACnB,MAAM,MAAM,MAAM,KAAK,KAAK;QAC5B,QAAQ,IAAI,SAAS,KAAK,IAAI,CAAC;QAC/B;OACF;OAMA,QAAQ,MAHa,aAAa,KAChC,WAAW,eAA6B,CAC1C,CACc;OACd;MACF;MAIA,IADuB,WAAW,SAAS,gBACvC,GAAgB;OAClB,MAAM,wCACJ,yCAAyC,UAAU;OACrD,IACE,CAAC,yCACD,0CAA0C,IAE1C,MAAM,IAAI,MAAM,8CAA8C;OAEhE,kBAAkB,SAAS;OAC3B,IAAI,UAAU;OACd,MAAM,eAAe,gBAAgB;OACrC,IAAI,gBAAgB,MAClB,UAAU,oBAAoB,SAAS,YAAY;OAGrD,MAAM,gBAAgB,MAAM,kBAC1B,iBACA,iBACA,GACF;OACA,MAAM,OAAO,MAAM,MAAM,iBAAiB;QACxC,MAAM;QACN,QAAQ,cAAc;QACtB,SAAS;QACT,MAAM,cAAc;QACpB,OAAO,cAAc;QACrB,UAAU,cAAc;QACxB,UAAU,cAAc;QACxB,aAAa,cAAc;QAC3B,WAAW,cAAc;OAC3B,CAAC;OAED,QAAQ,MADa,WAAW,eAAe,CAAC,CAAC,IAAI,CACvC;OACd;MACF;MAcA,QAAQ,MAXiB,MAAM,iBAAiB;OAC9C,MAAM;OACN,QAAQ,cAAc;OACtB,SAAS,iBAAiB,gBAAgB,OAAO;OACjD,MAAM,cAAc;OACpB,OAAO,cAAc;OACrB,UAAU,cAAc;OACxB,UAAU,cAAc;OACxB,aAAa,cAAc;OAC3B,WAAW,cAAc;MAC3B,CAAC,CACiB;KACpB,SAAS,KAAK;MACZ,OAAO,GAAG;KACZ;IACF,CAAC,CAAC,CACD,MAAM,MAAM;GACjB,CAEO;GAIT,OAAO,MAAM,eAAe;EAC9B,SAAS,KAAK;GAEZ,QAAQ,MAAM,0CAA0C,GAAG;GAC3D,OAAO,IAAI,SAAS,wBAAwB,EAAE,QAAQ,IAAI,CAAC;EAC7D;CACF,EAAA,CAAG,CACL;AACF;AAEA,IAAM,gBAAgB,OAAO,UAAkC;CAC7D,MAAM,OAAO,MAAM,MAAM;CACzB,MAAM,OAAO,MAAM;CAEnB,IAAI,MAAM,MAAM,SAAS,gBAAgB;EACvC,MAAM,MAAM,YAAY;EACxB,MAAM,cAAc,CAAC,CAAC;EACtB;CACF,OAAO,IAAI,MAAM,KAAK,SAAS,SAAS;EACtC,MAAM,QAAQ,MAAM,CAAC,CAAC,WAAW,KAAK,YAAY,CAAC,CAAC,CAAC;EACrD;CACF;CAEA,MAAM,oBAAoB,KAAK,kBAAkB,MAAM,GAAG,CAAC,CAAC;CAE5D,IAAI,kBAAkB,MACpB,iBAAiB,CAAC;CAGpB,MAAM,gBAAgB,eAAe;CACrC,MAAM,qBAAqB,MAAM,QAAQ,aAAa,IAClD,QACA,cAAc;CAElB,MAAM,QAAQ,qBAAqB,KAAK,QAAQ;CAChD,MAAM,6BAA6B,GAAG,kBAAkB,SAAS;CAEjE,IAAI,kBAAkB,SAAS;CAC/B,IAAI,CAAC,iBAAiB;EACpB,MAAM,kBAAkB,MAAM,QAAQ,aAAa,IAAI,QAAQ,cAAc;EAC7E,MAAM,wCAAwC,MAAM,QAAQ,aAAa,IACrE,OACA,cAAc;EAClB,MAAM,yCAAyC,MAAM,QAAQ,aAAa,IACtE,QACA,cAAc;EAClB,MAAM,2BAA2B,MAAM,QAAQ,aAAa,IACxD,QACA,cAAc;EAElB,SAAS,8BAA8B;GACrC,QAAQ;GACR,OAAO;GACP,cAAc;GACd,yBAAyB;GACzB,mBAAmB,KAAA;GACnB,OAAO;GACP,QAAQ;GACR,mBAAmB;GACnB,iBAAiB,CAAC;GAClB,kCAAkC,yCAAyC;GAC3E,wCAAwC,0CAA0C;GAClF,qCAAqC;GACrC,uCAAuC;GACvC,6CAA6C;GAC7C,yDAAyD;GACzD,oBAAoB,sBAAsB;GAC1C,0BAA0B,4BAA4B;EACxD;EACA,kBAAkB,SAAS;EAE3B,IAAI,CAAC,eAAe,oBAClB,eAAe,qBAAqB,CAAC;CAEzC;CAEA,QAAQ,KAAK,MAAb;EACE,KAAK;GACH,gBAAgB,SAAS;GACzB,gBAAgB,QAAQ;GACxB,gBAAgB,eAAe;GAC/B,gBAAgB,QAAQ;GACxB,gBAAgB,sCAAsC;GACtD,gBAAgB,wCAAwC;GACxD,gBAAgB,8CAA8C;GAC9D,gBAAgB,0DAA0D;GAC1E,gBAAgB,SAAS,KAAK,KAAK;GACnC,KAAK,YAAY,EAAE,kBAAkB,CAAC;GACtC;EAEF,KAAK,QAAQ;GACX,MAAM,0BAA0B,KAAK,KAAK;GAC1C,MAAM,UAAU,WAAW,eAAe,MAAM;GAEhD,IAAI,CAAC,QAAQ,MAAK,WAAU,WAAA,GAA+B,GACzD;IACE,wBAAwB;IACxB,wBAAwB;IACxB,wBAAwB;IACxB,wBAAwB;GAC1B,CAAC,CAAC,SAAQ,MAAK;IACb,YAAY,SAAS,CAAC;GACxB,CAAC;GAGH,gBAAgB,0BAA0B;GAC1C,gBAAgB,oBAAoB,KAAK,KAAK;GAE9C,IAAI,gBAAgB,+CAA+C,MAAM;IACvE,MAAM,8CAA8C,qBAAqB,aAAa;IACtF,IAAI,+CAA+C,MAAM;KACvD,IAAI,gBAAgB,kBAAkB,mCACpC,QAAQ,KACN,kGACF;KAEF,gBAAgB,8CACd;KACF,gBAAgB,wCAAwC,MAAM,iBAAiB,IAAI,CAAC,CAClF,4CAA4C,oBAC9C;KACA,gBAAgB,0DACd,iCAAiC,aAAa,KAAK;IACvD;GACF;GAEA,IAAI,CAAC,gBAAgB,QACnB,KAAK,YAAY;IACf,QAAQ;IACR,QAAQ,gBAAgB;IACxB;IACA,SAAA;GACF,CAAC;QACI;IACL,MAAM,SAAS,EAAE,GAAG,gBAAgB,OAAO;IAC3C,IAAI,gBAAgB,iBAClB,OAAO,eAAe,GAAG,MAAM,aAAa,GAAG,kBAAkB,SAAS;IAE5E,IAAI,OAAO,eACT,OAAO,gBAAgB,GAAG,MAAM,cAAc,GAAG,kBAAkB,SAAS;IAE9E,IAAI,QAAQ,gBAAgB,SAAS,gBAAgB,SAAS,MAC5D,OAAO,eAAe,QAAQ,GAAG,MAAM,YAAY,GAAG,kBAAkB,SAAS;IAEnF,KAAK,YAAY;KACf;KACA,QAAQ,gBAAgB;KACxB;KACA,SAAA;IACF,CAAC;GACH;GACA;EACF;EAEA,KAAK;GACH,gBAAgB,sCACd,KAAK,KAAK;GACZ,KAAK,YAAY,EAAE,kBAAkB,CAAC;GACtC;EAGF,KAAK,0CAA0C;GAC7C,MAAM,sCACJ,gBAAgB;GAClB,KAAK,YAAY;IACf;IACA;GACF,CAAC;GACD;EACF;EAEA,KAAK;GACH,gBAAgB,QAAQ,KAAK,KAAK;GAClC,KAAK,YAAY,EAAE,kBAAkB,CAAC;GACtC;EAGF,KAAK,YAAY;GACf,MAAM,QAAQ,gBAAgB;GAC9B,KAAK,YAAY;IAAE;IAAmB;GAAM,CAAC;GAC7C;EACF;EAEA,KAAK;GACH,gBAAgB,eAAe,KAAK,KAAK;GACzC,KAAK,YAAY,EAAE,kBAAkB,CAAC;GACtC;EAGF,KAAK,mBAAmB;GACtB,MAAM,eACJ,gBAAgB,gBAAgB,OAC5B,GAAG,MAAM,cAAc,GAAG,kBAAkB,SAAS,UACrD;GACN,KAAK,YAAY;IACf;IACA;GACF,CAAC;GACD;EACF;EAEA,KAAK;GACH,gBAAgB,eAAe,KAAK,KAAK;GACzC,KAAK,YAAY,EAAE,kBAAkB,CAAC;GACtC;EAGF,KAAK,mBAAmB;GACtB,MAAM,eAAe,gBAAgB;GACrC,KAAK,YAAY;IAAE;IAAmB;GAAa,CAAC;GACpD;EACF;EAEA,KAAK,YAAY;GACf,MAAM,QAAQ,KAAK,KAAK;GACxB,IAAI,OACF,gBAAgB,QAAQ;GAE1B,KAAK,YAAY,EAAE,kBAAkB,CAAC;GACtC;EACF;EAEA,KAAK,YAAY;GACf,MAAM,WAAW,GAAG,MAAM,YAAY,GAAG,kBAAkB,SAAS;GACpE,MAAM,QAAQ,gBAAgB,QAAQ,WAAW;GACjD,KAAK,YAAY;IAAE;IAAmB;GAAM,CAAC;GAC7C;EACF;EAEA,SACE;CACJ;AACF;AAGA,MAAM,iBAAiB,SAAS,WAAW;AAC3C,MAAM,iBAAiB,WAAW,aAAa"}
@@ -1,2 +1,2 @@
1
- export * from './src/protocol'
1
+ export * from './src/protocol.js'
2
2
  export {}
@@ -1 +1 @@
1
- {"version":3,"file":"protocol.js","names":[],"sources":["../src/protocol.ts"],"sourcesContent":["/**\n * Public, supported entry point for the oidc-client service worker\n * `postMessage` protocol.\n *\n * See `PROTOCOL.md` (in this package) for a full description of every\n * message type, payload, response shape, storage key convention and the\n * stability guarantees that apply to those exports.\n */\n\nimport type {\n MessageData,\n MessageEventData,\n MessageEventType,\n Nonce,\n OidcConfiguration,\n OidcServerConfiguration,\n Status,\n} from './types';\n\nexport type {\n MessageData,\n MessageEventData,\n MessageEventType,\n Nonce,\n OidcConfiguration,\n OidcServerConfiguration,\n Status,\n};\n\n/**\n * Semver-protected version of the service worker `postMessage` protocol.\n *\n * - The `MAJOR` component changes only on a breaking change to any of the\n * exports in this module.\n * - The `MINOR` component changes when new (additive) message types or\n * helpers are introduced.\n * - The `PATCH` component changes for documentation or non-behavioural\n * tweaks.\n */\nexport const PROTOCOL_VERSION = '1.0.0' as const;\n\n/**\n * Every supported service worker message type.\n *\n * The values are also the literal string used on the wire as\n * `MessageEventData.type` and must therefore remain stable across patch and\n * minor versions of the protocol.\n */\nexport const ServiceWorkerMessageType = {\n /** Lifecycle: tells the SW to skip the `waiting` state. */\n SKIP_WAITING: 'SKIP_WAITING',\n /** Lifecycle: asks the SW to claim the current page. */\n CLAIM: 'claim',\n /** Resets the session entry kept inside the SW for a configuration. */\n CLEAR: 'clear',\n /** Initialises a configuration entry inside the SW. */\n INIT: 'init',\n SET_STATE: 'setState',\n GET_STATE: 'getState',\n SET_CODE_VERIFIER: 'setCodeVerifier',\n GET_CODE_VERIFIER: 'getCodeVerifier',\n SET_SESSION_STATE: 'setSessionState',\n GET_SESSION_STATE: 'getSessionState',\n SET_NONCE: 'setNonce',\n GET_NONCE: 'getNonce',\n SET_DPOP_NONCE: 'setDemonstratingProofOfPossessionNonce',\n GET_DPOP_NONCE: 'getDemonstratingProofOfPossessionNonce',\n SET_DPOP_JWK: 'setDemonstratingProofOfPossessionJwk',\n GET_DPOP_JWK: 'getDemonstratingProofOfPossessionJwk',\n} as const;\n\nexport type ServiceWorkerMessageTypeKey = keyof typeof ServiceWorkerMessageType;\nexport type ServiceWorkerMessageTypeValue =\n (typeof ServiceWorkerMessageType)[ServiceWorkerMessageTypeKey];\n\n/**\n * Structural shape of a message sent to the service worker. The shape is\n * identical to {@link MessageEventData} but typed against the public\n * {@link ServiceWorkerMessageTypeValue} union and with optional fields where\n * the underlying SW tolerates them.\n */\nexport interface ServiceWorkerMessage<\n TData extends Partial<MessageData> | null = Partial<MessageData> | null,\n> {\n type: ServiceWorkerMessageTypeValue | 'SKIP_WAITING' | 'claim';\n configurationName: string;\n data: TData;\n /**\n * Optional tab identifier injected by the high-level helpers. Consumers\n * sending raw messages can omit it; the SW falls back to `'default'`.\n */\n tabId?: string;\n}\n\n/**\n * Generic envelope used by every response. Each individual message type may\n * extend it with additional, well-known fields (see PROTOCOL.md).\n */\nexport interface ServiceWorkerResponse {\n configurationName?: string;\n /** Set by the SW when it cannot service the request. */\n error?: unknown;\n [key: string]: unknown;\n}\n\n/**\n * Stable internal token placeholders. They are returned by the service\n * worker in lieu of secret values (access/refresh tokens, nonces and code\n * verifier) so consumers never see the cleartext.\n */\nexport const TOKEN_PLACEHOLDERS = {\n ACCESS_TOKEN: 'ACCESS_TOKEN_SECURED_BY_OIDC_SERVICE_WORKER',\n REFRESH_TOKEN: 'REFRESH_TOKEN_SECURED_BY_OIDC_SERVICE_WORKER',\n NONCE_TOKEN: 'NONCE_SECURED_BY_OIDC_SERVICE_WORKER',\n CODE_VERIFIER: 'CODE_VERIFIER_SECURED_BY_OIDC_SERVICE_WORKER',\n} as const;\n\n/** Prefix used for every DPoP placeholder returned by the SW. */\nexport const DPOP_TOKEN_PLACEHOLDER_PREFIX = 'DPOP_SECURED_BY_OIDC_SERVICE_WORKER' as const;\n\n/**\n * Browser storage key conventions used by the OIDC client when no service\n * worker is available, or as a fallback alongside the SW. They are exported\n * so external integrations can read/clean up the same entries.\n */\nexport const STORAGE_KEY_PREFIX = {\n /** sessionStorage – per-tab tab identifier (`oidc.tabId.<configurationName>`). */\n TAB_ID: 'oidc.tabId.',\n /** sessionStorage – `oidc.state.<configurationName>`. */\n STATE: 'oidc.state.',\n /** sessionStorage – `oidc.nonce.<configurationName>`. */\n NONCE: 'oidc.nonce.',\n /** sessionStorage – `oidc.code_verifier.<configurationName>`. */\n CODE_VERIFIER: 'oidc.code_verifier.',\n /** localStorage – `oidc.login.<configurationName>`. */\n LOGIN_PARAMS: 'oidc.login.',\n /** sessionStorage – `oidc.sw.version_mismatch_reload.<configurationName>`. */\n SW_VERSION_MISMATCH_RELOAD: 'oidc.sw.version_mismatch_reload.',\n} as const;\n\n/** sessionStorage key tracking the SW controllerchange reload counter. */\nexport const SW_CONTROLLER_CHANGE_RELOAD_COUNT_KEY =\n 'oidc.sw.controllerchange_reload_count' as const;\n\n/**\n * Builds a typed sessionStorage / localStorage key from one of the known\n * prefixes and a configuration name. The function is intentionally\n * single-purpose so we never lose the prefix-based stability guarantee.\n */\nexport const buildStorageKey = (\n prefix: (typeof STORAGE_KEY_PREFIX)[keyof typeof STORAGE_KEY_PREFIX],\n configurationName: string,\n): string => `${prefix}${configurationName}`;\n\n/**\n * Builds the stable placeholder string the SW returns instead of an\n * access/refresh/nonce/code-verifier secret. Useful for consumers that need\n * to detect whether a value comes from the SW.\n */\nexport const buildSecuredTokenPlaceholder = (\n placeholder: (typeof TOKEN_PLACEHOLDERS)[keyof typeof TOKEN_PLACEHOLDERS],\n configurationName: string,\n tabId: string = 'default',\n): string => `${placeholder}_${configurationName}#tabId=${tabId}`;\n\n/**\n * Builds the placeholder returned for DPoP-secured access tokens\n * (`DPOP_SECURED_BY_OIDC_SERVICE_WORKER_<config>#tabId=<tabId>`).\n */\nexport const buildDpopSecuredPlaceholder = (\n configurationName: string,\n tabId: string = 'default',\n): string => `${DPOP_TOKEN_PLACEHOLDER_PREFIX}_${configurationName}#tabId=${tabId}`;\n\n/**\n * Type guard returning `true` when the provided value is one of the\n * supported, public service worker message types.\n */\nexport const isServiceWorkerMessageType = (\n value: unknown,\n): value is ServiceWorkerMessageTypeValue => {\n if (typeof value !== 'string') {\n return false;\n }\n return Object.values(ServiceWorkerMessageType).includes(value as ServiceWorkerMessageTypeValue);\n};\n\n/**\n * Internal wire-level type, re-exported for legacy parity. New code should\n * prefer {@link ServiceWorkerMessageTypeValue}.\n *\n * @internal\n */\nexport type ServiceWorkerMessageEventType = MessageEventType;\n"],"mappings":";;;;;;;;;;;AAuCA,IAAa,mBAAmB;;;;;;;;AAShC,IAAa,2BAA2B;;CAEtC,cAAc;;CAEd,OAAO;;CAEP,OAAO;;CAEP,MAAM;CACN,WAAW;CACX,WAAW;CACX,mBAAmB;CACnB,mBAAmB;CACnB,mBAAmB;CACnB,mBAAmB;CACnB,WAAW;CACX,WAAW;CACX,gBAAgB;CAChB,gBAAgB;CAChB,cAAc;CACd,cAAc;AAChB;;;;;;AAyCA,IAAa,qBAAqB;CAChC,cAAc;CACd,eAAe;CACf,aAAa;CACb,eAAe;AACjB;;AAGA,IAAa,gCAAgC;;;;;;AAO7C,IAAa,qBAAqB;;CAEhC,QAAQ;;CAER,OAAO;;CAEP,OAAO;;CAEP,eAAe;;CAEf,cAAc;;CAEd,4BAA4B;AAC9B;;AAGA,IAAa,wCACX;;;;;;AAOF,IAAa,mBACX,QACA,sBACW,GAAG,SAAS;;;;;;AAOzB,IAAa,gCACX,aACA,mBACA,QAAgB,cACL,GAAG,YAAY,GAAG,kBAAkB,SAAS;;;;;AAM1D,IAAa,+BACX,mBACA,QAAgB,cACL,GAAG,8BAA8B,GAAG,kBAAkB,SAAS;;;;;AAM5E,IAAa,8BACX,UAC2C;CAC3C,IAAI,OAAO,UAAU,UACnB,OAAO;CAET,OAAO,OAAO,OAAO,wBAAwB,EAAE,SAAS,KAAsC;AAChG"}
1
+ {"version":3,"file":"protocol.js","names":[],"sources":["../src/protocol.ts"],"sourcesContent":["/**\n * Public, supported entry point for the oidc-client service worker\n * `postMessage` protocol.\n *\n * See `PROTOCOL.md` (in this package) for a full description of every\n * message type, payload, response shape, storage key convention and the\n * stability guarantees that apply to those exports.\n */\n\nimport type {\n MessageData,\n MessageEventData,\n MessageEventType,\n Nonce,\n OidcConfiguration,\n OidcServerConfiguration,\n Status,\n} from './types';\n\nexport type {\n MessageData,\n MessageEventData,\n MessageEventType,\n Nonce,\n OidcConfiguration,\n OidcServerConfiguration,\n Status,\n};\n\n/**\n * Semver-protected version of the service worker `postMessage` protocol.\n *\n * - The `MAJOR` component changes only on a breaking change to any of the\n * exports in this module.\n * - The `MINOR` component changes when new (additive) message types or\n * helpers are introduced.\n * - The `PATCH` component changes for documentation or non-behavioural\n * tweaks.\n */\nexport const PROTOCOL_VERSION = '1.0.0' as const;\n\n/**\n * Every supported service worker message type.\n *\n * The values are also the literal string used on the wire as\n * `MessageEventData.type` and must therefore remain stable across patch and\n * minor versions of the protocol.\n */\nexport const ServiceWorkerMessageType = {\n /** Lifecycle: tells the SW to skip the `waiting` state. */\n SKIP_WAITING: 'SKIP_WAITING',\n /** Lifecycle: asks the SW to claim the current page. */\n CLAIM: 'claim',\n /** Resets the session entry kept inside the SW for a configuration. */\n CLEAR: 'clear',\n /** Initialises a configuration entry inside the SW. */\n INIT: 'init',\n SET_STATE: 'setState',\n GET_STATE: 'getState',\n SET_CODE_VERIFIER: 'setCodeVerifier',\n GET_CODE_VERIFIER: 'getCodeVerifier',\n SET_SESSION_STATE: 'setSessionState',\n GET_SESSION_STATE: 'getSessionState',\n SET_NONCE: 'setNonce',\n GET_NONCE: 'getNonce',\n SET_DPOP_NONCE: 'setDemonstratingProofOfPossessionNonce',\n GET_DPOP_NONCE: 'getDemonstratingProofOfPossessionNonce',\n SET_DPOP_JWK: 'setDemonstratingProofOfPossessionJwk',\n GET_DPOP_JWK: 'getDemonstratingProofOfPossessionJwk',\n} as const;\n\nexport type ServiceWorkerMessageTypeKey = keyof typeof ServiceWorkerMessageType;\nexport type ServiceWorkerMessageTypeValue =\n (typeof ServiceWorkerMessageType)[ServiceWorkerMessageTypeKey];\n\n/**\n * Structural shape of a message sent to the service worker. The shape is\n * identical to {@link MessageEventData} but typed against the public\n * {@link ServiceWorkerMessageTypeValue} union and with optional fields where\n * the underlying SW tolerates them.\n */\nexport interface ServiceWorkerMessage<\n TData extends Partial<MessageData> | null = Partial<MessageData> | null,\n> {\n type: ServiceWorkerMessageTypeValue | 'SKIP_WAITING' | 'claim';\n configurationName: string;\n data: TData;\n /**\n * Optional tab identifier injected by the high-level helpers. Consumers\n * sending raw messages can omit it; the SW falls back to `'default'`.\n */\n tabId?: string;\n}\n\n/**\n * Generic envelope used by every response. Each individual message type may\n * extend it with additional, well-known fields (see PROTOCOL.md).\n */\nexport interface ServiceWorkerResponse {\n configurationName?: string;\n /** Set by the SW when it cannot service the request. */\n error?: unknown;\n [key: string]: unknown;\n}\n\n/**\n * Stable internal token placeholders. They are returned by the service\n * worker in lieu of secret values (access/refresh tokens, nonces and code\n * verifier) so consumers never see the cleartext.\n */\nexport const TOKEN_PLACEHOLDERS = {\n ACCESS_TOKEN: 'ACCESS_TOKEN_SECURED_BY_OIDC_SERVICE_WORKER',\n REFRESH_TOKEN: 'REFRESH_TOKEN_SECURED_BY_OIDC_SERVICE_WORKER',\n NONCE_TOKEN: 'NONCE_SECURED_BY_OIDC_SERVICE_WORKER',\n CODE_VERIFIER: 'CODE_VERIFIER_SECURED_BY_OIDC_SERVICE_WORKER',\n} as const;\n\n/** Prefix used for every DPoP placeholder returned by the SW. */\nexport const DPOP_TOKEN_PLACEHOLDER_PREFIX = 'DPOP_SECURED_BY_OIDC_SERVICE_WORKER' as const;\n\n/**\n * Browser storage key conventions used by the OIDC client when no service\n * worker is available, or as a fallback alongside the SW. They are exported\n * so external integrations can read/clean up the same entries.\n */\nexport const STORAGE_KEY_PREFIX = {\n /** sessionStorage – per-tab tab identifier (`oidc.tabId.<configurationName>`). */\n TAB_ID: 'oidc.tabId.',\n /** sessionStorage – `oidc.state.<configurationName>`. */\n STATE: 'oidc.state.',\n /** sessionStorage – `oidc.nonce.<configurationName>`. */\n NONCE: 'oidc.nonce.',\n /** sessionStorage – `oidc.code_verifier.<configurationName>`. */\n CODE_VERIFIER: 'oidc.code_verifier.',\n /** localStorage – `oidc.login.<configurationName>`. */\n LOGIN_PARAMS: 'oidc.login.',\n /** sessionStorage – `oidc.sw.version_mismatch_reload.<configurationName>`. */\n SW_VERSION_MISMATCH_RELOAD: 'oidc.sw.version_mismatch_reload.',\n} as const;\n\n/** sessionStorage key tracking the SW controllerchange reload counter. */\nexport const SW_CONTROLLER_CHANGE_RELOAD_COUNT_KEY =\n 'oidc.sw.controllerchange_reload_count' as const;\n\n/**\n * Builds a typed sessionStorage / localStorage key from one of the known\n * prefixes and a configuration name. The function is intentionally\n * single-purpose so we never lose the prefix-based stability guarantee.\n */\nexport const buildStorageKey = (\n prefix: (typeof STORAGE_KEY_PREFIX)[keyof typeof STORAGE_KEY_PREFIX],\n configurationName: string,\n): string => `${prefix}${configurationName}`;\n\n/**\n * Builds the stable placeholder string the SW returns instead of an\n * access/refresh/nonce/code-verifier secret. Useful for consumers that need\n * to detect whether a value comes from the SW.\n */\nexport const buildSecuredTokenPlaceholder = (\n placeholder: (typeof TOKEN_PLACEHOLDERS)[keyof typeof TOKEN_PLACEHOLDERS],\n configurationName: string,\n tabId: string = 'default',\n): string => `${placeholder}_${configurationName}#tabId=${tabId}`;\n\n/**\n * Builds the placeholder returned for DPoP-secured access tokens\n * (`DPOP_SECURED_BY_OIDC_SERVICE_WORKER_<config>#tabId=<tabId>`).\n */\nexport const buildDpopSecuredPlaceholder = (\n configurationName: string,\n tabId: string = 'default',\n): string => `${DPOP_TOKEN_PLACEHOLDER_PREFIX}_${configurationName}#tabId=${tabId}`;\n\n/**\n * Type guard returning `true` when the provided value is one of the\n * supported, public service worker message types.\n */\nexport const isServiceWorkerMessageType = (\n value: unknown,\n): value is ServiceWorkerMessageTypeValue => {\n if (typeof value !== 'string') {\n return false;\n }\n return Object.values(ServiceWorkerMessageType).includes(value as ServiceWorkerMessageTypeValue);\n};\n\n/**\n * Internal wire-level type, re-exported for legacy parity. New code should\n * prefer {@link ServiceWorkerMessageTypeValue}.\n *\n * @internal\n */\nexport type ServiceWorkerMessageEventType = MessageEventType;\n"],"mappings":";;;;;;;;;;;AAuCA,IAAa,mBAAmB;;;;;;;;AAShC,IAAa,2BAA2B;;CAEtC,cAAc;;CAEd,OAAO;;CAEP,OAAO;;CAEP,MAAM;CACN,WAAW;CACX,WAAW;CACX,mBAAmB;CACnB,mBAAmB;CACnB,mBAAmB;CACnB,mBAAmB;CACnB,WAAW;CACX,WAAW;CACX,gBAAgB;CAChB,gBAAgB;CAChB,cAAc;CACd,cAAc;AAChB;;;;;;AAyCA,IAAa,qBAAqB;CAChC,cAAc;CACd,eAAe;CACf,aAAa;CACb,eAAe;AACjB;;AAGA,IAAa,gCAAgC;;;;;;AAO7C,IAAa,qBAAqB;;CAEhC,QAAQ;;CAER,OAAO;;CAEP,OAAO;;CAEP,eAAe;;CAEf,cAAc;;CAEd,4BAA4B;AAC9B;;AAGA,IAAa,wCACX;;;;;;AAOF,IAAa,mBACX,QACA,sBACW,GAAG,SAAS;;;;;;AAOzB,IAAa,gCACX,aACA,mBACA,QAAgB,cACL,GAAG,YAAY,GAAG,kBAAkB,SAAS;;;;;AAM1D,IAAa,+BACX,mBACA,QAAgB,cACL,GAAG,8BAA8B,GAAG,kBAAkB,SAAS;;;;;AAM5E,IAAa,8BACX,UAC2C;CAC3C,IAAI,OAAO,UAAU,UACnB,OAAO;CAET,OAAO,OAAO,OAAO,wBAAwB,CAAC,CAAC,SAAS,KAAsC;AAChG"}
@@ -1,3 +1,3 @@
1
1
  export declare function replaceCodeVerifier(codeVerifier: string, newCodeVerifier: string): string;
2
- export declare const extractConfigurationNameFromCodeVerifier: (chaine: string) => string;
2
+ export declare const extractConfigurationNameFromCodeVerifier: (body: string) => string;
3
3
  //# sourceMappingURL=codeVerifier.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"codeVerifier.d.ts","sourceRoot":"","sources":["../../../src/utils/codeVerifier.ts"],"names":[],"mappings":"AAAA,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,MAAM,CAGzF;AAED,eAAO,MAAM,wCAAwC,GAAI,QAAQ,MAAM,KAAG,MASzE,CAAC"}
1
+ {"version":3,"file":"codeVerifier.d.ts","sourceRoot":"","sources":["../../../src/utils/codeVerifier.ts"],"names":[],"mappings":"AAAA,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,MAAM,CAGzF;AAED,eAAO,MAAM,wCAAwC,GAAI,MAAM,MAAM,KAAG,MAKvE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"serializeHeaders.d.ts","sourceRoot":"","sources":["../../../src/utils/serializeHeaders.ts"],"names":[],"mappings":"AAAA,iBAAS,gBAAgB,CAAC,OAAO,EAAE,OAAO,0BAQzC;AACD,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
1
+ {"version":3,"file":"serializeHeaders.d.ts","sourceRoot":"","sources":["../../../src/utils/serializeHeaders.ts"],"names":[],"mappings":"AAAA,iBAAS,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CASlE;AACD,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../../src/utils/tokens.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,cAAc,EACd,UAAU,EAEV,uBAAuB,EACvB,MAAM,EACP,MAAM,UAAU,CAAC;AAGlB,eAAO,MAAM,QAAQ,GAAI,SAAS,MAAM,QAEvC,CAAC;AACF,iBAAS,gBAAgB,CAAC,GAAG,EAAE,MAAM,UAMpC;AAED,iBAAS,eAAe,CAAC,yCAAyC,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,UAG5F;AAED,iBAAS,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,WAK3C;AAED,QAAA,MAAM,mBAAmB,GAAI,QAAQ,MAAM,QAc1C,CAAC;AAIF,QAAA,MAAM,iBAAiB,GACrB,QAAQ,MAAM,EACd,OAAO,MAAM,GAAG,IAAI,EACpB,yBAAyB,uBAAuB,KAC/C;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CA2CpC,CAAC;AAsBF,iBAAS,WAAW,CAClB,MAAM,EAAE,MAAM,EACd,sBAAsB,EAAE,UAAU,EAClC,iBAAiB,EAAE,MAAM;;;;;;;;;EA4F1B;AAGD,iBAAS,UAAU,CAAC,sBAAsB,EAAE,UAAU,IAE5C,UAAU,QAAQ,kCAsB3B;AAED,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,aAAa,EACb,mBAAmB,EACnB,iBAAiB,EACjB,UAAU,EACV,WAAW,GACZ,CAAC"}
1
+ {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../../src/utils/tokens.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,cAAc,EACd,UAAU,EAEV,uBAAuB,EACvB,MAAM,EACP,MAAM,UAAU,CAAC;AAElB,eAAO,MAAM,QAAQ,GAAI,SAAS,MAAM,QAEvC,CAAC;AACF,iBAAS,gBAAgB,CAAC,GAAG,EAAE,MAAM,UAMpC;AAED,iBAAS,eAAe,CAAC,yCAAyC,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,UAG5F;AAED,iBAAS,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,WAK3C;AAED,QAAA,MAAM,mBAAmB,GAAI,QAAQ,MAAM,QAW1C,CAAC;AAIF,QAAA,MAAM,iBAAiB,GACrB,QAAQ,MAAM,EACd,OAAO,MAAM,GAAG,IAAI,EACpB,yBAAyB,uBAAuB,KAC/C;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CA2CpC,CAAC;AAsBF,iBAAS,WAAW,CAClB,MAAM,EAAE,MAAM,EACd,sBAAsB,EAAE,UAAU,EAClC,iBAAiB,EAAE,MAAM;;;;;;;;;EA4F1B;AAGD,iBAAS,UAAU,CAAC,sBAAsB,EAAE,UAAU,IAE5C,UAAU,QAAQ,kCAsB3B;AAED,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,aAAa,EACb,mBAAmB,EACnB,iBAAiB,EACjB,UAAU,EACV,WAAW,GACZ,CAAC"}
@@ -1,3 +1,3 @@
1
- declare const _default: "7.29.3";
1
+ declare const _default: "7.29.5";
2
2
  export default _default;
3
3
  //# sourceMappingURL=version.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axa-fr/oidc-client-service-worker",
3
- "version": "7.29.3",
3
+ "version": "7.29.5",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "main": "dist/OidcServiceWorker.js",
@@ -46,14 +46,14 @@
46
46
  "lint": "eslint src"
47
47
  },
48
48
  "devDependencies": {
49
- "@vitest/coverage-v8": "4.1.6",
50
- "cpy": "13.2.2",
49
+ "@vitest/coverage-v8": "5.0.0",
50
+ "cpy": "13.2.3",
51
51
  "cpy-cli": "^7.0.0",
52
52
  "rimraf": "6.1.3",
53
- "typescript": "6.0.3",
54
- "vite": "8.0.13",
55
- "vite-plugin-dts": "5.0.0",
56
- "vitest": "4.1.6"
53
+ "typescript": "npm:@typescript/typescript6@6.0.2",
54
+ "vite": "8.3.0",
55
+ "vite-plugin-dts": "5.1.0",
56
+ "vitest": "5.0.0"
57
57
  },
58
58
  "publishConfig": {
59
59
  "access": "public",
@@ -35,6 +35,54 @@ const oidcServerConfigDefault = {
35
35
  };
36
36
 
37
37
  describe('getCurrentDatabasesTokenEndpoint', () => {
38
+ it.each([
39
+ ['https://EXAMPLE.com:443/token?code=example', 'https://example.com/token'],
40
+ ['http://example.com:80/token', 'http://EXAMPLE.com/token'],
41
+ ['https://example.com/token/child', 'https://example.com/token'],
42
+ ['https://example.com/token2', 'https://example.com/token'],
43
+ ['not-a-url', 'not-a-url'],
44
+ ])('preserves normalization and prefix matching for %s', (url, endpoint) => {
45
+ const database: Database = {
46
+ uninitialized: { ...oidcConfigDefaults, oidcServerConfiguration: null },
47
+ token: {
48
+ ...oidcConfigDefaults,
49
+ oidcServerConfiguration: { ...oidcServerConfigDefault, tokenEndpoint: endpoint },
50
+ },
51
+ revocation: {
52
+ ...oidcConfigDefaults,
53
+ oidcServerConfiguration: { ...oidcServerConfigDefault, revocationEndpoint: endpoint },
54
+ },
55
+ emptyEndpoints: {
56
+ ...oidcConfigDefaults,
57
+ oidcServerConfiguration: { ...oidcServerConfigDefault },
58
+ },
59
+ };
60
+
61
+ const result = getCurrentDatabasesTokenEndpoint(database, url);
62
+
63
+ expect(result).toEqual([database.token, database.revocation]);
64
+ expect(result[0]).toBe(database.token);
65
+ expect(result[1]).toBe(database.revocation);
66
+ });
67
+
68
+ it('returns no matches for an empty database', () => {
69
+ expect(getCurrentDatabasesTokenEndpoint({}, 'https://example.com/token')).toEqual([]);
70
+ });
71
+
72
+ it('keeps non-default ports distinct', () => {
73
+ const database: Database = {
74
+ config: {
75
+ ...oidcConfigDefaults,
76
+ oidcServerConfiguration: {
77
+ ...oidcServerConfigDefault,
78
+ tokenEndpoint: 'https://example.com:8443/token',
79
+ },
80
+ },
81
+ };
82
+
83
+ expect(getCurrentDatabasesTokenEndpoint(database, 'https://example.com/token')).toEqual([]);
84
+ });
85
+
38
86
  it('should return configs with matching token endpoint', () => {
39
87
  const database: Database = {
40
88
  config1: {
package/src/oidcConfig.ts CHANGED
@@ -82,11 +82,11 @@ const shouldBypassNonOidcRequest = (
82
82
  };
83
83
 
84
84
  const getMatchingOidcConfigurations = (database: Database, url: string): OidcConfig[] => {
85
+ const normalizedUrl = normalizeUrl(url);
85
86
  return Object.values(database).filter(config => {
86
87
  const { oidcServerConfiguration } = config || {};
87
88
  const { tokenEndpoint, revocationEndpoint } = oidcServerConfiguration || {};
88
89
 
89
- const normalizedUrl = normalizeUrl(url);
90
90
  return (
91
91
  (tokenEndpoint && normalizedUrl.startsWith(normalizeUrl(tokenEndpoint))) ||
92
92
  (revocationEndpoint && normalizedUrl.startsWith(normalizeUrl(revocationEndpoint)))
@@ -3,6 +3,18 @@ import { describe, expect, it } from 'vitest';
3
3
  import { extractConfigurationNameFromCodeVerifier, replaceCodeVerifier } from '../codeVerifier';
4
4
 
5
5
  describe('replaceCodeVerifier should', () => {
6
+ it.each([
7
+ ['?code_verifier=old&state=example', '&code_verifier=new&state=example'],
8
+ ['&CODE_VERIFIER=old', '&code_verifier=new'],
9
+ ['&code_verifier=first&code_verifier=second', '&code_verifier=new&code_verifier=second'],
10
+ ['code_verifier=old', 'code_verifier=old'],
11
+ ['&code_verifier=&state=example', '&code_verifier=&state=example'],
12
+ ['&other=example', '&other=example'],
13
+ ['', ''],
14
+ ])('preserve replacement boundaries for %s', (body, expected) => {
15
+ expect(replaceCodeVerifier(body, 'new')).toBe(expected);
16
+ });
17
+
6
18
  it.each([
7
19
  {
8
20
  body: 'code=F5CDCDB9AADB9ADA59560DE80CAAA6688BC5C8BA1CC1C1F9839F7E7B32171B3D-1&grant_type=authorization_code&client_id=interactive.public.short&redirect_uri=http%3A%2F%2Flocalhost%3A4200%2Fauthentication%2Fcallback&code_verifier=ONskPfcbfAYPp5xqhpMstHSz017896R7sy3wqrRdqC8lYB8yQciCCNLooqLC9qHFTF2FFhDQP4m8PEFNSry8eoCbQ9baYcoWjF1bEH6vGWExdTIMqauicjeVxqz58FO8',
@@ -21,6 +33,27 @@ describe('replaceCodeVerifier should', () => {
21
33
  });
22
34
 
23
35
  describe('extractConfigurationNameFromCodeVerifier should', () => {
36
+ it.each([
37
+ ['?code_verifier=CODE_VERIFIER_SECURED_BY_OIDC_SERVICE_WORKER_team%20one&state=x', 'team one'],
38
+ ['&code_verifier=CODE_VERIFIER_SECURED_BY_OIDC_SERVICE_WORKER_team%23tab', 'team#tab'],
39
+ ['&code_verifier=CODE_VERIFIER_SECURED_BY_OIDC_SERVICE_WORKER_team+one', 'team+one'],
40
+ ['code_verifier=CODE_VERIFIER_SECURED_BY_OIDC_SERVICE_WORKER_default', ''],
41
+ ['&CODE_VERIFIER=CODE_VERIFIER_SECURED_BY_OIDC_SERVICE_WORKER_default', ''],
42
+ ['&code_verifier=CODE_VERIFIER_SECURED_BY_OIDC_SERVICE_WORKER_', ''],
43
+ ['&code_verifier=ordinary', ''],
44
+ ['', ''],
45
+ ])('preserve extraction boundaries and decoding for %s', (body, expected) => {
46
+ expect(extractConfigurationNameFromCodeVerifier(body)).toBe(expected);
47
+ });
48
+
49
+ it('preserve malformed configuration escape errors', () => {
50
+ expect(() =>
51
+ extractConfigurationNameFromCodeVerifier(
52
+ '&code_verifier=CODE_VERIFIER_SECURED_BY_OIDC_SERVICE_WORKER_%ZZ',
53
+ ),
54
+ ).toThrow(URIError);
55
+ });
56
+
24
57
  it.each([
25
58
  {
26
59
  body: 'code=56DB8E3592FBD48DCF6F65B38B12845FF0186ECF6D66ECB5425C0F7E658B7951-1&grant_type=authorization_code&client_id=interactive.public.short&redirect_uri=https%3A%2F%2Fblack-rock-0dc6b0d03.1.azurestaticapps.net%2Fauthentication%2Fcallback&code_verifier=CODE_VERIFIER_SECURED_BY_OIDC_SERVICE_WORKER_default_tab1',
@@ -32,7 +65,6 @@ describe('extractConfigurationNameFromCodeVerifier should', () => {
32
65
  },
33
66
  ])('inject new codeVerifier', async ({ body, expected }) => {
34
67
  const configurationName = extractConfigurationNameFromCodeVerifier(body);
35
- console.log(configurationName);
36
68
  expect(configurationName).toEqual(expected);
37
69
  });
38
70
  });
@@ -4,7 +4,43 @@ import { serializeHeaders } from '..';
4
4
 
5
5
  describe('serializeHeaders', () => {
6
6
  it('can serialize basic header', () => {
7
- const result = serializeHeaders(new Headers({ 'Content-Type': 'application/json' })); // Error: Argument of type 'Headers' is not assignable to parameter of type 'Headers'.(2345
7
+ const result = serializeHeaders(new Headers({ 'Content-Type': 'application/json' }));
8
8
  expect(result).toEqual({ 'content-type': 'application/json' });
9
9
  });
10
+
11
+ it('returns an empty object for empty headers', () => {
12
+ expect(serializeHeaders(new Headers())).toEqual({});
13
+ });
14
+
15
+ it('normalizes names and preserves empty and combined header values', () => {
16
+ const headers = new Headers({
17
+ 'X-Empty': '',
18
+ 'X-Custom': 'first',
19
+ 'Content-Type': 'text/plain',
20
+ });
21
+ headers.append('x-custom', 'second');
22
+
23
+ expect(serializeHeaders(headers)).toEqual({
24
+ 'content-type': 'text/plain',
25
+ 'x-custom': 'first, second',
26
+ 'x-empty': '',
27
+ });
28
+ expect(headers.get('x-custom')).toBe('first, second');
29
+ });
30
+
31
+ it('preserves the combined value of repeated Set-Cookie headers', () => {
32
+ const headers = new Headers();
33
+ headers.append('Set-Cookie', 'first=1');
34
+ headers.append('Set-Cookie', 'second=2');
35
+
36
+ expect(serializeHeaders(headers)).toEqual({ 'set-cookie': 'first=1, second=2' });
37
+ });
38
+
39
+ it('returns a detached object that can be changed without mutating the headers', () => {
40
+ const headers = new Headers({ 'X-Custom': 'original' });
41
+ const serialized = serializeHeaders(headers);
42
+ serialized['x-custom'] = 'changed';
43
+
44
+ expect(headers.get('X-Custom')).toBe('original');
45
+ });
10
46
  });
@@ -1,4 +1,4 @@
1
- import { beforeEach, describe, expect, it } from 'vitest';
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2
2
 
3
3
  import { OidcServerConfiguration } from '../../types';
4
4
  import { _hideTokens, extractTokenPayload, isTokensOidcValid, isTokensValid, parseJwt } from '..';
@@ -56,6 +56,44 @@ describe('tokens', () => {
56
56
  });
57
57
 
58
58
  describe('extractTokenPayload', () => {
59
+ const payload = { sub: 'unit-test', name: 'Test user' };
60
+ const encodedPayload = btoa(JSON.stringify(payload));
61
+
62
+ afterEach(() => {
63
+ vi.restoreAllMocks();
64
+ });
65
+
66
+ it.each([`header.${encodedPayload}.signature`, `.${encodedPayload}.`])(
67
+ 'extracts the payload from a three-part token: %s',
68
+ token => {
69
+ expect(extractTokenPayload(token)).toEqual(payload);
70
+ },
71
+ );
72
+
73
+ it.each([
74
+ undefined,
75
+ '',
76
+ 'opaque-token',
77
+ `header.${encodedPayload}`,
78
+ `header.${encodedPayload}.signature.extra`,
79
+ `header.${encodedPayload}.signature.`,
80
+ ])('returns null for a token without exactly three parts: %s', token => {
81
+ const warn = vi.spyOn(console, 'warn').mockImplementation(() => undefined);
82
+
83
+ expect(extractTokenPayload(token)).toBeNull();
84
+ expect(warn).not.toHaveBeenCalled();
85
+ });
86
+
87
+ it.each(['header..signature', 'header.!.signature', 'header.bm90IGpzb24=.signature'])(
88
+ 'warns and returns null when decoding fails: %s',
89
+ token => {
90
+ const warn = vi.spyOn(console, 'warn').mockImplementation(() => undefined);
91
+
92
+ expect(extractTokenPayload(token)).toBeNull();
93
+ expect(warn).toHaveBeenCalledExactlyOnceWith(expect.any(Error));
94
+ },
95
+ );
96
+
59
97
  it('can extract token payload', () => {
60
98
  const result = extractTokenPayload(
61
99
  'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c',
@@ -3,13 +3,9 @@ export function replaceCodeVerifier(codeVerifier: string, newCodeVerifier: strin
3
3
  return codeVerifier.replace(regex, `&code_verifier=${newCodeVerifier}`);
4
4
  }
5
5
 
6
- export const extractConfigurationNameFromCodeVerifier = (chaine: string): string => {
6
+ export const extractConfigurationNameFromCodeVerifier = (body: string): string => {
7
7
  const regex = /[?&]code_verifier=CODE_VERIFIER_SECURED_BY_OIDC_SERVICE_WORKER_([^&]+)/;
8
- const match = chaine.match(regex);
8
+ const match = body.match(regex);
9
9
 
10
- if (match && match.length > 0) {
11
- return decodeURIComponent(match[1]);
12
- } else {
13
- return '';
14
- }
10
+ return match ? decodeURIComponent(match[1]) : '';
15
11
  };
@@ -1,8 +1,9 @@
1
- function serializeHeaders(headers: Headers) {
1
+ function serializeHeaders(headers: Headers): Record<string, string> {
2
2
  const headersObj: Record<string, string> = {};
3
3
  for (const key of headers.keys()) {
4
- if (headers.has(key)) {
5
- headersObj[key] = headers.get(key) as string;
4
+ const value = headers.get(key);
5
+ if (value !== null) {
6
+ headersObj[key] = value;
6
7
  }
7
8
  }
8
9
  return headersObj;
@@ -8,7 +8,6 @@ import {
8
8
  OidcServerConfiguration,
9
9
  Tokens,
10
10
  } from '../types';
11
- import { countLetter } from './strings';
12
11
 
13
12
  export const parseJwt = (payload: string) => {
14
13
  return JSON.parse(b64DecodeUnicode(payload.replaceAll(/-/g, '+').replaceAll(/_/g, '/')));
@@ -38,11 +37,8 @@ const extractTokenPayload = (token?: string) => {
38
37
  if (!token) {
39
38
  return null;
40
39
  }
41
- if (countLetter(token, '.') === 2) {
42
- return parseJwt(token.split('.')[1]);
43
- } else {
44
- return null;
45
- }
40
+ const parts = token.split('.');
41
+ return parts.length === 3 ? parseJwt(parts[1]) : null;
46
42
  } catch (e) {
47
43
  console.warn(e);
48
44
  }
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export default '7.29.3';
1
+ export default '7.29.5';