diff --git a/extension/chrome/elements/compose-modules/compose-draft-module.ts b/extension/chrome/elements/compose-modules/compose-draft-module.ts index fa94cb3a08e..c97779b1280 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 247b79d81d8..2bfbe2b1891 100644 --- a/extension/chrome/elements/compose-modules/compose-storage-module.ts +++ b/extension/chrome/elements/compose-modules/compose-storage-module.ts @@ -99,8 +99,7 @@ export class ComposeStorageModule extends ViewModule { public passphraseGet = async (senderKi?: KeyInfo) => { if (!senderKi) { - senderKi = await KeyStore.getFirst(this.view.acctEmail); - Assert.abortAndRenderErrorIfKeyinfoEmpty(senderKi); + senderKi = await KeyStore.getFirstRequired(this.view.acctEmail); } return await PassphraseStore.get(this.view.acctEmail, senderKi.fingerprints[0]); } 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 c189319de30..403c0c37b16 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 fd7d117f032..6927bd30270 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.fingerprints[0]); 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 d096a9389aa..ad9e425e297 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 6a1dcb8707c..324a791cd8a 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.fingerprints[0]); 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 7bd8b1cc158..219881e736c 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 0d2b176e2eb..349449ec807 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.getFirst(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/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..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.getFirst(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 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 f8f649a64f4..d465d210d64 100644 --- a/extension/js/common/platform/store/key-store.ts +++ b/extension/js/common/platform/store/key-store.ts @@ -4,6 +4,7 @@ import { KeyInfo, KeyInfoWithOptionalPp, KeyUtil } from '../../core/crypto/key.j import { AcctStore } from './acct-store.js'; import { PassphraseStore } from './passphrase-store.js'; import { AbstractStore } from './abstract-store.js'; +import { Assert } from '../../assert.js'; /** * Local store of account private keys @@ -21,11 +22,18 @@ export class KeyStore extends AbstractStore { return keys.filter(ki => fingerprints.includes(ki.fingerprints[0])); } - public static getFirst = async (acctEmail: string): Promise => { - const keys = await KeyStore.get(acctEmail); + 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 getAllWithOptionalPassPhrase = async (acctEmail: string): Promise => { const keys = await KeyStore.get(acctEmail); const withPp: KeyInfoWithOptionalPp[] = [];