@monocloud/auth-core 0.1.3 → 0.1.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.
@@ -1,11 +1,12 @@
1
- const require_internal = require('../internal-DytuO03E.cjs');
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ const require_utils_internal = require('./internal.cjs');
2
3
 
3
4
  //#region src/utils/index.ts
4
5
  const PBKDF2_ITERATIONS = 31e4;
5
6
  const SALT_LENGTH = 16;
6
7
  const GCM_IV_LENGTH = 12;
7
8
  const deriveEncryptionKey = async (secret, salt) => {
8
- const baseKey = await crypto.subtle.importKey("raw", require_internal.stringToArrayBuffer(secret), "PBKDF2", false, ["deriveKey"]);
9
+ const baseKey = await crypto.subtle.importKey("raw", require_utils_internal.stringToArrayBuffer(secret), "PBKDF2", false, ["deriveKey"]);
9
10
  return crypto.subtle.deriveKey({
10
11
  name: "PBKDF2",
11
12
  salt,
@@ -52,7 +53,7 @@ const parseCallbackParams = (queryOrUrl) => {
52
53
  const encrypt = async (data, secret) => {
53
54
  const salt = crypto.getRandomValues(new Uint8Array(SALT_LENGTH));
54
55
  const iv = crypto.getRandomValues(new Uint8Array(GCM_IV_LENGTH));
55
- const plaintextBuffer = require_internal.stringToArrayBuffer(data);
56
+ const plaintextBuffer = require_utils_internal.stringToArrayBuffer(data);
56
57
  const key = await deriveEncryptionKey(secret, salt);
57
58
  const ciphertext = await crypto.subtle.encrypt({
58
59
  name: "AES-GCM",
@@ -62,7 +63,7 @@ const encrypt = async (data, secret) => {
62
63
  resultBuffer.set(salt, 0);
63
64
  resultBuffer.set(iv, salt.byteLength);
64
65
  resultBuffer.set(new Uint8Array(ciphertext), salt.byteLength + iv.byteLength);
65
- return require_internal.arrayBufferToBase64(resultBuffer);
66
+ return require_utils_internal.arrayBufferToBase64(resultBuffer);
66
67
  };
67
68
  /**
68
69
  * Decrypts an encrypted string using a secret with AES-GCM.
@@ -74,13 +75,13 @@ const encrypt = async (data, secret) => {
74
75
  */
75
76
  const decrypt = async (encrypted, secret) => {
76
77
  try {
77
- const ciphertextBuffer = Uint8Array.from(atob(require_internal.fromB64Url(encrypted)), (c) => c.charCodeAt(0));
78
+ const ciphertextBuffer = Uint8Array.from(atob(require_utils_internal.fromB64Url(encrypted)), (c) => c.charCodeAt(0));
78
79
  if (ciphertextBuffer.byteLength <= SALT_LENGTH + GCM_IV_LENGTH) return;
79
80
  const salt = ciphertextBuffer.slice(0, SALT_LENGTH);
80
81
  const iv = ciphertextBuffer.slice(SALT_LENGTH, SALT_LENGTH + GCM_IV_LENGTH);
81
82
  const encryptedPayload = ciphertextBuffer.slice(SALT_LENGTH + GCM_IV_LENGTH);
82
83
  const key = await deriveEncryptionKey(secret, salt);
83
- return require_internal.arrayBufferToString(await crypto.subtle.decrypt({
84
+ return require_utils_internal.arrayBufferToString(await crypto.subtle.decrypt({
84
85
  name: "AES-GCM",
85
86
  iv
86
87
  }, key, encryptedPayload));
@@ -98,7 +99,7 @@ const decrypt = async (encrypted, secret) => {
98
99
  */
99
100
  const encryptSession = (session, secret, ttl) => {
100
101
  let expiresAt;
101
- if (typeof ttl === "number") expiresAt = require_internal.now() + ttl;
102
+ if (typeof ttl === "number") expiresAt = require_utils_internal.now() + ttl;
102
103
  return encrypt(JSON.stringify({
103
104
  session,
104
105
  expiresAt
@@ -112,7 +113,7 @@ const encryptSession = (session, secret, ttl) => {
112
113
  *
113
114
  * @returns Session object on success.
114
115
  *
115
- * @throws If decryption fails or the session has expired
116
+ * @throws If decryption fails or the session has expired.
116
117
  */
117
118
  const decryptSession = async (encryptedSession, secret) => {
118
119
  const decryptedText = await decrypt(encryptedSession, secret);
@@ -125,7 +126,7 @@ const decryptSession = async (encryptedSession, secret) => {
125
126
  }
126
127
  const { session, expiresAt } = payload;
127
128
  if (!session) throw new Error("Invalid session data");
128
- if (typeof expiresAt === "number" && expiresAt < require_internal.now()) throw new Error("Session Expired");
129
+ if (typeof expiresAt === "number" && expiresAt < require_utils_internal.now()) throw new Error("Session Expired");
129
130
  return session;
130
131
  };
131
132
  /**
@@ -139,7 +140,7 @@ const decryptSession = async (encryptedSession, secret) => {
139
140
  */
140
141
  const encryptAuthState = (authState, secret, ttl) => {
141
142
  let expiresAt;
142
- if (typeof ttl === "number") expiresAt = require_internal.now() + ttl;
143
+ if (typeof ttl === "number") expiresAt = require_utils_internal.now() + ttl;
143
144
  return encrypt(JSON.stringify({
144
145
  authState,
145
146
  expiresAt
@@ -151,9 +152,9 @@ const encryptAuthState = (authState, secret, ttl) => {
151
152
  * @param encryptedAuthState - The encrypted auth state string to decrypt.
152
153
  * @param secret - The secret used for decryption.
153
154
  *
154
- * @returns State object on success
155
+ * @returns State object on success.
155
156
  *
156
- * @throws If decryption fails or the auth state has expired
157
+ * @throws If decryption fails or the auth state has expired.
157
158
  *
158
159
  */
159
160
  const decryptAuthState = async (encryptedAuthState, secret) => {
@@ -167,7 +168,7 @@ const decryptAuthState = async (encryptedAuthState, secret) => {
167
168
  }
168
169
  const { authState, expiresAt } = payload;
169
170
  if (!authState) throw new Error("Invalid auth state");
170
- if (typeof expiresAt === "number" && expiresAt < require_internal.now()) throw new Error("Auth state expired");
171
+ if (typeof expiresAt === "number" && expiresAt < require_utils_internal.now()) throw new Error("Auth state expired");
171
172
  return authState;
172
173
  };
173
174
  /**
@@ -196,27 +197,26 @@ const isUserInGroup = (user, groups, groupsClaim = "groups", matchAll = false) =
196
197
  /**
197
198
  * Generates a random state string.
198
199
  */
199
- const generateState = () => require_internal.randomBytes(32);
200
+ const generateState = () => require_utils_internal.randomBytes(32);
200
201
  /**
201
202
  * Generates a PKCE (Proof Key for Code Exchange) code verifier and code challenge.
202
- *
203
203
  */
204
204
  const generatePKCE = async () => {
205
- const codeVerifier = require_internal.randomBytes(32);
205
+ const codeVerifier = require_utils_internal.randomBytes(32);
206
206
  return {
207
207
  codeVerifier,
208
- codeChallenge: require_internal.encodeBase64Url(await crypto.subtle.digest("SHA-256", require_internal.stringToArrayBuffer(codeVerifier)))
208
+ codeChallenge: require_utils_internal.encodeBase64Url(await crypto.subtle.digest("SHA-256", require_utils_internal.stringToArrayBuffer(codeVerifier)))
209
209
  };
210
210
  };
211
211
  /**
212
212
  * Generates a random nonce string.
213
213
  */
214
- const generateNonce = () => require_internal.randomBytes(32);
214
+ const generateNonce = () => require_utils_internal.randomBytes(32);
215
215
  /**
216
216
  * @ignore
217
217
  * Merges multiple arrays of strings, removing duplicates.
218
218
  *
219
- * @param args - List of arrays to merge
219
+ * @param args - List of arrays to merge.
220
220
  *
221
221
  * @returns A new array containing unique strings from both input arrays, or `undefined` if both inputs are `undefined`.
222
222
  */
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["stringToArrayBuffer","arrayBufferToBase64","fromB64Url","arrayBufferToString","now","payload: { session: MonoCloudSession; expiresAt?: number }","payload: { authState: T; expiresAt?: number }","randomBytes","encodeBase64Url"],"sources":["../../src/utils/index.ts"],"sourcesContent":["import type {\n AuthState,\n CallbackParams,\n IdTokenClaims,\n MonoCloudSession,\n MonoCloudUser,\n} from '../types';\nimport {\n arrayBufferToBase64,\n arrayBufferToString,\n encodeBase64Url,\n fromB64Url,\n now,\n randomBytes,\n stringToArrayBuffer,\n} from './internal';\n\nconst PBKDF2_ITERATIONS = 310_000;\nconst SALT_LENGTH = 16;\nconst GCM_IV_LENGTH = 12;\n\nconst deriveEncryptionKey = async (\n secret: string,\n salt: Uint8Array\n): Promise<CryptoKey> => {\n const baseKey = await crypto.subtle.importKey(\n 'raw',\n stringToArrayBuffer(secret) as BufferSource,\n 'PBKDF2',\n false,\n ['deriveKey']\n );\n\n return crypto.subtle.deriveKey(\n {\n name: 'PBKDF2',\n salt: salt as BufferSource,\n iterations: PBKDF2_ITERATIONS,\n hash: 'SHA-256',\n },\n baseKey,\n { name: 'AES-GCM', length: 256 },\n false,\n ['encrypt', 'decrypt']\n );\n};\n\n/**\n * Parses callback parameters from a URL, a URLSearchParams object, or a query string.\n */\nexport const parseCallbackParams = (\n queryOrUrl: string | URL | URLSearchParams\n): CallbackParams => {\n let params;\n\n if (queryOrUrl instanceof URL) {\n params = queryOrUrl.searchParams;\n } else if (queryOrUrl instanceof URLSearchParams) {\n params = queryOrUrl;\n } else {\n try {\n params = new URL(queryOrUrl).searchParams;\n } catch {\n // eslint-disable-next-line no-param-reassign\n queryOrUrl =\n queryOrUrl.startsWith('?') || queryOrUrl.startsWith('#')\n ? queryOrUrl.substring(1)\n : queryOrUrl;\n params = new URLSearchParams(queryOrUrl);\n }\n }\n\n const expiresIn = params.get('expires_in');\n\n return {\n state: params.get('state') ?? undefined,\n accessToken: params.get('access_token') ?? undefined,\n idToken: params.get('id_token') ?? undefined,\n refreshToken: params.get('refresh_token') ?? undefined,\n sessionState: params.get('session_state') ?? undefined,\n expiresIn: expiresIn ? parseInt(expiresIn, 10) : undefined,\n code: params.get('code') ?? undefined,\n error: params.get('error') ?? undefined,\n errorDescription: params.get('error_description') ?? undefined,\n };\n};\n\n/**\n * Encrypts a given string using a secret with AES-GCM.\n *\n * @param data - The plaintext data to encrypt.\n * @param secret - The secret used to derive the encryption key.\n * @returns Base64-encoded ciphertext.\n */\nexport const encrypt = async (\n data: string,\n secret: string\n): Promise<string> => {\n const salt = crypto.getRandomValues(new Uint8Array(SALT_LENGTH));\n const iv = crypto.getRandomValues(new Uint8Array(GCM_IV_LENGTH));\n const plaintextBuffer = stringToArrayBuffer(data);\n const key = await deriveEncryptionKey(secret, salt);\n\n const ciphertext = await crypto.subtle.encrypt(\n {\n name: 'AES-GCM',\n iv,\n },\n key,\n plaintextBuffer as BufferSource\n );\n\n const resultBuffer = new Uint8Array(\n salt.byteLength + iv.byteLength + ciphertext.byteLength\n );\n resultBuffer.set(salt, 0);\n resultBuffer.set(iv, salt.byteLength);\n resultBuffer.set(new Uint8Array(ciphertext), salt.byteLength + iv.byteLength);\n\n return arrayBufferToBase64(resultBuffer);\n};\n\n/**\n * Decrypts an encrypted string using a secret with AES-GCM.\n *\n * @param encrypted - The ciphertext to decrypt.\n * @param secret - The secret used to derive the decryption key.\n *\n * @returns Decrypted plaintext string or undefined if decryption fails.\n */\nexport const decrypt = async (\n encrypted: string,\n secret: string\n): Promise<string | undefined> => {\n try {\n const ciphertextBuffer = Uint8Array.from(atob(fromB64Url(encrypted)), c =>\n c.charCodeAt(0)\n );\n\n if (ciphertextBuffer.byteLength <= SALT_LENGTH + GCM_IV_LENGTH) {\n return undefined;\n }\n\n const salt = ciphertextBuffer.slice(0, SALT_LENGTH);\n const iv = ciphertextBuffer.slice(SALT_LENGTH, SALT_LENGTH + GCM_IV_LENGTH);\n const encryptedPayload = ciphertextBuffer.slice(\n SALT_LENGTH + GCM_IV_LENGTH\n );\n const key = await deriveEncryptionKey(secret, salt);\n const decryptedBuffer = await crypto.subtle.decrypt(\n {\n name: 'AES-GCM',\n iv,\n },\n key,\n encryptedPayload\n );\n return arrayBufferToString(decryptedBuffer);\n } catch {\n return undefined;\n }\n};\n\n/**\n * Encrypts a MonoCloud session object with a secret and optional time-to-live (TTL).\n *\n * @param session - The session object to encrypt.\n * @param secret - The secret used for encryption.\n * @param ttl - Optional time-to-live in seconds, after which the session expires.\n * @returns Encrypted session string.\n */\nexport const encryptSession = (\n session: MonoCloudSession,\n secret: string,\n ttl?: number\n): Promise<string> => {\n let expiresAt;\n\n if (typeof ttl === 'number') {\n expiresAt = now() + ttl;\n }\n return encrypt(JSON.stringify({ session, expiresAt }), secret);\n};\n\n/**\n * Decrypts an encrypted MonoCloud session.\n *\n * @param encryptedSession - The encrypted session string to decrypt.\n * @param secret - The secret used for decryption.\n *\n * @returns Session object on success.\n *\n * @throws If decryption fails or the session has expired\n */\nexport const decryptSession = async (\n encryptedSession: string,\n secret: string\n): Promise<MonoCloudSession> => {\n const decryptedText = await decrypt(encryptedSession, secret);\n\n if (!decryptedText) {\n throw new Error('Invalid session data');\n }\n\n let payload: { session: MonoCloudSession; expiresAt?: number };\n try {\n payload = JSON.parse(decryptedText);\n } catch {\n throw new Error('Invalid session data');\n }\n\n const { session, expiresAt } = payload;\n\n if (!session) {\n throw new Error('Invalid session data');\n }\n\n if (typeof expiresAt === 'number' && expiresAt < now()) {\n throw new Error('Session Expired');\n }\n\n return session;\n};\n\n/**\n * Encrypts an AuthState object with a secret and optional time-to-live (TTL).\n *\n * @param authState - A type that extends the AuthState interface.\n * @param secret - The secret used for encryption.\n * @param ttl - Optional time-to-live in seconds, after which the auth state expires.\n *\n * @returns Encrypted auth state string.\n */\nexport const encryptAuthState = <T extends AuthState>(\n authState: T,\n secret: string,\n ttl?: number\n): Promise<string> => {\n let expiresAt;\n\n if (typeof ttl === 'number') {\n expiresAt = now() + ttl;\n }\n\n return encrypt(JSON.stringify({ authState, expiresAt }), secret);\n};\n\n/**\n * Decrypts an encrypted AuthState.\n *\n * @param encryptedAuthState - The encrypted auth state string to decrypt.\n * @param secret - The secret used for decryption.\n *\n * @returns State object on success\n *\n * @throws If decryption fails or the auth state has expired\n *\n */\nexport const decryptAuthState = async <T extends AuthState>(\n encryptedAuthState: string,\n secret: string\n): Promise<T> => {\n const decryptedText = await decrypt(encryptedAuthState, secret);\n\n if (!decryptedText) {\n throw new Error('Invalid auth state');\n }\n\n let payload: { authState: T; expiresAt?: number };\n try {\n payload = JSON.parse(decryptedText);\n } catch {\n throw new Error('Invalid auth state');\n }\n\n const { authState, expiresAt } = payload;\n\n if (!authState) {\n throw new Error('Invalid auth state');\n }\n\n if (typeof expiresAt === 'number' && expiresAt < now()) {\n throw new Error('Auth state expired');\n }\n\n return authState;\n};\n\n/**\n * Checks if a user is a member of a specified group or groups.\n *\n * @param user - The user.\n * @param groups - An array of group names or IDs to check membership against.\n * @param groupsClaim - The claim in the user object that contains groups.\n * @param matchAll - If `true`, requires the user to be in all specified groups; if `false`, checks if the user is in at least one of the groups.\n *\n * @returns `true` if the user is in the specified groups, `false` otherwise.\n */\nexport const isUserInGroup = (\n user: MonoCloudUser | IdTokenClaims,\n groups: string[],\n groupsClaim = 'groups',\n matchAll = false\n): boolean => {\n const userGroups = (user[groupsClaim] ?? []) as (\n | string\n | { id: string; name: string }\n )[];\n\n if (!Array.isArray(groups) || groups.length === 0) {\n return true;\n }\n\n if (!Array.isArray(userGroups) || userGroups.length === 0) {\n return false;\n }\n\n let matched = false;\n\n for (const expectedGroup of groups) {\n const userInGroup = userGroups.some(\n g =>\n (typeof g === 'string' && g === expectedGroup) ||\n (typeof g === 'object' &&\n (g.id === expectedGroup || g.name === expectedGroup))\n );\n\n if (!matchAll && userInGroup) {\n return userInGroup;\n }\n\n if (matchAll && !userInGroup) {\n return false;\n }\n\n matched = userInGroup;\n }\n\n return matched;\n};\n\n/**\n * Generates a random state string.\n */\nexport const generateState = (): string => randomBytes(32);\n\n/**\n * Generates a PKCE (Proof Key for Code Exchange) code verifier and code challenge.\n *\n */\nexport const generatePKCE = async (): Promise<{\n codeVerifier: string;\n codeChallenge: string;\n}> => {\n const codeVerifier = randomBytes(32);\n return {\n codeVerifier,\n codeChallenge: encodeBase64Url(\n await crypto.subtle.digest(\n 'SHA-256',\n stringToArrayBuffer(codeVerifier) as BufferSource\n )\n ),\n };\n};\n\n/**\n * Generates a random nonce string.\n */\nexport const generateNonce = (): string => randomBytes(32);\n\n/**\n * @ignore\n * Merges multiple arrays of strings, removing duplicates.\n *\n * @param args - List of arrays to merge\n *\n * @returns A new array containing unique strings from both input arrays, or `undefined` if both inputs are `undefined`.\n */\nexport const mergeArrays = (\n ...args: (string[] | undefined)[]\n): string[] | undefined => {\n const arrays = args.filter(x => Array.isArray(x));\n return arrays.length > 0\n ? Array.from(new Set(arrays.reduce((acc, x) => [...acc, ...x], [])))\n : undefined;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["stringToArrayBuffer","arrayBufferToBase64","fromB64Url","arrayBufferToString","now","randomBytes","encodeBase64Url"],"sources":["../../src/utils/index.ts"],"sourcesContent":["import type {\n AuthState,\n CallbackParams,\n IdTokenClaims,\n MonoCloudSession,\n MonoCloudUser,\n} from '../types';\nimport {\n arrayBufferToBase64,\n arrayBufferToString,\n encodeBase64Url,\n fromB64Url,\n now,\n randomBytes,\n stringToArrayBuffer,\n} from './internal';\n\nconst PBKDF2_ITERATIONS = 310_000;\nconst SALT_LENGTH = 16;\nconst GCM_IV_LENGTH = 12;\n\nconst deriveEncryptionKey = async (\n secret: string,\n salt: Uint8Array\n): Promise<CryptoKey> => {\n const baseKey = await crypto.subtle.importKey(\n 'raw',\n stringToArrayBuffer(secret) as BufferSource,\n 'PBKDF2',\n false,\n ['deriveKey']\n );\n\n return crypto.subtle.deriveKey(\n {\n name: 'PBKDF2',\n salt: salt as BufferSource,\n iterations: PBKDF2_ITERATIONS,\n hash: 'SHA-256',\n },\n baseKey,\n { name: 'AES-GCM', length: 256 },\n false,\n ['encrypt', 'decrypt']\n );\n};\n\n/**\n * Parses callback parameters from a URL, a URLSearchParams object, or a query string.\n */\nexport const parseCallbackParams = (\n queryOrUrl: string | URL | URLSearchParams\n): CallbackParams => {\n let params;\n\n if (queryOrUrl instanceof URL) {\n params = queryOrUrl.searchParams;\n } else if (queryOrUrl instanceof URLSearchParams) {\n params = queryOrUrl;\n } else {\n try {\n params = new URL(queryOrUrl).searchParams;\n } catch {\n // eslint-disable-next-line no-param-reassign\n queryOrUrl =\n queryOrUrl.startsWith('?') || queryOrUrl.startsWith('#')\n ? queryOrUrl.substring(1)\n : queryOrUrl;\n params = new URLSearchParams(queryOrUrl);\n }\n }\n\n const expiresIn = params.get('expires_in');\n\n return {\n state: params.get('state') ?? undefined,\n accessToken: params.get('access_token') ?? undefined,\n idToken: params.get('id_token') ?? undefined,\n refreshToken: params.get('refresh_token') ?? undefined,\n sessionState: params.get('session_state') ?? undefined,\n expiresIn: expiresIn ? parseInt(expiresIn, 10) : undefined,\n code: params.get('code') ?? undefined,\n error: params.get('error') ?? undefined,\n errorDescription: params.get('error_description') ?? undefined,\n };\n};\n\n/**\n * Encrypts a given string using a secret with AES-GCM.\n *\n * @param data - The plaintext data to encrypt.\n * @param secret - The secret used to derive the encryption key.\n * @returns Base64-encoded ciphertext.\n */\nexport const encrypt = async (\n data: string,\n secret: string\n): Promise<string> => {\n const salt = crypto.getRandomValues(new Uint8Array(SALT_LENGTH));\n const iv = crypto.getRandomValues(new Uint8Array(GCM_IV_LENGTH));\n const plaintextBuffer = stringToArrayBuffer(data);\n const key = await deriveEncryptionKey(secret, salt);\n\n const ciphertext = await crypto.subtle.encrypt(\n {\n name: 'AES-GCM',\n iv,\n },\n key,\n plaintextBuffer as BufferSource\n );\n\n const resultBuffer = new Uint8Array(\n salt.byteLength + iv.byteLength + ciphertext.byteLength\n );\n resultBuffer.set(salt, 0);\n resultBuffer.set(iv, salt.byteLength);\n resultBuffer.set(new Uint8Array(ciphertext), salt.byteLength + iv.byteLength);\n\n return arrayBufferToBase64(resultBuffer);\n};\n\n/**\n * Decrypts an encrypted string using a secret with AES-GCM.\n *\n * @param encrypted - The ciphertext to decrypt.\n * @param secret - The secret used to derive the decryption key.\n *\n * @returns Decrypted plaintext string or undefined if decryption fails.\n */\nexport const decrypt = async (\n encrypted: string,\n secret: string\n): Promise<string | undefined> => {\n try {\n const ciphertextBuffer = Uint8Array.from(atob(fromB64Url(encrypted)), c =>\n c.charCodeAt(0)\n );\n\n if (ciphertextBuffer.byteLength <= SALT_LENGTH + GCM_IV_LENGTH) {\n return undefined;\n }\n\n const salt = ciphertextBuffer.slice(0, SALT_LENGTH);\n const iv = ciphertextBuffer.slice(SALT_LENGTH, SALT_LENGTH + GCM_IV_LENGTH);\n const encryptedPayload = ciphertextBuffer.slice(\n SALT_LENGTH + GCM_IV_LENGTH\n );\n const key = await deriveEncryptionKey(secret, salt);\n const decryptedBuffer = await crypto.subtle.decrypt(\n {\n name: 'AES-GCM',\n iv,\n },\n key,\n encryptedPayload\n );\n return arrayBufferToString(decryptedBuffer);\n } catch {\n return undefined;\n }\n};\n\n/**\n * Encrypts a MonoCloud session object with a secret and optional time-to-live (TTL).\n *\n * @param session - The session object to encrypt.\n * @param secret - The secret used for encryption.\n * @param ttl - Optional time-to-live in seconds, after which the session expires.\n * @returns Encrypted session string.\n */\nexport const encryptSession = (\n session: MonoCloudSession,\n secret: string,\n ttl?: number\n): Promise<string> => {\n let expiresAt;\n\n if (typeof ttl === 'number') {\n expiresAt = now() + ttl;\n }\n return encrypt(JSON.stringify({ session, expiresAt }), secret);\n};\n\n/**\n * Decrypts an encrypted MonoCloud session.\n *\n * @param encryptedSession - The encrypted session string to decrypt.\n * @param secret - The secret used for decryption.\n *\n * @returns Session object on success.\n *\n * @throws If decryption fails or the session has expired.\n */\nexport const decryptSession = async (\n encryptedSession: string,\n secret: string\n): Promise<MonoCloudSession> => {\n const decryptedText = await decrypt(encryptedSession, secret);\n\n if (!decryptedText) {\n throw new Error('Invalid session data');\n }\n\n let payload: { session: MonoCloudSession; expiresAt?: number };\n try {\n payload = JSON.parse(decryptedText);\n } catch {\n throw new Error('Invalid session data');\n }\n\n const { session, expiresAt } = payload;\n\n if (!session) {\n throw new Error('Invalid session data');\n }\n\n if (typeof expiresAt === 'number' && expiresAt < now()) {\n throw new Error('Session Expired');\n }\n\n return session;\n};\n\n/**\n * Encrypts an AuthState object with a secret and optional time-to-live (TTL).\n *\n * @param authState - A type that extends the AuthState interface.\n * @param secret - The secret used for encryption.\n * @param ttl - Optional time-to-live in seconds, after which the auth state expires.\n *\n * @returns Encrypted auth state string.\n */\nexport const encryptAuthState = <T extends AuthState>(\n authState: T,\n secret: string,\n ttl?: number\n): Promise<string> => {\n let expiresAt;\n\n if (typeof ttl === 'number') {\n expiresAt = now() + ttl;\n }\n\n return encrypt(JSON.stringify({ authState, expiresAt }), secret);\n};\n\n/**\n * Decrypts an encrypted AuthState.\n *\n * @param encryptedAuthState - The encrypted auth state string to decrypt.\n * @param secret - The secret used for decryption.\n *\n * @returns State object on success.\n *\n * @throws If decryption fails or the auth state has expired.\n *\n */\nexport const decryptAuthState = async <T extends AuthState>(\n encryptedAuthState: string,\n secret: string\n): Promise<T> => {\n const decryptedText = await decrypt(encryptedAuthState, secret);\n\n if (!decryptedText) {\n throw new Error('Invalid auth state');\n }\n\n let payload: { authState: T; expiresAt?: number };\n try {\n payload = JSON.parse(decryptedText);\n } catch {\n throw new Error('Invalid auth state');\n }\n\n const { authState, expiresAt } = payload;\n\n if (!authState) {\n throw new Error('Invalid auth state');\n }\n\n if (typeof expiresAt === 'number' && expiresAt < now()) {\n throw new Error('Auth state expired');\n }\n\n return authState;\n};\n\n/**\n * Checks if a user is a member of a specified group or groups.\n *\n * @param user - The user.\n * @param groups - An array of group names or IDs to check membership against.\n * @param groupsClaim - The claim in the user object that contains groups.\n * @param matchAll - If `true`, requires the user to be in all specified groups; if `false`, checks if the user is in at least one of the groups.\n *\n * @returns `true` if the user is in the specified groups, `false` otherwise.\n */\nexport const isUserInGroup = (\n user: MonoCloudUser | IdTokenClaims,\n groups: string[],\n groupsClaim = 'groups',\n matchAll = false\n): boolean => {\n const userGroups = (user[groupsClaim] ?? []) as (\n | string\n | { id: string; name: string }\n )[];\n\n if (!Array.isArray(groups) || groups.length === 0) {\n return true;\n }\n\n if (!Array.isArray(userGroups) || userGroups.length === 0) {\n return false;\n }\n\n let matched = false;\n\n for (const expectedGroup of groups) {\n const userInGroup = userGroups.some(\n g =>\n (typeof g === 'string' && g === expectedGroup) ||\n (typeof g === 'object' &&\n (g.id === expectedGroup || g.name === expectedGroup))\n );\n\n if (!matchAll && userInGroup) {\n return userInGroup;\n }\n\n if (matchAll && !userInGroup) {\n return false;\n }\n\n matched = userInGroup;\n }\n\n return matched;\n};\n\n/**\n * Generates a random state string.\n */\nexport const generateState = (): string => randomBytes(32);\n\n/**\n * Generates a PKCE (Proof Key for Code Exchange) code verifier and code challenge.\n */\nexport const generatePKCE = async (): Promise<{\n codeVerifier: string;\n codeChallenge: string;\n}> => {\n const codeVerifier = randomBytes(32);\n return {\n codeVerifier,\n codeChallenge: encodeBase64Url(\n await crypto.subtle.digest(\n 'SHA-256',\n stringToArrayBuffer(codeVerifier) as BufferSource\n )\n ),\n };\n};\n\n/**\n * Generates a random nonce string.\n */\nexport const generateNonce = (): string => randomBytes(32);\n\n/**\n * @ignore\n * Merges multiple arrays of strings, removing duplicates.\n *\n * @param args - List of arrays to merge.\n *\n * @returns A new array containing unique strings from both input arrays, or `undefined` if both inputs are `undefined`.\n */\nexport const mergeArrays = (\n ...args: (string[] | undefined)[]\n): string[] | undefined => {\n const arrays = args.filter(x => Array.isArray(x));\n return arrays.length > 0\n ? Array.from(new Set(arrays.reduce((acc, x) => [...acc, ...x], [])))\n : undefined;\n};\n"],"mappings":"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"}
@@ -1,7 +1,6 @@
1
- import { b as MonoCloudSession, p as IdTokenClaims, r as AuthState, s as CallbackParams, x as MonoCloudUser } from "../types-DwJl9ZUf.mjs";
1
+ import { b as MonoCloudUser, p as IdTokenClaims, r as AuthState, s as CallbackParams, y as MonoCloudSession } from "../types-hokU85Zr.mjs";
2
2
 
3
3
  //#region src/utils/index.d.ts
4
-
5
4
  /**
6
5
  * Parses callback parameters from a URL, a URLSearchParams object, or a query string.
7
6
  */
@@ -40,7 +39,7 @@ declare const encryptSession: (session: MonoCloudSession, secret: string, ttl?:
40
39
  *
41
40
  * @returns Session object on success.
42
41
  *
43
- * @throws If decryption fails or the session has expired
42
+ * @throws If decryption fails or the session has expired.
44
43
  */
45
44
  declare const decryptSession: (encryptedSession: string, secret: string) => Promise<MonoCloudSession>;
46
45
  /**
@@ -59,9 +58,9 @@ declare const encryptAuthState: <T extends AuthState>(authState: T, secret: stri
59
58
  * @param encryptedAuthState - The encrypted auth state string to decrypt.
60
59
  * @param secret - The secret used for decryption.
61
60
  *
62
- * @returns State object on success
61
+ * @returns State object on success.
63
62
  *
64
- * @throws If decryption fails or the auth state has expired
63
+ * @throws If decryption fails or the auth state has expired.
65
64
  *
66
65
  */
67
66
  declare const decryptAuthState: <T extends AuthState>(encryptedAuthState: string, secret: string) => Promise<T>;
@@ -82,7 +81,6 @@ declare const isUserInGroup: (user: MonoCloudUser | IdTokenClaims, groups: strin
82
81
  declare const generateState: () => string;
83
82
  /**
84
83
  * Generates a PKCE (Proof Key for Code Exchange) code verifier and code challenge.
85
- *
86
84
  */
87
85
  declare const generatePKCE: () => Promise<{
88
86
  codeVerifier: string;
@@ -96,7 +94,7 @@ declare const generateNonce: () => string;
96
94
  * @ignore
97
95
  * Merges multiple arrays of strings, removing duplicates.
98
96
  *
99
- * @param args - List of arrays to merge
97
+ * @param args - List of arrays to merge.
100
98
  *
101
99
  * @returns A new array containing unique strings from both input arrays, or `undefined` if both inputs are `undefined`.
102
100
  */
@@ -1,4 +1,4 @@
1
- import { h as now, i as encodeBase64Url, n as arrayBufferToString, s as fromB64Url, t as arrayBufferToBase64, v as randomBytes, x as stringToArrayBuffer } from "../internal-DXHuqjJJ.mjs";
1
+ import { arrayBufferToBase64, arrayBufferToString, encodeBase64Url, fromB64Url, now, randomBytes, stringToArrayBuffer } from "./internal.mjs";
2
2
 
3
3
  //#region src/utils/index.ts
4
4
  const PBKDF2_ITERATIONS = 31e4;
@@ -112,7 +112,7 @@ const encryptSession = (session, secret, ttl) => {
112
112
  *
113
113
  * @returns Session object on success.
114
114
  *
115
- * @throws If decryption fails or the session has expired
115
+ * @throws If decryption fails or the session has expired.
116
116
  */
117
117
  const decryptSession = async (encryptedSession, secret) => {
118
118
  const decryptedText = await decrypt(encryptedSession, secret);
@@ -151,9 +151,9 @@ const encryptAuthState = (authState, secret, ttl) => {
151
151
  * @param encryptedAuthState - The encrypted auth state string to decrypt.
152
152
  * @param secret - The secret used for decryption.
153
153
  *
154
- * @returns State object on success
154
+ * @returns State object on success.
155
155
  *
156
- * @throws If decryption fails or the auth state has expired
156
+ * @throws If decryption fails or the auth state has expired.
157
157
  *
158
158
  */
159
159
  const decryptAuthState = async (encryptedAuthState, secret) => {
@@ -199,7 +199,6 @@ const isUserInGroup = (user, groups, groupsClaim = "groups", matchAll = false) =
199
199
  const generateState = () => randomBytes(32);
200
200
  /**
201
201
  * Generates a PKCE (Proof Key for Code Exchange) code verifier and code challenge.
202
- *
203
202
  */
204
203
  const generatePKCE = async () => {
205
204
  const codeVerifier = randomBytes(32);
@@ -216,7 +215,7 @@ const generateNonce = () => randomBytes(32);
216
215
  * @ignore
217
216
  * Merges multiple arrays of strings, removing duplicates.
218
217
  *
219
- * @param args - List of arrays to merge
218
+ * @param args - List of arrays to merge.
220
219
  *
221
220
  * @returns A new array containing unique strings from both input arrays, or `undefined` if both inputs are `undefined`.
222
221
  */
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["payload: { session: MonoCloudSession; expiresAt?: number }","payload: { authState: T; expiresAt?: number }"],"sources":["../../src/utils/index.ts"],"sourcesContent":["import type {\n AuthState,\n CallbackParams,\n IdTokenClaims,\n MonoCloudSession,\n MonoCloudUser,\n} from '../types';\nimport {\n arrayBufferToBase64,\n arrayBufferToString,\n encodeBase64Url,\n fromB64Url,\n now,\n randomBytes,\n stringToArrayBuffer,\n} from './internal';\n\nconst PBKDF2_ITERATIONS = 310_000;\nconst SALT_LENGTH = 16;\nconst GCM_IV_LENGTH = 12;\n\nconst deriveEncryptionKey = async (\n secret: string,\n salt: Uint8Array\n): Promise<CryptoKey> => {\n const baseKey = await crypto.subtle.importKey(\n 'raw',\n stringToArrayBuffer(secret) as BufferSource,\n 'PBKDF2',\n false,\n ['deriveKey']\n );\n\n return crypto.subtle.deriveKey(\n {\n name: 'PBKDF2',\n salt: salt as BufferSource,\n iterations: PBKDF2_ITERATIONS,\n hash: 'SHA-256',\n },\n baseKey,\n { name: 'AES-GCM', length: 256 },\n false,\n ['encrypt', 'decrypt']\n );\n};\n\n/**\n * Parses callback parameters from a URL, a URLSearchParams object, or a query string.\n */\nexport const parseCallbackParams = (\n queryOrUrl: string | URL | URLSearchParams\n): CallbackParams => {\n let params;\n\n if (queryOrUrl instanceof URL) {\n params = queryOrUrl.searchParams;\n } else if (queryOrUrl instanceof URLSearchParams) {\n params = queryOrUrl;\n } else {\n try {\n params = new URL(queryOrUrl).searchParams;\n } catch {\n // eslint-disable-next-line no-param-reassign\n queryOrUrl =\n queryOrUrl.startsWith('?') || queryOrUrl.startsWith('#')\n ? queryOrUrl.substring(1)\n : queryOrUrl;\n params = new URLSearchParams(queryOrUrl);\n }\n }\n\n const expiresIn = params.get('expires_in');\n\n return {\n state: params.get('state') ?? undefined,\n accessToken: params.get('access_token') ?? undefined,\n idToken: params.get('id_token') ?? undefined,\n refreshToken: params.get('refresh_token') ?? undefined,\n sessionState: params.get('session_state') ?? undefined,\n expiresIn: expiresIn ? parseInt(expiresIn, 10) : undefined,\n code: params.get('code') ?? undefined,\n error: params.get('error') ?? undefined,\n errorDescription: params.get('error_description') ?? undefined,\n };\n};\n\n/**\n * Encrypts a given string using a secret with AES-GCM.\n *\n * @param data - The plaintext data to encrypt.\n * @param secret - The secret used to derive the encryption key.\n * @returns Base64-encoded ciphertext.\n */\nexport const encrypt = async (\n data: string,\n secret: string\n): Promise<string> => {\n const salt = crypto.getRandomValues(new Uint8Array(SALT_LENGTH));\n const iv = crypto.getRandomValues(new Uint8Array(GCM_IV_LENGTH));\n const plaintextBuffer = stringToArrayBuffer(data);\n const key = await deriveEncryptionKey(secret, salt);\n\n const ciphertext = await crypto.subtle.encrypt(\n {\n name: 'AES-GCM',\n iv,\n },\n key,\n plaintextBuffer as BufferSource\n );\n\n const resultBuffer = new Uint8Array(\n salt.byteLength + iv.byteLength + ciphertext.byteLength\n );\n resultBuffer.set(salt, 0);\n resultBuffer.set(iv, salt.byteLength);\n resultBuffer.set(new Uint8Array(ciphertext), salt.byteLength + iv.byteLength);\n\n return arrayBufferToBase64(resultBuffer);\n};\n\n/**\n * Decrypts an encrypted string using a secret with AES-GCM.\n *\n * @param encrypted - The ciphertext to decrypt.\n * @param secret - The secret used to derive the decryption key.\n *\n * @returns Decrypted plaintext string or undefined if decryption fails.\n */\nexport const decrypt = async (\n encrypted: string,\n secret: string\n): Promise<string | undefined> => {\n try {\n const ciphertextBuffer = Uint8Array.from(atob(fromB64Url(encrypted)), c =>\n c.charCodeAt(0)\n );\n\n if (ciphertextBuffer.byteLength <= SALT_LENGTH + GCM_IV_LENGTH) {\n return undefined;\n }\n\n const salt = ciphertextBuffer.slice(0, SALT_LENGTH);\n const iv = ciphertextBuffer.slice(SALT_LENGTH, SALT_LENGTH + GCM_IV_LENGTH);\n const encryptedPayload = ciphertextBuffer.slice(\n SALT_LENGTH + GCM_IV_LENGTH\n );\n const key = await deriveEncryptionKey(secret, salt);\n const decryptedBuffer = await crypto.subtle.decrypt(\n {\n name: 'AES-GCM',\n iv,\n },\n key,\n encryptedPayload\n );\n return arrayBufferToString(decryptedBuffer);\n } catch {\n return undefined;\n }\n};\n\n/**\n * Encrypts a MonoCloud session object with a secret and optional time-to-live (TTL).\n *\n * @param session - The session object to encrypt.\n * @param secret - The secret used for encryption.\n * @param ttl - Optional time-to-live in seconds, after which the session expires.\n * @returns Encrypted session string.\n */\nexport const encryptSession = (\n session: MonoCloudSession,\n secret: string,\n ttl?: number\n): Promise<string> => {\n let expiresAt;\n\n if (typeof ttl === 'number') {\n expiresAt = now() + ttl;\n }\n return encrypt(JSON.stringify({ session, expiresAt }), secret);\n};\n\n/**\n * Decrypts an encrypted MonoCloud session.\n *\n * @param encryptedSession - The encrypted session string to decrypt.\n * @param secret - The secret used for decryption.\n *\n * @returns Session object on success.\n *\n * @throws If decryption fails or the session has expired\n */\nexport const decryptSession = async (\n encryptedSession: string,\n secret: string\n): Promise<MonoCloudSession> => {\n const decryptedText = await decrypt(encryptedSession, secret);\n\n if (!decryptedText) {\n throw new Error('Invalid session data');\n }\n\n let payload: { session: MonoCloudSession; expiresAt?: number };\n try {\n payload = JSON.parse(decryptedText);\n } catch {\n throw new Error('Invalid session data');\n }\n\n const { session, expiresAt } = payload;\n\n if (!session) {\n throw new Error('Invalid session data');\n }\n\n if (typeof expiresAt === 'number' && expiresAt < now()) {\n throw new Error('Session Expired');\n }\n\n return session;\n};\n\n/**\n * Encrypts an AuthState object with a secret and optional time-to-live (TTL).\n *\n * @param authState - A type that extends the AuthState interface.\n * @param secret - The secret used for encryption.\n * @param ttl - Optional time-to-live in seconds, after which the auth state expires.\n *\n * @returns Encrypted auth state string.\n */\nexport const encryptAuthState = <T extends AuthState>(\n authState: T,\n secret: string,\n ttl?: number\n): Promise<string> => {\n let expiresAt;\n\n if (typeof ttl === 'number') {\n expiresAt = now() + ttl;\n }\n\n return encrypt(JSON.stringify({ authState, expiresAt }), secret);\n};\n\n/**\n * Decrypts an encrypted AuthState.\n *\n * @param encryptedAuthState - The encrypted auth state string to decrypt.\n * @param secret - The secret used for decryption.\n *\n * @returns State object on success\n *\n * @throws If decryption fails or the auth state has expired\n *\n */\nexport const decryptAuthState = async <T extends AuthState>(\n encryptedAuthState: string,\n secret: string\n): Promise<T> => {\n const decryptedText = await decrypt(encryptedAuthState, secret);\n\n if (!decryptedText) {\n throw new Error('Invalid auth state');\n }\n\n let payload: { authState: T; expiresAt?: number };\n try {\n payload = JSON.parse(decryptedText);\n } catch {\n throw new Error('Invalid auth state');\n }\n\n const { authState, expiresAt } = payload;\n\n if (!authState) {\n throw new Error('Invalid auth state');\n }\n\n if (typeof expiresAt === 'number' && expiresAt < now()) {\n throw new Error('Auth state expired');\n }\n\n return authState;\n};\n\n/**\n * Checks if a user is a member of a specified group or groups.\n *\n * @param user - The user.\n * @param groups - An array of group names or IDs to check membership against.\n * @param groupsClaim - The claim in the user object that contains groups.\n * @param matchAll - If `true`, requires the user to be in all specified groups; if `false`, checks if the user is in at least one of the groups.\n *\n * @returns `true` if the user is in the specified groups, `false` otherwise.\n */\nexport const isUserInGroup = (\n user: MonoCloudUser | IdTokenClaims,\n groups: string[],\n groupsClaim = 'groups',\n matchAll = false\n): boolean => {\n const userGroups = (user[groupsClaim] ?? []) as (\n | string\n | { id: string; name: string }\n )[];\n\n if (!Array.isArray(groups) || groups.length === 0) {\n return true;\n }\n\n if (!Array.isArray(userGroups) || userGroups.length === 0) {\n return false;\n }\n\n let matched = false;\n\n for (const expectedGroup of groups) {\n const userInGroup = userGroups.some(\n g =>\n (typeof g === 'string' && g === expectedGroup) ||\n (typeof g === 'object' &&\n (g.id === expectedGroup || g.name === expectedGroup))\n );\n\n if (!matchAll && userInGroup) {\n return userInGroup;\n }\n\n if (matchAll && !userInGroup) {\n return false;\n }\n\n matched = userInGroup;\n }\n\n return matched;\n};\n\n/**\n * Generates a random state string.\n */\nexport const generateState = (): string => randomBytes(32);\n\n/**\n * Generates a PKCE (Proof Key for Code Exchange) code verifier and code challenge.\n *\n */\nexport const generatePKCE = async (): Promise<{\n codeVerifier: string;\n codeChallenge: string;\n}> => {\n const codeVerifier = randomBytes(32);\n return {\n codeVerifier,\n codeChallenge: encodeBase64Url(\n await crypto.subtle.digest(\n 'SHA-256',\n stringToArrayBuffer(codeVerifier) as BufferSource\n )\n ),\n };\n};\n\n/**\n * Generates a random nonce string.\n */\nexport const generateNonce = (): string => randomBytes(32);\n\n/**\n * @ignore\n * Merges multiple arrays of strings, removing duplicates.\n *\n * @param args - List of arrays to merge\n *\n * @returns A new array containing unique strings from both input arrays, or `undefined` if both inputs are `undefined`.\n */\nexport const mergeArrays = (\n ...args: (string[] | undefined)[]\n): string[] | undefined => {\n const arrays = args.filter(x => Array.isArray(x));\n return arrays.length > 0\n ? Array.from(new Set(arrays.reduce((acc, x) => [...acc, ...x], [])))\n : undefined;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/utils/index.ts"],"sourcesContent":["import type {\n AuthState,\n CallbackParams,\n IdTokenClaims,\n MonoCloudSession,\n MonoCloudUser,\n} from '../types';\nimport {\n arrayBufferToBase64,\n arrayBufferToString,\n encodeBase64Url,\n fromB64Url,\n now,\n randomBytes,\n stringToArrayBuffer,\n} from './internal';\n\nconst PBKDF2_ITERATIONS = 310_000;\nconst SALT_LENGTH = 16;\nconst GCM_IV_LENGTH = 12;\n\nconst deriveEncryptionKey = async (\n secret: string,\n salt: Uint8Array\n): Promise<CryptoKey> => {\n const baseKey = await crypto.subtle.importKey(\n 'raw',\n stringToArrayBuffer(secret) as BufferSource,\n 'PBKDF2',\n false,\n ['deriveKey']\n );\n\n return crypto.subtle.deriveKey(\n {\n name: 'PBKDF2',\n salt: salt as BufferSource,\n iterations: PBKDF2_ITERATIONS,\n hash: 'SHA-256',\n },\n baseKey,\n { name: 'AES-GCM', length: 256 },\n false,\n ['encrypt', 'decrypt']\n );\n};\n\n/**\n * Parses callback parameters from a URL, a URLSearchParams object, or a query string.\n */\nexport const parseCallbackParams = (\n queryOrUrl: string | URL | URLSearchParams\n): CallbackParams => {\n let params;\n\n if (queryOrUrl instanceof URL) {\n params = queryOrUrl.searchParams;\n } else if (queryOrUrl instanceof URLSearchParams) {\n params = queryOrUrl;\n } else {\n try {\n params = new URL(queryOrUrl).searchParams;\n } catch {\n // eslint-disable-next-line no-param-reassign\n queryOrUrl =\n queryOrUrl.startsWith('?') || queryOrUrl.startsWith('#')\n ? queryOrUrl.substring(1)\n : queryOrUrl;\n params = new URLSearchParams(queryOrUrl);\n }\n }\n\n const expiresIn = params.get('expires_in');\n\n return {\n state: params.get('state') ?? undefined,\n accessToken: params.get('access_token') ?? undefined,\n idToken: params.get('id_token') ?? undefined,\n refreshToken: params.get('refresh_token') ?? undefined,\n sessionState: params.get('session_state') ?? undefined,\n expiresIn: expiresIn ? parseInt(expiresIn, 10) : undefined,\n code: params.get('code') ?? undefined,\n error: params.get('error') ?? undefined,\n errorDescription: params.get('error_description') ?? undefined,\n };\n};\n\n/**\n * Encrypts a given string using a secret with AES-GCM.\n *\n * @param data - The plaintext data to encrypt.\n * @param secret - The secret used to derive the encryption key.\n * @returns Base64-encoded ciphertext.\n */\nexport const encrypt = async (\n data: string,\n secret: string\n): Promise<string> => {\n const salt = crypto.getRandomValues(new Uint8Array(SALT_LENGTH));\n const iv = crypto.getRandomValues(new Uint8Array(GCM_IV_LENGTH));\n const plaintextBuffer = stringToArrayBuffer(data);\n const key = await deriveEncryptionKey(secret, salt);\n\n const ciphertext = await crypto.subtle.encrypt(\n {\n name: 'AES-GCM',\n iv,\n },\n key,\n plaintextBuffer as BufferSource\n );\n\n const resultBuffer = new Uint8Array(\n salt.byteLength + iv.byteLength + ciphertext.byteLength\n );\n resultBuffer.set(salt, 0);\n resultBuffer.set(iv, salt.byteLength);\n resultBuffer.set(new Uint8Array(ciphertext), salt.byteLength + iv.byteLength);\n\n return arrayBufferToBase64(resultBuffer);\n};\n\n/**\n * Decrypts an encrypted string using a secret with AES-GCM.\n *\n * @param encrypted - The ciphertext to decrypt.\n * @param secret - The secret used to derive the decryption key.\n *\n * @returns Decrypted plaintext string or undefined if decryption fails.\n */\nexport const decrypt = async (\n encrypted: string,\n secret: string\n): Promise<string | undefined> => {\n try {\n const ciphertextBuffer = Uint8Array.from(atob(fromB64Url(encrypted)), c =>\n c.charCodeAt(0)\n );\n\n if (ciphertextBuffer.byteLength <= SALT_LENGTH + GCM_IV_LENGTH) {\n return undefined;\n }\n\n const salt = ciphertextBuffer.slice(0, SALT_LENGTH);\n const iv = ciphertextBuffer.slice(SALT_LENGTH, SALT_LENGTH + GCM_IV_LENGTH);\n const encryptedPayload = ciphertextBuffer.slice(\n SALT_LENGTH + GCM_IV_LENGTH\n );\n const key = await deriveEncryptionKey(secret, salt);\n const decryptedBuffer = await crypto.subtle.decrypt(\n {\n name: 'AES-GCM',\n iv,\n },\n key,\n encryptedPayload\n );\n return arrayBufferToString(decryptedBuffer);\n } catch {\n return undefined;\n }\n};\n\n/**\n * Encrypts a MonoCloud session object with a secret and optional time-to-live (TTL).\n *\n * @param session - The session object to encrypt.\n * @param secret - The secret used for encryption.\n * @param ttl - Optional time-to-live in seconds, after which the session expires.\n * @returns Encrypted session string.\n */\nexport const encryptSession = (\n session: MonoCloudSession,\n secret: string,\n ttl?: number\n): Promise<string> => {\n let expiresAt;\n\n if (typeof ttl === 'number') {\n expiresAt = now() + ttl;\n }\n return encrypt(JSON.stringify({ session, expiresAt }), secret);\n};\n\n/**\n * Decrypts an encrypted MonoCloud session.\n *\n * @param encryptedSession - The encrypted session string to decrypt.\n * @param secret - The secret used for decryption.\n *\n * @returns Session object on success.\n *\n * @throws If decryption fails or the session has expired.\n */\nexport const decryptSession = async (\n encryptedSession: string,\n secret: string\n): Promise<MonoCloudSession> => {\n const decryptedText = await decrypt(encryptedSession, secret);\n\n if (!decryptedText) {\n throw new Error('Invalid session data');\n }\n\n let payload: { session: MonoCloudSession; expiresAt?: number };\n try {\n payload = JSON.parse(decryptedText);\n } catch {\n throw new Error('Invalid session data');\n }\n\n const { session, expiresAt } = payload;\n\n if (!session) {\n throw new Error('Invalid session data');\n }\n\n if (typeof expiresAt === 'number' && expiresAt < now()) {\n throw new Error('Session Expired');\n }\n\n return session;\n};\n\n/**\n * Encrypts an AuthState object with a secret and optional time-to-live (TTL).\n *\n * @param authState - A type that extends the AuthState interface.\n * @param secret - The secret used for encryption.\n * @param ttl - Optional time-to-live in seconds, after which the auth state expires.\n *\n * @returns Encrypted auth state string.\n */\nexport const encryptAuthState = <T extends AuthState>(\n authState: T,\n secret: string,\n ttl?: number\n): Promise<string> => {\n let expiresAt;\n\n if (typeof ttl === 'number') {\n expiresAt = now() + ttl;\n }\n\n return encrypt(JSON.stringify({ authState, expiresAt }), secret);\n};\n\n/**\n * Decrypts an encrypted AuthState.\n *\n * @param encryptedAuthState - The encrypted auth state string to decrypt.\n * @param secret - The secret used for decryption.\n *\n * @returns State object on success.\n *\n * @throws If decryption fails or the auth state has expired.\n *\n */\nexport const decryptAuthState = async <T extends AuthState>(\n encryptedAuthState: string,\n secret: string\n): Promise<T> => {\n const decryptedText = await decrypt(encryptedAuthState, secret);\n\n if (!decryptedText) {\n throw new Error('Invalid auth state');\n }\n\n let payload: { authState: T; expiresAt?: number };\n try {\n payload = JSON.parse(decryptedText);\n } catch {\n throw new Error('Invalid auth state');\n }\n\n const { authState, expiresAt } = payload;\n\n if (!authState) {\n throw new Error('Invalid auth state');\n }\n\n if (typeof expiresAt === 'number' && expiresAt < now()) {\n throw new Error('Auth state expired');\n }\n\n return authState;\n};\n\n/**\n * Checks if a user is a member of a specified group or groups.\n *\n * @param user - The user.\n * @param groups - An array of group names or IDs to check membership against.\n * @param groupsClaim - The claim in the user object that contains groups.\n * @param matchAll - If `true`, requires the user to be in all specified groups; if `false`, checks if the user is in at least one of the groups.\n *\n * @returns `true` if the user is in the specified groups, `false` otherwise.\n */\nexport const isUserInGroup = (\n user: MonoCloudUser | IdTokenClaims,\n groups: string[],\n groupsClaim = 'groups',\n matchAll = false\n): boolean => {\n const userGroups = (user[groupsClaim] ?? []) as (\n | string\n | { id: string; name: string }\n )[];\n\n if (!Array.isArray(groups) || groups.length === 0) {\n return true;\n }\n\n if (!Array.isArray(userGroups) || userGroups.length === 0) {\n return false;\n }\n\n let matched = false;\n\n for (const expectedGroup of groups) {\n const userInGroup = userGroups.some(\n g =>\n (typeof g === 'string' && g === expectedGroup) ||\n (typeof g === 'object' &&\n (g.id === expectedGroup || g.name === expectedGroup))\n );\n\n if (!matchAll && userInGroup) {\n return userInGroup;\n }\n\n if (matchAll && !userInGroup) {\n return false;\n }\n\n matched = userInGroup;\n }\n\n return matched;\n};\n\n/**\n * Generates a random state string.\n */\nexport const generateState = (): string => randomBytes(32);\n\n/**\n * Generates a PKCE (Proof Key for Code Exchange) code verifier and code challenge.\n */\nexport const generatePKCE = async (): Promise<{\n codeVerifier: string;\n codeChallenge: string;\n}> => {\n const codeVerifier = randomBytes(32);\n return {\n codeVerifier,\n codeChallenge: encodeBase64Url(\n await crypto.subtle.digest(\n 'SHA-256',\n stringToArrayBuffer(codeVerifier) as BufferSource\n )\n ),\n };\n};\n\n/**\n * Generates a random nonce string.\n */\nexport const generateNonce = (): string => randomBytes(32);\n\n/**\n * @ignore\n * Merges multiple arrays of strings, removing duplicates.\n *\n * @param args - List of arrays to merge.\n *\n * @returns A new array containing unique strings from both input arrays, or `undefined` if both inputs are `undefined`.\n */\nexport const mergeArrays = (\n ...args: (string[] | undefined)[]\n): string[] | undefined => {\n const arrays = args.filter(x => Array.isArray(x));\n return arrays.length > 0\n ? Array.from(new Set(arrays.reduce((acc, x) => [...acc, ...x], [])))\n : undefined;\n};\n"],"mappings":"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"}