From 043a5c7c0dc43219a0268969baac3deee43008ef Mon Sep 17 00:00:00 2001 From: Brendan Allan <14191578+Brendonovich@users.noreply.github.com> Date: Wed, 6 May 2026 16:40:45 +0800 Subject: [PATCH] feat(desktop): implement clipboard write permission handling (#25998) --- packages/desktop/src/main/windows.ts | 30 ++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/packages/desktop/src/main/windows.ts b/packages/desktop/src/main/windows.ts index 387e793b0e..41abfc784d 100644 --- a/packages/desktop/src/main/windows.ts +++ b/packages/desktop/src/main/windows.ts @@ -8,6 +8,7 @@ const root = dirname(fileURLToPath(import.meta.url)) const rendererRoot = join(root, "../renderer") const rendererProtocol = "oc" const rendererHost = "renderer" +const clipboardWritePermission = "clipboard-sanitized-write" protocol.registerSchemesAsPrivileged([ { @@ -107,6 +108,8 @@ export function createMainWindow() { }, }) + allowClipboardWrite(win) + win.webContents.session.webRequest.onBeforeSendHeaders((details, callback) => { const { requestHeaders } = details upsertKeyValue(requestHeaders, "Access-Control-Allow-Origin", ["*"]) @@ -157,6 +160,8 @@ export function createLoadingWindow() { }, }) + allowClipboardWrite(win) + loadWindow(win, "loading.html") return win @@ -191,6 +196,31 @@ function loadWindow(win: BrowserWindow, html: string) { void win.loadURL(`${rendererProtocol}://${rendererHost}/${html}`) } + +function allowClipboardWrite(win: BrowserWindow) { + win.webContents.session.setPermissionRequestHandler((webContents, permission, callback, details) => { + callback( + permission === clipboardWritePermission && + isTrustedRendererUrl(details.requestingUrl) && + webContents.id === win.webContents.id, + ) + }) + win.webContents.session.setPermissionCheckHandler((webContents, permission, requestingOrigin, details) => { + if (permission !== clipboardWritePermission) return false + if (webContents && webContents.id !== win.webContents.id) return false + return isTrustedRendererUrl(details.requestingUrl) || isTrustedRendererUrl(requestingOrigin) + }) +} + +function isTrustedRendererUrl(value?: string) { + if (!value || !URL.canParse(value)) return false + const url = new URL(value) + if (url.protocol === `${rendererProtocol}:` && url.host === rendererHost) return true + const devUrl = process.env.ELECTRON_RENDERER_URL + if (!devUrl || !URL.canParse(devUrl)) return false + return url.origin === new URL(devUrl).origin +} + function wireZoom(win: BrowserWindow) { win.webContents.setZoomFactor(1) win.webContents.on("zoom-changed", () => {