fix(desktop): restrict renderer navigation
This commit is contained in:
parent
c7871e14d4
commit
0e1bedda1b
3 changed files with 46 additions and 0 deletions
22
packages/desktop/src/main/navigation-policy.test.ts
Normal file
22
packages/desktop/src/main/navigation-policy.test.ts
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import { describe, expect, test } from "bun:test"
|
||||
import { isTrustedNavigationUrl } from "./navigation-policy"
|
||||
|
||||
describe("isTrustedNavigationUrl", () => {
|
||||
test("allows packaged renderer pages", () => {
|
||||
expect(isTrustedNavigationUrl("oc://renderer/index.html", undefined)).toBe(true)
|
||||
expect(isTrustedNavigationUrl("oc://renderer/assets/index.js", undefined)).toBe(true)
|
||||
})
|
||||
|
||||
test("rejects other hosts and protocols", () => {
|
||||
expect(isTrustedNavigationUrl("oc://attacker/index.html", undefined)).toBe(false)
|
||||
expect(isTrustedNavigationUrl("https://example.com", undefined)).toBe(false)
|
||||
expect(isTrustedNavigationUrl("not a url", undefined)).toBe(false)
|
||||
})
|
||||
|
||||
test("allows only the configured development origin", () => {
|
||||
const devUrl = "http://localhost:5173"
|
||||
expect(isTrustedNavigationUrl("http://localhost:5173/index.html", devUrl)).toBe(true)
|
||||
expect(isTrustedNavigationUrl("http://localhost:5174/index.html", devUrl)).toBe(false)
|
||||
expect(isTrustedNavigationUrl("https://localhost:5173/index.html", devUrl)).toBe(false)
|
||||
})
|
||||
})
|
||||
10
packages/desktop/src/main/navigation-policy.ts
Normal file
10
packages/desktop/src/main/navigation-policy.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
const rendererProtocol = "oc:"
|
||||
const rendererHost = "renderer"
|
||||
|
||||
export function isTrustedNavigationUrl(value: string, devUrl = process.env.ELECTRON_RENDERER_URL) {
|
||||
if (!URL.canParse(value)) return false
|
||||
const url = new URL(value)
|
||||
if (url.protocol === rendererProtocol && url.host === rendererHost) return true
|
||||
if (!devUrl || !URL.canParse(devUrl)) return false
|
||||
return url.origin === new URL(devUrl).origin
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@ import { dirname, isAbsolute, join, relative, resolve } from "node:path"
|
|||
import { fileURLToPath, pathToFileURL } from "node:url"
|
||||
import type { TitlebarTheme } from "../preload/types"
|
||||
import { exportDebugLogs, write as writeLog } from "./logging"
|
||||
import { isTrustedNavigationUrl } from "./navigation-policy"
|
||||
import { getStore, removeStoreFile } from "./store"
|
||||
import { PINCH_ZOOM_ENABLED_KEY, WINDOW_IDS_KEY } from "./store-keys"
|
||||
import { createUnresponsiveSampler } from "./unresponsive"
|
||||
|
|
@ -203,6 +204,7 @@ export function createMainWindow(id: string = randomUUID()) {
|
|||
})
|
||||
|
||||
allowRendererPermissions(win)
|
||||
restrictNavigation(win)
|
||||
wireWindowRecovery(win, id)
|
||||
|
||||
win.webContents.session.webRequest.onBeforeSendHeaders((details, callback) => {
|
||||
|
|
@ -229,6 +231,18 @@ export function createMainWindow(id: string = randomUUID()) {
|
|||
return win
|
||||
}
|
||||
|
||||
function restrictNavigation(win: BrowserWindow) {
|
||||
win.webContents.on("will-navigate", (event, url) => {
|
||||
if (isTrustedNavigationUrl(url)) return
|
||||
event.preventDefault()
|
||||
writeLog("window", "blocked renderer navigation", { url }, "warn")
|
||||
})
|
||||
win.webContents.setWindowOpenHandler(({ url }) => {
|
||||
writeLog("window", "blocked renderer window", { url }, "warn")
|
||||
return { action: "deny" }
|
||||
})
|
||||
}
|
||||
|
||||
function registerWindow(win: BrowserWindow, id: string) {
|
||||
windowIDs.set(win, id)
|
||||
registry.register(id, win)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue