Revert deletion of hydrateSession (#29703)
* Revert deletion of hydrateSession * remove line break to make prettier happy :-) * add tests for hydrateSession on soft logout * fix coding style --------- Co-authored-by: Florian Duros <florianduros@element.io>
This commit is contained in:
@@ -701,6 +701,43 @@ export async function setLoggedIn(credentials: IMatrixClientCreds): Promise<Matr
|
|||||||
return doSetLoggedIn(credentials, true, true);
|
return doSetLoggedIn(credentials, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hydrates an existing session by using the credentials provided. This will
|
||||||
|
* not clear any local storage, unlike setLoggedIn().
|
||||||
|
*
|
||||||
|
* Stops the existing Matrix client (without clearing its data) and starts a
|
||||||
|
* new one in its place. This additionally starts all other react-sdk services
|
||||||
|
* which use the new Matrix client.
|
||||||
|
*
|
||||||
|
* If the credentials belong to a different user from the session already stored,
|
||||||
|
* the old session will be cleared automatically.
|
||||||
|
*
|
||||||
|
* @param {IMatrixClientCreds} credentials The credentials to use
|
||||||
|
*
|
||||||
|
* @returns {Promise} promise which resolves to the new MatrixClient once it has been started
|
||||||
|
*/
|
||||||
|
export async function hydrateSession(credentials: IMatrixClientCreds): Promise<MatrixClient> {
|
||||||
|
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
|
* When we have a authenticated via OIDC-native flow and have a refresh token
|
||||||
* try to create a token refresher.
|
* try to create a token refresher.
|
||||||
|
|||||||
@@ -168,7 +168,7 @@ export default class SoftLogout extends React.Component<IProps, IState> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Lifecycle.setLoggedIn(credentials).catch((e) => {
|
Lifecycle.hydrateSession(credentials).catch((e) => {
|
||||||
logger.error(e);
|
logger.error(e);
|
||||||
this.setState({ busy: false, errorText: _t("auth|failed_soft_logout_auth") });
|
this.setState({ busy: false, errorText: _t("auth|failed_soft_logout_auth") });
|
||||||
});
|
});
|
||||||
@@ -204,7 +204,7 @@ export default class SoftLogout extends React.Component<IProps, IState> {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Lifecycle.setLoggedIn(credentials)
|
return Lifecycle.hydrateSession(credentials)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
if (this.props.onTokenLoginCompleted) {
|
if (this.props.onTokenLoginCompleted) {
|
||||||
this.props.onTokenLoginCompleted();
|
this.props.onTokenLoginCompleted();
|
||||||
|
|||||||
@@ -38,6 +38,12 @@ const webCrypto = new Crypto();
|
|||||||
const windowCrypto = window.crypto;
|
const windowCrypto = window.crypto;
|
||||||
|
|
||||||
describe("Lifecycle", () => {
|
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<BasePlatform>;
|
let mockPlatform: MockedObject<BasePlatform>;
|
||||||
|
|
||||||
const realLocalStorage = global.localStorage;
|
const realLocalStorage = global.localStorage;
|
||||||
@@ -53,7 +59,7 @@ describe("Lifecycle", () => {
|
|||||||
removeAllListeners: jest.fn(),
|
removeAllListeners: jest.fn(),
|
||||||
clearStores: jest.fn(),
|
clearStores: jest.fn(),
|
||||||
getAccountData: jest.fn(),
|
getAccountData: jest.fn(),
|
||||||
getDeviceId: jest.fn(),
|
getDeviceId: jest.fn().mockReturnValue(deviceId),
|
||||||
isVersionSupported: jest.fn().mockResolvedValue(true),
|
isVersionSupported: jest.fn().mockResolvedValue(true),
|
||||||
getCrypto: jest.fn(),
|
getCrypto: jest.fn(),
|
||||||
getClientWellKnown: 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 = {
|
const localStorageSession = {
|
||||||
mx_hs_url: homeserverUrl,
|
mx_hs_url: homeserverUrl,
|
||||||
mx_is_url: identityServerUrl,
|
mx_is_url: identityServerUrl,
|
||||||
@@ -605,6 +606,38 @@ describe("Lifecycle", () => {
|
|||||||
expect(MatrixClientPeg.start).toHaveBeenCalled();
|
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", () => {
|
describe("without a pickle key", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.spyOn(mockPlatform, "createPickleKey").mockResolvedValue(null);
|
jest.spyOn(mockPlatform, "createPickleKey").mockResolvedValue(null);
|
||||||
|
|||||||
Reference in New Issue
Block a user