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 = {