mirror of https://github.com/vector-im/riot-web
Merge pull request #3962 from matrix-org/dbkr/better_flow_for_upgrade_on_login
Improve encryption upgrade on login flowpull/21833/head
commit
d1cbec98b7
|
@ -25,15 +25,14 @@ import { _t } from '../../../../languageHandler';
|
||||||
import Modal from '../../../../Modal';
|
import Modal from '../../../../Modal';
|
||||||
|
|
||||||
const PHASE_LOADING = 0;
|
const PHASE_LOADING = 0;
|
||||||
const PHASE_RESTORE_KEY_BACKUP = 1;
|
const PHASE_MIGRATE = 1;
|
||||||
const PHASE_MIGRATE = 2;
|
const PHASE_PASSPHRASE = 2;
|
||||||
const PHASE_PASSPHRASE = 3;
|
const PHASE_PASSPHRASE_CONFIRM = 3;
|
||||||
const PHASE_PASSPHRASE_CONFIRM = 4;
|
const PHASE_SHOWKEY = 4;
|
||||||
const PHASE_SHOWKEY = 5;
|
const PHASE_KEEPITSAFE = 5;
|
||||||
const PHASE_KEEPITSAFE = 6;
|
const PHASE_STORING = 6;
|
||||||
const PHASE_STORING = 7;
|
const PHASE_DONE = 7;
|
||||||
const PHASE_DONE = 8;
|
const PHASE_CONFIRM_SKIP = 8;
|
||||||
const PHASE_OPTOUT_CONFIRM = 9;
|
|
||||||
|
|
||||||
const PASSWORD_MIN_SCORE = 4; // So secure, many characters, much complex, wow, etc, etc.
|
const PASSWORD_MIN_SCORE = 4; // So secure, many characters, much complex, wow, etc, etc.
|
||||||
const PASSPHRASE_FEEDBACK_DELAY = 500; // How long after keystroke to offer passphrase feedback, ms.
|
const PASSPHRASE_FEEDBACK_DELAY = 500; // How long after keystroke to offer passphrase feedback, ms.
|
||||||
|
@ -58,7 +57,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
|
||||||
accountPassword: PropTypes.string,
|
accountPassword: PropTypes.string,
|
||||||
};
|
};
|
||||||
|
|
||||||
defaultProps = {
|
static defaultProps = {
|
||||||
hasCancel: true,
|
hasCancel: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -110,9 +109,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
|
||||||
MatrixClientPeg.get().isCryptoEnabled() && await MatrixClientPeg.get().isKeyBackupTrusted(backupInfo)
|
MatrixClientPeg.get().isCryptoEnabled() && await MatrixClientPeg.get().isKeyBackupTrusted(backupInfo)
|
||||||
);
|
);
|
||||||
|
|
||||||
const phase = backupInfo ?
|
const phase = backupInfo ? PHASE_MIGRATE : PHASE_PASSPHRASE;
|
||||||
(backupSigStatus.usable ? PHASE_MIGRATE : PHASE_RESTORE_KEY_BACKUP) :
|
|
||||||
PHASE_PASSPHRASE;
|
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
phase,
|
phase,
|
||||||
|
@ -153,7 +150,11 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
|
||||||
|
|
||||||
_onMigrateFormSubmit = (e) => {
|
_onMigrateFormSubmit = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
if (this.state.backupSigStatus.usable) {
|
||||||
this._bootstrapSecretStorage();
|
this._bootstrapSecretStorage();
|
||||||
|
} else {
|
||||||
|
this._restoreBackup();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_onCopyClick = () => {
|
_onCopyClick = () => {
|
||||||
|
@ -228,6 +229,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (this.state.canUploadKeysWithPasswordOnly && e.httpStatus === 401 && e.data.flows) {
|
if (this.state.canUploadKeysWithPasswordOnly && e.httpStatus === 401 && e.data.flows) {
|
||||||
this.setState({
|
this.setState({
|
||||||
|
accountPassword: '',
|
||||||
accountPasswordCorrect: false,
|
accountPasswordCorrect: false,
|
||||||
phase: PHASE_MIGRATE,
|
phase: PHASE_MIGRATE,
|
||||||
});
|
});
|
||||||
|
@ -246,16 +248,26 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
|
||||||
this.props.onFinished(true);
|
this.props.onFinished(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onRestoreKeyBackupClick = () => {
|
_restoreBackup = async () => {
|
||||||
const RestoreKeyBackupDialog = sdk.getComponent('dialogs.keybackup.RestoreKeyBackupDialog');
|
const RestoreKeyBackupDialog = sdk.getComponent('dialogs.keybackup.RestoreKeyBackupDialog');
|
||||||
Modal.createTrackedDialog(
|
const { finished } = Modal.createTrackedDialog(
|
||||||
'Restore Backup', '', RestoreKeyBackupDialog, {showSummary: false}, null,
|
'Restore Backup', '', RestoreKeyBackupDialog, {showSummary: false}, null,
|
||||||
/* priority = */ false, /* static = */ true,
|
/* priority = */ false, /* static = */ true,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
await finished;
|
||||||
|
await this._fetchBackupInfo();
|
||||||
|
if (
|
||||||
|
this.state.backupSigStatus.usable &&
|
||||||
|
this.state.canUploadKeysWithPasswordOnly &&
|
||||||
|
this.state.accountPassword
|
||||||
|
) {
|
||||||
|
this._bootstrapSecretStorage();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_onOptOutClick = () => {
|
_onSkipSetupClick = () => {
|
||||||
this.setState({phase: PHASE_OPTOUT_CONFIRM});
|
this.setState({phase: PHASE_CONFIRM_SKIP});
|
||||||
}
|
}
|
||||||
|
|
||||||
_onSetUpClick = () => {
|
_onSetUpClick = () => {
|
||||||
|
@ -367,23 +379,6 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_renderPhaseRestoreKeyBackup() {
|
|
||||||
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
|
||||||
return <div>
|
|
||||||
<p>{_t(
|
|
||||||
"Key Backup is enabled on your account but has not been set " +
|
|
||||||
"up from this session. To set up secret storage, " +
|
|
||||||
"restore your key backup.",
|
|
||||||
)}</p>
|
|
||||||
<DialogButtons primaryButton={_t('Restore')}
|
|
||||||
onPrimaryButtonClick={this._onRestoreKeyBackupClick}
|
|
||||||
onCancel={this._onCancel}
|
|
||||||
hasCancel={true}
|
|
||||||
>
|
|
||||||
</DialogButtons>
|
|
||||||
</div>;
|
|
||||||
}
|
|
||||||
|
|
||||||
_renderPhaseMigrate() {
|
_renderPhaseMigrate() {
|
||||||
// TODO: This is a temporary screen so people who have the labs flag turned on and
|
// TODO: This is a temporary screen so people who have the labs flag turned on and
|
||||||
// click the button are aware they're making a change to their account.
|
// click the button are aware they're making a change to their account.
|
||||||
|
@ -394,7 +389,13 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
|
||||||
const Field = sdk.getComponent('views.elements.Field');
|
const Field = sdk.getComponent('views.elements.Field');
|
||||||
|
|
||||||
let authPrompt;
|
let authPrompt;
|
||||||
if (this.state.canUploadKeysWithPasswordOnly) {
|
let nextCaption = _t("Next");
|
||||||
|
if (!this.state.backupSigStatus.usable) {
|
||||||
|
authPrompt = <div>
|
||||||
|
<div>{_t("Restore your key backup to upgrade your encryption")}</div>
|
||||||
|
</div>;
|
||||||
|
nextCaption = _t("Restore");
|
||||||
|
} else if (this.state.canUploadKeysWithPasswordOnly) {
|
||||||
authPrompt = <div>
|
authPrompt = <div>
|
||||||
<div>{_t("Enter your account password to confirm the upgrade:")}</div>
|
<div>{_t("Enter your account password to confirm the upgrade:")}</div>
|
||||||
<div><Field type="password"
|
<div><Field type="password"
|
||||||
|
@ -419,12 +420,15 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
|
||||||
"as trusted for other users.",
|
"as trusted for other users.",
|
||||||
)}</p>
|
)}</p>
|
||||||
<div>{authPrompt}</div>
|
<div>{authPrompt}</div>
|
||||||
<DialogButtons primaryButton={_t('Next')}
|
<DialogButtons primaryButton={nextCaption}
|
||||||
primaryIsSubmit={true}
|
primaryIsSubmit={true}
|
||||||
hasCancel={true}
|
hasCancel={false}
|
||||||
onCancel={this._onCancel}
|
|
||||||
primaryDisabled={this.state.canUploadKeysWithPasswordOnly && !this.state.accountPassword}
|
primaryDisabled={this.state.canUploadKeysWithPasswordOnly && !this.state.accountPassword}
|
||||||
/>
|
>
|
||||||
|
<button type="button" className="danger" onClick={this._onSkipClick}>
|
||||||
|
{_t('Skip')}
|
||||||
|
</button>
|
||||||
|
</DialogButtons>
|
||||||
</form>;
|
</form>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -486,7 +490,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
|
||||||
disabled={!this._passPhraseIsValid()}
|
disabled={!this._passPhraseIsValid()}
|
||||||
>
|
>
|
||||||
<button type="button"
|
<button type="button"
|
||||||
onClick={this._onCancel}
|
onClick={this._onSkipSetupClick}
|
||||||
className="danger"
|
className="danger"
|
||||||
>{_t("Skip")}</button>
|
>{_t("Skip")}</button>
|
||||||
</DialogButtons>
|
</DialogButtons>
|
||||||
|
@ -554,7 +558,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
|
||||||
disabled={this.state.passPhrase !== this.state.passPhraseConfirm}
|
disabled={this.state.passPhrase !== this.state.passPhraseConfirm}
|
||||||
>
|
>
|
||||||
<button type="button"
|
<button type="button"
|
||||||
onClick={this._onCancel}
|
onClick={this._onSkipSetupClick}
|
||||||
className="danger"
|
className="danger"
|
||||||
>{_t("Skip")}</button>
|
>{_t("Skip")}</button>
|
||||||
</DialogButtons>
|
</DialogButtons>
|
||||||
|
@ -659,35 +663,32 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
_renderPhaseOptOutConfirm() {
|
_renderPhaseSkipConfirm() {
|
||||||
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
||||||
return <div>
|
return <div>
|
||||||
{_t(
|
{_t(
|
||||||
"Without setting up secret storage, you won't be able to restore your " +
|
"Without completing security on this device, it won’t have " +
|
||||||
"access to encrypted messages or your cross-signing identity for " +
|
"access to encrypted messages.",
|
||||||
"verifying other devices if you log out or use another device.",
|
|
||||||
)}
|
)}
|
||||||
<DialogButtons primaryButton={_t('Set up secret storage')}
|
<DialogButtons primaryButton={_t('Go back')}
|
||||||
onPrimaryButtonClick={this._onSetUpClick}
|
onPrimaryButtonClick={this._onSetUpClick}
|
||||||
hasCancel={false}
|
hasCancel={false}
|
||||||
>
|
>
|
||||||
<button onClick={this._onCancel}>I understand, continue without</button>
|
<button type="button" className="danger" onClick={this._onCancel}>{_t('Skip')}</button>
|
||||||
</DialogButtons>
|
</DialogButtons>
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
_titleForPhase(phase) {
|
_titleForPhase(phase) {
|
||||||
switch (phase) {
|
switch (phase) {
|
||||||
case PHASE_RESTORE_KEY_BACKUP:
|
|
||||||
return _t('Restore your Key Backup');
|
|
||||||
case PHASE_MIGRATE:
|
case PHASE_MIGRATE:
|
||||||
return _t('Upgrade your encryption');
|
return _t('Upgrade your encryption');
|
||||||
case PHASE_PASSPHRASE:
|
case PHASE_PASSPHRASE:
|
||||||
return _t('Set up encryption');
|
return _t('Set up encryption');
|
||||||
case PHASE_PASSPHRASE_CONFIRM:
|
case PHASE_PASSPHRASE_CONFIRM:
|
||||||
return _t('Confirm passphrase');
|
return _t('Confirm passphrase');
|
||||||
case PHASE_OPTOUT_CONFIRM:
|
case PHASE_CONFIRM_SKIP:
|
||||||
return _t('Warning!');
|
return _t('Are you sure?');
|
||||||
case PHASE_SHOWKEY:
|
case PHASE_SHOWKEY:
|
||||||
return _t('Recovery key');
|
return _t('Recovery key');
|
||||||
case PHASE_KEEPITSAFE:
|
case PHASE_KEEPITSAFE:
|
||||||
|
@ -722,9 +723,6 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
|
||||||
case PHASE_LOADING:
|
case PHASE_LOADING:
|
||||||
content = this._renderBusyPhase();
|
content = this._renderBusyPhase();
|
||||||
break;
|
break;
|
||||||
case PHASE_RESTORE_KEY_BACKUP:
|
|
||||||
content = this._renderPhaseRestoreKeyBackup();
|
|
||||||
break;
|
|
||||||
case PHASE_MIGRATE:
|
case PHASE_MIGRATE:
|
||||||
content = this._renderPhaseMigrate();
|
content = this._renderPhaseMigrate();
|
||||||
break;
|
break;
|
||||||
|
@ -746,8 +744,8 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
|
||||||
case PHASE_DONE:
|
case PHASE_DONE:
|
||||||
content = this._renderPhaseDone();
|
content = this._renderPhaseDone();
|
||||||
break;
|
break;
|
||||||
case PHASE_OPTOUT_CONFIRM:
|
case PHASE_CONFIRM_SKIP:
|
||||||
content = this._renderPhaseOptOutConfirm();
|
content = this._renderPhaseSkipConfirm();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -763,6 +761,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
|
||||||
title={this._titleForPhase(this.state.phase)}
|
title={this._titleForPhase(this.state.phase)}
|
||||||
headerImage={headerImage}
|
headerImage={headerImage}
|
||||||
hasCancel={this.props.hasCancel && [PHASE_PASSPHRASE].includes(this.state.phase)}
|
hasCancel={this.props.hasCancel && [PHASE_PASSPHRASE].includes(this.state.phase)}
|
||||||
|
fixedWidth={false}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
{content}
|
{content}
|
||||||
|
|
|
@ -39,7 +39,7 @@ export default class RestoreKeyBackupDialog extends React.PureComponent {
|
||||||
showSummary: PropTypes.bool,
|
showSummary: PropTypes.bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
defaultProps = {
|
static defaultProps = {
|
||||||
showSummary: true,
|
showSummary: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1996,7 +1996,7 @@
|
||||||
"The export file will be protected with a passphrase. You should enter the passphrase here, to decrypt the file.": "The export file will be protected with a passphrase. You should enter the passphrase here, to decrypt the file.",
|
"The export file will be protected with a passphrase. You should enter the passphrase here, to decrypt the file.": "The export file will be protected with a passphrase. You should enter the passphrase here, to decrypt the file.",
|
||||||
"File to import": "File to import",
|
"File to import": "File to import",
|
||||||
"Import": "Import",
|
"Import": "Import",
|
||||||
"Key Backup is enabled on your account but has not been set up from this session. To set up secret storage, restore your key backup.": "Key Backup is enabled on your account but has not been set up from this session. To set up secret storage, restore your key backup.",
|
"Restore your key backup to upgrade your encryption": "Restore your key backup to upgrade your encryption",
|
||||||
"Restore": "Restore",
|
"Restore": "Restore",
|
||||||
"Enter your account password to confirm the upgrade:": "Enter your account password to confirm the upgrade:",
|
"Enter your account password to confirm the upgrade:": "Enter your account password to confirm the upgrade:",
|
||||||
"You'll need to authenticate with the server to confirm the upgrade.": "You'll need to authenticate with the server to confirm the upgrade.",
|
"You'll need to authenticate with the server to confirm the upgrade.": "You'll need to authenticate with the server to confirm the upgrade.",
|
||||||
|
@ -2025,9 +2025,6 @@
|
||||||
"<b>Copy it</b> to your personal cloud storage": "<b>Copy it</b> to your personal cloud storage",
|
"<b>Copy it</b> to your personal cloud storage": "<b>Copy it</b> to your personal cloud storage",
|
||||||
"This device can now verify other devices, granting them access to encrypted messages and marking them as trusted for other users.": "This device can now verify other devices, granting them access to encrypted messages and marking them as trusted for other users.",
|
"This device can now verify other devices, granting them access to encrypted messages and marking them as trusted for other users.": "This device can now verify other devices, granting them access to encrypted messages and marking them as trusted for other users.",
|
||||||
"Verify other users in their profile.": "Verify other users in their profile.",
|
"Verify other users in their profile.": "Verify other users in their profile.",
|
||||||
"Without setting up secret storage, you won't be able to restore your access to encrypted messages or your cross-signing identity for verifying other devices if you log out or use another device.": "Without setting up secret storage, you won't be able to restore your access to encrypted messages or your cross-signing identity for verifying other devices if you log out or use another device.",
|
|
||||||
"Set up secret storage": "Set up secret storage",
|
|
||||||
"Restore your Key Backup": "Restore your Key Backup",
|
|
||||||
"Upgrade your encryption": "Upgrade your encryption",
|
"Upgrade your encryption": "Upgrade your encryption",
|
||||||
"Recovery key": "Recovery key",
|
"Recovery key": "Recovery key",
|
||||||
"Keep it safe": "Keep it safe",
|
"Keep it safe": "Keep it safe",
|
||||||
|
|
Loading…
Reference in New Issue