internxt-crypto 0.0.13 → 0.0.14

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.
Files changed (81) hide show
  1. package/dist/{aes-DSDxP8uF.mjs → aes-DCb9dJqb.mjs} +7 -30
  2. package/dist/aes-DCb9dJqb.mjs.map +1 -0
  3. package/dist/{aes-bOrKZuUC.js → aes-DQo1MyCz.js} +7 -30
  4. package/dist/aes-DQo1MyCz.js.map +1 -0
  5. package/dist/constants.d.mts +5 -5
  6. package/dist/constants.d.mts.map +1 -1
  7. package/dist/constants.d.ts +5 -5
  8. package/dist/constants.d.ts.map +1 -1
  9. package/dist/constants.js +8 -8
  10. package/dist/constants.js.map +1 -1
  11. package/dist/constants.mjs +5 -5
  12. package/dist/constants.mjs.map +1 -1
  13. package/dist/derive-key.js +1 -1
  14. package/dist/derive-key.mjs +1 -1
  15. package/dist/{deriveKeysFromPassword-Ko7NxkHM.js → deriveKeysFromPassword-BYaiSGKL.js} +4 -9
  16. package/dist/{deriveKeysFromPassword-Ko7NxkHM.js.map → deriveKeysFromPassword-BYaiSGKL.js.map} +1 -1
  17. package/dist/{deriveKeysFromPassword-DJRWZ8Rw.mjs → deriveKeysFromPassword-XIwzErlL.mjs} +4 -9
  18. package/dist/{deriveKeysFromPassword-DJRWZ8Rw.mjs.map → deriveKeysFromPassword-XIwzErlL.mjs.map} +1 -1
  19. package/dist/email-crypto.js +1 -1
  20. package/dist/email-crypto.mjs +1 -1
  21. package/dist/email-search.d.mts +18 -18
  22. package/dist/email-search.d.mts.map +1 -1
  23. package/dist/email-search.d.ts +18 -18
  24. package/dist/email-search.d.ts.map +1 -1
  25. package/dist/email-search.js +14 -14
  26. package/dist/email-search.js.map +1 -1
  27. package/dist/email-search.mjs +14 -14
  28. package/dist/email-search.mjs.map +1 -1
  29. package/dist/{emailEncryptionKey-27mIHh18.mjs → emailEncryptionKey-B9xHw1h_.mjs} +6 -6
  30. package/dist/emailEncryptionKey-B9xHw1h_.mjs.map +1 -0
  31. package/dist/{emailEncryptionKey-DbaDAdoW.js → emailEncryptionKey-CQNe5W_T.js} +6 -6
  32. package/dist/emailEncryptionKey-CQNe5W_T.js.map +1 -0
  33. package/dist/{emailKeys-BJGdkLrg.js → emailKeys-C0KhtfNP.js} +28 -49
  34. package/dist/emailKeys-C0KhtfNP.js.map +1 -0
  35. package/dist/{emailKeys-Fp9WR3wl.mjs → emailKeys-D4lp9NRv.mjs} +26 -47
  36. package/dist/emailKeys-D4lp9NRv.mjs.map +1 -0
  37. package/dist/index.d.mts +11 -11
  38. package/dist/index.d.mts.map +1 -1
  39. package/dist/index.d.ts +11 -11
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js +12 -12
  42. package/dist/index.mjs +7 -7
  43. package/dist/keystore-crypto.js +1 -1
  44. package/dist/keystore-crypto.mjs +1 -1
  45. package/dist/kyber768-SXnIo-Nw.mjs +47 -0
  46. package/dist/kyber768-SXnIo-Nw.mjs.map +1 -0
  47. package/dist/kyber768-WUVc2fIR.js +65 -0
  48. package/dist/kyber768-WUVc2fIR.js.map +1 -0
  49. package/dist/post-quantum-crypto.d.mts +5 -41
  50. package/dist/post-quantum-crypto.d.mts.map +1 -1
  51. package/dist/post-quantum-crypto.d.ts +5 -41
  52. package/dist/post-quantum-crypto.d.ts.map +1 -1
  53. package/dist/post-quantum-crypto.js +4 -16
  54. package/dist/post-quantum-crypto.mjs +2 -2
  55. package/dist/symmetric-crypto.d.mts +4 -4
  56. package/dist/symmetric-crypto.d.mts.map +1 -1
  57. package/dist/symmetric-crypto.d.ts +4 -4
  58. package/dist/symmetric-crypto.d.ts.map +1 -1
  59. package/dist/symmetric-crypto.js +1 -1
  60. package/dist/symmetric-crypto.mjs +1 -1
  61. package/dist/types.d.mts +5 -1
  62. package/dist/types.d.mts.map +1 -1
  63. package/dist/types.d.ts +5 -1
  64. package/dist/types.d.ts.map +1 -1
  65. package/dist/types.js.map +1 -1
  66. package/dist/types.mjs.map +1 -1
  67. package/package.json +2 -1
  68. package/dist/aes-DSDxP8uF.mjs.map +0 -1
  69. package/dist/aes-bOrKZuUC.js.map +0 -1
  70. package/dist/emailEncryptionKey-27mIHh18.mjs.map +0 -1
  71. package/dist/emailEncryptionKey-DbaDAdoW.js.map +0 -1
  72. package/dist/emailKeys-BJGdkLrg.js.map +0 -1
  73. package/dist/emailKeys-Fp9WR3wl.mjs.map +0 -1
  74. package/dist/kyber1024-PpwE1rki.mjs +0 -144
  75. package/dist/kyber1024-PpwE1rki.mjs.map +0 -1
  76. package/dist/kyber1024-jeKS8CXf.js +0 -173
  77. package/dist/kyber1024-jeKS8CXf.js.map +0 -1
  78. package/dist/kyber768-DGBB_RS7.d.ts +0 -32
  79. package/dist/kyber768-DGBB_RS7.d.ts.map +0 -1
  80. package/dist/kyber768-DzIcGg1i.d.mts +0 -32
  81. package/dist/kyber768-DzIcGg1i.d.mts.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"email-search.mjs","names":[],"sources":["../src/email-search/indexedDB.ts","../src/email-search/mailCache.ts","../src/email-search/search.ts"],"sourcesContent":["import { DBSchema, openDB, deleteDB, IDBPDatabase } from 'idb';\nimport { StoredEmail, Email } from '../types';\nimport { decryptEmailSymmetrically, encryptEmailContentSymmetricallyWithKey } from '../email-crypto/core';\nimport { deriveSymmetricCryptoKeyFromContext } from '../derive-key';\nimport { CONTEXT_INDEX, DB_LABEL, DB_VERSION } from '../constants';\nimport { getAux } from '../email-crypto';\n\nexport type MailDB = IDBPDatabase<EncryptedSearchDB>;\n\nexport interface EncryptedSearchDB extends DBSchema {\n email: {\n key: string;\n value: StoredEmail;\n indexes: { byTime: number[] };\n };\n}\n\n/**\n * Returns IndexedDB database name for the given user\n *\n * @param userID - The user ID\n * @returns The database name\n */\nconst getDatabaseName = (userID: string): string => {\n return `ES:${userID}:DB`;\n};\n\n/**\n * Opens IndexedDB database for the given user\n *\n * @param userID - The user ID\n * @returns The database\n */\nexport const openDatabase = async (userID: string): Promise<MailDB> => {\n try {\n const dbName = getDatabaseName(userID);\n return openDB<EncryptedSearchDB>(dbName, DB_VERSION, {\n upgrade(db) {\n if (!db.objectStoreNames.contains(DB_LABEL)) {\n const store = db.createObjectStore(DB_LABEL, { keyPath: 'id' });\n store.createIndex('byTime', 'params.createdAt');\n }\n },\n });\n } catch (error) {\n throw new Error(`Cannot open a database for the user ${userID}`, { cause: error });\n }\n};\n\n/**\n * Closes the IndexedDB database\n *\n * @param esDB - The database\n */\nexport const closeDatabase = (esDB: MailDB): void => {\n return esDB.close();\n};\n\n/**\n * Deletes IndexedDB database for the given user\n *\n * @param userID - The user ID\n * @returns The database\n */\nexport const deleteDatabase = async (userID: string): Promise<void> => {\n const dbName = getDatabaseName(userID);\n return deleteDB(dbName);\n};\n\n/**\n * Derives database encryption key for the given user\n *\n * @param userID - The user ID\n * @returns The symmetric CryptoKey for protecting database\n */\nexport const deriveIndexKey = async (baseKey: Uint8Array): Promise<CryptoKey> => {\n return deriveSymmetricCryptoKeyFromContext(CONTEXT_INDEX, baseKey);\n};\n\n/**\n * Encrypts the given email and stores it in the IndexedDB database\n *\n * @param newEmailToStore - The email for storing\n * @param indexKey - The symmetric CryptoKey key for protecting database\n * @param esDB - The database\n */\nexport const encryptAndStoreEmail = async (\n newEmailToStore: Email,\n indexKey: CryptoKey,\n esDB: MailDB,\n): Promise<void> => {\n try {\n const aux = getAux(newEmailToStore.params, false);\n const enc = await encryptEmailContentSymmetricallyWithKey(newEmailToStore.body, indexKey, aux, newEmailToStore.id);\n const encryptedEmail: StoredEmail = { enc, params: newEmailToStore.params, id: newEmailToStore.id };\n await esDB.put(DB_LABEL, encryptedEmail);\n } catch (error) {\n throw new Error('Cannot encrypt and add the given email to the database', { cause: error });\n }\n};\n\n/**\n * Encrypts the given set of emails and stores it in the IndexedDB database\n *\n * @param newEmailsToStore - The set of emails for storing\n * @param indexKey - The symmetric CryptoKey key for protecting database\n * @param esDB - The database\n */\nexport const encryptAndStoreManyEmail = async (\n newEmailsToStore: Email[],\n indexKey: CryptoKey,\n esDB: MailDB,\n): Promise<void> => {\n try {\n const encryptedEmails = await Promise.all(\n newEmailsToStore.map(async (email: Email) => {\n const aux = getAux(email.params, false);\n const enc = await encryptEmailContentSymmetricallyWithKey(email.body, indexKey, aux, email.id);\n\n return { enc, params: email.params, id: email.id };\n }),\n );\n\n const tr = esDB.transaction(DB_LABEL, 'readwrite');\n await Promise.all([...encryptedEmails.map((encEmail) => tr.store.put(encEmail)), tr.done]);\n } catch (error) {\n throw new Error('Cannot encrypt and add emails to the database', { cause: error });\n }\n};\n\n/**\n * Decrypts the given email\n *\n * @param indexKey - The symmetric CryptoKey key for protecting database\n * @param encryptedEmail - The encrypted email\n * @returns The decrypted email\n */\nconst decryptEmail = async (indexKey: CryptoKey, encryptedEmail: StoredEmail): Promise<Email> => {\n try {\n const aux = getAux(encryptedEmail.params, false);\n const email = await decryptEmailSymmetrically(indexKey, aux, encryptedEmail.enc);\n return { body: email, params: encryptedEmail.params, id: encryptedEmail.id };\n } catch (error) {\n throw new Error('Cannot decrypt the given email', { cause: error });\n }\n};\n\n/**\n * Fetches the email from the database and decrypts it\n *\n * @param emailID - The email identifier\n * @param indexKey - The symmetric CryptoKey key for protecting database\n * @param encryptedEmail - The encrypted email\n * @returns The decrypted email\n */\nexport const getAndDecryptEmail = async (emailID: string, indexKey: CryptoKey, esDB: MailDB): Promise<Email> => {\n try {\n const encryptedEmail = await esDB.get(DB_LABEL, emailID);\n if (!encryptedEmail) {\n throw new Error(`DB cannot find email with id ${emailID}`);\n }\n return decryptEmail(indexKey, encryptedEmail);\n } catch (error) {\n throw new Error(`Cannot fetch the email ${emailID} from the database`, { cause: error });\n }\n};\n\n/**\n * Fetches all email from the database and decrypts them\n *\n * @param indexKey - The symmetric CryptoKey key for protecting database\n * @param esDB - The database\n * @returns The decrypted emails\n */\nexport const getAndDecryptAllEmails = async (indexKey: CryptoKey, esDB: MailDB): Promise<Email[]> => {\n try {\n const encryptedEmails = await esDB.getAll(DB_LABEL);\n\n const decryptedEmails = await Promise.all(\n encryptedEmails.map(async (encEmail) => {\n const aux = getAux(encEmail.params, false);\n const body = await decryptEmailSymmetrically(indexKey, aux, encEmail.enc);\n return { body, params: encEmail.params, id: encEmail.id };\n }),\n );\n\n return decryptedEmails.filter((email): email is Email => email !== null);\n } catch (error) {\n throw new Error('Cannot fetch and decrypt all emails from the database', { cause: error });\n }\n};\n\n/**\n * Deletes the email from the database\n *\n * @param emailID - The email identifier\n * @param esDB - The database\n */\nexport const deleteEmail = async (emailID: string, esDB: MailDB): Promise<void> => {\n await esDB.delete(DB_LABEL, emailID);\n};\n\n/**\n * Returns the number of stored email\n *\n * @param esDB - The database\n * @returns The number of stored emails\n */\nexport const getEmailCount = async (esDB: MailDB): Promise<number> => {\n return await esDB.count(DB_LABEL);\n};\n\n/**\n * Removes the given number of oldests emails from the database\n *\n * @param emailsToDelete - The number of emails to delete\n * @param esDB - The database\n */\nexport const deleteOldestEmails = async (emailsToDelete: number, esDB: MailDB): Promise<void> => {\n try {\n const tx = esDB.transaction(DB_LABEL, 'readwrite');\n const index = tx.store.index('byTime');\n\n let cursor = await index.openCursor();\n let deletedCount = 0;\n\n while (cursor && deletedCount < emailsToDelete) {\n await cursor.delete();\n deletedCount++;\n cursor = await cursor.continue();\n }\n\n await tx.done;\n } catch (error) {\n throw new Error(`Cannot delete ${emailsToDelete} oldests emails from the database`, { cause: error });\n }\n};\n\n/**\n * Enforces the maximum email number in the database\n *\n * @param esDB - The database\n * @param max - The maximum allowed number of emails\n */\nexport const enforceMaxEmailNumber = async (esDB: MailDB, max: number): Promise<void> => {\n try {\n const currentCount = await getEmailCount(esDB);\n if (currentCount <= max) {\n return;\n }\n await deleteOldestEmails(currentCount - max, esDB);\n } catch (error) {\n throw new Error(`Cannot enforce the maximum of ${max} emails on the database`, { cause: error });\n }\n};\n\n/**\n * Fetches all emails from the database, decrypts them and sortes the results in the specified order\n *\n * @param esDB - The database\n * @param indexKey - The symmetric CryptoKey key for protecting database\n * @param direction - The order of sorting. If 'next' - oldest first, if 'prev' - newest first\n * @returns Decryped emails in the specified order\n */\nconst fetchEmails = async (esDB: MailDB, indexKey: CryptoKey, direction: 'next' | 'prev'): Promise<Email[]> => {\n try {\n const tx = esDB.transaction(DB_LABEL, 'readonly');\n const index = tx.store.index('byTime');\n\n const encryptedEmails: StoredEmail[] = [];\n let cursor = await index.openCursor(null, direction);\n\n while (cursor) {\n encryptedEmails.push(cursor.value);\n cursor = await cursor.continue();\n }\n\n const emails = await Promise.all(encryptedEmails.map((encryptedEmail) => decryptEmail(indexKey, encryptedEmail)));\n\n return emails;\n } catch (error) {\n throw new Error('Cannot fetch emails from database', { cause: error });\n }\n};\n\n/**\n * Fetches all emails from the database, decrypts them and sortes the results based on the creation time (newest first)\n *\n * @param esDB - The database\n * @param indexKey - The symmetric CryptoKey key for protecting database\n * @returns The number of stored emails\n */\nexport const getAllEmailsSortedNewestFirst = async (esDB: MailDB, indexKey: CryptoKey): Promise<Email[]> => {\n return fetchEmails(esDB, indexKey, 'prev');\n};\n\n/**\n * Fetches all emails from the database, decrypts them and sortes the results based on the creation time (oldest first)\n *\n * @param esDB - The database\n * @param indexKey - The symmetric CryptoKey key for protecting database\n * @returns The number of stored emails\n */\nexport const getAllEmailsSortedOldestFirst = async (esDB: MailDB, indexKey: CryptoKey): Promise<Email[]> => {\n return fetchEmails(esDB, indexKey, 'next');\n};\n\n/**\n * Fetches a batch of emails from the database, decrypts them and sortes the results based on the creation time (newest first)\n *\n * @param esDB - The database\n * @param indexKey - The symmetric CryptoKey key for protecting database\n * @param batchSize - The size of the batch\n * @param startCursor - The starting point (optional). If not given, starts from the beginning\n * @returns The number of stored emails\n */\nexport const getEmailBatch = async (\n esDB: MailDB,\n indexKey: CryptoKey,\n batchSize: number,\n startCursor?: IDBValidKey,\n): Promise<{ emails: Email[]; nextCursor?: IDBValidKey }> => {\n try {\n const tx = esDB.transaction(DB_LABEL, 'readonly');\n const index = tx.store.index('byTime');\n\n const encryptedEmails: StoredEmail[] = [];\n let cursor;\n\n if (startCursor) {\n const range = IDBKeyRange.upperBound(startCursor, true);\n cursor = await index.openCursor(range, 'prev');\n } else {\n cursor = await index.openCursor(null, 'prev');\n }\n\n let count = 0;\n let nextCursor: IDBValidKey | undefined;\n\n while (cursor && count < batchSize) {\n encryptedEmails.push(cursor.value);\n nextCursor = cursor.key;\n count++;\n cursor = await cursor.continue();\n }\n\n const emails = await Promise.all(encryptedEmails.map((encryptedEmail) => decryptEmail(indexKey, encryptedEmail)));\n\n return {\n emails,\n nextCursor: count === batchSize ? nextCursor : undefined,\n };\n } catch (error) {\n throw new Error(`Cannot fetch email batch of ${batchSize} from the database`, { cause: error });\n }\n};\n","import { MAX_CACHE_SIZE, MAX_EMAIL_PER_BATCH } from '../constants';\nimport { getEmailBatch, getAllEmailsSortedNewestFirst, getEmailCount, MailDB } from './indexedDB';\nimport { Email, MailCache } from '../types';\nimport { emailToBinary } from '../email-crypto';\n\n/**\n * Estimates the email size in the memory\n *\n * @param email - The email\n * @returns The estimation of the email size\n */\nfunction sizeOfEmail(email: Email): number {\n return emailToBinary(email).byteLength;\n}\n\n/**\n * Creates an empty cache variable\n *\n * @returns The empty cache\n */\nfunction createEmptyCache(): MailCache<Email> {\n return {\n esCache: new Map(),\n cacheSize: 0,\n isCacheLimited: false,\n isCacheReady: true,\n };\n}\n\n/**\n * Fetches all emails from the database in batches and cahces them\n *\n * @param indexKey - The symmetric CryptoKey key for protecting database\n * @param esCache - The cache to add emails too\n * @param esDB - The database\n */\nexport const createCacheFromDB = async (indexKey: CryptoKey, esDB: MailDB): Promise<MailCache<Email>> => {\n const esCache = createEmptyCache();\n esCache.isCacheReady = false;\n try {\n const count = await getEmailCount(esDB);\n if (!count) {\n esCache.isCacheReady = true;\n return esCache;\n }\n\n if (count <= MAX_EMAIL_PER_BATCH) {\n const emails = await getAllEmailsSortedNewestFirst(esDB, indexKey);\n addEmailsToCache(emails, esCache);\n } else {\n let nextCursor: IDBValidKey | undefined = undefined;\n\n let cacheFull = false;\n while (!cacheFull) {\n const { emails, nextCursor: newCursor }: { emails: Email[]; nextCursor?: IDBValidKey } = await getEmailBatch(\n esDB,\n indexKey,\n MAX_EMAIL_PER_BATCH,\n nextCursor,\n );\n if (!newCursor || !emails.length) break;\n nextCursor = newCursor;\n\n const success = addEmailsToCache(emails, esCache);\n if (!success) cacheFull = true;\n }\n }\n return esCache;\n } catch (error) {\n throw new Error(`Email caching failed: ${error}`, { cause: error });\n }\n};\n\n/**\n * Gets an email from the cache\n *\n * @param emailID - The email identifier\n * @param esCache - The email cache\n * @returns The found email or throws an error\n */\nexport const getEmailFromCache = async (emailID: string, esCache: MailCache<Email>): Promise<Email> => {\n const email = esCache.esCache.get(emailID);\n if (!email) {\n throw new Error(`Email not found in cache for ID: ${emailID}`);\n }\n return email;\n};\n\n/**\n * Removes the email from cache\n *\n * @param emailID - The email identifier\n * @param esCache - The email cache\n */\nexport const deleteEmailFromCache = async (emailID: string, esCache: MailCache<Email>): Promise<void> => {\n try {\n const email = await getEmailFromCache(emailID, esCache);\n const size = sizeOfEmail(email);\n const removed = esCache.esCache.delete(emailID);\n if (removed) esCache.cacheSize -= size;\n } catch (error) {\n throw new Error(`Failed to delete email with ID ${emailID}`, { cause: error });\n }\n};\n\n/**\n * Adds emails to the cache\n *\n * @param emails - The emails to add\n * @param esCache - The email cache\n * @returns TRUE if all emails were added sucessfully, or FALSE and error reason.\n */\nexport function addEmailsToCache(emails: Email[], esCache: MailCache<Email>): { success: boolean; reason?: string } {\n try {\n for (const email of emails) {\n const result = addEmailToCache(email, esCache);\n if (!result.success) return result;\n }\n return { success: true };\n } catch (error) {\n throw new Error('Failed to add emails to the cache', { cause: error });\n }\n}\n\n/**\n * Adds email to the cache\n *\n * @param email - The email to add\n * @param esCache - The email cache\n * @returns TRUE if the email was added sucessfully, or FALSE and error reason.\n */\nexport const addEmailToCache = (email: Email, esCache: MailCache<Email>): { success: boolean; reason?: string } => {\n try {\n if (esCache.esCache.has(email.id)) {\n return { success: false, reason: 'email already exists in cache' };\n }\n\n const emailSize = sizeOfEmail(email);\n\n if (esCache.cacheSize + emailSize > MAX_CACHE_SIZE) {\n esCache.isCacheLimited = true;\n return { success: false, reason: 'hit cache limit' };\n }\n\n esCache.esCache.set(email.id, email);\n esCache.cacheSize += emailSize;\n\n return { success: true };\n } catch (error) {\n throw new Error('Failed to add email to the cache', { cause: error });\n }\n};\n","import { Index, DefaultSearchResults } from 'flexsearch';\nimport type { IndexOptions } from 'flexsearch';\nimport { Email, MailCache, EmailSearchResult } from '../types';\n\ntype ExtendedIndexOptions = IndexOptions & {\n minlength?: number;\n resolution?: number;\n optimize?: boolean;\n fastupdate?: boolean;\n cache?: boolean;\n};\n\nconst SUBJECT_OPTIONS: ExtendedIndexOptions = {\n preset: 'match',\n tokenize: 'forward',\n resolution: 9,\n minlength: 2,\n optimize: true,\n fastupdate: true,\n cache: true,\n};\nconst BODY_OPTIONS: ExtendedIndexOptions = {\n ...SUBJECT_OPTIONS,\n minlength: 3,\n resolution: 6,\n};\n\nconst FROM_OPTIONS: ExtendedIndexOptions = {\n ...SUBJECT_OPTIONS,\n tokenize: 'strict',\n minlength: 1,\n};\n\nconst TO_OPTIONS: ExtendedIndexOptions = {\n ...SUBJECT_OPTIONS,\n tokenize: 'strict',\n minlength: 1,\n};\n\nexport interface EmailSearchIndex {\n subjectIndex: Index;\n bodyIndex: Index;\n fromIndex: Index;\n toIndex: Index;\n isReady: boolean;\n}\n\n/**\n * Creates new email search index\n *\n * @returns The email search index\n */\nconst createSearchIndex = (): EmailSearchIndex => ({\n subjectIndex: new Index(SUBJECT_OPTIONS),\n bodyIndex: new Index(BODY_OPTIONS),\n fromIndex: new Index(FROM_OPTIONS),\n toIndex: new Index(TO_OPTIONS),\n isReady: false,\n});\n\n/**\n * Adds the given email to the email search index\n *\n * @param email - The email to add\n * @param searchIndex - The email search index\n */\nexport const addEmailToSearchIndex = (email: Email, searchIndex: EmailSearchIndex): void => {\n try {\n const emailId = email.id;\n\n if (email.params.subject) {\n searchIndex.subjectIndex.add(emailId, email.params.subject);\n }\n\n if (email.body?.text) {\n searchIndex.bodyIndex.add(emailId, email.body.text);\n }\n\n if (email.params.sender) {\n const senderText = `${email.params.sender.name || ''} ${email.params.sender.email || ''}`.trim();\n searchIndex.fromIndex.add(emailId, senderText);\n }\n\n const recipientsList = email.params.recipients?.length ? email.params.recipients : [email.params.recipient];\n\n const recipientsText = recipientsList\n .map((recipient) => `${recipient.name || ''} ${recipient.email || ''}`.trim())\n .join(' ');\n searchIndex.toIndex.add(emailId, recipientsText);\n } catch (error) {\n throw new Error('Failed to add email to the search index', { cause: error });\n }\n};\n\n/**\n * Removes the email from the email search index\n *\n * @param emailID - The email identifier\n * @param searchIndex - The email search index\n */\nexport const removeEmailFromSearchIndex = (emailID: string, searchIndex: EmailSearchIndex): void => {\n try {\n searchIndex.subjectIndex.remove(emailID);\n searchIndex.bodyIndex.remove(emailID);\n searchIndex.fromIndex.remove(emailID);\n searchIndex.toIndex.remove(emailID);\n } catch (error) {\n throw new Error(`Failed to remove email with ID ${emailID} from the search index`, { cause: error });\n }\n};\n\n/**\n * Buils the email search index from the email cache\n *\n * @param esCache - The email cache\n * @returns The email search index\n */\nexport const buildSearchIndexFromCache = async (esCache: MailCache<Email>): Promise<EmailSearchIndex> => {\n try {\n const searchIndex = createSearchIndex();\n searchIndex.isReady = false;\n\n for (const email of esCache.esCache.values()) {\n addEmailToSearchIndex(email, searchIndex);\n }\n\n searchIndex.isReady = true;\n return searchIndex;\n } catch (error) {\n throw new Error('Failed build an email search index from the cache', { cause: error });\n }\n};\n\nexport interface SearchOptions {\n fields?: ('subject' | 'body' | 'from' | 'to')[];\n limit?: number;\n boost?: {\n subject?: number;\n body?: number;\n from?: number;\n to?: number;\n };\n}\n\n/**\n * Searches in teh\n *\n * @param query - The string to search for\n * @param esCache - The email cache\n * @param searchIndex - The email search index\n * @param opetions - The optional search limitations\n * @returns The result of the email search (emails ans their corresponding result weights)\n */\nexport const searchEmails = async (\n query: string,\n esCache: MailCache<Email>,\n searchIndex: EmailSearchIndex,\n options: SearchOptions = {},\n): Promise<EmailSearchResult[]> => {\n try {\n if (!searchIndex.isReady || !query.trim()) {\n return [];\n }\n\n const {\n fields = ['subject', 'body', 'from', 'to'],\n limit = 50,\n boost = { subject: 3, body: 1, from: 2, to: 2 },\n } = options;\n\n const results = new Map<string, number>();\n\n const searchPromises = fields.map(async (field) => {\n let fieldResults: DefaultSearchResults;\n\n switch (field) {\n case 'subject':\n fieldResults = await searchIndex.subjectIndex.searchAsync(query);\n break;\n case 'body':\n fieldResults = await searchIndex.bodyIndex.searchAsync(query);\n break;\n case 'from':\n fieldResults = await searchIndex.fromIndex.searchAsync(query);\n break;\n case 'to':\n fieldResults = await searchIndex.toIndex.searchAsync(query);\n break;\n default:\n return;\n }\n\n const fieldBoost = boost[field] || 1;\n\n fieldResults.forEach((emailId) => {\n const currentScore = results.get(String(emailId)) || 0;\n results.set(String(emailId), currentScore + fieldBoost);\n });\n });\n\n await Promise.all(searchPromises);\n\n const emailResults: EmailSearchResult[] = [];\n\n for (const [emailId, score] of results) {\n const email = esCache.esCache.get(emailId);\n if (email) {\n emailResults.push({ email, score });\n }\n }\n emailResults.sort((a, b) => (b.score || 0) - (a.score || 0));\n return emailResults.slice(0, limit);\n } catch (error) {\n throw new Error('Email search failed', { cause: error });\n }\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"email-search.mjs","names":[],"sources":["../src/email-search/indexedDB.ts","../src/email-search/mailCache.ts","../src/email-search/search.ts"],"sourcesContent":["import { DBSchema, openDB, deleteDB, IDBPDatabase } from 'idb';\nimport { StoredEmail, Email } from '../types';\nimport { decryptEmailSymmetrically, encryptEmailContentSymmetricallyWithKey } from '../email-crypto/core';\nimport { deriveSymmetricKeyFromContext } from '../derive-key';\nimport { CONTEXT_INDEX, DB_LABEL, DB_VERSION } from '../constants';\nimport { getAux } from '../email-crypto';\n\nexport type MailDB = IDBPDatabase<EncryptedSearchDB>;\n\nexport interface EncryptedSearchDB extends DBSchema {\n email: {\n key: string;\n value: StoredEmail;\n indexes: { byTime: number[] };\n };\n}\n\n/**\n * Returns IndexedDB database name for the given user\n *\n * @param userID - The user ID\n * @returns The database name\n */\nconst getDatabaseName = (userID: string): string => {\n return `ES:${userID}:DB`;\n};\n\n/**\n * Opens IndexedDB database for the given user\n *\n * @param userID - The user ID\n * @returns The database\n */\nexport const openDatabase = async (userID: string): Promise<MailDB> => {\n try {\n const dbName = getDatabaseName(userID);\n return openDB<EncryptedSearchDB>(dbName, DB_VERSION, {\n upgrade(db) {\n if (!db.objectStoreNames.contains(DB_LABEL)) {\n const store = db.createObjectStore(DB_LABEL, { keyPath: 'id' });\n store.createIndex('byTime', 'params.createdAt');\n }\n },\n });\n } catch (error) {\n throw new Error(`Cannot open a database for the user ${userID}`, { cause: error });\n }\n};\n\n/**\n * Closes the IndexedDB database\n *\n * @param esDB - The database\n */\nexport const closeDatabase = (esDB: MailDB): void => {\n return esDB.close();\n};\n\n/**\n * Deletes IndexedDB database for the given user\n *\n * @param userID - The user ID\n * @returns The database\n */\nexport const deleteDatabase = async (userID: string): Promise<void> => {\n const dbName = getDatabaseName(userID);\n return deleteDB(dbName);\n};\n\n/**\n * Derives database encryption key for the given user\n *\n * @param userID - The user ID\n * @returns The symmetric key for protecting database\n */\nexport const deriveIndexKey = async (baseKey: Uint8Array): Promise<Uint8Array> => {\n return deriveSymmetricKeyFromContext(CONTEXT_INDEX, baseKey);\n};\n\n/**\n * Encrypts the given email and stores it in the IndexedDB database\n *\n * @param newEmailToStore - The email for storing\n * @param indexKey - The symmetric key for protecting database\n * @param esDB - The database\n */\nexport const encryptAndStoreEmail = async (\n newEmailToStore: Email,\n indexKey: Uint8Array,\n esDB: MailDB,\n): Promise<void> => {\n try {\n const aux = getAux(newEmailToStore.params, false);\n const enc = await encryptEmailContentSymmetricallyWithKey(newEmailToStore.body, indexKey, aux, newEmailToStore.id);\n const encryptedEmail: StoredEmail = { enc, params: newEmailToStore.params, id: newEmailToStore.id };\n await esDB.put(DB_LABEL, encryptedEmail);\n } catch (error) {\n throw new Error('Cannot encrypt and add the given email to the database', { cause: error });\n }\n};\n\n/**\n * Encrypts the given set of emails and stores it in the IndexedDB database\n *\n * @param newEmailsToStore - The set of emails for storing\n * @param indexKey - The symmetric key key for protecting database\n * @param esDB - The database\n */\nexport const encryptAndStoreManyEmail = async (\n newEmailsToStore: Email[],\n indexKey: Uint8Array,\n esDB: MailDB,\n): Promise<void> => {\n try {\n const encryptedEmails = await Promise.all(\n newEmailsToStore.map(async (email: Email) => {\n const aux = getAux(email.params, false);\n const enc = await encryptEmailContentSymmetricallyWithKey(email.body, indexKey, aux, email.id);\n\n return { enc, params: email.params, id: email.id };\n }),\n );\n\n const tr = esDB.transaction(DB_LABEL, 'readwrite');\n await Promise.all([...encryptedEmails.map((encEmail) => tr.store.put(encEmail)), tr.done]);\n } catch (error) {\n throw new Error('Cannot encrypt and add emails to the database', { cause: error });\n }\n};\n\n/**\n * Decrypts the given email\n *\n * @param indexKey - The symmetric key key for protecting database\n * @param encryptedEmail - The encrypted email\n * @returns The decrypted email\n */\nconst decryptEmail = async (indexKey: Uint8Array, encryptedEmail: StoredEmail): Promise<Email> => {\n try {\n const aux = getAux(encryptedEmail.params, false);\n const email = await decryptEmailSymmetrically(indexKey, aux, encryptedEmail.enc);\n return { body: email, params: encryptedEmail.params, id: encryptedEmail.id };\n } catch (error) {\n throw new Error('Cannot decrypt the given email', { cause: error });\n }\n};\n\n/**\n * Fetches the email from the database and decrypts it\n *\n * @param emailID - The email identifier\n * @param indexKey - The symmetric key key for protecting database\n * @param encryptedEmail - The encrypted email\n * @returns The decrypted email\n */\nexport const getAndDecryptEmail = async (emailID: string, indexKey: Uint8Array, esDB: MailDB): Promise<Email> => {\n try {\n const encryptedEmail = await esDB.get(DB_LABEL, emailID);\n if (!encryptedEmail) {\n throw new Error(`DB cannot find email with id ${emailID}`);\n }\n return decryptEmail(indexKey, encryptedEmail);\n } catch (error) {\n throw new Error(`Cannot fetch the email ${emailID} from the database`, { cause: error });\n }\n};\n\n/**\n * Fetches all email from the database and decrypts them\n *\n * @param indexKey - The symmetric key key for protecting database\n * @param esDB - The database\n * @returns The decrypted emails\n */\nexport const getAndDecryptAllEmails = async (indexKey: Uint8Array, esDB: MailDB): Promise<Email[]> => {\n try {\n const encryptedEmails = await esDB.getAll(DB_LABEL);\n\n const decryptedEmails = await Promise.all(\n encryptedEmails.map(async (encEmail) => {\n const aux = getAux(encEmail.params, false);\n const body = await decryptEmailSymmetrically(indexKey, aux, encEmail.enc);\n return { body, params: encEmail.params, id: encEmail.id };\n }),\n );\n\n return decryptedEmails.filter((email): email is Email => email !== null);\n } catch (error) {\n throw new Error('Cannot fetch and decrypt all emails from the database', { cause: error });\n }\n};\n\n/**\n * Deletes the email from the database\n *\n * @param emailID - The email identifier\n * @param esDB - The database\n */\nexport const deleteEmail = async (emailID: string, esDB: MailDB): Promise<void> => {\n await esDB.delete(DB_LABEL, emailID);\n};\n\n/**\n * Returns the number of stored email\n *\n * @param esDB - The database\n * @returns The number of stored emails\n */\nexport const getEmailCount = async (esDB: MailDB): Promise<number> => {\n return await esDB.count(DB_LABEL);\n};\n\n/**\n * Removes the given number of oldests emails from the database\n *\n * @param emailsToDelete - The number of emails to delete\n * @param esDB - The database\n */\nexport const deleteOldestEmails = async (emailsToDelete: number, esDB: MailDB): Promise<void> => {\n try {\n const tx = esDB.transaction(DB_LABEL, 'readwrite');\n const index = tx.store.index('byTime');\n\n let cursor = await index.openCursor();\n let deletedCount = 0;\n\n while (cursor && deletedCount < emailsToDelete) {\n await cursor.delete();\n deletedCount++;\n cursor = await cursor.continue();\n }\n\n await tx.done;\n } catch (error) {\n throw new Error(`Cannot delete ${emailsToDelete} oldests emails from the database`, { cause: error });\n }\n};\n\n/**\n * Enforces the maximum email number in the database\n *\n * @param esDB - The database\n * @param max - The maximum allowed number of emails\n */\nexport const enforceMaxEmailNumber = async (esDB: MailDB, max: number): Promise<void> => {\n try {\n const currentCount = await getEmailCount(esDB);\n if (currentCount <= max) {\n return;\n }\n await deleteOldestEmails(currentCount - max, esDB);\n } catch (error) {\n throw new Error(`Cannot enforce the maximum of ${max} emails on the database`, { cause: error });\n }\n};\n\n/**\n * Fetches all emails from the database, decrypts them and sortes the results in the specified order\n *\n * @param esDB - The database\n * @param indexKey - The symmetric key key for protecting database\n * @param direction - The order of sorting. If 'next' - oldest first, if 'prev' - newest first\n * @returns Decryped emails in the specified order\n */\nconst fetchEmails = async (esDB: MailDB, indexKey: Uint8Array, direction: 'next' | 'prev'): Promise<Email[]> => {\n try {\n const tx = esDB.transaction(DB_LABEL, 'readonly');\n const index = tx.store.index('byTime');\n\n const encryptedEmails: StoredEmail[] = [];\n let cursor = await index.openCursor(null, direction);\n\n while (cursor) {\n encryptedEmails.push(cursor.value);\n cursor = await cursor.continue();\n }\n\n const emails = await Promise.all(encryptedEmails.map((encryptedEmail) => decryptEmail(indexKey, encryptedEmail)));\n\n return emails;\n } catch (error) {\n throw new Error('Cannot fetch emails from database', { cause: error });\n }\n};\n\n/**\n * Fetches all emails from the database, decrypts them and sortes the results based on the creation time (newest first)\n *\n * @param esDB - The database\n * @param indexKey - The symmetric Uint8Array key for protecting database\n * @returns The number of stored emails\n */\nexport const getAllEmailsSortedNewestFirst = async (esDB: MailDB, indexKey: Uint8Array): Promise<Email[]> => {\n return fetchEmails(esDB, indexKey, 'prev');\n};\n\n/**\n * Fetches all emails from the database, decrypts them and sortes the results based on the creation time (oldest first)\n *\n * @param esDB - The database\n * @param indexKey - The symmetric key for protecting database\n * @returns The number of stored emails\n */\nexport const getAllEmailsSortedOldestFirst = async (esDB: MailDB, indexKey: Uint8Array): Promise<Email[]> => {\n return fetchEmails(esDB, indexKey, 'next');\n};\n\n/**\n * Fetches a batch of emails from the database, decrypts them and sortes the results based on the creation time (newest first)\n *\n * @param esDB - The database\n * @param indexKey - The symmetric key for protecting database\n * @param batchSize - The size of the batch\n * @param startCursor - The starting point (optional). If not given, starts from the beginning\n * @returns The number of stored emails\n */\nexport const getEmailBatch = async (\n esDB: MailDB,\n indexKey: Uint8Array,\n batchSize: number,\n startCursor?: IDBValidKey,\n): Promise<{ emails: Email[]; nextCursor?: IDBValidKey }> => {\n try {\n const tx = esDB.transaction(DB_LABEL, 'readonly');\n const index = tx.store.index('byTime');\n\n const encryptedEmails: StoredEmail[] = [];\n let cursor;\n\n if (startCursor) {\n const range = IDBKeyRange.upperBound(startCursor, true);\n cursor = await index.openCursor(range, 'prev');\n } else {\n cursor = await index.openCursor(null, 'prev');\n }\n\n let count = 0;\n let nextCursor: IDBValidKey | undefined;\n\n while (cursor && count < batchSize) {\n encryptedEmails.push(cursor.value);\n nextCursor = cursor.key;\n count++;\n cursor = await cursor.continue();\n }\n\n const emails = await Promise.all(encryptedEmails.map((encryptedEmail) => decryptEmail(indexKey, encryptedEmail)));\n\n return {\n emails,\n nextCursor: count === batchSize ? nextCursor : undefined,\n };\n } catch (error) {\n throw new Error(`Cannot fetch email batch of ${batchSize} from the database`, { cause: error });\n }\n};\n","import { MAX_CACHE_SIZE, MAX_EMAIL_PER_BATCH } from '../constants';\nimport { getEmailBatch, getAllEmailsSortedNewestFirst, getEmailCount, MailDB } from './indexedDB';\nimport { Email, MailCache } from '../types';\nimport { emailToBinary } from '../email-crypto';\n\n/**\n * Estimates the email size in the memory\n *\n * @param email - The email\n * @returns The estimation of the email size\n */\nfunction sizeOfEmail(email: Email): number {\n return emailToBinary(email).byteLength;\n}\n\n/**\n * Creates an empty cache variable\n *\n * @returns The empty cache\n */\nfunction createEmptyCache(): MailCache<Email> {\n return {\n esCache: new Map(),\n cacheSize: 0,\n isCacheLimited: false,\n isCacheReady: true,\n };\n}\n\n/**\n * Fetches all emails from the database in batches and cahces them\n *\n * @param indexKey - The symmetric key for protecting database\n * @param esCache - The cache to add emails too\n * @param esDB - The database\n */\nexport const createCacheFromDB = async (indexKey: Uint8Array, esDB: MailDB): Promise<MailCache<Email>> => {\n const esCache = createEmptyCache();\n esCache.isCacheReady = false;\n try {\n const count = await getEmailCount(esDB);\n if (!count) {\n esCache.isCacheReady = true;\n return esCache;\n }\n\n if (count <= MAX_EMAIL_PER_BATCH) {\n const emails = await getAllEmailsSortedNewestFirst(esDB, indexKey);\n addEmailsToCache(emails, esCache);\n } else {\n let nextCursor: IDBValidKey | undefined = undefined;\n\n let cacheFull = false;\n while (!cacheFull) {\n const { emails, nextCursor: newCursor }: { emails: Email[]; nextCursor?: IDBValidKey } = await getEmailBatch(\n esDB,\n indexKey,\n MAX_EMAIL_PER_BATCH,\n nextCursor,\n );\n if (!newCursor || !emails.length) break;\n nextCursor = newCursor;\n\n const success = addEmailsToCache(emails, esCache);\n if (!success) cacheFull = true;\n }\n }\n return esCache;\n } catch (error) {\n throw new Error(`Email caching failed: ${error}`, { cause: error });\n }\n};\n\n/**\n * Gets an email from the cache\n *\n * @param emailID - The email identifier\n * @param esCache - The email cache\n * @returns The found email or throws an error\n */\nexport const getEmailFromCache = async (emailID: string, esCache: MailCache<Email>): Promise<Email> => {\n const email = esCache.esCache.get(emailID);\n if (!email) {\n throw new Error(`Email not found in cache for ID: ${emailID}`);\n }\n return email;\n};\n\n/**\n * Removes the email from cache\n *\n * @param emailID - The email identifier\n * @param esCache - The email cache\n */\nexport const deleteEmailFromCache = async (emailID: string, esCache: MailCache<Email>): Promise<void> => {\n try {\n const email = await getEmailFromCache(emailID, esCache);\n const size = sizeOfEmail(email);\n const removed = esCache.esCache.delete(emailID);\n if (removed) esCache.cacheSize -= size;\n } catch (error) {\n throw new Error(`Failed to delete email with ID ${emailID}`, { cause: error });\n }\n};\n\n/**\n * Adds emails to the cache\n *\n * @param emails - The emails to add\n * @param esCache - The email cache\n * @returns TRUE if all emails were added sucessfully, or FALSE and error reason.\n */\nexport function addEmailsToCache(emails: Email[], esCache: MailCache<Email>): { success: boolean; reason?: string } {\n try {\n for (const email of emails) {\n const result = addEmailToCache(email, esCache);\n if (!result.success) return result;\n }\n return { success: true };\n } catch (error) {\n throw new Error('Failed to add emails to the cache', { cause: error });\n }\n}\n\n/**\n * Adds email to the cache\n *\n * @param email - The email to add\n * @param esCache - The email cache\n * @returns TRUE if the email was added sucessfully, or FALSE and error reason.\n */\nexport const addEmailToCache = (email: Email, esCache: MailCache<Email>): { success: boolean; reason?: string } => {\n try {\n if (esCache.esCache.has(email.id)) {\n return { success: false, reason: 'email already exists in cache' };\n }\n\n const emailSize = sizeOfEmail(email);\n\n if (esCache.cacheSize + emailSize > MAX_CACHE_SIZE) {\n esCache.isCacheLimited = true;\n return { success: false, reason: 'hit cache limit' };\n }\n\n esCache.esCache.set(email.id, email);\n esCache.cacheSize += emailSize;\n\n return { success: true };\n } catch (error) {\n throw new Error('Failed to add email to the cache', { cause: error });\n }\n};\n","import { Index, DefaultSearchResults } from 'flexsearch';\nimport type { IndexOptions } from 'flexsearch';\nimport { Email, MailCache, EmailSearchResult } from '../types';\n\ntype ExtendedIndexOptions = IndexOptions & {\n minlength?: number;\n resolution?: number;\n optimize?: boolean;\n fastupdate?: boolean;\n cache?: boolean;\n};\n\nconst SUBJECT_OPTIONS: ExtendedIndexOptions = {\n preset: 'match',\n tokenize: 'forward',\n resolution: 9,\n minlength: 2,\n optimize: true,\n fastupdate: true,\n cache: true,\n};\nconst BODY_OPTIONS: ExtendedIndexOptions = {\n ...SUBJECT_OPTIONS,\n minlength: 3,\n resolution: 6,\n};\n\nconst FROM_OPTIONS: ExtendedIndexOptions = {\n ...SUBJECT_OPTIONS,\n tokenize: 'strict',\n minlength: 1,\n};\n\nconst TO_OPTIONS: ExtendedIndexOptions = {\n ...SUBJECT_OPTIONS,\n tokenize: 'strict',\n minlength: 1,\n};\n\nexport interface EmailSearchIndex {\n subjectIndex: Index;\n bodyIndex: Index;\n fromIndex: Index;\n toIndex: Index;\n isReady: boolean;\n}\n\n/**\n * Creates new email search index\n *\n * @returns The email search index\n */\nconst createSearchIndex = (): EmailSearchIndex => ({\n subjectIndex: new Index(SUBJECT_OPTIONS),\n bodyIndex: new Index(BODY_OPTIONS),\n fromIndex: new Index(FROM_OPTIONS),\n toIndex: new Index(TO_OPTIONS),\n isReady: false,\n});\n\n/**\n * Adds the given email to the email search index\n *\n * @param email - The email to add\n * @param searchIndex - The email search index\n */\nexport const addEmailToSearchIndex = (email: Email, searchIndex: EmailSearchIndex): void => {\n try {\n const emailId = email.id;\n\n if (email.params.subject) {\n searchIndex.subjectIndex.add(emailId, email.params.subject);\n }\n\n if (email.body?.text) {\n searchIndex.bodyIndex.add(emailId, email.body.text);\n }\n\n if (email.params.sender) {\n const senderText = `${email.params.sender.name || ''} ${email.params.sender.email || ''}`.trim();\n searchIndex.fromIndex.add(emailId, senderText);\n }\n\n const recipientsList = email.params.recipients?.length ? email.params.recipients : [email.params.recipient];\n\n const recipientsText = recipientsList\n .map((recipient) => `${recipient.name || ''} ${recipient.email || ''}`.trim())\n .join(' ');\n searchIndex.toIndex.add(emailId, recipientsText);\n } catch (error) {\n throw new Error('Failed to add email to the search index', { cause: error });\n }\n};\n\n/**\n * Removes the email from the email search index\n *\n * @param emailID - The email identifier\n * @param searchIndex - The email search index\n */\nexport const removeEmailFromSearchIndex = (emailID: string, searchIndex: EmailSearchIndex): void => {\n try {\n searchIndex.subjectIndex.remove(emailID);\n searchIndex.bodyIndex.remove(emailID);\n searchIndex.fromIndex.remove(emailID);\n searchIndex.toIndex.remove(emailID);\n } catch (error) {\n throw new Error(`Failed to remove email with ID ${emailID} from the search index`, { cause: error });\n }\n};\n\n/**\n * Buils the email search index from the email cache\n *\n * @param esCache - The email cache\n * @returns The email search index\n */\nexport const buildSearchIndexFromCache = async (esCache: MailCache<Email>): Promise<EmailSearchIndex> => {\n try {\n const searchIndex = createSearchIndex();\n searchIndex.isReady = false;\n\n for (const email of esCache.esCache.values()) {\n addEmailToSearchIndex(email, searchIndex);\n }\n\n searchIndex.isReady = true;\n return searchIndex;\n } catch (error) {\n throw new Error('Failed build an email search index from the cache', { cause: error });\n }\n};\n\nexport interface SearchOptions {\n fields?: ('subject' | 'body' | 'from' | 'to')[];\n limit?: number;\n boost?: {\n subject?: number;\n body?: number;\n from?: number;\n to?: number;\n };\n}\n\n/**\n * Searches in teh\n *\n * @param query - The string to search for\n * @param esCache - The email cache\n * @param searchIndex - The email search index\n * @param opetions - The optional search limitations\n * @returns The result of the email search (emails ans their corresponding result weights)\n */\nexport const searchEmails = async (\n query: string,\n esCache: MailCache<Email>,\n searchIndex: EmailSearchIndex,\n options: SearchOptions = {},\n): Promise<EmailSearchResult[]> => {\n try {\n if (!searchIndex.isReady || !query.trim()) {\n return [];\n }\n\n const {\n fields = ['subject', 'body', 'from', 'to'],\n limit = 50,\n boost = { subject: 3, body: 1, from: 2, to: 2 },\n } = options;\n\n const results = new Map<string, number>();\n\n const searchPromises = fields.map(async (field) => {\n let fieldResults: DefaultSearchResults;\n\n switch (field) {\n case 'subject':\n fieldResults = await searchIndex.subjectIndex.searchAsync(query);\n break;\n case 'body':\n fieldResults = await searchIndex.bodyIndex.searchAsync(query);\n break;\n case 'from':\n fieldResults = await searchIndex.fromIndex.searchAsync(query);\n break;\n case 'to':\n fieldResults = await searchIndex.toIndex.searchAsync(query);\n break;\n default:\n return;\n }\n\n const fieldBoost = boost[field] || 1;\n\n fieldResults.forEach((emailId) => {\n const currentScore = results.get(String(emailId)) || 0;\n results.set(String(emailId), currentScore + fieldBoost);\n });\n });\n\n await Promise.all(searchPromises);\n\n const emailResults: EmailSearchResult[] = [];\n\n for (const [emailId, score] of results) {\n const email = esCache.esCache.get(emailId);\n if (email) {\n emailResults.push({ email, score });\n }\n }\n emailResults.sort((a, b) => (b.score || 0) - (a.score || 0));\n return emailResults.slice(0, limit);\n } catch (error) {\n throw new Error('Email search failed', { cause: error });\n }\n};\n"],"mappings":"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"}
@@ -2,9 +2,9 @@ import { AES_KEY_BIT_LENGTH, CONTEXT_ENC_KEYSTORE, CONTEXT_RECOVERY } from "./co
2
2
  import { a as importPublicKey, i as importPrivateKey, t as exportPrivateKey } from "./keys-BfcaiAOv.mjs";
3
3
  import { a as genMnemonic, c as publicKeyToBase64, f as uint8ArrayToBase64, l as UTF8ToUint8, o as mnemonicToBytes, u as base64ToUint8Array } from "./genID-3Er5IowC.mjs";
4
4
  import { n as getBytesFromData } from "./mac-ZpRlx8Fs.mjs";
5
- import { n as encryptSymmetrically, t as decryptSymmetrically } from "./aes-DSDxP8uF.mjs";
6
- import { o as deriveSymmetricCryptoKeyFromContext } from "./deriveKeysFromPassword-DJRWZ8Rw.mjs";
7
- import { t as generateEmailKeys } from "./emailKeys-Fp9WR3wl.mjs";
5
+ import { n as encryptSymmetrically, t as decryptSymmetrically } from "./aes-DCb9dJqb.mjs";
6
+ import { c as deriveSymmetricKeyFromContext } from "./deriveKeysFromPassword-XIwzErlL.mjs";
7
+ import { t as generateEmailKeys } from "./emailKeys-D4lp9NRv.mjs";
8
8
  import { KeystoreType } from "./types.mjs";
9
9
 
10
10
  //#region src/keystore-crypto/core.ts
@@ -76,7 +76,7 @@ async function decryptKeystoreContent(secretKey, encryptedKeystore) {
76
76
  */
77
77
  async function deriveRecoveryKey(recoveryCodes) {
78
78
  const recoverCodesArray = mnemonicToBytes(recoveryCodes);
79
- return deriveSymmetricCryptoKeyFromContext(CONTEXT_RECOVERY, getBytesFromData(AES_KEY_BIT_LENGTH / 8, recoverCodesArray));
79
+ return deriveSymmetricKeyFromContext(CONTEXT_RECOVERY, getBytesFromData(AES_KEY_BIT_LENGTH / 8, recoverCodesArray));
80
80
  }
81
81
  /**
82
82
  * Derives a secret key for protecting the encryption keystore
@@ -85,7 +85,7 @@ async function deriveRecoveryKey(recoveryCodes) {
85
85
  * @returns The derived secret key for protecting the encryption keystore
86
86
  */
87
87
  async function deriveEncryptionKeystoreKey(baseKey) {
88
- return deriveSymmetricCryptoKeyFromContext(CONTEXT_ENC_KEYSTORE, baseKey);
88
+ return deriveSymmetricKeyFromContext(CONTEXT_ENC_KEYSTORE, baseKey);
89
89
  }
90
90
 
91
91
  //#endregion
@@ -147,4 +147,4 @@ async function openRecoveryKeystore(recoveryCodes, encryptedKeystore) {
147
147
 
148
148
  //#endregion
149
149
  export { openEncryptionKeystore as n, openRecoveryKeystore as r, createEncryptionAndRecoveryKeystores as t };
150
- //# sourceMappingURL=emailEncryptionKey-27mIHh18.mjs.map
150
+ //# sourceMappingURL=emailEncryptionKey-B9xHw1h_.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emailEncryptionKey-B9xHw1h_.mjs","names":[],"sources":["../src/keystore-crypto/core.ts","../src/keystore-crypto/emailEncryptionKey.ts"],"sourcesContent":["import { encryptSymmetrically, decryptSymmetrically } from '../symmetric-crypto';\nimport { base64ToUint8Array, uint8ArrayToBase64, UTF8ToUint8, mnemonicToBytes, publicKeyToBase64 } from '../utils';\nimport { deriveSymmetricKeyFromContext } from '../derive-key';\nimport { CONTEXT_ENC_KEYSTORE, AES_KEY_BIT_LENGTH, CONTEXT_RECOVERY } from '../constants';\nimport { getBytesFromData } from '../hash';\nimport { EmailKeys, EncryptedKeystore, KeystoreType } from '../types';\nimport { exportPrivateKey, importPrivateKey, importPublicKey } from '../asymmetric-crypto';\n\n/**\n * Encrypts the keystore content using symmetric encryption\n *\n * @param secretKey - The symmetric key to encrypt the keystore content\n * @param content - The content of the keystore\n * @param userID - The ID of the user\n * @param tag - The keystore type-specific tag string\n * @returns The encrypted keystore content\n */\nexport async function encryptKeystoreContent(\n secretKey: Uint8Array,\n keys: EmailKeys,\n userEmail: string,\n type: KeystoreType,\n): Promise<EncryptedKeystore> {\n try {\n const aux = UTF8ToUint8(userEmail + type);\n const publicKeys = await publicKeyToBase64(keys.publicKeys);\n const kyberPrivateKeyEnc = await encryptSymmetrically(secretKey, keys.privateKeys.kyberPrivateKey, aux);\n const eccPrivateKey = await exportPrivateKey(keys.privateKeys.eccPrivateKey);\n const eccPrivateKeyEnc = await encryptSymmetrically(secretKey, eccPrivateKey, aux);\n const encryptedKeys = {\n publicKeys,\n privateKeys: {\n kyberPrivateKeyBase64: uint8ArrayToBase64(kyberPrivateKeyEnc),\n eccPrivateKeyBase64: uint8ArrayToBase64(eccPrivateKeyEnc),\n },\n };\n\n const keystore: EncryptedKeystore = {\n userEmail,\n type,\n encryptedKeys,\n };\n return keystore;\n } catch (error) {\n throw new Error('Failed to encrypt keystore content', { cause: error });\n }\n}\n\n/**\n * Decrypts the keystore content using symmetric encryption\n *\n * @param secretKey - The symmetric key to decrypt the keystore content\n * @param encryptedKeys - The encrypted keystore content\n * @param userEmail - The ID of the user\n * @param tag - The keystore type-specific tag string\n * @returns The decrypted keystore content\n */\nexport async function decryptKeystoreContent(\n secretKey: Uint8Array,\n encryptedKeystore: EncryptedKeystore,\n): Promise<EmailKeys> {\n try {\n const aux = UTF8ToUint8(encryptedKeystore.userEmail + encryptedKeystore.type);\n const kyberPublicKey = base64ToUint8Array(encryptedKeystore.encryptedKeys.publicKeys.kyberPublicKeyBase64);\n const eccPublicArray = base64ToUint8Array(encryptedKeystore.encryptedKeys.publicKeys.eccPublicKeyBase64);\n const eccPublicKey = await importPublicKey(eccPublicArray);\n const encKyberPrivateKey = base64ToUint8Array(encryptedKeystore.encryptedKeys.privateKeys.kyberPrivateKeyBase64);\n const kyberPrivateKey = await decryptSymmetrically(secretKey, encKyberPrivateKey, aux);\n const eccEncArray = base64ToUint8Array(encryptedKeystore.encryptedKeys.privateKeys.eccPrivateKeyBase64);\n const eccKey = await decryptSymmetrically(secretKey, eccEncArray, aux);\n const eccPrivateKey = await importPrivateKey(eccKey);\n const keys = {\n publicKeys: {\n kyberPublicKey,\n eccPublicKey,\n },\n privateKeys: {\n kyberPrivateKey,\n eccPrivateKey,\n },\n };\n return keys;\n } catch (error) {\n throw new Error('Failed to decrypt keystore content', { cause: error });\n }\n}\n\n/**\n * Derives a secret key for protecting the recovery keystore\n *\n * @param recoveryCodes - The recovery codes\n * @returns The derived secret key for protecting the recovery keystore\n */\nexport async function deriveRecoveryKey(recoveryCodes: string): Promise<Uint8Array> {\n const recoverCodesArray = mnemonicToBytes(recoveryCodes);\n const recoveryCodesBuffer = getBytesFromData(AES_KEY_BIT_LENGTH / 8, recoverCodesArray);\n return deriveSymmetricKeyFromContext(CONTEXT_RECOVERY, recoveryCodesBuffer);\n}\n\n/**\n * Derives a secret key for protecting the encryption keystore\n *\n * @param baseKey - The base secret key from which a new key secret will be derived\n * @returns The derived secret key for protecting the encryption keystore\n */\nexport async function deriveEncryptionKeystoreKey(baseKey: Uint8Array): Promise<Uint8Array> {\n return deriveSymmetricKeyFromContext(CONTEXT_ENC_KEYSTORE, baseKey);\n}\n","import { EmailKeys, EncryptedKeystore, KeystoreType } from '../types';\nimport { genMnemonic } from '../utils';\nimport { encryptKeystoreContent, decryptKeystoreContent, deriveEncryptionKeystoreKey, deriveRecoveryKey } from './core';\nimport { generateEmailKeys } from '../email-crypto';\n\n/**\n * Generates email keys and creates encrypted main and recovery keystores\n * The main keystore encryption key is derived from the base key (stored in session storage)\n * The recovery keystore encryption key is derived from the recovery codes\n *\n * @returns The encryption and recovery keystores, recovery codes and email keys\n */\nexport async function createEncryptionAndRecoveryKeystores(\n userEmail: string,\n baseKey: Uint8Array,\n): Promise<{\n encryptionKeystore: EncryptedKeystore;\n recoveryKeystore: EncryptedKeystore;\n recoveryCodes: string;\n keys: EmailKeys;\n}> {\n try {\n const keys = await generateEmailKeys();\n\n const secretKey = await deriveEncryptionKeystoreKey(baseKey);\n const encryptionKeystore = await encryptKeystoreContent(secretKey, keys, userEmail, KeystoreType.ENCRYPTION);\n\n const recoveryCodes = genMnemonic();\n const recoveryKey = await deriveRecoveryKey(recoveryCodes);\n const recoveryKeystore = await encryptKeystoreContent(recoveryKey, keys, userEmail, KeystoreType.RECOVERY);\n\n return { encryptionKeystore, recoveryKeystore, recoveryCodes, keys };\n } catch (error) {\n throw new Error('Failed to create encryption and recovery keystores', { cause: error });\n }\n}\n\n/**\n * Opens the encryption keystore and returns the email encryption keys\n * The decryption key is derived from the base key (stored in session storage)\n *\n * @param encryptedKeystore - The encrypted keystore containing encryption keys\n * @param baseKey - The base key from which the decryption key will be derived\n * @returns The encryption keys\n */\nexport async function openEncryptionKeystore(\n encryptedKeystore: EncryptedKeystore,\n baseKey: Uint8Array,\n): Promise<EmailKeys> {\n try {\n if (encryptedKeystore.type != KeystoreType.ENCRYPTION) {\n throw new Error('Input is invalid');\n }\n const secretKey = await deriveEncryptionKeystoreKey(baseKey);\n const keys = await decryptKeystoreContent(secretKey, encryptedKeystore);\n return keys;\n } catch (error) {\n throw new Error('Failed to open encryption keystore', { cause: error });\n }\n}\n\n/**\n * Opens the recovery keystore and returns the email encryption keys\n * The decryption key is derived from the base key (stored in session storage)\n *\n * @param recoveryCodes - The user's recovery codes\n * @param encryptedKeystore - The encrypted keystore containing encryption keys\n * @returns The encryption keys\n */\nexport async function openRecoveryKeystore(\n recoveryCodes: string,\n encryptedKeystore: EncryptedKeystore,\n): Promise<EmailKeys> {\n try {\n if (encryptedKeystore.type != KeystoreType.RECOVERY) {\n throw new Error('Input is invalid');\n }\n const recoveryKey = await deriveRecoveryKey(recoveryCodes);\n const keys = await decryptKeystoreContent(recoveryKey, encryptedKeystore);\n return keys;\n } catch (error) {\n throw new Error('Failed to open recovery keystore', { cause: error });\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAiBA,eAAsB,uBACpB,WACA,MACA,WACA,MAC4B;AAC5B,KAAI;EACF,MAAM,MAAM,YAAY,YAAY,KAAK;EACzC,MAAM,aAAa,MAAM,kBAAkB,KAAK,WAAW;EAC3D,MAAM,qBAAqB,MAAM,qBAAqB,WAAW,KAAK,YAAY,iBAAiB,IAAI;EAEvG,MAAM,mBAAmB,MAAM,qBAAqB,WAD9B,MAAM,iBAAiB,KAAK,YAAY,cAAc,EACE,IAAI;AAclF,SALoC;GAClC;GACA;GACA,eAXoB;IACpB;IACA,aAAa;KACX,uBAAuB,mBAAmB,mBAAmB;KAC7D,qBAAqB,mBAAmB,iBAAiB;KAC1D;IACF;GAMA;UAEM,OAAO;AACd,QAAM,IAAI,MAAM,sCAAsC,EAAE,OAAO,OAAO,CAAC;;;;;;;;;;;;AAa3E,eAAsB,uBACpB,WACA,mBACoB;AACpB,KAAI;EACF,MAAM,MAAM,YAAY,kBAAkB,YAAY,kBAAkB,KAAK;EAC7E,MAAM,iBAAiB,mBAAmB,kBAAkB,cAAc,WAAW,qBAAqB;EAE1G,MAAM,eAAe,MAAM,gBADJ,mBAAmB,kBAAkB,cAAc,WAAW,mBAAmB,CAC9C;EAE1D,MAAM,kBAAkB,MAAM,qBAAqB,WADxB,mBAAmB,kBAAkB,cAAc,YAAY,sBAAsB,EAC9B,IAAI;EAGtF,MAAM,gBAAgB,MAAM,iBADb,MAAM,qBAAqB,WADtB,mBAAmB,kBAAkB,cAAc,YAAY,oBAAoB,EACrC,IAAI,CAClB;AAWpD,SAVa;GACX,YAAY;IACV;IACA;IACD;GACD,aAAa;IACX;IACA;IACD;GACF;UAEM,OAAO;AACd,QAAM,IAAI,MAAM,sCAAsC,EAAE,OAAO,OAAO,CAAC;;;;;;;;;AAU3E,eAAsB,kBAAkB,eAA4C;CAClF,MAAM,oBAAoB,gBAAgB,cAAc;AAExD,QAAO,8BAA8B,kBADT,iBAAiB,qBAAqB,GAAG,kBAAkB,CACZ;;;;;;;;AAS7E,eAAsB,4BAA4B,SAA0C;AAC1F,QAAO,8BAA8B,sBAAsB,QAAQ;;;;;;;;;;;;AC9FrE,eAAsB,qCACpB,WACA,SAMC;AACD,KAAI;EACF,MAAM,OAAO,MAAM,mBAAmB;EAGtC,MAAM,qBAAqB,MAAM,uBADf,MAAM,4BAA4B,QAAQ,EACO,MAAM,WAAW,aAAa,WAAW;EAE5G,MAAM,gBAAgB,aAAa;AAInC,SAAO;GAAE;GAAoB,kBAFJ,MAAM,uBADX,MAAM,kBAAkB,cAAc,EACS,MAAM,WAAW,aAAa,SAAS;GAE3D;GAAe;GAAM;UAC7D,OAAO;AACd,QAAM,IAAI,MAAM,sDAAsD,EAAE,OAAO,OAAO,CAAC;;;;;;;;;;;AAY3F,eAAsB,uBACpB,mBACA,SACoB;AACpB,KAAI;AACF,MAAI,kBAAkB,QAAQ,aAAa,WACzC,OAAM,IAAI,MAAM,mBAAmB;AAIrC,SADa,MAAM,uBADD,MAAM,4BAA4B,QAAQ,EACP,kBAAkB;UAEhE,OAAO;AACd,QAAM,IAAI,MAAM,sCAAsC,EAAE,OAAO,OAAO,CAAC;;;;;;;;;;;AAY3E,eAAsB,qBACpB,eACA,mBACoB;AACpB,KAAI;AACF,MAAI,kBAAkB,QAAQ,aAAa,SACzC,OAAM,IAAI,MAAM,mBAAmB;AAIrC,SADa,MAAM,uBADC,MAAM,kBAAkB,cAAc,EACH,kBAAkB;UAElE,OAAO;AACd,QAAM,IAAI,MAAM,oCAAoC,EAAE,OAAO,OAAO,CAAC"}
@@ -2,9 +2,9 @@ const require_constants = require('./constants.js');
2
2
  const require_keys = require('./keys-CinT7kEY.js');
3
3
  const require_genID = require('./genID-YJSl3YhL.js');
4
4
  const require_mac = require('./mac-BMb1F0dN.js');
5
- const require_aes = require('./aes-bOrKZuUC.js');
6
- const require_deriveKeysFromPassword = require('./deriveKeysFromPassword-Ko7NxkHM.js');
7
- const require_emailKeys = require('./emailKeys-BJGdkLrg.js');
5
+ const require_aes = require('./aes-DQo1MyCz.js');
6
+ const require_deriveKeysFromPassword = require('./deriveKeysFromPassword-BYaiSGKL.js');
7
+ const require_emailKeys = require('./emailKeys-C0KhtfNP.js');
8
8
  const require_types = require('./types.js');
9
9
 
10
10
  //#region src/keystore-crypto/core.ts
@@ -76,7 +76,7 @@ async function decryptKeystoreContent(secretKey, encryptedKeystore) {
76
76
  */
77
77
  async function deriveRecoveryKey(recoveryCodes) {
78
78
  const recoverCodesArray = require_genID.mnemonicToBytes(recoveryCodes);
79
- return require_deriveKeysFromPassword.deriveSymmetricCryptoKeyFromContext(require_constants.CONTEXT_RECOVERY, require_mac.getBytesFromData(require_constants.AES_KEY_BIT_LENGTH / 8, recoverCodesArray));
79
+ return require_deriveKeysFromPassword.deriveSymmetricKeyFromContext(require_constants.CONTEXT_RECOVERY, require_mac.getBytesFromData(require_constants.AES_KEY_BIT_LENGTH / 8, recoverCodesArray));
80
80
  }
81
81
  /**
82
82
  * Derives a secret key for protecting the encryption keystore
@@ -85,7 +85,7 @@ async function deriveRecoveryKey(recoveryCodes) {
85
85
  * @returns The derived secret key for protecting the encryption keystore
86
86
  */
87
87
  async function deriveEncryptionKeystoreKey(baseKey) {
88
- return require_deriveKeysFromPassword.deriveSymmetricCryptoKeyFromContext(require_constants.CONTEXT_ENC_KEYSTORE, baseKey);
88
+ return require_deriveKeysFromPassword.deriveSymmetricKeyFromContext(require_constants.CONTEXT_ENC_KEYSTORE, baseKey);
89
89
  }
90
90
 
91
91
  //#endregion
@@ -164,4 +164,4 @@ Object.defineProperty(exports, 'openRecoveryKeystore', {
164
164
  return openRecoveryKeystore;
165
165
  }
166
166
  });
167
- //# sourceMappingURL=emailEncryptionKey-DbaDAdoW.js.map
167
+ //# sourceMappingURL=emailEncryptionKey-CQNe5W_T.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emailEncryptionKey-CQNe5W_T.js","names":["UTF8ToUint8","publicKeyToBase64","encryptSymmetrically","exportPrivateKey","uint8ArrayToBase64","base64ToUint8Array","importPublicKey","decryptSymmetrically","importPrivateKey","mnemonicToBytes","deriveSymmetricKeyFromContext","CONTEXT_RECOVERY","getBytesFromData","AES_KEY_BIT_LENGTH","CONTEXT_ENC_KEYSTORE","generateEmailKeys","KeystoreType","genMnemonic"],"sources":["../src/keystore-crypto/core.ts","../src/keystore-crypto/emailEncryptionKey.ts"],"sourcesContent":["import { encryptSymmetrically, decryptSymmetrically } from '../symmetric-crypto';\nimport { base64ToUint8Array, uint8ArrayToBase64, UTF8ToUint8, mnemonicToBytes, publicKeyToBase64 } from '../utils';\nimport { deriveSymmetricKeyFromContext } from '../derive-key';\nimport { CONTEXT_ENC_KEYSTORE, AES_KEY_BIT_LENGTH, CONTEXT_RECOVERY } from '../constants';\nimport { getBytesFromData } from '../hash';\nimport { EmailKeys, EncryptedKeystore, KeystoreType } from '../types';\nimport { exportPrivateKey, importPrivateKey, importPublicKey } from '../asymmetric-crypto';\n\n/**\n * Encrypts the keystore content using symmetric encryption\n *\n * @param secretKey - The symmetric key to encrypt the keystore content\n * @param content - The content of the keystore\n * @param userID - The ID of the user\n * @param tag - The keystore type-specific tag string\n * @returns The encrypted keystore content\n */\nexport async function encryptKeystoreContent(\n secretKey: Uint8Array,\n keys: EmailKeys,\n userEmail: string,\n type: KeystoreType,\n): Promise<EncryptedKeystore> {\n try {\n const aux = UTF8ToUint8(userEmail + type);\n const publicKeys = await publicKeyToBase64(keys.publicKeys);\n const kyberPrivateKeyEnc = await encryptSymmetrically(secretKey, keys.privateKeys.kyberPrivateKey, aux);\n const eccPrivateKey = await exportPrivateKey(keys.privateKeys.eccPrivateKey);\n const eccPrivateKeyEnc = await encryptSymmetrically(secretKey, eccPrivateKey, aux);\n const encryptedKeys = {\n publicKeys,\n privateKeys: {\n kyberPrivateKeyBase64: uint8ArrayToBase64(kyberPrivateKeyEnc),\n eccPrivateKeyBase64: uint8ArrayToBase64(eccPrivateKeyEnc),\n },\n };\n\n const keystore: EncryptedKeystore = {\n userEmail,\n type,\n encryptedKeys,\n };\n return keystore;\n } catch (error) {\n throw new Error('Failed to encrypt keystore content', { cause: error });\n }\n}\n\n/**\n * Decrypts the keystore content using symmetric encryption\n *\n * @param secretKey - The symmetric key to decrypt the keystore content\n * @param encryptedKeys - The encrypted keystore content\n * @param userEmail - The ID of the user\n * @param tag - The keystore type-specific tag string\n * @returns The decrypted keystore content\n */\nexport async function decryptKeystoreContent(\n secretKey: Uint8Array,\n encryptedKeystore: EncryptedKeystore,\n): Promise<EmailKeys> {\n try {\n const aux = UTF8ToUint8(encryptedKeystore.userEmail + encryptedKeystore.type);\n const kyberPublicKey = base64ToUint8Array(encryptedKeystore.encryptedKeys.publicKeys.kyberPublicKeyBase64);\n const eccPublicArray = base64ToUint8Array(encryptedKeystore.encryptedKeys.publicKeys.eccPublicKeyBase64);\n const eccPublicKey = await importPublicKey(eccPublicArray);\n const encKyberPrivateKey = base64ToUint8Array(encryptedKeystore.encryptedKeys.privateKeys.kyberPrivateKeyBase64);\n const kyberPrivateKey = await decryptSymmetrically(secretKey, encKyberPrivateKey, aux);\n const eccEncArray = base64ToUint8Array(encryptedKeystore.encryptedKeys.privateKeys.eccPrivateKeyBase64);\n const eccKey = await decryptSymmetrically(secretKey, eccEncArray, aux);\n const eccPrivateKey = await importPrivateKey(eccKey);\n const keys = {\n publicKeys: {\n kyberPublicKey,\n eccPublicKey,\n },\n privateKeys: {\n kyberPrivateKey,\n eccPrivateKey,\n },\n };\n return keys;\n } catch (error) {\n throw new Error('Failed to decrypt keystore content', { cause: error });\n }\n}\n\n/**\n * Derives a secret key for protecting the recovery keystore\n *\n * @param recoveryCodes - The recovery codes\n * @returns The derived secret key for protecting the recovery keystore\n */\nexport async function deriveRecoveryKey(recoveryCodes: string): Promise<Uint8Array> {\n const recoverCodesArray = mnemonicToBytes(recoveryCodes);\n const recoveryCodesBuffer = getBytesFromData(AES_KEY_BIT_LENGTH / 8, recoverCodesArray);\n return deriveSymmetricKeyFromContext(CONTEXT_RECOVERY, recoveryCodesBuffer);\n}\n\n/**\n * Derives a secret key for protecting the encryption keystore\n *\n * @param baseKey - The base secret key from which a new key secret will be derived\n * @returns The derived secret key for protecting the encryption keystore\n */\nexport async function deriveEncryptionKeystoreKey(baseKey: Uint8Array): Promise<Uint8Array> {\n return deriveSymmetricKeyFromContext(CONTEXT_ENC_KEYSTORE, baseKey);\n}\n","import { EmailKeys, EncryptedKeystore, KeystoreType } from '../types';\nimport { genMnemonic } from '../utils';\nimport { encryptKeystoreContent, decryptKeystoreContent, deriveEncryptionKeystoreKey, deriveRecoveryKey } from './core';\nimport { generateEmailKeys } from '../email-crypto';\n\n/**\n * Generates email keys and creates encrypted main and recovery keystores\n * The main keystore encryption key is derived from the base key (stored in session storage)\n * The recovery keystore encryption key is derived from the recovery codes\n *\n * @returns The encryption and recovery keystores, recovery codes and email keys\n */\nexport async function createEncryptionAndRecoveryKeystores(\n userEmail: string,\n baseKey: Uint8Array,\n): Promise<{\n encryptionKeystore: EncryptedKeystore;\n recoveryKeystore: EncryptedKeystore;\n recoveryCodes: string;\n keys: EmailKeys;\n}> {\n try {\n const keys = await generateEmailKeys();\n\n const secretKey = await deriveEncryptionKeystoreKey(baseKey);\n const encryptionKeystore = await encryptKeystoreContent(secretKey, keys, userEmail, KeystoreType.ENCRYPTION);\n\n const recoveryCodes = genMnemonic();\n const recoveryKey = await deriveRecoveryKey(recoveryCodes);\n const recoveryKeystore = await encryptKeystoreContent(recoveryKey, keys, userEmail, KeystoreType.RECOVERY);\n\n return { encryptionKeystore, recoveryKeystore, recoveryCodes, keys };\n } catch (error) {\n throw new Error('Failed to create encryption and recovery keystores', { cause: error });\n }\n}\n\n/**\n * Opens the encryption keystore and returns the email encryption keys\n * The decryption key is derived from the base key (stored in session storage)\n *\n * @param encryptedKeystore - The encrypted keystore containing encryption keys\n * @param baseKey - The base key from which the decryption key will be derived\n * @returns The encryption keys\n */\nexport async function openEncryptionKeystore(\n encryptedKeystore: EncryptedKeystore,\n baseKey: Uint8Array,\n): Promise<EmailKeys> {\n try {\n if (encryptedKeystore.type != KeystoreType.ENCRYPTION) {\n throw new Error('Input is invalid');\n }\n const secretKey = await deriveEncryptionKeystoreKey(baseKey);\n const keys = await decryptKeystoreContent(secretKey, encryptedKeystore);\n return keys;\n } catch (error) {\n throw new Error('Failed to open encryption keystore', { cause: error });\n }\n}\n\n/**\n * Opens the recovery keystore and returns the email encryption keys\n * The decryption key is derived from the base key (stored in session storage)\n *\n * @param recoveryCodes - The user's recovery codes\n * @param encryptedKeystore - The encrypted keystore containing encryption keys\n * @returns The encryption keys\n */\nexport async function openRecoveryKeystore(\n recoveryCodes: string,\n encryptedKeystore: EncryptedKeystore,\n): Promise<EmailKeys> {\n try {\n if (encryptedKeystore.type != KeystoreType.RECOVERY) {\n throw new Error('Input is invalid');\n }\n const recoveryKey = await deriveRecoveryKey(recoveryCodes);\n const keys = await decryptKeystoreContent(recoveryKey, encryptedKeystore);\n return keys;\n } catch (error) {\n throw new Error('Failed to open recovery keystore', { cause: error });\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAiBA,eAAsB,uBACpB,WACA,MACA,WACA,MAC4B;AAC5B,KAAI;EACF,MAAM,MAAMA,0BAAY,YAAY,KAAK;EACzC,MAAM,aAAa,MAAMC,gCAAkB,KAAK,WAAW;EAC3D,MAAM,qBAAqB,MAAMC,iCAAqB,WAAW,KAAK,YAAY,iBAAiB,IAAI;EAEvG,MAAM,mBAAmB,MAAMA,iCAAqB,WAD9B,MAAMC,8BAAiB,KAAK,YAAY,cAAc,EACE,IAAI;AAclF,SALoC;GAClC;GACA;GACA,eAXoB;IACpB;IACA,aAAa;KACX,uBAAuBC,iCAAmB,mBAAmB;KAC7D,qBAAqBA,iCAAmB,iBAAiB;KAC1D;IACF;GAMA;UAEM,OAAO;AACd,QAAM,IAAI,MAAM,sCAAsC,EAAE,OAAO,OAAO,CAAC;;;;;;;;;;;;AAa3E,eAAsB,uBACpB,WACA,mBACoB;AACpB,KAAI;EACF,MAAM,MAAMJ,0BAAY,kBAAkB,YAAY,kBAAkB,KAAK;EAC7E,MAAM,iBAAiBK,iCAAmB,kBAAkB,cAAc,WAAW,qBAAqB;EAE1G,MAAM,eAAe,MAAMC,6BADJD,iCAAmB,kBAAkB,cAAc,WAAW,mBAAmB,CAC9C;EAE1D,MAAM,kBAAkB,MAAME,iCAAqB,WADxBF,iCAAmB,kBAAkB,cAAc,YAAY,sBAAsB,EAC9B,IAAI;EAGtF,MAAM,gBAAgB,MAAMG,8BADb,MAAMD,iCAAqB,WADtBF,iCAAmB,kBAAkB,cAAc,YAAY,oBAAoB,EACrC,IAAI,CAClB;AAWpD,SAVa;GACX,YAAY;IACV;IACA;IACD;GACD,aAAa;IACX;IACA;IACD;GACF;UAEM,OAAO;AACd,QAAM,IAAI,MAAM,sCAAsC,EAAE,OAAO,OAAO,CAAC;;;;;;;;;AAU3E,eAAsB,kBAAkB,eAA4C;CAClF,MAAM,oBAAoBI,8BAAgB,cAAc;AAExD,QAAOC,6DAA8BC,oCADTC,6BAAiBC,uCAAqB,GAAG,kBAAkB,CACZ;;;;;;;;AAS7E,eAAsB,4BAA4B,SAA0C;AAC1F,QAAOH,6DAA8BI,wCAAsB,QAAQ;;;;;;;;;;;;AC9FrE,eAAsB,qCACpB,WACA,SAMC;AACD,KAAI;EACF,MAAM,OAAO,MAAMC,qCAAmB;EAGtC,MAAM,qBAAqB,MAAM,uBADf,MAAM,4BAA4B,QAAQ,EACO,MAAM,WAAWC,2BAAa,WAAW;EAE5G,MAAM,gBAAgBC,2BAAa;AAInC,SAAO;GAAE;GAAoB,kBAFJ,MAAM,uBADX,MAAM,kBAAkB,cAAc,EACS,MAAM,WAAWD,2BAAa,SAAS;GAE3D;GAAe;GAAM;UAC7D,OAAO;AACd,QAAM,IAAI,MAAM,sDAAsD,EAAE,OAAO,OAAO,CAAC;;;;;;;;;;;AAY3F,eAAsB,uBACpB,mBACA,SACoB;AACpB,KAAI;AACF,MAAI,kBAAkB,QAAQA,2BAAa,WACzC,OAAM,IAAI,MAAM,mBAAmB;AAIrC,SADa,MAAM,uBADD,MAAM,4BAA4B,QAAQ,EACP,kBAAkB;UAEhE,OAAO;AACd,QAAM,IAAI,MAAM,sCAAsC,EAAE,OAAO,OAAO,CAAC;;;;;;;;;;;AAY3E,eAAsB,qBACpB,eACA,mBACoB;AACpB,KAAI;AACF,MAAI,kBAAkB,QAAQA,2BAAa,SACzC,OAAM,IAAI,MAAM,mBAAmB;AAIrC,SADa,MAAM,uBADC,MAAM,kBAAkB,cAAc,EACH,kBAAkB;UAElE,OAAO;AACd,QAAM,IAAI,MAAM,oCAAoC,EAAE,OAAO,OAAO,CAAC"}
@@ -2,36 +2,24 @@ const require_chunk = require('./chunk-EbLFQX5m.js');
2
2
  const require_constants = require('./constants.js');
3
3
  const require_keys = require('./keys-CinT7kEY.js');
4
4
  const require_genID = require('./genID-YJSl3YhL.js');
5
- const require_aes = require('./aes-bOrKZuUC.js');
6
- const require_deriveKeysFromPassword = require('./deriveKeysFromPassword-Ko7NxkHM.js');
7
- const require_kyber1024 = require('./kyber1024-jeKS8CXf.js');
5
+ const require_aes = require('./aes-DQo1MyCz.js');
6
+ const require_deriveKeysFromPassword = require('./deriveKeysFromPassword-BYaiSGKL.js');
7
+ const require_kyber768 = require('./kyber768-WUVc2fIR.js');
8
8
  let _noble_hashes_utils_js = require("@noble/hashes/utils.js");
9
+ let _noble_ciphers_aes_js = require("@noble/ciphers/aes.js");
9
10
 
10
11
  //#region src/key-wrapper/aesWrapper.ts
11
12
  /**
12
- * Converts wrapping key in Uint8Array into CryptoKey
13
- *
14
- * @param key - The wrapping key in Uint8Array representation
15
- * @returns The resulting CryptoKey
16
- */
17
- async function importWrappingKey(key) {
18
- try {
19
- return await crypto.subtle.importKey(require_constants.KEY_FORMAT, key, require_constants.KEY_WRAPPING_ALGORITHM, false, ["wrapKey", "unwrapKey"]);
20
- } catch (error) {
21
- throw new Error("Failed to import wrapping key", { cause: error });
22
- }
23
- }
24
- /**
25
13
  * Derives wrapping key from two secrets
26
14
  *
27
15
  * @param eccSecret - The secret exchanged via elliptic curves
28
16
  * @param kyberSecret - The secret exchanged via Kyber KEM
29
- * @returns The resulting wrapping CryptoKey
17
+ * @returns The resulting wrapping key
30
18
  */
31
19
  async function deriveWrappingKey(eccSecret, kyberSecret) {
32
20
  try {
33
21
  if (eccSecret.length !== kyberSecret.length) throw new Error("secrets must have equal length");
34
- return await importWrappingKey(await require_deriveKeysFromPassword.deriveSymmetricKeyFromTwoKeysAndContext(eccSecret, kyberSecret, require_constants.CONTEXT_WRAPPING));
22
+ return require_deriveKeysFromPassword.deriveSymmetricKeyFromTwoKeysAndContext(eccSecret, kyberSecret, require_constants.CONTEXT_WRAPPING);
35
23
  } catch (error) {
36
24
  throw new Error("Failed to derive wrapping key", { cause: error });
37
25
  }
@@ -39,31 +27,22 @@ async function deriveWrappingKey(eccSecret, kyberSecret) {
39
27
  /**
40
28
  * Unwraps the given wrapped key
41
29
  *
42
- * @param encryptedKey - The encrypted key
43
- * @param wrappingKey - The secret key used for decryption
44
- * @returns The resulting wrapping CryptoKey
30
+ * @param encryptedKey - The wrapped key
31
+ * @param wrappingKey - The secret key used for unwrapping
32
+ * @returns The resulting key
45
33
  */
46
34
  async function unwrapKey(encryptedKey, wrappingKey) {
47
- try {
48
- return await crypto.subtle.unwrapKey(require_constants.KEY_FORMAT, encryptedKey, wrappingKey, require_constants.KEY_WRAPPING_ALGORITHM, require_constants.AES_ALGORITHM, false, ["encrypt", "decrypt"]);
49
- } catch (error) {
50
- throw new Error("Failed to unwrap key", { cause: error });
51
- }
35
+ return (0, _noble_ciphers_aes_js.aeskw)(wrappingKey).decrypt(encryptedKey);
52
36
  }
53
37
  /**
54
- * Wraps the given CryptoKey
38
+ * Wraps the given key
55
39
  *
56
- * @param encryptionKey - The CryptoKey to be wrapped
40
+ * @param key - The key to be wrapped
57
41
  * @param wrappingKey - The secret key used for wrapping
58
42
  * @returns The resulting ciphertext
59
43
  */
60
- async function wrapKey(encryptionKey, wrappingKey) {
61
- try {
62
- const result = await crypto.subtle.wrapKey(require_constants.KEY_FORMAT, encryptionKey, wrappingKey, require_constants.KEY_WRAPPING_ALGORITHM);
63
- return new Uint8Array(result);
64
- } catch (error) {
65
- throw new Error("Failed to wrap key", { cause: error });
66
- }
44
+ async function wrapKey(key, wrappingKey) {
45
+ return (0, _noble_ciphers_aes_js.aeskw)(wrappingKey).encrypt(key);
67
46
  }
68
47
 
69
48
  //#endregion
@@ -181,7 +160,7 @@ async function decryptEmailBody(enc, encParams, encryptionKey, isSubjectEncrypte
181
160
  async function encryptEmailContentSymmetrically(email, aux, emailID) {
182
161
  try {
183
162
  if (!email.text) throw new Error("Invalid input");
184
- const encryptionKey = await require_aes.genSymmetricCryptoKey();
163
+ const encryptionKey = require_aes.genSymmetricKey();
185
164
  return {
186
165
  enc: await encryptEmailContentSymmetricallyWithKey(email, encryptionKey, aux, emailID),
187
166
  encryptionKey
@@ -202,7 +181,7 @@ async function encryptEmailContentSymmetrically(email, aux, emailID) {
202
181
  async function encryptEmailContentAndSubjectSymmetrically(email, subject, aux, emailID) {
203
182
  try {
204
183
  if (!subject || !email.text) throw new Error("Invalid input");
205
- const encryptionKey = await require_aes.genSymmetricCryptoKey();
184
+ const encryptionKey = require_aes.genSymmetricKey();
206
185
  return {
207
186
  enc: await encryptEmailContentSymmetricallyWithKey(email, encryptionKey, aux, emailID),
208
187
  encSubject: require_genID.uint8ArrayToBase64(await require_aes.encryptSymmetrically(encryptionKey, require_genID.UTF8ToUint8(subject), aux)),
@@ -216,7 +195,7 @@ async function encryptEmailContentAndSubjectSymmetrically(email, subject, aux, e
216
195
  * Decrypts symmetrically encrypted email.
217
196
  *
218
197
  * @param encryptedEmail - The email to decrypt.
219
- * @param encryptionKey - The symmetric CryptoKey.
198
+ * @param encryptionKey - The symmetric key.
220
199
  * @returns The decrypted email
221
200
  */
222
201
  async function decryptEmailAndSubjectSymmetrically(encryptionKey, aux, encSubject, enc) {
@@ -269,7 +248,7 @@ async function decryptEmailAttachements(encryptedAttachments, encryptionKey, aux
269
248
  * Decrypts symmetrically encrypted email.
270
249
  *
271
250
  * @param encryptedEmail - The email to decrypt.
272
- * @param encryptionKey - The symmetric CryptoKey.
251
+ * @param encryptionKey - The symmetric key.
273
252
  * @returns The decrypted email
274
253
  */
275
254
  async function decryptEmailSymmetrically(encryptionKey, aux, enc) {
@@ -287,7 +266,7 @@ async function decryptEmailSymmetrically(encryptionKey, aux, enc) {
287
266
  /**
288
267
  * Encrypts the email symmetric key using hybrid encryption.
289
268
  *
290
- * @param emailEncryptionKey - The symmetric CryptoKey used for email encryption.
269
+ * @param emailEncryptionKey - The symmetric key used for email encryption.
291
270
  * @param recipientPublicKey - The public key of the recipient.
292
271
  * @param senderPrivateKey - The private key of the sender.
293
272
  * @returns The encrypted email symmetric key
@@ -295,7 +274,7 @@ async function decryptEmailSymmetrically(encryptionKey, aux, enc) {
295
274
  async function encryptKeysHybrid(emailEncryptionKey, recipientPublicKey, senderPrivateKey) {
296
275
  try {
297
276
  const eccSecret = await require_keys.deriveSecretKey(recipientPublicKey.eccPublicKey, senderPrivateKey.eccPrivateKey);
298
- const { cipherText: kyberCiphertext, sharedSecret: kyberSecret } = require_kyber1024.encapsulateKyber(recipientPublicKey.kyberPublicKey);
277
+ const { cipherText: kyberCiphertext, sharedSecret: kyberSecret } = require_kyber768.encapsulateKyber(recipientPublicKey.kyberPublicKey);
299
278
  return {
300
279
  encryptedKey: require_genID.uint8ArrayToBase64(await wrapKey(emailEncryptionKey, await deriveWrappingKey(eccSecret, kyberSecret))),
301
280
  kyberCiphertext: require_genID.uint8ArrayToBase64(kyberCiphertext)
@@ -310,12 +289,12 @@ async function encryptKeysHybrid(emailEncryptionKey, recipientPublicKey, senderP
310
289
  * @param encryptedKey - The encrypted email key.
311
290
  * @param senderPublicKey - The public key of the sender.
312
291
  * @param recipientPrivateKey - The private key of the recipient.
313
- * @returns The email encryption CryptoKey
292
+ * @returns The email encryption key
314
293
  */
315
294
  async function decryptKeysHybrid(encryptedKey, senderPublicKey, recipientPrivateKey) {
316
295
  try {
317
296
  const kyberCiphertext = require_genID.base64ToUint8Array(encryptedKey.kyberCiphertext);
318
- return await unwrapKey(require_genID.base64ToUint8Array(encryptedKey.encryptedKey), await deriveWrappingKey(await require_keys.deriveSecretKey(senderPublicKey.eccPublicKey, recipientPrivateKey.eccPrivateKey), require_kyber1024.decapsulateKyber(kyberCiphertext, recipientPrivateKey.kyberPrivateKey)));
297
+ return await unwrapKey(require_genID.base64ToUint8Array(encryptedKey.encryptedKey), await deriveWrappingKey(await require_keys.deriveSecretKey(senderPublicKey.eccPublicKey, recipientPrivateKey.eccPrivateKey), require_kyber768.decapsulateKyber(kyberCiphertext, recipientPrivateKey.kyberPrivateKey)));
319
298
  } catch (error) {
320
299
  throw new Error("Failed to decrypt email key encrypted via hybrid encryption", { cause: error });
321
300
  }
@@ -323,14 +302,14 @@ async function decryptKeysHybrid(encryptedKey, senderPublicKey, recipientPrivate
323
302
  /**
324
303
  * Password-protects the email symmetric key.
325
304
  *
326
- * @param emailEncryptionKey - The symmetric CryptoKey used for email encryption.
305
+ * @param emailEncryptionKey - The symmetric key used for email encryption.
327
306
  * @param password - The secret password for key protection.
328
307
  * @returns The password-protected email symmetric key
329
308
  */
330
309
  async function passwordProtectKey(emailEncryptionKey, password) {
331
310
  try {
332
311
  const { key, salt } = await require_deriveKeysFromPassword.getKeyFromPassword(password);
333
- const encryptedKey = await wrapKey(emailEncryptionKey, await importWrappingKey(key));
312
+ const encryptedKey = await wrapKey(emailEncryptionKey, key);
334
313
  const saltStr = require_genID.uint8ArrayToBase64(salt);
335
314
  return {
336
315
  encryptedKey: require_genID.uint8ArrayToBase64(encryptedKey),
@@ -345,12 +324,12 @@ async function passwordProtectKey(emailEncryptionKey, password) {
345
324
  *
346
325
  * @param emailEncryptionKey - The password-protected email key.
347
326
  * @param password - The secret password for key protection.
348
- * @returns The email encryption CryptoKey
327
+ * @returns The email encryption key
349
328
  */
350
329
  async function removePasswordProtection(emailEncryptionKey, password) {
351
330
  try {
352
331
  const salt = require_genID.base64ToUint8Array(emailEncryptionKey.salt);
353
- return await unwrapKey(require_genID.base64ToUint8Array(emailEncryptionKey.encryptedKey), await importWrappingKey(await require_deriveKeysFromPassword.getKeyFromPasswordAndSalt(password, salt)));
332
+ return await unwrapKey(require_genID.base64ToUint8Array(emailEncryptionKey.encryptedKey), await require_deriveKeysFromPassword.getKeyFromPasswordAndSalt(password, salt));
354
333
  } catch (error) {
355
334
  throw new Error("Failed to remove password-protection from email key", { cause: error });
356
335
  }
@@ -488,7 +467,7 @@ async function decryptPwdProtectedEmail(encryptedEmail, password) {
488
467
  */
489
468
  async function generateEmailKeys() {
490
469
  try {
491
- const kyberKeys = require_kyber1024.generateKyberKeys();
470
+ const kyberKeys = require_kyber768.generateKyberKeys();
492
471
  const keys = await require_keys.generateEccKeys();
493
472
  return {
494
473
  publicKeys: {
@@ -590,4 +569,4 @@ Object.defineProperty(exports, 'wrapKey', {
590
569
  return wrapKey;
591
570
  }
592
571
  });
593
- //# sourceMappingURL=emailKeys-BJGdkLrg.js.map
572
+ //# sourceMappingURL=emailKeys-C0KhtfNP.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emailKeys-C0KhtfNP.js","names":["deriveSymmetricKeyFromTwoKeysAndContext","CONTEXT_WRAPPING","UTF8ToUint8","uuidToBytes","UTF8ToUint8","genSymmetricKey","uint8ArrayToBase64","encryptSymmetrically","UTF8ToUint8","decryptSymmetrically","base64ToUint8Array","uint8ToUTF8","uuidToBytes","deriveSecretKey","encapsulateKyber","decapsulateKyber","getKeyFromPassword","getKeyFromPasswordAndSalt","generateKyberKeys","generateEccKeys"],"sources":["../src/key-wrapper/aesWrapper.ts","../src/email-crypto/converters.ts","../src/email-crypto/utils.ts","../src/email-crypto/core.ts","../src/email-crypto/hybridEncyptedEmail.ts","../src/email-crypto/pwdProtectedEmail.ts","../src/email-crypto/emailKeys.ts"],"sourcesContent":["import { CONTEXT_WRAPPING } from '../constants';\nimport { deriveSymmetricKeyFromTwoKeysAndContext } from '../derive-key';\nimport { aeskw } from '@noble/ciphers/aes.js';\n\n/**\n * Derives wrapping key from two secrets\n *\n * @param eccSecret - The secret exchanged via elliptic curves\n * @param kyberSecret - The secret exchanged via Kyber KEM\n * @returns The resulting wrapping key\n */\nexport async function deriveWrappingKey(eccSecret: Uint8Array, kyberSecret: Uint8Array): Promise<Uint8Array> {\n try {\n if (eccSecret.length !== kyberSecret.length) {\n throw new Error('secrets must have equal length');\n }\n return deriveSymmetricKeyFromTwoKeysAndContext(eccSecret, kyberSecret, CONTEXT_WRAPPING);\n } catch (error) {\n throw new Error('Failed to derive wrapping key', { cause: error });\n }\n}\n\n/**\n * Unwraps the given wrapped key\n *\n * @param encryptedKey - The wrapped key\n * @param wrappingKey - The secret key used for unwrapping\n * @returns The resulting key\n */\nexport async function unwrapKey(encryptedKey: Uint8Array, wrappingKey: Uint8Array): Promise<Uint8Array> {\n return aeskw(wrappingKey).decrypt(encryptedKey);\n}\n\n/**\n * Wraps the given key\n *\n * @param key - The key to be wrapped\n * @param wrappingKey - The secret key used for wrapping\n * @returns The resulting ciphertext\n */\nexport async function wrapKey(key: Uint8Array, wrappingKey: Uint8Array): Promise<Uint8Array> {\n return aeskw(wrappingKey).encrypt(key);\n}\n","import { UTF8ToUint8 } from '../utils';\nimport { User, Email } from '../types';\nimport { concatBytes } from '@noble/hashes/utils.js';\n\nexport function userToBytes(user: User): Uint8Array {\n try {\n const json = JSON.stringify(user);\n return UTF8ToUint8(json);\n } catch (error) {\n throw new Error('Failed to convert User to bytes', { cause: error });\n }\n}\n\nexport function recipientsToBytes(recipients: User[]): Uint8Array {\n try {\n const array = recipients.map((user) => userToBytes(user));\n return concatBytes(...array);\n } catch (error) {\n throw new Error('Failed to convert recipients to bytes', { cause: error });\n }\n}\n\n/**\n * Converts an Email type into a Uint8Array array.\n *\n * @param email - The email.\n * @returns The Uint8Array array representation of the Email type.\n */\nexport function emailToBinary(email: Email): Uint8Array {\n try {\n const json = JSON.stringify(email);\n return UTF8ToUint8(json);\n } catch (error) {\n throw new Error('Failed to convert EmailBody to Uint8Array', { cause: error });\n }\n}\n","import { concatBytes } from '@noble/hashes/utils.js';\nimport { EmailPublicParameters } from '../types';\nimport { UTF8ToUint8, uuidToBytes } from '../utils';\nimport { userToBytes, recipientsToBytes } from './converters';\n\n/**\n * Creates an auxiliary string from public fields of the email.\n *\n * @param params - The email public parameters.\n * @param isSubjectEncrypted - Indicates if the email subject field should be encrypted\n * @returns The resulting auxiliary string\n */\nexport function getAux(params: EmailPublicParameters, isSubjectEncrypted: boolean): Uint8Array {\n try {\n const { subject, replyToEmailID, sender, recipient, recipients } = params;\n const replyBytes = replyToEmailID ? uuidToBytes(replyToEmailID) : new Uint8Array();\n const senderBytes = userToBytes(sender);\n const recipientBytes = userToBytes(recipient);\n const recipientsBytes = recipients ? recipientsToBytes(recipients) : new Uint8Array();\n\n if (isSubjectEncrypted) {\n return concatBytes(replyBytes, senderBytes, recipientBytes, recipientsBytes);\n } else {\n const subjectBytes = UTF8ToUint8(subject);\n return concatBytes(subjectBytes, replyBytes, senderBytes, recipientBytes, recipientsBytes);\n }\n } catch (error) {\n throw new Error('Failed to create aux', { cause: error });\n }\n}\n","import {\n HybridEncKey,\n PwdProtectedKey,\n PublicKeys,\n PrivateKeys,\n EmailBody,\n EmailBodyEncrypted,\n Email,\n EmailPublicParameters,\n} from '../types';\nimport { encryptSymmetrically, decryptSymmetrically, genSymmetricKey } from '../symmetric-crypto';\nimport { encapsulateKyber, decapsulateKyber } from '../post-quantum-crypto';\nimport { deriveWrappingKey, wrapKey, unwrapKey } from '../key-wrapper';\nimport { deriveSecretKey } from '../asymmetric-crypto';\nimport { getKeyFromPassword, getKeyFromPasswordAndSalt } from '../derive-key';\nimport { UTF8ToUint8, base64ToUint8Array, uint8ArrayToBase64, uint8ToUTF8, uuidToBytes } from '../utils';\nimport { getAux } from './utils';\n\nexport async function encryptEmailBody(\n email: Email,\n isSubjectEncrypted: boolean,\n): Promise<{\n enc: EmailBodyEncrypted;\n params: EmailPublicParameters;\n encryptionKey: Uint8Array;\n}> {\n try {\n const aux = getAux(email.params, isSubjectEncrypted);\n\n let enc: EmailBodyEncrypted;\n let encryptionKey: Uint8Array;\n let params = email.params;\n\n if (isSubjectEncrypted) {\n const result = await encryptEmailContentAndSubjectSymmetrically(email.body, email.params.subject, aux, email.id);\n enc = result.enc;\n encryptionKey = result.encryptionKey;\n params = { ...email.params, subject: result.encSubject };\n } else {\n const result = await encryptEmailContentSymmetrically(email.body, aux, email.id);\n enc = result.enc;\n encryptionKey = result.encryptionKey;\n }\n\n return { encryptionKey, enc, params };\n } catch (error) {\n throw new Error('Failed to encrypt email body', { cause: error });\n }\n}\n\nexport async function decryptEmailBody(\n enc: EmailBodyEncrypted,\n encParams: EmailPublicParameters,\n encryptionKey: Uint8Array,\n isSubjectEncrypted: boolean,\n): Promise<{\n params: EmailPublicParameters;\n body: EmailBody;\n}> {\n try {\n const aux = getAux(encParams, isSubjectEncrypted);\n let body: EmailBody;\n let params = encParams;\n if (isSubjectEncrypted) {\n const result = await decryptEmailAndSubjectSymmetrically(encryptionKey, aux, encParams.subject, enc);\n body = result.body;\n params = { ...encParams, subject: result.subject };\n } else {\n body = await decryptEmailSymmetrically(encryptionKey, aux, enc);\n }\n\n return { body, params };\n } catch (error) {\n throw new Error('Failed to encrypt email body', { cause: error });\n }\n}\n\n/**\n * Symmetrically encrypts an email with a randomly sampled key.\n *\n * @param email - The email to encrypt.\n * @param aux - The auxiliary data (e.g., email ID or timestamp) for AEAD.\n * @param emailID - The unique identifier of the email.\n * @returns The resulting ciphertext and the used symmetric key\n */\nexport async function encryptEmailContentSymmetrically(\n email: EmailBody,\n aux: Uint8Array,\n emailID: string,\n): Promise<{ enc: EmailBodyEncrypted; encryptionKey: Uint8Array }> {\n try {\n if (!email.text) {\n throw new Error('Invalid input');\n }\n const encryptionKey = genSymmetricKey();\n const enc = await encryptEmailContentSymmetricallyWithKey(email, encryptionKey, aux, emailID);\n return { enc, encryptionKey };\n } catch (error) {\n throw new Error('Failed to symmetrically encrypt email', { cause: error });\n }\n}\n\n/**\n * Symmetrically encrypts an email with a randomly sampled key.\n *\n * @param email - The email to encrypt.\n * @param subject - The email subject to encrypt.\n * @param aux - The auxiliary data (e.g., email ID or timestamp) for AEAD.\n * @param emailID - The unique identifier of the email.\n * @returns The resulting ciphertext and the used symmetric key\n */\nexport async function encryptEmailContentAndSubjectSymmetrically(\n email: EmailBody,\n subject: string,\n aux: Uint8Array,\n emailID: string,\n): Promise<{ enc: EmailBodyEncrypted; encSubject: string; encryptionKey: Uint8Array }> {\n try {\n if (!subject || !email.text) {\n throw new Error('Invalid input');\n }\n const encryptionKey = genSymmetricKey();\n const enc = await encryptEmailContentSymmetricallyWithKey(email, encryptionKey, aux, emailID);\n const subjectBuff = UTF8ToUint8(subject);\n const subjectEnc = await encryptSymmetrically(encryptionKey, subjectBuff, aux);\n const encSubject = uint8ArrayToBase64(subjectEnc);\n return { enc, encSubject, encryptionKey };\n } catch (error) {\n throw new Error('Failed to symmetrically encrypt email and subject', { cause: error });\n }\n}\n\n/**\n * Decrypts symmetrically encrypted email.\n *\n * @param encryptedEmail - The email to decrypt.\n * @param encryptionKey - The symmetric key.\n * @returns The decrypted email\n */\nexport async function decryptEmailAndSubjectSymmetrically(\n encryptionKey: Uint8Array,\n aux: Uint8Array,\n encSubject: string,\n enc: EmailBodyEncrypted,\n): Promise<{ body: EmailBody; subject: string }> {\n try {\n const array = base64ToUint8Array(encSubject);\n const subjectArray = await decryptSymmetrically(encryptionKey, array, aux);\n const body = await decryptEmailSymmetrically(encryptionKey, aux, enc);\n const subject = uint8ToUTF8(subjectArray);\n return { body, subject };\n } catch (error) {\n throw new Error('Failed to symmetrically decrypt email and subject', { cause: error });\n }\n}\n\n/**\n * Symmetrically encrypts an email with a randomly sampled key.\n *\n * @param email - The email to encrypt.\n * @returns The resulting ciphertext and the used symmetric key\n */\nexport async function encryptEmailContentSymmetricallyWithKey(\n emailBody: EmailBody,\n encryptionKey: Uint8Array,\n aux: Uint8Array,\n emailID: string,\n): Promise<EmailBodyEncrypted> {\n try {\n const freeField = uuidToBytes(emailID);\n const text = UTF8ToUint8(emailBody.text);\n const encryptedText = await encryptSymmetrically(encryptionKey, text, aux, freeField);\n const encText = uint8ArrayToBase64(encryptedText);\n const result: EmailBodyEncrypted = { encText };\n\n if (emailBody.attachments) {\n const encryptedAttachements = await encryptEmailAttachements(emailBody.attachments, encryptionKey, aux, emailID);\n result.encAttachments = encryptedAttachements?.map(uint8ArrayToBase64);\n }\n return result;\n } catch (error) {\n throw new Error('Failed to symmetrically encrypt email with the given key', { cause: error });\n }\n}\n\nasync function encryptEmailAttachements(\n attachments: string[],\n encryptionKey: Uint8Array,\n aux: Uint8Array,\n emailID: string,\n): Promise<Uint8Array[]> {\n try {\n const freeField = uuidToBytes(emailID);\n const encryptedAttachments = await Promise.all(\n attachments.map((attachment) => {\n const binaryAttachment = UTF8ToUint8(attachment);\n return encryptSymmetrically(encryptionKey, binaryAttachment, aux, freeField);\n }),\n );\n return encryptedAttachments;\n } catch (error) {\n throw new Error('Failed to symmetrically encrypt email attachements', { cause: error });\n }\n}\n\nasync function decryptEmailAttachements(\n encryptedAttachments: Uint8Array[],\n encryptionKey: Uint8Array,\n aux: Uint8Array,\n): Promise<Uint8Array[]> {\n try {\n const decryptedAttachments = await Promise.all(\n encryptedAttachments.map((attachment) => {\n return decryptSymmetrically(encryptionKey, attachment, aux);\n }),\n );\n return decryptedAttachments;\n } catch (error) {\n throw new Error('Failed to symmetrically decrypt email attachements', { cause: error });\n }\n}\n\n/**\n * Decrypts symmetrically encrypted email.\n *\n * @param encryptedEmail - The email to decrypt.\n * @param encryptionKey - The symmetric key.\n * @returns The decrypted email\n */\nexport async function decryptEmailSymmetrically(\n encryptionKey: Uint8Array,\n aux: Uint8Array,\n enc: EmailBodyEncrypted,\n): Promise<EmailBody> {\n try {\n const cipher = base64ToUint8Array(enc.encText);\n const textArray = await decryptSymmetrically(encryptionKey, cipher, aux);\n const text = uint8ToUTF8(textArray);\n const result: EmailBody = { text };\n\n if (enc.encAttachments) {\n const encAttachements = enc.encAttachments?.map(base64ToUint8Array);\n const attachmentsArray = await decryptEmailAttachements(encAttachements, encryptionKey, aux);\n result.attachments = attachmentsArray?.map((att) => uint8ToUTF8(att));\n }\n return result;\n } catch (error) {\n throw new Error('Failed to symmetrically decrypt email', { cause: error });\n }\n}\n\n/**\n * Encrypts the email symmetric key using hybrid encryption.\n *\n * @param emailEncryptionKey - The symmetric key used for email encryption.\n * @param recipientPublicKey - The public key of the recipient.\n * @param senderPrivateKey - The private key of the sender.\n * @returns The encrypted email symmetric key\n */\nexport async function encryptKeysHybrid(\n emailEncryptionKey: Uint8Array,\n recipientPublicKey: PublicKeys,\n senderPrivateKey: PrivateKeys,\n): Promise<HybridEncKey> {\n try {\n const eccSecret = await deriveSecretKey(recipientPublicKey.eccPublicKey, senderPrivateKey.eccPrivateKey);\n const { cipherText: kyberCiphertext, sharedSecret: kyberSecret } = encapsulateKyber(\n recipientPublicKey.kyberPublicKey,\n );\n const wrappingKey = await deriveWrappingKey(eccSecret, kyberSecret);\n const encryptedKey = await wrapKey(emailEncryptionKey, wrappingKey);\n const encryptedKeyBase64 = uint8ArrayToBase64(encryptedKey);\n const kyberCiphertextBase64 = uint8ArrayToBase64(kyberCiphertext);\n\n return { encryptedKey: encryptedKeyBase64, kyberCiphertext: kyberCiphertextBase64 };\n } catch (error) {\n throw new Error('Failed to encrypt email key using hybrid encryption', { cause: error });\n }\n}\n\n/**\n * Decrypts the email symmetric key encrypted via hybrid encryption.\n *\n * @param encryptedKey - The encrypted email key.\n * @param senderPublicKey - The public key of the sender.\n * @param recipientPrivateKey - The private key of the recipient.\n * @returns The email encryption key\n */\nexport async function decryptKeysHybrid(\n encryptedKey: HybridEncKey,\n senderPublicKey: PublicKeys,\n recipientPrivateKey: PrivateKeys,\n): Promise<Uint8Array> {\n try {\n const kyberCiphertext = base64ToUint8Array(encryptedKey.kyberCiphertext);\n const encKey = base64ToUint8Array(encryptedKey.encryptedKey);\n const eccSecret = await deriveSecretKey(senderPublicKey.eccPublicKey, recipientPrivateKey.eccPrivateKey);\n const kyberSecret = decapsulateKyber(kyberCiphertext, recipientPrivateKey.kyberPrivateKey);\n const wrappingKey = await deriveWrappingKey(eccSecret, kyberSecret);\n const encryptionKey = await unwrapKey(encKey, wrappingKey);\n return encryptionKey;\n } catch (error) {\n throw new Error('Failed to decrypt email key encrypted via hybrid encryption', { cause: error });\n }\n}\n\n/**\n * Password-protects the email symmetric key.\n *\n * @param emailEncryptionKey - The symmetric key used for email encryption.\n * @param password - The secret password for key protection.\n * @returns The password-protected email symmetric key\n */\nexport async function passwordProtectKey(emailEncryptionKey: Uint8Array, password: string): Promise<PwdProtectedKey> {\n try {\n const { key, salt } = await getKeyFromPassword(password);\n const encryptedKey = await wrapKey(emailEncryptionKey, key);\n const saltStr = uint8ArrayToBase64(salt);\n const encryptedKeyStr = uint8ArrayToBase64(encryptedKey);\n return { encryptedKey: encryptedKeyStr, salt: saltStr };\n } catch (error) {\n throw new Error('Failed to password-protect email key', { cause: error });\n }\n}\n\n/**\n * Removes passoword-protection and exposes the email symmetric key.\n *\n * @param emailEncryptionKey - The password-protected email key.\n * @param password - The secret password for key protection.\n * @returns The email encryption key\n */\nexport async function removePasswordProtection(\n emailEncryptionKey: PwdProtectedKey,\n password: string,\n): Promise<Uint8Array> {\n try {\n const salt = base64ToUint8Array(emailEncryptionKey.salt);\n const encryptedKey = base64ToUint8Array(emailEncryptionKey.encryptedKey);\n const key = await getKeyFromPasswordAndSalt(password, salt);\n const encryptionKey = await unwrapKey(encryptedKey, key);\n return encryptionKey;\n } catch (error) {\n throw new Error('Failed to remove password-protection from email key', { cause: error });\n }\n}\n","import { PublicKeys, PrivateKeys, HybridEncryptedEmail, Email, UserWithPublicKeys } from '../types';\nimport { decryptEmailBody, encryptKeysHybrid, decryptKeysHybrid, encryptEmailBody } from './core';\n\n/**\n * Encrypts the email using hybrid encryption.\n *\n * @param email - The email to encrypt.\n * @param recipientPublicKeys - The public keys of the recipient.\n * @param senderPrivateKey - The private key of the sender.\n * @param isSubjectEncrypted - Indicates if the email subject field should be encrypted\n * @returns The encrypted email\n */\nexport async function encryptEmailHybrid(\n email: Email,\n recipient: UserWithPublicKeys,\n senderPrivateKey: PrivateKeys,\n isSubjectEncrypted: boolean = false,\n): Promise<HybridEncryptedEmail> {\n try {\n const { encryptionKey, params, enc } = await encryptEmailBody(email, isSubjectEncrypted);\n const encryptedKey = await encryptKeysHybrid(encryptionKey, recipient.publicKeys, senderPrivateKey);\n return { enc, encryptedKey, recipientEmail: recipient.email, params, isSubjectEncrypted, id: email.id };\n } catch (error) {\n throw new Error('Failed to encrypt email with hybrid encryption', { cause: error });\n }\n}\n\n/**\n * Encrypts the email using hybrid encryption for multiple recipients.\n *\n * @param email - The email to encrypt.\n * @param recipients - The recipients with corresponding public keys.\n * @param senderPrivateKey - The private key of the sender.\n * @param isSubjectEncrypted - Indicates if the email subject field should be encrypted\n * @returns The set of encrypted email\n */\nexport async function encryptEmailHybridForMultipleRecipients(\n email: Email,\n recipients: UserWithPublicKeys[],\n senderPrivateKey: PrivateKeys,\n isSubjectEncrypted: boolean = false,\n): Promise<HybridEncryptedEmail[]> {\n try {\n const { encryptionKey, params, enc } = await encryptEmailBody(email, isSubjectEncrypted);\n\n const encryptedEmails: HybridEncryptedEmail[] = [];\n for (const recipient of recipients) {\n const encryptedKey = await encryptKeysHybrid(encryptionKey, recipient.publicKeys, senderPrivateKey);\n encryptedEmails.push({\n enc,\n encryptedKey,\n recipientEmail: recipient.email,\n params,\n isSubjectEncrypted,\n id: email.id,\n });\n }\n return encryptedEmails;\n } catch (error) {\n throw new Error('Failed to encrypt email to multiple recipients with hybrid encryption', { cause: error });\n }\n}\n\n/**\n * Decrypts the email using hybrid encryption.\n *\n * @param encryptedEmail - The encrypted email.\n * @param senderPublicKeys - The public key of the sender.\n * @param recipientPrivateKeys - The private key of the recipient.\n * @returns The decrypted email\n */\nexport async function decryptEmailHybrid(\n encryptedEmail: HybridEncryptedEmail,\n senderPublicKeys: PublicKeys,\n recipientPrivateKeys: PrivateKeys,\n): Promise<Email> {\n try {\n const { isSubjectEncrypted, params: encParams, enc, encryptedKey, id } = encryptedEmail;\n const encryptionKey = await decryptKeysHybrid(encryptedKey, senderPublicKeys, recipientPrivateKeys);\n const { body, params } = await decryptEmailBody(enc, encParams, encryptionKey, isSubjectEncrypted);\n return { body, params, id };\n } catch (error) {\n throw new Error('Failed to decrypt email with hybrid encryption', { cause: error });\n }\n}\n","import { PwdProtectedEmail, Email } from '../types';\nimport { decryptEmailBody, passwordProtectKey, removePasswordProtection, encryptEmailBody } from './core';\n\n/**\n * Creates a password-protected email.\n *\n * @param email - The email to password-protect\n * @param password - The secret password shared among recipients\n * @param isSubjectEncrypted - Indicates if the email subject field should be encrypted\n * @returns The password-protected email\n */\nexport async function createPwdProtectedEmail(\n email: Email,\n password: string,\n isSubjectEncrypted: boolean = false,\n): Promise<PwdProtectedEmail> {\n try {\n if (!email?.body || !email.params) {\n throw new Error('Failed to password-protect email: Invalid email structure');\n }\n const { encryptionKey, params, enc } = await encryptEmailBody(email, isSubjectEncrypted);\n const encryptedKey = await passwordProtectKey(encryptionKey, password);\n\n return { enc, encryptedKey, params, id: email.id, isSubjectEncrypted };\n } catch (error) {\n throw new Error('Failed to password-protect email', { cause: error });\n }\n}\n\n/**\n * Opens a password-protected email.\n *\n * @param encryptedEmail - The encrypted email\n * @param password - The secret password shared among recipients.\n * @returns The decrypted email\n */\nexport async function decryptPwdProtectedEmail(encryptedEmail: PwdProtectedEmail, password: string): Promise<Email> {\n try {\n const { isSubjectEncrypted, params: encParams, enc, id } = encryptedEmail;\n const encryptionKey = await removePasswordProtection(encryptedEmail.encryptedKey, password);\n const { body, params } = await decryptEmailBody(enc, encParams, encryptionKey, isSubjectEncrypted);\n return { body, params, id };\n } catch (error) {\n throw new Error('Failed to decrypt password-protect email', { cause: error });\n }\n}\n","import { generateEccKeys } from '../asymmetric-crypto';\nimport { generateKyberKeys } from '../post-quantum-crypto';\nimport { EmailKeys } from '../types';\n\n/**\n * Generates public and private keys for email service.\n *\n * @returns The user's private and public keys\n */\nexport async function generateEmailKeys(): Promise<EmailKeys> {\n try {\n const kyberKeys = generateKyberKeys();\n const keys = await generateEccKeys();\n\n const emailKeys: EmailKeys = {\n publicKeys: {\n eccPublicKey: keys.publicKey,\n kyberPublicKey: kyberKeys.publicKey,\n },\n privateKeys: {\n eccPrivateKey: keys.privateKey,\n kyberPrivateKey: kyberKeys.secretKey,\n },\n };\n\n return emailKeys;\n } catch (error) {\n throw new Error('Failed to generate keys for email service', { cause: error });\n }\n}\n"],"mappings":"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"}