diff --git a/src/main/external-url-policy.ts b/src/main/external-url-policy.ts index 18c3dc41..4f85ac7f 100644 --- a/src/main/external-url-policy.ts +++ b/src/main/external-url-policy.ts @@ -47,7 +47,7 @@ export function classifyExternalUrl(rawUrl: string): ExternalUrlDecision { } const parsed = new URL(normalized); const host = parsed.hostname.toLowerCase(); - if (TRUSTED_EXTERNAL_HOSTS.has(host)) { + if (parsed.protocol === "https:" && TRUSTED_EXTERNAL_HOSTS.has(host)) { return { kind: "trusted", url: normalized, host }; } return { kind: "confirm", url: normalized, host }; diff --git a/tests/unit/external-url-policy.test.ts b/tests/unit/external-url-policy.test.ts index 6e4db9d8..16ff38a9 100644 --- a/tests/unit/external-url-policy.test.ts +++ b/tests/unit/external-url-policy.test.ts @@ -17,6 +17,7 @@ describe("external URL policy", () => { it("separates trusted hosts from confirmation hosts", () => { expect(classifyExternalUrl("https://github.com/acme/repo")).toMatchObject({ kind: "trusted", host: "github.com" }); + expect(classifyExternalUrl("http://github.com/acme/repo")).toMatchObject({ kind: "confirm", host: "github.com" }); expect(classifyExternalUrl("https://example.com/report")).toMatchObject({ kind: "confirm", host: "example.com" }); }); }); diff --git a/tests/unit/ipc-open-work-product-url-policy.test.ts b/tests/unit/ipc-open-work-product-url-policy.test.ts index b5c0516a..50b6d0cd 100644 --- a/tests/unit/ipc-open-work-product-url-policy.test.ts +++ b/tests/unit/ipc-open-work-product-url-policy.test.ts @@ -87,7 +87,19 @@ describe("openWorkProduct external URL policy", () => { expect(electron.openExternal).toHaveBeenCalledWith("https://github.com/acme/repo"); }); - it("asks before opening untrusted http hosts", async () => { + it("asks before opening trusted hosts over http", async () => { + electron.openExternal.mockClear(); + electron.showMessageBox.mockClear(); + electron.showMessageBox.mockResolvedValueOnce({ response: 0 }); + + const result = await openUrl("http://github.com/acme/repo"); + + expect(result).toEqual({ ok: true, data: true }); + expect(electron.showMessageBox).toHaveBeenCalledTimes(1); + expect(electron.openExternal).toHaveBeenCalledWith("http://github.com/acme/repo"); + }); + + it("asks before opening untrusted hosts", async () => { electron.openExternal.mockClear(); electron.showMessageBox.mockClear(); electron.showMessageBox.mockResolvedValueOnce({ response: 0 });