diff --git a/extension/chrome/settings/modules/add_key.htm b/extension/chrome/settings/modules/add_key.htm
index 2abbcbe4039..db65def88ab 100644
--- a/extension/chrome/settings/modules/add_key.htm
+++ b/extension/chrome/settings/modules/add_key.htm
@@ -69,7 +69,7 @@
Add Private Key
-
+
diff --git a/extension/js/common/ui/key-import-ui.ts b/extension/js/common/ui/key-import-ui.ts
index ce13b731712..f2342abacff 100644
--- a/extension/js/common/ui/key-import-ui.ts
+++ b/extension/js/common/ui/key-import-ui.ts
@@ -356,7 +356,21 @@ export class KeyImportUi {
const keyinfos = await KeyStore.get(acctEmail);
const privateKeysIds = keyinfos.map(ki => ki.fingerprints[0]);
if (privateKeysIds.includes(k.id)) {
- throw new UserAlert('This is one of your current keys, try another one.');
+ const key = keyinfos.find(ki => ki.id === k.id);
+ if (key) {
+ const existingKey = await KeyUtil.parse(key.public);
+ const hasNewerExpiration = !!(k.expiration && existingKey.expiration && k.expiration > existingKey.expiration);
+ if (hasNewerExpiration) {
+ const updateKeyMessage =
+ "The key you're trying to import is a newer version of one you already have, based on its expiry date. " +
+ "We'll redirect you to the key update page to manage your key.";
+ if (await Ui.modal.confirm(updateKeyMessage, true)) {
+ window.location.href = Url.create('/chrome/settings/modules/my_key_update.htm', { acctEmail, fingerprint: k.id, parentTabId: '' });
+ }
+ } else {
+ throw new UserAlert('This is one of your current keys, try another one.');
+ }
+ }
}
}
};
diff --git a/extension/js/common/ui/passphrase-ui.ts b/extension/js/common/ui/passphrase-ui.ts
index 7620d4be690..c8eae1f7ce7 100644
--- a/extension/js/common/ui/passphrase-ui.ts
+++ b/extension/js/common/ui/passphrase-ui.ts
@@ -26,6 +26,9 @@ export const initPassphraseToggle = async (passphraseInputIds: string[], forceIn
for (const id of passphraseInputIds) {
const passphraseInput = $(`#${id}`);
passphraseInput.addClass('toggled_passphrase');
+ if (!passphraseInput.attr('data-test')) {
+ passphraseInput.attr('data-test', 'input-passphrase');
+ }
if (show) {
passphraseInput.after(``); // xss-direct
passphraseInput.attr('type', 'text');
diff --git a/test/source/tests/settings.ts b/test/source/tests/settings.ts
index 0addfe2bb5a..20e75521b1a 100644
--- a/test/source/tests/settings.ts
+++ b/test/source/tests/settings.ts
@@ -813,6 +813,43 @@ export const defineSettingsTests = (testVariant: TestVariant, testWithBrowser: T
expect(pubkeyExpiration).to.equal(expectedExpiration);
})
);
+ test(
+ 'settings - inform user when importing newer key version',
+ testWithBrowser(async (t, browser) => {
+ t.context.mockApi!.configProvider = new ConfigurationProvider({
+ attester: {
+ pubkeyLookup: {},
+ },
+ });
+ const acct = 'flowcrypt.compatibility@gmail.com';
+ const settingsPage = await BrowserRecipe.openSettingsLoginApprove(t, browser, acct);
+ const key50yearExpiry = testConstants.keyWith50yearsExpiry;
+ await SetupPageRecipe.manualEnter(settingsPage, '', {
+ key: {
+ title: '?',
+ armored: key50yearExpiry,
+ passphrase: 'passphrase',
+ longid: '6B673BAB02EC3E43',
+ },
+ });
+ await SettingsPageRecipe.toggleScreen(settingsPage, 'additional');
+ const addKeyPage = await SettingsPageRecipe.awaitNewPageFrame(settingsPage, '@action-open-add-key-page', ['add_key.htm']);
+ await addKeyPage.waitAndClick('@source-paste');
+ await addKeyPage.waitAndType('@input-armored-key', testConstants.keyWith80yearsExpiry);
+ await addKeyPage.waitAndType('@input-passphrase', 'passphrase');
+ await addKeyPage.waitAndClick('@action-add-private-key-btn');
+ const expectedInfoMsg =
+ "The key you're trying to import is a newer version of one you already have, based on its expiry date. " +
+ "We'll redirect you to the key update page to manage your key.";
+ await addKeyPage.waitAndRespondToModal('confirm', 'confirm', expectedInfoMsg);
+ const myKeyUpdatePage = await settingsPage.getFrame(['my_key_update.htm']);
+ await myKeyUpdatePage.waitAndClick('@source-paste');
+ await myKeyUpdatePage.waitAndType('@input-prv-key', testConstants.keyWith80yearsExpiry);
+ await myKeyUpdatePage.waitAndType('@input-passphrase', 'passphrase');
+ await myKeyUpdatePage.waitAndClick('@action-update-key');
+ await myKeyUpdatePage.waitAndRespondToModal('confirm', 'confirm', 'Public and private key updated locally.');
+ })
+ );
test(
'settings - attachment previews are rendered according to their types',
testWithBrowser(async (t, browser) => {
diff --git a/test/source/tests/tooling/consts.ts b/test/source/tests/tooling/consts.ts
index ad4302abe70..0b8bf037f0f 100644
--- a/test/source/tests/tooling/consts.ts
+++ b/test/source/tests/tooling/consts.ts
@@ -2050,6 +2050,42 @@ UR98qQ186mnyAcpbCVs7suK/0v+OIDHbF4gxMpRZmljstuT7mK4o6obfYwbOAq0Z
LE0zUUI5Yvk=
=XL9F
-----END PGP PUBLIC KEY BLOCK-----`,
+ keyWith50yearsExpiry: `-----BEGIN PGP PRIVATE KEY BLOCK-----
+Comment: passphrase is passphrase
+
+lIYEZ9etehYJKwYBBAHaRw8BAQdAS3w39Z7POxljA2Pw82iHSxdw/LXR+FzOpNMA
+v6Pzjuf+BwMCnms3a0yOh9L/bSD0R3dfzQAnyKtlY5wuT9GY30ne9Wi5OrodVPDL
+mm9lwOoq4CZhT76FCZH+VqQ1/W4ag5eXGus53teE9f+DvFQuBdUDFLQkdGVzdCBr
+ZXkgPGxvbmcudGltZXNwYW5AZXhhbXBsZS5jb20+iJkEExYKAEECGwMFCwkIBwIC
+IgIGFQoJCAsCBBYCAwECHgcCF4AWIQS6AopPWvdAXlKLtolrZzurAuw+QwUCZ9et
+qQUJXfwPLwAKCRBrZzurAuw+Q0mZAP4g+96pBZQK+x0GWeTPbctN95Iutex0RS+f
+vVsMhTPvwQD/Ytlt25KLL5hUdw4RMDckK6l9G+RoQH6FyWPWpZmZuw+ciwRn1616
+EgorBgEEAZdVAQUBAQdA9TVaPoFGzRGv3zmNNEDQDGONRo7Up3baDpux3rgvmnMD
+AQgH/gcDAiP/VHZnfkp4/2ux2bb4OZ9GHtIWZ4ijNqBggR3HBX/T9y3JSCgxs1uc
+LM0JL5XrwaGGDDokpEr+GBuFFuGw6LfV+bw4No2Xuv84SxAF1RCIfgQYFgoAJhYh
+BLoCik9a90BeUou2iWtnO6sC7D5DBQJn1616AhsMBQmWYBgAAAoJEGtnO6sC7D5D
+OkYA/1W6mbl/dAqt1j3kwFptypOiK48yLcXjIYpptpqi6Jy+AQCofaj8LPWXUZmK
+dm7daVbBUy6YHWaePL/Si2pfPR1WDg==
+=5V6v
+-----END PGP PRIVATE KEY BLOCK-----`,
+ keyWith80yearsExpiry: `-----BEGIN PGP PRIVATE KEY BLOCK-----
+Comment: passphrase is passphrase
+
+lIYEZ9etehYJKwYBBAHaRw8BAQdAS3w39Z7POxljA2Pw82iHSxdw/LXR+FzOpNMA
+v6Pzjuf+BwMCNigCZ9Hr0Ab/cwmxlbbT1PEXSJyu7oVhZlTFjKu0SAmKp9vxjv44
+Ry5So0rGJ5WjChH6SAHGoU7embN4zO8gf7oezsYcS3l4pkx/SAdworQkdGVzdCBr
+ZXkgPGxvbmcudGltZXNwYW5AZXhhbXBsZS5jb20+iJkEExYKAEEWIQS6AopPWvdA
+XlKLtolrZzurAuw+QwUCZ9etegIbAwUJlmAYAAULCQgHAgIiAgYVCgkICwIEFgID
+AQIeBwIXgAAKCRBrZzurAuw+Q61pAP9UJMO8zjug77uEtepzSTEe42DXD6DPiGzT
+2zGfIsuZ3QEA2MfWfxxSylNOcenjDiyJdZXbQ9XBIOd6gnSYpPFi0g+ciwRn1616
+EgorBgEEAZdVAQUBAQdA9TVaPoFGzRGv3zmNNEDQDGONRo7Up3baDpux3rgvmnMD
+AQgH/gcDAuFWQ5cWpFMO/wxxJn+r1CbUruerHu0m/lNAI9zq5PQ++i5vfrufR34r
+ENWg+7hKHItP0eN4dC+63pfKOHw9ugcCQNPOtudaLTC1s9gMu9iIfgQYFgoAJhYh
+BLoCik9a90BeUou2iWtnO6sC7D5DBQJn1616AhsMBQmWYBgAAAoJEGtnO6sC7D5D
+OkYA/1W6mbl/dAqt1j3kwFptypOiK48yLcXjIYpptpqi6Jy+AQCofaj8LPWXUZmK
+dm7daVbBUy6YHWaePL/Si2pfPR1WDg==
+=Tujf
+-----END PGP PRIVATE KEY BLOCK-----`,
};
export const testKeyConstants = {