diff --git a/src/email-crypto/converters.ts b/src/email-crypto/converters.ts deleted file mode 100644 index 6823252..0000000 --- a/src/email-crypto/converters.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { UTF8ToUint8 } from '../utils'; -import { User, Email } from '../types'; -import { concatBytes } from '@noble/hashes/utils.js'; - -/** - * Converts a Users into a Uint8Array. - * - * @param user - The user. - * @returns The Uint8Array representation of the user. - */ -export function userToBytes(user: User): Uint8Array { - try { - const json = JSON.stringify(user); - return UTF8ToUint8(json); - } catch (error) { - throw new Error('Failed to convert User to bytes', { cause: error }); - } -} - -/** - * Converts an array of Users into a Uint8Array. - * - * @param recipients - The array of Users. - * @returns The Uint8Array representation of the array of Users. - */ -export function recipientsToBytes(recipients: User[]): Uint8Array { - try { - const array = recipients.map((user) => userToBytes(user)); - return concatBytes(...array); - } catch (error) { - throw new Error('Failed to convert recipients to bytes', { cause: error }); - } -} - -/** - * Converts an Email type into a Uint8Array array. - * - * @param email - The email. - * @returns The Uint8Array array representation of the Email type. - */ -export function emailToBinary(email: Email): Uint8Array { - try { - const json = JSON.stringify(email); - return UTF8ToUint8(json); - } catch (error) { - throw new Error('Failed to convert EmailBody to Uint8Array', { cause: error }); - } -} diff --git a/src/email-crypto/core.ts b/src/email-crypto/core.ts index d539af7..aadb24c 100644 --- a/src/email-crypto/core.ts +++ b/src/email-crypto/core.ts @@ -1,270 +1,106 @@ -import { HybridEncKey, PwdProtectedKey, EmailBody, EmailBodyEncrypted, Email, EmailPublicParameters } from '../types'; +import { HybridEncKey, PwdProtectedKey, EmailBody, EmailBodyEncrypted, RecipientWithPublicKey } from '../types'; import { encryptSymmetrically, decryptSymmetrically, genSymmetricKey } from '../symmetric-crypto'; import { encapsulateHybrid, decapsulateHybrid } from '../hybrid-crypto'; import { wrapKey, unwrapKey } from '../key-wrapper'; import { getKeyFromPassword, getKeyFromPasswordAndSalt } from '../derive-key'; import { UTF8ToUint8, base64ToUint8Array, uint8ArrayToBase64, uint8ToUTF8 } from '../utils'; -import { getAux } from './utils'; /** * Symmetrically encrypts email body. * - * @param email - The email to encrypt. - * @param isSubjectEncrypted - Indicates if the email subject field was encrypted - * @returns The resulting encrypted email body, updated public parameters (with encrypted subject if it was encrypted) and symmetric key used for encryption + * @param body - The email body to encrypt. + * @param aux - An optional auxilary sting for AEAD (e.g., email ID or timestamp). + * @returns The resulting encrypted email body and symmetric key used for encryption */ export async function encryptEmailBody( - email: Email, - isSubjectEncrypted: boolean, + body: EmailBody, + aux?: Uint8Array, ): Promise<{ - enc: EmailBodyEncrypted; - params: EmailPublicParameters; + encEmailBody: EmailBodyEncrypted; encryptionKey: Uint8Array; }> { try { - const aux = getAux(email.params, isSubjectEncrypted); - - let enc: EmailBodyEncrypted; - let encryptionKey: Uint8Array; - let params = email.params; - - if (isSubjectEncrypted) { - const result = await encryptEmailContentAndSubjectSymmetrically(email.body, email.params.subject, aux); - enc = result.enc; - encryptionKey = result.encryptionKey; - params = { ...email.params, subject: result.encSubject }; - } else { - const result = await encryptEmailContentSymmetrically(email.body, aux); - enc = result.enc; - encryptionKey = result.encryptionKey; - } - - return { encryptionKey, enc, params }; - } catch (error) { - throw new Error('Failed to encrypt email body', { cause: error }); - } -} - -/** - * Decrypts symmetrically encrypted email body. - * - * @param enc - The email body to decrypt. - * @param encParams - The email paramaters. - * @param encryptionKey - The symmetric key to decrypt the email. - * @param isSubjectEncrypted - Indicates if the email subject field was encrypted - * @returns The resulting decrypted email body and updated public parameters (with decrypted subject if it was encrypted) - */ -export async function decryptEmailBody( - enc: EmailBodyEncrypted, - encParams: EmailPublicParameters, - encryptionKey: Uint8Array, - isSubjectEncrypted: boolean, -): Promise<{ - params: EmailPublicParameters; - body: EmailBody; -}> { - try { - const aux = getAux(encParams, isSubjectEncrypted); - let body: EmailBody; - let params = encParams; - if (isSubjectEncrypted) { - const result = await decryptEmailAndSubjectSymmetrically(encryptionKey, aux, encParams.subject, enc); - body = result.body; - params = { ...encParams, subject: result.subject }; - } else { - body = await decryptEmailSymmetrically(encryptionKey, aux, enc); - } - - return { body, params }; - } catch (error) { - throw new Error('Failed to encrypt email body', { cause: error }); - } -} - -/** - * Symmetrically encrypts an email with a randomly sampled key. - * - * @param email - The email to encrypt. - * @param aux - The auxiliary data (e.g., email ID or timestamp) for AEAD. - * @returns The resulting ciphertext and the used symmetric key - */ -export async function encryptEmailContentSymmetrically( - email: EmailBody, - aux: Uint8Array, -): Promise<{ enc: EmailBodyEncrypted; encryptionKey: Uint8Array }> { - try { - if (!email.text) { + if (!body.text || !body.subject) { throw new Error('Invalid input'); } const encryptionKey = genSymmetricKey(); - const enc = await encryptEmailContentSymmetricallyWithKey(email, encryptionKey, aux); - return { enc, encryptionKey }; - } catch (error) { - throw new Error('Failed to symmetrically encrypt email', { cause: error }); - } -} + const encEmailBody = await encryptEmailBodyWithKey(body, encryptionKey, aux); -/** - * Symmetrically encrypts an email with a randomly sampled key. - * - * @param email - The email to encrypt. - * @param subject - The email subject to encrypt. - * @param aux - The auxiliary data (e.g., email ID or timestamp) for AEAD. - * @returns The resulting ciphertext and the used symmetric key - */ -export async function encryptEmailContentAndSubjectSymmetrically( - email: EmailBody, - subject: string, - aux: Uint8Array, -): Promise<{ enc: EmailBodyEncrypted; encSubject: string; encryptionKey: Uint8Array }> { - try { - if (!subject || !email.text) { - throw new Error('Invalid input'); - } - const encryptionKey = genSymmetricKey(); - const enc = await encryptEmailContentSymmetricallyWithKey(email, encryptionKey, aux); - const subjectBuff = UTF8ToUint8(subject); - const subjectEnc = await encryptSymmetrically(encryptionKey, subjectBuff, aux); - const encSubject = uint8ArrayToBase64(subjectEnc); - return { enc, encSubject, encryptionKey }; + return { encEmailBody, encryptionKey }; } catch (error) { - throw new Error('Failed to symmetrically encrypt email and subject', { cause: error }); + throw new Error('Failed to symmetrically encrypt email body', { cause: error }); } } /** - * Decrypts symmetrically encrypted email and its subject. + * Symmetrically encrypts email body with the given key. * - * @param encryptionKey - The symmetric key for encryption. - * @param aux - The auxiliary data (e.g., email ID or timestamp) for AEAD. - * @param encSubject - The encrypted email subject. - * @param enc - The encrypted email body. - * @returns The resulting encrypted emailBody + * @param body - The email body to encrypt. + * @param encryptionKey - The symmetric key to encrypt the email. + * @param aux - An optional auxilary sting for AEAD (e.g., email ID or timestamp). + * @returns The resulting encrypted email body and symmetric key used for encryption */ -export async function decryptEmailAndSubjectSymmetrically( +export async function encryptEmailBodyWithKey( + body: EmailBody, encryptionKey: Uint8Array, - aux: Uint8Array, - encSubject: string, - enc: EmailBodyEncrypted, -): Promise<{ body: EmailBody; subject: string }> { - try { - const array = base64ToUint8Array(encSubject); - const subjectArray = await decryptSymmetrically(encryptionKey, array, aux); - const body = await decryptEmailSymmetrically(encryptionKey, aux, enc); - const subject = uint8ToUTF8(subjectArray); - return { body, subject }; - } catch (error) { - throw new Error('Failed to symmetrically decrypt email and subject', { cause: error }); - } -} - -/** - * Symmetrically encrypts an email with a randomly sampled key. - * - * @param emailBody - The email body to encrypt. - * @param encryptionKey - The symmetric key for encryption. - * @param aux - The auxiliary data (e.g., email ID or timestamp) for AEAD. - * @returns The resulting encrypted emailBody - */ -export async function encryptEmailContentSymmetricallyWithKey( - emailBody: EmailBody, - encryptionKey: Uint8Array, - aux: Uint8Array, + aux?: Uint8Array, ): Promise { try { - const text = UTF8ToUint8(emailBody.text); + const text = UTF8ToUint8(body.text); + const subject = UTF8ToUint8(body.subject); + const subjectEnc = await encryptSymmetrically(encryptionKey, subject, aux); const encryptedText = await encryptSymmetrically(encryptionKey, text, aux); const encText = uint8ArrayToBase64(encryptedText); - const result: EmailBodyEncrypted = { encText }; - - if (emailBody.attachments) { - const encryptedAttachements = await encryptEmailAttachements(emailBody.attachments, encryptionKey, aux); - result.encAttachments = encryptedAttachements?.map(uint8ArrayToBase64); - } - return result; - } catch (error) { - throw new Error('Failed to symmetrically encrypt email with the given key', { cause: error }); - } -} + const encSubject = uint8ArrayToBase64(subjectEnc); + const enc: EmailBodyEncrypted = { encText, encSubject }; -/** - * Symmetrically encrypts email attachements. - * - * @param attachments - The attachments. - * @param encryptionKey - The symmetric key. - * @param aux - The auxiliary data (e.g., email ID or timestamp) for AEAD. - * @returns The decrypted email attackements - */ -async function encryptEmailAttachements( - attachments: string[], - encryptionKey: Uint8Array, - aux: Uint8Array, -): Promise { - try { - const encryptedAttachments = await Promise.all( - attachments.map((attachment) => { + if (body.attachments) { + const promises = body.attachments.map((attachment) => { const binaryAttachment = UTF8ToUint8(attachment); return encryptSymmetrically(encryptionKey, binaryAttachment, aux); - }), - ); - return encryptedAttachments; - } catch (error) { - throw new Error('Failed to symmetrically encrypt email attachements', { cause: error }); - } -} + }); + const encryptedAttachments = await Promise.all(promises); + enc.encAttachments = encryptedAttachments?.map(uint8ArrayToBase64); + } -/** - * Decrypts symmetrically encrypted email attachements. - * - * @param encryptedAttachments - The encrypted attachments. - * @param encryptionKey - The symmetric key. - * @param aux - The auxiliary data (e.g., email ID or timestamp) for AEAD. - * @returns The decrypted email attackements - */ -async function decryptEmailAttachements( - encryptedAttachments: Uint8Array[], - encryptionKey: Uint8Array, - aux: Uint8Array, -): Promise { - try { - const decryptedAttachments = await Promise.all( - encryptedAttachments.map((attachment) => { - return decryptSymmetrically(encryptionKey, attachment, aux); - }), - ); - return decryptedAttachments; + return enc; } catch (error) { - throw new Error('Failed to symmetrically decrypt email attachements', { cause: error }); + throw new Error('Failed to encrypt email body', { cause: error }); } } /** - * Decrypts symmetrically encrypted email. + * Decrypts symmetrically encrypted email body. * - * @param encryptionKey - The symmetric key. - * @param aux - The auxiliary data (e.g., email ID or timestamp) for AEAD. - * @param enc - The email body to decrypt. - * @returns The decrypted email + * @param encEmailBody - The email body to decrypt. + * @param encryptionKey - The symmetric key to decrypt the email. + * @param aux - An optional auxilary sting for AEAD (e.g., email ID or timestamp). + * @returns The resulting decrypted email body */ -export async function decryptEmailSymmetrically( +export async function decryptEmailBody( + encEmailBody: EmailBodyEncrypted, encryptionKey: Uint8Array, - aux: Uint8Array, - enc: EmailBodyEncrypted, + aux?: Uint8Array, ): Promise { try { - const cipher = base64ToUint8Array(enc.encText); - const textArray = await decryptSymmetrically(encryptionKey, cipher, aux); + const encSubject = base64ToUint8Array(encEmailBody.encSubject); + const subjectArray = await decryptSymmetrically(encryptionKey, encSubject, aux); + const subject = uint8ToUTF8(subjectArray); + const encText = base64ToUint8Array(encEmailBody.encText); + const textArray = await decryptSymmetrically(encryptionKey, encText, aux); const text = uint8ToUTF8(textArray); - const result: EmailBody = { text }; + const body: EmailBody = { text, subject }; - if (enc.encAttachments) { - const encAttachements = enc.encAttachments?.map(base64ToUint8Array); - const attachmentsArray = await decryptEmailAttachements(encAttachements, encryptionKey, aux); - result.attachments = attachmentsArray?.map((att) => uint8ToUTF8(att)); + if (encEmailBody.encAttachments) { + const encAttachments = encEmailBody.encAttachments?.map(base64ToUint8Array); + const promises = encAttachments?.map((encAtt) => decryptSymmetrically(encryptionKey, encAtt, aux)); + const decryptedAttachments = await Promise.all(promises); + body.attachments = decryptedAttachments?.map((att) => uint8ToUTF8(att)); } - return result; + + return body; } catch (error) { - throw new Error('Failed to symmetrically decrypt email', { cause: error }); + throw new Error('Failed to symmetrically decrypt email body', { cause: error }); } } @@ -272,20 +108,24 @@ export async function decryptEmailSymmetrically( * Encrypts the email symmetric key using hybrid encryption. * * @param emailEncryptionKey - The symmetric key used for email encryption. - * @param recipientPublicHybridKey - The public key of the recipient. + * @param recipient - The recipient with a public hybrid key. * @returns The encrypted email symmetric key */ export async function encryptKeysHybrid( emailEncryptionKey: Uint8Array, - recipientPublicHybridKey: Uint8Array, + recipient: RecipientWithPublicKey, ): Promise { try { - const { cipherText, sharedSecret } = encapsulateHybrid(recipientPublicHybridKey); + const { cipherText, sharedSecret } = encapsulateHybrid(recipient.publicHybridKey); const encryptedKey = await wrapKey(emailEncryptionKey, sharedSecret); const encryptedKeyBase64 = uint8ArrayToBase64(encryptedKey); const kyberCiphertextBase64 = uint8ArrayToBase64(cipherText); - return { encryptedKey: encryptedKeyBase64, kyberCiphertext: kyberCiphertextBase64 }; + return { + encryptedKey: encryptedKeyBase64, + hybridCiphertext: kyberCiphertextBase64, + encryptedForEmail: recipient.email, + }; } catch (error) { throw new Error('Failed to encrypt email key using hybrid encryption', { cause: error }); } @@ -303,7 +143,7 @@ export async function decryptKeysHybrid( recipientPrivateKey: Uint8Array, ): Promise { try { - const kyberCiphertext = base64ToUint8Array(encryptedKey.kyberCiphertext); + const kyberCiphertext = base64ToUint8Array(encryptedKey.hybridCiphertext); const encKey = base64ToUint8Array(encryptedKey.encryptedKey); const sharedSecret = decapsulateHybrid(kyberCiphertext, recipientPrivateKey); const encryptionKey = await unwrapKey(encKey, sharedSecret); diff --git a/src/email-crypto/hybridEncyptedEmail.ts b/src/email-crypto/hybridEncyptedEmail.ts index 60fd1a4..f20aa39 100644 --- a/src/email-crypto/hybridEncyptedEmail.ts +++ b/src/email-crypto/hybridEncyptedEmail.ts @@ -1,54 +1,50 @@ -import { HybridEncryptedEmail, Email, UserWithPublicKey } from '../types'; +import { HybridEncryptedEmail, EmailBody, RecipientWithPublicKey } from '../types'; import { decryptEmailBody, encryptKeysHybrid, decryptKeysHybrid, encryptEmailBody } from './core'; /** - * Encrypts the email using hybrid encryption. + * Encrypts the email body using hybrid encryption. * - * @param email - The email to encrypt. + * @param body - The email body to encrypt. * @param recipientPublicKeys - The public keys of the recipient. - * @param isSubjectEncrypted - Indicates if the email subject field should be encrypted - * @returns The encrypted email + * @param aux - An optional auxilary sting for AEAD (e.g., email ID or timestamp). + * @returns The encrypted email body */ export async function encryptEmailHybrid( - email: Email, - recipient: UserWithPublicKey, - isSubjectEncrypted: boolean = false, + body: EmailBody, + recipient: RecipientWithPublicKey, + aux?: Uint8Array, ): Promise { try { - const { encryptionKey, params, enc } = await encryptEmailBody(email, isSubjectEncrypted); - const encryptedKey = await encryptKeysHybrid(encryptionKey, recipient.publicHybridKey); - return { enc, encryptedKey, recipientEmail: recipient.email, params, isSubjectEncrypted, id: email.id }; + const { encryptionKey, encEmailBody } = await encryptEmailBody(body, aux); + const encryptedKey = await encryptKeysHybrid(encryptionKey, recipient); + return { encEmailBody, encryptedKey }; } catch (error) { - throw new Error('Failed to encrypt email with hybrid encryption', { cause: error }); + throw new Error('Failed to encrypt email body with hybrid encryption', { cause: error }); } } /** - * Encrypts the email using hybrid encryption for multiple recipients. + * Encrypts the email body using hybrid encryption for multiple recipients. * - * @param email - The email to encrypt. + * @param body - The email body to encrypt for multiple recipients. * @param recipients - The recipients with corresponding public keys. - * @param isSubjectEncrypted - Indicates if the email subject field should be encrypted - * @returns The set of encrypted email + * @param aux - An optional auxilary sting for AEAD (e.g., email ID or timestamp). + * @returns The set of encrypted email bodies */ export async function encryptEmailHybridForMultipleRecipients( - email: Email, - recipients: UserWithPublicKey[], - isSubjectEncrypted: boolean = false, + body: EmailBody, + recipients: RecipientWithPublicKey[], + aux?: Uint8Array, ): Promise { try { - const { encryptionKey, params, enc } = await encryptEmailBody(email, isSubjectEncrypted); + const { encryptionKey, encEmailBody } = await encryptEmailBody(body, aux); const encryptedEmails: HybridEncryptedEmail[] = []; for (const recipient of recipients) { - const encryptedKey = await encryptKeysHybrid(encryptionKey, recipient.publicHybridKey); + const encryptedKey = await encryptKeysHybrid(encryptionKey, recipient); encryptedEmails.push({ - enc, + encEmailBody: encEmailBody, encryptedKey, - recipientEmail: recipient.email, - params, - isSubjectEncrypted, - id: email.id, }); } return encryptedEmails; @@ -60,19 +56,20 @@ export async function encryptEmailHybridForMultipleRecipients( /** * Decrypts the email using hybrid encryption. * - * @param encryptedEmail - The encrypted email. + * @param encEmailBody - The encrypted email. * @param recipientPrivateHybridKeys - The private key of the recipient. - * @returns The decrypted email + * @param aux - An optional auxilary sting for AEAD (e.g., email ID or timestamp). + * @returns The decrypted email body */ export async function decryptEmailHybrid( - encryptedEmail: HybridEncryptedEmail, + encEmailBody: HybridEncryptedEmail, recipientPrivateHybridKeys: Uint8Array, -): Promise { + aux?: Uint8Array, +): Promise { try { - const { isSubjectEncrypted, params: encParams, enc, encryptedKey, id } = encryptedEmail; - const encryptionKey = await decryptKeysHybrid(encryptedKey, recipientPrivateHybridKeys); - const { body, params } = await decryptEmailBody(enc, encParams, encryptionKey, isSubjectEncrypted); - return { body, params, id }; + const encryptionKey = await decryptKeysHybrid(encEmailBody.encryptedKey, recipientPrivateHybridKeys); + const body = await decryptEmailBody(encEmailBody.encEmailBody, encryptionKey, aux); + return body; } catch (error) { throw new Error('Failed to decrypt email with hybrid encryption', { cause: error }); } diff --git a/src/email-crypto/index.ts b/src/email-crypto/index.ts index 71d730a..64a4848 100644 --- a/src/email-crypto/index.ts +++ b/src/email-crypto/index.ts @@ -1,5 +1,3 @@ export * from './hybridEncyptedEmail'; export * from './pwdProtectedEmail'; -export * from './converters'; export * from './emailKeys'; -export * from './utils'; diff --git a/src/email-crypto/pwdProtectedEmail.ts b/src/email-crypto/pwdProtectedEmail.ts index e99e60a..eddabe5 100644 --- a/src/email-crypto/pwdProtectedEmail.ts +++ b/src/email-crypto/pwdProtectedEmail.ts @@ -1,4 +1,4 @@ -import { PwdProtectedEmail, Email } from '../types'; +import { PwdProtectedEmail, EmailBody } from '../types'; import { decryptEmailBody, passwordProtectKey, removePasswordProtection, encryptEmailBody } from './core'; /** @@ -6,22 +6,19 @@ import { decryptEmailBody, passwordProtectKey, removePasswordProtection, encrypt * * @param email - The email to password-protect * @param password - The secret password shared among recipients - * @param isSubjectEncrypted - Indicates if the email subject field should be encrypted + * @param aux - An optional auxilary sting for AEAD (e.g., email ID or timestamp). * @returns The password-protected email */ export async function createPwdProtectedEmail( - email: Email, + emailBody: EmailBody, password: string, - isSubjectEncrypted: boolean = false, + aux?: Uint8Array, ): Promise { try { - if (!email?.body || !email.params) { - throw new Error('Failed to password-protect email: Invalid email structure'); - } - const { encryptionKey, params, enc } = await encryptEmailBody(email, isSubjectEncrypted); + const { encryptionKey, encEmailBody } = await encryptEmailBody(emailBody, aux); const encryptedKey = await passwordProtectKey(encryptionKey, password); - return { enc, encryptedKey, params, id: email.id, isSubjectEncrypted }; + return { encEmailBody, encryptedKey }; } catch (error) { throw new Error('Failed to password-protect email', { cause: error }); } @@ -32,14 +29,18 @@ export async function createPwdProtectedEmail( * * @param encryptedEmail - The encrypted email * @param password - The secret password shared among recipients. - * @returns The decrypted email + * @param aux - An optional auxilary sting for AEAD (e.g., email ID or timestamp). + * @returns The decrypted email body */ -export async function decryptPwdProtectedEmail(encryptedEmail: PwdProtectedEmail, password: string): Promise { +export async function decryptPwdProtectedEmail( + encryptedEmail: PwdProtectedEmail, + password: string, + aux?: Uint8Array, +): Promise { try { - const { isSubjectEncrypted, params: encParams, enc, id } = encryptedEmail; const encryptionKey = await removePasswordProtection(encryptedEmail.encryptedKey, password); - const { body, params } = await decryptEmailBody(enc, encParams, encryptionKey, isSubjectEncrypted); - return { body, params, id }; + const body = await decryptEmailBody(encryptedEmail.encEmailBody, encryptionKey, aux); + return body; } catch (error) { throw new Error('Failed to decrypt password-protect email', { cause: error }); } diff --git a/src/email-crypto/utils.ts b/src/email-crypto/utils.ts deleted file mode 100644 index 1fb7e83..0000000 --- a/src/email-crypto/utils.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { concatBytes } from '@noble/hashes/utils.js'; -import { EmailPublicParameters } from '../types'; -import { UTF8ToUint8, uuidToBytes } from '../utils'; -import { userToBytes, recipientsToBytes } from './converters'; - -/** - * Creates an auxiliary string from public fields of the email. - * - * @param params - The email public parameters. - * @param isSubjectEncrypted - Indicates if the email subject field should be encrypted - * @returns The resulting auxiliary string - */ -export function getAux(params: EmailPublicParameters, isSubjectEncrypted: boolean): Uint8Array { - try { - const { subject, replyToEmailID, sender, recipient, recipients } = params; - const replyBytes = replyToEmailID ? uuidToBytes(replyToEmailID) : new Uint8Array(); - const senderBytes = userToBytes(sender); - const recipientBytes = userToBytes(recipient); - const recipientsBytes = recipients ? recipientsToBytes(recipients) : new Uint8Array(); - - if (isSubjectEncrypted) { - return concatBytes(replyBytes, senderBytes, recipientBytes, recipientsBytes); - } else { - const subjectBytes = UTF8ToUint8(subject); - return concatBytes(subjectBytes, replyBytes, senderBytes, recipientBytes, recipientsBytes); - } - } catch (error) { - throw new Error('Failed to create aux', { cause: error }); - } -} diff --git a/src/email-search/indexedDB.ts b/src/email-search/indexedDB.ts index b6cce3a..93b447e 100644 --- a/src/email-search/indexedDB.ts +++ b/src/email-search/indexedDB.ts @@ -1,9 +1,8 @@ import { DBSchema, openDB, deleteDB, IDBPDatabase } from 'idb'; import { StoredEmail, Email } from '../types'; -import { decryptEmailSymmetrically, encryptEmailContentSymmetricallyWithKey } from '../email-crypto/core'; +import { decryptEmailBody, encryptEmailBodyWithKey } from '../email-crypto/core'; import { deriveSymmetricKeyFromContext } from '../derive-key'; import { CONTEXT_INDEX, DB_LABEL, DB_VERSION } from '../constants'; -import { getAux } from '../email-crypto'; export type MailDB = IDBPDatabase; @@ -90,9 +89,8 @@ export const encryptAndStoreEmail = async ( esDB: MailDB, ): Promise => { try { - const aux = getAux(newEmailToStore.params, false); - const enc = await encryptEmailContentSymmetricallyWithKey(newEmailToStore.body, indexKey, aux); - const encryptedEmail: StoredEmail = { enc, params: newEmailToStore.params, id: newEmailToStore.id }; + const enc = await encryptEmailBodyWithKey(newEmailToStore.body, indexKey); + const encryptedEmail: StoredEmail = { encEmailBody: enc, params: newEmailToStore.params, id: newEmailToStore.id }; await esDB.put(DB_LABEL, encryptedEmail); } catch (error) { throw new Error('Cannot encrypt and add the given email to the database', { cause: error }); @@ -114,10 +112,9 @@ export const encryptAndStoreManyEmail = async ( try { const encryptedEmails = await Promise.all( newEmailsToStore.map(async (email: Email) => { - const aux = getAux(email.params, false); - const enc = await encryptEmailContentSymmetricallyWithKey(email.body, indexKey, aux); + const encEmailBody = await encryptEmailBodyWithKey(email.body, indexKey); - return { enc, params: email.params, id: email.id }; + return { encEmailBody, params: email.params, id: email.id }; }), ); @@ -137,8 +134,7 @@ export const encryptAndStoreManyEmail = async ( */ const decryptEmail = async (indexKey: Uint8Array, encryptedEmail: StoredEmail): Promise => { try { - const aux = getAux(encryptedEmail.params, false); - const email = await decryptEmailSymmetrically(indexKey, aux, encryptedEmail.enc); + const email = await decryptEmailBody(encryptedEmail.encEmailBody, indexKey); return { body: email, params: encryptedEmail.params, id: encryptedEmail.id }; } catch (error) { throw new Error('Cannot decrypt the given email', { cause: error }); @@ -178,8 +174,7 @@ export const getAndDecryptAllEmails = async (indexKey: Uint8Array, esDB: MailDB) const decryptedEmails = await Promise.all( encryptedEmails.map(async (encEmail) => { - const aux = getAux(encEmail.params, false); - const body = await decryptEmailSymmetrically(indexKey, aux, encEmail.enc); + const body = await decryptEmailBody(encEmail.encEmailBody, indexKey); return { body, params: encEmail.params, id: encEmail.id }; }), ); diff --git a/src/email-search/mailCache.ts b/src/email-search/mailCache.ts index 215448c..c197231 100644 --- a/src/email-search/mailCache.ts +++ b/src/email-search/mailCache.ts @@ -1,7 +1,7 @@ import { MAX_CACHE_SIZE, MAX_EMAIL_PER_BATCH } from '../constants'; import { getEmailBatch, getAllEmailsSortedNewestFirst, getEmailCount, MailDB } from './indexedDB'; import { Email, MailCache } from '../types'; -import { emailToBinary } from '../email-crypto'; +import { emailToBinary } from './utils'; /** * Estimates the email size in the memory diff --git a/src/email-search/search.ts b/src/email-search/search.ts index ff93cc2..79e61a3 100644 --- a/src/email-search/search.ts +++ b/src/email-search/search.ts @@ -67,19 +67,10 @@ const createSearchIndex = (): EmailSearchIndex => ({ export const addEmailToSearchIndex = (email: Email, searchIndex: EmailSearchIndex): void => { try { const emailId = email.id; - - if (email.params.subject) { - searchIndex.subjectIndex.add(emailId, email.params.subject); - } - - if (email.body?.text) { - searchIndex.bodyIndex.add(emailId, email.body.text); - } - - if (email.params.sender) { - const senderText = `${email.params.sender.name || ''} ${email.params.sender.email || ''}`.trim(); - searchIndex.fromIndex.add(emailId, senderText); - } + searchIndex.subjectIndex.add(emailId, email.body.subject); + searchIndex.bodyIndex.add(emailId, email.body.text); + const senderText = `${email.params.sender.name || ''} ${email.params.sender.email || ''}`.trim(); + searchIndex.fromIndex.add(emailId, senderText); const recipientsList = email.params.recipients?.length ? email.params.recipients : [email.params.recipient]; diff --git a/src/email-search/utils.ts b/src/email-search/utils.ts new file mode 100644 index 0000000..3267a83 --- /dev/null +++ b/src/email-search/utils.ts @@ -0,0 +1,17 @@ +import { UTF8ToUint8 } from '../utils'; +import { Email } from '../types'; + +/** + * Converts an Email type into a Uint8Array array. + * + * @param email - The email. + * @returns The Uint8Array array representation of the Email type. + */ +export function emailToBinary(email: Email): Uint8Array { + try { + const json = JSON.stringify(email); + return UTF8ToUint8(json); + } catch (error) { + throw new Error('Failed to convert EmailBody to Uint8Array', { cause: error }); + } +} diff --git a/src/types.ts b/src/types.ts index 86fe3d6..b363941 100644 --- a/src/types.ts +++ b/src/types.ts @@ -10,7 +10,8 @@ export type User = { name: string; }; -export type UserWithPublicKey = User & { +export type RecipientWithPublicKey = { + email: string; publicHybridKey: Uint8Array; }; @@ -21,30 +22,24 @@ export type HybridKeyPair = { export type HybridEncryptedEmail = { encryptedKey: HybridEncKey; - enc: EmailBodyEncrypted; - recipientEmail: string; - params: EmailPublicParameters; - id: string; - isSubjectEncrypted: boolean; + encEmailBody: EmailBodyEncrypted; }; export type PwdProtectedEmail = { encryptedKey: PwdProtectedKey; - enc: EmailBodyEncrypted; - params: EmailPublicParameters; - id: string; - isSubjectEncrypted: boolean; + encEmailBody: EmailBodyEncrypted; }; export type StoredEmail = { params: EmailPublicParameters; - enc: EmailBodyEncrypted; + encEmailBody: EmailBodyEncrypted; id: string; }; export type HybridEncKey = { - kyberCiphertext: string; + hybridCiphertext: string; encryptedKey: string; + encryptedForEmail: string; }; export type PwdProtectedKey = { @@ -54,16 +49,17 @@ export type PwdProtectedKey = { export type EmailBodyEncrypted = { encText: string; + encSubject: string; encAttachments?: string[]; }; export type EmailBody = { text: string; + subject: string; attachments?: string[]; }; export type EmailPublicParameters = { - subject: string; createdAt: string; sender: User; recipient: User; diff --git a/tests/email-crypto/core.test.ts b/tests/email-crypto/core.test.ts index 65070fd..e824505 100644 --- a/tests/email-crypto/core.test.ts +++ b/tests/email-crypto/core.test.ts @@ -1,40 +1,16 @@ import { describe, expect, it } from 'vitest'; -import { EmailBody, User, EmailPublicParameters } from '../../src/types'; -import { - decryptEmailAndSubjectSymmetrically, - decryptEmailSymmetrically, - encryptEmailContentAndSubjectSymmetrically, - encryptEmailContentSymmetrically, -} from '../../src/email-crypto/core'; +import { EmailBody } from '../../src/types'; +import { decryptEmailBody, encryptEmailBody } from '../../src/email-crypto/core'; import { generateUuid } from '../../src/utils'; -import { getAux } from '../../src/email-crypto'; import { genSymmetricKey } from '../../src/symmetric-crypto'; describe('Test email crypto functions', () => { const emailBody: EmailBody = { text: 'test body', - }; - - const userAlice: User = { - email: 'alice email', - name: 'alice', - }; - - const userBob = { - email: 'bob email', - name: 'bob', - }; - - const emailParams: EmailPublicParameters = { - labels: ['test label 1', 'test label2'], - createdAt: '2023-06-14T08:11:22.000Z', subject: 'test subject', - sender: userAlice, - recipient: userBob, - replyToEmailID: generateUuid(), }; - const aux = getAux(emailParams, false); + const aux = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]); it('should generate email id', async () => { const result1 = generateUuid(); @@ -44,59 +20,28 @@ describe('Test email crypto functions', () => { }); it('should encrypt and decrypt email', async () => { - const { enc, encryptionKey } = await encryptEmailContentSymmetrically(emailBody, aux); - const result = await decryptEmailSymmetrically(encryptionKey, aux, enc); + const { encEmailBody, encryptionKey } = await encryptEmailBody(emailBody, aux); + const result = await decryptEmailBody(encEmailBody, encryptionKey, aux); expect(result).toEqual(emailBody); }); it('should throw an error if decryption fails', async () => { - const { enc, encryptionKey } = await encryptEmailContentSymmetrically(emailBody, aux); + const { encEmailBody, encryptionKey } = await encryptEmailBody(emailBody, aux); const bad_encryptionKey = await genSymmetricKey(); - await expect(decryptEmailSymmetrically(bad_encryptionKey, aux, enc)).rejects.toThrowError( - /Failed to symmetrically decrypt email/, + await expect(decryptEmailBody(encEmailBody, bad_encryptionKey, aux)).rejects.toThrowError( + /Failed to symmetrically decrypt email body/, ); - const bad_aux = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]); - await expect(decryptEmailSymmetrically(encryptionKey, bad_aux, enc)).rejects.toThrowError( - /Failed to symmetrically decrypt email/, + const bad_aux = new Uint8Array([4, 5, 6, 7, 8]); + await expect(decryptEmailBody(encEmailBody, encryptionKey, bad_aux)).rejects.toThrowError( + /Failed to symmetrically decrypt email body/, ); }); - it('should throw an error if decryption fails', async () => { - const bad_encryptionKey = await genSymmetricKey(); - const { enc, encryptionKey, encSubject } = await encryptEmailContentAndSubjectSymmetrically( - emailBody, - emailParams.subject, - aux, - ); - await expect(decryptEmailAndSubjectSymmetrically(bad_encryptionKey, aux, encSubject, enc)).rejects.toThrowError( - /Failed to symmetrically decrypt email and subject/, - ); - - const bad_aux = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]); - - await expect(decryptEmailAndSubjectSymmetrically(encryptionKey, bad_aux, encSubject, enc)).rejects.toThrowError( - /Failed to symmetrically decrypt email and subject/, - ); - }); - - it('should throw an error if cannot create aux', async () => { - const bad_params = { replyToEmailID: BigInt(423) }; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - expect(() => getAux(bad_params as any as EmailPublicParameters, false)).toThrowError(/Failed to create aux/); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - expect(() => getAux(bad_params as any as EmailPublicParameters, true)).toThrowError(/Failed to create aux/); - }); it('should throw an error if cannot encrypt', async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any const bad_email: any = {}; bad_email.self = bad_email; - await expect(encryptEmailContentSymmetrically(bad_email, aux)).rejects.toThrowError( - /Failed to symmetrically encrypt email/, - ); - - await expect(encryptEmailContentAndSubjectSymmetrically(bad_email, emailParams.subject, aux)).rejects.toThrowError( - /Failed to symmetrically encrypt email and subject/, - ); + await expect(encryptEmailBody(bad_email, aux)).rejects.toThrowError(/Failed to symmetrically encrypt email body/); }); }); diff --git a/tests/email-crypto/hybridEmail.test.ts b/tests/email-crypto/hybridEmail.test.ts index 364073e..936c754 100644 --- a/tests/email-crypto/hybridEmail.test.ts +++ b/tests/email-crypto/hybridEmail.test.ts @@ -6,53 +6,30 @@ import { generateEmailKeys, } from '../../src/email-crypto'; -import { EmailBody, HybridEncryptedEmail, HybridEncKey, EmailPublicParameters, Email } from '../../src/types'; -import { generateUuid } from '../../src/utils'; +import { EmailBody, HybridEncryptedEmail, HybridEncKey } from '../../src/types'; describe('Test email crypto functions', async () => { - const emailBody: EmailBody = { + const email: EmailBody = { text: 'test body', - }; - - const userAlice = { - email: 'alice email', - name: 'alice', - }; - - const userBob = { - email: 'bob email', - name: 'bob', - }; - - const emailParams: EmailPublicParameters = { - labels: ['test label 1', 'test label2'], - createdAt: '2023-06-14T08:11:22.000Z', subject: 'test subject', - sender: userAlice, - recipient: userBob, - replyToEmailID: generateUuid(), - }; - - const email: Email = { - id: generateUuid(), - body: emailBody, - params: emailParams, }; const { secretKey: alicePrivateKeys, publicKey: alicePublicKeys } = await generateEmailKeys(); const { secretKey: bobPrivateKeys, publicKey: bobPublicKeys } = await generateEmailKeys(); const bobWithPublicKeys = { - ...userBob, + email: 'bob email', publicHybridKey: bobPublicKeys, }; const aliceWithPublicKeys = { - ...userAlice, + email: 'alice email', publicHybridKey: alicePublicKeys, }; it('should encrypt and decrypt email sucessfully', async () => { const encryptedEmail = await encryptEmailHybrid(email, bobWithPublicKeys); + + expect(encryptedEmail.encEmailBody.encSubject).not.toBe(email.subject); const decryptedEmail = await decryptEmailHybrid(encryptedEmail, bobPrivateKeys); expect(decryptedEmail).toStrictEqual(email); @@ -60,12 +37,12 @@ describe('Test email crypto functions', async () => { it('should throw an error if public key is given instead of the secret one', async () => { const bad_recipient = { - ...userAlice, + email: 'alice email', publicHybridKey: alicePrivateKeys, }; await expect(encryptEmailHybrid(email, bad_recipient)).rejects.toThrowError( - /Failed to encrypt email with hybrid encryption/, + /Failed to encrypt email body with hybrid encryption/, ); }); @@ -79,18 +56,16 @@ describe('Test email crypto functions', async () => { it('should throw an error if hybrid email decryption fails', async () => { const encKey: HybridEncKey = { - kyberCiphertext: 'mock kyber ciphertext', + hybridCiphertext: 'mock kyber ciphertext', encryptedKey: 'mock encrypted key', + encryptedForEmail: 'mock recipient email', }; const bad_encrypted_email: HybridEncryptedEmail = { encryptedKey: encKey, - enc: { + encEmailBody: { encText: 'mock encrypted text', + encSubject: 'mock encrypted subject', }, - recipientEmail: userBob.email, - params: emailParams, - id: generateUuid(), - isSubjectEncrypted: false, }; await expect(decryptEmailHybrid(bad_encrypted_email, bobPrivateKeys)).rejects.toThrowError( @@ -105,7 +80,7 @@ describe('Test email crypto functions', async () => { ]); expect(encryptedEmail.length).toBe(2); - expect(encryptedEmail[0].enc).toBe(encryptedEmail[1].enc); + expect(encryptedEmail[0].encEmailBody).toBe(encryptedEmail[1].encEmailBody); }); it('should throw an error if encryption to multiple recipients fails', async () => { diff --git a/tests/email-crypto/hybridEmailAndSubject.test.ts b/tests/email-crypto/hybridEmailAndSubject.test.ts deleted file mode 100644 index 04e80cc..0000000 --- a/tests/email-crypto/hybridEmailAndSubject.test.ts +++ /dev/null @@ -1,112 +0,0 @@ -import { describe, expect, it } from 'vitest'; -import { - encryptEmailHybrid, - decryptEmailHybrid, - encryptEmailHybridForMultipleRecipients, - generateEmailKeys, -} from '../../src/email-crypto'; - -import { EmailBody, HybridEncryptedEmail, HybridEncKey, EmailPublicParameters, Email } from '../../src/types'; -import { generateUuid } from '../../src/utils'; - -describe('Test email crypto functions', async () => { - const emailBody: EmailBody = { - text: 'test body', - }; - - const userAlice = { - email: 'alice email', - name: 'alice', - }; - - const userBob = { - email: 'bob email', - name: 'bob', - }; - - const emailParams: EmailPublicParameters = { - labels: ['test label 1', 'test label2'], - createdAt: '2023-06-14T08:11:22.000Z', - subject: 'test subject', - sender: userAlice, - recipient: userBob, - replyToEmailID: generateUuid(), - }; - - const email: Email = { - id: generateUuid(), - body: emailBody, - params: emailParams, - }; - - const { secretKey: alicePrivateKeys, publicKey: alicePublicKeys } = await generateEmailKeys(); - const { secretKey: bobPrivateKeys, publicKey: bobPublicKeys } = await generateEmailKeys(); - - const bobWithPublicKeys = { - ...userBob, - publicHybridKey: bobPublicKeys, - }; - const aliceWithPublicKeys = { - ...userAlice, - publicHybridKey: alicePublicKeys, - }; - - it('should encrypt and decrypt email sucessfully', async () => { - const encryptedEmail = await encryptEmailHybrid(email, bobWithPublicKeys, true); - const decryptedEmail = await decryptEmailHybrid(encryptedEmail, bobPrivateKeys); - - expect(decryptedEmail).toStrictEqual(email); - expect(encryptedEmail.params.subject).not.toBe(email.params.subject); - }); - - it('should throw an error if hybrid email decryption fails', async () => { - const encKey: HybridEncKey = { - kyberCiphertext: 'mock kyber ciphertext', - encryptedKey: 'mock encrypted key', - }; - const bad_encrypted_email: HybridEncryptedEmail = { - encryptedKey: encKey, - enc: { - encText: 'mock encrypted email text', - }, - recipientEmail: userBob.email, - params: emailParams, - id: 'test id', - isSubjectEncrypted: true, - }; - - await expect(decryptEmailHybrid(bad_encrypted_email, bobPrivateKeys)).rejects.toThrowError( - /Failed to decrypt email with hybrid encryption/, - ); - }); - - it('should encrypt the email to multiple senders sucessfully', async () => { - const encryptedEmail = await encryptEmailHybridForMultipleRecipients( - email, - [bobWithPublicKeys, aliceWithPublicKeys], - true, - ); - - expect(encryptedEmail.length).toBe(2); - expect(encryptedEmail[0].enc).toBe(encryptedEmail[1].enc); - expect(encryptedEmail[0].params.subject).toBe(encryptedEmail[1].params.subject); - expect(encryptedEmail[0].params.subject).not.toBe(email.params.subject); - - const decEmailBob = await decryptEmailHybrid(encryptedEmail[0], bobPrivateKeys); - expect(decEmailBob).toStrictEqual(email); - - const decEmailEve = await decryptEmailHybrid(encryptedEmail[1], alicePrivateKeys); - expect(decEmailEve).toStrictEqual(email); - }); - - it('should throw an error if encryption to multiple recipients fails', async () => { - const bad_eveWithPublicKeys = { - email: 'eve email', - name: 'eve', - publicHybridKey: new Uint8Array(), - }; - await expect( - encryptEmailHybridForMultipleRecipients(email, [bobWithPublicKeys, bad_eveWithPublicKeys], true), - ).rejects.toThrowError(/Failed to encrypt email to multiple recipients with hybrid encryption/); - }); -}); diff --git a/tests/email-crypto/pwdProtectedEmail.test.ts b/tests/email-crypto/pwdProtectedEmail.test.ts index f1d85cc..ac5ecd4 100644 --- a/tests/email-crypto/pwdProtectedEmail.test.ts +++ b/tests/email-crypto/pwdProtectedEmail.test.ts @@ -1,37 +1,14 @@ import { describe, expect, it } from 'vitest'; import { createPwdProtectedEmail, decryptPwdProtectedEmail } from '../../src/email-crypto'; -import { EmailBody, User, EmailPublicParameters, Email } from '../../src/types'; -import { generateUuid } from '../../src/utils'; +import { EmailBody } from '../../src/types'; describe('Test email crypto functions', () => { - const emailBody: EmailBody = { + const email: EmailBody = { text: 'Hi Bob, This is a test message. -Alice.', - }; - - const sharedSecret = 'test shared secret'; - const userAlice: User = { - email: 'alice email', - name: 'alice', - }; - - const userBob: User = { - email: 'bob email', - name: 'bob', - }; - const emailParams: EmailPublicParameters = { - labels: ['test label 1', 'test label2'], - createdAt: '2023-06-14T08:11:22.000Z', subject: 'test subject', - sender: userAlice, - recipient: userBob, - replyToEmailID: generateUuid(), }; - const email = { - body: emailBody, - params: emailParams, - id: generateUuid(), - }; + const sharedSecret = 'test shared secret'; it('should encrypt and decrypt email sucessfully', async () => { const encryptedEmail = await createPwdProtectedEmail(email, sharedSecret); @@ -40,9 +17,7 @@ describe('Test email crypto functions', () => { }); it('should throw an error if encryption fails', async () => { - const bad_email = { - params: emailParams, - } as unknown as Email; + const bad_email = {} as unknown as EmailBody; await expect(createPwdProtectedEmail(bad_email, sharedSecret)).rejects.toThrowError( /Failed to password-protect email/, ); diff --git a/tests/email-crypto/pwdProtectedEmailAndSubject.test.ts b/tests/email-crypto/pwdProtectedEmailAndSubject.test.ts deleted file mode 100644 index f315c61..0000000 --- a/tests/email-crypto/pwdProtectedEmailAndSubject.test.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { describe, expect, it } from 'vitest'; -import { createPwdProtectedEmail, decryptPwdProtectedEmail } from '../../src/email-crypto'; -import { EmailBody, Email, User, EmailPublicParameters } from '../../src/types'; -import { generateUuid } from '../../src/utils'; - -describe('Test email crypto functions', () => { - const emailBody: EmailBody = { - text: 'Hi Bob, This is a test message. -Alice.', - }; - - const sharedSecret = 'test shared secret'; - const userAlice: User = { - email: 'alice email', - name: 'alice', - }; - - const userBob: User = { - email: 'bob email', - name: 'bob', - }; - const emailParams: EmailPublicParameters = { - labels: ['test label 1', 'test label2'], - createdAt: '2023-06-14T08:11:22.000Z', - subject: 'test subject', - sender: userAlice, - recipient: userBob, - replyToEmailID: generateUuid(), - }; - - const email = { - body: emailBody, - params: emailParams, - id: generateUuid(), - }; - - it('should encrypt and decrypt email sucessfully', async () => { - const encryptedEmail = await createPwdProtectedEmail(email, sharedSecret, true); - const decryptedEmail = await decryptPwdProtectedEmail(encryptedEmail, sharedSecret); - expect(decryptedEmail).toStrictEqual(email); - expect(encryptedEmail.params.subject).not.toBe(email.params.subject); - }); - - it('should throw an error if encryption fails', async () => { - const bad_email = { - params: emailParams, - } as unknown as Email; - await expect(createPwdProtectedEmail(bad_email, sharedSecret, true)).rejects.toThrowError( - /Failed to password-protect email/, - ); - }); - - it('should throw an error if a different secret used for decryption', async () => { - const encryptedEmail = await createPwdProtectedEmail(email, sharedSecret, true); - const wrongSecret = 'different secret'; - await expect(decryptPwdProtectedEmail(encryptedEmail, wrongSecret)).rejects.toThrowError( - /Failed to decrypt password-protect email/, - ); - }); -}); diff --git a/tests/email-search/cacheLimit.test.ts b/tests/email-search/cacheLimit.test.ts index 751e18e..6cfa7c1 100644 --- a/tests/email-search/cacheLimit.test.ts +++ b/tests/email-search/cacheLimit.test.ts @@ -2,8 +2,8 @@ import { describe, it, expect, vi } from 'vitest'; import { addEmailToCache } from '../../src/email-search'; import { generateTestEmail } from './helper'; -vi.mock('../../src/email-crypto', async () => { - const actual = await vi.importActual('../../src/email-crypto'); +vi.mock('../../src/email-search/utils', async () => { + const actual = await vi.importActual('../../src/email-search/utils'); return { ...actual, emailToBinary: () => new Uint8Array(700 * 1024 * 1024), diff --git a/tests/email-search/helper.ts b/tests/email-search/helper.ts index f856e4d..9716ae0 100644 --- a/tests/email-search/helper.ts +++ b/tests/email-search/helper.ts @@ -1,5 +1,5 @@ import { Email, User } from '../../src/types'; -import { emailToBinary } from '../../src/email-crypto'; +import { emailToBinary } from '../../src/email-search/utils'; import { generateUuid } from '../../src/utils'; const randomString = (length: number = 8): string => @@ -14,18 +14,18 @@ const randomUser = (): User => ({ email: `${randomString(6)}@example.com`, }); -export const generateTestEmail = (): Email => { +export const generateTestEmail = (data?: string): Email => { const sender = randomUser(); const recipient = randomUser(); return { id: generateUuid(), body: { - text: `This is a test email body: ${randomString(20)}`, + text: data ? data : `This is a test email body: ${randomString(20)}`, + subject: `Test Subject ${randomString(6)}`, ...(Math.random() > 0.5 ? { attachments: [`file_${randomString(4)}.txt`] } : {}), }, params: { - subject: `Test Subject ${randomString(6)}`, createdAt: randomDate(), sender, recipient, @@ -50,28 +50,6 @@ export function getEmailSize(email: Email): number { return emailToBinary(email).byteLength; } -const generateEmailWithGivenText = (data: string): Email => { - const sender = randomUser(); - const recipient = randomUser(); - - return { - id: generateUuid(), - body: { - text: data, - ...(Math.random() > 0.5 ? { attachments: [`file_${randomString(4)}.txt`] } : {}), - }, - params: { - subject: `Test Subject ${randomString(6)}`, - createdAt: randomDate(), - sender, - recipient, - recipients: Math.random() > 0.5 ? [randomUser(), randomUser()] : undefined, - replyToEmailID: generateUuid(), - labels: Math.random() > 0.5 ? ['inbox', 'test'] : undefined, - }, - }; -}; - export const getSearchTestEmails = (content: string[]): Email[] => { - return content.map((text) => generateEmailWithGivenText(text)); + return content.map((text) => generateTestEmail(text)); };