Skip to content

Commit 68a4431

Browse files
committed
Add a new state between LOADING/SOFT_LOGOUT and LOGGED_IN
... so that we can transition into COMPLETE_SECURITY without going via LOGGED_IN.
1 parent ecd05e9 commit 68a4431

3 files changed

Lines changed: 104 additions & 65 deletions

File tree

src/PosthogTrackers.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ const notLoggedInMap: Record<Exclude<Views, Views.LOGGED_IN>, ScreenName> = {
2727
[Views.FORGOT_PASSWORD]: "ForgotPassword",
2828
[Views.COMPLETE_SECURITY]: "CompleteSecurity",
2929
[Views.E2E_SETUP]: "E2ESetup",
30+
[Views.PENDING_CLIENT_START]: "Loading",
3031
[Views.SOFT_LOGOUT]: "SoftLogout",
3132
[Views.LOCK_STOLEN]: "SessionLockStolen",
3233
};

src/Views.ts

Lines changed: 62 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -20,52 +20,62 @@ Please see LICENSE files in the repository root for full details.
2020
* │ LOADING │─────────────────────────────►│ CONFIRM_LOCK_ │
2121
* │ │◄─────────────────────────────│ THEFT │
2222
* └─────────────────┘ Lock theft confirmed └─────────────────┘
23-
* Session recovered │ │ │
24-
* ┌──────────────┘ │ └────────────────┐
25-
* │ ┌─────────────┘ │ No previous session
26-
* │ │ Token/OIDC login succeeded │
27-
* │ │ ▼
28-
* │ │ ┌─────────────────┐
29-
* │ │ │ WELCOME │ (from all other states
30-
* │ │ │ │ except LOCK_STOLEN)
31-
* │ │ └─────────────────┘ │
32-
* │ │ "Create Account" │ │ "Sign in" │ Client logged out
33-
* │ │ ┌────────────────────────┘ │ │
34-
* │ │ │ │ ┌────────────────────┘
35-
* │ │ │ │ │
36-
* │ │ ▼ "Create an ▼ ▼ "Forgot
37-
* │ │ ┌─────────────────┐ account" ┌─────────────────┐ password" ┌─────────────────┐
38-
* │ │ │ REGISTER │◄───────────────│ LOGIN │───────────────►│ FORGOT_PASSWORD │
39-
* │ │ │ │───────────────►│ │◄───────────────│ │
40-
* │ │ └─────────────────┘ "Sign in here" └─────────────────┘ Complete / └─────────────────┘
41-
* │ │ │ │ "Sign in instead" ▲
42-
* │ │ └────────────────────────────────┐ │ │
43-
* │ └────────────────────────────────────────┐ │ │ │
44-
* │ ▼ ▼ ▼ │
45-
* │ ┌──────────────────┐ │
46-
* │ │ (postLoginSetup) │ │
47-
* │ └──────────────────┘ │
48-
* │ ┌────────────────────────────────────┘ │ │ │
49-
* │ │ E2EE not enabled ┌─────────────┘ └──────┐ │
50-
* │ │ │ Account has │ Account lacks │
51-
* │ │ │ cross-signing │ cross-signing │
52-
* │ │ │ keys │ keys │
53-
* │ │ Client started and ▼ ▼ │
54-
* │ │ force_verification ┌─────────────────┐ ┌─────────────────┐ │
55-
* │ │ pending │ COMPLETE_ │ │ E2E_SETUP │ │
56-
* │ │ ┌─────────────────►│ SECURITY │ │ │ │
57-
* │ │ │ └─────────────────┘ └─────────────────┘ │ "Forgotten
58-
* │ │ │ ┌───────────────────────┘ │ │ your
59-
* │ │ │ │ ┌───────────────────────────────────────────────┘ │ password?"
60-
* │ │ │ │ │ │
61-
* │ │ │ │ │ (from all other states │
62-
* │ │ │ │ │ except LOCK_STOLEN) │
63-
* │ │ │ │ │ └──────────────┐ │
64-
* ▼ ▼ │ ▼ ▼ Soft logout error ▼ │
65-
* ┌─────────────────┐ ┌─────────────────┐
66-
* │ LOGGED_IN │ Re-authentication succeeded │ SOFT_LOGOUT │
67-
* │ │◄────────────────────────────────────────────────────────│ │
68-
* └─────────────────┘ └─────────────────┘
23+
* Session recovered │ │ │ Token/OIDC login succeeded
24+
* ┌──────────────┘ │ └──────────────────────────────────────────────────────────────────┐
25+
* │ └───────────────────────────────────────────┐ │
26+
* │ │ No previous session │
27+
* │ ▼ │
28+
* │ (from all other states ┌─────────────────┐ │
29+
* │ except LOCK_STOLEN) │ WELCOME │ │
30+
* │ │ │ │ │
31+
* │ │ Client logged out └─────────────────┘ │
32+
* │ │ │ │ │
33+
* │ └──────────────────────────┐ "Sign in" │ │ "Create account" │
34+
* │ │ ┌────────────┘ └──────────────┐ │
35+
* │ │ │ │ │
36+
* │ "Forgot ▼ ▼ "Create an ▼ │
37+
* │ ┌─────────────────┐ password" ┌─────────────────┐ account" ┌─────────────────┐ │
38+
* │ │ FORGOT_PASSWORD │◄───────────────│ LOGIN │───────────────►│ REGISTER │ │
39+
* │ │ │───────────────►│ │◄───────────────│ │ │
40+
* │ └─────────────────┘ Complete / └─────────────────┘ "Sign in here" └─────────────────┘ │
41+
* │ ▲ "Sign in instead" │ │ │
42+
* │ │ └──────────────────────┐ ┌─────────┘ │
43+
* │ │"Forgotten your │ │ ┌──────────────────┘
44+
* │ │ password?" │ │ │
45+
* │ │ │ │ │
46+
* │ ┌─────────────────┐ Soft-logout error │ │ │
47+
* │ │ SOFT_LOGOUT │◄───────────── (from all other states │ │ │
48+
* │ │ │ except LOCK_STOLEN) │ │ │
49+
* │ └─────────────────┘ │ │ │
50+
* │ │ Re-authentication succeeded ▼ ▼ ▼
51+
* │ │ ┌──────────────────┐
52+
* ▼ ▼ │ (postLoginSetup) │
53+
* ┌─────────────────┐ └──────────────────┘
54+
* │ PENDING_CLIENT_ │ Account has │ │ │ Account lacks
55+
* │ START │ cross-signing │ │ │ cross-signing
56+
* └─────────────────┘ keys │ │ │ keys
57+
* │ │ │ │ │
58+
* │ └───────────────────────────────┐ │ │ │
59+
* │ Client started, │ │ │ └──────┐
60+
* │ force_verification pending │ │ │ │
61+
* │ ▼ │ │ │
62+
* │ Client started, ┌─────────────────┐ │ │ │
63+
* │ force_verification │ COMPLETE_ │◄────────────┘ │ ▼
64+
* │ not needed │ SECURITY │ │ ┌─────────────────┐
65+
* │ └─────────────────┘ │ │ E2E_SETUP │
66+
* │ │ │ │ │
67+
* │ ┌─────────────────────────────────────┘ E2EE not enabled │ └─────────────────┘
68+
* │ │ ┌─────────────────────────────────────────────────────────────┘ │
69+
* │ │ │ ┌──────────────────────────────────────────────────────────────────────┘
70+
* │ │ │ │
71+
* │ │ │ │
72+
* │ │ │ │
73+
* │ │ │ │
74+
* ▼ ▼ ▼ ▼
75+
* ┌─────────────────┐
76+
* │ LOGGED_IN │
77+
* │ │
78+
* └─────────────────┘
6979
*
7080
* (from all other states)
7181
* │
@@ -102,6 +112,12 @@ enum Views {
102112
// flow to setup SSSS / cross-signing on this account
103113
E2E_SETUP,
104114

115+
/**
116+
* We have successfully recovered a session from localstorage, but the client
117+
* has not yet been started.
118+
*/
119+
PENDING_CLIENT_START,
120+
105121
// we are logged in with an active matrix client. The logged_in state also
106122
// includes guests users as they too are logged in at the client level.
107123
LOGGED_IN,

src/components/structures/MatrixChat.tsx

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1520,18 +1520,27 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
15201520
this.stores.client = MatrixClientPeg.safeGet();
15211521
StorageManager.tryPersistStorage();
15221522

1523-
// If we're in the middle of a login/registration, we wait for it to complete before transitioning to the logged
1524-
// in view the login flow will call `postLoginSetup` when it's done, which will arrange for `onShowPostLoginScreen`
1525-
// to be called.
1523+
// If we're loading the app for the first time, we can now transition to a splash screen while we wait for the
1524+
// client to start. The exceptions are:
1525+
//
1526+
// - If there is a token login in flight: in that case we wait for the login to complete (which hits
1527+
// `postLoginSetup`).
1528+
//
1529+
// - Lifecycle emits an `Action.OnLoggedIn` event during startup even if the localstorage flag indicating a
1530+
// previous soft logout is set. In that situation we actually want to wait for the `Action.ClientNotViable`
1531+
// event, which will transition us into Views.SOFT_LOGOUT. We therefore have to check for !isSoftLogout().
1532+
// There will be a subsequent `Action.OnLoggedIn` event once the reauthentication completes.
1533+
//
1534+
// XXX: fix this properly by having Lifecycle not emit OnLoggedIn when it knows it is about to emit a
1535+
// ClientNotViable.
1536+
//
1537+
// If we're already in the SOFT_LOGOUT view, that means that reauthentication has succeeded, and we can
1538+
// transition to the splash screen.
15261539
if (
1527-
!this.tokenLogin &&
1528-
!Lifecycle.isSoftLogout() &&
1529-
this.state.view !== Views.LOGIN &&
1530-
this.state.view !== Views.REGISTER &&
1531-
this.state.view !== Views.COMPLETE_SECURITY &&
1532-
this.state.view !== Views.E2E_SETUP
1540+
(this.state.view === Views.LOADING && !Lifecycle.isSoftLogout() && !this.tokenLogin) ||
1541+
this.state.view === Views.SOFT_LOGOUT
15331542
) {
1534-
this.onShowPostLoginScreen();
1543+
this.setStateForNewView({ view: Views.PENDING_CLIENT_START });
15351544
}
15361545
}
15371546

