internxt-crypto 0.0.10-alpha → 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 (158) hide show
  1. package/README.md +3 -4
  2. package/dist/aes-DSDxP8uF.mjs +184 -0
  3. package/dist/aes-DSDxP8uF.mjs.map +1 -0
  4. package/dist/aes-bOrKZuUC.js +226 -0
  5. package/dist/aes-bOrKZuUC.js.map +1 -0
  6. package/dist/asymmetric-crypto.d.mts +5 -2
  7. package/dist/asymmetric-crypto.d.mts.map +1 -0
  8. package/dist/asymmetric-crypto.d.ts +5 -2
  9. package/dist/asymmetric-crypto.d.ts.map +1 -0
  10. package/dist/asymmetric-crypto.js +9 -92
  11. package/dist/asymmetric-crypto.mjs +2 -84
  12. package/dist/chunk-DQk6qfdC.mjs +18 -0
  13. package/dist/chunk-EbLFQX5m.js +60 -0
  14. package/dist/constants.d.mts +5 -11
  15. package/dist/constants.d.mts.map +1 -0
  16. package/dist/constants.d.ts +5 -11
  17. package/dist/constants.d.ts.map +1 -0
  18. package/dist/constants.js +33 -49
  19. package/dist/constants.js.map +1 -1
  20. package/dist/constants.mjs +32 -40
  21. package/dist/constants.mjs.map +1 -1
  22. package/dist/derive-key.d.mts +11 -8
  23. package/dist/derive-key.d.mts.map +1 -0
  24. package/dist/derive-key.d.ts +11 -8
  25. package/dist/derive-key.d.ts.map +1 -0
  26. package/dist/derive-key.js +13 -795
  27. package/dist/derive-key.mjs +2 -783
  28. package/dist/deriveKeysFromPassword-DJRWZ8Rw.mjs +735 -0
  29. package/dist/deriveKeysFromPassword-DJRWZ8Rw.mjs.map +1 -0
  30. package/dist/deriveKeysFromPassword-Ko7NxkHM.js +2492 -0
  31. package/dist/deriveKeysFromPassword-Ko7NxkHM.js.map +1 -0
  32. package/dist/email-crypto.d.mts +55 -78
  33. package/dist/email-crypto.d.mts.map +1 -0
  34. package/dist/email-crypto.d.ts +55 -78
  35. package/dist/email-crypto.d.ts.map +1 -0
  36. package/dist/email-crypto.js +13 -1409
  37. package/dist/email-crypto.mjs +2 -1380
  38. package/dist/email-search.d.mts +36 -32
  39. package/dist/email-search.d.mts.map +1 -0
  40. package/dist/email-search.d.ts +36 -32
  41. package/dist/email-search.d.ts.map +1 -0
  42. package/dist/email-search.js +534 -540
  43. package/dist/email-search.js.map +1 -1
  44. package/dist/email-search.mjs +532 -538
  45. package/dist/email-search.mjs.map +1 -1
  46. package/dist/emailEncryptionKey-27mIHh18.mjs +150 -0
  47. package/dist/emailEncryptionKey-27mIHh18.mjs.map +1 -0
  48. package/dist/emailEncryptionKey-DbaDAdoW.js +167 -0
  49. package/dist/emailEncryptionKey-DbaDAdoW.js.map +1 -0
  50. package/dist/emailKeys-BJGdkLrg.js +593 -0
  51. package/dist/emailKeys-BJGdkLrg.js.map +1 -0
  52. package/dist/emailKeys-Fp9WR3wl.mjs +509 -0
  53. package/dist/emailKeys-Fp9WR3wl.mjs.map +1 -0
  54. package/dist/genID-3Er5IowC.mjs +153 -0
  55. package/dist/genID-3Er5IowC.mjs.map +1 -0
  56. package/dist/genID-YJSl3YhL.js +238 -0
  57. package/dist/genID-YJSl3YhL.js.map +1 -0
  58. package/dist/hash.d.mts +18 -15
  59. package/dist/hash.d.mts.map +1 -0
  60. package/dist/hash.d.ts +18 -15
  61. package/dist/hash.d.ts.map +1 -0
  62. package/dist/hash.js +12 -95
  63. package/dist/hash.mjs +2 -84
  64. package/dist/index.d.mts +15 -18
  65. package/dist/index.d.mts.map +1 -0
  66. package/dist/index.d.ts +15 -18
  67. package/dist/index.d.ts.map +1 -0
  68. package/dist/index.js +125 -2698
  69. package/dist/index.mjs +13 -2538
  70. package/dist/keys-BfcaiAOv.mjs +90 -0
  71. package/dist/keys-BfcaiAOv.mjs.map +1 -0
  72. package/dist/keys-CinT7kEY.js +125 -0
  73. package/dist/keys-CinT7kEY.js.map +1 -0
  74. package/dist/keystore-crypto.d.mts +17 -46
  75. package/dist/keystore-crypto.d.mts.map +1 -0
  76. package/dist/keystore-crypto.d.ts +17 -46
  77. package/dist/keystore-crypto.d.ts.map +1 -0
  78. package/dist/keystore-crypto.js +5 -529
  79. package/dist/keystore-crypto.mjs +2 -500
  80. package/dist/kyber1024-PpwE1rki.mjs +144 -0
  81. package/dist/kyber1024-PpwE1rki.mjs.map +1 -0
  82. package/dist/kyber1024-jeKS8CXf.js +173 -0
  83. package/dist/kyber1024-jeKS8CXf.js.map +1 -0
  84. package/dist/{kyber768-B87rMQ7u.d.mts → kyber768-DGBB_RS7.d.ts} +8 -6
  85. package/dist/kyber768-DGBB_RS7.d.ts.map +1 -0
  86. package/dist/{kyber768-B87rMQ7u.d.ts → kyber768-DzIcGg1i.d.mts} +8 -6
  87. package/dist/kyber768-DzIcGg1i.d.mts.map +1 -0
  88. package/dist/mac-BMb1F0dN.js +170 -0
  89. package/dist/mac-BMb1F0dN.js.map +1 -0
  90. package/dist/mac-ZpRlx8Fs.mjs +116 -0
  91. package/dist/mac-ZpRlx8Fs.mjs.map +1 -0
  92. package/dist/post-quantum-crypto.d.mts +23 -27
  93. package/dist/post-quantum-crypto.d.mts.map +1 -0
  94. package/dist/post-quantum-crypto.d.ts +23 -27
  95. package/dist/post-quantum-crypto.d.ts.map +1 -0
  96. package/dist/post-quantum-crypto.js +14 -92
  97. package/dist/post-quantum-crypto.mjs +2 -89
  98. package/dist/storage-service.d.mts +28 -34
  99. package/dist/storage-service.d.mts.map +1 -0
  100. package/dist/storage-service.d.ts +28 -34
  101. package/dist/storage-service.d.ts.map +1 -0
  102. package/dist/storage-service.js +51 -53
  103. package/dist/storage-service.js.map +1 -1
  104. package/dist/storage-service.mjs +40 -51
  105. package/dist/storage-service.mjs.map +1 -1
  106. package/dist/symmetric-crypto.d.mts +8 -7
  107. package/dist/symmetric-crypto.d.mts.map +1 -0
  108. package/dist/symmetric-crypto.d.ts +8 -7
  109. package/dist/symmetric-crypto.d.ts.map +1 -0
  110. package/dist/symmetric-crypto.js +10 -142
  111. package/dist/symmetric-crypto.mjs +2 -133
  112. package/dist/types.d.mts +71 -69
  113. package/dist/types.d.mts.map +1 -0
  114. package/dist/types.d.ts +71 -69
  115. package/dist/types.d.ts.map +1 -0
  116. package/dist/types.js +8 -10
  117. package/dist/types.js.map +1 -1
  118. package/dist/types.mjs +7 -9
  119. package/dist/types.mjs.map +1 -1
  120. package/dist/utils.d.mts +34 -78
  121. package/dist/utils.d.mts.map +1 -0
  122. package/dist/utils.d.ts +34 -78
  123. package/dist/utils.d.ts.map +1 -0
  124. package/dist/utils.js +17 -313
  125. package/dist/utils.mjs +2 -272
  126. package/package.json +21 -87
  127. package/dist/asymmetric-crypto.js.map +0 -1
  128. package/dist/asymmetric-crypto.mjs.map +0 -1
  129. package/dist/derive-key.js.map +0 -1
  130. package/dist/derive-key.mjs.map +0 -1
  131. package/dist/email-crypto.js.map +0 -1
  132. package/dist/email-crypto.mjs.map +0 -1
  133. package/dist/email-service.d.mts +0 -38
  134. package/dist/email-service.d.ts +0 -38
  135. package/dist/email-service.js +0 -154
  136. package/dist/email-service.js.map +0 -1
  137. package/dist/email-service.mjs +0 -147
  138. package/dist/email-service.mjs.map +0 -1
  139. package/dist/hash.js.map +0 -1
  140. package/dist/hash.mjs.map +0 -1
  141. package/dist/index.js.map +0 -1
  142. package/dist/index.mjs.map +0 -1
  143. package/dist/keystore-crypto.js.map +0 -1
  144. package/dist/keystore-crypto.mjs.map +0 -1
  145. package/dist/keystore-service.d.mts +0 -82
  146. package/dist/keystore-service.d.ts +0 -82
  147. package/dist/keystore-service.js +0 -349
  148. package/dist/keystore-service.js.map +0 -1
  149. package/dist/keystore-service.mjs +0 -342
  150. package/dist/keystore-service.mjs.map +0 -1
  151. package/dist/post-quantum-crypto.js.map +0 -1
  152. package/dist/post-quantum-crypto.mjs.map +0 -1
  153. package/dist/symmetric-crypto.js.map +0 -1
  154. package/dist/symmetric-crypto.mjs.map +0 -1
  155. package/dist/utils-BDaK_d6T.d.ts +0 -114
  156. package/dist/utils-v34IRTIx.d.mts +0 -114
  157. package/dist/utils.js.map +0 -1
  158. package/dist/utils.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/constants.ts","../src/hash/blake3.ts","../src/symmetric-crypto/keys.ts","../src/symmetric-crypto/core.ts","../src/symmetric-crypto/aes.ts","../src/utils/converters.ts","../src/email-crypto/converters.ts","../src/derive-key/deriveKeysFromKey.ts","../src/email-crypto/core.ts","../src/email-crypto/utils.ts","../src/email-search/indexedDB.ts","../src/email-search/mailCache.ts","../src/email-search/search.ts"],"names":["blake3","utf8ToBytes","randomBytes","openDB","deleteDB","Index"],"mappings":"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","file":"email-search.js","sourcesContent":["export const AES_ALGORITHM = 'AES-GCM';\nexport const AES_KEY_BIT_LENGTH = 256;\nexport const AUX_LEN = 128;\nexport const IV_LEN_BYTES = 16;\n\nexport const KEY_WRAPPING_ALGORITHM = 'AES-KW';\nexport const KEY_FORMAT = 'raw';\nexport const CONTEXT_WRAPPING = 'CRYPTO library 2025-08-22 18:10:00 key derived from ecc and kyber secrets';\n\nexport const ECC_ALGORITHM = 'X25519';\n\nexport const CONTEXT_LOGIN = 'CRYPTO library 2025-07-26 16:18:03 key for opening identity keystore';\nexport const CONTEXT_ENC_KEYSTORE = 'CRYPTO library 2025-07-30 16:18:03 key for opening encryption keys keystore';\nexport const CONTEXT_RECOVERY = 'CRYPTO library 2025-07-30 16:20:00 key for account recovery';\nexport const CONTEXT_INDEX = 'CRYPTO library 2025-07-30 17:20:00 key for protecting current search indices';\nexport const CONTEXT_DERIVE = 'CRYPTO library 2025-08-27 17:08:00 derive one key from two keys';\n\nexport const PREFIX_MEDIA_KEY_COMMITMENT = 'CRYPTO library 2025-08-26 18:29:00 prefix for commitment to media keys';\nexport const PREFIX_PUBLIC_KEY_COMMITMENT = 'CRYPTO library 2025-08-26 18:30:00 prefix for commitment to public keys';\nexport const PREFIX_IDENTITY_KEY_COMMITMENT =\n 'CRYPTO library 2025-08-26 18:45:00 prefix for commitment to identity keys';\n\n// Second recommended parameter set from RFC 9106\nexport const ARGON2ID_PARALLELISM = 3;\nexport const ARGON2ID_ITERATIONS = 4;\nexport const ARGON2ID_MEMORY_SIZE = 65536;\nexport const ARGON2ID_SALT_BYTE_LENGTH = 16;\nexport const ARGON2ID_OUTPUT_BYTE_LENGTH = 32;\n\nexport const IDENTITY_KEYSTORE_TAG = 'Identity keystore';\nexport const ENCRYPTION_KEYSTORE_TAG = 'Encryption keystore';\nexport const RECOVERY_KEYSTORE_TAG = 'Key recovery keystroe';\nexport const INDEX_KEYSTORE_TAG = 'Current encrypted indices';\n\nexport const KYBER512_PUBLIC_KEY_LENGTH = 800;\nexport const KYBER512_SECRET_KEY_LENGTH = 1632;\n\nexport const KYBER768_PUBLIC_KEY_LENGTH = 1184;\nexport const KYBER768_SECRET_KEY_LENGTH = 2400;\n\nexport const KYBER1024_PUBLIC_KEY_LENGTH = 1568;\nexport const KYBER1024_SECRET_KEY_LENGTH = 3168;\n\nexport const KYBER_SEED_LENGTH = 64;\n\nexport const HASH_BIT_LEN = 256;\n\nexport const MAX_CACHE_SIZE = 600000000; // 600 MB\nexport const MAX_EMAIL_PER_BATCH = 100;\nexport const DB_LABEL = 'email';\nexport const DB_VERSION = 1;\n","import { blake3 } from '@noble/hashes/blake3.js';\nimport { utf8ToBytes, bytesToHex } from '@noble/hashes/utils.js';\n\n/**\n * Hashes the given array of data\n *\n * @param data - The data to hash\n * @returns The resulting hash array\n */\nexport function hashData(data: Uint8Array[]): Uint8Array {\n try {\n const hasher = blake3.create();\n for (const d of data) {\n hasher.update(d);\n }\n return hasher.digest();\n } catch (error) {\n throw new Error('Failed to compute hash', { cause: error });\n }\n}\n\nexport function keyedHashHex(hashKey: Uint8Array, data: Uint8Array[]): string {\n try {\n const hash = keyedHash(hashKey, data);\n return bytesToHex(hash);\n } catch (error) {\n throw new Error('Failed to compute hash hex', { cause: error });\n }\n}\n\nexport function keyedHash(hashKey: Uint8Array, data: Uint8Array[]): Uint8Array {\n try {\n const hasher = blake3.create({ key: hashKey });\n for (const d of data) {\n hasher.update(d);\n }\n return hasher.digest();\n } catch (error) {\n throw new Error('Failed to compute hash', { cause: error });\n }\n}\n\n/**\n * Hashes the given array of data\n *\n * @param data - The data to hash\n * @returns The resulting hash hex string\n */\nexport function hashDataHex(data: Uint8Array[]): string {\n try {\n const hash = hashData(data);\n return bytesToHex(hash);\n } catch (error) {\n throw new Error('Failed to compute hash', { cause: error });\n }\n}\n\n/**\n * Hashes the given array of data using blake3 algorithm\n *\n * @param bytes - The desired output byte-length\n * @param data - The data to hash\n * @returns The resulting hash value\n */\nexport function getBytesFromData(bytes: number, data: Uint8Array[]): Uint8Array {\n try {\n const hasher = blake3.create({ dkLen: bytes });\n for (const chunk of data) {\n hasher.update(chunk);\n }\n return hasher.digest();\n } catch (error) {\n throw new Error('Failed to get bytes from data', { cause: error });\n }\n}\n\n/**\n * Hashes the given array of data using blake3 algorithm\n *\n * @param bytes - The desired output byte-length\n * @param data - The data to hash\n * @returns The resulting hash value\n */\nexport function getBytesFromDataHex(bytes: number, data: Uint8Array[]): string {\n try {\n const hash = getBytesFromData(bytes, data);\n return bytesToHex(hash);\n } catch (error) {\n throw new Error('Failed to get bytes from data', { cause: error });\n }\n}\n\n/**\n * Hashes the given string using blake3 algorithm\n *\n * @param bytes - The desired output byte-length\n * @param value - The string to hash\n * @returns The resulting hash value\n */\nexport function getBytesFromString(bytes: number, value: string): Uint8Array {\n return blake3(utf8ToBytes(value), { dkLen: bytes });\n}\n\n/**\n * Hashes the given string using blake3 algorithm\n *\n * @param bytes - The desired output byte-length\n * @param value - The string to hash\n * @returns The resulting hash value\n */\nexport function getBytesFromStrinHex(bytes: number, value: string): string {\n return bytesToHex(getBytesFromString(bytes, value));\n}\n","import { AES_ALGORITHM, AES_KEY_BIT_LENGTH, KEY_FORMAT } from '../constants';\nimport { getBytesFromString } from '../hash';\n\n/**\n * Converts Uint8Array into CryptoKey\n *\n * @param keyData - The Uint8Array representation of the symmetric key\n * @returns The resulting symmetric CryptoKey.\n */\nexport async function importSymmetricCryptoKey(keyData: Uint8Array | ArrayBuffer): Promise<CryptoKey> {\n return crypto.subtle.importKey(\n KEY_FORMAT,\n new Uint8Array(keyData),\n {\n name: AES_ALGORITHM,\n length: AES_KEY_BIT_LENGTH,\n },\n true,\n ['encrypt', 'decrypt'],\n );\n}\n\n/**\n * Converts CryptoKey into Uint8Array\n *\n * @param key - The symmetric CryptoKey\n * @returns The resulting Uint8Array.\n */\nexport async function exportSymmetricCryptoKey(key: CryptoKey): Promise<Uint8Array> {\n try {\n const rawKey = await crypto.subtle.exportKey(KEY_FORMAT, key);\n return new Uint8Array(rawKey);\n } catch (error) {\n throw new Error('Failed to export symmetric CryptoKey', { cause: error });\n }\n}\n\n/**\n * Generates symmetric CryptoKey\n *\n * @returns The generated CryptoKey.\n */\nexport async function genSymmetricCryptoKey(): Promise<CryptoKey> {\n return crypto.subtle.generateKey(\n {\n name: AES_ALGORITHM,\n length: AES_KEY_BIT_LENGTH,\n },\n true,\n ['encrypt', 'decrypt'],\n );\n}\n\n/**\n * Generates symmetric key as Uint8Array\n *\n * @returns The generated Uint8Array.\n */\nexport function genSymmetricKey(): Uint8Array {\n try {\n const key = new Uint8Array(AES_KEY_BIT_LENGTH / 8);\n crypto.getRandomValues(key);\n return key;\n } catch (error) {\n throw new Error('Failed to generate symmetric key', { cause: error });\n }\n}\n\n/**\n * Derives CryptoKey from the given key material\n *\n * @returns The derived CryptoKey.\n */\nexport async function deriveSymmetricCryptoKey(keyMaterial: string): Promise<CryptoKey> {\n try {\n const hashBuffer = await getBytesFromString(AES_KEY_BIT_LENGTH / 8, keyMaterial);\n return importSymmetricCryptoKey(hashBuffer);\n } catch (error) {\n throw new Error('Failed to derive CryptoKey from the given key material', { cause: error });\n }\n}\n","import { randomBytes } from '@noble/post-quantum/utils.js';\nimport { getBytesFromString } from '../hash';\nimport { AUX_LEN, AES_ALGORITHM, IV_LEN_BYTES } from '../constants';\n\n/**\n * Creates an initialization vector (IV) using RGB-based construction (8.2.2 NIST Special Publication 800-38D)\n * Constructs a 128-bits IV from 2 fileds: the random field (at least 96 bits) and the free field (32 bits).\n * If free filed is empty, then the entier 128-bit IV is sampled randomly.\n *\n * @param freeFiled - The string with an unrestricted content. Can be a device identifier, etc.\n * @returns The resulting 128-bits initialization vector.\n */\nexport async function createNISTbasedIV(freeField?: string): Promise<Uint8Array> {\n try {\n if (!freeField) {\n return randomBytes(IV_LEN_BYTES);\n }\n\n const iv = new Uint8Array(16);\n\n const randFiled = randomBytes(12);\n iv.set(randFiled, 0);\n\n const freeFiledFixedLength = await getBytesFromString(4, freeField);\n iv.set(freeFiledFixedLength, 12);\n\n return iv;\n } catch (error) {\n throw new Error('Failed to create IV', { cause: error });\n }\n}\n\n/**\n * Hashes aux string to make it fixed-length\n *\n * @param aux - The auxilay string of arbitrary length\n * @returns The resulting fixed-length auxilary string.\n */\nexport async function makeAuxFixedLength(aux: string): Promise<Uint8Array> {\n return getBytesFromString(AUX_LEN / 8, aux);\n}\n\n/**\n * Symmetrically encrypts message\n *\n * @param message - The message to encrypt\n * @param encryptionKey - The encryption key\n * @param iv - The initialization vector\n * @param additionalData - The auxilary data\n * @returns The resulting ciphertext\n */\nexport async function encryptMessage(\n message: Uint8Array,\n encryptionKey: CryptoKey,\n iv: Uint8Array,\n additionalData: Uint8Array,\n): Promise<Uint8Array> {\n try {\n const encrypted = await crypto.subtle.encrypt(\n { name: AES_ALGORITHM, iv: iv as BufferSource, additionalData: additionalData as BufferSource },\n encryptionKey,\n message as BufferSource,\n );\n return new Uint8Array(encrypted);\n } catch (error) {\n throw new Error('Failed to encrypt symmetrically', { cause: error });\n }\n}\n\n/**\n * Symmetrically decrypts message\n *\n * @param ciphertext - The encrypted message\n * @param ciphertext - The initialization vector\n * @param encryptionKey - The encryption key\n * @param additionalData - The auxilary data\n * @returns The resulting decrypted message\n */\nexport async function decryptMessage(\n ciphertext: Uint8Array,\n iv: Uint8Array,\n encryptionKey: CryptoKey,\n additionalData: Uint8Array,\n): Promise<Uint8Array> {\n try {\n const decrypted = await crypto.subtle.decrypt(\n { name: AES_ALGORITHM, iv: iv as BufferSource, additionalData: additionalData as BufferSource },\n encryptionKey,\n ciphertext as BufferSource,\n );\n return new Uint8Array(decrypted);\n } catch (error) {\n throw new Error('Failed to decrypt symmetrically', { cause: error });\n }\n}\n","import { SymmetricCiphertext } from '../types';\nimport { createNISTbasedIV, makeAuxFixedLength, encryptMessage, decryptMessage } from './core';\n\n/**\n * Symmetrically encrypts the message\n *\n * @param encryptionKey - The symmetric CryptoKey used for message encryption\n * @param message - The message to encrypt\n * @param freeField - The context of the message (required for IV generation)\n * @param aux - The auxilary string\n * @returns The resulting ciphertext.\n */\nexport async function encryptSymmetrically(\n encryptionKey: CryptoKey,\n message: Uint8Array,\n aux: string,\n freeField?: string,\n): Promise<SymmetricCiphertext> {\n try {\n const iv = await createNISTbasedIV(freeField);\n const additionalData = await makeAuxFixedLength(aux);\n const ciphertext = await encryptMessage(message, encryptionKey, iv, additionalData);\n return { ciphertext, iv };\n } catch (error) {\n throw new Error('Failed to encrypt symmetrically', { cause: error });\n }\n}\n\n/**\n * Decryps symmetrically encrypted message\n *\n * @param encryptionKey - The symmetric CryptoKey used for message encryption\n * @param encryptedMessage - The ciphertext\n * @param aux - The auxilary string\n * @returns The resulting ciphertext.\n */\nexport async function decryptSymmetrically(\n encryptionKey: CryptoKey,\n encryptedMessage: SymmetricCiphertext,\n aux: string,\n): Promise<Uint8Array> {\n try {\n const additionalData = await makeAuxFixedLength(aux);\n const result = await decryptMessage(\n encryptedMessage.ciphertext,\n encryptedMessage.iv,\n encryptionKey,\n additionalData,\n );\n return result;\n } catch (error) {\n throw new Error('Failed to decrypt symmetrically', { cause: error });\n }\n}\n","import { bytesToHex, hexToBytes } from '@noble/hashes/utils.js';\n\n/**\n * Converts a Uint8Array into a hexadecimal string.\n *\n * @param array - The Uint8Array to convert.\n * @returns The hexadecimal string representation of the array.\n */\nexport function uint8ArrayToHex(array: Uint8Array): string {\n return bytesToHex(array);\n}\n\n/**\n * Converts a UTF-8 string into a Uint8Array.\n *\n * @param str - The UTF-8 string to convert.\n * @returns A Uint8Array created from the UTF-8 string.\n */\nexport function UTF8ToUint8(str: string): Uint8Array {\n return new TextEncoder().encode(str);\n}\n\n/**\n * Converts an Uint8Array into a UTF-8 string.\n *\n * @param array - The Uint8Array to convert.\n * @returns The UTF-8 string representation of the array.\n */\nexport function uint8ToUTF8(array: Uint8Array): string {\n return new TextDecoder().decode(array);\n}\n\n/**\n * Converts a hexadecimal string into a Uint8Array.\n *\n * @param hex - The hexadecimal string to convert.\n * @returns A Uint8Array created from the hex string.\n */\nexport function hexToUint8Array(hex: string): Uint8Array {\n return hexToBytes(hex);\n}\n\n/**\n * Converts a Uint8Array into a base64 string.\n *\n * @param array - The Uint8Array to convert.\n * @returns The base64 string representation of the array.\n */\nexport function uint8ArrayToBase64(buffer: Uint8Array): string {\n const array = Uint16Array.from(buffer);\n const binaryString = new TextDecoder('UTF-16').decode(array);\n return btoa(binaryString);\n}\n\n/**\n * Converts a base64 string into a Uint8Array.\n *\n * @param str - The base64 string to convert.\n * @returns A Uint8Array created from the base64 string.\n */\nexport function base64ToUint8Array(str: string): Uint8Array {\n const binaryString = atob(str);\n const len = binaryString.length;\n const array = new Uint8Array(len);\n for (let i = 0; i < len; i++) {\n array[i] = binaryString.charCodeAt(i);\n }\n return new Uint8Array(array.buffer);\n}\n","import { uint8ArrayToBase64, base64ToUint8Array, UTF8ToUint8, uint8ToUTF8, ciphertextToBase64 } from '../utils';\nimport {\n EmailBody,\n HybridEncKey,\n PwdProtectedKey,\n User,\n EmailPublicParameters,\n HybridEncryptedEmail,\n PwdProtectedEmail,\n Email,\n} from '../types';\n\n/**\n * Converts a User type into a base64 string.\n *\n * @param user - The given user.\n * @returns The base64 representation of the user.\n */\nexport function userToBase64(user: User): string {\n try {\n const json = JSON.stringify(user);\n return btoa(json);\n } catch (error) {\n throw new Error('Failed to convert User to base64', { cause: error });\n }\n}\n\n/**\n * Converts a base64 string into a User type\n *\n * @param base64 - The base64 representation of the user.\n * @returns The User type.\n */\nexport function base64ToUser(base64: string): User {\n try {\n const json = atob(base64);\n const user: User = JSON.parse(json);\n return user;\n } catch (error) {\n throw new Error('Failed to convert base64 to User', { cause: error });\n }\n}\n\n/**\n * Converts an EmailBody type into a Uint8Array array.\n *\n * @param body - The email body.\n * @returns The Uint8Array array representation of the EmailBody type.\n */\nexport function emailBodyToBinary(body: EmailBody): Uint8Array {\n try {\n const json = JSON.stringify(body);\n return UTF8ToUint8(json);\n } catch (error) {\n throw new Error('Failed to convert EmailBody to Uint8Array', { cause: error });\n }\n}\n\n/**\n * Converts an Uint8Array array into EmailBody type.\n *\n * @param array - The Uint8Array array.\n * @returns The EmailBody type representation of the Uint8Array.\n */\nexport function binaryToEmailBody(array: Uint8Array): EmailBody {\n try {\n const json = uint8ToUTF8(array);\n const email: EmailBody = JSON.parse(json);\n return email;\n } catch (error) {\n throw new Error('Failed to convert Uint8Array to EmailBody', { cause: error });\n }\n}\n\n/**\n * Converts a hybrid key of the type HybridEncKey into base64 string.\n *\n * @param encHybridKey - The HybridEncKey key.\n * @returns The resulting base64 key encoding.\n */\nexport function encHybridKeyToBase64(encHybridKey: HybridEncKey): string {\n try {\n const json = JSON.stringify({\n kyberCiphertext: uint8ArrayToBase64(encHybridKey.kyberCiphertext),\n encryptedKey: uint8ArrayToBase64(encHybridKey.encryptedKey),\n });\n const base64 = btoa(json);\n return base64;\n } catch (error) {\n throw new Error('Failed to convert hybrid key to base64', { cause: error });\n }\n}\n\n/**\n * Converts a base64 string into a hybrid key of the type HybridEncKey.\n *\n * @param base - The base64 encoding of the hybrid key.\n * @returns The resulting HybridEncKey key.\n */\nexport function base64ToEncHybridKey(base64: string): HybridEncKey {\n try {\n const json = atob(base64);\n const obj = JSON.parse(json);\n return {\n encryptedKey: base64ToUint8Array(obj.encryptedKey),\n kyberCiphertext: base64ToUint8Array(obj.kyberCiphertext),\n };\n } catch (error) {\n throw new Error('Failed to convert base64 to hybrid key', { cause: error });\n }\n}\n\n/**\n * Converts a password-protected key of the type PwdProtectedKey into base64 string.\n *\n * @param pwdProtectedKey - The password-protected key of the type PwdProtectedKey.\n * @returns The resulting base64 key encoding.\n */\nexport function pwdProtectedKeyToBase64(pwdProtectedKey: PwdProtectedKey): string {\n try {\n const json = JSON.stringify({\n encryptedKey: uint8ArrayToBase64(pwdProtectedKey.encryptedKey),\n salt: uint8ArrayToBase64(pwdProtectedKey.salt),\n });\n const base64 = btoa(json);\n return base64;\n } catch (error) {\n throw new Error('Failed to convert password-protected key to base64', { cause: error });\n }\n}\n\n/**\n * Converts a base64 string into a password-protected key of the type PwdProtectedKey.\n *\n * @param base64 - The base64 string.\n * @returns The resulting PwdProtectedKey key.\n */\nexport function base64ToPwdProtectedKey(base64: string): PwdProtectedKey {\n try {\n const json = atob(base64);\n const obj = JSON.parse(json);\n return {\n encryptedKey: base64ToUint8Array(obj.encryptedKey),\n salt: base64ToUint8Array(obj.salt),\n };\n } catch (error) {\n throw new Error('Failed to convert base64 to password-protected key', { cause: error });\n }\n}\n\n/**\n * Converts an email public parameters of type EmailPublicParameters into base64 string.\n *\n * @param params - The EmailPublicParameters email paramaters.\n * @returns The resulting base64 string encoding.\n */\nexport function paramsToBase64(params: EmailPublicParameters): string {\n try {\n const json = JSON.stringify({\n ...params,\n sender: userToBase64(params.sender),\n recipient: userToBase64(params.recipient),\n recipients: params.recipients?.map(userToBase64),\n });\n const base64 = btoa(json);\n return base64;\n } catch (error) {\n throw new Error('Failed to convert email public parameters to base64', { cause: error });\n }\n}\n\n/**\n * Converts a base64 string into an email paramaters of the type EmailPublicParameters.\n *\n * @param base64 - The base64 string.\n * @returns The resulting EmailPublicParameters email parameters.\n */\nexport function base64ToParams(base64: string): EmailPublicParameters {\n try {\n const json = atob(base64);\n const obj = JSON.parse(json);\n return {\n ...obj,\n sender: base64ToUser(obj.sender),\n recipient: base64ToUser(obj.recipient),\n recipients: obj.recipients?.map(base64ToUser),\n };\n } catch (error) {\n throw new Error('Failed to convert base64 to email params', { cause: error });\n }\n}\n\n/**\n * Converts an encrypted via hybrid encryption email into base64 string.\n *\n * @param email - The HybridEncryptedEmail encrypted via hybrid encryption email.\n * @returns The resulting base64 string encoding.\n */\nexport function hybridEncyptedEmailToBase64(email: HybridEncryptedEmail): string {\n try {\n const json = JSON.stringify({\n encryptedKey: encHybridKeyToBase64(email.encryptedKey),\n enc: ciphertextToBase64(email.enc),\n recipientEmail: email.recipientEmail,\n });\n const base64 = btoa(json);\n return base64;\n } catch (error) {\n throw new Error('Failed to convert hybrid email to base64', { cause: error });\n }\n}\n\n/**\n * Converts a pwd protected email into base64 string.\n *\n * @param email - The PwdProtectedEmail pwd protected email.\n * @returns The resulting base64 string encoding.\n */\nexport function pwdProtectedEmailToBase64(email: PwdProtectedEmail): string {\n try {\n const json = JSON.stringify({\n encryptedKey: pwdProtectedKeyToBase64(email.encryptedKey),\n enc: ciphertextToBase64(email.enc),\n });\n const base64 = btoa(json);\n return base64;\n } catch (error) {\n throw new Error('Failed to convert pwd protected email to base64', { 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 { blake3 } from '@noble/hashes/blake3.js';\nimport { AES_KEY_BIT_LENGTH, CONTEXT_DERIVE } from '../constants';\nimport { UTF8ToUint8 } from '../utils';\nimport { importSymmetricCryptoKey } from '../symmetric-crypto';\n\n/**\n * Derives a symmetric key from the base key and context string\n *\n * @param context - The context string.\n * The context string should be hardcoded, globally unique, and application-specific.\n * @param baseKey - The base key (NOT PASSWORD!)\n * @returns The derived secret key\n */\nexport function deriveSymmetricKeyFromContext(context: string, baseKey: Uint8Array): Uint8Array {\n return blake3(baseKey, { context: UTF8ToUint8(context) });\n}\n\n/**\n * Derives a symmetric CryptoKey from the base key and context string\n *\n * @param context - The context string.\n * The context string should be hardcoded, globally unique, and application-specific.\n * @param baseKey - The base key (NOT PASSWORD!)\n * @returns The derived secret CryptoKey\n */\nexport async function deriveSymmetricCryptoKeyFromContext(context: string, baseKey: Uint8Array): Promise<CryptoKey> {\n try {\n if (baseKey.length != AES_KEY_BIT_LENGTH / 8) {\n throw new Error(`Base key length must be exactly ${AES_KEY_BIT_LENGTH / 8} bytes`);\n }\n if (!context) {\n throw new Error('Context is empry');\n }\n const keyBytes = deriveSymmetricKeyFromContext(context, baseKey);\n const key = await importSymmetricCryptoKey(keyBytes);\n\n return key;\n } catch (error) {\n throw new Error('Failed to derive CryptoKey from base key and context', { cause: error });\n }\n}\n\n/**\n * Derives a symmetric key from two keys\n *\n * @param key1 - The 32-bytes key\n * @param key2 - The 32-bytes key\n * @returns The derived secret key\n */\nexport function deriveSymmetricKeyFromTwoKeys(key1: Uint8Array, key2: Uint8Array): Uint8Array {\n return deriveKeyFromTwoKeysAndContext(key1, key2, CONTEXT_DERIVE);\n}\n\n/**\n * Derives a symmetric CryptoKey from two keys\n *\n * @param key1 - The 32-bytes key\n * @param key2 - The 32-bytes key\n * @returns The derived secret CryptoKey\n */\nexport async function deriveSymmetricCryptoKeyFromTwoKeys(key1: Uint8Array, key2: Uint8Array): Promise<CryptoKey> {\n try {\n const keyBytes = deriveSymmetricKeyFromTwoKeys(key1, key2);\n const key = await importSymmetricCryptoKey(keyBytes);\n return key;\n } catch (error) {\n throw new Error('Failed to derive symmetric CryptoKey from two keys', { cause: error });\n }\n}\n\n/**\n * Derives a symmetric key from two keys and context\n *\n * @param key1 - The 32-bytes key\n * @param key2 - The 32-bytes key\n * @param context - The context string\n * @returns The derived symmetric key\n */\nexport function deriveKeyFromTwoKeysAndContext(key1: Uint8Array, key2: Uint8Array, context: string): Uint8Array {\n try {\n if (key2.length != AES_KEY_BIT_LENGTH / 8 || key1.length != AES_KEY_BIT_LENGTH / 8) {\n throw new Error(`Input key length must be exactly ${AES_KEY_BIT_LENGTH / 8} bytes`);\n }\n const key = blake3(key1, { key: key2 });\n return blake3(key, { context: UTF8ToUint8(context) });\n } catch (error) {\n throw new Error('Failed to derive symmetric key from two keys and context', { cause: error });\n }\n}\n","import { SymmetricCiphertext, HybridEncKey, PwdProtectedKey, PublicKeys, PrivateKeys, EmailBody } from '../types';\nimport { genSymmetricCryptoKey, encryptSymmetrically, decryptSymmetrically } from '../symmetric-crypto';\nimport { emailBodyToBinary, binaryToEmailBody } from './converters';\nimport { encapsulateKyber, decapsulateKyber } from '../post-quantum-crypto';\nimport { deriveWrappingKey, wrapKey, unwrapKey, importWrappingKey } from '../key-wrapper';\nimport { deriveSecretKey } from '../asymmetric-crypto';\nimport { getKeyFromPassword, getKeyFromPasswordAndSalt } from '../derive-key';\nimport { UTF8ToUint8, uint8ToUTF8 } from '../utils';\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: string,\n emailID: string,\n): Promise<{ enc: SymmetricCiphertext; encryptionKey: CryptoKey }> {\n try {\n const encryptionKey = await genSymmetricCryptoKey();\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: string,\n emailID: string,\n): Promise<{ enc: SymmetricCiphertext; subjectEnc: SymmetricCiphertext; encryptionKey: CryptoKey }> {\n try {\n const encryptionKey = await genSymmetricCryptoKey();\n const enc = await encryptEmailContentSymmetricallyWithKey(email, encryptionKey, aux, emailID);\n const subjectBuff = UTF8ToUint8(subject);\n const subjectEnc = await encryptSymmetrically(encryptionKey, subjectBuff, aux);\n return { enc, encryptionKey, subjectEnc };\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 CryptoKey.\n * @returns The decrypted email\n */\nexport async function decryptEmailAndSubjectSymmetrically(\n emailCiphertext: SymmetricCiphertext,\n encSubject: SymmetricCiphertext,\n encryptionKey: CryptoKey,\n aux: string,\n): Promise<{ body: EmailBody; subject: string }> {\n try {\n const binaryEmail = await decryptSymmetrically(encryptionKey, emailCiphertext, aux);\n const subject = await decryptSymmetrically(encryptionKey, encSubject, aux);\n const body = binaryToEmailBody(binaryEmail);\n return { body, subject: uint8ToUTF8(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: CryptoKey,\n aux: string,\n emailID: string,\n): Promise<SymmetricCiphertext> {\n try {\n const binaryEmail = emailBodyToBinary(emailBody);\n const ciphertext = await encryptSymmetrically(encryptionKey, binaryEmail, aux, emailID);\n return ciphertext;\n } catch (error) {\n throw new Error('Failed to symmetrically encrypt email with the given key', { cause: error });\n }\n}\n\n/**\n * Decrypts symmetrically encrypted email.\n *\n * @param encryptedEmail - The email to decrypt.\n * @param encryptionKey - The symmetric CryptoKey.\n * @returns The decrypted email\n */\nexport async function decryptEmailSymmetrically(\n emailCiphertext: SymmetricCiphertext,\n encryptionKey: CryptoKey,\n aux: string,\n): Promise<EmailBody> {\n try {\n const binaryEmail = await decryptSymmetrically(encryptionKey, emailCiphertext, aux);\n const body = binaryToEmailBody(binaryEmail);\n return body;\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 CryptoKey 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: CryptoKey,\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 return { encryptedKey, kyberCiphertext };\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 CryptoKey\n */\nexport async function decryptKeysHybrid(\n encryptedKey: HybridEncKey,\n senderPublicKey: PublicKeys,\n recipientPrivateKey: PrivateKeys,\n): Promise<CryptoKey> {\n try {\n const eccSecret = await deriveSecretKey(senderPublicKey.eccPublicKey, recipientPrivateKey.eccPrivateKey);\n const kyberSecret = decapsulateKyber(encryptedKey.kyberCiphertext, recipientPrivateKey.kyberPrivateKey);\n const wrappingKey = await deriveWrappingKey(eccSecret, kyberSecret);\n const encryptionKey = await unwrapKey(encryptedKey.encryptedKey, 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 CryptoKey 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: CryptoKey, password: string): Promise<PwdProtectedKey> {\n try {\n const { key, salt } = await getKeyFromPassword(password);\n const wrappingKey = await importWrappingKey(key);\n const encryptedKey = await wrapKey(emailEncryptionKey, wrappingKey);\n return { encryptedKey, salt };\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 CryptoKey\n */\nexport async function removePasswordProtection(\n emailEncryptionKey: PwdProtectedKey,\n password: string,\n): Promise<CryptoKey> {\n try {\n const key = await getKeyFromPasswordAndSalt(password, emailEncryptionKey.salt);\n const wrappingKey = await importWrappingKey(key);\n const encryptionKey = await unwrapKey(emailEncryptionKey.encryptedKey, wrappingKey);\n return encryptionKey;\n } catch (error) {\n throw new Error('Failed to remove password-protection from email key', { cause: error });\n }\n}\n","import { EmailPublicParameters } from '../types';\nimport { v4 as uuidv4 } from 'uuid';\n\n/**\n * Creates an auxilary string from public fields of the email.\n *\n * @param params - The email public parameters.\n * @returns The resulting auxilary string\n */\nexport function getAux(params: EmailPublicParameters): string {\n try {\n const { subject, replyToEmailID, sender, recipients } = params;\n const aux = JSON.stringify({ subject, replyToEmailID, sender, recipients });\n return aux;\n } catch (error) {\n throw new Error('Failed to create aux', { cause: error });\n }\n}\n\n/**\n * Creates an auxilary string from public fields of the email (except for subject field).\n *\n * @param params - The email public parameters.\n * @returns The resulting auxilary string\n */\nexport function getAuxWithoutSubject(params: EmailPublicParameters): string {\n try {\n const { replyToEmailID, sender, recipients } = params;\n const aux = JSON.stringify({ replyToEmailID, sender, recipients });\n return aux;\n } catch (error) {\n throw new Error('Failed to create aux without subject', { cause: error });\n }\n}\n\n/**\n * Creates a random email ID.\n *\n * @returns The resulting auxilary string\n */\nexport function generateEmailID(): string {\n return uuidv4();\n}\n","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);\n const ciphertext = await encryptEmailContentSymmetricallyWithKey(\n newEmailToStore.body,\n indexKey,\n aux,\n newEmailToStore.id,\n );\n const encryptedEmail = { content: ciphertext, 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);\n const ciphertext = await encryptEmailContentSymmetricallyWithKey(email.body, indexKey, aux, email.id);\n\n return { content: ciphertext, 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);\n const email = await decryptEmailSymmetrically(encryptedEmail.content, indexKey, aux);\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);\n const body = await decryptEmailSymmetrically(encEmail.content, indexKey, aux);\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"]}
1
+ {"version":3,"file":"email-search.js","names":["DB_VERSION","DB_LABEL","deriveSymmetricCryptoKeyFromContext","CONTEXT_INDEX","getAux","encryptEmailContentSymmetricallyWithKey","decryptEmailSymmetrically","emailToBinary","MAX_EMAIL_PER_BATCH","MAX_CACHE_SIZE","Index"],"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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"}