internxt-crypto 0.0.11 → 0.0.13

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 (163) hide show
  1. package/dist/{symmetric-crypto-CrdS1Che.mjs → aes-DSDxP8uF.mjs} +4 -17
  2. package/dist/aes-DSDxP8uF.mjs.map +1 -0
  3. package/dist/{symmetric-crypto-D65zB396.js → aes-bOrKZuUC.js} +7 -25
  4. package/dist/aes-bOrKZuUC.js.map +1 -0
  5. package/dist/asymmetric-crypto.d.mts +1 -4
  6. package/dist/asymmetric-crypto.d.mts.map +1 -0
  7. package/dist/asymmetric-crypto.d.ts +1 -4
  8. package/dist/asymmetric-crypto.d.ts.map +1 -0
  9. package/dist/asymmetric-crypto.js +8 -7
  10. package/dist/asymmetric-crypto.mjs +1 -1
  11. package/dist/{chunk-DWirmd9C.mjs → chunk-DQk6qfdC.mjs} +3 -3
  12. package/dist/{chunk-Dt-PWiN7.js → chunk-EbLFQX5m.js} +3 -3
  13. package/dist/constants.d.mts.map +1 -0
  14. package/dist/constants.d.ts.map +1 -0
  15. package/dist/constants.js +63 -30
  16. package/dist/constants.js.map +1 -0
  17. package/dist/constants.mjs +33 -2
  18. package/dist/constants.mjs.map +1 -0
  19. package/dist/derive-key.d.mts +1 -4
  20. package/dist/derive-key.d.mts.map +1 -0
  21. package/dist/derive-key.d.ts +1 -4
  22. package/dist/derive-key.d.ts.map +1 -0
  23. package/dist/derive-key.js +12 -14
  24. package/dist/derive-key.mjs +1 -4
  25. package/dist/{derive-key-Be7hS-cN.mjs → deriveKeysFromPassword-DJRWZ8Rw.mjs} +5 -21
  26. package/dist/deriveKeysFromPassword-DJRWZ8Rw.mjs.map +1 -0
  27. package/dist/{derive-key-CBf2WxJd.js → deriveKeysFromPassword-Ko7NxkHM.js} +24 -45
  28. package/dist/deriveKeysFromPassword-Ko7NxkHM.js.map +1 -0
  29. package/dist/email-crypto.d.mts +2 -5
  30. package/dist/email-crypto.d.mts.map +1 -0
  31. package/dist/email-crypto.d.ts +2 -5
  32. package/dist/email-crypto.d.ts.map +1 -0
  33. package/dist/email-crypto.js +12 -16
  34. package/dist/email-crypto.mjs +1 -6
  35. package/dist/email-search.d.mts +2 -5
  36. package/dist/email-search.d.mts.map +1 -0
  37. package/dist/email-search.d.ts +2 -5
  38. package/dist/email-search.d.ts.map +1 -0
  39. package/dist/email-search.js +14 -52
  40. package/dist/email-search.js.map +1 -1
  41. package/dist/email-search.mjs +5 -39
  42. package/dist/email-search.mjs.map +1 -1
  43. package/dist/{keystore-crypto-Bjgriq9h.mjs → emailEncryptionKey-27mIHh18.mjs} +10 -19
  44. package/dist/emailEncryptionKey-27mIHh18.mjs.map +1 -0
  45. package/dist/{keystore-crypto-B4yCVo9l.js → emailEncryptionKey-DbaDAdoW.js} +25 -40
  46. package/dist/emailEncryptionKey-DbaDAdoW.js.map +1 -0
  47. package/dist/{email-crypto-BrT98taw.js → emailKeys-BJGdkLrg.js} +50 -74
  48. package/dist/emailKeys-BJGdkLrg.js.map +1 -0
  49. package/dist/{email-crypto-DJUEjTxA.mjs → emailKeys-Fp9WR3wl.mjs} +8 -33
  50. package/dist/emailKeys-Fp9WR3wl.mjs.map +1 -0
  51. package/dist/{utils-DS04iUcX.mjs → genID-3Er5IowC.mjs} +4 -24
  52. package/dist/genID-3Er5IowC.mjs.map +1 -0
  53. package/dist/{utils-CNs3cyDj.js → genID-YJSl3YhL.js} +6 -31
  54. package/dist/genID-YJSl3YhL.js.map +1 -0
  55. package/dist/hash.d.mts +1 -4
  56. package/dist/hash.d.mts.map +1 -0
  57. package/dist/hash.d.ts +1 -4
  58. package/dist/hash.d.ts.map +1 -0
  59. package/dist/hash.js +11 -10
  60. package/dist/hash.mjs +1 -1
  61. package/dist/index.d.mts +11 -31
  62. package/dist/index.d.mts.map +1 -0
  63. package/dist/index.d.ts +11 -31
  64. package/dist/index.d.ts.map +1 -0
  65. package/dist/index.js +93 -84
  66. package/dist/index.mjs +12 -14
  67. package/dist/{asymmetric-crypto-CyXsV4XT.mjs → keys-BfcaiAOv.mjs} +3 -15
  68. package/dist/keys-BfcaiAOv.mjs.map +1 -0
  69. package/dist/{asymmetric-crypto-BORmLhnx.js → keys-CinT7kEY.js} +2 -20
  70. package/dist/keys-CinT7kEY.js.map +1 -0
  71. package/dist/keystore-crypto.d.mts +2 -5
  72. package/dist/keystore-crypto.d.mts.map +1 -0
  73. package/dist/keystore-crypto.d.ts +2 -5
  74. package/dist/keystore-crypto.d.ts.map +1 -0
  75. package/dist/keystore-crypto.js +5 -10
  76. package/dist/keystore-crypto.mjs +1 -7
  77. package/dist/{post-quantum-crypto-Vv34t6gX.mjs → kyber1024-PpwE1rki.mjs} +3 -13
  78. package/dist/kyber1024-PpwE1rki.mjs.map +1 -0
  79. package/dist/{post-quantum-crypto-CAi-cEkV.js → kyber1024-jeKS8CXf.js} +2 -18
  80. package/dist/kyber1024-jeKS8CXf.js.map +1 -0
  81. package/dist/kyber768-DGBB_RS7.d.ts +32 -0
  82. package/dist/kyber768-DGBB_RS7.d.ts.map +1 -0
  83. package/dist/kyber768-DzIcGg1i.d.mts +32 -0
  84. package/dist/kyber768-DzIcGg1i.d.mts.map +1 -0
  85. package/dist/{hash-BoqwNkcd.js → mac-BMb1F0dN.js} +3 -23
  86. package/dist/mac-BMb1F0dN.js.map +1 -0
  87. package/dist/{hash-CXeGAwai.mjs → mac-ZpRlx8Fs.mjs} +3 -18
  88. package/dist/mac-ZpRlx8Fs.mjs.map +1 -0
  89. package/dist/post-quantum-crypto.d.mts +68 -2
  90. package/dist/post-quantum-crypto.d.mts.map +1 -0
  91. package/dist/post-quantum-crypto.d.ts +68 -2
  92. package/dist/post-quantum-crypto.d.ts.map +1 -0
  93. package/dist/post-quantum-crypto.js +7 -6
  94. package/dist/post-quantum-crypto.mjs +1 -1
  95. package/dist/storage-service.d.mts +47 -2
  96. package/dist/storage-service.d.mts.map +1 -0
  97. package/dist/storage-service.d.ts +47 -2
  98. package/dist/storage-service.d.ts.map +1 -0
  99. package/dist/storage-service.js +58 -4
  100. package/dist/storage-service.js.map +1 -0
  101. package/dist/storage-service.mjs +55 -2
  102. package/dist/storage-service.mjs.map +1 -0
  103. package/dist/symmetric-crypto.d.mts +1 -4
  104. package/dist/symmetric-crypto.d.mts.map +1 -0
  105. package/dist/symmetric-crypto.d.ts +1 -4
  106. package/dist/symmetric-crypto.d.ts.map +1 -0
  107. package/dist/symmetric-crypto.js +9 -9
  108. package/dist/symmetric-crypto.mjs +1 -2
  109. package/dist/types.d.mts +104 -2
  110. package/dist/types.d.mts.map +1 -0
  111. package/dist/types.d.ts +104 -2
  112. package/dist/types.d.ts.map +1 -0
  113. package/dist/types.js +11 -2
  114. package/dist/types.js.map +1 -0
  115. package/dist/types.mjs +9 -2
  116. package/dist/types.mjs.map +1 -0
  117. package/dist/utils.d.mts +2 -5
  118. package/dist/utils.d.mts.map +1 -0
  119. package/dist/utils.d.ts +2 -5
  120. package/dist/utils.d.ts.map +1 -0
  121. package/dist/utils.js +16 -15
  122. package/dist/utils.mjs +1 -1
  123. package/package.json +23 -14
  124. package/dist/asymmetric-crypto-BORmLhnx.js.map +0 -1
  125. package/dist/asymmetric-crypto-CyXsV4XT.mjs.map +0 -1
  126. package/dist/constants-Ccp21E03.js +0 -208
  127. package/dist/constants-Ccp21E03.js.map +0 -1
  128. package/dist/constants-kTeX-2T0.mjs +0 -34
  129. package/dist/constants-kTeX-2T0.mjs.map +0 -1
  130. package/dist/derive-key-Be7hS-cN.mjs.map +0 -1
  131. package/dist/derive-key-CBf2WxJd.js.map +0 -1
  132. package/dist/email-crypto-BrT98taw.js.map +0 -1
  133. package/dist/email-crypto-DJUEjTxA.mjs.map +0 -1
  134. package/dist/hash-BoqwNkcd.js.map +0 -1
  135. package/dist/hash-CXeGAwai.mjs.map +0 -1
  136. package/dist/index-CQqgKsbX.d.ts +0 -50
  137. package/dist/index-CintVUbp.d.ts +0 -97
  138. package/dist/index-D5pBU_A5.d.mts +0 -50
  139. package/dist/index-MaOov-ag.d.mts +0 -97
  140. package/dist/keystore-crypto-B4yCVo9l.js.map +0 -1
  141. package/dist/keystore-crypto-Bjgriq9h.mjs.map +0 -1
  142. package/dist/keystore-service.d.mts +0 -48
  143. package/dist/keystore-service.d.ts +0 -48
  144. package/dist/keystore-service.js +0 -122
  145. package/dist/keystore-service.js.map +0 -1
  146. package/dist/keystore-service.mjs +0 -114
  147. package/dist/keystore-service.mjs.map +0 -1
  148. package/dist/post-quantum-crypto-CAi-cEkV.js.map +0 -1
  149. package/dist/post-quantum-crypto-Vv34t6gX.mjs.map +0 -1
  150. package/dist/storage-service-BgIK2aYZ.js +0 -82
  151. package/dist/storage-service-BgIK2aYZ.js.map +0 -1
  152. package/dist/storage-service-CubCbhY2.mjs +0 -65
  153. package/dist/storage-service-CubCbhY2.mjs.map +0 -1
  154. package/dist/symmetric-crypto-CrdS1Che.mjs.map +0 -1
  155. package/dist/symmetric-crypto-D65zB396.js.map +0 -1
  156. package/dist/types-52g887Zi.js +0 -16
  157. package/dist/types-52g887Zi.js.map +0 -1
  158. package/dist/types-BiEoleqw.mjs +0 -10
  159. package/dist/types-BiEoleqw.mjs.map +0 -1
  160. package/dist/types-Ds3ivE9W.d.ts +0 -104
  161. package/dist/types-DwQJtrTx.d.mts +0 -104
  162. package/dist/utils-CNs3cyDj.js.map +0 -1
  163. package/dist/utils-DS04iUcX.mjs.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","../src/email-search/index.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}`);\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","export * from './indexedDB';\nexport * from './mailCache';\nexport * from './search';\n"],"mappings":";;;;;;;;;;;;;;;;;;AAuBA,MAAM,mBAAmB,WAA2B;AAClD,QAAO,MAAM,OAAO;;;;;;;;AAStB,MAAa,eAAe,OAAO,WAAoC;AACrE,KAAI;AAEF,SAAO,OADQ,gBAAgB,OAAO,EACG,YAAY,EACnD,QAAQ,IAAI;AACV,OAAI,CAAC,GAAG,iBAAiB,SAAS,SAAS,CAEzC,CADc,GAAG,kBAAkB,UAAU,EAAE,SAAS,MAAM,CAAC,CACzD,YAAY,UAAU,mBAAmB;KAGpD,CAAC;UACK,OAAO;AACd,QAAM,IAAI,MAAM,uCAAuC,UAAU,EAAE,OAAO,OAAO,CAAC;;;;;;;;AAStF,MAAa,iBAAiB,SAAuB;AACnD,QAAO,KAAK,OAAO;;;;;;;;AASrB,MAAa,iBAAiB,OAAO,WAAkC;AAErE,QAAO,SADQ,gBAAgB,OAAO,CACf;;;;;;;;AASzB,MAAa,iBAAiB,OAAO,YAA4C;AAC/E,QAAO,oCAAoC,eAAe,QAAQ;;;;;;;;;AAUpE,MAAa,uBAAuB,OAClC,iBACA,UACA,SACkB;AAClB,KAAI;EACF,MAAM,MAAM,OAAO,gBAAgB,QAAQ,MAAM;EAEjD,MAAM,iBAA8B;GAAE,KAD1B,MAAM,wCAAwC,gBAAgB,MAAM,UAAU,KAAK,gBAAgB,GAAG;GACvE,QAAQ,gBAAgB;GAAQ,IAAI,gBAAgB;GAAI;AACnG,QAAM,KAAK,IAAI,UAAU,eAAe;UACjC,OAAO;AACd,QAAM,IAAI,MAAM,0DAA0D,EAAE,OAAO,OAAO,CAAC;;;;;;;;;;AAW/F,MAAa,2BAA2B,OACtC,kBACA,UACA,SACkB;AAClB,KAAI;EACF,MAAM,kBAAkB,MAAM,QAAQ,IACpC,iBAAiB,IAAI,OAAO,UAAiB;GAC3C,MAAM,MAAM,OAAO,MAAM,QAAQ,MAAM;AAGvC,UAAO;IAAE,KAFG,MAAM,wCAAwC,MAAM,MAAM,UAAU,KAAK,MAAM,GAAG;IAEhF,QAAQ,MAAM;IAAQ,IAAI,MAAM;IAAI;IAClD,CACH;EAED,MAAM,KAAK,KAAK,YAAY,UAAU,YAAY;AAClD,QAAM,QAAQ,IAAI,CAAC,GAAG,gBAAgB,KAAK,aAAa,GAAG,MAAM,IAAI,SAAS,CAAC,EAAE,GAAG,KAAK,CAAC;UACnF,OAAO;AACd,QAAM,IAAI,MAAM,iDAAiD,EAAE,OAAO,OAAO,CAAC;;;;;;;;;;AAWtF,MAAM,eAAe,OAAO,UAAqB,mBAAgD;AAC/F,KAAI;AAGF,SAAO;GAAE,MADK,MAAM,0BAA0B,UADlC,OAAO,eAAe,QAAQ,MAAM,EACa,eAAe,IAAI;GAC1D,QAAQ,eAAe;GAAQ,IAAI,eAAe;GAAI;UACrE,OAAO;AACd,QAAM,IAAI,MAAM,kCAAkC,EAAE,OAAO,OAAO,CAAC;;;;;;;;;;;AAYvE,MAAa,qBAAqB,OAAO,SAAiB,UAAqB,SAAiC;AAC9G,KAAI;EACF,MAAM,iBAAiB,MAAM,KAAK,IAAI,UAAU,QAAQ;AACxD,MAAI,CAAC,eACH,OAAM,IAAI,MAAM,gCAAgC,UAAU;AAE5D,SAAO,aAAa,UAAU,eAAe;UACtC,OAAO;AACd,QAAM,IAAI,MAAM,0BAA0B,QAAQ,qBAAqB,EAAE,OAAO,OAAO,CAAC;;;;;;;;;;AAW5F,MAAa,yBAAyB,OAAO,UAAqB,SAAmC;AACnG,KAAI;EACF,MAAM,kBAAkB,MAAM,KAAK,OAAO,SAAS;AAUnD,UARwB,MAAM,QAAQ,IACpC,gBAAgB,IAAI,OAAO,aAAa;AAGtC,UAAO;IAAE,MADI,MAAM,0BAA0B,UADjC,OAAO,SAAS,QAAQ,MAAM,EACkB,SAAS,IAAI;IAC1D,QAAQ,SAAS;IAAQ,IAAI,SAAS;IAAI;IACzD,CACH,EAEsB,QAAQ,UAA0B,UAAU,KAAK;UACjE,OAAO;AACd,QAAM,IAAI,MAAM,yDAAyD,EAAE,OAAO,OAAO,CAAC;;;;;;;;;AAU9F,MAAa,cAAc,OAAO,SAAiB,SAAgC;AACjF,OAAM,KAAK,OAAO,UAAU,QAAQ;;;;;;;;AAStC,MAAa,gBAAgB,OAAO,SAAkC;AACpE,QAAO,MAAM,KAAK,MAAM,SAAS;;;;;;;;AASnC,MAAa,qBAAqB,OAAO,gBAAwB,SAAgC;AAC/F,KAAI;EACF,MAAM,KAAK,KAAK,YAAY,UAAU,YAAY;EAGlD,IAAI,SAAS,MAFC,GAAG,MAAM,MAAM,SAAS,CAEb,YAAY;EACrC,IAAI,eAAe;AAEnB,SAAO,UAAU,eAAe,gBAAgB;AAC9C,SAAM,OAAO,QAAQ;AACrB;AACA,YAAS,MAAM,OAAO,UAAU;;AAGlC,QAAM,GAAG;UACF,OAAO;AACd,QAAM,IAAI,MAAM,iBAAiB,eAAe,oCAAoC,EAAE,OAAO,OAAO,CAAC;;;;;;;;;AAUzG,MAAa,wBAAwB,OAAO,MAAc,QAA+B;AACvF,KAAI;EACF,MAAM,eAAe,MAAM,cAAc,KAAK;AAC9C,MAAI,gBAAgB,IAClB;AAEF,QAAM,mBAAmB,eAAe,KAAK,KAAK;UAC3C,OAAO;AACd,QAAM,IAAI,MAAM,iCAAiC,IAAI,0BAA0B,EAAE,OAAO,OAAO,CAAC;;;;;;;;;;;AAYpG,MAAM,cAAc,OAAO,MAAc,UAAqB,cAAiD;AAC7G,KAAI;EAEF,MAAM,QADK,KAAK,YAAY,UAAU,WAAW,CAChC,MAAM,MAAM,SAAS;EAEtC,MAAM,kBAAiC,EAAE;EACzC,IAAI,SAAS,MAAM,MAAM,WAAW,MAAM,UAAU;AAEpD,SAAO,QAAQ;AACb,mBAAgB,KAAK,OAAO,MAAM;AAClC,YAAS,MAAM,OAAO,UAAU;;AAKlC,SAFe,MAAM,QAAQ,IAAI,gBAAgB,KAAK,mBAAmB,aAAa,UAAU,eAAe,CAAC,CAAC;UAG1G,OAAO;AACd,QAAM,IAAI,MAAM,qCAAqC,EAAE,OAAO,OAAO,CAAC;;;;;;;;;;AAW1E,MAAa,gCAAgC,OAAO,MAAc,aAA0C;AAC1G,QAAO,YAAY,MAAM,UAAU,OAAO;;;;;;;;;AAU5C,MAAa,gCAAgC,OAAO,MAAc,aAA0C;AAC1G,QAAO,YAAY,MAAM,UAAU,OAAO;;;;;;;;;;;AAY5C,MAAa,gBAAgB,OAC3B,MACA,UACA,WACA,gBAC2D;AAC3D,KAAI;EAEF,MAAM,QADK,KAAK,YAAY,UAAU,WAAW,CAChC,MAAM,MAAM,SAAS;EAEtC,MAAM,kBAAiC,EAAE;EACzC,IAAI;AAEJ,MAAI,aAAa;GACf,MAAM,QAAQ,YAAY,WAAW,aAAa,KAAK;AACvD,YAAS,MAAM,MAAM,WAAW,OAAO,OAAO;QAE9C,UAAS,MAAM,MAAM,WAAW,MAAM,OAAO;EAG/C,IAAI,QAAQ;EACZ,IAAI;AAEJ,SAAO,UAAU,QAAQ,WAAW;AAClC,mBAAgB,KAAK,OAAO,MAAM;AAClC,gBAAa,OAAO;AACpB;AACA,YAAS,MAAM,OAAO,UAAU;;AAKlC,SAAO;GACL,QAHa,MAAM,QAAQ,IAAI,gBAAgB,KAAK,mBAAmB,aAAa,UAAU,eAAe,CAAC,CAAC;GAI/G,YAAY,UAAU,YAAY,aAAa;GAChD;UACM,OAAO;AACd,QAAM,IAAI,MAAM,+BAA+B,UAAU,qBAAqB,EAAE,OAAO,OAAO,CAAC;;;;;;;;;;;;ACtVnG,SAAS,YAAY,OAAsB;AACzC,QAAO,cAAc,MAAM,CAAC;;;;;;;AAQ9B,SAAS,mBAAqC;AAC5C,QAAO;EACL,yBAAS,IAAI,KAAK;EAClB,WAAW;EACX,gBAAgB;EAChB,cAAc;EACf;;;;;;;;;AAUH,MAAa,oBAAoB,OAAO,UAAqB,SAA4C;CACvG,MAAM,UAAU,kBAAkB;AAClC,SAAQ,eAAe;AACvB,KAAI;EACF,MAAM,QAAQ,MAAM,cAAc,KAAK;AACvC,MAAI,CAAC,OAAO;AACV,WAAQ,eAAe;AACvB,UAAO;;AAGT,MAAI,SAAS,oBAEX,kBADe,MAAM,8BAA8B,MAAM,SAAS,EACzC,QAAQ;OAC5B;GACL,IAAI,aAAsC;GAE1C,IAAI,YAAY;AAChB,UAAO,CAAC,WAAW;IACjB,MAAM,EAAE,QAAQ,YAAY,cAA6D,MAAM,cAC7F,MACA,UACA,qBACA,WACD;AACD,QAAI,CAAC,aAAa,CAAC,OAAO,OAAQ;AAClC,iBAAa;AAGb,QAAI,CADY,iBAAiB,QAAQ,QAAQ,CACnC,aAAY;;;AAG9B,SAAO;UACA,OAAO;AACd,QAAM,IAAI,MAAM,yBAAyB,QAAQ;;;;;;;;;;AAWrD,MAAa,oBAAoB,OAAO,SAAiB,YAA8C;CACrG,MAAM,QAAQ,QAAQ,QAAQ,IAAI,QAAQ;AAC1C,KAAI,CAAC,MACH,OAAM,IAAI,MAAM,oCAAoC,UAAU;AAEhE,QAAO;;;;;;;;AAST,MAAa,uBAAuB,OAAO,SAAiB,YAA6C;AACvG,KAAI;EAEF,MAAM,OAAO,YADC,MAAM,kBAAkB,SAAS,QAAQ,CACxB;AAE/B,MADgB,QAAQ,QAAQ,OAAO,QAAQ,CAClC,SAAQ,aAAa;UAC3B,OAAO;AACd,QAAM,IAAI,MAAM,kCAAkC,WAAW,EAAE,OAAO,OAAO,CAAC;;;;;;;;;;AAWlF,SAAgB,iBAAiB,QAAiB,SAAkE;AAClH,KAAI;AACF,OAAK,MAAM,SAAS,QAAQ;GAC1B,MAAM,SAAS,gBAAgB,OAAO,QAAQ;AAC9C,OAAI,CAAC,OAAO,QAAS,QAAO;;AAE9B,SAAO,EAAE,SAAS,MAAM;UACjB,OAAO;AACd,QAAM,IAAI,MAAM,qCAAqC,EAAE,OAAO,OAAO,CAAC;;;;;;;;;;AAW1E,MAAa,mBAAmB,OAAc,YAAqE;AACjH,KAAI;AACF,MAAI,QAAQ,QAAQ,IAAI,MAAM,GAAG,CAC/B,QAAO;GAAE,SAAS;GAAO,QAAQ;GAAiC;EAGpE,MAAM,YAAY,YAAY,MAAM;AAEpC,MAAI,QAAQ,YAAY,YAAY,gBAAgB;AAClD,WAAQ,iBAAiB;AACzB,UAAO;IAAE,SAAS;IAAO,QAAQ;IAAmB;;AAGtD,UAAQ,QAAQ,IAAI,MAAM,IAAI,MAAM;AACpC,UAAQ,aAAa;AAErB,SAAO,EAAE,SAAS,MAAM;UACjB,OAAO;AACd,QAAM,IAAI,MAAM,oCAAoC,EAAE,OAAO,OAAO,CAAC;;;;;;ACzIzE,MAAM,kBAAwC;CAC5C,QAAQ;CACR,UAAU;CACV,YAAY;CACZ,WAAW;CACX,UAAU;CACV,YAAY;CACZ,OAAO;CACR;AACD,MAAM,eAAqC;CACzC,GAAG;CACH,WAAW;CACX,YAAY;CACb;AAED,MAAM,eAAqC;CACzC,GAAG;CACH,UAAU;CACV,WAAW;CACZ;AAED,MAAM,aAAmC;CACvC,GAAG;CACH,UAAU;CACV,WAAW;CACZ;;;;;;AAeD,MAAM,2BAA6C;CACjD,cAAc,IAAI,MAAM,gBAAgB;CACxC,WAAW,IAAI,MAAM,aAAa;CAClC,WAAW,IAAI,MAAM,aAAa;CAClC,SAAS,IAAI,MAAM,WAAW;CAC9B,SAAS;CACV;;;;;;;AAQD,MAAa,yBAAyB,OAAc,gBAAwC;AAC1F,KAAI;EACF,MAAM,UAAU,MAAM;AAEtB,MAAI,MAAM,OAAO,QACf,aAAY,aAAa,IAAI,SAAS,MAAM,OAAO,QAAQ;AAG7D,MAAI,MAAM,MAAM,KACd,aAAY,UAAU,IAAI,SAAS,MAAM,KAAK,KAAK;AAGrD,MAAI,MAAM,OAAO,QAAQ;GACvB,MAAM,aAAa,GAAG,MAAM,OAAO,OAAO,QAAQ,GAAG,GAAG,MAAM,OAAO,OAAO,SAAS,KAAK,MAAM;AAChG,eAAY,UAAU,IAAI,SAAS,WAAW;;EAKhD,MAAM,kBAFiB,MAAM,OAAO,YAAY,SAAS,MAAM,OAAO,aAAa,CAAC,MAAM,OAAO,UAAU,EAGxG,KAAK,cAAc,GAAG,UAAU,QAAQ,GAAG,GAAG,UAAU,SAAS,KAAK,MAAM,CAAC,CAC7E,KAAK,IAAI;AACZ,cAAY,QAAQ,IAAI,SAAS,eAAe;UACzC,OAAO;AACd,QAAM,IAAI,MAAM,2CAA2C,EAAE,OAAO,OAAO,CAAC;;;;;;;;;AAUhF,MAAa,8BAA8B,SAAiB,gBAAwC;AAClG,KAAI;AACF,cAAY,aAAa,OAAO,QAAQ;AACxC,cAAY,UAAU,OAAO,QAAQ;AACrC,cAAY,UAAU,OAAO,QAAQ;AACrC,cAAY,QAAQ,OAAO,QAAQ;UAC5B,OAAO;AACd,QAAM,IAAI,MAAM,kCAAkC,QAAQ,yBAAyB,EAAE,OAAO,OAAO,CAAC;;;;;;;;;AAUxG,MAAa,4BAA4B,OAAO,YAAyD;AACvG,KAAI;EACF,MAAM,cAAc,mBAAmB;AACvC,cAAY,UAAU;AAEtB,OAAK,MAAM,SAAS,QAAQ,QAAQ,QAAQ,CAC1C,uBAAsB,OAAO,YAAY;AAG3C,cAAY,UAAU;AACtB,SAAO;UACA,OAAO;AACd,QAAM,IAAI,MAAM,qDAAqD,EAAE,OAAO,OAAO,CAAC;;;;;;;;;;;;AAwB1F,MAAa,eAAe,OAC1B,OACA,SACA,aACA,UAAyB,EAAE,KACM;AACjC,KAAI;AACF,MAAI,CAAC,YAAY,WAAW,CAAC,MAAM,MAAM,CACvC,QAAO,EAAE;EAGX,MAAM,EACJ,SAAS;GAAC;GAAW;GAAQ;GAAQ;GAAK,EAC1C,QAAQ,IACR,QAAQ;GAAE,SAAS;GAAG,MAAM;GAAG,MAAM;GAAG,IAAI;GAAG,KAC7C;EAEJ,MAAM,0BAAU,IAAI,KAAqB;EAEzC,MAAM,iBAAiB,OAAO,IAAI,OAAO,UAAU;GACjD,IAAI;AAEJ,WAAQ,OAAR;IACE,KAAK;AACH,oBAAe,MAAM,YAAY,aAAa,YAAY,MAAM;AAChE;IACF,KAAK;AACH,oBAAe,MAAM,YAAY,UAAU,YAAY,MAAM;AAC7D;IACF,KAAK;AACH,oBAAe,MAAM,YAAY,UAAU,YAAY,MAAM;AAC7D;IACF,KAAK;AACH,oBAAe,MAAM,YAAY,QAAQ,YAAY,MAAM;AAC3D;IACF,QACE;;GAGJ,MAAM,aAAa,MAAM,UAAU;AAEnC,gBAAa,SAAS,YAAY;IAChC,MAAM,eAAe,QAAQ,IAAI,OAAO,QAAQ,CAAC,IAAI;AACrD,YAAQ,IAAI,OAAO,QAAQ,EAAE,eAAe,WAAW;KACvD;IACF;AAEF,QAAM,QAAQ,IAAI,eAAe;EAEjC,MAAM,eAAoC,EAAE;AAE5C,OAAK,MAAM,CAAC,SAAS,UAAU,SAAS;GACtC,MAAM,QAAQ,QAAQ,QAAQ,IAAI,QAAQ;AAC1C,OAAI,MACF,cAAa,KAAK;IAAE;IAAO;IAAO,CAAC;;AAGvC,eAAa,MAAM,GAAG,OAAO,EAAE,SAAS,MAAM,EAAE,SAAS,GAAG;AAC5D,SAAO,aAAa,MAAM,GAAG,MAAM;UAC5B,OAAO;AACd,QAAM,IAAI,MAAM,uBAAuB,EAAE,OAAO,OAAO,CAAC"}
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,12 +1,11 @@
1
- import { t as __exportAll } from "./chunk-DWirmd9C.mjs";
2
- import { f as CONTEXT_RECOVERY, n as AES_KEY_BIT_LENGTH, u as CONTEXT_ENC_KEYSTORE } from "./constants-kTeX-2T0.mjs";
3
- import { a as importPrivateKey, n as exportPrivateKey, o as importPublicKey } from "./asymmetric-crypto-CyXsV4XT.mjs";
4
- import { d as base64ToUint8Array, l as publicKeyToBase64, o as genMnemonic, p as uint8ArrayToBase64, s as mnemonicToBytes, u as UTF8ToUint8 } from "./utils-DS04iUcX.mjs";
5
- import { r as getBytesFromData } from "./hash-CXeGAwai.mjs";
6
- import { n as decryptSymmetrically, r as encryptSymmetrically } from "./symmetric-crypto-CrdS1Che.mjs";
7
- import { s as deriveSymmetricCryptoKeyFromContext } from "./derive-key-Be7hS-cN.mjs";
8
- import { n as generateEmailKeys } from "./email-crypto-DJUEjTxA.mjs";
9
- import { t as KeystoreType } from "./types-BiEoleqw.mjs";
1
+ import { AES_KEY_BIT_LENGTH, CONTEXT_ENC_KEYSTORE, CONTEXT_RECOVERY } from "./constants.mjs";
2
+ import { a as importPublicKey, i as importPrivateKey, t as exportPrivateKey } from "./keys-BfcaiAOv.mjs";
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
+ 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";
8
+ import { KeystoreType } from "./types.mjs";
10
9
 
11
10
  //#region src/keystore-crypto/core.ts
12
11
  /**
@@ -147,13 +146,5 @@ async function openRecoveryKeystore(recoveryCodes, encryptedKeystore) {
147
146
  }
148
147
 
149
148
  //#endregion
150
- //#region src/keystore-crypto/index.ts
151
- var keystore_crypto_exports = /* @__PURE__ */ __exportAll({
152
- createEncryptionAndRecoveryKeystores: () => createEncryptionAndRecoveryKeystores,
153
- openEncryptionKeystore: () => openEncryptionKeystore,
154
- openRecoveryKeystore: () => openRecoveryKeystore
155
- });
156
-
157
- //#endregion
158
- export { openRecoveryKeystore as i, createEncryptionAndRecoveryKeystores as n, openEncryptionKeystore as r, keystore_crypto_exports as t };
159
- //# sourceMappingURL=keystore-crypto-Bjgriq9h.mjs.map
149
+ export { openEncryptionKeystore as n, openRecoveryKeystore as r, createEncryptionAndRecoveryKeystores as t };
150
+ //# sourceMappingURL=emailEncryptionKey-27mIHh18.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emailEncryptionKey-27mIHh18.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 { deriveSymmetricCryptoKeyFromContext } 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: CryptoKey,\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: CryptoKey,\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<CryptoKey> {\n const recoverCodesArray = mnemonicToBytes(recoveryCodes);\n const recoveryCodesBuffer = getBytesFromData(AES_KEY_BIT_LENGTH / 8, recoverCodesArray);\n return deriveSymmetricCryptoKeyFromContext(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<CryptoKey> {\n return deriveSymmetricCryptoKeyFromContext(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,eAA2C;CACjF,MAAM,oBAAoB,gBAAgB,cAAc;AAExD,QAAO,oCAAoC,kBADf,iBAAiB,qBAAqB,GAAG,kBAAkB,CACN;;;;;;;;AASnF,eAAsB,4BAA4B,SAAyC;AACzF,QAAO,oCAAoC,sBAAsB,QAAQ;;;;;;;;;;;;AC9F3E,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"}
@@ -1,12 +1,11 @@
1
- const require_chunk = require('./chunk-Dt-PWiN7.js');
2
- const require_constants = require('./constants-Ccp21E03.js');
3
- const require_asymmetric_crypto = require('./asymmetric-crypto-BORmLhnx.js');
4
- const require_utils = require('./utils-CNs3cyDj.js');
5
- const require_hash = require('./hash-BoqwNkcd.js');
6
- const require_symmetric_crypto = require('./symmetric-crypto-D65zB396.js');
7
- const require_derive_key = require('./derive-key-CBf2WxJd.js');
8
- const require_email_crypto = require('./email-crypto-BrT98taw.js');
9
- const require_types = require('./types-52g887Zi.js');
1
+ const require_constants = require('./constants.js');
2
+ const require_keys = require('./keys-CinT7kEY.js');
3
+ const require_genID = require('./genID-YJSl3YhL.js');
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');
8
+ const require_types = require('./types.js');
10
9
 
11
10
  //#region src/keystore-crypto/core.ts
12
11
  /**
@@ -20,18 +19,18 @@ const require_types = require('./types-52g887Zi.js');
20
19
  */
21
20
  async function encryptKeystoreContent(secretKey, keys, userEmail, type) {
22
21
  try {
23
- const aux = require_utils.UTF8ToUint8(userEmail + type);
24
- const publicKeys = await require_utils.publicKeyToBase64(keys.publicKeys);
25
- const kyberPrivateKeyEnc = await require_symmetric_crypto.encryptSymmetrically(secretKey, keys.privateKeys.kyberPrivateKey, aux);
26
- const eccPrivateKeyEnc = await require_symmetric_crypto.encryptSymmetrically(secretKey, await require_asymmetric_crypto.exportPrivateKey(keys.privateKeys.eccPrivateKey), aux);
22
+ const aux = require_genID.UTF8ToUint8(userEmail + type);
23
+ const publicKeys = await require_genID.publicKeyToBase64(keys.publicKeys);
24
+ const kyberPrivateKeyEnc = await require_aes.encryptSymmetrically(secretKey, keys.privateKeys.kyberPrivateKey, aux);
25
+ const eccPrivateKeyEnc = await require_aes.encryptSymmetrically(secretKey, await require_keys.exportPrivateKey(keys.privateKeys.eccPrivateKey), aux);
27
26
  return {
28
27
  userEmail,
29
28
  type,
30
29
  encryptedKeys: {
31
30
  publicKeys,
32
31
  privateKeys: {
33
- kyberPrivateKeyBase64: require_utils.uint8ArrayToBase64(kyberPrivateKeyEnc),
34
- eccPrivateKeyBase64: require_utils.uint8ArrayToBase64(eccPrivateKeyEnc)
32
+ kyberPrivateKeyBase64: require_genID.uint8ArrayToBase64(kyberPrivateKeyEnc),
33
+ eccPrivateKeyBase64: require_genID.uint8ArrayToBase64(eccPrivateKeyEnc)
35
34
  }
36
35
  }
37
36
  };
@@ -50,11 +49,11 @@ async function encryptKeystoreContent(secretKey, keys, userEmail, type) {
50
49
  */
51
50
  async function decryptKeystoreContent(secretKey, encryptedKeystore) {
52
51
  try {
53
- const aux = require_utils.UTF8ToUint8(encryptedKeystore.userEmail + encryptedKeystore.type);
54
- const kyberPublicKey = require_utils.base64ToUint8Array(encryptedKeystore.encryptedKeys.publicKeys.kyberPublicKeyBase64);
55
- const eccPublicKey = await require_asymmetric_crypto.importPublicKey(require_utils.base64ToUint8Array(encryptedKeystore.encryptedKeys.publicKeys.eccPublicKeyBase64));
56
- const kyberPrivateKey = await require_symmetric_crypto.decryptSymmetrically(secretKey, require_utils.base64ToUint8Array(encryptedKeystore.encryptedKeys.privateKeys.kyberPrivateKeyBase64), aux);
57
- const eccPrivateKey = await require_asymmetric_crypto.importPrivateKey(await require_symmetric_crypto.decryptSymmetrically(secretKey, require_utils.base64ToUint8Array(encryptedKeystore.encryptedKeys.privateKeys.eccPrivateKeyBase64), aux));
52
+ const aux = require_genID.UTF8ToUint8(encryptedKeystore.userEmail + encryptedKeystore.type);
53
+ const kyberPublicKey = require_genID.base64ToUint8Array(encryptedKeystore.encryptedKeys.publicKeys.kyberPublicKeyBase64);
54
+ const eccPublicKey = await require_keys.importPublicKey(require_genID.base64ToUint8Array(encryptedKeystore.encryptedKeys.publicKeys.eccPublicKeyBase64));
55
+ const kyberPrivateKey = await require_aes.decryptSymmetrically(secretKey, require_genID.base64ToUint8Array(encryptedKeystore.encryptedKeys.privateKeys.kyberPrivateKeyBase64), aux);
56
+ const eccPrivateKey = await require_keys.importPrivateKey(await require_aes.decryptSymmetrically(secretKey, require_genID.base64ToUint8Array(encryptedKeystore.encryptedKeys.privateKeys.eccPrivateKeyBase64), aux));
58
57
  return {
59
58
  publicKeys: {
60
59
  kyberPublicKey,
@@ -76,8 +75,8 @@ async function decryptKeystoreContent(secretKey, encryptedKeystore) {
76
75
  * @returns The derived secret key for protecting the recovery keystore
77
76
  */
78
77
  async function deriveRecoveryKey(recoveryCodes) {
79
- const recoverCodesArray = require_utils.mnemonicToBytes(recoveryCodes);
80
- return require_derive_key.deriveSymmetricCryptoKeyFromContext(require_constants.CONTEXT_RECOVERY, require_hash.getBytesFromData(require_constants.AES_KEY_BIT_LENGTH / 8, recoverCodesArray));
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));
81
80
  }
82
81
  /**
83
82
  * Derives a secret key for protecting the encryption keystore
@@ -86,7 +85,7 @@ async function deriveRecoveryKey(recoveryCodes) {
86
85
  * @returns The derived secret key for protecting the encryption keystore
87
86
  */
88
87
  async function deriveEncryptionKeystoreKey(baseKey) {
89
- return require_derive_key.deriveSymmetricCryptoKeyFromContext(require_constants.CONTEXT_ENC_KEYSTORE, baseKey);
88
+ return require_deriveKeysFromPassword.deriveSymmetricCryptoKeyFromContext(require_constants.CONTEXT_ENC_KEYSTORE, baseKey);
90
89
  }
91
90
 
92
91
  //#endregion
@@ -100,9 +99,9 @@ async function deriveEncryptionKeystoreKey(baseKey) {
100
99
  */
101
100
  async function createEncryptionAndRecoveryKeystores(userEmail, baseKey) {
102
101
  try {
103
- const keys = await require_email_crypto.generateEmailKeys();
102
+ const keys = await require_emailKeys.generateEmailKeys();
104
103
  const encryptionKeystore = await encryptKeystoreContent(await deriveEncryptionKeystoreKey(baseKey), keys, userEmail, require_types.KeystoreType.ENCRYPTION);
105
- const recoveryCodes = require_utils.genMnemonic();
104
+ const recoveryCodes = require_genID.genMnemonic();
106
105
  return {
107
106
  encryptionKeystore,
108
107
  recoveryKeystore: await encryptKeystoreContent(await deriveRecoveryKey(recoveryCodes), keys, userEmail, require_types.KeystoreType.RECOVERY),
@@ -146,14 +145,6 @@ async function openRecoveryKeystore(recoveryCodes, encryptedKeystore) {
146
145
  }
147
146
  }
148
147
 
149
- //#endregion
150
- //#region src/keystore-crypto/index.ts
151
- var keystore_crypto_exports = /* @__PURE__ */ require_chunk.__exportAll({
152
- createEncryptionAndRecoveryKeystores: () => createEncryptionAndRecoveryKeystores,
153
- openEncryptionKeystore: () => openEncryptionKeystore,
154
- openRecoveryKeystore: () => openRecoveryKeystore
155
- });
156
-
157
148
  //#endregion
158
149
  Object.defineProperty(exports, 'createEncryptionAndRecoveryKeystores', {
159
150
  enumerable: true,
@@ -161,12 +152,6 @@ Object.defineProperty(exports, 'createEncryptionAndRecoveryKeystores', {
161
152
  return createEncryptionAndRecoveryKeystores;
162
153
  }
163
154
  });
164
- Object.defineProperty(exports, 'keystore_crypto_exports', {
165
- enumerable: true,
166
- get: function () {
167
- return keystore_crypto_exports;
168
- }
169
- });
170
155
  Object.defineProperty(exports, 'openEncryptionKeystore', {
171
156
  enumerable: true,
172
157
  get: function () {
@@ -179,4 +164,4 @@ Object.defineProperty(exports, 'openRecoveryKeystore', {
179
164
  return openRecoveryKeystore;
180
165
  }
181
166
  });
182
- //# sourceMappingURL=keystore-crypto-B4yCVo9l.js.map
167
+ //# sourceMappingURL=emailEncryptionKey-DbaDAdoW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emailEncryptionKey-DbaDAdoW.js","names":["UTF8ToUint8","publicKeyToBase64","encryptSymmetrically","exportPrivateKey","uint8ArrayToBase64","base64ToUint8Array","importPublicKey","decryptSymmetrically","importPrivateKey","mnemonicToBytes","deriveSymmetricCryptoKeyFromContext","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 { deriveSymmetricCryptoKeyFromContext } 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: CryptoKey,\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: CryptoKey,\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<CryptoKey> {\n const recoverCodesArray = mnemonicToBytes(recoveryCodes);\n const recoveryCodesBuffer = getBytesFromData(AES_KEY_BIT_LENGTH / 8, recoverCodesArray);\n return deriveSymmetricCryptoKeyFromContext(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<CryptoKey> {\n return deriveSymmetricCryptoKeyFromContext(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,eAA2C;CACjF,MAAM,oBAAoBI,8BAAgB,cAAc;AAExD,QAAOC,mEAAoCC,oCADfC,6BAAiBC,uCAAqB,GAAG,kBAAkB,CACN;;;;;;;;AASnF,eAAsB,4BAA4B,SAAyC;AACzF,QAAOH,mEAAoCI,wCAAsB,QAAQ;;;;;;;;;;;;AC9F3E,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"}