Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion extension/chrome/settings/modules/add_key.htm
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ <h1>Add Private Key <span id="spinner_container"></span></h1>
</div>
<div class="source_paste_container display_none">
<div class="line">
<textarea class="input_private_key" data-test="input-armored-key" placeholder="ASCII Armored Private Key" maxlength="80000"> </textarea>
<textarea class="input_private_key" data-test="input-armored-key" placeholder="ASCII Armored Private Key" maxlength="120000"> </textarea>
</div>
<div class="line display_none unprotected_key_create_pass_phrase" style="text-align: left; padding-left: 40px">
This key is unprotected. Create a pass phrase or
Expand Down
2 changes: 1 addition & 1 deletion extension/chrome/settings/modules/compatibility.htm
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ <h1>OpenPGP key compatibility test</h1>
class="input_key"
style="width: 650px; height: 200px"
spellcheck="false"
maxlength="80000"
maxlength="120000"
></textarea>
</div>

Expand Down
2 changes: 1 addition & 1 deletion extension/chrome/settings/modules/my_key_update.htm
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
</div>
<div class="source_paste_container display_none">
<div class="line">
<textarea class="input_private_key armored" data-test="input-prv-key" placeholder="Updated ASCII Armored Private Key" maxlength="80000"></textarea>
<textarea class="input_private_key armored" data-test="input-prv-key" placeholder="Updated ASCII Armored Private Key" maxlength="120000"></textarea>
</div>
<div class="line">
<input class="input_passphrase" type="password" data-test="input-passphrase" placeholder="Private Key Passphrase" maxlength="256" />
Expand Down
2 changes: 1 addition & 1 deletion extension/chrome/settings/setup.htm
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ <h1>Set Up FlowCrypt</h1>
placeholder="ASCII Armored Private Key"
data-test="input-step2bmanualenter-ascii-key"
spellcheck="false"
maxlength="80000"
maxlength="120000"
></textarea>
</div>
<div class="line display_none unprotected_key_create_pass_phrase">
Expand Down
2 changes: 1 addition & 1 deletion extension/js/common/core/crypto/pgp/openpgp-key.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { PgpMsgMethod, VerifyRes } from './msg-util.js';
import * as Stream from '@openpgp/web-stream-tools';

