From b8683462e8f0bee0654defe92883e36ef99cef44 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Fri, 3 Jan 2020 15:34:03 +0000 Subject: [PATCH] Update backup creation paths for SSSS This updates the various backup creation entry points to ensure they support creating with secret storage if the feature flag is enabled. --- .../keybackup/CreateKeyBackupDialog.js | 53 ++++++++++++++++--- .../keybackup/RecoveryMethodRemovedDialog.js | 2 + src/components/views/dialogs/LogoutDialog.js | 1 + .../keybackup/RestoreKeyBackupDialog.js | 2 +- .../views/rooms/RoomRecoveryReminder.js | 1 + .../views/settings/KeyBackupPanel.js | 34 ++++-------- 6 files changed, 61 insertions(+), 32 deletions(-) diff --git a/src/async-components/views/dialogs/keybackup/CreateKeyBackupDialog.js b/src/async-components/views/dialogs/keybackup/CreateKeyBackupDialog.js index 3fac00c1b3..19720e077a 100644 --- a/src/async-components/views/dialogs/keybackup/CreateKeyBackupDialog.js +++ b/src/async-components/views/dialogs/keybackup/CreateKeyBackupDialog.js @@ -1,6 +1,6 @@ /* Copyright 2018, 2019 New Vector Ltd -Copyright 2019 The Matrix.org Foundation C.I.C. +Copyright 2019, 2020 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,11 +17,14 @@ limitations under the License. import React from 'react'; import FileSaver from 'file-saver'; +import PropTypes from 'prop-types'; import sdk from '../../../../index'; import MatrixClientPeg from '../../../../MatrixClientPeg'; import { scorePassword } from '../../../../utils/PasswordScorer'; import { _t } from '../../../../languageHandler'; +import { accessSecretStorage } from '../../../../CrossSigningManager'; +import SettingsStore from '../../../../../lib/settings/SettingsStore'; const PHASE_PASSPHRASE = 0; const PHASE_PASSPHRASE_CONFIRM = 1; @@ -49,10 +52,20 @@ function selectText(target) { * on the server. */ export default class CreateKeyBackupDialog extends React.PureComponent { + static propTypes = { + secureSecretStorage: PropTypes.bool, + onFinished: PropTypes.func.isRequired, + } + constructor(props) { super(props); + this._recoveryKeyNode = null; + this._keyBackupInfo = null; + this._setZxcvbnResultTimeout = null; + this.state = { + secureSecretStorage: props.secureSecretStorage, phase: PHASE_PASSPHRASE, passPhrase: '', passPhraseConfirm: '', @@ -61,12 +74,25 @@ export default class CreateKeyBackupDialog extends React.PureComponent { zxcvbnResult: null, setPassPhrase: false, }; + + if (this.state.secureSecretStorage === undefined) { + this.state.secureSecretStorage = + SettingsStore.isFeatureEnabled("feature_cross_signing"); + } + + // If we're using secret storage, skip ahead to the backing up step, as + // `accessSecretStorage` will handle passphrases as needed. + if (this.state.secureSecretStorage) { + this.state.phase = PHASE_BACKINGUP; + } } - componentWillMount() { - this._recoveryKeyNode = null; - this._keyBackupInfo = null; - this._setZxcvbnResultTimeout = null; + componentDidMount() { + // If we're using secret storage, skip ahead to the backing up step, as + // `accessSecretStorage` will handle passphrases as needed. + if (this.state.secureSecretStorage) { + this._createBackup(); + } } componentWillUnmount() { @@ -103,15 +129,26 @@ export default class CreateKeyBackupDialog extends React.PureComponent { } _createBackup = async () => { + const { secureSecretStorage } = this.state; this.setState({ phase: PHASE_BACKINGUP, error: null, }); let info; try { - info = await MatrixClientPeg.get().createKeyBackupVersion( - this._keyBackupInfo, - ); + if (secureSecretStorage) { + await accessSecretStorage(async () => { + info = await MatrixClientPeg.get().prepareKeyBackupVersion( + null /* random key */, + { secureSecretStorage: true }, + ); + info = await MatrixClientPeg.get().createKeyBackupVersion(info); + }); + } else { + info = await MatrixClientPeg.get().createKeyBackupVersion( + this._keyBackupInfo, + ); + } await MatrixClientPeg.get().scheduleAllGroupSessionsForBackup(); this.setState({ phase: PHASE_DONE, diff --git a/src/async-components/views/dialogs/keybackup/RecoveryMethodRemovedDialog.js b/src/async-components/views/dialogs/keybackup/RecoveryMethodRemovedDialog.js index 1975fbe6d6..4383908e23 100644 --- a/src/async-components/views/dialogs/keybackup/RecoveryMethodRemovedDialog.js +++ b/src/async-components/views/dialogs/keybackup/RecoveryMethodRemovedDialog.js @@ -1,5 +1,6 @@ /* Copyright 2019 New Vector Ltd +Copyright 2020 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -35,6 +36,7 @@ export default class RecoveryMethodRemovedDialog extends React.PureComponent { this.props.onFinished(); Modal.createTrackedDialogAsync("Key Backup", "Key Backup", import("./CreateKeyBackupDialog"), + null, null, /* priority = */ false, /* static = */ true, ); } diff --git a/src/components/views/dialogs/LogoutDialog.js b/src/components/views/dialogs/LogoutDialog.js index 6e4f950830..ede03f13cc 100644 --- a/src/components/views/dialogs/LogoutDialog.js +++ b/src/components/views/dialogs/LogoutDialog.js @@ -102,6 +102,7 @@ export default class LogoutDialog extends React.Component { } else { Modal.createTrackedDialogAsync("Key Backup", "Key Backup", import("../../../async-components/views/dialogs/keybackup/CreateKeyBackupDialog"), + null, null, /* priority = */ false, /* static = */ true, ); } diff --git a/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js b/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js index 2881cc920c..106d8cd6f8 100644 --- a/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js +++ b/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js @@ -76,7 +76,7 @@ export default class RestoreKeyBackupDialog extends React.PureComponent { onFinished: () => { this._loadBackupStatus(); }, - }, + }, null, /* priority = */ false, /* static = */ true, ); } diff --git a/src/components/views/rooms/RoomRecoveryReminder.js b/src/components/views/rooms/RoomRecoveryReminder.js index 8554c804c0..aa8134d680 100644 --- a/src/components/views/rooms/RoomRecoveryReminder.js +++ b/src/components/views/rooms/RoomRecoveryReminder.js @@ -78,6 +78,7 @@ export default class RoomRecoveryReminder extends React.PureComponent { } else { Modal.createTrackedDialogAsync("Key Backup", "Key Backup", import("../../../async-components/views/dialogs/keybackup/CreateKeyBackupDialog"), + null, null, /* priority = */ false, /* static = */ true, ); } } diff --git a/src/components/views/settings/KeyBackupPanel.js b/src/components/views/settings/KeyBackupPanel.js index 55bfadba88..765dd16717 100644 --- a/src/components/views/settings/KeyBackupPanel.js +++ b/src/components/views/settings/KeyBackupPanel.js @@ -128,36 +128,24 @@ export default class KeyBackupPanel extends React.PureComponent { Modal.createTrackedDialogAsync('Key Backup', 'Key Backup', import('../../../async-components/views/dialogs/keybackup/CreateKeyBackupDialog'), { + secureSecretStorage: false, onFinished: () => { this._loadBackupStatus(); }, - }, + }, null, /* priority = */ false, /* static = */ true, ); } _startNewBackupWithSecureSecretStorage = async () => { - const cli = MatrixClientPeg.get(); - let info; - try { - await accessSecretStorage(async () => { - info = await cli.prepareKeyBackupVersion( - null /* random key */, - { secureSecretStorage: true }, - ); - info = await cli.createKeyBackupVersion(info); - }); - await MatrixClientPeg.get().scheduleAllGroupSessionsForBackup(); - this._loadBackupStatus(); - } catch (e) { - console.error("Error creating key backup", e); - // TODO: If creating a version succeeds, but backup fails, should we - // delete the version, disable backup, or do nothing? If we just - // disable without deleting, we'll enable on next app reload since - // it is trusted. - if (info && info.version) { - MatrixClientPeg.get().deleteKeyBackupVersion(info.version); - } - } + Modal.createTrackedDialogAsync('Key Backup', 'Key Backup', + import('../../../async-components/views/dialogs/keybackup/CreateKeyBackupDialog'), + { + secureSecretStorage: true, + onFinished: () => { + this._loadBackupStatus(); + }, + }, null, /* priority = */ false, /* static = */ true, + ); } _deleteBackup = () => {