feat: Disable session lock when running in element-desktop (#30643)
* feat: Disable session lock when running in element-desktop * feat: Use Platform abstractions over direct invocation for session lock. * fix: Remove window.electron checks from session lock methods. * docs: Remove extraneous doc comments. * feat: Convert BasePlatform session methods to abstract methods. * fix: Check for PlatformPeg instance in session lock. * fix: Remove async marker from checkSessionLockFree
This commit is contained in:
@@ -508,4 +508,19 @@ export default abstract class BasePlatform {
|
||||
* Begin update polling, if applicable
|
||||
*/
|
||||
public startUpdater(): void {}
|
||||
|
||||
/**
|
||||
* Checks if the current session is lock-free, i.e., no other instance is holding the session lock.
|
||||
* Platforms that support session locking should override this method.
|
||||
* @returns {boolean} True if the session is lock-free, false otherwise.
|
||||
*/
|
||||
public abstract checkSessionLockFree(): boolean;
|
||||
/**
|
||||
* Attempts to acquire a session lock for this instance.
|
||||
* If another instance is detected, calls the provided callback.
|
||||
* Platforms that support session locking should override this method.
|
||||
* @param _onNewInstance Callback to invoke if a new instance is detected.
|
||||
* @returns {Promise<boolean>} True if the lock was acquired, false otherwise.
|
||||
*/
|
||||
public abstract getSessionLock(_onNewInstance: () => Promise<void>): Promise<boolean>;
|
||||
}
|
||||
|
||||
@@ -130,7 +130,6 @@ import { NotificationLevel } from "../../stores/notifications/NotificationLevel"
|
||||
import { type UserTab } from "../views/dialogs/UserTab";
|
||||
import { shouldSkipSetupEncryption } from "../../utils/crypto/shouldSkipSetupEncryption";
|
||||
import { Filter } from "../views/dialogs/spotlight/Filter";
|
||||
import { checkSessionLockFree, getSessionLock } from "../../utils/SessionLock";
|
||||
import { SessionLockStolenView } from "./auth/SessionLockStolenView";
|
||||
import { ConfirmSessionLockTheftView } from "./auth/ConfirmSessionLockTheftView";
|
||||
import { LoginSplashView } from "./auth/LoginSplashView";
|
||||
@@ -314,7 +313,8 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
private async initSession(): Promise<void> {
|
||||
// The Rust Crypto SDK will break if two Element instances try to use the same datastore at once, so
|
||||
// make sure we are the only Element instance in town (on this browser/domain).
|
||||
if (!(await getSessionLock(() => this.onSessionLockStolen()))) {
|
||||
const platform = PlatformPeg.get();
|
||||
if (platform && !(await platform.getSessionLock(() => this.onSessionLockStolen()))) {
|
||||
// we failed to get the lock. onSessionLockStolen should already have been called, so nothing left to do.
|
||||
return;
|
||||
}
|
||||
@@ -479,7 +479,8 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
// mounted.
|
||||
if (!this.sessionLoadStarted) {
|
||||
this.sessionLoadStarted = true;
|
||||
if (!checkSessionLockFree()) {
|
||||
const platform = PlatformPeg.get();
|
||||
if (platform && !platform.checkSessionLockFree()) {
|
||||
// another instance holds the lock; confirm its theft before proceeding
|
||||
setTimeout(() => this.setState({ view: Views.CONFIRM_LOCK_THEFT }), 0);
|
||||
} else {
|
||||
|
||||
@@ -558,4 +558,12 @@ export default class ElectronPlatform extends BasePlatform {
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
public checkSessionLockFree(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
public async getSessionLock(_onNewInstance: () => Promise<void>): Promise<boolean> {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import ToastStore from "../../stores/ToastStore.ts";
|
||||
import GenericToast from "../../components/views/toasts/GenericToast.tsx";
|
||||
import SdkConfig from "../../SdkConfig.ts";
|
||||
import type { ActionPayload } from "../../dispatcher/payloads.ts";
|
||||
import * as SessionLock from "../../utils/SessionLock.ts";
|
||||
|
||||
const POKE_RATE_MS = 10 * 60 * 1000; // 10 min
|
||||
|
||||
@@ -268,4 +269,12 @@ export default class WebPlatform extends BasePlatform {
|
||||
public reload(): void {
|
||||
window.location.reload();
|
||||
}
|
||||
|
||||
public checkSessionLockFree(): boolean {
|
||||
return SessionLock.checkSessionLockFree();
|
||||
}
|
||||
|
||||
public async getSessionLock(onNewInstance: () => Promise<void>): Promise<boolean> {
|
||||
return SessionLock.getSessionLock(onNewInstance);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import { type MethodLikeKeys, mocked, type MockedObject } from "jest-mock";
|
||||
|
||||
import BasePlatform from "../../src/BasePlatform";
|
||||
import PlatformPeg from "../../src/PlatformPeg";
|
||||
import * as SessionLock from "../../src/utils/SessionLock";
|
||||
|
||||
// doesn't implement abstract
|
||||
// @ts-ignore
|
||||
@@ -18,6 +19,14 @@ class MockPlatform extends BasePlatform {
|
||||
super();
|
||||
Object.assign(this, platformMocks);
|
||||
}
|
||||
|
||||
public checkSessionLockFree(): boolean {
|
||||
return SessionLock.checkSessionLockFree();
|
||||
}
|
||||
|
||||
public async getSessionLock(onNewInstance: () => Promise<void>): Promise<boolean> {
|
||||
return SessionLock.getSessionLock(onNewInstance);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Mock Platform Peg
|
||||
|
||||
@@ -1632,6 +1632,10 @@ describe("<MatrixChat />", () => {
|
||||
});
|
||||
|
||||
describe("Multi-tab lockout", () => {
|
||||
beforeEach(() => {
|
||||
mockPlatformPeg();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
Lifecycle.setSessionLockNotStolen();
|
||||
});
|
||||
@@ -1677,6 +1681,8 @@ describe("<MatrixChat />", () => {
|
||||
beforeEach(() => {
|
||||
// make sure we start from a clean DOM for each of these tests
|
||||
document.body.replaceChildren();
|
||||
// use the MockPlatform
|
||||
mockPlatformPeg();
|
||||
});
|
||||
|
||||
function simulateSessionLockClaim() {
|
||||
|
||||
Reference in New Issue
Block a user