type OpenpgpMsgOrCleartext = OpenPGP.Message<OpenPGP.Data> | OpenPGP.CleartextMessage;
interface KeyWithPrivateFields extends Key {
export interface KeyWithPrivateFields extends Key {
internal: OpenPGP.Key | string; // usable key without weak packets
rawArmored: string;
}
Expand Down
2 changes: 1 addition & 1 deletion extension/js/common/lang.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export const Lang = {
creatingKeysNotAllowedPleaseImport: 'Creating keys is not allowed on your domain. Please import your keys.',
keyBackupsNotAllowed: 'Key backups are not allowed on this domain.',
prvHasFixableCompatIssue:
'This key has minor usability issues that can be fixed. This commonly happens when importing keys from Symantec&trade; PGP Desktop or other legacy software. It may be missing User IDs, or it may be missing a self-signature. It is also possible that the key is simply expired.',
'This key has minor usability issues that can be fixed. This commonly happens when importing keys from Symantec&trade; PGP Desktop or other legacy software.It may be missing user IDs, a self-signature, or have an invalid user ID (e.g., a user ID with image data). It is also possible that the key is simply expired.',
ppMatchAllSet: "Your pass phrase matches. Good job! You're all set.",
noKeys: 'Keys for your account were not set up yet - please ask your systems administrator.',
prvBackupToDesignatedMailboxEmailSubject: (acctEmail: string, fingerprint: string) =>
Expand Down
23 changes: 22 additions & 1 deletion extension/js/common/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { Api } from './api/shared/api.js';
import { Time } from './browser/time.js';
import { Google } from './api/email-provider/gmail/google.js';
import { ConfiguredIdpOAuth } from './api/authentication/configured-idp-oauth.js';
import { KeyWithPrivateFields } from './core/crypto/pgp/openpgp-key.js';

declare const zxcvbn: (password: string, userInputs: string[]) => { guesses: number };

Expand Down Expand Up @@ -256,7 +257,27 @@ export class Settings {
const expireSeconds = expireYears === 'never' ? 0 : Math.floor((Date.now() - origPrv.created) / 1000) + 60 * 60 * 24 * 365 * Number(expireYears);
await KeyUtil.decrypt(origPrv, passphrase);
let reformatted;
const userIds = uids.map(uid => Str.parseEmail(uid)).map(u => ({ email: u.email, name: u.name || '' }));
let userIds: { email: string | undefined; name: string }[] = [];
const internal = (origPrv as KeyWithPrivateFields).internal;
if (typeof internal !== 'string' && internal?.users) {
for (const u of internal.users) {
if (u.userID) {
userIds.push({
email: u.userID.email,
name: u.userID.name || '',
});
}
}
if (!userIds.length) {
userIds = uids.map(uid => {
const parsed = Str.parseEmail(uid);
return {
email: parsed.email,
name: parsed.name || '',
};
});
}
}
try {
reformatted = await KeyUtil.reformatKey(origPrv, passphrase, userIds, expireSeconds);
} catch (e) {
Expand Down
35 changes: 34 additions & 1 deletion test/source/tests/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { KeyInfoWithIdentity, KeyUtil, PubkeyInfoWithLastCheck } from '../core/c
import { Buf } from '../core/buf';
import { GoogleData } from '../mock/google/google-data';
import Parse from './../util/parse';
import { OpenPGPKey } from '../core/crypto/pgp/openpgp-key';
import { KeyWithPrivateFields, OpenPGPKey } from '../core/crypto/pgp/openpgp-key';
import { BrowserHandle, ControllablePage } from '../browser';
import { AvaContext } from './tooling';
import { ConfigurationProvider, HttpClientErr, Status } from '../mock/lib/api';
Expand All @@ -29,6 +29,7 @@ import { twoKeys1, twoKeys2 } from '../mock/key-manager/key-manager-constants';
import { getKeyManagerAutogenRules } from '../mock/fes/fes-constants';
import { FesClientConfiguration } from '../mock/fes/shared-tenant-fes-endpoints';
import { flowcryptCompatibilityAliasList } from '../mock/google/google-endpoints';
import { Key } from 'openpgp';

export const defineSettingsTests = (testVariant: TestVariant, testWithBrowser: TestWithBrowser) => {
if (testVariant !== 'CONSUMER-LIVE-GMAIL') {
Expand Down Expand Up @@ -1132,6 +1133,38 @@ export const defineSettingsTests = (testVariant: TestVariant, testWithBrowser: T
await settingsPage.close();
})
);
test(
'settings - fix and import keypair with embedded image generated from gpg2',
testWithBrowser(async (t, browser) => {
t.context.mockApi!.configProvider = new ConfigurationProvider({
attester: {
pubkeyLookup: {},
},
});
const acct = '[email protected]';
const settingsPage = await BrowserRecipe.openSettingsLoginApprove(t, browser, acct);
await SetupPageRecipe.manualEnter(settingsPage, '', {
fixKey: true,
key: {
title: '',
armored: testConstants.keyWithEmbeddedImage,
passphrase: 'passphrase',
longid: '1ABCEBCA0A4FB17C',
},
});
await SettingsPageRecipe.toggleScreen(settingsPage, 'additional');
await settingsPage.waitAndClick('@action-open-pubkey-page');
const myKeyFrame = await settingsPage.getFrame(['my_key.htm']);
const downloadedFile = await myKeyFrame.awaitDownloadTriggeredByClicking('@action-download-prv');
const fileName = 'flowcrypt-backup-flowcryptcompatibilitygmailcom-0x1ABCEBCA0A4FB17C.asc';
const parsedKey = (await KeyUtil.parse(downloadedFile[fileName].toString())) as KeyWithPrivateFields;
const originalKey = (await KeyUtil.parse(testConstants.keyWithEmbeddedImage)) as KeyWithPrivateFields;
expect((originalKey.internal as Key)?.users[2].userID?.userID).to.equal(undefined);
expect((parsedKey.internal as Key)?.users[2].userID?.userID).to.equal('Some user id <[email protected]>');
expect((originalKey.internal as Key)?.users.length).to.equal(5);
expect((parsedKey.internal as Key)?.users.length).to.equal(4);
})
);
test(
'settings - my key page - update private key from file',
testWithBrowser(async (t, browser) => {
Expand Down
Loading