diff --git a/src/Lifecycle.ts b/src/Lifecycle.ts index f87af1a791..4602f2b5bb 100644 --- a/src/Lifecycle.ts +++ b/src/Lifecycle.ts @@ -366,7 +366,7 @@ async function abortLogin() { // The plan is to gradually move the localStorage access done here into // SessionStore to avoid bugs where the view becomes out-of-sync with // localStorage (e.g. isGuest etc.) -async function restoreFromLocalStorage(opts?: { ignoreGuest?: boolean }): Promise { +export async function restoreFromLocalStorage(opts?: { ignoreGuest?: boolean }): Promise { const ignoreGuest = opts?.ignoreGuest; if (!localStorage) { diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx index 62c729c422..a399d92eaf 100644 --- a/src/components/structures/MatrixChat.tsx +++ b/src/components/structures/MatrixChat.tsx @@ -218,6 +218,7 @@ export default class MatrixChat extends React.PureComponent { private screenAfterLogin?: IScreen; private windowWidth: number; private pageChanging: boolean; + private tokenLogin?: boolean; private accountPassword?: string; private accountPasswordTimer?: NodeJS.Timeout; private focusComposer: boolean; @@ -323,13 +324,16 @@ export default class MatrixChat extends React.PureComponent { Lifecycle.attemptTokenLogin( this.props.realQueryParams, this.props.defaultDeviceDisplayName, - ).then((loggedIn) => { + ).then(async (loggedIn) => { if (loggedIn) { + this.tokenLogin = true; this.props.onTokenLoginCompleted(); - // don't do anything else until the page reloads - just stay in - // the 'loading' state. - return; + // Create and start the client + await Lifecycle.restoreFromLocalStorage({ + ignoreGuest: true, + }); + return this.postLoginSetup(); } // if the user has followed a login or register link, don't reanimate @@ -353,6 +357,39 @@ export default class MatrixChat extends React.PureComponent { CountlyAnalytics.instance.enable(/* anonymous = */ true); } + private async postLoginSetup() { + const cli = MatrixClientPeg.get(); + const cryptoEnabled = cli.isCryptoEnabled(); + + const promisesList = [this.firstSyncPromise.promise]; + if (cryptoEnabled) { + // wait for the client to finish downloading cross-signing keys for us so we + // know whether or not we have keys set up on this account + promisesList.push(cli.downloadKeys([cli.getUserId()])); + } + + // Now update the state to say we're waiting for the first sync to complete rather + // than for the login to finish. + this.setState({ pendingInitialSync: true }); + + await Promise.all(promisesList); + + if (!cryptoEnabled) { + this.setState({ pendingInitialSync: false }); + return; + } + + const crossSigningIsSetUp = cli.getStoredCrossSigningForUser(cli.getUserId()); + if (crossSigningIsSetUp) { + this.setStateForNewView({ view: Views.COMPLETE_SECURITY }); + } else if (await cli.doesServerSupportUnstableFeature("org.matrix.e2e_cross_signing")) { + this.setStateForNewView({ view: Views.E2E_SETUP }); + } else { + this.onLoggedIn(); + } + this.setState({ pendingInitialSync: false }); + } + // TODO: [REACT-WARNING] Replace with appropriate lifecycle stage // eslint-disable-next-line camelcase UNSAFE_componentWillUpdate(props, state) { @@ -1833,40 +1870,7 @@ export default class MatrixChat extends React.PureComponent { // Create and start the client await Lifecycle.setLoggedIn(credentials); - - const cli = MatrixClientPeg.get(); - const cryptoEnabled = cli.isCryptoEnabled(); - if (!cryptoEnabled) { - this.onLoggedIn(); - } - - const promisesList = [this.firstSyncPromise.promise]; - if (cryptoEnabled) { - // wait for the client to finish downloading cross-signing keys for us so we - // know whether or not we have keys set up on this account - promisesList.push(cli.downloadKeys([cli.getUserId()])); - } - - // Now update the state to say we're waiting for the first sync to complete rather - // than for the login to finish. - this.setState({ pendingInitialSync: true }); - - await Promise.all(promisesList); - - if (!cryptoEnabled) { - this.setState({ pendingInitialSync: false }); - return; - } - - const crossSigningIsSetUp = cli.getStoredCrossSigningForUser(cli.getUserId()); - if (crossSigningIsSetUp) { - this.setStateForNewView({ view: Views.COMPLETE_SECURITY }); - } else if (await cli.doesServerSupportUnstableFeature("org.matrix.e2e_cross_signing")) { - this.setStateForNewView({ view: Views.E2E_SETUP }); - } else { - this.onLoggedIn(); - } - this.setState({ pendingInitialSync: false }); + await this.postLoginSetup(); }; // complete security / e2e setup has finished @@ -1910,6 +1914,7 @@ export default class MatrixChat extends React.PureComponent { ); } else if (this.state.view === Views.LOGGED_IN) { diff --git a/src/components/structures/auth/E2eSetup.js b/src/components/structures/auth/E2eSetup.js index 6df8158002..d97a972718 100644 --- a/src/components/structures/auth/E2eSetup.js +++ b/src/components/structures/auth/E2eSetup.js @@ -24,6 +24,7 @@ export default class E2eSetup extends React.Component { static propTypes = { onFinished: PropTypes.func.isRequired, accountPassword: PropTypes.string, + tokenLogin: PropTypes.bool, }; render() { @@ -33,6 +34,7 @@ export default class E2eSetup extends React.Component { diff --git a/src/components/views/dialogs/security/CreateCrossSigningDialog.js b/src/components/views/dialogs/security/CreateCrossSigningDialog.js index 226419e759..be546d2616 100644 --- a/src/components/views/dialogs/security/CreateCrossSigningDialog.js +++ b/src/components/views/dialogs/security/CreateCrossSigningDialog.js @@ -34,6 +34,7 @@ import InteractiveAuthDialog from '../InteractiveAuthDialog'; export default class CreateCrossSigningDialog extends React.PureComponent { static propTypes = { accountPassword: PropTypes.string, + tokenLogin: PropTypes.bool, }; constructor(props) { @@ -96,6 +97,9 @@ export default class CreateCrossSigningDialog extends React.PureComponent { user: MatrixClientPeg.get().getUserId(), password: this.state.accountPassword, }); + } else if (this.props.tokenLogin) { + // We are hoping the grace period is active + await makeRequest({}); } else { const dialogAesthetics = { [SSOAuthEntry.PHASE_PREAUTH]: { @@ -144,6 +148,12 @@ export default class CreateCrossSigningDialog extends React.PureComponent { }); this.props.onFinished(true); } catch (e) { + if (this.props.tokenLogin) { + // ignore any failures, we are relying on grace period here + this.props.onFinished(); + return; + } + this.setState({ error: e }); console.error("Error bootstrapping cross-signing", e); }