From c0632d01956bfc39fa2aac3b7618550b47272ccb Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 12 May 2020 17:17:17 -0600 Subject: [PATCH] Acquire a new session before enacting deactivation Fixes https://github.com/vector-im/riot-web/issues/13645 Every time the checkbox value changes we acquire a new session now. This avoids us asking the server to change its direction partway through the request. This causes a bit of UI jerk as the dialog goes from auth -> loading -> auth, however it's better than the alternative of reworking the entire UIA structure to support the `authData` dict changing. Originally this commit consisted of a `disabled` flag on the `InteractiveAuth` component which carried through to the stage's component, however it turns out that stack doesn't respect changes to the `authData` prop, which means the session ID we eventually send down is wrong (`erase: false` instead of the one with `erase: true`). Therefore, we do some logic to ensure we remount `InteractiveAuth` completely. Further work in this area is described in https://github.com/vector-im/riot-web/issues/13646 --- .../views/dialogs/DeactivateAccountDialog.js | 46 ++++++++++++------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/src/components/views/dialogs/DeactivateAccountDialog.js b/src/components/views/dialogs/DeactivateAccountDialog.js index b269ec2fdb..d84042011d 100644 --- a/src/components/views/dialogs/DeactivateAccountDialog.js +++ b/src/components/views/dialogs/DeactivateAccountDialog.js @@ -34,6 +34,7 @@ export default class DeactivateAccountDialog extends React.Component { shouldErase: false, errStr: null, authData: null, // for UIA + authEnabled: true, // see usages for information // A few strings that are passed to InteractiveAuth for design or are displayed // next to the InteractiveAuth component. @@ -42,21 +43,7 @@ export default class DeactivateAccountDialog extends React.Component { continueKind: null, }; - MatrixClientPeg.get().deactivateAccount(null, false).then(r => { - // If we got here, oops. The server didn't require any auth. - // Our application lifecycle will catch the error and do the logout bits. - // We'll try to log something in an vain attempt to record what happened (storage - // is also obliterated on logout). - console.warn("User's account got deactivated without confirmation: Server had no auth"); - this.setState({errStr: _t("Server did not require any authentication")}); - }).catch(e => { - if (e && e.httpStatus === 401 && e.data) { - // Valid UIA response - this.setState({authData: e.data}); - } else { - this.setState({errStr: _t("Server did not return valid authentication information.")}); - } - }); + this._initAuth(/* shouldErase= */false); } _onStagePhaseChange = (stage, phase) => { @@ -124,13 +111,40 @@ export default class DeactivateAccountDialog extends React.Component { _onEraseFieldChange = (ev) => { this.setState({ shouldErase: ev.target.checked, + + // Disable the auth form because we're going to have to reinitialize the auth + // information. We do this because we can't modify the parameters in the UIA + // session, and the user will have selected something which changes the request. + // Therefore, we throw away the last auth session and try a new one. + authEnabled: false, }); + + // As mentioned above, set up for auth again to get updated UIA session info + this._initAuth(/* shouldErase= */ev.target.checked); }; _onCancel() { this.props.onFinished(false); } + _initAuth(shouldErase) { + MatrixClientPeg.get().deactivateAccount(null, shouldErase).then(r => { + // If we got here, oops. The server didn't require any auth. + // Our application lifecycle will catch the error and do the logout bits. + // We'll try to log something in an vain attempt to record what happened (storage + // is also obliterated on logout). + console.warn("User's account got deactivated without confirmation: Server had no auth"); + this.setState({errStr: _t("Server did not require any authentication")}); + }).catch(e => { + if (e && e.httpStatus === 401 && e.data) { + // Valid UIA response + this.setState({authData: e.data, authEnabled: true}); + } else { + this.setState({errStr: _t("Server did not return valid authentication information.")}); + } + }); + }; + render() { const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); @@ -142,7 +156,7 @@ export default class DeactivateAccountDialog extends React.Component { } let auth =
{_t("Loading...")}
; - if (this.state.authData) { + if (this.state.authData && this.state.authEnabled) { auth = (
{this.state.bodyText}