Skip to content

Commit 85cf5f9

Browse files
committed
added reliable attachment type recognition
1 parent e25fb01 commit 85cf5f9

File tree

4 files changed

+46
-19
lines changed

4 files changed

+46
-19
lines changed

extension/js/common/browser/browser-msg.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { Ui } from './ui.js';
2020
import { AuthRes } from '../api/authentication/generic/oauth.js';
2121
import { GlobalStore } from '../platform/store/global-store.js';
2222
import { BgUtils } from '../../service_worker/bgutils.js';
23+
import { ThunderbirdAttachment } from '../core/attachment.js';
2324

2425
export type GoogleAuthWindowResult$result = 'Success' | 'Denied' | 'Error' | 'Closed';
2526
export type ScreenDimensions = { width: number; height: number; availLeft: number; availTop: number };
@@ -98,7 +99,7 @@ export namespace Bm {
9899
export type PgpBlockRetry = { frameId: string; messageSender: Dest };
99100
export type PgpBlockReady = { frameId: string; messageSender: Dest };
100101
export type ThunderbirdOpenPassphraseDialog = { acctEmail: string; longids: string };
101-
export type ThunderbirdGetDownloadableAttachment = { attachment: messenger.messages.MessageAttachment };
102+
export type ThunderbirdGetDownloadableAttachment = { attachments: messenger.messages.MessageAttachment[] };
102103
export type ThunderbirdInitiateAttachmentDownload = { decryptedFileName: string; decryptedContent: Buf };
103104

104105
export namespace Res {
@@ -116,7 +117,7 @@ export namespace Bm {
116117
export type ExpirationCacheGet<V> = Promise<V | undefined>;
117118
export type ExpirationCacheSet = Promise<void>;
118119
export type ExpirationCacheDeleteExpired = Promise<void>;
119-
export type ThunderbirdGetDownloadableAttachment = Buf | undefined;
120+
export type ThunderbirdGetDownloadableAttachment = ThunderbirdAttachment[];
120121
export type ThunderbirdGetCurrentUser = string | undefined;
121122
export type ThunderbirdMsgGet = { attachments: messenger.messages.MessageAttachment[]; messagePart: messenger.messages.MessagePart };
122123
export type ThunderbirdOpenPassphraseDialog = Promise<void>;

extension/js/common/core/attachment.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ export type AttachmentProperties = {
2929
contentDescription?: string;
3030
contentTransferEncoding?: ContentTransferEncoding;
3131
};
32+
export type ThunderbirdAttachment = {
33+
name: string;
34+
contentType: string;
35+
data: Buf;
36+
treatAs: Attachment$treatAs;
37+
};
3238
export type AttachmentMeta = (AttachmentId | { data: Uint8Array }) & AttachmentProperties;
3339

3440
export type FcAttachmentLinkData = { name: string; type: string; size: number };

extension/js/content_scripts/webmail/thunderbird/thunderbird-element-replacer.ts

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
'use strict';
44

55
import { BrowserMsg } from '../../../common/browser/browser-msg.js';
6-
import { Attachment } from '../../../common/core/attachment.js';
6+
import { Attachment, ThunderbirdAttachment } from '../../../common/core/attachment.js';
77
import { Buf } from '../../../common/core/buf.js';
88
import { KeyUtil } from '../../../common/core/crypto/key.js';
99
import { DecryptError, DecryptErrTypes, MsgUtil, VerifyRes } from '../../../common/core/crypto/pgp/msg-util.js';
@@ -44,11 +44,9 @@ export class ThunderbirdElementReplacer extends WebmailElementReplacer {
4444
await this.messageVerify(signerKeys);
4545
}
4646
if (emailBodyToParse && attachments.length) {
47-
for (const attachment of attachments) {
48-
const fcAttachment = await BrowserMsg.send.bg.await.thunderbirdGetDownloadableAttachment({ attachment });
49-
if (fcAttachment) {
50-
await this.attachmentUiRenderer(attachment.name, fcAttachment, signerKeys, emailBodyToParse);
51-
}
47+
const fcAttachments = await BrowserMsg.send.bg.await.thunderbirdGetDownloadableAttachment({ attachments });
48+
for (const fcAttachment of fcAttachments) {
49+
await this.attachmentUiRenderer(fcAttachment, signerKeys, emailBodyToParse);
5250
}
5351
}
5452
}
@@ -112,14 +110,17 @@ export class ThunderbirdElementReplacer extends WebmailElementReplacer {
112110
$('body').html(pgpBlock); // xss-sanitized
113111
};
114112

115-
private attachmentUiRenderer = async (attachmentName: string, fcAttachment: Buf, verificationPubs: string[], plaintext: string) => {
116-
if (attachmentName.endsWith('.pgp')) {
117-
const generatedPgpTemplate = this.generatePgpAttachmentTemplate(attachmentName, fcAttachment);
113+
private attachmentUiRenderer = async (fcAttachment: ThunderbirdAttachment, verificationPubs: string[], plaintext: string) => {
114+
if (fcAttachment.treatAs === 'encryptedFile') {
115+
const generatedPgpTemplate = this.generatePgpAttachmentTemplate(fcAttachment.name, fcAttachment.data);
118116
$('.pgp_attachments_block').append(generatedPgpTemplate); // xss-sanitized
119-
} else if (Attachment.encryptedMsgNames.some(a => attachmentName.includes(a)) && !this.emailBodyFromThunderbirdMail) {
120-
await this.messageDecrypt(verificationPubs, fcAttachment);
121-
} else if (attachmentName.endsWith('.asc')) {
122-
const sigText = new TextDecoder('utf-8').decode(fcAttachment).trim();
117+
} else if (
118+
(fcAttachment.treatAs === 'encryptedMsg' || Attachment.encryptedMsgNames.some(a => fcAttachment.name.includes(a))) &&
119+
!this.emailBodyFromThunderbirdMail
120+
) {
121+
await this.messageDecrypt(verificationPubs, fcAttachment.data);
122+
} else if (fcAttachment.treatAs === 'signature') {
123+
const sigText = new TextDecoder('utf-8').decode(fcAttachment.data).trim();
123124
if (this.resemblesSignedMsg(sigText)) {
124125
await this.messageVerify(verificationPubs, { plaintext, sigText });
125126
}

extension/js/service_worker/bg-handlers.ts

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -166,13 +166,32 @@ export class BgHandlers {
166166
public static thunderbirdGetDownloadableAttachment = async (
167167
r: Bm.ThunderbirdGetDownloadableAttachment
168168
): Promise<Bm.Res.ThunderbirdGetDownloadableAttachment> => {
169+
const processableAttachments: Bm.Res.ThunderbirdGetDownloadableAttachment = [];
169170
const [tab] = await messenger.mailTabs.query({ active: true, currentWindow: true });
170171
if (tab.id) {
171-
const rawAttachment = await messenger.messages.getAttachmentFile(tab.id, r.attachment.partName);
172-
const data = new Uint8Array(await rawAttachment.arrayBuffer());
173-
return new Attachment({ data }).getData();
172+
const fcAttachments: Attachment[] = [];
173+
// convert Thunderbird Attachments to FlowCrypt recognizable Attachments
174+
for (const tbAttachment of r.attachments) {
175+
const rawAttachment = await messenger.messages.getAttachmentFile(tab.id, tbAttachment.partName);
176+
fcAttachments.push(
177+
new Attachment({
178+
data: new Uint8Array(await rawAttachment.arrayBuffer()),
179+
type: tbAttachment.contentType,
180+
name: tbAttachment.name,
181+
length: tbAttachment.size,
182+
})
183+
);
184+
}
185+
for (const fcAttachment of fcAttachments) {
186+
processableAttachments.push({
187+
name: fcAttachment.name,
188+
contentType: fcAttachment.type,
189+
data: fcAttachment.getData(),
190+
treatAs: fcAttachment.treatAs(fcAttachments),
191+
});
192+
}
174193
}
175-
return;
194+
return processableAttachments;
176195
};
177196

178197
public static thunderbirdInitiateAttachmentDownload = async (

0 commit comments

Comments
 (0)