Skip to content

Commit d2efdfc

Browse files
yantakusTom J
andauthored
issue #409 all keys treated equally (#3086)
* Dummy commit. * Remove unused types. * Remove primary key. * Rename 'myPrivateKeys' field to 'keysWeNeedPassPhraseFor'. * Disallow removing the last key. * Add KeyStore.getAll method. Refactor KeyStore.get(this.view.acctEmail, ['primary']) usages. * Refactor the rest of ['primary'] usages. * Ensure KeyStore.getFirst returns a key or throws an error. * Refactor KeyStore.get method. * Rename KeyStore.getFirst to .getFirstOrRenderError. * Revert KeyStore.getFirst -> getFirstOrRenderError (lots of tests were failing). * Fix failing 'settings - verify key presense 1pp1' test. * Fix my key page issue properly. * Fix `compose - own key expired` failing test. * Made my_key page fingerprint url param required. * Make fingerprint URL param required for my_key_update page. * Fix my_key page issue. * Refactor my_key page click handler. * fix key update link when expired Co-authored-by: Tom J <tom@holub.me>
1 parent 9d1b2e1 commit d2efdfc

File tree

23 files changed

+55
-66
lines changed

23 files changed

+55
-66
lines changed

extension/chrome/elements/compose-modules/compose-draft-module.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -315,8 +315,9 @@ export class ComposeDraftModule extends ViewModule<ComposeView> {
315315
} else {
316316
Xss.sanitizeRender(this.view.S.cached('prompt'), `${promptText}<br><br><a href="#" class="action_close">close</a>`).css({ display: 'block', height: '100%' });
317317
}
318-
this.view.S.cached('prompt').find('a.action_open_passphrase_dialog').click(this.view.setHandler(() => {
319-
BrowserMsg.send.passphraseDialog(this.view.parentTabId, { type: 'draft', longids: ['primary'] });
318+
this.view.S.cached('prompt').find('a.action_open_passphrase_dialog').click(this.view.setHandler(async () => {
319+
const primaryKi = await KeyStore.getFirst(this.view.acctEmail);
320+
BrowserMsg.send.passphraseDialog(this.view.parentTabId, { type: 'draft', longids: [primaryKi.longid] });
320321
}));
321322
this.view.S.cached('prompt').find('a.action_close').click(this.view.setHandler(() => this.view.renderModule.closeMsg()));
322323
await this.view.storageModule.whenMasterPassphraseEntered();

extension/chrome/elements/compose-modules/compose-render-module.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ export class ComposeRenderModule extends ViewModule<ComposeView> {
198198
<br><br>I was not able to read your encrypted message because it was encrypted for a wrong key.
199199
<br><br>My current public key is attached below. Please update your records and send me a new encrypted message.
200200
<br><br>Thank you</div>`);
201-
const [primaryKi] = await KeyStore.get(this.view.acctEmail, ['primary']);
201+
const primaryKi = await KeyStore.getFirst(this.view.acctEmail);
202202
const att = Att.keyinfoAsPubkeyAtt(primaryKi);
203203
this.view.attsModule.attach.addFile(new File([att.getData()], att.name));
204204
this.view.sendBtnModule.popover.toggleItemTick($('.action-toggle-encrypt-sending-option'), 'encrypt', false); // don't encrypt

extension/chrome/elements/compose-modules/compose-storage-module.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export class ComposeStorageModule extends ViewModule<ComposeView> {
3939
let result = await this.view.myPubkeyModule.chooseMyPublicKeyBySenderEmail(keys, senderEmail);
4040
if (!result) {
4141
this.view.errModule.debug(`ComposerStorage.getKey: could not find key based on senderEmail: ${senderEmail}, using primary instead`);
42-
result = keys.find(ki => ki.primary);
42+
result = keys[0];
4343
Assert.abortAndRenderErrorIfKeyinfoEmpty(result);
4444
} else {
4545
this.view.errModule.debug(`ComposerStorage.getKey: found key based on senderEmail: ${senderEmail}`);
@@ -100,7 +100,7 @@ export class ComposeStorageModule extends ViewModule<ComposeView> {
100100

101101
public passphraseGet = async (senderKi?: KeyInfo) => {
102102
if (!senderKi) {
103-
[senderKi] = await KeyStore.get(this.view.acctEmail, ['primary']);
103+
senderKi = await KeyStore.getFirst(this.view.acctEmail);
104104
Assert.abortAndRenderErrorIfKeyinfoEmpty(senderKi);
105105
}
106106
return await PassphraseStore.get(this.view.acctEmail, senderKi.fingerprint);

extension/chrome/elements/compose-modules/formatters/encrypted-mail-msg-formatter.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { BaseMailFormatter } from './base-mail-formatter.js';
77
import { ComposerResetBtnTrigger } from '../compose-err-module.js';
88
import { Mime, SendableMsgBody } from '../../../../js/common/core/mime.js';
99
import { NewMsgData } from '../compose-types.js';
10-
import { Str, Value } from '../../../../js/common/core/common.js';
10+
import { Str, Url, Value } from '../../../../js/common/core/common.js';
1111
import { ApiErr } from '../../../../js/common/api/shared/api-error.js';
1212
import { Att } from '../../../../js/common/core/att.js';
1313
import { Buf } from '../../../../js/common/core/buf.js';
@@ -143,8 +143,12 @@ export class EncryptedMsgMailFormatter extends BaseMailFormatter {
143143
return undefined;
144144
}
145145
for (const myKey of pubs.filter(ap => ap.isMine)) {
146-
if (await myKey.pubkey.usableButExpired) {
147-
const path = chrome.runtime.getURL(`chrome/settings/index.htm?acctEmail=${encodeURIComponent(myKey.email)}&page=%2Fchrome%2Fsettings%2Fmodules%2Fmy_key_update.htm`);
146+
if (myKey.pubkey.usableButExpired) {
147+
const path = Url.create(chrome.runtime.getURL('chrome/settings/index.htm'), {
148+
acctEmail: myKey.email,
149+
page: '/chrome/settings/modules/my_key_update.htm',
150+
pageUrlParams: JSON.stringify({ fingerprint: myKey.pubkey.id }),
151+
});
148152
const errModalLines = [
149153
'This message could not be encrypted because your own Private Key is expired.',
150154
'',

extension/chrome/elements/passphrase.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ View.run(class PassphraseView extends View {
2020
private readonly parentTabId: string;
2121
private readonly longids: string[];
2222
private readonly type: string;
23-
private myPrivateKeys: KeyInfo[] | undefined;
23+
private keysWeNeedPassPhraseFor: KeyInfo[] | undefined;
2424

2525
constructor() {
2626
super();
@@ -35,7 +35,7 @@ View.run(class PassphraseView extends View {
3535
Ui.event.protect();
3636
await initPassphraseToggle(['passphrase']);
3737
const allPrivateKeys = await KeyStore.get(this.acctEmail);
38-
this.myPrivateKeys = allPrivateKeys.filter(ki => this.longids.includes(ki.longid) || (ki.primary && this.longids.includes('primary')));
38+
this.keysWeNeedPassPhraseFor = allPrivateKeys.filter(ki => this.longids.includes(ki.longid));
3939
if (this.type === 'embedded') {
4040
$('h1').parent().css('display', 'none');
4141
$('div.separator').css('display', 'none');
@@ -55,12 +55,12 @@ View.run(class PassphraseView extends View {
5555
$('#passphrase').focus();
5656
if (allPrivateKeys.length > 1) {
5757
let html: string;
58-
if (this.myPrivateKeys.length === 1) {
59-
html = `For key Fingerprint: <span class="good">${Xss.escape(Str.spaced(this.myPrivateKeys[0].fingerprint || ''))}</span>`;
58+
if (this.keysWeNeedPassPhraseFor.length === 1) {
59+
html = `For key Fingerprint: <span class="good">${Xss.escape(Str.spaced(this.keysWeNeedPassPhraseFor[0].fingerprint || ''))}</span>`;
6060
} else {
6161
html = 'Pass phrase needed for any of the following keys:';
62-
for (const i of this.myPrivateKeys.keys()) {
63-
html += `<div>Fingerprint ${String(i + 1)}: <span class="good">${Xss.escape(Str.spaced(this.myPrivateKeys[i].fingerprint) || '')}</span></div>`;
62+
for (const i of this.keysWeNeedPassPhraseFor.keys()) {
63+
html += `<div>Fingerprint ${String(i + 1)}: <span class="good">${Xss.escape(Str.spaced(this.keysWeNeedPassPhraseFor[i].fingerprint) || '')}</span></div>`;
6464
}
6565
}
6666
Xss.sanitizeRender('.which_key', html);
@@ -106,7 +106,7 @@ View.run(class PassphraseView extends View {
106106
const pass = String($('#passphrase').val());
107107
const storageType: StorageType = $('.forget').prop('checked') ? 'session' : 'local';
108108
let atLeastOneMatched = false;
109-
for (const keyinfo of this.myPrivateKeys!) { // if passphrase matches more keys, it will save the pass phrase for all keys
109+
for (const keyinfo of this.keysWeNeedPassPhraseFor!) { // if passphrase matches more keys, it will save the pass phrase for all keys
110110
const prv = await KeyUtil.parse(keyinfo.private);
111111
try {
112112
if (await KeyUtil.decrypt(prv, pass) === true) {

extension/chrome/elements/pgp_block_modules/pgp-block-decrypt-module.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ export class PgpBlockViewDecryptModule {
9393
this.view.renderModule.renderText('Decrypting...');
9494
await this.decryptAndRender(encryptedData, optionalPwd);
9595
} else {
96-
const [primaryKi] = await KeyStore.get(this.view.acctEmail, ['primary']);
96+
const primaryKi = await KeyStore.getFirst(this.view.acctEmail);
9797
if (!result.longids.chosen && !primaryKi) {
9898
await this.view.errorModule.renderErr(Lang.pgpBlock.notProperlySetUp + this.view.errorModule.btnHtml('FlowCrypt settings', 'green settings'), undefined);
9999
} else if (result.error.type === DecryptErrTypes.keyMismatch) {

extension/chrome/settings/index.htm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ <h1 class="text-center">FlowCrypt Settings</h1>
159159

160160
<div class="row settings-icons-rows">
161161
<div class="col-sm-2 col-xs-6">
162-
<a href="#" class="show_settings_page" page="modules/my_key.htm" data-test="action-open-pubkey-page">
162+
<a href="#" class="action_open_public_key_page" data-test="action-open-pubkey-page">
163163
<span class="box">
164164
<img src="/img/svgs/pub-key-icon.svg" class="pub-key-icon" alt="Your Public Keys">
165165
</span>

extension/chrome/settings/index.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,11 @@ View.run(class SettingsView extends View {
149149
Catch.report(`Unknown target page in element: ${target.outerHTML}`);
150150
}
151151
}));
152+
$('.action_open_public_key_page').click(this.setHandler(async target => {
153+
const ki = await KeyStore.getFirst(this.acctEmail!);
154+
const escapedFp = Xss.escape(ki.fingerprint);
155+
await Settings.renderSubPage(this.acctEmail!, this.tabId, 'modules/my_key.htm', `&fingerprint=${escapedFp}`);
156+
}));
152157
$('.action_show_encrypted_inbox').click(this.setHandler(target => {
153158
window.location.href = Url.create('/chrome/settings/inbox/inbox.htm', { acctEmail: this.acctEmail! });
154159
}));
@@ -425,18 +430,16 @@ View.run(class SettingsView extends View {
425430
const created = new Date(prv.created);
426431
const date = Str.monthName(created.getMonth()) + ' ' + created.getDate() + ', ' + created.getFullYear();
427432
const escapedFp = Xss.escape(ki.fingerprint);
428-
let escapedPrimaryOrRm = '';
429-
if (ki.primary) {
430-
escapedPrimaryOrRm = '(primary)';
431-
} else if (canRemoveKey) {
432-
escapedPrimaryOrRm = `(<a href="#" class="action_remove_key" data-test="action-remove-key" fingerprint="${escapedFp}">remove</a>)`;
433+
let removeKeyBtn = '';
434+
if (canRemoveKey && privateKeys.length > 1) {
435+
removeKeyBtn = `(<a href="#" class="action_remove_key" data-test="action-remove-key" fingerprint="${escapedFp}">remove</a>)`;
433436
}
434437
const escapedEmail = Xss.escape(prv.emails[0] || '');
435438
const escapedLink = `<a href="#" data-test="action-show-key-${i}" class="action_show_key" page="modules/my_key.htm" addurltext="&fingerprint=${escapedFp}">${escapedEmail}</a>`;
436439
const fpHtml = `fingerprint:&nbsp;<span class="good">${Str.spaced(escapedFp)}</span>`;
437440
const space = `&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`;
438441
html += `<div class="row key-content-row key_${escapedFp}">`;
439-
html += ` <div class="col-sm-12">${escapedLink} from ${Xss.escape(date)}${space}${fpHtml}${space}${escapedPrimaryOrRm}</div>`;
442+
html += ` <div class="col-sm-12">${escapedLink} from ${Xss.escape(date)}${space}${fpHtml}${space}${removeKeyBtn}</div>`;
440443
html += `</div>`;
441444
}
442445
Xss.sanitizeAppend('.key_list', html);

extension/chrome/settings/modules/backup-automatic-module.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export class BackupAutomaticModule extends ViewModule<BackupView> {
2525
}
2626

2727
private setupCreateSimpleAutomaticInboxBackup = async () => {
28-
const [primaryKi] = await KeyStore.get(this.view.acctEmail, ['primary']);
28+
const primaryKi = await KeyStore.getFirst(this.view.acctEmail);
2929
if (!(await KeyUtil.parse(primaryKi.private)).fullyEncrypted) {
3030
await Ui.modal.warning('Key not protected with a pass phrase, skipping');
3131
throw new UnreportableError('Key not protected with a pass phrase, skipping');

extension/chrome/settings/modules/backup-manual-module.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ export class BackupManualActionModule extends ViewModule<BackupView> {
6161

6262
private actionManualBackupHandler = async () => {
6363
const selected = $('input[type=radio][name=input_backup_choice]:checked').val();
64-
const [primaryKi] = await KeyStore.get(this.view.acctEmail, ['primary']);
64+
const primaryKi = await KeyStore.getFirst(this.view.acctEmail);
6565
Assert.abortAndRenderErrorIfKeyinfoEmpty(primaryKi);
6666
if (! await this.isPrivateKeyEncrypted(primaryKi)) {
6767
await Ui.modal.error('Sorry, cannot back up private key because it\'s not protected with a pass phrase.');

0 commit comments

Comments
 (0)