fix(voice-call): pin plivo callback origins (#58238)

This commit is contained in:
Vincent Koc
2026-03-31 19:50:35 +09:00
committed by GitHub
parent cf3ae2612b
commit efe9183f9d
3 changed files with 34 additions and 0 deletions

View File

@@ -64,4 +64,30 @@ describe("PlivoProvider", () => {
"plivo:v3:verified",
);
});
it("pins stored callback bases to publicUrl instead of request Host", () => {
const provider = new PlivoProvider(
{
authId: "MA000000000000000000",
authToken: "test-token",
},
{
publicUrl: "https://voice.openclaw.ai/voice/webhook?provider=plivo",
},
);
provider.parseWebhookEvent({
headers: { host: "attacker.example" },
rawBody:
"CallUUID=call-uuid&CallStatus=in-progress&Direction=outbound&From=%2B15550000000&To=%2B15550000001&Event=StartApp",
url: "https://attacker.example/voice/webhook?provider=plivo&flow=answer&callId=internal-call-id",
method: "POST",
query: { provider: "plivo", flow: "answer", callId: "internal-call-id" },
});
const callbackMap = (provider as unknown as { callUuidToWebhookUrl: Map<string, string> })
.callUuidToWebhookUrl;
expect(callbackMap.get("call-uuid")).toBe("https://voice.openclaw.ai/voice/webhook");
});
});

View File

@@ -544,6 +544,13 @@ export class PlivoProvider implements VoiceCallProvider {
private baseWebhookUrlFromCtx(ctx: WebhookContext): string | null {
try {
if (this.options.publicUrl) {
const base = new URL(this.options.publicUrl);
const requestUrl = new URL(ctx.url);
base.pathname = requestUrl.pathname;
return `${base.origin}${base.pathname}`;
}
const u = new URL(
reconstructWebhookUrl(ctx, {
allowedHosts: this.options.webhookSecurity?.allowedHosts,