@@ -1764,15 +1773,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
17641773
const cli = MatrixClientPeg.safeGet();
17651774

17661775
const shouldForceVerification = await this.shouldForceVerification();
1767-
// XXX: Don't replace the screen if it's already one of these: postLoginSetup
1768-
// changes to these screens in certain circumstances so we shouldn't clobber it.
1769-
// We should probably have one place where we decide what the next screen is after
1770-
// login.
1771-
if (![Views.COMPLETE_SECURITY, Views.E2E_SETUP].includes(this.state.view)) {
1772-
if (shouldForceVerification) {
1773-
this.setStateForNewView({ view: Views.COMPLETE_SECURITY });
1774-
}
1775-
}
17761776

17771777
const crypto = cli.getCrypto();
17781778
if (crypto) {
@@ -1789,6 +1789,19 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
17891789
this.setState({
17901790
ready: true,
17911791
});
1792+
1793+
// If the view is PENDING_CLIENT_START, that means we recovered the session from localstorage, or from
1794+
// soft-logout: we can now transition to the logged-in view.
1795+
//
1796+
// If the view is something else, that probably means it's a login or registration view; we handle that in
1797+
// `postLoginSetup`.
1798+
if (this.state.view === Views.PENDING_CLIENT_START) {
1799+
if (shouldForceVerification) {
1800+
this.setStateForNewView({ view: Views.COMPLETE_SECURITY });
1801+
} else {
1802+
await this.onShowPostLoginScreen();
1803+
}
1804+
}
17921805
}
17931806

17941807
public showScreen(screen: string, params?: { [key: string]: any }): void {
@@ -2147,6 +2160,15 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
21472160
view = <CompleteSecurity onFinished={this.onCompleteSecurityE2eSetupFinished} />;
21482161
} else if (this.state.view === Views.E2E_SETUP) {
21492162
view = <E2eSetup onCancelled={this.onCompleteSecurityE2eSetupFinished} />;
2163+
} else if (this.state.view === Views.PENDING_CLIENT_START) {
2164+
// we think we are logged in, but are still waiting for the /sync to complete
2165+
view = (
2166+
<LoginSplashView
2167+
matrixClient={MatrixClientPeg.safeGet()}
2168+
onLogoutClick={this.onLogoutClick}
2169+
syncError={this.state.syncError}
2170+
/>
2171+
);
21502172
} else if (this.state.view === Views.LOGGED_IN) {
21512173
// `ready` and `view==LOGGED_IN` may be set before `page_type` (because the
21522174
// latter is set via the dispatcher). If we don't yet have a `page_type`,

0 commit comments

Comments
 (0)