From 1e16d4aafe473626cc3ec4c6ef3b409d4956f2e8 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Wed, 14 Apr 2021 04:19:51 -0400 Subject: [PATCH 1/9] allow lookupEmail return several keys --- .../compose-modules/compose-storage-module.ts | 29 +++++++++++++------ .../pgp-block-signature-module.ts | 13 ++++----- .../chrome/settings/setup/setup-render.ts | 4 +-- extension/js/common/api/key-server/wkd.ts | 17 +++++------ extension/js/common/api/pub-lookup.ts | 15 ++++++---- extension/js/common/browser/browser-msg.ts | 13 +++++++-- .../webmail/gmail-element-replacer.ts | 2 +- 7 files changed, 58 insertions(+), 35 deletions(-) diff --git a/extension/chrome/elements/compose-modules/compose-storage-module.ts b/extension/chrome/elements/compose-modules/compose-storage-module.ts index 76cd8560714..9e4b5187f70 100644 --- a/extension/chrome/elements/compose-modules/compose-storage-module.ts +++ b/extension/chrome/elements/compose-modules/compose-storage-module.ts @@ -14,7 +14,7 @@ import { ComposeView } from '../compose.js'; import { KeyStore } from '../../../js/common/platform/store/key-store.js'; import { AcctStore } from '../../../js/common/platform/store/acct-store.js'; import { GlobalStore } from '../../../js/common/platform/store/global-store.js'; -import { ContactStore } from '../../../js/common/platform/store/contact-store.js'; +import { ContactStore, ContactUpdate } from '../../../js/common/platform/store/contact-store.js'; import { PassphraseStore } from '../../../js/common/platform/store/passphrase-store.js'; import { Settings } from '../../../js/common/settings.js'; import { Ui } from '../../../js/common/browser/ui.js'; @@ -102,20 +102,31 @@ export class ComposeStorageModule extends ViewModule { try { const lookupResult = await this.view.pubLookup.lookupEmail(email); if (lookupResult && email) { - if (lookupResult.pubkey) { - const key = await KeyUtil.parse(lookupResult.pubkey); + const pubkeys: Key[] = []; + for (const pubkey of lookupResult.pubkeys) { + const key = await KeyUtil.parse(pubkey); if (!key.usableForEncryption && !KeyUtil.expired(key)) { // Not to skip expired keys console.info('Dropping found+parsed key because getEncryptionKeyPacket===null', { for: email, fingerprint: key.id }); Ui.toast(`Public Key retrieved for email ${email} with id ${key.id} was ignored because it's not usable for encryption.`, 5); - lookupResult.pubkey = null; // tslint:disable-line:no-null-keyword + } else { + pubkeys.push(key); } } - const ksContact = await ContactStore.obj({ email, name, pubkey: lookupResult.pubkey, lastCheck: Date.now() }); - if (ksContact.pubkey) { - this.ksLookupsByEmail[email] = ksContact.pubkey; + // save multiple pubkeys as separate operations + // todo: add a convenient method to storage? + const updates: ContactUpdate[] = []; + if (!pubkeys.length && name) { + // update just name + updates.push({ name } as ContactUpdate); } - await ContactStore.save(undefined, ksContact); - return ksContact; + for (const pubkey of pubkeys) { + updates.push({ name, pubkey, pubkeyLastCheck: Date.now() }); + } + if (updates.length) { + await Promise.all(updates.map(async (update) => await ContactStore.update(undefined, email, update))); + } + const [preferred] = await ContactStore.get(undefined, [email]); + return preferred ?? PUBKEY_LOOKUP_RESULT_FAIL; } else { return PUBKEY_LOOKUP_RESULT_FAIL; } diff --git a/extension/chrome/elements/pgp_block_modules/pgp-block-signature-module.ts b/extension/chrome/elements/pgp_block_modules/pgp-block-signature-module.ts index a1022a9783e..c7a2822f3de 100644 --- a/extension/chrome/elements/pgp_block_modules/pgp-block-signature-module.ts +++ b/extension/chrome/elements/pgp_block_modules/pgp-block-signature-module.ts @@ -9,7 +9,6 @@ import { PgpBlockView } from '../pgp_block'; import { Ui } from '../../../js/common/browser/ui.js'; import { VerifyRes } from '../../../js/common/core/crypto/pgp/msg-util.js'; import { ContactStore } from '../../../js/common/platform/store/contact-store.js'; -import { OpenPGPKey } from '../../../js/common/core/crypto/pgp/openpgp-key.js'; import { Str } from '../../../js/common/core/common.js'; export class PgpBlockViewSignatureModule { @@ -60,19 +59,19 @@ export class PgpBlockViewSignatureModule { return; } // ---> and user doesn't have pubkey for that email addr - const { pubkey } = await this.view.pubLookup.lookupEmail(senderEmail); - if (!pubkey) { + const { pubkeys } = await this.view.pubLookup.lookupEmail(senderEmail); + if (!pubkeys.length) { render(`Missing pubkey ${signerLongid}`, () => undefined); return; } // ---> and pubkey found on keyserver by sender email - const { key } = await BrowserMsg.send.bg.await.keyParse({ armored: pubkey }); - if (!key.allIds.map(id => OpenPGPKey.fingerprintToLongid(id)).includes(signerLongid)) { - render(`Fetched sender's pubkey ${OpenPGPKey.fingerprintToLongid(key.id)} but message was signed with a different key: ${signerLongid}, will not verify.`, () => undefined); + const { key: pubkey } = await BrowserMsg.send.bg.await.keyMatch({ pubkeys, longid: signerLongid }); + if (!pubkey) { + render(`Fetched ${pubkeys.length} sender's pubkeys but message was signed with a different key: ${signerLongid}, will not verify.`, () => undefined); return; } // ---> and longid it matches signature - await ContactStore.save(undefined, await ContactStore.obj({ email: senderEmail, pubkey })); // <= TOFU auto-import + await ContactStore.update(undefined, senderEmail, { pubkey }); // <= TOFU auto-import render('Fetched pubkey, click to verify', () => window.location.reload()); } else { // don't know who sent it render('Cannot verify: missing pubkey, missing sender info', () => undefined); diff --git a/extension/chrome/settings/setup/setup-render.ts b/extension/chrome/settings/setup/setup-render.ts index 01dcee66fd5..25f9d4e0525 100644 --- a/extension/chrome/settings/setup/setup-render.ts +++ b/extension/chrome/settings/setup/setup-render.ts @@ -98,8 +98,8 @@ export class SetupRenderModule { } catch (e) { return await Settings.promptToRetry(e, Lang.setup.failedToCheckIfAcctUsesEncryption, () => this.renderSetupDialog()); } - if (keyserverRes.pubkey) { - const pub = await KeyUtil.parse(keyserverRes.pubkey); + if (keyserverRes.pubkeys.length) { + const pub = await KeyUtil.parse(keyserverRes.pubkeys[0]); // todo: ? this.view.acctEmailAttesterPubId = pub.id; if (!this.view.orgRules.canBackupKeys()) { // they already have a key recorded on attester, but no backups allowed on the domain. They should enter their prv manually diff --git a/extension/js/common/api/key-server/wkd.ts b/extension/js/common/api/key-server/wkd.ts index d2f3087e661..8f1b860645b 100644 --- a/extension/js/common/api/key-server/wkd.ts +++ b/extension/js/common/api/key-server/wkd.ts @@ -6,7 +6,7 @@ import { Api } from './../shared/api.js'; import { ApiErr } from '../shared/api-error.js'; import { opgp } from '../../core/crypto/pgp/openpgpjs-custom.js'; import { Buf } from '../../core/buf.js'; -import { PubkeySearchResult } from './../pub-lookup.js'; +import { PubkeysSearchResult } from './../pub-lookup.js'; import { Key, KeyUtil } from '../../core/crypto/key.js'; import { Str } from '../../core/common.js'; @@ -64,22 +64,21 @@ export class Wkd extends Api { return await KeyUtil.readMany(response.buf); } - public lookupEmail = async (email: string): Promise => { + public lookupEmail = async (email: string): Promise => { const { keys, errs } = await this.rawLookupEmail(email); if (errs.length) { - return { pubkey: null, pgpClient: null }; + return { pubkeys: [], pgpClient: null }; } - const key = keys.find(key => key.usableForEncryption && key.emails.some(x => x.toLowerCase() === email.toLowerCase())); - if (!key) { - return { pubkey: null, pgpClient: null }; + const pubkeys = keys.filter(key => key.emails.some(x => x.toLowerCase() === email.toLowerCase())); + if (!pubkeys.length) { + return { pubkeys: [], pgpClient: null }; } // if recipient uses same domain, we assume they use flowcrypt const pgpClient = this.myOwnDomain === Str.getDomainFromEmailAddress(email) ? 'flowcrypt' : 'pgp-other'; try { - const pubkey = KeyUtil.armor(key); - return { pubkey, pgpClient }; + return { pubkeys: pubkeys.map(pubkey => KeyUtil.armor(pubkey)), pgpClient }; } catch (e) { - return { pubkey: null, pgpClient: null }; + return { pubkeys: [], pgpClient: null }; } } diff --git a/extension/js/common/api/pub-lookup.ts b/extension/js/common/api/pub-lookup.ts index 9ae4a83dafb..eca2c4c4743 100644 --- a/extension/js/common/api/pub-lookup.ts +++ b/extension/js/common/api/pub-lookup.ts @@ -10,6 +10,7 @@ import { OrgRules } from '../org-rules.js'; export type PgpClient = 'flowcrypt' | 'pgp-other' | null; export type PubkeySearchResult = { pubkey: string | null; pgpClient: PgpClient }; +export type PubkeysSearchResult = { pubkeys: string[]; pgpClient: PgpClient }; /** * Look up public keys. @@ -39,24 +40,28 @@ export class PubLookup { } } - public lookupEmail = async (email: string): Promise => { + public lookupEmail = async (email: string): Promise => { if (this.keyManager) { const res = await this.keyManager.lookupPublicKey(email); if (res.publicKeys.length) { - return { pubkey: res.publicKeys[0].publicKey, pgpClient: 'flowcrypt' }; + return { pubkeys: res.publicKeys.map(x => x.publicKey), pgpClient: 'flowcrypt' }; } } const wkdRes = await this.wkd.lookupEmail(email); - if (wkdRes.pubkey) { + if (wkdRes.pubkeys.length) { return wkdRes; } if (this.internalSks) { const res = await this.internalSks.lookupEmail(email); if (res.pubkey) { - return res; + return { pubkeys: [res.pubkey], pgpClient: res.pgpClient }; } } - return await this.attester.lookupEmail(email); + const attRes = await this.attester.lookupEmail(email); + if (attRes.pubkey) { + return { pubkeys: [attRes.pubkey], pgpClient: attRes.pgpClient }; + } + return { pubkeys: [], pgpClient: null }; // tslint:disable-line:no-null-keyword } public lookupFingerprint = async (fingerprintOrLongid: string): Promise => { diff --git a/extension/js/common/browser/browser-msg.ts b/extension/js/common/browser/browser-msg.ts index 1ca9e1e0c56..c39f10af1fb 100644 --- a/extension/js/common/browser/browser-msg.ts +++ b/extension/js/common/browser/browser-msg.ts @@ -18,6 +18,7 @@ import { Ui } from './ui.js'; import { GlobalStoreDict, GlobalIndex } from '../platform/store/global-store.js'; import { AcctStoreDict, AccountIndex } from '../platform/store/acct-store.js'; import { Contact, Key, KeyUtil } from '../core/crypto/key.js'; +import { OpenPGPKey } from '../core/crypto/pgp/openpgp-key.js'; export type GoogleAuthWindowResult$result = 'Success' | 'Denied' | 'Error' | 'Closed'; @@ -62,6 +63,7 @@ export namespace Bm { export type PgpHashChallengeAnswer = { answer: string }; export type PgpMsgType = PgpMsgMethod.Arg.Type; export type KeyParse = { armored: string }; + export type KeyMatch = { pubkeys: string[], longid: string }; export type Ajax = { req: JQueryAjaxSettings, stack: string }; export type AjaxGmailAttachmentGetChunk = { acctEmail: string, msgId: string, attachmentId: string }; export type ShowAttachmentPreview = { iframeUrl: string }; @@ -82,6 +84,7 @@ export namespace Bm { export type PgpMsgType = PgpMsgTypeResult; export type PgpHashChallengeAnswer = { hashed: string }; export type KeyParse = { key: Key }; + export type KeyMatch = { key: Key | undefined }; export type AjaxGmailAttachmentGetChunk = { chunk: Buf }; export type _tab_ = { tabId: string | null | undefined }; export type Db = any; // not included in Any below @@ -90,7 +93,7 @@ export namespace Bm { export type Any = GetActiveTabInfo | _tab_ | ReconnectAcctAuthPopup | PgpMsgDecrypt | PgpMsgDiagnoseMsgPubkeys | PgpMsgVerify | PgpHashChallengeAnswer | PgpMsgType | KeyParse | StoreSessionGet | StoreSessionSet | StoreAcctGet | StoreAcctSet | StoreGlobalGet | StoreGlobalSet - | AjaxGmailAttachmentGetChunk; + | AjaxGmailAttachmentGetChunk | KeyMatch; } export type AnyRequest = PassphraseEntry | StripeResult | OpenPage | OpenGoogleAuthDialog | Redirect | Reload | @@ -99,7 +102,7 @@ export namespace Bm { NotificationShow | PassphraseDialog | PassphraseDialog | Settings | SetCss | AddOrRemoveClass | ReconnectAcctAuthPopup | Db | StoreSessionSet | StoreSessionGet | StoreGlobalGet | StoreGlobalSet | StoreAcctGet | StoreAcctSet | KeyParse | PgpMsgDecrypt | PgpMsgDiagnoseMsgPubkeys | PgpMsgVerifyDetached | PgpHashChallengeAnswer | PgpMsgType | Ajax | FocusFrame | - ShowAttachmentPreview | ReRenderRecipient; + ShowAttachmentPreview | ReRenderRecipient | KeyMatch; // export type RawResponselessHandler = (req: AnyRequest) => Promise; // export type RawRespoHandler = (req: AnyRequest) => Promise; @@ -146,6 +149,7 @@ export class BrowserMsg { pgpMsgDecrypt: (bm: Bm.PgpMsgDecrypt) => BrowserMsg.sendAwait(undefined, 'pgpMsgDecrypt', bm, true) as Promise, pgpMsgVerifyDetached: (bm: Bm.PgpMsgVerifyDetached) => BrowserMsg.sendAwait(undefined, 'pgpMsgVerifyDetached', bm, true) as Promise, keyParse: (bm: Bm.KeyParse) => BrowserMsg.sendAwait(undefined, 'keyParse', bm, true) as Promise, + keyMatch: (bm: Bm.KeyMatch) => BrowserMsg.sendAwait(undefined, 'keyMatch', bm, true) as Promise, pgpMsgType: (bm: Bm.PgpMsgType) => BrowserMsg.sendAwait(undefined, 'pgpMsgType', bm, true) as Promise, }, }, @@ -244,6 +248,11 @@ export class BrowserMsg { BrowserMsg.bgAddListener('pgpMsgVerifyDetached', MsgUtil.verifyDetached); BrowserMsg.bgAddListener('pgpMsgType', MsgUtil.type); BrowserMsg.bgAddListener('keyParse', async (r: Bm.KeyParse) => ({ key: await KeyUtil.parse(r.armored) })); + BrowserMsg.bgAddListener('keyMatch', async (r: Bm.KeyMatch) => ({ + key: + (await Promise.all(r.pubkeys.map(async (pub) => await KeyUtil.parse(pub)))). + find(k => k.allIds.map(id => OpenPGPKey.fingerprintToLongid(id).includes(r.longid))) + })); } public static addListener = (name: string, handler: Handler) => { diff --git a/extension/js/content_scripts/webmail/gmail-element-replacer.ts b/extension/js/content_scripts/webmail/gmail-element-replacer.ts index fd5aa20600e..16e3d2e7079 100644 --- a/extension/js/content_scripts/webmail/gmail-element-replacer.ts +++ b/extension/js/content_scripts/webmail/gmail-element-replacer.ts @@ -693,7 +693,7 @@ export class GmailElementReplacer implements WebmailElementReplacer { const [contact] = await ContactStore.get(undefined, [email]); if (contact && contact.pubkey) { this.recipientHasPgpCache[email] = true; - } else if ((await this.pubLookup.lookupEmail(email)).pubkey) { + } else if ((await this.pubLookup.lookupEmail(email)).pubkeys.length) { this.recipientHasPgpCache[email] = true; } else { this.recipientHasPgpCache[email] = false; From bacf762c55ae522f66b36113eb6df0b46d208df4 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Wed, 14 Apr 2021 09:31:03 -0400 Subject: [PATCH 2/9] updated Wkd tests --- .../tests/browser-unit-tests/unit-Wkd.js | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/test/source/tests/browser-unit-tests/unit-Wkd.js b/test/source/tests/browser-unit-tests/unit-Wkd.js index 319e2f055ab..3261755362d 100644 --- a/test/source/tests/browser-unit-tests/unit-Wkd.js +++ b/test/source/tests/browser-unit-tests/unit-Wkd.js @@ -26,11 +26,11 @@ BROWSER_UNIT_TEST_NAME(`Wkd direct method`); wkd.port = 8001; let email; email = 'john.doe@localhost'; - if (!(await wkd.lookupEmail(email)).pubkey) { + if (!(await wkd.lookupEmail(email)).pubkeys.length) { throw Error(`Wkd for ${email} didn't return a pubkey`); } email = 'John.Doe@localhost'; - if (!(await wkd.lookupEmail(email)).pubkey) { + if (!(await wkd.lookupEmail(email)).pubkey.length) { throw Error(`Wkd for ${email} didn't return a pubkey`); } return 'pass'; @@ -42,30 +42,32 @@ BROWSER_UNIT_TEST_NAME(`Wkd advanced method`); wkd.port = 8001; let email; email = 'john.doe@localhost'; - if (!(await wkd.lookupEmail(email)).pubkey) { + if (!(await wkd.lookupEmail(email)).pubkeys.length) { throw Error(`Wkd for ${email} didn't return a pubkey`); } email = 'John.Doe@localHOST'; - if (!(await wkd.lookupEmail(email)).pubkey) { + if (!(await wkd.lookupEmail(email)).pubkeys.length) { throw Error(`Wkd for ${email} didn't return a pubkey`); } return 'pass'; })(); -BROWSER_UNIT_TEST_NAME(`Wkd client picks valid key among revoked keys`); +BROWSER_UNIT_TEST_NAME(`Wkd client returns all keys`); (async () => { const wkd = new Wkd('flowcrypt.com'); wkd.port = 8001; const email = 'some.revoked@localhost'; - const pubkey = (await wkd.lookupEmail(email)).pubkey; - if (!pubkey) { + const pubkeys = (await wkd.lookupEmail(email)).pubkeys; + if (!pubkeys.length) { throw Error(`Wkd for ${email} didn't return a pubkey`); } - const key = await KeyUtil.parse(pubkey); - if (key && key.id.toUpperCase() === 'D6662C5FB9BDE9DA01F3994AAA1EF832D8CCA4F2' && key.usableForEncryption) { + const ids = (await Promise.all(pubkeys.map(async(pubkey) => await KeyUtil.parse(pubkey)))).map(key => key.id.toUpperCase()); + if (ids.length === 3 && ids.includes('D6662C5FB9BDE9DA01F3994AAA1EF832D8CCA4F2') && + ids.includes('A5CFC8E8EA4AE69989FE2631097EEBF354259A5E') && + ids.includes('3930752556D57C46A1C56B63DE8538DDA1648C76')) { return 'pass'; } else { - return `Expected key with id=D6662C5FB9BDE9DA01F3994AAA1EF832D8CCA4F2 wasn't received`; + return "Expected keys weren't received"; } })(); @@ -74,7 +76,7 @@ BROWSER_UNIT_TEST_NAME(`Wkd advanced shouldn't fall back on direct if advanced p const wkd = new Wkd('flowcrypt.com'); wkd.port = 8001; const email = 'jack.advanced@localhost'; - if ((await wkd.lookupEmail(email)).pubkey) { + if ((await wkd.lookupEmail(email)).pubkeys.length) { throw Error(`Wkd for ${email} didn't expect a pubkey`); } return 'pass'; @@ -85,7 +87,7 @@ BROWSER_UNIT_TEST_NAME(`Wkd incorrect UID should fail`); const wkd = new Wkd('flowcrypt.com'); wkd.port = 8001; const email = 'incorrect@localhost'; - if ((await wkd.lookupEmail(email)).pubkey) { + if ((await wkd.lookupEmail(email)).pubkeys.length) { throw Error(`Wkd for ${email} didn't expect a pubkey`); } return 'pass'; @@ -95,7 +97,7 @@ BROWSER_UNIT_TEST_NAME(`Wkd should extract key for human@flowcrypt.com`); (async () => { const wkd = new Wkd('flowcrypt.com'); const email = 'human@flowcrypt.com'; - if (!(await wkd.lookupEmail(email)).pubkey) { + if (!(await wkd.lookupEmail(email)).pubkeys.length) { throw Error(`Wkd for ${email} didn't return a pubkey`); } return 'pass'; From 577457bcab975f769b080e4c4c34b1880404bd1c Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Wed, 14 Apr 2021 09:32:36 -0400 Subject: [PATCH 3/9] Added Key.revoked flag --- .../chrome/elements/compose-modules/compose-storage-module.ts | 2 +- extension/js/common/core/crypto/key.ts | 1 + extension/js/common/core/crypto/pgp/openpgp-key.ts | 1 + extension/js/common/core/crypto/smime/smime-key.ts | 2 ++ 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/extension/chrome/elements/compose-modules/compose-storage-module.ts b/extension/chrome/elements/compose-modules/compose-storage-module.ts index 9e4b5187f70..24fca310603 100644 --- a/extension/chrome/elements/compose-modules/compose-storage-module.ts +++ b/extension/chrome/elements/compose-modules/compose-storage-module.ts @@ -105,7 +105,7 @@ export class ComposeStorageModule extends ViewModule { const pubkeys: Key[] = []; for (const pubkey of lookupResult.pubkeys) { const key = await KeyUtil.parse(pubkey); - if (!key.usableForEncryption && !KeyUtil.expired(key)) { // Not to skip expired keys + if (!key.usableForEncryption && !key.revoked && !KeyUtil.expired(key)) { // Not to skip expired and revoked keys console.info('Dropping found+parsed key because getEncryptionKeyPacket===null', { for: email, fingerprint: key.id }); Ui.toast(`Public Key retrieved for email ${email} with id ${key.id} was ignored because it's not usable for encryption.`, 5); } else { diff --git a/extension/js/common/core/crypto/key.ts b/extension/js/common/core/crypto/key.ts index 2e87d6a802b..80f374fe1f7 100644 --- a/extension/js/common/core/crypto/key.ts +++ b/extension/js/common/core/crypto/key.ts @@ -23,6 +23,7 @@ export interface Key { id: string; // This is a fingerprint for OpenPGP keys and Serial Number for X.509 keys. allIds: string[]; // a list of fingerprints for OpenPGP key or a Serial Number for X.509 keys. created: number; + revoked: boolean; lastModified: number | undefined; // date of last signature, or undefined if never had valid signature expiration: number | undefined; // number of millis of expiration or undefined if never expires usableForEncryption: boolean; diff --git a/extension/js/common/core/crypto/pgp/openpgp-key.ts b/extension/js/common/core/crypto/pgp/openpgp-key.ts index feaeb16d96e..ef96664b39b 100644 --- a/extension/js/common/core/crypto/pgp/openpgp-key.ts +++ b/extension/js/common/core/crypto/pgp/openpgp-key.ts @@ -232,6 +232,7 @@ export class OpenPGPKey { curve: (algoInfo as any).curve as string | undefined, algorithmId: opgp.enums.publicKey[algoInfo.algorithm] }, + revoked: keyWithoutWeakPackets.revocationSignatures.length > 0 } as Key); (key as any)[internal] = keyWithoutWeakPackets; (key as any).rawKey = opgpKey; diff --git a/extension/js/common/core/crypto/smime/smime-key.ts b/extension/js/common/core/crypto/smime/smime-key.ts index 330639fb3a2..ae6dff25572 100644 --- a/extension/js/common/core/crypto/smime/smime-key.ts +++ b/extension/js/common/core/crypto/smime/smime-key.ts @@ -58,6 +58,7 @@ export class SmimeKey { fullyEncrypted: false, isPublic: certificate.publicKey && !certificate.privateKey, isPrivate: !!certificate.privateKey, + revoked: false // todo: } as Key; const headers = PgpArmor.headers('pkcs12'); (key as unknown as { raw: string }).raw = `${headers.begin}\n${forge.util.encode64(bytes)}\n${headers.end}`; @@ -109,6 +110,7 @@ export class SmimeKey { fullyEncrypted: false, isPublic: certificate.publicKey && !certificate.privateKey, isPrivate: !!certificate.privateKey, + revoked: false // todo: } as Key; (key as unknown as { rawArmored: string }).rawArmored = text; return key; From 2a9750742941ff2cbec59cfe9c27618de9e91145 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Wed, 14 Apr 2021 09:48:32 -0400 Subject: [PATCH 4/9] test fix --- test/source/tests/browser-unit-tests/unit-Wkd.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/source/tests/browser-unit-tests/unit-Wkd.js b/test/source/tests/browser-unit-tests/unit-Wkd.js index 3261755362d..242d9171825 100644 --- a/test/source/tests/browser-unit-tests/unit-Wkd.js +++ b/test/source/tests/browser-unit-tests/unit-Wkd.js @@ -30,7 +30,7 @@ BROWSER_UNIT_TEST_NAME(`Wkd direct method`); throw Error(`Wkd for ${email} didn't return a pubkey`); } email = 'John.Doe@localhost'; - if (!(await wkd.lookupEmail(email)).pubkey.length) { + if (!(await wkd.lookupEmail(email)).pubkeys.length) { throw Error(`Wkd for ${email} didn't return a pubkey`); } return 'pass'; From e306014b0b301844e853d1abecd361b7387fe6e5 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Wed, 14 Apr 2021 12:27:11 -0400 Subject: [PATCH 5/9] fix --- .../elements/compose-modules/compose-storage-module.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/extension/chrome/elements/compose-modules/compose-storage-module.ts b/extension/chrome/elements/compose-modules/compose-storage-module.ts index 24fca310603..82a3f3e6f40 100644 --- a/extension/chrome/elements/compose-modules/compose-storage-module.ts +++ b/extension/chrome/elements/compose-modules/compose-storage-module.ts @@ -115,9 +115,13 @@ export class ComposeStorageModule extends ViewModule { // save multiple pubkeys as separate operations // todo: add a convenient method to storage? const updates: ContactUpdate[] = []; - if (!pubkeys.length && name) { - // update just name - updates.push({ name } as ContactUpdate); + if (!pubkeys.length) { + if (name) { + // update just name + updates.push({ name } as ContactUpdate); + } else { + return ContactStore.obj({ email }); + } } for (const pubkey of pubkeys) { updates.push({ name, pubkey, pubkeyLastCheck: Date.now() }); From 38d3c548528b25736a3463f06e0969714dbe1287 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Wed, 14 Apr 2021 12:57:38 -0400 Subject: [PATCH 6/9] tslint fix --- .../chrome/elements/compose-modules/compose-storage-module.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension/chrome/elements/compose-modules/compose-storage-module.ts b/extension/chrome/elements/compose-modules/compose-storage-module.ts index 82a3f3e6f40..14b785b6866 100644 --- a/extension/chrome/elements/compose-modules/compose-storage-module.ts +++ b/extension/chrome/elements/compose-modules/compose-storage-module.ts @@ -120,7 +120,7 @@ export class ComposeStorageModule extends ViewModule { // update just name updates.push({ name } as ContactUpdate); } else { - return ContactStore.obj({ email }); + return await ContactStore.obj({ email }); } } for (const pubkey of pubkeys) { From bc934eaeaee7bc5353b8a7045ee8cfe90e7c617d Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Mon, 19 Apr 2021 07:22:07 -0400 Subject: [PATCH 7/9] removed extra directives --- extension/js/common/api/key-server/wkd.ts | 1 - extension/js/common/api/pub-lookup.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/extension/js/common/api/key-server/wkd.ts b/extension/js/common/api/key-server/wkd.ts index ab5d928332b..66dea82cfb6 100644 --- a/extension/js/common/api/key-server/wkd.ts +++ b/extension/js/common/api/key-server/wkd.ts @@ -9,7 +9,6 @@ import { Buf } from '../../core/buf.js'; import { PubkeysSearchResult } from './../pub-lookup.js'; import { Key, KeyUtil } from '../../core/crypto/key.js'; -// tslint:disable:no-null-keyword // tslint:disable:no-direct-ajax export class Wkd extends Api { diff --git a/extension/js/common/api/pub-lookup.ts b/extension/js/common/api/pub-lookup.ts index 901c623c591..29b36ed7c4a 100644 --- a/extension/js/common/api/pub-lookup.ts +++ b/extension/js/common/api/pub-lookup.ts @@ -60,7 +60,7 @@ export class PubLookup { if (attRes.pubkey) { return { pubkeys: [attRes.pubkey] }; } - return { pubkeys: [] }; // tslint:disable-line:no-null-keyword + return { pubkeys: [] }; } public lookupFingerprint = async (fingerprintOrLongid: string): Promise => { From 481cedddb0191fd93778c82a69c6a5a6a8cd0b15 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Wed, 21 Apr 2021 03:48:02 -0400 Subject: [PATCH 8/9] added a comment --- .../chrome/elements/compose-modules/compose-storage-module.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/extension/chrome/elements/compose-modules/compose-storage-module.ts b/extension/chrome/elements/compose-modules/compose-storage-module.ts index 14b785b6866..b095afb27d9 100644 --- a/extension/chrome/elements/compose-modules/compose-storage-module.ts +++ b/extension/chrome/elements/compose-modules/compose-storage-module.ts @@ -120,6 +120,7 @@ export class ComposeStorageModule extends ViewModule { // update just name updates.push({ name } as ContactUpdate); } else { + // No public key found. Returning early, nothing to update in local store below. return await ContactStore.obj({ email }); } } From 570d1c596b6a60f311335f4588f9ef51069d15ef Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Wed, 21 Apr 2021 04:02:04 -0400 Subject: [PATCH 9/9] removed unused acctEmailAttesterPubId --- extension/chrome/settings/setup.ts | 1 - extension/chrome/settings/setup/setup-render.ts | 2 -- 2 files changed, 3 deletions(-) diff --git a/extension/chrome/settings/setup.ts b/extension/chrome/settings/setup.ts index 45f38f21888..2660701cbce 100644 --- a/extension/chrome/settings/setup.ts +++ b/extension/chrome/settings/setup.ts @@ -62,7 +62,6 @@ export class SetupView extends View { public pubLookup!: PubLookup; public keyManager: KeyManager | undefined; // not set if no url in org rules - public acctEmailAttesterPubId: string | undefined; public fetchedKeyBackups: KeyInfo[] = []; public fetchedKeyBackupsUniqueLongids: string[] = []; public importedKeysUniqueLongids: string[] = []; diff --git a/extension/chrome/settings/setup/setup-render.ts b/extension/chrome/settings/setup/setup-render.ts index 6f185991585..138cd29924d 100644 --- a/extension/chrome/settings/setup/setup-render.ts +++ b/extension/chrome/settings/setup/setup-render.ts @@ -98,8 +98,6 @@ export class SetupRenderModule { return await Settings.promptToRetry(e, Lang.setup.failedToCheckIfAcctUsesEncryption, () => this.renderSetupDialog()); } if (keyserverRes.pubkeys.length) { - const pub = await KeyUtil.parse(keyserverRes.pubkeys[0]); // todo: ? - this.view.acctEmailAttesterPubId = pub.id; if (!this.view.orgRules.canBackupKeys()) { // they already have a key recorded on attester, but no backups allowed on the domain. They should enter their prv manually this.displayBlock('step_2b_manual_enter');