From c43e8d684f7a82c9165fbb49ad955979f07ab14e Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 10 Jun 2025 08:55:51 +0100 Subject: [PATCH] Wire up setContentProtectionEnable for Windows & macOS (#2379) --- src/electron-main.ts | 2 ++ src/ipc.ts | 13 ----------- src/preload.cts | 13 +++++++++-- src/settings.ts | 54 +++++++++++++++++++++++++++++++++++++++++--- src/store.ts | 5 ++++ 5 files changed, 69 insertions(+), 18 deletions(-) diff --git a/src/electron-main.ts b/src/electron-main.ts index aaa0e7e79b..0241b3be6f 100644 --- a/src/electron-main.ts +++ b/src/electron-main.ts @@ -485,6 +485,8 @@ app.on("ready", async () => { }, }); + global.mainWindow.setContentProtection(store.get("enableContentProtection")); + try { console.debug("Ensuring storage is ready"); if (!(await store.prepareSafeStorage(global.mainWindow.webContents.session))) return; diff --git a/src/ipc.ts b/src/ipc.ts index 67c2eafc66..3b3d3cce9c 100644 --- a/src/ipc.ts +++ b/src/ipc.ts @@ -9,7 +9,6 @@ import { app, autoUpdater, desktopCapturer, ipcMain, powerSaveBlocker, TouchBar, import IpcMainEvent = Electron.IpcMainEvent; import { randomArray } from "./utils.js"; -import { Settings } from "./settings.js"; import { getDisplayMediaCallback, setDisplayMediaCallback } from "./displayMediaCallback.js"; import Store, { clearDataAndRelaunch } from "./store.js"; @@ -69,18 +68,6 @@ ipcMain.on("ipcCall", async function (_ev: IpcMainEvent, payload) { case "getUpdateFeedUrl": ret = autoUpdater.getFeedURL(); break; - case "getSettingValue": { - const [settingName] = args; - const setting = Settings[settingName]; - ret = await setting.read(); - break; - } - case "setSettingValue": { - const [settingName, value] = args; - const setting = Settings[settingName]; - await setting.write(value); - break; - } case "setLanguage": global.appLocalization.setAppLocale(args[0]); break; diff --git a/src/preload.cts b/src/preload.cts index e879ed5588..f8922ab632 100644 --- a/src/preload.cts +++ b/src/preload.cts @@ -54,11 +54,20 @@ contextBridge.exposeInMainWorld("electron", { protocol: string; sessionId: string; config: IConfigOptions; + supportedSettings: Record; }> { - const [{ protocol, sessionId }, config] = await Promise.all([ + const [{ protocol, sessionId }, config, supportedSettings] = await Promise.all([ ipcRenderer.invoke("getProtocol"), ipcRenderer.invoke("getConfig"), + ipcRenderer.invoke("getSupportedSettings"), ]); - return { protocol, sessionId, config }; + return { protocol, sessionId, config, supportedSettings }; + }, + + async setSettingValue(settingName: string, value: any): Promise { + return ipcRenderer.invoke("setSettingValue", settingName, value); + }, + async getSettingValue(settingName: string): Promise { + return ipcRenderer.invoke("getSettingValue", settingName); }, }); diff --git a/src/settings.ts b/src/settings.ts index 4f042ca30f..7c97aeca5d 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -5,15 +5,18 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com Please see LICENSE files in the repository root for full details. */ +import { ipcMain } from "electron"; + import * as tray from "./tray.js"; import Store from "./store.js"; interface Setting { read(): Promise; write(value: any): Promise; + supported?(): boolean; // if undefined, the setting is always supported } -export const Settings: Record = { +const Settings: Record = { "Electron.autoLaunch": { async read(): Promise { return global.launcher.isEnabled(); @@ -35,7 +38,10 @@ export const Settings: Record = { }, }, "Electron.alwaysShowMenuBar": { - // not supported on macOS + // This isn't relevant on Mac as Menu bars don't live in the app window + supported(): boolean { + return process.platform !== "darwin"; + }, async read(): Promise { return !global.mainWindow!.autoHideMenuBar; }, @@ -46,7 +52,10 @@ export const Settings: Record = { }, }, "Electron.showTrayIcon": { - // not supported on macOS + // Things other than Mac support tray icons + supported(): boolean { + return process.platform !== "darwin"; + }, async read(): Promise { return tray.hasTray(); }, @@ -68,4 +77,43 @@ export const Settings: Record = { Store.instance?.set("disableHardwareAcceleration", !value); }, }, + "Electron.enableContentProtection": { + // Unsupported on Linux https://www.electronjs.org/docs/latest/api/browser-window#winsetcontentprotectionenable-macos-windows + // Broken on macOS https://github.com/electron/electron/issues/19880 + supported(): boolean { + return process.platform === "win32"; + }, + async read(): Promise { + return Store.instance?.get("enableContentProtection"); + }, + async write(value: any): Promise { + global.mainWindow?.setContentProtection(value); + Store.instance?.set("enableContentProtection", value); + }, + }, }; + +ipcMain.handle("getSupportedSettings", async () => { + const supportedSettings: Record = {}; + for (const [key, setting] of Object.entries(Settings)) { + supportedSettings[key] = setting.supported?.() ?? true; + } + return supportedSettings; +}); +ipcMain.handle("setSettingValue", async (_ev, settingName: string, value: any) => { + const setting = Settings[settingName]; + if (!setting) { + throw new Error(`Unknown setting: ${settingName}`); + } + console.debug(`Writing setting value for: ${settingName} = ${value}`); + await setting.write(value); +}); +ipcMain.handle("getSettingValue", async (_ev, settingName: string) => { + const setting = Settings[settingName]; + if (!setting) { + throw new Error(`Unknown setting: ${settingName}`); + } + const value = await setting.read(); + console.debug(`Reading setting value for: ${settingName} = ${value}`); + return value; +}); diff --git a/src/store.ts b/src/store.ts index c9b18fb843..4137d226a2 100644 --- a/src/store.ts +++ b/src/store.ts @@ -83,6 +83,7 @@ interface StoreData { autoHideMenuBar: boolean; locale?: string | string[]; disableHardwareAcceleration: boolean; + enableContentProtection: boolean; safeStorage?: Record; /** the safeStorage backend used for the safeStorage data as written */ safeStorageBackend?: SafeStorageBackend; @@ -217,6 +218,10 @@ class Store extends ElectronStore { type: "boolean", default: false, }, + enableContentProtection: { + type: "boolean", + default: false, + }, safeStorage: { type: "object", },