From d9b9c918cb7147f195dc4d35196151bdd9a4ce92 Mon Sep 17 00:00:00 2001 From: Tom Date: Sat, 7 Jan 2023 17:01:02 +0800 Subject: [PATCH 01/14] issue 4870 wip --- .../encrypted-mail-msg-formatter.ts | 60 ++++++++++--------- extension/js/common/api/account-server.ts | 4 +- 2 files changed, 34 insertions(+), 30 deletions(-) diff --git a/extension/chrome/elements/compose-modules/formatters/encrypted-mail-msg-formatter.ts b/extension/chrome/elements/compose-modules/formatters/encrypted-mail-msg-formatter.ts index ff506a15b08..aa7c78cec5a 100644 --- a/extension/chrome/elements/compose-modules/formatters/encrypted-mail-msg-formatter.ts +++ b/extension/chrome/elements/compose-modules/formatters/encrypted-mail-msg-formatter.ts @@ -21,7 +21,7 @@ import { Xss } from '../../../../js/common/platform/xss.js'; import { AcctStore } from '../../../../js/common/platform/store/acct-store.js'; import { SmimeKey } from '../../../../js/common/core/crypto/smime/smime-key.js'; import { PgpHash } from '../../../../js/common/core/crypto/pgp/pgp-hash.js'; -import { UploadedMessageData } from '../../../../js/common/api/account-server.js'; +import { UploadedMessageResponse } from '../../../../js/common/api/account-server.js'; import { ParsedKeyInfo } from '../../../../js/common/core/crypto/key-store-util.js'; import { MultipleMessages } from './general-mail-formatter.js'; import { Api, RecipientType } from '../../../../js/common/api/shared/api.js'; @@ -95,23 +95,26 @@ export class EncryptedMsgMailFormatter extends BaseMailFormatter { private formatSendablePwdMsgs = async (newMsg: NewMsgData, pubkeys: PubkeyResult[], signingKey?: ParsedKeyInfo) => { // password-protected message, temporarily uploaded (already encrypted) to: // - flowcrypt.com/api (consumers and customers without on-prem setup), or - // - FlowCrypt Enterprise Server (enterprise customers with on-prem setup) + // - FlowCrypt External Service at fes.example.com (enterprise customers with on-prem setup) // It will be served to recipient through web - const uploadedMessageData = await this.prepareAndUploadPwdEncryptedMsg(newMsg); // encrypted for pwd only, pubkeys ignored - // pwdRecipients that have their personal link - const individualPwdRecipients = Object.keys(uploadedMessageData.emailToExternalIdAndUrl ?? {}).filter(email => !pubkeys.some(p => p.email === email)); - const legacyPwdRecipients: { [type in RecipientType]?: EmailParts[] } = {}; + const uploadedMessageResponse = await this.prepareEncryptAndUploadPwdEncryptedMsg(newMsg); // encrypted for pwd only, pubkeys ignored newMsg.pwd = undefined; - const encryptedAttachments = await this.view.attachmentsModule.attachment.collectEncryptAttachments(pubkeys); + const pubkeyEncryptedAttachments = await this.view.attachmentsModule.attachment.collectEncryptAttachments(pubkeys); const pubkeyRecipients: { [type in RecipientType]?: EmailParts[] } = {}; + const pwdRecipients: { [type in RecipientType]?: EmailParts[] } = {}; for (const [sendingType, value] of Object.entries(newMsg.recipients)) { if (Api.isRecipientHeaderNameType(sendingType)) { pubkeyRecipients[sendingType] = value?.filter(emailPart => pubkeys.some(p => p.email === emailPart.email)); - legacyPwdRecipients[sendingType] = value?.filter( - emailPart => !pubkeys.some(p => p.email === emailPart.email) && !individualPwdRecipients.includes(emailPart.email) - ); + pwdRecipients[sendingType] = value?.filter(emailPart => !pubkeys.some(p => p.email === emailPart.email)); } } + // We used to support sending individual messages to each of the password recipients, each with unique link + // as per https://github.com/FlowCrypt/flowcrypt-browser/issues/4348. We later reverted that behavior in + // https://github.com/FlowCrypt/flowcrypt-browser/issues/4870. Therefore currently it's a single message + // again even though the code could support multiple messages. If by 2024 there is still support for multiple + // messages that is unused, then this can be refactored back to a single message + // (`SendableMsg[]` to `SendableMsg` and so on, including error handling which is much simpler when there is + // just one message to send) const msgs: SendableMsg[] = []; // pubkey recipients get one combined message. If there are not pubkey recpients, only password - protected messages will be sent if (pubkeyRecipients.to?.length || pubkeyRecipients.cc?.length || pubkeyRecipients.bcc?.length) { @@ -132,30 +135,30 @@ export class EncryptedMsgMailFormatter extends BaseMailFormatter { }; msgs.push(await this.sendableNonPwdMsg(pubkeyMsgData, pubkeys, signingKey?.key)); } - // adding individual messages for each recipient that doesn't have a pubkey - for (const recipientEmail of individualPwdRecipients) { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const { url, externalId } = uploadedMessageData.emailToExternalIdAndUrl![recipientEmail]; - const foundParsedRecipient = (newMsg.recipients.to ?? []) - .concat(newMsg.recipients.cc ?? []) - .concat(newMsg.recipients.bcc ?? []) - .find(r => r.email.toLowerCase() === recipientEmail.toLowerCase()); - // todo: since a message is allowed to have only `cc` or `bcc` without `to`, should we preserve the original placement(s) of the recipient? - const individualMsgData = { ...newMsg, recipients: { to: [foundParsedRecipient ?? { email: recipientEmail }] } }; - msgs.push(await this.sendablePwdMsg(individualMsgData, pubkeys, { msgUrl: url, externalId }, signingKey?.key)); - } - if (legacyPwdRecipients.to?.length || legacyPwdRecipients.cc?.length || legacyPwdRecipients.bcc?.length) { - const legacyPwdMsgData = { ...newMsg, recipients: legacyPwdRecipients }; - msgs.push(await this.sendablePwdMsg(legacyPwdMsgData, pubkeys, { msgUrl: uploadedMessageData.url }, signingKey?.key)); + // // adding individual messages for each recipient that doesn't have a pubkey + // for (const recipientEmail of individualLinkPwdRecipients) { + // // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + // const { url, externalId } = uploadedMessageResponse.emailToExternalIdAndUrl![recipientEmail]; + // const foundParsedRecipient = (newMsg.recipients.to ?? []) + // .concat(newMsg.recipients.cc ?? []) + // .concat(newMsg.recipients.bcc ?? []) + // .find(r => r.email.toLowerCase() === recipientEmail.toLowerCase()); + // // todo: since a message is allowed to have only `cc` or `bcc` without `to`, should we preserve the original placement(s) of the recipient? + // const individualMsgData = { ...newMsg, recipients: { to: [foundParsedRecipient ?? { email: recipientEmail }] } }; + // msgs.push(await this.sendablePwdMsg(individualMsgData, pubkeys, { msgUrl: url, externalId }, signingKey?.key)); + // } + if (pwdRecipients.to?.length || pwdRecipients.cc?.length || pwdRecipients.bcc?.length) { + const legacyPwdMsgData = { ...newMsg, recipients: pwdRecipients }; + msgs.push(await this.sendablePwdMsg(legacyPwdMsgData, pubkeys, { msgUrl: uploadedMessageResponse.url }, signingKey?.key)); } return { senderKi: signingKey?.keyInfo, msgs, - renderSentMessage: { recipients: newMsg.recipients, attachments: encryptedAttachments }, + renderSentMessage: { recipients: newMsg.recipients, attachments: pubkeyEncryptedAttachments }, }; }; - private prepareAndUploadPwdEncryptedMsg = async (newMsg: NewMsgData): Promise => { + private prepareEncryptAndUploadPwdEncryptedMsg = async (newMsg: NewMsgData): Promise => { // PGP/MIME + included attachments (encrypted for password only) if (!newMsg.pwd) { throw new Error('password unexpectedly missing'); @@ -198,7 +201,8 @@ export class EncryptedMsgMailFormatter extends BaseMailFormatter { replyToken, newMsg.from.email, // todo: Str.formatEmailWithOptionalName? newMsg.recipients, - p => this.view.sendBtnModule.renderUploadProgress(p, 'FIRST-HALF') // still need to upload to Gmail later, this request represents first half of progress + // still need to upload to Gmail later, this request represents first half of progress + p => this.view.sendBtnModule.renderUploadProgress(p, 'FIRST-HALF') ); }; diff --git a/extension/js/common/api/account-server.ts b/extension/js/common/api/account-server.ts index c575fe91e08..666942859bf 100644 --- a/extension/js/common/api/account-server.ts +++ b/extension/js/common/api/account-server.ts @@ -11,7 +11,7 @@ import { ParsedRecipients } from './email-provider/email-provider-api.js'; import { BackendAuthErr } from './shared/api-error.js'; import { Api, ProgressCb } from './shared/api.js'; -export type UploadedMessageData = { +export type UploadedMessageResponse = { url: string; // both FES and FlowCryptComApi externalId?: string; // legacy FES emailToExternalIdAndUrl?: { [email: string]: { url: string; externalId: string } }; // FES only @@ -59,7 +59,7 @@ export class AccountServer extends Api { from: string, recipients: ParsedRecipients, progressCb: ProgressCb - ): Promise => { + ): Promise => { if (await this.isFesUsed()) { const fes = new EnterpriseServer(this.acctEmail); // Recipients are used to later cross-check replies from the web From cf339c08e5ccc737ad780371fcd70ccde7db171b Mon Sep 17 00:00:00 2001 From: Tom J Date: Sat, 7 Jan 2023 11:29:08 +0000 Subject: [PATCH 02/14] wip, functionality done but untested, tests will need fixing --- .../compose-modules/compose-draft-module.ts | 2 +- .../encrypted-mail-msg-formatter.ts | 74 +++++-------------- 2 files changed, 21 insertions(+), 55 deletions(-) diff --git a/extension/chrome/elements/compose-modules/compose-draft-module.ts b/extension/chrome/elements/compose-modules/compose-draft-module.ts index 09cc59769db..68c38132da9 100644 --- a/extension/chrome/elements/compose-modules/compose-draft-module.ts +++ b/extension/chrome/elements/compose-modules/compose-draft-module.ts @@ -126,7 +126,7 @@ export class ComposeDraftModule extends ViewModule { const msgData = await this.view.inputModule.extractAll(); const { pubkeys } = await this.view.storageModule.collectSingleFamilyKeys([], msgData.from.email, true); msgData.pwd = undefined; // not needed for drafts - const sendable = await new EncryptedMsgMailFormatter(this.view, true).sendableNonPwdMsg(msgData, pubkeys); + const sendable = await new EncryptedMsgMailFormatter(this.view, true).encryptSendableNonPwdMsg(msgData, pubkeys); if (this.view.replyParams?.inReplyTo) { sendable.headers.References = this.view.replyParams.inReplyTo; sendable.headers['In-Reply-To'] = this.view.replyParams.inReplyTo; diff --git a/extension/chrome/elements/compose-modules/formatters/encrypted-mail-msg-formatter.ts b/extension/chrome/elements/compose-modules/formatters/encrypted-mail-msg-formatter.ts index aa7c78cec5a..938980cccae 100644 --- a/extension/chrome/elements/compose-modules/formatters/encrypted-mail-msg-formatter.ts +++ b/extension/chrome/elements/compose-modules/formatters/encrypted-mail-msg-formatter.ts @@ -6,7 +6,7 @@ import { BaseMailFormatter } from './base-mail-formatter.js'; import { ComposerResetBtnTrigger } from '../compose-err-module.js'; import { Mime, SendableMsgBody } from '../../../../js/common/core/mime.js'; import { getUniqueRecipientEmails, NewMsgData } from '../compose-types.js'; -import { EmailParts, Str, Value } from '../../../../js/common/core/common.js'; +import { Str, Value } from '../../../../js/common/core/common.js'; import { ApiErr } from '../../../../js/common/api/shared/api-error.js'; import { Attachment } from '../../../../js/common/core/attachment.js'; import { Buf } from '../../../../js/common/core/buf.js'; @@ -24,7 +24,6 @@ import { PgpHash } from '../../../../js/common/core/crypto/pgp/pgp-hash.js'; import { UploadedMessageResponse } from '../../../../js/common/api/account-server.js'; import { ParsedKeyInfo } from '../../../../js/common/core/crypto/key-store-util.js'; import { MultipleMessages } from './general-mail-formatter.js'; -import { Api, RecipientType } from '../../../../js/common/api/shared/api.js'; /** * this type must be kept in sync with FES UI code, changes must be backwards compatible @@ -44,9 +43,9 @@ type ReplyInfoRaw = { export class EncryptedMsgMailFormatter extends BaseMailFormatter { public sendableMsgs = async (newMsg: NewMsgData, pubkeys: PubkeyResult[], signingKey?: ParsedKeyInfo): Promise => { if (newMsg.pwd && !this.isDraft) { - return await this.formatSendablePwdMsgs(newMsg, pubkeys, signingKey); + return await this.formatSendablePwdMsg(newMsg, pubkeys, signingKey); } else { - const msg = await this.sendableNonPwdMsg(newMsg, pubkeys, signingKey?.key); + const msg = await this.encryptSendableNonPwdMsg(newMsg, pubkeys, signingKey?.key); return { senderKi: signingKey?.keyInfo, msgs: [msg], @@ -58,7 +57,7 @@ export class EncryptedMsgMailFormatter extends BaseMailFormatter { } }; - public sendableNonPwdMsg = async (newMsg: NewMsgData, pubkeys: PubkeyResult[], signingPrv?: Key): Promise => { + public encryptSendableNonPwdMsg = async (newMsg: NewMsgData, pubkeys: PubkeyResult[], signingPrv?: Key): Promise => { if (!this.isDraft) { // S/MIME drafts are currently formatted with inline armored data const x509certs = pubkeys.map(entry => entry.pubkey).filter(pub => pub.family === 'x509'); @@ -92,22 +91,13 @@ export class EncryptedMsgMailFormatter extends BaseMailFormatter { }); }; - private formatSendablePwdMsgs = async (newMsg: NewMsgData, pubkeys: PubkeyResult[], signingKey?: ParsedKeyInfo) => { + private formatSendablePwdMsg = async (newMsg: NewMsgData, pubkeys: PubkeyResult[], signingKey?: ParsedKeyInfo) => { // password-protected message, temporarily uploaded (already encrypted) to: // - flowcrypt.com/api (consumers and customers without on-prem setup), or // - FlowCrypt External Service at fes.example.com (enterprise customers with on-prem setup) // It will be served to recipient through web const uploadedMessageResponse = await this.prepareEncryptAndUploadPwdEncryptedMsg(newMsg); // encrypted for pwd only, pubkeys ignored newMsg.pwd = undefined; - const pubkeyEncryptedAttachments = await this.view.attachmentsModule.attachment.collectEncryptAttachments(pubkeys); - const pubkeyRecipients: { [type in RecipientType]?: EmailParts[] } = {}; - const pwdRecipients: { [type in RecipientType]?: EmailParts[] } = {}; - for (const [sendingType, value] of Object.entries(newMsg.recipients)) { - if (Api.isRecipientHeaderNameType(sendingType)) { - pubkeyRecipients[sendingType] = value?.filter(emailPart => pubkeys.some(p => p.email === emailPart.email)); - pwdRecipients[sendingType] = value?.filter(emailPart => !pubkeys.some(p => p.email === emailPart.email)); - } - } // We used to support sending individual messages to each of the password recipients, each with unique link // as per https://github.com/FlowCrypt/flowcrypt-browser/issues/4348. We later reverted that behavior in // https://github.com/FlowCrypt/flowcrypt-browser/issues/4870. Therefore currently it's a single message @@ -115,45 +105,20 @@ export class EncryptedMsgMailFormatter extends BaseMailFormatter { // messages that is unused, then this can be refactored back to a single message // (`SendableMsg[]` to `SendableMsg` and so on, including error handling which is much simpler when there is // just one message to send) - const msgs: SendableMsg[] = []; - // pubkey recipients get one combined message. If there are not pubkey recpients, only password - protected messages will be sent - if (pubkeyRecipients.to?.length || pubkeyRecipients.cc?.length || pubkeyRecipients.bcc?.length) { - const uniquePubkeyRecipientToAndCCs = Value.arr.unique( - (pubkeyRecipients.to || []).concat(pubkeyRecipients.cc || []).map(recipient => recipient.email.toLowerCase()) - ); - // pubkey recipients should be able to reply to "to" and "cc" pwd recipients - const replyToForMessageSentToPubkeyRecipients = (newMsg.recipients.to ?? []) - .concat(newMsg.recipients.cc ?? []) - .filter(recipient => !uniquePubkeyRecipientToAndCCs.includes(recipient.email.toLowerCase())); - const pubkeyMsgData = { - ...newMsg, - recipients: pubkeyRecipients, - // brackets are required for test emails like '@test:8001' - replyTo: replyToForMessageSentToPubkeyRecipients.length - ? `${Str.formatEmailList([newMsg.from, ...replyToForMessageSentToPubkeyRecipients], true)}` - : undefined, - }; - msgs.push(await this.sendableNonPwdMsg(pubkeyMsgData, pubkeys, signingKey?.key)); - } - // // adding individual messages for each recipient that doesn't have a pubkey - // for (const recipientEmail of individualLinkPwdRecipients) { - // // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - // const { url, externalId } = uploadedMessageResponse.emailToExternalIdAndUrl![recipientEmail]; - // const foundParsedRecipient = (newMsg.recipients.to ?? []) - // .concat(newMsg.recipients.cc ?? []) - // .concat(newMsg.recipients.bcc ?? []) - // .find(r => r.email.toLowerCase() === recipientEmail.toLowerCase()); - // // todo: since a message is allowed to have only `cc` or `bcc` without `to`, should we preserve the original placement(s) of the recipient? - // const individualMsgData = { ...newMsg, recipients: { to: [foundParsedRecipient ?? { email: recipientEmail }] } }; - // msgs.push(await this.sendablePwdMsg(individualMsgData, pubkeys, { msgUrl: url, externalId }, signingKey?.key)); - // } - if (pwdRecipients.to?.length || pwdRecipients.cc?.length || pwdRecipients.bcc?.length) { - const legacyPwdMsgData = { ...newMsg, recipients: pwdRecipients }; - msgs.push(await this.sendablePwdMsg(legacyPwdMsgData, pubkeys, { msgUrl: uploadedMessageResponse.url }, signingKey?.key)); - } + const msg = await this.sendableCombinedPubkeyMsgWithoutAttachedFilesWithLinkToUploadedPwdMsg( + newMsg, + pubkeys, + { msgUrl: uploadedMessageResponse.url }, + signingKey?.key + ); + // the above message has pgp/mime encrypted content that was attached as a set of pgp/mime attachments, + // but doesn't have the actual attachments the user has attached (they were uploaded to FES/backend but weren't + // attached to the message itself). We are adding the attachments here. + const pubkeyEncryptedAttachments = await this.view.attachmentsModule.attachment.collectEncryptAttachments(pubkeys); + msg.attachments = msg.attachments.concat(pubkeyEncryptedAttachments); return { senderKi: signingKey?.keyInfo, - msgs, + msgs: [msg], renderSentMessage: { recipients: newMsg.recipients, attachments: pubkeyEncryptedAttachments }, }; }; @@ -195,7 +160,8 @@ export class EncryptedMsgMailFormatter extends BaseMailFormatter { { Subject: newMsg.subject }, // eslint-disable-line @typescript-eslint/naming-convention await this.view.attachmentsModule.attachment.collectAttachments() ); - const { data: pwdEncryptedWithAttachments } = await this.encryptDataArmor(Buf.fromUtfStr(pgpMimeWithAttachments), newMsg.pwd, []); // encrypted only for pwd, not signed + // encrypted only for pwd, not signed + const { data: pwdEncryptedWithAttachments } = await this.encryptDataArmor(Buf.fromUtfStr(pgpMimeWithAttachments), newMsg.pwd, []); return await this.view.acctServer.messageUpload( pwdEncryptedWithAttachments, replyToken, @@ -206,7 +172,7 @@ export class EncryptedMsgMailFormatter extends BaseMailFormatter { ); }; - private sendablePwdMsg = async ( + private sendableCombinedPubkeyMsgWithoutAttachedFilesWithLinkToUploadedPwdMsg = async ( newMsg: NewMsgData, pubs: PubkeyResult[], { msgUrl, externalId }: { msgUrl: string; externalId?: string }, From 59068d0737d3e0b3ef07d42058afd6003d484f09 Mon Sep 17 00:00:00 2001 From: Tom J Date: Sat, 7 Jan 2023 17:08:52 +0000 Subject: [PATCH 03/14] wip --- .../encrypted-mail-msg-formatter.ts | 5 ++- .../strategies/send-message-strategy.ts | 41 +++++-------------- test/source/tests/compose.ts | 2 +- 3 files changed, 16 insertions(+), 32 deletions(-) diff --git a/extension/chrome/elements/compose-modules/formatters/encrypted-mail-msg-formatter.ts b/extension/chrome/elements/compose-modules/formatters/encrypted-mail-msg-formatter.ts index 938980cccae..c216580d56c 100644 --- a/extension/chrome/elements/compose-modules/formatters/encrypted-mail-msg-formatter.ts +++ b/extension/chrome/elements/compose-modules/formatters/encrypted-mail-msg-formatter.ts @@ -119,7 +119,10 @@ export class EncryptedMsgMailFormatter extends BaseMailFormatter { return { senderKi: signingKey?.keyInfo, msgs: [msg], - renderSentMessage: { recipients: newMsg.recipients, attachments: pubkeyEncryptedAttachments }, + renderSentMessage: { + recipients: newMsg.recipients, + attachments: pubkeyEncryptedAttachments + }, }; }; diff --git a/test/source/mock/google/strategies/send-message-strategy.ts b/test/source/mock/google/strategies/send-message-strategy.ts index 272dcaf64c8..99b98ed4cb6 100644 --- a/test/source/mock/google/strategies/send-message-strategy.ts +++ b/test/source/mock/google/strategies/send-message-strategy.ts @@ -149,36 +149,17 @@ class PwdEncryptedMessageWithFesReplyRenderingTestStrategy implements ITestMsgSt const mimeMsg = parseResult.mimeMsg; const expectedSenderEmail = 'user2@standardsubdomainfes.localhost:8001'; expect(mimeMsg.from!.text).to.equal(`First Last <${expectedSenderEmail}>`); - if (mimeMsg.text?.includes('http://fes.standardsubdomainfes.localhost:8001/message/FES-MOCK-MESSAGE-FOR-SENDER@DOMAIN.COM-ID')) { - expect(mimeMsg.text!).to.include(`${expectedSenderEmail} has sent you a password-encrypted email`); - expect(mimeMsg.text!).to.include('Follow this link to open it'); - expect((mimeMsg.to as AddressObject).text).to.equal('sender@domain.com'); - expect(mimeMsg.cc).to.be.an.undefined; - expect(mimeMsg.bcc).to.be.an.undefined; - expect(mimeMsg.headers.get('reply-to')).to.be.an.undefined; - } else if (mimeMsg.text?.includes('http://fes.standardsubdomainfes.localhost:8001/message/FES-MOCK-MESSAGE-FOR-TO@EXAMPLE.COM-ID')) { - expect(mimeMsg.text!).to.include(`${expectedSenderEmail} has sent you a password-encrypted email`); - expect(mimeMsg.text!).to.include('Follow this link to open it'); - expect((mimeMsg.to as AddressObject).text).to.equal('to@example.com'); - expect(mimeMsg.cc).to.be.an.undefined; - expect(mimeMsg.bcc).to.be.an.undefined; - expect(mimeMsg.headers.get('reply-to')).to.be.an.undefined; - } else { - // this is a message to pubkey recipients - expect(mimeMsg.text!).to.not.include('has sent you a password-encrypted email'); - expect(mimeMsg.text!).to.not.include('Follow this link to open it'); - const kisWithPp = await Config.getKeyInfo(['flowcrypt.test.key.used.pgp']); - const encryptedData = Buf.fromUtfStr(mimeMsg.text!); - const decrypted = await MsgUtil.decryptMessage({ kisWithPp, encryptedData, verificationPubs: [] }); - expect(decrypted.success).to.be.true; - expect(decrypted.content!.toUtfStr()).to.include('> some dummy text'); - expect((mimeMsg.to as AddressObject).text).to.equal('flowcrypt.compatibility@gmail.com, mock.only.pubkey@flowcrypt.com'); - expect(mimeMsg.cc).to.be.an.undefined; - expect(mimeMsg.bcc).to.be.an.undefined; - expect((mimeMsg.headers.get('reply-to') as AddressObject).text).to.equal( - 'First Last , sender@domain.com, to@example.com' - ); - } + expect(mimeMsg.text).to.include(`${expectedSenderEmail} has sent you a password-encrypted email`); + expect(mimeMsg.text).to.include('Follow this link to open it'); + expect((mimeMsg.to as AddressObject).text).to.equal('sender@domain.com, flowcrypt.compatibility@gmail.com, to@example.com, mock.only.pubkey@flowcrypt.com'); + expect(mimeMsg.cc).to.be.an.undefined; + expect(mimeMsg.bcc).to.be.an.undefined; + expect(mimeMsg.headers.get('reply-to')).to.be.an.undefined; + const kisWithPp = await Config.getKeyInfo(['flowcrypt.test.key.used.pgp']); + const encryptedData = mimeMsg.attachments.find(a => a.filename === 'encrypted.asc')!.content; + const decrypted = await MsgUtil.decryptMessage({ kisWithPp, encryptedData, verificationPubs: [] }); + expect(decrypted.success).to.be.true; + expect(decrypted.content!.toUtfStr()).to.include('> some dummy text'); await new SaveMessageInStorageStrategy().test(parseResult, id); }; } diff --git a/test/source/tests/compose.ts b/test/source/tests/compose.ts index 7c33a3ea245..87c591937ed 100644 --- a/test/source/tests/compose.ts +++ b/test/source/tests/compose.ts @@ -2487,7 +2487,7 @@ export const defineComposeTests = (testVariant: TestVariant, testWithBrowser: Te 'to: sender@domain.com, flowcrypt.compatibility@gmail.com, to@example.com, mock.only.pubkey@flowcrypt.com' ); const sentMsgs = (await GoogleData.withInitializedData(acct)).getMessagesByThread('1803be2e506153d2'); - expect(sentMsgs.length).to.equal(4); // 1 original + 3 newly sent + expect(sentMsgs.length).to.equal(1); // 1 combined message for all const attachmentFrames = (composePage.target as Page).frames(); expect(attachmentFrames.length).to.equal(3); // 1 pgp block + 2 attachments expect( From b3d8fd5dbc983bd3c272750d774a8956775f53f6 Mon Sep 17 00:00:00 2001 From: Tom J Date: Mon, 9 Jan 2023 12:51:25 +0000 Subject: [PATCH 04/14] fix test --- test/source/tests/compose.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/source/tests/compose.ts b/test/source/tests/compose.ts index 87c591937ed..c2600fab5ac 100644 --- a/test/source/tests/compose.ts +++ b/test/source/tests/compose.ts @@ -2487,7 +2487,7 @@ export const defineComposeTests = (testVariant: TestVariant, testWithBrowser: Te 'to: sender@domain.com, flowcrypt.compatibility@gmail.com, to@example.com, mock.only.pubkey@flowcrypt.com' ); const sentMsgs = (await GoogleData.withInitializedData(acct)).getMessagesByThread('1803be2e506153d2'); - expect(sentMsgs.length).to.equal(1); // 1 combined message for all + expect(sentMsgs.length).to.equal(2); // 1 original message to reply to, 1 new sent const attachmentFrames = (composePage.target as Page).frames(); expect(attachmentFrames.length).to.equal(3); // 1 pgp block + 2 attachments expect( From 3d9a82c4106a6057a7b58684071c20775b550837 Mon Sep 17 00:00:00 2001 From: Tom J Date: Mon, 9 Jan 2023 17:55:28 +0000 Subject: [PATCH 05/14] fix a test --- .../strategies/send-message-strategy.ts | 37 ++++++++----------- test/source/tests/compose.ts | 2 +- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/test/source/mock/google/strategies/send-message-strategy.ts b/test/source/mock/google/strategies/send-message-strategy.ts index 99b98ed4cb6..5c962453f61 100644 --- a/test/source/mock/google/strategies/send-message-strategy.ts +++ b/test/source/mock/google/strategies/send-message-strategy.ts @@ -93,29 +93,24 @@ class PwdEncryptedMessageWithFesIdTokenTestStrategy implements ITestMsgStrategy class PwdEncryptedMessageWithFesPubkeyRecipientInBccTestStrategy implements ITestMsgStrategy { public test = async (parseResult: ParseMsgResult, id: string) => { const mimeMsg = parseResult.mimeMsg; + console.log('--- MIME MSG ---'); + console.log(mimeMsg); + console.log('--- END MIME MSG ---'); const expectedSenderEmail = 'user3@standardsubdomainfes.localhost:8001'; expect(mimeMsg.from!.text).to.equal(`First Last <${expectedSenderEmail}>`); - if (mimeMsg.text?.includes('http://fes.standardsubdomainfes.localhost:8001/message/FES-MOCK-MESSAGE-FOR-TO@EXAMPLE.COM-ID')) { - expect(mimeMsg.text!).to.include(`${expectedSenderEmail} has sent you a password-encrypted email`); - expect(mimeMsg.text!).to.include('Follow this link to open it'); - expect((mimeMsg.to as AddressObject).text).to.equal('to@example.com'); - expect(mimeMsg.cc).to.be.an.undefined; - expect(mimeMsg.bcc).to.be.an.undefined; - expect(mimeMsg.headers.get('reply-to')).to.be.an.undefined; - } else { - // this is a message to pubkey recipients - expect(mimeMsg.text!).to.not.include('has sent you a password-encrypted email'); - expect(mimeMsg.text!).to.not.include('Follow this link to open it'); - const kisWithPp = await Config.getKeyInfo(['flowcrypt.test.key.used.pgp']); - const encryptedData = Buf.fromUtfStr(mimeMsg.text!); - const decrypted = await MsgUtil.decryptMessage({ kisWithPp, encryptedData, verificationPubs: [] }); - expect(decrypted.success).to.be.true; - expect(decrypted.content!.toUtfStr()).to.equal('PWD encrypted message with FES - pubkey recipient in bcc'); - expect((mimeMsg.bcc as AddressObject).text).to.equal('flowcrypt.compatibility@gmail.com'); - expect(mimeMsg.cc).to.be.an.undefined; - expect(mimeMsg.to).to.be.an.undefined; - expect((mimeMsg.headers.get('reply-to') as AddressObject).text).to.equal('First Last , to@example.com'); - } + // originally fes + expect(mimeMsg.text!).to.include(`${expectedSenderEmail} has sent you a password-encrypted email`); + expect(mimeMsg.text!).to.include('Follow this link to open it'); + expect((mimeMsg.to as AddressObject).text).to.equal('to@example.com'); + expect(mimeMsg.cc).to.be.an.undefined; + expect((mimeMsg.bcc as AddressObject).text).to.equal('flowcrypt.compatibility@gmail.com'); + expect(mimeMsg.headers.get('reply-to')).to.be.an.undefined; + const kisWithPp = await Config.getKeyInfo(['flowcrypt.test.key.used.pgp']); + const encryptedData = mimeMsg.attachments.find(a => a.filename === 'encrypted.asc')!.content; + const decrypted = await MsgUtil.decryptMessage({ kisWithPp, encryptedData, verificationPubs: [] }); + expect(decrypted.success).to.be.true; + expect(decrypted.content!.toUtfStr()).to.contain('PWD encrypted message with FES - pubkey recipient in bcc'); + expect((mimeMsg.headers.get('reply-to') as AddressObject).text).to.be.empty; await new SaveMessageInStorageStrategy().test(parseResult, id); }; } diff --git a/test/source/tests/compose.ts b/test/source/tests/compose.ts index c2600fab5ac..d09e9f52477 100644 --- a/test/source/tests/compose.ts +++ b/test/source/tests/compose.ts @@ -2533,7 +2533,7 @@ export const defineComposeTests = (testVariant: TestVariant, testWithBrowser: Te await composePage.waitAndClick('@action-send', { delay: 1 }); await ComposePageRecipe.closed(composePage); const sentMsgs = (await GoogleData.withInitializedData(acct)).searchMessagesBySubject(subject); - expect(sentMsgs.length).to.equal(2); + expect(sentMsgs.length).to.equal(1); // this test is using PwdEncryptedMessageWithFesPubkeyRecipientInBccTestStrategy to check sent result based on subject "PWD encrypted message with FES - pubkey recipient in bcc" // also see '/api/v1/message' in fes-endpoints.ts mock }) From 47ec85ef8d3c7dba67fabea7ceeaeea3190b8a81 Mon Sep 17 00:00:00 2001 From: Tom J Date: Mon, 9 Jan 2023 18:11:27 +0000 Subject: [PATCH 06/14] improve test --- .../strategies/send-message-strategy.ts | 23 ++++---- test/source/tests/flaky.ts | 53 +++---------------- 2 files changed, 18 insertions(+), 58 deletions(-) diff --git a/test/source/mock/google/strategies/send-message-strategy.ts b/test/source/mock/google/strategies/send-message-strategy.ts index 5c962453f61..ca3d175684a 100644 --- a/test/source/mock/google/strategies/send-message-strategy.ts +++ b/test/source/mock/google/strategies/send-message-strategy.ts @@ -116,25 +116,26 @@ class PwdEncryptedMessageWithFesPubkeyRecipientInBccTestStrategy implements ITes } class PwdEncryptedMessageWithFesReplyBadRequestTestStrategy implements ITestMsgStrategy { - public test = async (parseResult: ParseMsgResult, id: string) => { + public test = async (parseResult: ParseMsgResult) => { const mimeMsg = parseResult.mimeMsg; const expectedSenderEmail = 'user4@standardsubdomainfes.localhost:8001'; expect(mimeMsg.from!.text).to.equal(`First Last <${expectedSenderEmail}>`); const to = parsedMailAddressObjectAsArray(mimeMsg.to) .concat(parsedMailAddressObjectAsArray(mimeMsg.cc)) .concat(parsedMailAddressObjectAsArray(mimeMsg.bcc)); - expect(to.length).to.equal(1); - const recipientEmail = to[0].text; - if (recipientEmail === 'to@example.com') { - // success - await new SaveMessageInStorageStrategy().test(parseResult, id); - return; - } else if (recipientEmail === 'invalid@example.com') { + // expect(to.length).to.equal(1); + const recipientEmails = to.map(to => to.text) + // if (recipientEmail === 'to@example.com') { + // // success + // await new SaveMessageInStorageStrategy().test(parseResult, id); + // return; + // } else + if (recipientEmails.includes('invalid@example.com')) { throw new HttpClientErr('Invalid to header', Status.BAD_REQUEST); - } else if (recipientEmail === 'timeout@example.com') { + } else if (recipientEmails.includes('timeout@example.com')) { throw new HttpClientErr('RequestTimeout', Status.BAD_REQUEST); } else { - throw new HttpClientErr(`Vague failure for ${recipientEmail}`, Status.BAD_REQUEST); + throw new HttpClientErr(`Vague failure for ${recipientEmails.join(',')}`, Status.BAD_REQUEST); } }; } @@ -362,7 +363,7 @@ export class TestBySubjectStrategyContext { this.strategy = new PwdEncryptedMessageWithFesReplyRenderingTestStrategy(); } else if (subject.includes('PWD encrypted message with FES - pubkey recipient in bcc')) { this.strategy = new PwdEncryptedMessageWithFesPubkeyRecipientInBccTestStrategy(); - } else if (subject.includes('PWD encrypted message with FES web portal - some sends fail with BadRequest error')) { + } else if (subject.includes('PWD encrypted message with FES web portal - sends fails with BadRequest error')) { this.strategy = new PwdEncryptedMessageWithFesReplyBadRequestTestStrategy(); } else if (subject.includes('PWD encrypted message with FES web portal - a send fails with gateway update error')) { this.strategy = new SaveMessageInStorageStrategy(); diff --git a/test/source/tests/flaky.ts b/test/source/tests/flaky.ts index fb55220b1f3..2b6cd795981 100644 --- a/test/source/tests/flaky.ts +++ b/test/source/tests/flaky.ts @@ -202,7 +202,7 @@ export const defineFlakyTests = (testVariant: TestVariant, testWithBrowser: Test ); ava.default( - 'user4@standardsubdomainfes.localhost:8001 - PWD encrypted message with FES web portal - some sends fail with BadRequest error', + 'user4@standardsubdomainfes.localhost:8001 - PWD encrypted message with FES web portal - sends fails with BadRequest error', testWithBrowser(undefined, async (t, browser) => { const acct = 'user4@standardsubdomainfes.localhost:8001'; // added port to trick extension into calling the mock const settingsPage = await BrowserRecipe.openSettingsLoginApprove(t, browser, acct); @@ -222,22 +222,9 @@ export const defineFlakyTests = (testVariant: TestVariant, testWithBrowser: Test }); await dbPage.close(); const subject = 'PWD encrypted message with FES web portal - some sends fail with BadRequest error - ' + testVariant; - let expectedNumberOfPassedMessages = (await GoogleData.withInitializedData(acct)).searchMessagesBySubject(subject).length; - // 1. vague Gmail error with partial success - let composePage = await ComposePageRecipe.openStandalone(t, browser, 'user4@standardsubdomainfes.localhost:8001'); - await ComposePageRecipe.fillMsg(composePage, { to: 'to@example.com', cc: 'cc@example.com', bcc: 'flowcrypt.compatibility@gmail.com' }, subject); - await composePage.waitAndType('@input-password', 'gO0d-pwd'); - await composePage.waitAndClick('@action-send', { delay: 1 }); - await composePage.waitAndRespondToModal( - 'confirm', - 'cancel', - 'Messages to some recipients were sent successfully, while messages to flowcrypt.compatibility@gmail.com, Mr Cc ' + - 'encountered error(s) from Gmail. Please help us improve FlowCrypt by reporting the error to us.' - ); - await composePage.close(); - expect((await GoogleData.withInitializedData(acct)).searchMessagesBySubject(subject).length).to.equal(++expectedNumberOfPassedMessages); + const expectedNumberOfPassedMessages = (await GoogleData.withInitializedData(acct)).searchMessagesBySubject(subject).length; // 2. vague Gmail error with all failures - composePage = await ComposePageRecipe.openStandalone(t, browser, 'user4@standardsubdomainfes.localhost:8001'); + let composePage = await ComposePageRecipe.openStandalone(t, browser, 'user4@standardsubdomainfes.localhost:8001'); await ComposePageRecipe.fillMsg(composePage, { cc: 'cc@example.com', bcc: 'flowcrypt.compatibility@gmail.com' }, subject); await composePage.waitAndType('@input-password', 'gO0d-pwd'); await composePage.waitAndClick('@action-send', { delay: 1 }); @@ -247,21 +234,7 @@ export const defineFlakyTests = (testVariant: TestVariant, testWithBrowser: Test 'Google returned an error when sending message. ' + 'Please help us improve FlowCrypt by reporting the error to us.' ); await composePage.close(); - expect((await GoogleData.withInitializedData(acct)).searchMessagesBySubject(subject).length).to.equal(expectedNumberOfPassedMessages); // + 0 messages - // 3. "invalid To" Gmail error with partial success - composePage = await ComposePageRecipe.openStandalone(t, browser, 'user4@standardsubdomainfes.localhost:8001'); - await ComposePageRecipe.fillMsg(composePage, { to: 'invalid@example.com', cc: 'to@example.com' }, subject); - await composePage.waitAndType('@input-password', 'gO0d-pwd'); - await composePage.waitAndClick('@action-send', { delay: 1 }); - await composePage.waitAndRespondToModal( - 'error', - 'confirm', - 'Messages to some recipients were sent successfully, while messages to invalid@example.com ' + - 'encountered error(s) from Gmail: Invalid recipients\n\nPlease remove recipients, add them back and re-send the message.' - ); - await composePage.close(); - expect((await GoogleData.withInitializedData(acct)).searchMessagesBySubject(subject).length).to.equal(++expectedNumberOfPassedMessages); - // 4. "invalid To" Gmail error with all failures + // 2. "invalid To" Gmail error composePage = await ComposePageRecipe.openStandalone(t, browser, 'user4@standardsubdomainfes.localhost:8001'); await ComposePageRecipe.fillMsg(composePage, { to: 'invalid@example.com', cc: 'cc@example.com' }, subject); await composePage.waitAndType('@input-password', 'gO0d-pwd'); @@ -272,21 +245,7 @@ export const defineFlakyTests = (testVariant: TestVariant, testWithBrowser: Test 'Error from google: Invalid recipients\n\nPlease remove recipients, add them back and re-send the message.' ); await composePage.close(); - expect((await GoogleData.withInitializedData(acct)).searchMessagesBySubject(subject).length).to.equal(expectedNumberOfPassedMessages); // + 0 messages - // 5. "RequestTimeout" error with partial success - composePage = await ComposePageRecipe.openStandalone(t, browser, 'user4@standardsubdomainfes.localhost:8001'); - await ComposePageRecipe.fillMsg(composePage, { to: 'timeout@example.com', cc: 'to@example.com' }, subject); - await composePage.waitAndType('@input-password', 'gO0d-pwd'); - await composePage.waitAndClick('@action-send', { delay: 1 }); - await composePage.waitAndRespondToModal( - 'error', - 'confirm', - 'Messages to some recipients were sent successfully, while messages to timeout@example.com ' + - 'encountered network errors. Please check your internet connection and try again.' - ); - await composePage.close(); - expect((await GoogleData.withInitializedData(acct)).searchMessagesBySubject(subject).length).to.equal(++expectedNumberOfPassedMessages); - // 6. "RequestTimeout" error with all failures + // 3. "RequestTimeout" error with all failures composePage = await ComposePageRecipe.openStandalone(t, browser, 'user4@standardsubdomainfes.localhost:8001'); await ComposePageRecipe.fillMsg(composePage, { to: 'timeout@example.com', cc: 'cc@example.com' }, subject); await composePage.waitAndType('@input-password', 'gO0d-pwd'); @@ -298,7 +257,7 @@ export const defineFlakyTests = (testVariant: TestVariant, testWithBrowser: Test '(This may also be caused by missing extension permissions).' ); await composePage.close(); - expect((await GoogleData.withInitializedData(acct)).searchMessagesBySubject(subject).length).to.equal(expectedNumberOfPassedMessages); // + 0 messages + expect((await GoogleData.withInitializedData(acct)).searchMessagesBySubject(subject).length).to.equal(expectedNumberOfPassedMessages); // this test is using PwdEncryptedMessageWithFesReplyBadRequestTestStrategy to check sent result based on subject // "PWD encrypted message with FES web portal - some sends fail with BadRequest error" // also see '/api/v1/message' in fes-endpoints.ts mock From 01a7cd08377edd371f1809ad48e2b2c88b260caf Mon Sep 17 00:00:00 2001 From: Tom J Date: Tue, 10 Jan 2023 13:34:04 +0000 Subject: [PATCH 07/14] remove individual urls --- extension/js/common/api/account-server.ts | 1 - .../api/account-servers/enterprise-server.ts | 5 +- test/source/mock/fes/fes-endpoints.ts | 98 ++----------------- .../strategies/send-message-strategy.ts | 2 +- test/source/test.ts | 2 +- test/source/tests/compose.ts | 6 +- 6 files changed, 16 insertions(+), 98 deletions(-) diff --git a/extension/js/common/api/account-server.ts b/extension/js/common/api/account-server.ts index 666942859bf..4b35eafb87e 100644 --- a/extension/js/common/api/account-server.ts +++ b/extension/js/common/api/account-server.ts @@ -14,7 +14,6 @@ import { Api, ProgressCb } from './shared/api.js'; export type UploadedMessageResponse = { url: string; // both FES and FlowCryptComApi externalId?: string; // legacy FES - emailToExternalIdAndUrl?: { [email: string]: { url: string; externalId: string } }; // FES only }; /** diff --git a/extension/js/common/api/account-servers/enterprise-server.ts b/extension/js/common/api/account-servers/enterprise-server.ts index 5a28ecf1260..d27a8f8f876 100644 --- a/extension/js/common/api/account-servers/enterprise-server.ts +++ b/extension/js/common/api/account-servers/enterprise-server.ts @@ -20,9 +20,8 @@ type EventTag = 'compose' | 'decrypt' | 'setup' | 'settings' | 'import-pub' | 'i export namespace FesRes { export type ReplyToken = { replyToken: string }; export type MessageUpload = { - url: string; // LEGACY - externalId: string; // LEGACY - emailToExternalIdAndUrl?: { [email: string]: { url: string; externalId: string } }; + url: string; + externalId: string; }; export type ServiceInfo = { vendor: string; service: string; orgId: string; version: string; apiVersion: string }; export type ClientConfiguration = { clientConfiguration: ClientConfigurationJson }; diff --git a/test/source/mock/fes/fes-endpoints.ts b/test/source/mock/fes/fes-endpoints.ts index 6063725bc58..df1c5eba7fe 100644 --- a/test/source/mock/fes/fes-endpoints.ts +++ b/test/source/mock/fes/fes-endpoints.ts @@ -34,21 +34,11 @@ const processMessageFromUser = async (body: string) => { // small.txt expect(decryptedMimeMsg).to.contain('Content-Type: text/plain; name=small.txt\r\n' + 'Content-Disposition: attachment; filename=small.txt'); expect(decryptedMimeMsg).to.contain('Content-Transfer-Encoding: base64\r\n\r\n' + 'c21hbGwgdGV4dCBmaWxlCm5vdCBtdWNoIGhlcmUKdGhpcyB3b3JrZWQK'); - const response = { + return { // this url is required for pubkey encrypted message url: `http://${standardFesUrl}/message/FES-MOCK-MESSAGE-ID`, externalId: 'FES-MOCK-EXTERNAL-ID', - emailToExternalIdAndUrl: {} as { [email: string]: { url: string; externalId: string } }, }; - response.emailToExternalIdAndUrl['to@example.com'] = { - url: `http://${standardFesUrl}/message/FES-MOCK-MESSAGE-FOR-TO@EXAMPLE.COM-ID`, - externalId: 'FES-MOCK-EXTERNAL-FOR-TO@EXAMPLE.COM-ID', - }; - response.emailToExternalIdAndUrl['bcc@example.com'] = { - url: `http://${standardFesUrl}/message/FES-MOCK-MESSAGE-FOR-BCC@EXAMPLE.COM-ID`, - externalId: 'FES-MOCK-EXTERNAL-FOR-BCC@EXAMPLE.COM-ID', - }; - return response; }; const processMessageFromUser2 = async (body: string) => { @@ -76,29 +66,11 @@ const processMessageFromUser2 = async (body: string) => { expect(decryptedMimeMsg).to.contain( 'Content-Transfer-Encoding: base64\r\n\r\n' + 'JVBERi0xLjQKJcOkw7zDtsOfCjIgMCBvYmoKPDwvTGVuZ3RoIDMgMCBSL0ZpbHRlci9GbGF0ZURl' ); - const response = { + return { // this url is required for pubkey encrypted message url: `http://${standardFesUrl}/message/FES-MOCK-MESSAGE-ID`, externalId: 'FES-MOCK-EXTERNAL-ID', - emailToExternalIdAndUrl: {} as { [email: string]: { url: string; externalId: string } }, - }; - response.emailToExternalIdAndUrl['to@example.com'] = { - url: `http://${standardFesUrl}/message/FES-MOCK-MESSAGE-FOR-TO@EXAMPLE.COM-ID`, - externalId: 'FES-MOCK-EXTERNAL-FOR-TO@EXAMPLE.COM-ID', - }; - response.emailToExternalIdAndUrl['sender@domain.com'] = { - url: `http://${standardFesUrl}/message/FES-MOCK-MESSAGE-FOR-SENDER@DOMAIN.COM-ID`, - externalId: 'FES-MOCK-EXTERNAL-FOR-SENDER@DOMAIN.COM-ID', - }; - response.emailToExternalIdAndUrl['flowcrypt.compatibility@gmail.com'] = { - url: `http://${standardFesUrl}/message/FES-MOCK-MESSAGE-FOR-FLOWCRYPT.COMPATIBILITY@GMAIL.COM-ID`, - externalId: 'FES-MOCK-EXTERNAL-FOR-FLOWCRYPT.COMPATIBILITY@GMAIL.COM-ID', }; - response.emailToExternalIdAndUrl['mock.only.pubkey@flowcrypt.com'] = { - url: `http://${standardFesUrl}/message/FES-MOCK-MESSAGE-FOR-MOCK.ONLY.PUBKEY@FLOWCRYPT.COM-ID`, - externalId: 'FES-MOCK-EXTERNAL-FOR-MOCK.ONLY.PUBKEY@FLOWCRYPT.COM-ID', - }; - return response; }; const processMessageFromUser3 = async (body: string) => { @@ -122,67 +94,11 @@ const processMessageFromUser3 = async (body: string) => { expect(decryptedMimeMsg).to.contain( 'Content-Type: text/plain\r\n' + 'Content-Transfer-Encoding: quoted-printable\r\n\r\n' + 'PWD encrypted message with FES - pubkey recipient in bcc' ); - const response = { - // this url is required for pubkey encrypted message - url: `http://${standardFesUrl}/message/FES-MOCK-MESSAGE-ID`, - externalId: 'FES-MOCK-EXTERNAL-ID', - emailToExternalIdAndUrl: {} as { [email: string]: { url: string; externalId: string } }, - }; - response.emailToExternalIdAndUrl['to@example.com'] = { - url: `http://${standardFesUrl}/message/FES-MOCK-MESSAGE-FOR-TO@EXAMPLE.COM-ID`, - externalId: 'FES-MOCK-EXTERNAL-FOR-TO@EXAMPLE.COM-ID', - }; - response.emailToExternalIdAndUrl['flowcrypt.compatibility@gmail.com'] = { - url: `http://${standardFesUrl}/message/FES-MOCK-MESSAGE-FOR-FLOWCRYPT.COMPATIBILITY@GMAIL.COM-ID`, - externalId: 'FES-MOCK-EXTERNAL-FOR-FLOWCRYPT.COMPATIBILITY@GMAIL.COM-ID', - }; - return response; -}; - -const processMessageFromUser4 = async (body: string) => { - const response = { + return { // this url is required for pubkey encrypted message url: `http://${standardFesUrl}/message/FES-MOCK-MESSAGE-ID`, externalId: 'FES-MOCK-EXTERNAL-ID', - emailToExternalIdAndUrl: {} as { [email: string]: { url: string; externalId: string } }, }; - if (body.includes('to@example.com')) { - response.emailToExternalIdAndUrl['to@example.com'] = { - url: `http://${standardFesUrl}/message/FES-MOCK-MESSAGE-FOR-TO@EXAMPLE.COM-ID`, - externalId: 'FES-MOCK-EXTERNAL-FOR-TO@EXAMPLE.COM-ID', - }; - } - if (body.includes('invalid@example.com')) { - response.emailToExternalIdAndUrl['invalid@example.com'] = { - url: `http://${standardFesUrl}/message/FES-MOCK-MESSAGE-FOR-INVALID@EXAMPLE.COM-ID`, - externalId: 'FES-MOCK-EXTERNAL-FOR-INVALID@EXAMPLE.COM-ID', - }; - } - if (body.includes('timeout@example.com')) { - response.emailToExternalIdAndUrl['timeout@example.com'] = { - url: `http://${standardFesUrl}/message/FES-MOCK-MESSAGE-FOR-TIMEOUT@EXAMPLE.COM-ID`, - externalId: 'FES-MOCK-EXTERNAL-FOR-TIMEOUT@EXAMPLE.COM-ID', - }; - } - if (body.includes('Mr Cc ')) { - response.emailToExternalIdAndUrl['cc@example.com'] = { - url: `http://${standardFesUrl}/message/FES-MOCK-MESSAGE-FOR-CC@EXAMPLE.COM-ID`, - externalId: 'FES-MOCK-EXTERNAL-FOR-CC@EXAMPLE.COM-ID', - }; - } - if (body.includes('First Last ')) { - response.emailToExternalIdAndUrl['flowcrypt.compatibility@gmail.com'] = { - url: `http://${standardFesUrl}/message/FES-MOCK-MESSAGE-FOR-FLOWCRYPT.COMPATIBILITY@GMAIL.COM-ID`, - externalId: 'FES-MOCK-EXTERNAL-FOR-FLOWCRYPT.COMPATIBILITY@GMAIL.COM-ID', - }; - } - if (body.includes('gatewayfailure@example.com')) { - response.emailToExternalIdAndUrl['gatewayfailure@example.com'] = { - url: `http://${standardFesUrl}/message/FES-MOCK-MESSAGE-FOR-GATEWAYFAILURE@EXAMPLE.COM-ID`, - externalId: 'FES-MOCK-EXTERNAL-FOR-GATEWAYFAILURE@EXAMPLE.COM-ID', - }; - } - return response; }; export const mockFesEndpoints: HandlersDefinition = { @@ -243,7 +159,11 @@ export const mockFesEndpoints: HandlersDefinition = { return await processMessageFromUser3(body); } if (body.includes('"from":"user4@standardsubdomainfes.localhost:8001"')) { - return await processMessageFromUser4(body); + return { + // this url is required for pubkey encrypted message + url: `http://${standardFesUrl}/message/FES-MOCK-MESSAGE-ID`, + externalId: 'FES-MOCK-EXTERNAL-ID', + } } } throw new HttpClientErr('Not Found', 404); @@ -288,7 +208,7 @@ export const mockFesEndpoints: HandlersDefinition = { throw new HttpClientErr('Not Found', 404); }, '/api/v1/message/FES-MOCK-EXTERNAL-FOR-GATEWAYFAILURE@EXAMPLE.COM-ID/gateway': async () => { - // test: `user4@standardsubdomainfes.localhost:8001 - PWD encrypted message with FES web portal - a send fails with gateway update error` + // test: `user4@standardsubdomainfes.localhost:8001 - PWD encrypted message with FES web portal - send fails with gateway update error` throw new HttpClientErr(`Test error`, Status.BAD_REQUEST); }, }; diff --git a/test/source/mock/google/strategies/send-message-strategy.ts b/test/source/mock/google/strategies/send-message-strategy.ts index ca3d175684a..6ca119abeaa 100644 --- a/test/source/mock/google/strategies/send-message-strategy.ts +++ b/test/source/mock/google/strategies/send-message-strategy.ts @@ -365,7 +365,7 @@ export class TestBySubjectStrategyContext { this.strategy = new PwdEncryptedMessageWithFesPubkeyRecipientInBccTestStrategy(); } else if (subject.includes('PWD encrypted message with FES web portal - sends fails with BadRequest error')) { this.strategy = new PwdEncryptedMessageWithFesReplyBadRequestTestStrategy(); - } else if (subject.includes('PWD encrypted message with FES web portal - a send fails with gateway update error')) { + } else if (subject.includes('PWD encrypted message with FES web portal - send fails with gateway update error')) { this.strategy = new SaveMessageInStorageStrategy(); } else if (subject.includes('Message With Image')) { this.strategy = new SaveMessageInStorageStrategy(); diff --git a/test/source/test.ts b/test/source/test.ts index 4ddf208fe3a..56e63cb39c9 100644 --- a/test/source/test.ts +++ b/test/source/test.ts @@ -146,7 +146,7 @@ ava.default.after.always('evaluate Catch.reportErr errors', async t => { 'BrowserMsg(ajax) Bad Request: 400 when GET-ing https://localhost:8001/flowcrypt-email-key-manager/v1/keys/private (no body): -> RequestTimeout', ].includes(e.message) ) - // below for test "user4@standardsubdomainfes.localhost:8001 - PWD encrypted message with FES web portal - a send fails with gateway update error" + // below for test "user4@standardsubdomainfes.localhost:8001 - PWD encrypted message with FES web portal - send fails with gateway update error" .filter(e => !e.message.includes('Test error')) // below for test "no.fes@example.com - skip FES on consumer, show friendly message on enterprise" .filter(e => !e.trace.includes('-1 when GET-ing https://fes.example.com')) diff --git a/test/source/tests/compose.ts b/test/source/tests/compose.ts index d09e9f52477..09a415c0277 100644 --- a/test/source/tests/compose.ts +++ b/test/source/tests/compose.ts @@ -2540,7 +2540,7 @@ export const defineComposeTests = (testVariant: TestVariant, testWithBrowser: Te ); ava.default( - 'user4@standardsubdomainfes.localhost:8001 - PWD encrypted message with FES web portal - a send fails with gateway update error', + 'user4@standardsubdomainfes.localhost:8001 - PWD encrypted message with FES web portal - send fails with gateway update error', testWithBrowser(undefined, async (t, browser) => { const acct = 'user4@standardsubdomainfes.localhost:8001'; // added port to trick extension into calling the mock const settingsPage = await BrowserRecipe.openSettingsLoginApprove(t, browser, acct); @@ -2550,7 +2550,7 @@ export const defineComposeTests = (testVariant: TestVariant, testWithBrowser: Te { submitPubkey: false, usedPgpBefore: false }, { isSavePassphraseChecked: false, isSavePassphraseHidden: false } ); - const subject = 'PWD encrypted message with FES web portal - a send fails with gateway update error - ' + testVariant; + const subject = 'PWD encrypted message with FES web portal - send fails with gateway update error - ' + testVariant; const expectedNumberOfPassedMessages = (await GoogleData.withInitializedData(acct)).searchMessagesBySubject(subject).length; const composePage = await ComposePageRecipe.openStandalone(t, browser, 'user4@standardsubdomainfes.localhost:8001'); await ComposePageRecipe.fillMsg(composePage, { to: 'gatewayfailure@example.com' }, subject); @@ -2559,7 +2559,7 @@ export const defineComposeTests = (testVariant: TestVariant, testWithBrowser: Te await composePage.waitForContent('.ui-toast-title', 'Failed to bind Gateway ID of the message:'); await composePage.close(); expect((await GoogleData.withInitializedData(acct)).searchMessagesBySubject(subject).length).to.equal(expectedNumberOfPassedMessages + 1); - // this test is using PwdEncryptedMessageWithFesReplyGatewayErrorTestStrategy to check sent result based on subject "PWD encrypted message with FES web portal - a send fails with gateway update error" + // this test is using SaveMessageInStorageStrategy to check sent result based on subject "PWD encrypted message with FES web portal - send fails with gateway update error" // also see '/api/v1/message' in fes-endpoints.ts mock }) ); From 710e3485492b578e77f52b6420da6d48bfde6b21 Mon Sep 17 00:00:00 2001 From: Tom J Date: Tue, 10 Jan 2023 15:56:16 +0000 Subject: [PATCH 08/14] fixed test --- .../formatters/encrypted-mail-msg-formatter.ts | 2 +- extension/js/common/api/account-server.ts | 2 +- test/source/mock/fes/fes-endpoints.ts | 7 +++++++ test/source/mock/google/google-data.ts | 6 +++++- 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/extension/chrome/elements/compose-modules/formatters/encrypted-mail-msg-formatter.ts b/extension/chrome/elements/compose-modules/formatters/encrypted-mail-msg-formatter.ts index c216580d56c..1a326b31b65 100644 --- a/extension/chrome/elements/compose-modules/formatters/encrypted-mail-msg-formatter.ts +++ b/extension/chrome/elements/compose-modules/formatters/encrypted-mail-msg-formatter.ts @@ -108,7 +108,7 @@ export class EncryptedMsgMailFormatter extends BaseMailFormatter { const msg = await this.sendableCombinedPubkeyMsgWithoutAttachedFilesWithLinkToUploadedPwdMsg( newMsg, pubkeys, - { msgUrl: uploadedMessageResponse.url }, + { msgUrl: uploadedMessageResponse.url, externalId: uploadedMessageResponse.externalId }, signingKey?.key ); // the above message has pgp/mime encrypted content that was attached as a set of pgp/mime attachments, diff --git a/extension/js/common/api/account-server.ts b/extension/js/common/api/account-server.ts index 4b35eafb87e..6098cb36191 100644 --- a/extension/js/common/api/account-server.ts +++ b/extension/js/common/api/account-server.ts @@ -13,7 +13,7 @@ import { Api, ProgressCb } from './shared/api.js'; export type UploadedMessageResponse = { url: string; // both FES and FlowCryptComApi - externalId?: string; // legacy FES + externalId?: string; // FES }; /** diff --git a/test/source/mock/fes/fes-endpoints.ts b/test/source/mock/fes/fes-endpoints.ts index df1c5eba7fe..0c98e46f319 100644 --- a/test/source/mock/fes/fes-endpoints.ts +++ b/test/source/mock/fes/fes-endpoints.ts @@ -149,6 +149,13 @@ export const mockFesEndpoints: HandlersDefinition = { if (req.headers.host === standardFesUrl && req.method === 'POST' && typeof body === 'string') { // test: `compose - user@standardsubdomainfes.localhost:8001 - PWD encrypted message with FES web portal` authenticate(req, 'oidc'); + if (body.includes('gatewayfailure@example.com')) { // recipient + return { + // this url is required for pubkey encrypted message + url: `http://${standardFesUrl}/message/FES-MOCK-MESSAGE-ID`, + externalId: 'FES-MOCK-EXTERNAL-FOR-GATEWAYFAILURE@EXAMPLE.COM-ID', + } + } if (body.includes('"from":"user@standardsubdomainfes.localhost:8001"')) { return await processMessageFromUser(body); } diff --git a/test/source/mock/google/google-data.ts b/test/source/mock/google/google-data.ts index b40894c24b4..e761bb7501f 100644 --- a/test/source/mock/google/google-data.ts +++ b/test/source/mock/google/google-data.ts @@ -282,7 +282,11 @@ export class GoogleData { payload: { headers: [ { name: 'Subject', value: parsedMail.subject || '' }, - { name: 'Message-ID', value: parsedMail.messageId || '' }, + // todo - Gmail doesn't retain message ids we give it in the MIME message. + // therefore ideally, we would not retain them in mock either, to be consistent + // in a separate PR try to remove `parsedMail.messageId || ` below + // see if it breaks any tests + { name: 'Message-ID', value: parsedMail.messageId || `mock-gmail-message-id-${Util.lousyRandom()}` }, ], body, }, From 79d527c51cb463993611e7addbdff2190e5d6bac Mon Sep 17 00:00:00 2001 From: Tom J Date: Tue, 10 Jan 2023 16:29:58 +0000 Subject: [PATCH 09/14] small fixes --- .../mock/google/strategies/send-message-strategy.ts | 11 +---------- test/source/tests/flaky.ts | 2 +- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/test/source/mock/google/strategies/send-message-strategy.ts b/test/source/mock/google/strategies/send-message-strategy.ts index 6ca119abeaa..ee424ebcc9c 100644 --- a/test/source/mock/google/strategies/send-message-strategy.ts +++ b/test/source/mock/google/strategies/send-message-strategy.ts @@ -93,9 +93,6 @@ class PwdEncryptedMessageWithFesIdTokenTestStrategy implements ITestMsgStrategy class PwdEncryptedMessageWithFesPubkeyRecipientInBccTestStrategy implements ITestMsgStrategy { public test = async (parseResult: ParseMsgResult, id: string) => { const mimeMsg = parseResult.mimeMsg; - console.log('--- MIME MSG ---'); - console.log(mimeMsg); - console.log('--- END MIME MSG ---'); const expectedSenderEmail = 'user3@standardsubdomainfes.localhost:8001'; expect(mimeMsg.from!.text).to.equal(`First Last <${expectedSenderEmail}>`); // originally fes @@ -123,13 +120,7 @@ class PwdEncryptedMessageWithFesReplyBadRequestTestStrategy implements ITestMsgS const to = parsedMailAddressObjectAsArray(mimeMsg.to) .concat(parsedMailAddressObjectAsArray(mimeMsg.cc)) .concat(parsedMailAddressObjectAsArray(mimeMsg.bcc)); - // expect(to.length).to.equal(1); const recipientEmails = to.map(to => to.text) - // if (recipientEmail === 'to@example.com') { - // // success - // await new SaveMessageInStorageStrategy().test(parseResult, id); - // return; - // } else if (recipientEmails.includes('invalid@example.com')) { throw new HttpClientErr('Invalid to header', Status.BAD_REQUEST); } else if (recipientEmails.includes('timeout@example.com')) { @@ -363,7 +354,7 @@ export class TestBySubjectStrategyContext { this.strategy = new PwdEncryptedMessageWithFesReplyRenderingTestStrategy(); } else if (subject.includes('PWD encrypted message with FES - pubkey recipient in bcc')) { this.strategy = new PwdEncryptedMessageWithFesPubkeyRecipientInBccTestStrategy(); - } else if (subject.includes('PWD encrypted message with FES web portal - sends fails with BadRequest error')) { + } else if (subject.includes('PWD encrypted message with FES web portal - send fails with BadRequest error')) { this.strategy = new PwdEncryptedMessageWithFesReplyBadRequestTestStrategy(); } else if (subject.includes('PWD encrypted message with FES web portal - send fails with gateway update error')) { this.strategy = new SaveMessageInStorageStrategy(); diff --git a/test/source/tests/flaky.ts b/test/source/tests/flaky.ts index 2b6cd795981..16056e4dfee 100644 --- a/test/source/tests/flaky.ts +++ b/test/source/tests/flaky.ts @@ -202,7 +202,7 @@ export const defineFlakyTests = (testVariant: TestVariant, testWithBrowser: Test ); ava.default( - 'user4@standardsubdomainfes.localhost:8001 - PWD encrypted message with FES web portal - sends fails with BadRequest error', + 'user4@standardsubdomainfes.localhost:8001 - PWD encrypted message with FES web portal - send fails with BadRequest error', testWithBrowser(undefined, async (t, browser) => { const acct = 'user4@standardsubdomainfes.localhost:8001'; // added port to trick extension into calling the mock const settingsPage = await BrowserRecipe.openSettingsLoginApprove(t, browser, acct); From 41f4b59fbc2788f139e7e462d6ef3d6fdf790e05 Mon Sep 17 00:00:00 2001 From: Tom J Date: Tue, 10 Jan 2023 16:41:48 +0000 Subject: [PATCH 10/14] fix test --- .../strategies/send-message-strategy.ts | 32 ++++++++----------- test/source/tests/compose.ts | 2 +- 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/test/source/mock/google/strategies/send-message-strategy.ts b/test/source/mock/google/strategies/send-message-strategy.ts index ee424ebcc9c..f4f0bff3c6e 100644 --- a/test/source/mock/google/strategies/send-message-strategy.ts +++ b/test/source/mock/google/strategies/send-message-strategy.ts @@ -29,26 +29,20 @@ class PwdAndPubkeyEncryptedMessagesWithFlowCryptComApiTestStrategy implements IT const mimeMsg = parseResult.mimeMsg; const senderEmail = Str.parseEmail(mimeMsg.from!.text).email; await new SaveMessageInStorageStrategy().test(parseResult, id); - if (mimeMsg.cc) { - // this is a message to the pubkey recipient - expect((mimeMsg.cc as AddressObject).text!).to.include('flowcrypt.compatibility@gmail.com'); - expect(mimeMsg.text!).to.not.include('has sent you a password-encrypted email'); - expect(mimeMsg.text!).to.not.include('Follow this link to open it'); - const kisWithPp = await Config.getKeyInfo(['flowcrypt.compatibility.1pp1', 'flowcrypt.compatibility.2pp1']); - const encryptedData = Buf.fromUtfStr(mimeMsg.text!); - const decrypted = await MsgUtil.decryptMessage({ kisWithPp, encryptedData, verificationPubs: [] }); - expect(decrypted.success).to.be.true; - expect(decrypted.content!.toUtfStr()).to.contain('PWD and pubkey encrypted messages with flowcrypt.com/api'); - expect(mimeMsg.bcc).to.be.an.undefined; - expect(mimeMsg.to).to.be.an.undefined; - expect((mimeMsg.headers.get('reply-to') as AddressObject).text).to.equal('First Last , test@email.com'); - } else { - expect(mimeMsg.text!).to.contain(`${senderEmail} has sent you a password-encrypted email`); - expect(mimeMsg.text!).to.contain('Follow this link to open it'); - if (!mimeMsg.text?.match(/https:\/\/flowcrypt.com\/[a-z0-9A-Z]{10}/)) { - throw new HttpClientErr(`Error: cannot find pwd encrypted flowcrypt.com/api link in:\n\n${mimeMsg.text}`); - } + expect(mimeMsg.text!).to.contain(`${senderEmail} has sent you a password-encrypted email`); + expect(mimeMsg.text!).to.contain('Follow this link to open it'); + if (!mimeMsg.text?.match(/https:\/\/flowcrypt.com\/[a-z0-9A-Z]{10}/)) { + throw new HttpClientErr(`Error: cannot find pwd encrypted flowcrypt.com/api link in:\n\n${mimeMsg.text}`); } + const kisWithPp = await Config.getKeyInfo(['flowcrypt.compatibility.1pp1', 'flowcrypt.compatibility.2pp1']); + const encryptedData = mimeMsg.attachments.find(a => a.filename === 'encrypted.asc')!.content; + const decrypted = await MsgUtil.decryptMessage({ kisWithPp, encryptedData, verificationPubs: [] }); + expect(decrypted.success).to.be.true; + expect(decrypted.content!.toUtfStr()).to.contain('PWD and pubkey encrypted messages with flowcrypt.com/api'); + expect((mimeMsg.to as AddressObject).text!).to.include('test@email.com'); + expect((mimeMsg.cc as AddressObject).text!).to.include('flowcrypt.compatibility@gmail.com'); + expect(mimeMsg.bcc).to.be.an.undefined; + expect(mimeMsg.headers.get('reply-to')).to.be.undefined; }; } class PwdEncryptedMessageWithFlowCryptComApiTestStrategy implements ITestMsgStrategy { diff --git a/test/source/tests/compose.ts b/test/source/tests/compose.ts index 09a415c0277..d69afff5776 100644 --- a/test/source/tests/compose.ts +++ b/test/source/tests/compose.ts @@ -39,7 +39,7 @@ export const defineComposeTests = (testVariant: TestVariant, testWithBrowser: Te await ComposePageRecipe.selectFromOption(composePage, acct); await ComposePageRecipe.fillMsg(composePage, { to: 'test@email.com', cc: 'flowcrypt.compatibility@gmail.com' }, subject); await ComposePageRecipe.sendAndClose(composePage, { password: msgPwd }); - expect((await GoogleData.withInitializedData(acct)).searchMessagesBySubject(subject).length).to.equal(expectedNumberOfPassedMessages); + expect((await GoogleData.withInitializedData(acct)).searchMessagesBySubject(subject).length).to.equal(expectedNumberOfPassedMessages + 1); // this test is using PwdAndPubkeyEncryptedMessagesWithFlowCryptComApiTestStrategy to check sent result based on subject "PWD and pubkey encrypted messages with flowcrypt.com/api" }) ); From 1c94e820cf3fa1de613c628e06efdd33a9467a32 Mon Sep 17 00:00:00 2001 From: Tom J Date: Tue, 10 Jan 2023 17:19:44 +0000 Subject: [PATCH 11/14] fix test --- test/source/mock/fes/fes-endpoints.ts | 4 +++- test/source/mock/google/strategies/send-message-strategy.ts | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/test/source/mock/fes/fes-endpoints.ts b/test/source/mock/fes/fes-endpoints.ts index 0c98e46f319..f408bf562ec 100644 --- a/test/source/mock/fes/fes-endpoints.ts +++ b/test/source/mock/fes/fes-endpoints.ts @@ -92,7 +92,9 @@ const processMessageFromUser3 = async (body: string) => { const decryptedMimeMsg = decrypted.content!.toUtfStr(); // small.txt expect(decryptedMimeMsg).to.contain( - 'Content-Type: text/plain\r\n' + 'Content-Transfer-Encoding: quoted-printable\r\n\r\n' + 'PWD encrypted message with FES - pubkey recipient in bcc' + 'Content-Type: text/plain\r\n' + + 'Content-Transfer-Encoding: quoted-printable\r\n\r\n' + + 'PWD encrypted message with FES - pubkey recipient in bcc' ); return { // this url is required for pubkey encrypted message diff --git a/test/source/mock/google/strategies/send-message-strategy.ts b/test/source/mock/google/strategies/send-message-strategy.ts index f4f0bff3c6e..e6bd6f0c25e 100644 --- a/test/source/mock/google/strategies/send-message-strategy.ts +++ b/test/source/mock/google/strategies/send-message-strategy.ts @@ -100,8 +100,8 @@ class PwdEncryptedMessageWithFesPubkeyRecipientInBccTestStrategy implements ITes const encryptedData = mimeMsg.attachments.find(a => a.filename === 'encrypted.asc')!.content; const decrypted = await MsgUtil.decryptMessage({ kisWithPp, encryptedData, verificationPubs: [] }); expect(decrypted.success).to.be.true; - expect(decrypted.content!.toUtfStr()).to.contain('PWD encrypted message with FES - pubkey recipient in bcc'); - expect((mimeMsg.headers.get('reply-to') as AddressObject).text).to.be.empty; + expect(decrypted.content!.toUtfStr()).to.contain('PWD encrypted message with FES - pubkey recipient'); + expect(mimeMsg.headers.get('reply-to')).to.be.undefined; await new SaveMessageInStorageStrategy().test(parseResult, id); }; } From 05918ce7b2054fe685817ab94c47badc0d8a6de9 Mon Sep 17 00:00:00 2001 From: Tom J Date: Tue, 10 Jan 2023 17:27:59 +0000 Subject: [PATCH 12/14] fix test --- .../strategies/send-message-strategy.ts | 20 ++++++++----------- test/source/tests/compose.ts | 2 +- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/test/source/mock/google/strategies/send-message-strategy.ts b/test/source/mock/google/strategies/send-message-strategy.ts index e6bd6f0c25e..53021d2aa7a 100644 --- a/test/source/mock/google/strategies/send-message-strategy.ts +++ b/test/source/mock/google/strategies/send-message-strategy.ts @@ -66,20 +66,16 @@ class PwdEncryptedMessageWithFesIdTokenTestStrategy implements ITestMsgStrategy const mimeMsg = parseResult.mimeMsg; const expectedSenderEmail = 'user@standardsubdomainfes.localhost:8001'; expect(mimeMsg.from!.text).to.equal(`First Last <${expectedSenderEmail}>`); - if (mimeMsg.text?.includes('http://fes.standardsubdomainfes.localhost:8001/message/FES-MOCK-MESSAGE-FOR-TO@EXAMPLE.COM-ID')) { - expect((mimeMsg.to as AddressObject).text).to.equal('Mr To '); - expect(mimeMsg.cc).to.be.an.undefined; - expect(mimeMsg.bcc).to.be.an.undefined; - } else if (mimeMsg.text?.includes('http://fes.standardsubdomainfes.localhost:8001/message/FES-MOCK-MESSAGE-FOR-BCC@EXAMPLE.COM-ID')) { - expect((mimeMsg.to as AddressObject).text).to.equal('Mr Bcc '); - expect(mimeMsg.cc).to.be.an.undefined; - expect(mimeMsg.bcc).to.be.an.undefined; - } else { - // no pubkey recipients in this test - throw new HttpClientErr(`Error: cannot find pwd encrypted FES link in:\n\n${mimeMsg.text}`); - } + expect((mimeMsg.to as AddressObject).text).to.equal('Mr To '); + expect(mimeMsg.cc).to.be.an.undefined; + expect((mimeMsg.bcc as AddressObject).text).to.equal('Mr Bcc '); expect(mimeMsg.text!).to.include(`${expectedSenderEmail} has sent you a password-encrypted email`); expect(mimeMsg.text!).to.include('Follow this link to open it'); + const kisWithPp = await Config.getKeyInfo(['flowcrypt.test.key.used.pgp']); + const encryptedData = mimeMsg.attachments.find(a => a.filename === 'encrypted.asc')!.content; + const decrypted = await MsgUtil.decryptMessage({ kisWithPp, encryptedData, verificationPubs: [] }); + expect(decrypted.success).to.be.true; + expect(decrypted.content!.toUtfStr()).to.contain('PWD encrypted message with FES - ID TOKEN'); await new SaveMessageInStorageStrategy().test(parseResult, id); }; } diff --git a/test/source/tests/compose.ts b/test/source/tests/compose.ts index d69afff5776..01046384780 100644 --- a/test/source/tests/compose.ts +++ b/test/source/tests/compose.ts @@ -2434,7 +2434,7 @@ export const defineComposeTests = (testVariant: TestVariant, testWithBrowser: Te await composePage.waitAndClick('@action-send', { delay: 1 }); await ComposePageRecipe.closed(composePage); const sentMsgs = (await GoogleData.withInitializedData(acct)).searchMessagesBySubject(subject); - expect(sentMsgs.length).to.equal(2); + expect(sentMsgs.length).to.equal(1); // this test is using PwdEncryptedMessageWithFesIdTokenTestStrategy to check sent result based on subject "PWD encrypted message with FES - ID TOKEN" // also see '/api/v1/message' in fes-endpoints.ts mock }) From 333cb2147acaf53c442a8413b194f1793dc87218 Mon Sep 17 00:00:00 2001 From: Tom J Date: Tue, 10 Jan 2023 17:39:23 +0000 Subject: [PATCH 13/14] fix flaky test --- test/source/tests/flaky.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/source/tests/flaky.ts b/test/source/tests/flaky.ts index 16056e4dfee..3b058c738df 100644 --- a/test/source/tests/flaky.ts +++ b/test/source/tests/flaky.ts @@ -221,9 +221,9 @@ export const defineFlakyTests = (testVariant: TestVariant, testWithBrowser: Test /* eslint-enable @typescript-eslint/no-explicit-any */ }); await dbPage.close(); - const subject = 'PWD encrypted message with FES web portal - some sends fail with BadRequest error - ' + testVariant; + const subject = 'PWD encrypted message with FES web portal - send fails with BadRequest error - ' + testVariant; const expectedNumberOfPassedMessages = (await GoogleData.withInitializedData(acct)).searchMessagesBySubject(subject).length; - // 2. vague Gmail error with all failures + // 1. vague Gmail error with all failures let composePage = await ComposePageRecipe.openStandalone(t, browser, 'user4@standardsubdomainfes.localhost:8001'); await ComposePageRecipe.fillMsg(composePage, { cc: 'cc@example.com', bcc: 'flowcrypt.compatibility@gmail.com' }, subject); await composePage.waitAndType('@input-password', 'gO0d-pwd'); From 8c16842b4b0d38dde2ae97896653174fd0e5003d Mon Sep 17 00:00:00 2001 From: Tom J Date: Tue, 10 Jan 2023 18:53:15 +0000 Subject: [PATCH 14/14] fix test --- test/source/mock/google/strategies/send-message-strategy.ts | 2 +- test/source/tests/compose.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/source/mock/google/strategies/send-message-strategy.ts b/test/source/mock/google/strategies/send-message-strategy.ts index 53021d2aa7a..27dee6db6a8 100644 --- a/test/source/mock/google/strategies/send-message-strategy.ts +++ b/test/source/mock/google/strategies/send-message-strategy.ts @@ -28,7 +28,6 @@ class PwdAndPubkeyEncryptedMessagesWithFlowCryptComApiTestStrategy implements IT public test = async (parseResult: ParseMsgResult, id: string) => { const mimeMsg = parseResult.mimeMsg; const senderEmail = Str.parseEmail(mimeMsg.from!.text).email; - await new SaveMessageInStorageStrategy().test(parseResult, id); expect(mimeMsg.text!).to.contain(`${senderEmail} has sent you a password-encrypted email`); expect(mimeMsg.text!).to.contain('Follow this link to open it'); if (!mimeMsg.text?.match(/https:\/\/flowcrypt.com\/[a-z0-9A-Z]{10}/)) { @@ -43,6 +42,7 @@ class PwdAndPubkeyEncryptedMessagesWithFlowCryptComApiTestStrategy implements IT expect((mimeMsg.cc as AddressObject).text!).to.include('flowcrypt.compatibility@gmail.com'); expect(mimeMsg.bcc).to.be.an.undefined; expect(mimeMsg.headers.get('reply-to')).to.be.undefined; + await new SaveMessageInStorageStrategy().test(parseResult, id); }; } class PwdEncryptedMessageWithFlowCryptComApiTestStrategy implements ITestMsgStrategy { diff --git a/test/source/tests/compose.ts b/test/source/tests/compose.ts index 01046384780..68a4842bdf0 100644 --- a/test/source/tests/compose.ts +++ b/test/source/tests/compose.ts @@ -34,12 +34,12 @@ export const defineComposeTests = (testVariant: TestVariant, testWithBrowser: Te const acct = 'flowcrypt.compatibility@gmail.com'; const msgPwd = 'super hard password for the message'; const subject = 'PWD and pubkey encrypted messages with flowcrypt.com/api'; - const expectedNumberOfPassedMessages = (await GoogleData.withInitializedData(acct)).searchMessagesBySubject(subject).length + 2; + const expectedNumberOfPassedMessages = (await GoogleData.withInitializedData(acct)).searchMessagesBySubject(subject).length + 1; const composePage = await ComposePageRecipe.openStandalone(t, browser, 'compatibility'); await ComposePageRecipe.selectFromOption(composePage, acct); await ComposePageRecipe.fillMsg(composePage, { to: 'test@email.com', cc: 'flowcrypt.compatibility@gmail.com' }, subject); await ComposePageRecipe.sendAndClose(composePage, { password: msgPwd }); - expect((await GoogleData.withInitializedData(acct)).searchMessagesBySubject(subject).length).to.equal(expectedNumberOfPassedMessages + 1); + expect((await GoogleData.withInitializedData(acct)).searchMessagesBySubject(subject).length).to.equal(expectedNumberOfPassedMessages); // this test is using PwdAndPubkeyEncryptedMessagesWithFlowCryptComApiTestStrategy to check sent result based on subject "PWD and pubkey encrypted messages with flowcrypt.com/api" }) );