fix: detect the desktop link window by Electron's default user agent

Fixes #1675
This commit is contained in:
SirHephaistos authored and GitHub committed 2026-10-19 22:02:46 -05:00
1 parent b22b3679e4
commit a699feb4e2
2 files changed
+32 -4

No files matched your search

+10 -4
View File
@@ -16,14 +16,20 @@ export function isInMobileWebView(): boolean {
);
}
// The desktop app's own user agent. The link window frames the server
// cross-origin, and Electron does not carry webContents.setUserAgent into
// such a frame, so there navigator.userAgent is Electron's default, which
// still names the app: "... termix/26.10.2 Chrome/... Electron/43.7.7 ...".
const DESKTOP_USER_AGENT = /Termix-Desktop\/|\btermix\/[\w.-]+ .*\bElectron\//i;
// Being framed alone is not enough: any site could frame this page and
// receive the token posted to window.parent. The desktop app tags every
// request and frame with its own user agent, which a web page cannot fake
// in someone else's browser.
// receive the token posted to window.parent. The desktop app's user agent,
// in either form above, is something a web page cannot fake in someone
// else's browser.
export function isInElectronWebView(): boolean {
if (isInMobileWebView()) return false;
if ((window as EmbeddedFrameWindow).IS_ELECTRON_WEBVIEW) return true;
if (!/Termix-Desktop\//.test(navigator.userAgent)) return false;
if (!DESKTOP_USER_AGENT.test(navigator.userAgent)) return false;
try {
if (window.self !== window.top) return true;
} catch {
+22
View File
@@ -49,4 +49,26 @@ describe("embedded frame detection", () => {
);
expect(isInElectronWebView()).toBe(true);
});
it("spots the desktop link window by Electron's default user agent", () => {
// What a cross-origin frame inside the desktop app reports (#1675).
vi.spyOn(window, "top", "get").mockReturnValue({} as Window);
vi.spyOn(navigator, "userAgent", "get").mockReturnValue(
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) termix/26.10.2 Chrome/150.0.7871.250 Electron/43.7.7 Safari/537.36",
);
expect(isInElectronWebView()).toBe(true);
});
it("does not trust another Electron app or a plain browser frame", () => {
vi.spyOn(window, "top", "get").mockReturnValue({} as Window);
const ua = vi.spyOn(navigator, "userAgent", "get");
ua.mockReturnValue(
"Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0 Safari/537.36",
);
expect(isInElectronWebView()).toBe(false);
ua.mockReturnValue(
"Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) other-app/1.0.0 Chrome/150.0 Electron/43.7.7 Safari/537.36",
);
expect(isInElectronWebView()).toBe(false);
});
});