diff --git a/extension/js/common/browser/browser-msg.ts b/extension/js/common/browser/browser-msg.ts index 4c566caa5c1..c72f4a0c937 100644 --- a/extension/js/common/browser/browser-msg.ts +++ b/extension/js/common/browser/browser-msg.ts @@ -20,6 +20,7 @@ import { Ui } from './ui.js'; import { AuthRes } from '../api/authentication/generic/oauth.js'; import { GlobalStore } from '../platform/store/global-store.js'; import { BgUtils } from '../../service_worker/bgutils.js'; +import { ThunderbirdAttachment } from '../core/attachment.js'; export type GoogleAuthWindowResult$result = 'Success' | 'Denied' | 'Error' | 'Closed'; export type ScreenDimensions = { width: number; height: number; availLeft: number; availTop: number }; @@ -98,7 +99,7 @@ export namespace Bm { export type PgpBlockRetry = { frameId: string; messageSender: Dest }; export type PgpBlockReady = { frameId: string; messageSender: Dest }; export type ThunderbirdOpenPassphraseDialog = { acctEmail: string; longids: string }; - export type ThunderbirdGetDownloadableAttachment = { attachment: messenger.messages.MessageAttachment }; + export type ThunderbirdGetDownloadableAttachment = { attachments: messenger.messages.MessageAttachment[] }; export type ThunderbirdInitiateAttachmentDownload = { decryptedFileName: string; decryptedContent: Buf }; export namespace Res { @@ -116,7 +117,7 @@ export namespace Bm { export type ExpirationCacheGet = Promise; export type ExpirationCacheSet = Promise; export type ExpirationCacheDeleteExpired = Promise; - export type ThunderbirdGetDownloadableAttachment = Buf | undefined; + export type ThunderbirdGetDownloadableAttachment = ThunderbirdAttachment[]; export type ThunderbirdGetCurrentUser = string | undefined; export type ThunderbirdMsgGet = { attachments: messenger.messages.MessageAttachment[]; messagePart: messenger.messages.MessagePart }; export type ThunderbirdOpenPassphraseDialog = Promise; diff --git a/extension/js/common/core/attachment.ts b/extension/js/common/core/attachment.ts index 25909141051..f907c2cfb92 100644 --- a/extension/js/common/core/attachment.ts +++ b/extension/js/common/core/attachment.ts @@ -29,6 +29,12 @@ export type AttachmentProperties = { contentDescription?: string; contentTransferEncoding?: ContentTransferEncoding; }; +export type ThunderbirdAttachment = { + name: string; + contentType: string; + data: Buf; + treatAs: Attachment$treatAs; +}; export type AttachmentMeta = (AttachmentId | { data: Uint8Array }) & AttachmentProperties; export type FcAttachmentLinkData = { name: string; type: string; size: number }; diff --git a/extension/js/content_scripts/webmail/thunderbird/thunderbird-element-replacer.ts b/extension/js/content_scripts/webmail/thunderbird/thunderbird-element-replacer.ts index 4f134759145..2186c300f30 100644 --- a/extension/js/content_scripts/webmail/thunderbird/thunderbird-element-replacer.ts +++ b/extension/js/content_scripts/webmail/thunderbird/thunderbird-element-replacer.ts @@ -3,7 +3,7 @@ 'use strict'; import { BrowserMsg } from '../../../common/browser/browser-msg.js'; -import { Attachment } from '../../../common/core/attachment.js'; +import { Attachment, ThunderbirdAttachment } from '../../../common/core/attachment.js'; import { Buf } from '../../../common/core/buf.js'; import { KeyUtil } from '../../../common/core/crypto/key.js'; import { DecryptError, DecryptErrTypes, MsgUtil, VerifyRes } from '../../../common/core/crypto/pgp/msg-util.js'; @@ -44,11 +44,9 @@ export class ThunderbirdElementReplacer extends WebmailElementReplacer { await this.messageVerify(signerKeys); } if (emailBodyToParse && attachments.length) { - for (const attachment of attachments) { - const fcAttachment = await BrowserMsg.send.bg.await.thunderbirdGetDownloadableAttachment({ attachment }); - if (fcAttachment) { - await this.attachmentUiRenderer(attachment.name, fcAttachment, signerKeys, emailBodyToParse); - } + const fcAttachments = await BrowserMsg.send.bg.await.thunderbirdGetDownloadableAttachment({ attachments }); + for (const fcAttachment of fcAttachments) { + await this.attachmentUiRenderer(fcAttachment, signerKeys, emailBodyToParse); } } } @@ -112,14 +110,17 @@ export class ThunderbirdElementReplacer extends WebmailElementReplacer { $('body').html(pgpBlock); // xss-sanitized }; - private attachmentUiRenderer = async (attachmentName: string, fcAttachment: Buf, verificationPubs: string[], plaintext: string) => { - if (attachmentName.endsWith('.pgp')) { - const generatedPgpTemplate = this.generatePgpAttachmentTemplate(attachmentName, fcAttachment); + private attachmentUiRenderer = async (fcAttachment: ThunderbirdAttachment, verificationPubs: string[], plaintext: string) => { + if (fcAttachment.treatAs === 'encryptedFile') { + const generatedPgpTemplate = this.generatePgpAttachmentTemplate(fcAttachment.name, fcAttachment.data); $('.pgp_attachments_block').append(generatedPgpTemplate); // xss-sanitized - } else if (Attachment.encryptedMsgNames.some(a => attachmentName.includes(a)) && !this.emailBodyFromThunderbirdMail) { - await this.messageDecrypt(verificationPubs, fcAttachment); - } else if (attachmentName.endsWith('.asc')) { - const sigText = new TextDecoder('utf-8').decode(fcAttachment).trim(); + } else if ( + (fcAttachment.treatAs === 'encryptedMsg' || Attachment.encryptedMsgNames.some(a => fcAttachment.name.includes(a))) && + !this.emailBodyFromThunderbirdMail + ) { + await this.messageDecrypt(verificationPubs, fcAttachment.data); + } else if (fcAttachment.treatAs === 'signature') { + const sigText = new TextDecoder('utf-8').decode(fcAttachment.data).trim(); if (this.resemblesSignedMsg(sigText)) { await this.messageVerify(verificationPubs, { plaintext, sigText }); } diff --git a/extension/js/service_worker/bg-handlers.ts b/extension/js/service_worker/bg-handlers.ts index d45a3570a9e..43cc782ad96 100644 --- a/extension/js/service_worker/bg-handlers.ts +++ b/extension/js/service_worker/bg-handlers.ts @@ -166,13 +166,32 @@ export class BgHandlers { public static thunderbirdGetDownloadableAttachment = async ( r: Bm.ThunderbirdGetDownloadableAttachment ): Promise => { + const processableAttachments: Bm.Res.ThunderbirdGetDownloadableAttachment = []; const [tab] = await messenger.mailTabs.query({ active: true, currentWindow: true }); if (tab.id) { - const rawAttachment = await messenger.messages.getAttachmentFile(tab.id, r.attachment.partName); - const data = new Uint8Array(await rawAttachment.arrayBuffer()); - return new Attachment({ data }).getData(); + const fcAttachments: Attachment[] = []; + // convert Thunderbird Attachments to FlowCrypt recognizable Attachments + for (const tbAttachment of r.attachments) { + const rawAttachment = await messenger.messages.getAttachmentFile(tab.id, tbAttachment.partName); + fcAttachments.push( + new Attachment({ + data: new Uint8Array(await rawAttachment.arrayBuffer()), + type: tbAttachment.contentType, + name: tbAttachment.name, + length: tbAttachment.size, + }) + ); + } + for (const fcAttachment of fcAttachments) { + processableAttachments.push({ + name: fcAttachment.name, + contentType: fcAttachment.type, + data: fcAttachment.getData(), + treatAs: fcAttachment.treatAs(fcAttachments), + }); + } } - return; + return processableAttachments; }; public static thunderbirdInitiateAttachmentDownload = async (