Skip to content

Commit 2789340

Browse files
committed
wip
1 parent ac59d1f commit 2789340

File tree

4 files changed

+48
-25
lines changed

4 files changed

+48
-25
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ export namespace Bm {
114114
export type ExpirationCacheSet = Promise<void>;
115115
export type ExpirationCacheDeleteExpired = Promise<void>;
116116
export type ThunderbirdGetCurrentUser = string | undefined;
117-
export type ThunderbirdMsgGet = messenger.messages.MessagePart | undefined;
117+
export type ThunderbirdMsgGet = { attachments: messenger.messages.MessageAttachment[]; messagePart: messenger.messages.MessagePart };
118118
export type ThunderbirdOpenPassphraseDialog = Promise<void>;
119119
// eslint-disable-next-line @typescript-eslint/no-explicit-any
120120
export type Db = any; // not included in Any below

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

Lines changed: 42 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,14 @@ export class ThunderbirdElementReplacer extends WebmailElementReplacer {
2727

2828
public replaceThunderbirdMsgPane = async () => {
2929
if (Catch.isThunderbirdMail()) {
30-
const fullMsg = await BrowserMsg.send.bg.await.thunderbirdMsgGet();
31-
if (!fullMsg) {
30+
const { messagePart, attachments } = await BrowserMsg.send.bg.await.thunderbirdMsgGet();
31+
if (!messagePart) {
3232
return;
3333
} else {
3434
const acctEmail = await BrowserMsg.send.bg.await.thunderbirdGetCurrentUser();
3535
const parsedPubs = (await ContactStore.getOneWithAllPubkeys(undefined, String(acctEmail)))?.sortedPubkeys ?? [];
3636
const signerKeys = parsedPubs.map(key => KeyUtil.armor(key.pubkey));
37-
if (this.isPublicKeyEncryptedMsg(fullMsg)) {
37+
if (this.isPublicKeyEncryptedMsg(messagePart)) {
3838
const result = await MsgUtil.decryptMessage({
3939
kisWithPp: await KeyStore.getAllWithOptionalPassPhrase(String(acctEmail)),
4040
encryptedData: this.emailBodyFromThunderbirdMail,
@@ -69,7 +69,7 @@ export class ThunderbirdElementReplacer extends WebmailElementReplacer {
6969
const pgpBlock = this.generatePgpBlockTemplate(decryptionErrorMsg, 'not signed', this.emailBodyFromThunderbirdMail);
7070
$('body').html(pgpBlock); // xss-sanitized
7171
}
72-
} else if (this.isCleartextMsg(fullMsg)) {
72+
} else if (this.isCleartextMsg(messagePart)) {
7373
const message = await openpgp.readCleartextMessage({ cleartextMessage: this.emailBodyFromThunderbirdMail });
7474
const result = await OpenPGPKey.verify(message, await ContactStore.getPubkeyInfos(undefined, signerKeys));
7575
let verificationStatus = '';
@@ -83,7 +83,17 @@ export class ThunderbirdElementReplacer extends WebmailElementReplacer {
8383
const pgpBlock = this.generatePgpBlockTemplate('not encrypted', verificationStatus, signedMessage);
8484
$('body').html(pgpBlock); // xss-sanitized
8585
}
86-
// todo: detached signed message via https://github.com/FlowCrypt/flowcrypt-browser/issues/5668
86+
}
87+
if (!attachments.length) {
88+
return;
89+
} else {
90+
for (const attachment of attachments) {
91+
const generatedPgpTemplate = this.generatePgpAttachmentTemplate(attachment.name);
92+
const pgpAttachmentHtml = $('<div>');
93+
pgpAttachmentHtml.html(generatedPgpTemplate); // xss-sanitized
94+
$('.pgp_attachments_block').append(pgpAttachmentHtml); // xss-sanitized
95+
// todo: detached signed message via https://github.com/FlowCrypt/flowcrypt-browser/issues/5668
96+
}
8797
}
8898
}
8999
};
@@ -98,17 +108,26 @@ export class ThunderbirdElementReplacer extends WebmailElementReplacer {
98108
<div class="pgp_block">
99109
<pre>${Xss.escape(messageToRender)}</pre>
100110
</div>
111+
<div class="pgp_attachments_block">
112+
</div>
101113
</div>`;
102114
};
103115

104-
private isCleartextMsg = (fullMsg: messenger.messages.MessagePart): boolean => {
116+
private generatePgpAttachmentTemplate = (attachmentName: string): string => {
117+
return `<div>
118+
<div class="attachment_name">${Xss.escape(attachmentName)}</div>
119+
</div>
120+
`;
121+
};
122+
123+
private isCleartextMsg = (messagePart: messenger.messages.MessagePart): boolean => {
105124
return (
106-
(fullMsg.headers &&
107-
'openpgp' in fullMsg.headers &&
108-
fullMsg.parts &&
109-
fullMsg.parts[0]?.parts?.length === 1 &&
110-
fullMsg.parts[0].parts[0].contentType === 'text/plain' &&
111-
this.resemblesCleartextMsg(fullMsg.parts[0].parts[0].body?.trim() || '')) ||
125+
(messagePart.headers &&
126+
'openpgp' in messagePart.headers &&
127+
messagePart.parts &&
128+
messagePart.parts[0]?.parts?.length === 1 &&
129+
messagePart.parts[0].parts[0].contentType === 'text/plain' &&
130+
this.resemblesCleartextMsg(messagePart.parts[0].parts[0].body?.trim() || '')) ||
112131
false
113132
);
114133
};
@@ -122,16 +141,18 @@ export class ThunderbirdElementReplacer extends WebmailElementReplacer {
122141
);
123142
};
124143

125-
private isPublicKeyEncryptedMsg = (fullMsg: messenger.messages.MessagePart): boolean => {
126-
if (fullMsg.headers && 'openpgp' in fullMsg.headers && fullMsg.parts) {
144+
private isPublicKeyEncryptedMsg = (messagePart: messenger.messages.MessagePart): boolean => {
145+
if (messagePart.headers && 'openpgp' in messagePart.headers && messagePart.parts) {
127146
return (
128-
(fullMsg.parts[0]?.parts?.length === 2 &&
129-
fullMsg.parts[0]?.parts[1].contentType === 'application/pgp-encrypted' &&
130-
this.resemblesAsciiArmoredMsg(fullMsg.parts[0]?.parts[0].body?.trim() || '')) ||
131-
(fullMsg.parts[0]?.parts?.length === 1 &&
132-
fullMsg.parts[0]?.contentType === 'multipart/mixed' &&
133-
this.resemblesAsciiArmoredMsg(fullMsg.parts[0]?.parts[0].body?.trim() || '')) ||
134-
(fullMsg.parts.length === 1 && fullMsg.parts[0]?.contentType === 'text/plain' && this.resemblesAsciiArmoredMsg(fullMsg.parts[0]?.body?.trim() || '')) ||
147+
(messagePart.parts[0]?.parts?.length === 2 &&
148+
messagePart.parts[0]?.parts[1].contentType === 'application/pgp-encrypted' &&
149+
this.resemblesAsciiArmoredMsg(messagePart.parts[0]?.parts[0].body?.trim() || '')) ||
150+
(messagePart.parts[0]?.parts?.length === 1 &&
151+
messagePart.parts[0]?.contentType === 'multipart/mixed' &&
152+
this.resemblesAsciiArmoredMsg(messagePart.parts[0]?.parts[0].body?.trim() || '')) ||
153+
(messagePart.parts.length === 1 &&
154+
messagePart.parts[0]?.contentType === 'text/plain' &&
155+
this.resemblesAsciiArmoredMsg(messagePart.parts[0]?.body?.trim() || '')) ||
135156
false
136157
);
137158
}

extension/js/service_worker/bg-handlers.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,10 +172,12 @@ export class BgHandlers {
172172
if (tab.id) {
173173
const message = await messenger.messageDisplay.getDisplayedMessage(tab.id);
174174
if (message?.id) {
175-
return await messenger.messages.getFull(Number(message.id));
175+
const attachments = await messenger.messages.listAttachments(message.id);
176+
const messagePart = await messenger.messages.getFull(message.id);
177+
return { attachments, messagePart };
176178
}
177179
}
178-
return;
180+
return { attachments: [], messagePart: {} as messenger.messages.MessagePart };
179181
};
180182

181183
public static thunderbirdOpenPassphraseDialog = async (r: Bm.ThunderbirdOpenPassphraseDialog): Promise<Bm.Res.ThunderbirdOpenPassphraseDialog> => {

tooling/build-types-and-manifests.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ addManifest(
6262
(manifest.browser_action as messenger._manifest._WebExtensionManifestAction).default_title = 'FlowCrypt';
6363
manifest.name = 'FlowCrypt Encryption for Thunderbird';
6464
manifest.description = 'Simple end-to-end encryption to secure email and attachments on Thunderbird';
65-
manifest.permissions = [...(manifestV3.permissions ?? []), 'compose', 'messagesRead', 'messagesUpdate', 'messagesModify', 'accountsRead'];
65+
manifest.permissions = [...(manifestV3.permissions ?? []), 'compose', 'downloads', 'messagesRead', 'messagesUpdate', 'messagesModify', 'accountsRead'];
6666
manifest.compose_action = {
6767
default_title: 'Secure Compose', // eslint-disable-line @typescript-eslint/naming-convention
6868
default_icon: '/img/logo/flowcrypt-logo-64-64.png', // eslint-disable-line @typescript-eslint/naming-convention

0 commit comments

Comments
 (0)