Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
08cc689
wip: refactor
martgil Jul 24, 2024
dd6b230
wip: Register content script for Thunderbird
martgil Jul 24, 2024
87dea43
refactor: move Thunderbird event handler and content script registrat…
martgil Jul 24, 2024
951f944
wip: update manifest.json
martgil Jul 25, 2024
24e73d0
wip
martgil Jul 26, 2024
eb5a1b0
wip
martgil Jul 28, 2024
cd8dbb9
wip
martgil Jul 28, 2024
c4467b6
wip
martgil Jul 28, 2024
79c33b7
wip
martgil Jul 31, 2024
8ad4a5e
Merge remote-tracking branch 'origin/master' into issue-5667-added-me…
martgil Jul 31, 2024
183dfed
wip
martgil Jul 31, 2024
9e061d4
added functionality to obtain pgp message from a background script
martgil Jul 31, 2024
8cbe0ea
fix openpgp undefined in content-script
martgil Aug 1, 2024
e015143
wip
martgil Aug 1, 2024
3462ce6
Merge remote-tracking branch 'origin/master' into issue-5667-added-me…
martgil Aug 5, 2024
8b44889
Merge branch 'master' into issue-5667-added-message-decryption-on-thu…
martgil Aug 15, 2024
518d38b
Add "thunderbird_get_current_user" to BrowserMsg
martgil Aug 16, 2024
f3f99ab
Add "thunderbird_msg_decrypt" to BrowserMsg
martgil Aug 16, 2024
1472fd5
fix BrowserMsg listener names
martgil Aug 16, 2024
92b3263
Merge remote-tracking branch 'origin/master' into issue-5667-added-me…
martgil Aug 20, 2024
9afaf6e
wip
martgil Aug 21, 2024
abf898b
wip
martgil Aug 21, 2024
f901bc5
fix missing opgp reference in Thunderbird port
martgil Aug 21, 2024
ab34c37
Merge branch 'master' into issue-5667-added-message-decryption-on-thu…
martgil Aug 23, 2024
b719396
Added pgp message decryption
martgil Aug 24, 2024
fd54d62
fix failing test
martgil Aug 24, 2024
c19f7f4
run element replacer in heartbeat (runIntervalFunctionsPeriodically)
martgil Aug 24, 2024
8cf725f
Improved decrypted message rendering in Thunderbird
martgil Aug 24, 2024
25df0e6
Add cleartext signed message detection
martgil Aug 24, 2024
20a8b03
wip
martgil Aug 25, 2024
2cd3e47
Add signature verification in Thunderbird (cleartext message)
martgil Aug 25, 2024
7565afb
wip
martgil Aug 25, 2024
f89e496
wip: Better signature verification handling
martgil Aug 25, 2024
ba0ed46
wip
martgil Aug 25, 2024
cc7aba4
wip
martgil Aug 25, 2024
0dddb00
cleanup
martgil Aug 25, 2024
cf24357
Merge branch 'master' into issue-5667-added-message-decryption-on-thu…
martgil Aug 26, 2024
adafaa9
Add passphrase dialog prompt in Thunderbird
martgil Aug 27, 2024
8fba4f2
Add autoclose for completely unlock passphrase in Thunderbird
martgil Aug 27, 2024
3203a2f
add another case for encrypted message detection
martgil Aug 27, 2024
53589ef
fix unsafe assignment of an any value
martgil Aug 28, 2024
50ea4aa
better content script bundling
martgil Aug 28, 2024
d78693c
cleanup
martgil Aug 28, 2024
909684c
Add todo in preparation for post thunderbird development
martgil Aug 28, 2024
cb7765f
Merge branch 'master' into issue-5667-added-message-decryption-on-thu…
martgil Sep 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions extension/chrome/dev/export.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { Catch } from '../../js/common/platform/catch.js';
import { Gmail } from '../../js/common/api/email-provider/gmail/gmail.js';
import { Time } from '../../js/common/browser/time.js';
import { Url } from '../../js/common/core/common.js';
import { opgp } from '../../js/common/core/crypto/pgp/openpgpjs-custom.js';
import { opgp as openpgp } from '../../js/common/core/crypto/pgp/openpgpjs-custom.js';

