fix(browser): land PR #23962 extension relay CORS fix

Reworks browser relay CORS handling for extension-origin preflight and JSON responses, adds regression tests, and updates changelog.
Landed from contributor @miloudbelarebia (PR #23962).

Co-authored-by: Miloud Belarebia <miloudbelarebia@users.noreply.github.com>
This commit is contained in:
Peter Steinberger
2026-02-26 14:14:30 +00:00
parent 081b1aa1ed
commit 4c75eca580
3 changed files with 88 additions and 0 deletions

View File

@@ -208,6 +208,61 @@ describe("chrome extension relay server", () => {
expect(err.message).toContain("401");
});
it("allows CORS preflight from chrome-extension origins", async () => {
const port = await getFreePort();
cdpUrl = `http://127.0.0.1:${port}`;
await ensureChromeExtensionRelayServer({ cdpUrl });
const origin = "chrome-extension://abcdefghijklmnop";
const res = await fetch(`${cdpUrl}/json/version`, {
method: "OPTIONS",
headers: {
Origin: origin,
"Access-Control-Request-Method": "GET",
"Access-Control-Request-Headers": "x-openclaw-relay-token",
},
});
expect(res.status).toBe(204);
expect(res.headers.get("access-control-allow-origin")).toBe(origin);
expect(res.headers.get("access-control-allow-headers") ?? "").toContain(
"x-openclaw-relay-token",
);
});
it("rejects CORS preflight from non-extension origins", async () => {
const port = await getFreePort();
cdpUrl = `http://127.0.0.1:${port}`;
await ensureChromeExtensionRelayServer({ cdpUrl });
const res = await fetch(`${cdpUrl}/json/version`, {
method: "OPTIONS",
headers: {
Origin: "https://example.com",
"Access-Control-Request-Method": "GET",
},
});
expect(res.status).toBe(403);
});
it("returns CORS headers on JSON responses for extension origins", async () => {
const port = await getFreePort();
cdpUrl = `http://127.0.0.1:${port}`;
await ensureChromeExtensionRelayServer({ cdpUrl });
const origin = "chrome-extension://abcdefghijklmnop";
const res = await fetch(`${cdpUrl}/json/version`, {
headers: {
Origin: origin,
...relayAuthHeaders(cdpUrl),
},
});
expect(res.status).toBe(200);
expect(res.headers.get("access-control-allow-origin")).toBe(origin);
});
it("rejects extension websocket access without relay auth token", async () => {
const port = await getFreePort();
cdpUrl = `http://127.0.0.1:${port}`;