Skip to content

Commit 6e7d6df

Browse files
#5297 Improve handling of recipients keys with identities missing email (#6207)
* feat: improve handling of recipients keys with identities missing email * fix: test * fix: revert changes * fix: flaky * fix: pr reviews
1 parent cdf6c07 commit 6e7d6df

File tree

21 files changed

+122
-114
lines changed

21 files changed

+122
-114
lines changed

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -436,17 +436,17 @@ export class ComposeRenderModule extends ViewModule<ComposeView> {
436436
return; // key is invalid
437437
}
438438
const key = await KeyUtil.parse(normalizedPub);
439-
if (!key.emails.length) {
440-
// no users is not desired
439+
const firstUserWithEmail = key.users.find(u => u.email);
440+
if (!firstUserWithEmail?.email) {
441441
await Ui.modal.warning(`There are no email addresses listed in this Public Key - don't know who this key belongs to.`);
442442
return;
443443
}
444-
await ContactStore.update(undefined, key.emails[0], {
445-
name: Str.parseEmail(key.identities[0]).name,
444+
await ContactStore.update(undefined, firstUserWithEmail.email, {
445+
name: firstUserWithEmail.name,
446446
pubkey: normalizedPub,
447447
pubkeyLastCheck: Date.now(),
448448
});
449-
this.view.S.cached('input_to').val(key.emails[0]);
449+
this.view.S.cached('input_to').val(firstUserWithEmail.email);
450450
await this.view.recipientsModule.parseRenderRecipients(this.view.S.cached('input_to'));
451451
}
452452
};

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ export class GeneralMailFormatter {
9797
// This is important to consider when an email address with a email tag is present on the
9898
// signingKey, as technically it is the same email.
9999
const baseSenderEmail = senderEmail.includes('+') ? senderEmail.replace(/(.+)(?=\+).*(?=@)/, '$1') : senderEmail;
100-
return signingKey.emails.some(email => email.includes(baseSenderEmail));
100+
return signingKey.users.some(u => u.email?.includes(baseSenderEmail));
101101
}
102102
return true;
103103
};

