From 640e3dac36df9e66e9f7cc6495ce1fb5fde932d0 Mon Sep 17 00:00:00 2001 From: Tom J Date: Fri, 4 Dec 2020 19:29:42 +0000 Subject: [PATCH 1/4] issue 3108 first attempt splitting KeyStore.getFirst --- .../elements/compose-modules/compose-draft-module.ts | 2 +- .../elements/compose-modules/compose-render-module.ts | 2 +- .../elements/compose-modules/compose-storage-module.ts | 2 +- .../pgp_block_modules/pgp-block-decrypt-module.ts | 2 +- extension/chrome/settings/index.ts | 2 +- .../chrome/settings/modules/backup-automatic-module.ts | 4 +--- .../chrome/settings/modules/backup-manual-module.ts | 4 +--- extension/chrome/settings/modules/change_passphrase.ts | 3 +-- extension/chrome/settings/modules/keyserver.ts | 6 ++---- extension/chrome/settings/modules/security.ts | 2 +- extension/chrome/settings/modules/test_passphrase.ts | 3 +-- extension/chrome/settings/setup.ts | 3 +-- extension/js/common/api/email-provider/sendable-msg.ts | 2 +- extension/js/common/assert.ts | 2 +- extension/js/common/platform/store/key-store.ts | 9 ++++++++- 15 files changed, 23 insertions(+), 25 deletions(-) diff --git a/extension/chrome/elements/compose-modules/compose-draft-module.ts b/extension/chrome/elements/compose-modules/compose-draft-module.ts index 1a7daa5006e..dffe0f26ed0 100644 --- a/extension/chrome/elements/compose-modules/compose-draft-module.ts +++ b/extension/chrome/elements/compose-modules/compose-draft-module.ts @@ -316,7 +316,7 @@ export class ComposeDraftModule extends ViewModule { Xss.sanitizeRender(this.view.S.cached('prompt'), `${promptText}

close`).css({ display: 'block', height: '100%' }); } this.view.S.cached('prompt').find('a.action_open_passphrase_dialog').click(this.view.setHandler(async () => { - const primaryKi = await KeyStore.getFirst(this.view.acctEmail); + const primaryKi = await KeyStore.getFirstRequired(this.view.acctEmail); BrowserMsg.send.passphraseDialog(this.view.parentTabId, { type: 'draft', longids: [primaryKi.longid] }); })); this.view.S.cached('prompt').find('a.action_close').click(this.view.setHandler(() => this.view.renderModule.closeMsg())); diff --git a/extension/chrome/elements/compose-modules/compose-render-module.ts b/extension/chrome/elements/compose-modules/compose-render-module.ts index 4a344529180..78fa36bce60 100644 --- a/extension/chrome/elements/compose-modules/compose-render-module.ts +++ b/extension/chrome/elements/compose-modules/compose-render-module.ts @@ -207,7 +207,7 @@ export class ComposeRenderModule extends ViewModule {

I was not able to read your encrypted message because it was encrypted for a wrong key.

My current public key is attached below. Please update your records and send me a new encrypted message.

Thank you`); - const primaryKi = await KeyStore.getFirst(this.view.acctEmail); + const primaryKi = await KeyStore.getFirstRequired(this.view.acctEmail); const attachment = Attachment.keyinfoAsPubkeyAtt(primaryKi); this.view.attsModule.attach.addFile(new File([attachment.getData()], attachment.name)); this.view.sendBtnModule.popover.toggleItemTick($('.action-toggle-encrypt-sending-option'), 'encrypt', false); // don't encrypt diff --git a/extension/chrome/elements/compose-modules/compose-storage-module.ts b/extension/chrome/elements/compose-modules/compose-storage-module.ts index ba29b81ff0c..040ce62f94a 100644 --- a/extension/chrome/elements/compose-modules/compose-storage-module.ts +++ b/extension/chrome/elements/compose-modules/compose-storage-module.ts @@ -99,7 +99,7 @@ export class ComposeStorageModule extends ViewModule { public passphraseGet = async (senderKi?: KeyInfo) => { if (!senderKi) { - senderKi = await KeyStore.getFirst(this.view.acctEmail); + senderKi = await KeyStore.getFirstRequired(this.view.acctEmail); Assert.abortAndRenderErrorIfKeyinfoEmpty(senderKi); } return await PassphraseStore.get(this.view.acctEmail, senderKi.fingerprint); diff --git a/extension/chrome/elements/pgp_block_modules/pgp-block-decrypt-module.ts b/extension/chrome/elements/pgp_block_modules/pgp-block-decrypt-module.ts index 7d3cb546ff0..36da62e52b4 100644 --- a/extension/chrome/elements/pgp_block_modules/pgp-block-decrypt-module.ts +++ b/extension/chrome/elements/pgp_block_modules/pgp-block-decrypt-module.ts @@ -93,7 +93,7 @@ export class PgpBlockViewDecryptModule { this.view.renderModule.renderText('Decrypting...'); await this.decryptAndRender(encryptedData, optionalPwd); } else { - const primaryKi = await KeyStore.getFirst(this.view.acctEmail); + const primaryKi = await KeyStore.getFirstOptional(this.view.acctEmail); if (!result.longids.chosen && !primaryKi) { await this.view.errorModule.renderErr(Lang.pgpBlock.notProperlySetUp + this.view.errorModule.btnHtml('FlowCrypt settings', 'green settings'), undefined); } else if (result.error.type === DecryptErrTypes.keyMismatch) { diff --git a/extension/chrome/settings/index.ts b/extension/chrome/settings/index.ts index a41bd5dc1ad..687af0c520e 100644 --- a/extension/chrome/settings/index.ts +++ b/extension/chrome/settings/index.ts @@ -152,7 +152,7 @@ View.run(class SettingsView extends View { } })); $('.action_open_public_key_page').click(this.setHandler(async () => { - const ki = await KeyStore.getFirst(this.acctEmail!); + const ki = await KeyStore.getFirstRequired(this.acctEmail!); const escapedFp = Xss.escape(ki.fingerprint); await Settings.renderSubPage(this.acctEmail!, this.tabId, 'modules/my_key.htm', `&fingerprint=${escapedFp}`); })); diff --git a/extension/chrome/settings/modules/backup-automatic-module.ts b/extension/chrome/settings/modules/backup-automatic-module.ts index 06624b4d545..41763b04fcb 100644 --- a/extension/chrome/settings/modules/backup-automatic-module.ts +++ b/extension/chrome/settings/modules/backup-automatic-module.ts @@ -9,7 +9,6 @@ import { Settings } from '../../../js/common/settings.js'; import { UnreportableError } from '../../../js/common/platform/catch.js'; import { Ui } from '../../../js/common/browser/ui.js'; import { ApiErr } from '../../../js/common/api/shared/api-error.js'; -import { Assert } from '../../../js/common/assert.js'; import { GoogleAuth } from '../../../js/common/api/email-provider/gmail/google-auth.js'; import { KeyStore } from '../../../js/common/platform/store/key-store.js'; import { KeyUtil } from '../../../js/common/core/crypto/key.js'; @@ -25,12 +24,11 @@ export class BackupAutomaticModule extends ViewModule { } private setupCreateSimpleAutomaticInboxBackup = async () => { - const primaryKi = await KeyStore.getFirst(this.view.acctEmail); + const primaryKi = await KeyStore.getFirstRequired(this.view.acctEmail); if (!(await KeyUtil.parse(primaryKi.private)).fullyEncrypted) { await Ui.modal.warning('Key not protected with a pass phrase, skipping'); throw new UnreportableError('Key not protected with a pass phrase, skipping'); } - Assert.abortAndRenderErrorIfKeyinfoEmpty(primaryKi); try { await this.view.manualModule.doBackupOnEmailProvider(primaryKi.private); await this.view.renderBackupDone(); diff --git a/extension/chrome/settings/modules/backup-manual-module.ts b/extension/chrome/settings/modules/backup-manual-module.ts index 6315ccbaac4..c84742ee3d0 100644 --- a/extension/chrome/settings/modules/backup-manual-module.ts +++ b/extension/chrome/settings/modules/backup-manual-module.ts @@ -5,7 +5,6 @@ import { ViewModule } from '../../../js/common/view-module.js'; import { Xss } from '../../../js/common/platform/xss.js'; import { BackupView } from './backup.js'; -import { Assert } from '../../../js/common/assert.js'; import { Attachment } from '../../../js/common/core/attachment.js'; import { SendableMsg } from '../../../js/common/api/email-provider/sendable-msg.js'; import { GMAIL_RECOVERY_EMAIL_SUBJECTS } from '../../../js/common/core/const.js'; @@ -56,8 +55,7 @@ export class BackupManualActionModule extends ViewModule { private actionManualBackupHandler = async () => { const selected = $('input[type=radio][name=input_backup_choice]:checked').val(); - const primaryKi = await KeyStore.getFirst(this.view.acctEmail); - Assert.abortAndRenderErrorIfKeyinfoEmpty(primaryKi); + const primaryKi = await KeyStore.getFirstRequired(this.view.acctEmail); if (! await this.isPrivateKeyEncrypted(primaryKi)) { await Ui.modal.error('Sorry, cannot back up private key because it\'s not protected with a pass phrase.'); return; diff --git a/extension/chrome/settings/modules/change_passphrase.ts b/extension/chrome/settings/modules/change_passphrase.ts index 8d22fcf26a7..82e2919b184 100644 --- a/extension/chrome/settings/modules/change_passphrase.ts +++ b/extension/chrome/settings/modules/change_passphrase.ts @@ -38,9 +38,8 @@ View.run(class ChangePassPhraseView extends View { $('#step_0_enter_current #current_pass_phrase').attr('placeholder', 'Current primary key pass phrase'); $('#step_1_enter_new #new_pass_phrase').attr('placeholder', 'Enter a new primary key pass phrase'); } - const primaryKi = await KeyStore.getFirst(this.acctEmail); + const primaryKi = await KeyStore.getFirstRequired(this.acctEmail); this.primaryKi = primaryKi; - Assert.abortAndRenderErrorIfKeyinfoEmpty(this.primaryKi); const storedOrSessionPp = await PassphraseStore.get(this.acctEmail, this.primaryKi.fingerprint); const key = await KeyUtil.parse(this.primaryKi.private); this.primaryPrv = key; diff --git a/extension/chrome/settings/modules/keyserver.ts b/extension/chrome/settings/modules/keyserver.ts index d43dd5ee9d1..89e80cd3fe7 100644 --- a/extension/chrome/settings/modules/keyserver.ts +++ b/extension/chrome/settings/modules/keyserver.ts @@ -80,8 +80,7 @@ View.run(class KeyserverView extends View { return await Ui.modal.error('Disallowed by your organisation rules'); } Xss.sanitizeRender(target, Ui.spinner('white')); - const primaryKi = await KeyStore.getFirst(this.acctEmail); - Assert.abortAndRenderErrorIfKeyinfoEmpty(primaryKi); + const primaryKi = await KeyStore.getFirstRequired(this.acctEmail); try { await this.pubLookup.attester.initialLegacySubmit(String($(target).attr('email')), primaryKi.public); } catch (e) { @@ -97,8 +96,7 @@ View.run(class KeyserverView extends View { return await Ui.modal.error('Disallowed by your organisation rules'); } Xss.sanitizeRender(target, Ui.spinner('white')); - const primaryKi = await KeyStore.getFirst(this.acctEmail); - Assert.abortAndRenderErrorIfKeyinfoEmpty(primaryKi); + const primaryKi = await KeyStore.getFirstRequired(this.acctEmail); try { const responseText = await this.pubLookup.attester.replacePubkey(String($(target).attr('email')), primaryKi.public); await Ui.modal.info(responseText); diff --git a/extension/chrome/settings/modules/security.ts b/extension/chrome/settings/modules/security.ts index f0c4396f911..a2de261d157 100644 --- a/extension/chrome/settings/modules/security.ts +++ b/extension/chrome/settings/modules/security.ts @@ -39,7 +39,7 @@ View.run(class SecurityView extends View { public render = async () => { await initPassphraseToggle(['passphrase_entry']); - this.primaryKi = await KeyStore.getFirst(this.acctEmail); + this.primaryKi = await KeyStore.getFirstOptional(this.acctEmail); Assert.abortAndRenderErrorIfKeyinfoEmpty(this.primaryKi); this.authInfo = await AcctStore.authInfo(this.acctEmail); const storage = await AcctStore.get(this.acctEmail, ['hide_message_password', 'outgoing_language']); diff --git a/extension/chrome/settings/modules/test_passphrase.ts b/extension/chrome/settings/modules/test_passphrase.ts index bac41c331d1..cef715609c7 100644 --- a/extension/chrome/settings/modules/test_passphrase.ts +++ b/extension/chrome/settings/modules/test_passphrase.ts @@ -27,8 +27,7 @@ View.run(class TestPassphrase extends View { } public render = async () => { - const keyInfo = await KeyStore.getFirst(this.acctEmail); - Assert.abortAndRenderErrorIfKeyinfoEmpty(keyInfo); + const keyInfo = await KeyStore.getFirstRequired(this.acctEmail); await initPassphraseToggle(['password']); this.primaryKey = await KeyUtil.parse(keyInfo.private); if (!this.primaryKey.fullyEncrypted) { diff --git a/extension/chrome/settings/setup.ts b/extension/chrome/settings/setup.ts index 8bf68b6e203..e3256222aea 100644 --- a/extension/chrome/settings/setup.ts +++ b/extension/chrome/settings/setup.ts @@ -183,8 +183,7 @@ export class SetupView extends View { } public submitPublicKeysAndFinalizeSetup = async ({ submit_main, submit_all }: { submit_main: boolean, submit_all: boolean }): Promise => { - const primaryKi = await KeyStore.getFirst(this.acctEmail); - Assert.abortAndRenderErrorIfKeyinfoEmpty(primaryKi); + const primaryKi = await KeyStore.getFirstRequired(this.acctEmail); try { await this.submitPublicKeyIfNeeded(primaryKi.public, { submit_main, submit_all }); } catch (e) { diff --git a/extension/js/common/api/email-provider/sendable-msg.ts b/extension/js/common/api/email-provider/sendable-msg.ts index 83e5ac01951..c5f5d10d326 100644 --- a/extension/js/common/api/email-provider/sendable-msg.ts +++ b/extension/js/common/api/email-provider/sendable-msg.ts @@ -88,7 +88,7 @@ export class SendableMsg { } private static create = async (acctEmail: string, { from, recipients, subject, thread, body, attachments, type, isDraft }: SendableMsgDefinition): Promise => { - const primaryKi = await KeyStore.getFirst(acctEmail); + const primaryKi = await KeyStore.getFirstOptional(acctEmail); const headers: Dict = primaryKi ? { OpenPGP: `id=${primaryKi.longid}` } : {}; // todo - use autocrypt format return new SendableMsg( acctEmail, diff --git a/extension/js/common/assert.ts b/extension/js/common/assert.ts index c199a49ca49..2fd7bb3495e 100644 --- a/extension/js/common/assert.ts +++ b/extension/js/common/assert.ts @@ -35,7 +35,7 @@ export class Assert { public static abortAndRenderErrOnUnprotectedKey = async (acctEmail?: string, tabId?: string) => { if (acctEmail) { - const primaryKi = await KeyStore.getFirst(acctEmail); + const primaryKi = await KeyStore.getFirstOptional(acctEmail); const { setup_done } = await AcctStore.get(acctEmail, ['setup_done']); if (setup_done && primaryKi && !(await KeyUtil.parse(primaryKi.private)).fullyEncrypted) { if (window.location.pathname === '/chrome/settings/index.htm') { diff --git a/extension/js/common/platform/store/key-store.ts b/extension/js/common/platform/store/key-store.ts index a64ac2e0d16..891fa826f16 100644 --- a/extension/js/common/platform/store/key-store.ts +++ b/extension/js/common/platform/store/key-store.ts @@ -5,6 +5,7 @@ import { AcctStore } from './acct-store.js'; import { PassphraseStore } from './passphrase-store.js'; import { AbstractStore } from './abstract-store.js'; import { OpenPGPKey } from '../../core/crypto/pgp/openpgp-key.js'; +import { Assert } from '../../assert.js'; /** * Local store of account private keys @@ -20,12 +21,18 @@ export class KeyStore extends AbstractStore { return keys.filter(ki => fingerprints.includes(ki.fingerprint)); } - public static getFirst = async (acctEmail: string): Promise => { + public static getFirstOptional = async (acctEmail: string): Promise => { const stored = await AcctStore.get(acctEmail, ['keys']); const keys: KeyInfo[] = stored.keys || []; return keys[0]; } + public static getFirstRequired = async (acctEmail: string): Promise => { + const key = await KeyStore.getFirstOptional(acctEmail); + Assert.abortAndRenderErrorIfKeyinfoEmpty(key); + return key as KeyInfo; + } + public static getAllWithPp = async (acctEmail: string): Promise => { const keys = await KeyStore.get(acctEmail); for (const ki of keys) { From e067654347a79077f8f20b50ded60fc739be9c99 Mon Sep 17 00:00:00 2001 From: danishnavid008 Date: Thu, 10 Dec 2020 11:29:56 +0500 Subject: [PATCH 2/4] Replaced getFirstOptional with getFirstRequired wherever expected --- .../chrome/elements/compose-modules/compose-storage-module.ts | 1 - extension/chrome/settings/modules/security.ts | 3 +-- extension/js/common/api/email-provider/sendable-msg.ts | 2 +- extension/js/common/assert.ts | 2 +- 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/extension/chrome/elements/compose-modules/compose-storage-module.ts b/extension/chrome/elements/compose-modules/compose-storage-module.ts index 040ce62f94a..af68941b137 100644 --- a/extension/chrome/elements/compose-modules/compose-storage-module.ts +++ b/extension/chrome/elements/compose-modules/compose-storage-module.ts @@ -100,7 +100,6 @@ export class ComposeStorageModule extends ViewModule { public passphraseGet = async (senderKi?: KeyInfo) => { if (!senderKi) { senderKi = await KeyStore.getFirstRequired(this.view.acctEmail); - Assert.abortAndRenderErrorIfKeyinfoEmpty(senderKi); } return await PassphraseStore.get(this.view.acctEmail, senderKi.fingerprint); } diff --git a/extension/chrome/settings/modules/security.ts b/extension/chrome/settings/modules/security.ts index a2de261d157..6829df72a3d 100644 --- a/extension/chrome/settings/modules/security.ts +++ b/extension/chrome/settings/modules/security.ts @@ -39,8 +39,7 @@ View.run(class SecurityView extends View { public render = async () => { await initPassphraseToggle(['passphrase_entry']); - this.primaryKi = await KeyStore.getFirstOptional(this.acctEmail); - Assert.abortAndRenderErrorIfKeyinfoEmpty(this.primaryKi); + this.primaryKi = await KeyStore.getFirstRequired(this.acctEmail); this.authInfo = await AcctStore.authInfo(this.acctEmail); const storage = await AcctStore.get(this.acctEmail, ['hide_message_password', 'outgoing_language']); this.orgRules = await OrgRules.newInstance(this.acctEmail); diff --git a/extension/js/common/api/email-provider/sendable-msg.ts b/extension/js/common/api/email-provider/sendable-msg.ts index c5f5d10d326..d9464874d6c 100644 --- a/extension/js/common/api/email-provider/sendable-msg.ts +++ b/extension/js/common/api/email-provider/sendable-msg.ts @@ -88,7 +88,7 @@ export class SendableMsg { } private static create = async (acctEmail: string, { from, recipients, subject, thread, body, attachments, type, isDraft }: SendableMsgDefinition): Promise => { - const primaryKi = await KeyStore.getFirstOptional(acctEmail); + const primaryKi = await KeyStore.getFirstRequired(acctEmail); const headers: Dict = primaryKi ? { OpenPGP: `id=${primaryKi.longid}` } : {}; // todo - use autocrypt format return new SendableMsg( acctEmail, diff --git a/extension/js/common/assert.ts b/extension/js/common/assert.ts index 2fd7bb3495e..8634977407b 100644 --- a/extension/js/common/assert.ts +++ b/extension/js/common/assert.ts @@ -35,7 +35,7 @@ export class Assert { public static abortAndRenderErrOnUnprotectedKey = async (acctEmail?: string, tabId?: string) => { if (acctEmail) { - const primaryKi = await KeyStore.getFirstOptional(acctEmail); + const primaryKi = await KeyStore.getFirstRequired(acctEmail); const { setup_done } = await AcctStore.get(acctEmail, ['setup_done']); if (setup_done && primaryKi && !(await KeyUtil.parse(primaryKi.private)).fullyEncrypted) { if (window.location.pathname === '/chrome/settings/index.htm') { From ece36d621bb4d1f5155a05afdaa85e2fbd99277d Mon Sep 17 00:00:00 2001 From: danishnavid008 Date: Thu, 10 Dec 2020 11:44:24 +0500 Subject: [PATCH 3/4] adding changes --- extension/js/common/assert.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension/js/common/assert.ts b/extension/js/common/assert.ts index 8634977407b..2fd7bb3495e 100644 --- a/extension/js/common/assert.ts +++ b/extension/js/common/assert.ts @@ -35,7 +35,7 @@ export class Assert { public static abortAndRenderErrOnUnprotectedKey = async (acctEmail?: string, tabId?: string) => { if (acctEmail) { - const primaryKi = await KeyStore.getFirstRequired(acctEmail); + const primaryKi = await KeyStore.getFirstOptional(acctEmail); const { setup_done } = await AcctStore.get(acctEmail, ['setup_done']); if (setup_done && primaryKi && !(await KeyUtil.parse(primaryKi.private)).fullyEncrypted) { if (window.location.pathname === '/chrome/settings/index.htm') { From 92e3c85b9b83785a39e3889d141749f61c125b3d Mon Sep 17 00:00:00 2001 From: danishnavid008 Date: Sat, 12 Dec 2020 00:51:40 +0500 Subject: [PATCH 4/4] adding changes --- extension/chrome/settings/modules/change_passphrase.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/extension/chrome/settings/modules/change_passphrase.ts b/extension/chrome/settings/modules/change_passphrase.ts index e20aee15f2f..324a791cd8a 100644 --- a/extension/chrome/settings/modules/change_passphrase.ts +++ b/extension/chrome/settings/modules/change_passphrase.ts @@ -73,7 +73,6 @@ View.run(class ChangePassPhraseView extends View { await Ui.modal.error('Pass phrase did not match, please try again.'); $('#current_pass_phrase').val('').focus(); } - Assert.abortAndRenderErrorIfKeyinfoEmpty(this.primaryKi); } private actionSetPassPhraseHandler = async (target: HTMLElement) => {