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
|
* Begin update polling, if applicable
|
||||||
*/
|
*/
|
||||||
public startUpdater(): void {}
|
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 { type UserTab } from "../views/dialogs/UserTab";
|
||||||
import { shouldSkipSetupEncryption } from "../../utils/crypto/shouldSkipSetupEncryption";
|
import { shouldSkipSetupEncryption } from "../../utils/crypto/shouldSkipSetupEncryption";
|
||||||
import { Filter } from "../views/dialogs/spotlight/Filter";
|
import { Filter } from "../views/dialogs/spotlight/Filter";
|
||||||
import { checkSessionLockFree, getSessionLock } from "../../utils/SessionLock";
|
|
||||||
import { SessionLockStolenView } from "./auth/SessionLockStolenView";
|
import { SessionLockStolenView } from "./auth/SessionLockStolenView";
|
||||||
import { ConfirmSessionLockTheftView } from "./auth/ConfirmSessionLockTheftView";
|
import { ConfirmSessionLockTheftView } from "./auth/ConfirmSessionLockTheftView";
|
||||||
import { LoginSplashView } from "./auth/LoginSplashView";
|
import { LoginSplashView } from "./auth/LoginSplashView";
|
||||||
@@ -314,7 +313,8 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
|||||||
private async initSession(): Promise<void> {
|
private async initSession(): Promise<void> {
|
||||||
// The Rust Crypto SDK will break if two Element instances try to use the same datastore at once, so
|
// 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).
|
// 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.
|
// we failed to get the lock. onSessionLockStolen should already have been called, so nothing left to do.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -479,7 +479,8 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
|||||||
// mounted.
|
// mounted.
|
||||||
if (!this.sessionLoadStarted) {
|
if (!this.sessionLoadStarted) {
|
||||||
this.sessionLoadStarted = true;
|
this.sessionLoadStarted = true;
|
||||||
if (!checkSessionLockFree()) {
|
const platform = PlatformPeg.get();
|
||||||
|
if (platform && !platform.checkSessionLockFree()) {
|
||||||
// another instance holds the lock; confirm its theft before proceeding
|
// another instance holds the lock; confirm its theft before proceeding
|
||||||
setTimeout(() => this.setState({ view: Views.CONFIRM_LOCK_THEFT }), 0);
|
setTimeout(() => this.setState({ view: Views.CONFIRM_LOCK_THEFT }), 0);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -558,4 +558,12 @@ export default class ElectronPlatform extends BasePlatform {
|
|||||||
}
|
}
|
||||||
return url;
|
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 GenericToast from "../../components/views/toasts/GenericToast.tsx";
|
||||||
import SdkConfig from "../../SdkConfig.ts";
|
import SdkConfig from "../../SdkConfig.ts";
|
||||||
import type { ActionPayload } from "../../dispatcher/payloads.ts";
|
import type { ActionPayload } from "../../dispatcher/payloads.ts";
|
||||||
|
import * as SessionLock from "../../utils/SessionLock.ts";
|
||||||
|
|
||||||
const POKE_RATE_MS = 10 * 60 * 1000; // 10 min
|
const POKE_RATE_MS = 10 * 60 * 1000; // 10 min
|
||||||
|
|
||||||
@@ -268,4 +269,12 @@ export default class WebPlatform extends BasePlatform {
|
|||||||
public reload(): void {
|
public reload(): void {
|
||||||
window.location.reload();
|
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 BasePlatform from "../../src/BasePlatform";
|
||||||
import PlatformPeg from "../../src/PlatformPeg";
|
import PlatformPeg from "../../src/PlatformPeg";
|
||||||
|
import * as SessionLock from "../../src/utils/SessionLock";
|
||||||
|
|
||||||
// doesn't implement abstract
|
// doesn't implement abstract
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@@ -18,6 +19,14 @@ class MockPlatform extends BasePlatform {
|
|||||||
super();
|
super();
|
||||||
Object.assign(this, platformMocks);
|
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
|
* Mock Platform Peg
|
||||||
|
|||||||
@@ -1632,6 +1632,10 @@ describe("<MatrixChat />", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("Multi-tab lockout", () => {
|
describe("Multi-tab lockout", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
mockPlatformPeg();
|
||||||
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
Lifecycle.setSessionLockNotStolen();
|
Lifecycle.setSessionLockNotStolen();
|
||||||
});
|
});
|
||||||
@@ -1677,6 +1681,8 @@ describe("<MatrixChat />", () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
// make sure we start from a clean DOM for each of these tests
|
// make sure we start from a clean DOM for each of these tests
|
||||||
document.body.replaceChildren();
|
document.body.replaceChildren();
|
||||||
|
// use the MockPlatform
|
||||||
|
mockPlatformPeg();
|
||||||
});
|
});
|
||||||
|
|
||||||
function simulateSessionLockClaim() {
|
function simulateSessionLockClaim() {
|
||||||
|
|||||||
Reference in New Issue
Block a user