extension/chrome/elements/pgp_pubkey.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ View.run(
7777
} else {
7878
let emailText = '';
7979
if (this.parsedPublicKeys.length === 1) {
80-
const email = this.firstParsedPublicKey.emails[0];
80+
const email = KeyUtil.getPrimaryEmail(this.firstParsedPublicKey);
8181
if (email) {
8282
emailText = email;
8383
$('.input_email').val(email); // checked above
@@ -90,7 +90,7 @@ View.run(
9090
Xss.escape(
9191
' for ' +
9292
this.parsedPublicKeys
93-
.map(pub => pub.emails[0])
93+
.map(pub => KeyUtil.getPrimaryEmail(pub))
9494
.filter(e => !!e)
9595
.join(', ')
9696
)
@@ -193,9 +193,9 @@ View.run(
193193
$('.error_introduce_label').html(`This OpenPGP key is not usable.<br/><small>(${await this.getErrorText()})</small>`); // xss-escaped
194194
$('.hide_if_error').hide();
195195
$('.fingerprints, .add_contact, #manual_import_warning').remove();
196-
const email = this.firstParsedPublicKey?.emails[0];
196+
const email = this.firstParsedPublicKey ? KeyUtil.getPrimaryEmail(this.firstParsedPublicKey) : undefined;
197197
if (email) {
198-
$('.error_container .input_error_email').val(`${this.firstParsedPublicKey?.emails[0]}`);
198+
$('.error_container .input_error_email').val(email);
199199
} else {
200200
$('.error_container .input_error_email').hide();
201201
}
@@ -208,7 +208,7 @@ View.run(
208208
const emails = new Set<string>();
209209
for (const pubkey of this.parsedPublicKeys!) {
210210
/* eslint-enable @typescript-eslint/no-non-null-assertion */
211-
const email = pubkey.emails[0];
211+
const email = KeyUtil.getPrimaryEmail(pubkey);
212212
if (email) {
213213
await ContactStore.update(undefined, email, { pubkey: KeyUtil.armor(pubkey) });
214214
emails.add(email);

extension/chrome/settings/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -537,7 +537,7 @@ View.run(
537537
removeKeyBtn = `<a href="#" class="action_remove_key" style="margin-left: 5px;" data-test="action-remove-key-${originalIndex}" data-fingerprint=${ki.fingerprints[0]} data-type="${ki.family}" data-id="${ki.id}" data-longid="${ki.longid}">remove</a>`;
538538
}
539539

540-
const escapedEmail = Xss.escape(prv.emails[0] || '');
540+
const escapedEmail = Xss.escape(KeyUtil.getPrimaryEmail(prv) || '');
541541
const escapedLink = `<a href="#" data-test="action-show-key-${originalIndex}" class="action_show_key" page="modules/my_key.htm" addurltext="&fingerprint=${ki.id}">${escapedEmail}</a>`;
542542
const fpHtml = `<span class="good" style="font-family: monospace;">${Str.spaced(Xss.escape(ki.fingerprints[0]))}</span>`;
543543

extension/chrome/settings/modules/add_key_generate_module.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,10 @@ export class AddKeyGenerateModule extends ViewModule<AddKeyView> {
9090
const adminPubkey = this.view.clientConfiguration.getPublicKeyForPrivateKeyBackupToDesignatedMailbox();
9191
if (adminPubkey) {
9292
const msgEncryptionKey = await KeyUtil.parse(adminPubkey);
93-
const destinationEmail = msgEncryptionKey.emails[0];
93+
const destinationEmail = KeyUtil.getPrimaryEmail(msgEncryptionKey);
94+
if (!destinationEmail) {
95+
throw new Error('Admin public key does not have an email address');
96+
}
9497
try {
9598
const privateKey = await KeyStore.get(this.view.acctEmail);
9699
const primaryKeyId = privateKey[0].id;

extension/chrome/settings/modules/contacts.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ View.run(
181181
[
182182
`Type: ${key.family}`,
183183
`Fingerprint: ${Str.spaced(key.id || 'none')}`,
184-
`Users: ${key.emails?.join(', ')}`,
184+
`Users: ${key.users?.map(u => u.email).filter(Boolean).join(', ')}`,
185185
`Created on: ${key.created ? new Date(key.created) : ''}`,
186186
`Expiration: ${key.expiration ? new Date(key.expiration) : 'Does not expire'}`,
187187
`Last signature: ${key.lastModified ? new Date(key.lastModified) : ''}`,

extension/chrome/settings/modules/my_key.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ View.run(
4949
$('.action_view_user_ids').attr('href', this.myKeyUserIdsUrl);
5050
$('.action_view_update').attr('href', this.myKeyUpdateUrl);
5151
$('.fingerprint').text(Str.spaced(this.keyInfo.fingerprints[0]));
52-
Xss.sanitizeRender('.email', this.pubKey.emails.map(email => `<span>${Xss.escape(email)}</span>`).join(', '));
52+
const emails = this.pubKey.users.map(u => u.email).filter((e): e is string => !!e);
53+
Xss.sanitizeRender('.email', emails.map(email => `<span>${Xss.escape(email)}</span>`).join(', '));
5354
const expiration = this.pubKey.expiration;
5455
const creation = Str.datetimeToDate(Str.fromDate(new Date(this.pubKey.created)));
5556
Xss.sanitizeRender('.key_status_contatiner', KeyUtil.statusHtml(this.keyInfo.longid, this.pubKey));

extension/chrome/settings/modules/my_key_update.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ View.run(
115115
KeyImportUi.allowReselect();
116116
if (typeof updatedKey === 'undefined') {
117117
await Ui.modal.warning(Lang.setup.keyFormattedWell(this.prvHeaders.begin, String(this.prvHeaders.end)), Ui.getTestCompatibilityLink(this.acctEmail));
118-
} else if (updatedKeyEncrypted.identities.length === 0) {
118+
} else if (updatedKeyEncrypted.users.length === 0) {
119119
throw new KeyCanBeFixed(updatedKeyEncrypted);
120120
} else if (updatedKey.isPublic) {
121121
await Ui.modal.warning(

extension/chrome/settings/modules/my_key_user_ids.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ View.run(
3030
Assert.abortAndRenderErrorIfKeyinfoEmpty(this.ki ? [this.ki] : []);
3131
$('.action_show_public_key').attr('href', this.myKeyUrl);
3232
const prv = await KeyUtil.parse(this.ki.private);
33-
Xss.sanitizeRender('.user_ids', prv.identities.map((uid: string) => `<div>${Xss.escape(uid)}</div>`).join(''));
33+
Xss.sanitizeRender('.user_ids', prv.users.map(u => `<div>${Xss.escape(u.full)}</div>`).join(''));
3434
$('.email').text(this.acctEmail);
3535
$('.fingerprint').text(Str.spaced(this.ki.fingerprints[0]));
3636
};

extension/chrome/settings/setup/setup-create-key.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,10 @@ export class SetupCreateKeyModule {
4444
const adminPubkey = this.view.clientConfiguration.getPublicKeyForPrivateKeyBackupToDesignatedMailbox();
4545
if (adminPubkey) {
4646
const msgEncryptionKey = await KeyUtil.parse(adminPubkey);
47-
const destinationEmail = msgEncryptionKey.emails[0];
47+
const destinationEmail = KeyUtil.getPrimaryEmail(msgEncryptionKey);
48+
if (!destinationEmail) {
49+
throw new Error('Admin public key does not have an email address');
50+
}
4851
try {
4952
const privateKey = await KeyStore.get(this.view.acctEmail);
5053
const primaryKeyId = privateKey[0].id;

0 commit comments

Comments
 (0)