diff --git a/src/Lifecycle.ts b/src/Lifecycle.ts index 273b2eeb107..c1559886b47 100644 --- a/src/Lifecycle.ts +++ b/src/Lifecycle.ts @@ -701,6 +701,43 @@ export async function setLoggedIn(credentials: IMatrixClientCreds): Promise { + const oldUserId = MatrixClientPeg.safeGet().getUserId(); + const oldDeviceId = MatrixClientPeg.safeGet().getDeviceId(); + + stopMatrixClient(); // unsets MatrixClientPeg.get() + localStorage.removeItem("mx_soft_logout"); + _isLoggingOut = false; + + const overwrite = credentials.userId !== oldUserId || credentials.deviceId !== oldDeviceId; + if (overwrite) { + logger.warn("Clearing all data: Old session belongs to a different user/session"); + } + + if (!credentials.pickleKey && credentials.deviceId !== undefined) { + logger.info("Lifecycle#hydrateSession: Pickle key not provided - trying to get one"); + credentials.pickleKey = + (await PlatformPeg.get()?.getPickleKey(credentials.userId, credentials.deviceId)) ?? undefined; + } + + return doSetLoggedIn(credentials, overwrite, false); +} + /** * When we have a authenticated via OIDC-native flow and have a refresh token * try to create a token refresher. diff --git a/src/components/structures/auth/SoftLogout.tsx b/src/components/structures/auth/SoftLogout.tsx index 7ebcc7af6a4..68fe65aedc2 100644 --- a/src/components/structures/auth/SoftLogout.tsx +++ b/src/components/structures/auth/SoftLogout.tsx @@ -168,7 +168,7 @@ export default class SoftLogout extends React.Component { return; } - Lifecycle.setLoggedIn(credentials).catch((e) => { + Lifecycle.hydrateSession(credentials).catch((e) => { logger.error(e); this.setState({ busy: false, errorText: _t("auth|failed_soft_logout_auth") }); }); @@ -204,7 +204,7 @@ export default class SoftLogout extends React.Component { return false; } - return Lifecycle.setLoggedIn(credentials) + return Lifecycle.hydrateSession(credentials) .then(() => { if (this.props.onTokenLoginCompleted) { this.props.onTokenLoginCompleted(); diff --git a/test/unit-tests/Lifecycle-test.ts b/test/unit-tests/Lifecycle-test.ts index 62a93b6d388..97ab3c61098 100644 --- a/test/unit-tests/Lifecycle-test.ts +++ b/test/unit-tests/Lifecycle-test.ts @@ -38,6 +38,12 @@ const webCrypto = new Crypto(); const windowCrypto = window.crypto; describe("Lifecycle", () => { + const homeserverUrl = "https://domain"; + const identityServerUrl = "https://is.org"; + const userId = "@alice:domain"; + const deviceId = "abc123"; + const accessToken = "test-access-token"; + let mockPlatform: MockedObject; const realLocalStorage = global.localStorage; @@ -53,7 +59,7 @@ describe("Lifecycle", () => { removeAllListeners: jest.fn(), clearStores: jest.fn(), getAccountData: jest.fn(), - getDeviceId: jest.fn(), + getDeviceId: jest.fn().mockReturnValue(deviceId), isVersionSupported: jest.fn().mockResolvedValue(true), getCrypto: jest.fn(), getClientWellKnown: jest.fn(), @@ -156,11 +162,6 @@ describe("Lifecycle", () => { }); }; - const homeserverUrl = "https://server.org"; - const identityServerUrl = "https://is.org"; - const userId = "@alice:server.org"; - const deviceId = "abc123"; - const accessToken = "test-access-token"; const localStorageSession = { mx_hs_url: homeserverUrl, mx_is_url: identityServerUrl, @@ -605,6 +606,38 @@ describe("Lifecycle", () => { expect(MatrixClientPeg.start).toHaveBeenCalled(); }); + describe("after a soft-logout", () => { + beforeEach(async () => { + await setLoggedIn(credentials); + localStorage.setItem("mx_soft_logout", "true"); + }); + + it("should not clear the storage if device is the same", async () => { + await Lifecycle.hydrateSession(credentials); + + expect(localStorage.removeItem).toHaveBeenCalledWith("mx_soft_logout"); + expect(mockClient.getUserId).toHaveReturnedWith(userId); + expect(mockClient.getDeviceId).toHaveReturnedWith(deviceId); + expect(mockClient.clearStores).toHaveBeenCalledTimes(1); + }); + + it("should clear the storage if device is not the same", async () => { + const fakeCredentials = { + homeserverUrl, + identityServerUrl, + userId: "@bob:domain", + deviceId, + accessToken, + }; + await Lifecycle.hydrateSession(fakeCredentials); + + expect(localStorage.removeItem).toHaveBeenCalledWith("mx_soft_logout"); + expect(mockClient.getUserId).toHaveReturnedWith(userId); + expect(mockClient.getDeviceId).toHaveReturnedWith(deviceId); + expect(mockClient.clearStores).toHaveBeenCalledTimes(2); + }); + }); + describe("without a pickle key", () => { beforeEach(() => { jest.spyOn(mockPlatform, "createPickleKey").mockResolvedValue(null);