fix(desktop): restrict external links
This commit is contained in:
parent
c7871e14d4
commit
c552cee37e
3 changed files with 31 additions and 1 deletions
19
packages/desktop/src/main/external-link.test.ts
Normal file
19
packages/desktop/src/main/external-link.test.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
import { describe, expect, test } from "bun:test"
|
||||
import { safeExternalUrl } from "./external-link"
|
||||
|
||||
describe("safeExternalUrl", () => {
|
||||
test("allows web links", () => {
|
||||
expect(safeExternalUrl("https://opencode.ai/docs")).toBe("https://opencode.ai/docs")
|
||||
expect(safeExternalUrl("http://localhost:3000/callback")).toBe("http://localhost:3000/callback")
|
||||
})
|
||||
|
||||
test("rejects executable and application protocols", () => {
|
||||
expect(safeExternalUrl("file:///tmp/script.sh")).toBeUndefined()
|
||||
expect(safeExternalUrl("ssh://attacker.example")).toBeUndefined()
|
||||
expect(safeExternalUrl("custom-handler:payload")).toBeUndefined()
|
||||
})
|
||||
|
||||
test("rejects malformed URLs", () => {
|
||||
expect(safeExternalUrl("not a url")).toBeUndefined()
|
||||
})
|
||||
})
|
||||
8
packages/desktop/src/main/external-link.ts
Normal file
8
packages/desktop/src/main/external-link.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
const allowedProtocols = new Set(["https:", "http:"])
|
||||
|
||||
export function safeExternalUrl(value: string) {
|
||||
if (!URL.canParse(value)) return
|
||||
const url = new URL(value)
|
||||
if (!allowedProtocols.has(url.protocol)) return
|
||||
return url.toString()
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@ import type { DesktopMenuAction } from "@opencode-ai/app/desktop-menu"
|
|||
import type { FatalRendererError, ServerReadyData, TitlebarTheme } from "../preload/types"
|
||||
import { runDesktopMenuAction } from "./desktop-menu-actions"
|
||||
import { setForceFocus } from "./debug"
|
||||
import { safeExternalUrl } from "./external-link"
|
||||
import { assertAttachmentBudget, createPickedFileAuthorizations } from "./attachment-picker"
|
||||
import { getStore, removeStoreFileIfEmpty } from "./store"
|
||||
import { getPinchZoomEnabled, getWindowID, setPinchZoomEnabled, setTitlebar, updateTitlebar } from "./windows"
|
||||
|
|
@ -178,7 +179,9 @@ export function registerIpcHandlers(deps: Deps) {
|
|||
)
|
||||
|
||||
ipcMain.on("open-link", (_event: IpcMainEvent, url: string) => {
|
||||
void shell.openExternal(url)
|
||||
const externalUrl = safeExternalUrl(url)
|
||||
if (!externalUrl) return
|
||||
void shell.openExternal(externalUrl)
|
||||
})
|
||||
|
||||
ipcMain.handle("open-path", async (_event: IpcMainInvokeEvent, path: string, app?: string) => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue