mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 05:20:43 +00:00
fix(realtime): strip originator header from browser WebRTC SDP offer (#76435)
Remove server-side-only OpenAI attribution headers from browser WebRTC SDP offer headers while preserving Gateway-side attribution. Closes #76435. Thanks @hclsys.
This commit is contained in:
@@ -19,6 +19,7 @@ Docs: https://docs.openclaw.ai
|
||||
|
||||
### Fixes
|
||||
|
||||
- Control UI/Talk: fix Talk (OpenAI Realtime WebRTC) CORS failure by stripping server-side-only attribution headers (`originator`, `version`, `User-Agent`) from browser offer headers; `api.openai.com/v1/realtime/calls` only allows `authorization` and `content-type` in its CORS preflight, so forwarding these headers caused the browser SDP exchange to fail. Fixes #76435. Thanks @hclsys.
|
||||
- Plugins/onboarding: trust optional official plugin and web-search installs selected from the official catalog so npm security scanning treats them like other source-linked official install paths. Thanks @vincentkoc.
|
||||
- Microsoft Teams: persist sent-message markers across Gateway restarts so follow-up replies to recent bot messages keep resolving the original conversation instead of dropping out after restart, with marker TTLs preserved on best-effort recovery. (#75585) Thanks @amknight.
|
||||
- Matrix: persist pending approval reaction targets across Gateway restarts so room approvers can still approve or deny outstanding prompts after OpenClaw comes back online. (#75586) Thanks @amknight.
|
||||
|
||||
@@ -192,14 +192,12 @@ describe("buildOpenAIRealtimeVoiceProvider", () => {
|
||||
transport: "webrtc-sdp",
|
||||
clientSecret: "client-secret-123",
|
||||
offerUrl: "https://api.openai.com/v1/realtime/calls",
|
||||
offerHeaders: {
|
||||
originator: "openclaw",
|
||||
version: "2026.3.22",
|
||||
},
|
||||
});
|
||||
expect((session as { offerHeaders?: Record<string, string> }).offerHeaders).not.toHaveProperty(
|
||||
"User-Agent",
|
||||
);
|
||||
// originator, version, and User-Agent are server-side attribution headers; they
|
||||
// must not be forwarded to the browser so that the browser's direct SDP POST to
|
||||
// api.openai.com passes the CORS preflight (only authorization,content-type
|
||||
// allowed — #76435). All three are filtered, leaving no browser offer headers.
|
||||
expect((session as { offerHeaders?: Record<string, string> }).offerHeaders).toBeUndefined();
|
||||
});
|
||||
|
||||
it("resolves keychain OPENAI_API_KEY refs before creating browser sessions", async () => {
|
||||
|
||||
@@ -731,8 +731,12 @@ function resolveOpenAIRealtimeBrowserOfferHeaders(): Record<string, string> | un
|
||||
transport: "http",
|
||||
defaultHeaders: {},
|
||||
});
|
||||
// Strip server-side-only attribution headers: browser direct fetches to
|
||||
// api.openai.com fail CORS preflight when these are present (only
|
||||
// authorization,content-type are allowed by the endpoint's CORS policy).
|
||||
const SERVER_ONLY_HEADERS = new Set(["user-agent", "originator", "version"]);
|
||||
const browserHeaders = Object.fromEntries(
|
||||
Object.entries(headers ?? {}).filter(([key]) => key.toLowerCase() !== "user-agent"),
|
||||
Object.entries(headers ?? {}).filter(([key]) => !SERVER_ONLY_HEADERS.has(key.toLowerCase())),
|
||||
);
|
||||
return Object.keys(browserHeaders).length > 0 ? browserHeaders : undefined;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user