fix: reject unvalidated voice media streams · openclaw/openclaw@1d9b9ef
steipete-oai
·
2026-06-14
·
via Recent Commits to openclaw:main
File tree
extensions/voice-call/src
| Original file line number | Diff line number | Diff line change |
|---|
@@ -199,6 +199,39 @@ describe("MediaStreamHandler security hardening", () => {
|
199 | 199 | expect((error as Error).cause).toBeInstanceOf(SyntaxError); |
200 | 200 | }); |
201 | 201 | |
| 202 | +it("rejects start frames when no stream acceptance validator is configured", async () => { |
| 203 | +const createSession = vi.fn(() => createStubSession()); |
| 204 | +const handler = new MediaStreamHandler({ |
| 205 | +transcriptionProvider: { |
| 206 | + createSession, |
| 207 | +id: "openai", |
| 208 | +label: "OpenAI", |
| 209 | +isConfigured: () => true, |
| 210 | +}, |
| 211 | +providerConfig: {}, |
| 212 | +}); |
| 213 | +const server = await startWsServer(handler); |
| 214 | + |
| 215 | +try { |
| 216 | +const ws = await connectWs(server.url); |
| 217 | +ws.send( |
| 218 | +JSON.stringify({ |
| 219 | +event: "start", |
| 220 | +streamSid: "MZ-unvalidated", |
| 221 | +start: { callSid: "CA-unvalidated" }, |
| 222 | +}), |
| 223 | +); |
| 224 | + |
| 225 | +const closed = await waitForClose(ws); |
| 226 | + |
| 227 | +expect(closed.code).toBe(1008); |
| 228 | +expect(closed.reason).toBe("Unauthorized stream"); |
| 229 | +expect(createSession).not.toHaveBeenCalled(); |
| 230 | +} finally { |
| 231 | +await server.close(); |
| 232 | +} |
| 233 | +}); |
| 234 | + |
202 | 235 | it("emits common Talk events for telephony STT/TTS sessions", async () => { |
203 | 236 | let callbacks: RealtimeTranscriptionSessionCreateRequest | undefined; |
204 | 237 | const sentAudio: Buffer[] = []; |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -45,7 +45,7 @@ export interface MediaStreamConfig {
|
45 | 45 | maxConnections?: number; |
46 | 46 | /** Optional trusted resolver for the source IP used by pending-connection guards. */ |
47 | 47 | resolveClientIp?: (request: IncomingMessage) => string | undefined; |
48 | | -/** Validate whether to accept a media stream for the given call ID */ |
| 48 | +/** Validate whether to accept a media stream for the given call ID. Missing validator rejects. */ |
49 | 49 | shouldAcceptStream?: (params: { callId: string; streamSid: string; token?: string }) => boolean; |
50 | 50 | /** Callback when transcript is received */ |
51 | 51 | onTranscript?: (callId: string, transcript: string) => void; |
@@ -321,10 +321,13 @@ export class MediaStreamHandler {
|
321 | 321 | ws.close(1008, "Missing callSid"); |
322 | 322 | return null; |
323 | 323 | } |
324 | | -if ( |
325 | | -this.config.shouldAcceptStream && |
326 | | -!this.config.shouldAcceptStream({ callId: callSid, streamSid, token: effectiveToken }) |
327 | | -) { |
| 324 | +if (!this.config.shouldAcceptStream) { |
| 325 | +console.warn("[MediaStream] Rejecting stream without an acceptance validator"); |
| 326 | +ws.close(1008, "Unauthorized stream"); |
| 327 | +return null; |
| 328 | +} |
| 329 | + |
| 330 | +if (!this.config.shouldAcceptStream({ callId: callSid, streamSid, token: effectiveToken })) { |
328 | 331 | console.warn(`[MediaStream] Rejecting stream for unknown call: ${callSid}`); |
329 | 332 | ws.close(1008, "Unknown call"); |
330 | 333 | return null; |
|
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。