Catch.try(async () => {
const uncheckedUrlParams = Url.parse(['acctEmail']);
Expand Down Expand Up @@ -123,7 +123,7 @@ Catch.try(async () => {
const pwd = prompt('Please enter encryption password');
if (pwd) {
print('encrypting..');
const encrypted = await opgp.encrypt({ format: 'binary', message: await opgp.createMessage({ binary: data }), passwords: [pwd] });
const encrypted = await openpgp.encrypt({ format: 'binary', message: await openpgp.createMessage({ binary: data }), passwords: [pwd] });
save(encrypted); // todo: test
} else {
save(data);
Expand Down
6 changes: 3 additions & 3 deletions extension/chrome/elements/compose.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { Ui } from '../../js/common/browser/ui.js';
import { PromiseCancellation, Url } from '../../js/common/core/common.js';
import { View } from '../../js/common/view.js';
import { XssSafeFactory } from '../../js/common/xss-safe-factory.js';
import { opgp } from '../../js/common/core/crypto/pgp/openpgpjs-custom.js';
import { opgp as openpgp } from '../../js/common/core/crypto/pgp/openpgpjs-custom.js';
import { ComposeAttachmentsModule } from './compose-modules/compose-attachments-module.js';
import { ComposeDraftModule } from './compose-modules/compose-draft-module.js';
import { ComposeErrModule } from './compose-modules/compose-err-module.js';
Expand Down Expand Up @@ -174,8 +174,8 @@ export class ComposeView extends View {
const storage = await AcctStore.get(this.acctEmail, ['sendAs', 'hide_message_password', 'fesUrl']);
this.clientConfiguration = await ClientConfiguration.newInstance(this.acctEmail);
if (this.clientConfiguration.shouldHideArmorMeta()) {
opgp.config.showComment = false;
opgp.config.showVersion = false;
openpgp.config.showComment = false;
openpgp.config.showVersion = false;
}
this.pubLookup = new PubLookup(this.clientConfiguration);
this.factory = new XssSafeFactory(this.acctEmail, this.tabId);
Expand Down
16 changes: 16 additions & 0 deletions extension/chrome/elements/passphrase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,20 @@ View.run(
BrowserMsg.send.passphraseEntry({ entered, initiatorFrameId });
};

private closeDialogPageOpenedExternally = async () => {
if (window.top === window.self) {
if (Catch.isThunderbirdMail()) {
const currentTab = await messenger.tabs.query({ active: true, currentWindow: true });
if (currentTab.length > 0) {
const tabId = currentTab[0].id;
if (tabId) {
await messenger.tabs.remove(tabId);
}
}
}
}
};

private submitHandler = async () => {
if (await this.bruteForceProtection.shouldDisablePassphraseCheck()) {
return;
Expand Down Expand Up @@ -237,10 +251,12 @@ View.run(
}
if (unlockCount && allPrivateKeys.length > 1) {
Ui.toast(`${unlockCount} of ${allPrivateKeys.length} keys ${unlockCount > 1 ? 'were' : 'was'} unlocked by this pass phrase`);
await this.closeDialogPageOpenedExternally();
}
if (atLeastOneMatched) {
await this.bruteForceProtection.passphraseCheckSucceed();
this.closeDialog(true, this.initiatorFrameId);
await this.closeDialogPageOpenedExternally();
} else {
await this.bruteForceProtection.passphraseCheckFailed();
this.renderFailedEntryPpPrompt();
Expand Down
8 changes: 4 additions & 4 deletions extension/chrome/settings/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { Gmail } from '../../js/common/api/email-provider/gmail/gmail.js';
import { Google } from '../../js/common/api/email-provider/gmail/google.js';
import { KeyImportUi } from '../../js/common/ui/key-import-ui.js';
import { Lang } from '../../js/common/lang.js';
import { opgp } from '../../js/common/core/crypto/pgp/openpgpjs-custom.js';
import { opgp as openpgp } from '../../js/common/core/crypto/pgp/openpgpjs-custom.js';
import { ClientConfiguration } from '../../js/common/client-configuration.js';
import { Settings } from '../../js/common/settings.js';
import { SetupCreateKeyModule } from './setup/setup-create-key.js';
Expand Down Expand Up @@ -124,9 +124,9 @@ export class SetupView extends View {
this.storage = await AcctStore.get(this.acctEmail, ['setup_done', 'email_provider', 'fesUrl']);
this.storage.email_provider = this.storage.email_provider || 'gmail';
this.clientConfiguration = await ClientConfiguration.newInstance(this.acctEmail);
if (this.clientConfiguration.shouldHideArmorMeta() && typeof opgp !== 'undefined') {
opgp.config.showComment = false;
opgp.config.showVersion = false;
if (this.clientConfiguration.shouldHideArmorMeta() && typeof openpgp !== 'undefined') {
openpgp.config.showComment = false;
openpgp.config.showVersion = false;
}
this.pubLookup = new PubLookup(this.clientConfiguration);
if (this.clientConfiguration.usesKeyManager() && this.idToken) {
Expand Down
2 changes: 1 addition & 1 deletion extension/css/cryptup.css
Original file line number Diff line number Diff line change
Expand Up @@ -1428,7 +1428,7 @@ td {
.backup_neutral {
border: none;
border-left: 4px solid #989898;
padding-left: 10px;
padding: 6px 10px;
}

.pgp_neutral .error_container {
Expand Down
4 changes: 2 additions & 2 deletions extension/js/common/api/key-server/wkd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { ApiErr } from '../shared/api-error.js';
import { Buf } from '../../core/buf.js';
import { PubkeysSearchResult } from './../pub-lookup.js';
import { WKD_API_HOST } from '../../core/const.js';
import { opgp } from '../../core/crypto/pgp/openpgpjs-custom.js';
import { opgp as openpgp } from '../../core/crypto/pgp/openpgpjs-custom.js';
import { ArmoredKeyIdentityWithEmails, KeyUtil } from '../../core/crypto/key.js';

export class Wkd extends Api {
Expand Down Expand Up @@ -52,7 +52,7 @@ export class Wkd extends Api {
if (!response.buf) {
return [];
}
if (typeof opgp !== 'undefined') {
if (typeof openpgp !== 'undefined') {
return await KeyUtil.parseAndArmorKeys(response.buf);
}
// in pgp-block.html there is no openpgp loaded for performance, use background
Expand Down
13 changes: 12 additions & 1 deletion extension/js/common/browser/browser-msg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ export namespace Bm {
export type ReRenderRecipient = { email: string };
export type PgpBlockRetry = { frameId: string; messageSender: Dest };
export type PgpBlockReady = { frameId: string; messageSender: Dest };
export type ThunderbirdOpenPassphraseDialog = { acctEmail: string; longids: string };

export namespace Res {
export type GetActiveTabInfo = {
Expand All @@ -112,6 +113,9 @@ export namespace Bm {
export type ExpirationCacheGet<V> = Promise<V | undefined>;
export type ExpirationCacheSet = Promise<void>;
export type ExpirationCacheDeleteExpired = Promise<void>;
export type ThunderbirdGetCurrentUser = string | undefined;
export type ThunderbirdMsgGet = messenger.messages.MessagePart | undefined;
export type ThunderbirdOpenPassphraseDialog = Promise<void>;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type Db = any; // not included in Any below
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand All @@ -128,7 +132,8 @@ export namespace Bm {
| ExpirationCacheSet
| ExpirationCacheDeleteExpired
| AjaxGmailAttachmentGetChunk
| ConfirmationResult;
| ConfirmationResult
| ThunderbirdMsgGet;
}

export type AnyRequest =
Expand Down Expand Up @@ -169,6 +174,7 @@ export namespace Bm {
| PgpBlockReady
| PgpBlockRetry
| ConfirmationResult
| ThunderbirdOpenPassphraseDialog
| Ajax;

export type AsyncRespondingHandler = (req: AnyRequest) => Promise<Res.Any>;
Expand Down Expand Up @@ -232,6 +238,11 @@ export class BrowserMsg {
BrowserMsg.sendAwait(undefined, 'expirationCacheSet', bm, true) as Promise<Bm.Res.ExpirationCacheSet>,
expirationCacheDeleteExpired: (bm: Bm.ExpirationCacheDeleteExpired) =>
BrowserMsg.sendAwait(undefined, 'expirationCacheDeleteExpired', bm, true) as Promise<Bm.Res.ExpirationCacheDeleteExpired>,
thunderbirdGetCurrentUser: () =>
BrowserMsg.sendAwait(undefined, 'thunderbirdGetCurrentUser', undefined, true) as Promise<Bm.Res.ThunderbirdGetCurrentUser>,
thunderbirdMsgGet: () => BrowserMsg.sendAwait(undefined, 'thunderbirdMsgGet', undefined, true) as Promise<Bm.Res.ThunderbirdMsgGet>,
thunderbirdOpenPassphraseDiaglog: (bm: Bm.ThunderbirdOpenPassphraseDialog) =>
BrowserMsg.sendAwait(undefined, 'thunderbirdOpenPassphraseDialog', bm, true) as Promise<Bm.Res.ThunderbirdOpenPassphraseDialog>,
},
},
passphraseEntry: (bm: Bm.PassphraseEntry) => {
Expand Down
2 changes: 1 addition & 1 deletion extension/js/common/browser/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export class Env {
}

public static async webmails(): Promise<WebMailName[]> {
return ['gmail']; // async because storage may be involved in the future
return ['gmail', 'thunderbird']; // async because storage may be involved in the future
}

public static getBaseUrl() {
Expand Down
12 changes: 6 additions & 6 deletions extension/js/common/core/crypto/key.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Buf } from '../buf.js';
import { Catch } from '../../platform/catch.js';
import { MsgBlockParser } from '../msg-block-parser.js';
import { PgpArmor } from './pgp/pgp-armor.js';
import { opgp } from './pgp/openpgpjs-custom.js';
import { opgp as openpgp } from './pgp/openpgpjs-custom.js';
import { OpenPGPKey } from './pgp/openpgp-key.js';
import type * as OpenPGP from 'openpgp';
import { SmimeKey } from './smime/smime-key.js';
Expand Down Expand Up @@ -210,7 +210,7 @@ export class KeyUtil {
allErr: Error[] = [];
let uncheckedOpgpKeyCount = 0;
try {
const keys = await opgp.readKeys({ binaryKeys: key }); // todo: opgp.readKey ?
const keys = await openpgp.readKeys({ binaryKeys: key }); // todo: openpgp.readKey ?
uncheckedOpgpKeyCount = keys.length;
for (const key of keys) {
try {
Expand Down Expand Up @@ -348,12 +348,12 @@ export class KeyUtil {
let keys: OpenPGP.Key[] = [];
armored = PgpArmor.normalize(armored, 'key');
if (RegExp(PgpArmor.headers('publicKey', 're').begin).test(armored)) {
keys = await opgp.readKeys({ armoredKeys: armored });
keys = await openpgp.readKeys({ armoredKeys: armored });
} else if (RegExp(PgpArmor.headers('privateKey', 're').begin).test(armored)) {
keys = await opgp.readKeys({ armoredKeys: armored });
keys = await openpgp.readKeys({ armoredKeys: armored });
} else if (RegExp(PgpArmor.headers('encryptedMsg', 're').begin).test(armored)) {
const packets = (await opgp.readMessage({ armoredMessage: armored })).packets;
keys = [type === 'publicKey' ? new opgp.PublicKey(packets) : new opgp.PrivateKey(packets)];
const packets = (await openpgp.readMessage({ armoredMessage: armored })).packets;
keys = [type === 'publicKey' ? new openpgp.PublicKey(packets) : new openpgp.PrivateKey(packets)];
}
for (const k of keys) {
for (const u of k.users) {
Expand Down
16 changes: 8 additions & 8 deletions extension/js/common/core/crypto/pgp/msg-util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Key, KeyInfoWithIdentity, KeyInfoWithIdentityAndOptionalPp, KeyUtil } f
import { ReplaceableMsgBlockType } from '../../msg-block.js';
import { Buf } from '../../buf.js';
import { PgpArmor, PreparedForDecrypt } from './pgp-armor.js';
import { opgp } from './openpgpjs-custom.js';
import { opgp as openpgp } from './openpgpjs-custom.js';
import type * as OpenPGP from 'openpgp';
import { KeyCache } from '../../../platform/key-cache.js';
import { SmimeKey, SmimeMsg } from '../smime/smime-key.js';
Expand Down Expand Up @@ -127,11 +127,11 @@ export class MsgUtil {
// 10XX XXXX - potential old pgp packet tag
tagNumber = (firstByte & 0b00111100) / 4; // 10TTTTLL where T is tag number bit. Division by 4 in place of two bit shifts. I hate bit shifts.
}
if (Object.values(opgp.enums.packet).includes(tagNumber)) {
if (Object.values(openpgp.enums.packet).includes(tagNumber)) {
// Indeed a valid OpenPGP packet tag number
// This does not 100% mean it's OpenPGP message
// But it's a good indication that it may be
const t = opgp.enums.packet;
const t = openpgp.enums.packet;
const msgTypes = [
t.publicKeyEncryptedSessionKey,
t.symEncryptedIntegrityProtectedData,
Expand Down Expand Up @@ -163,7 +163,7 @@ export class MsgUtil {
}

public static async verifyDetached({ plaintext, sigText, verificationPubs }: PgpMsgMethod.Arg.VerifyDetached) {
const message = await opgp.createMessage({ text: Str.with(plaintext) });
const message = await openpgp.createMessage({ text: Str.with(plaintext) });
try {
await message.appendSignature(sigText);
} catch (formatErr) {
Expand Down Expand Up @@ -220,8 +220,8 @@ export class MsgUtil {
// cleartext and PKCS#7 are gone by this line
const msg = prepared.message;
const packets = msg.packets;
const isSymEncrypted = packets.filter(p => p instanceof opgp.SymEncryptedSessionKeyPacket).length > 0;
const isPubEncrypted = packets.filter(p => p instanceof opgp.PublicKeyEncryptedSessionKeyPacket).length > 0;
const isSymEncrypted = packets.filter(p => p instanceof openpgp.SymEncryptedSessionKeyPacket).length > 0;
const isPubEncrypted = packets.filter(p => p instanceof openpgp.PublicKeyEncryptedSessionKeyPacket).length > 0;
if (isSymEncrypted && !isPubEncrypted && !msgPwd) {
return {
success: false,
Expand Down Expand Up @@ -256,7 +256,7 @@ export class MsgUtil {
isEncrypted,
};
}
if (msg.packets.filterByTag(opgp.enums.packet.symmetricallyEncryptedData).length) {
if (msg.packets.filterByTag(openpgp.enums.packet.symmetricallyEncryptedData).length) {
const noMdc =
'Security threat!\n\nMessage is missing integrity checks (MDC). ' +
' The sender should update their outdated software.\n\nDisplay the message at your own risk.';
Expand Down Expand Up @@ -287,7 +287,7 @@ export class MsgUtil {
}

public static async diagnosePubkeys({ armoredPubs, message }: PgpMsgMethod.Arg.DiagnosePubkeys) {
const m = await opgp.readMessage({ armoredMessage: Str.with(message) });
const m = await openpgp.readMessage({ armoredMessage: Str.with(message) });
const msgKeyIds = m.getEncryptionKeyIDs();
const localKeyIds: string[] = [];
for (const k of await Promise.all(armoredPubs.map(pub => KeyUtil.parse(pub)))) {
Expand Down
Loading
Loading