import { ipcMain, shell } from "electron"; import { beforeEach, describe, expect, it, vi } from "vitest"; import { isAllowedExternalUrl, registerOpenerHandlers } from "./opener"; vi.mock("electron", () => ({ ipcMain: { handle: vi.fn() }, shell: { openExternal: vi.fn() }, })); function getRegisteredOpenUrlHandler(): (_event: unknown, url: unknown) => Promise { registerOpenerHandlers(); const handler = vi.mocked(ipcMain.handle).mock.calls.find(([channel]) => { return channel === "paseo:opener:openUrl"; })?.[1]; if (typeof handler !== "function") { throw new Error("open URL handler was not registered"); } return handler as (_event: unknown, url: unknown) => Promise; } describe("desktop opener", () => { beforeEach(() => { vi.mocked(ipcMain.handle).mockReset(); vi.mocked(shell.openExternal).mockReset(); }); it("allows only http and https external URLs", () => { expect(isAllowedExternalUrl("https://example.com/path")).toBe(true); expect(isAllowedExternalUrl("http://localhost:8081")).toBe(true); expect(isAllowedExternalUrl("file:///etc/passwd")).toBe(false); expect(isAllowedExternalUrl("javascript:alert(1)")).toBe(false); expect(isAllowedExternalUrl("paseo://settings")).toBe(false); expect(isAllowedExternalUrl("/relative/path")).toBe(false); expect(isAllowedExternalUrl(null)).toBe(false); }); it("opens allowed URLs through Electron shell", async () => { const handler = getRegisteredOpenUrlHandler(); await handler({}, "https://example.com"); expect(shell.openExternal).toHaveBeenCalledWith("https://example.com"); }); it("rejects blocked URLs before invoking Electron shell", async () => { const handler = getRegisteredOpenUrlHandler(); await expect(handler({}, "file:///etc/passwd")).rejects.toThrow("Unsupported external URL"); expect(shell.openExternal).not.toHaveBeenCalled(); }); });