diff --git a/src/components/views/settings/SecureBackupPanel.js b/src/components/views/settings/SecureBackupPanel.tsx similarity index 88% rename from src/components/views/settings/SecureBackupPanel.js rename to src/components/views/settings/SecureBackupPanel.tsx index d473708ce1..cdafb860d9 100644 --- a/src/components/views/settings/SecureBackupPanel.js +++ b/src/components/views/settings/SecureBackupPanel.tsx @@ -27,13 +27,29 @@ import QuestionDialog from '../dialogs/QuestionDialog'; import RestoreKeyBackupDialog from '../dialogs/security/RestoreKeyBackupDialog'; import { accessSecretStorage } from '../../../SecurityManager'; import { replaceableComponent } from "../../../utils/replaceableComponent"; +import { IKeyBackupInfo } from "matrix-js-sdk/src/crypto/keybackup"; +import { TrustInfo } from "matrix-js-sdk/src/crypto/backup"; + +interface IState { + loading: boolean; + error: null; + backupKeyStored: boolean; + backupKeyCached: boolean; + backupKeyWellFormed: boolean; + secretStorageKeyInAccount: boolean; + secretStorageReady: boolean; + backupInfo: IKeyBackupInfo; + backupSigStatus: TrustInfo; + sessionsRemaining: number; +} @replaceableComponent("views.settings.SecureBackupPanel") -export default class SecureBackupPanel extends React.PureComponent { - constructor(props) { +export default class SecureBackupPanel extends React.PureComponent<{}, IState> { + private unmounted = false; + + constructor(props: {}) { super(props); - this._unmounted = false; this.state = { loading: true, error: null, @@ -48,42 +64,42 @@ export default class SecureBackupPanel extends React.PureComponent { }; } - componentDidMount() { - this._checkKeyBackupStatus(); + public componentDidMount(): void { + this.checkKeyBackupStatus(); - MatrixClientPeg.get().on('crypto.keyBackupStatus', this._onKeyBackupStatus); + MatrixClientPeg.get().on('crypto.keyBackupStatus', this.onKeyBackupStatus); MatrixClientPeg.get().on( 'crypto.keyBackupSessionsRemaining', - this._onKeyBackupSessionsRemaining, + this.onKeyBackupSessionsRemaining, ); } - componentWillUnmount() { - this._unmounted = true; + public componentWillUnmount(): void { + this.unmounted = true; if (MatrixClientPeg.get()) { - MatrixClientPeg.get().removeListener('crypto.keyBackupStatus', this._onKeyBackupStatus); + MatrixClientPeg.get().removeListener('crypto.keyBackupStatus', this.onKeyBackupStatus); MatrixClientPeg.get().removeListener( 'crypto.keyBackupSessionsRemaining', - this._onKeyBackupSessionsRemaining, + this.onKeyBackupSessionsRemaining, ); } } - _onKeyBackupSessionsRemaining = (sessionsRemaining) => { + private onKeyBackupSessionsRemaining = (sessionsRemaining: number): void => { this.setState({ sessionsRemaining, }); - } + }; - _onKeyBackupStatus = () => { + private onKeyBackupStatus = (): void => { // This just loads the current backup status rather than forcing // a re-check otherwise we risk causing infinite loops - this._loadBackupStatus(); - } + this.loadBackupStatus(); + }; - async _checkKeyBackupStatus() { - this._getUpdatedDiagnostics(); + private async checkKeyBackupStatus(): Promise { + this.getUpdatedDiagnostics(); try { const { backupInfo, trustInfo } = await MatrixClientPeg.get().checkKeyBackup(); this.setState({ @@ -94,7 +110,7 @@ export default class SecureBackupPanel extends React.PureComponent { }); } catch (e) { console.log("Unable to fetch check backup status", e); - if (this._unmounted) return; + if (this.unmounted) return; this.setState({ loading: false, error: e, @@ -104,13 +120,13 @@ export default class SecureBackupPanel extends React.PureComponent { } } - async _loadBackupStatus() { + private async loadBackupStatus(): Promise { this.setState({ loading: true }); - this._getUpdatedDiagnostics(); + this.getUpdatedDiagnostics(); try { const backupInfo = await MatrixClientPeg.get().getKeyBackupVersion(); const backupSigStatus = await MatrixClientPeg.get().isKeyBackupTrusted(backupInfo); - if (this._unmounted) return; + if (this.unmounted) return; this.setState({ loading: false, error: null, @@ -119,7 +135,7 @@ export default class SecureBackupPanel extends React.PureComponent { }); } catch (e) { console.log("Unable to fetch key backup status", e); - if (this._unmounted) return; + if (this.unmounted) return; this.setState({ loading: false, error: e, @@ -129,7 +145,7 @@ export default class SecureBackupPanel extends React.PureComponent { } } - async _getUpdatedDiagnostics() { + private async getUpdatedDiagnostics(): Promise { const cli = MatrixClientPeg.get(); const secretStorage = cli.crypto.secretStorage; @@ -140,7 +156,7 @@ export default class SecureBackupPanel extends React.PureComponent { const secretStorageKeyInAccount = await secretStorage.hasKey(); const secretStorageReady = await cli.isSecretStorageReady(); - if (this._unmounted) return; + if (this.unmounted) return; this.setState({ backupKeyStored, backupKeyCached, @@ -150,18 +166,18 @@ export default class SecureBackupPanel extends React.PureComponent { }); } - _startNewBackup = () => { + private startNewBackup = (): void => { Modal.createTrackedDialogAsync('Key Backup', 'Key Backup', import('../../../async-components/views/dialogs/security/CreateKeyBackupDialog'), { onFinished: () => { - this._loadBackupStatus(); + this.loadBackupStatus(); }, }, null, /* priority = */ false, /* static = */ true, ); - } + }; - _deleteBackup = () => { + private deleteBackup = (): void => { Modal.createTrackedDialog('Delete Backup', '', QuestionDialog, { title: _t('Delete Backup'), description: _t( @@ -174,33 +190,33 @@ export default class SecureBackupPanel extends React.PureComponent { if (!proceed) return; this.setState({ loading: true }); MatrixClientPeg.get().deleteKeyBackupVersion(this.state.backupInfo.version).then(() => { - this._loadBackupStatus(); + this.loadBackupStatus(); }); }, }); - } + }; - _restoreBackup = async () => { + private restoreBackup = async (): Promise => { Modal.createTrackedDialog( 'Restore Backup', '', RestoreKeyBackupDialog, null, null, /* priority = */ false, /* static = */ true, ); - } + }; - _resetSecretStorage = async () => { + private resetSecretStorage = async (): Promise => { this.setState({ error: null }); try { - await accessSecretStorage(() => { }, /* forceReset = */ true); + await accessSecretStorage(async () => { }, /* forceReset = */ true); } catch (e) { console.error("Error resetting secret storage", e); - if (this._unmounted) return; + if (this.unmounted) return; this.setState({ error: e }); } - if (this._unmounted) return; - this._loadBackupStatus(); - } + if (this.unmounted) return; + this.loadBackupStatus(); + }; - render() { + public render(): JSX.Element { const { loading, error, @@ -261,7 +277,7 @@ export default class SecureBackupPanel extends React.PureComponent { ; } - let backupSigStatuses = backupSigStatus.sigs.map((sig, i) => { + let backupSigStatuses: React.ReactNode = backupSigStatus.sigs.map((sig, i) => { const deviceName = sig.device ? (sig.device.getDisplayName() || sig.device.deviceId) : null; const validity = sub => @@ -369,14 +385,14 @@ export default class SecureBackupPanel extends React.PureComponent { ; actions.push( - + { restoreButtonCaption } , ); if (!isSecureBackupRequired()) { actions.push( - + { _t("Delete Backup") } , ); @@ -390,7 +406,7 @@ export default class SecureBackupPanel extends React.PureComponent {

{ _t("Back up your keys before signing out to avoid losing them.") }

; actions.push( - + { _t("Set up") } , ); @@ -398,7 +414,7 @@ export default class SecureBackupPanel extends React.PureComponent { if (secretStorageKeyInAccount) { actions.push( - + { _t("Reset") } , );