feat(lotus): work when served from its own origin (cinny #43)
Two things tied EC to the host's origin: - Widget message check: matrix-widget-api's strictOriginCheck compares ev.origin with THIS frame's origin, so on call.chat.lotusguild.org every message from chat.lotusguild.org would be dropped and calls would not start. restrictToHost() instead requires ev.source === window.parent and ev.origin === parentUrl's origin. Same-origin deployments keep working (the host origin is our own origin there), and it is stricter than before: the sender must also be our parent window. - Soundboard: the host's blob: clip URL is origin-bound. io.lotus.inject_audio now accepts the clip's bytes (`audio`, ArrayBuffer, <= 8 MiB) and prefers them over `url`; hosts that only send `url` are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
43a5e93c37
commit
a93bd9d7d8
@@ -10,7 +10,11 @@ import { afterEach, beforeEach, expect, test, vi } from "vitest";
|
||||
import { of } from "rxjs";
|
||||
|
||||
import { type CallViewModel } from "../state/CallViewModel/CallViewModel";
|
||||
import { startLotusAudioInject } from "./lotusAudioInject";
|
||||
import {
|
||||
MAX_INJECT_BYTES,
|
||||
parseInjectSource,
|
||||
startLotusAudioInject,
|
||||
} from "./lotusAudioInject";
|
||||
import { LotusWidgetActions } from "./lotusActions";
|
||||
|
||||
const lazyActions = new EventEmitter();
|
||||
@@ -223,3 +227,34 @@ test("#14: the shared context stays open while another instance is still active"
|
||||
stopB();
|
||||
expect(ctx.close).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
// [cinny #43] Cross-origin hosts send the clip bytes instead of a blob: URL.
|
||||
test("parseInjectSource prefers the clip bytes over the url", () => {
|
||||
const audio = new ArrayBuffer(16);
|
||||
expect(parseInjectSource({ audio, url: "https://x.example/a.ogg" })).toBe(
|
||||
audio,
|
||||
);
|
||||
});
|
||||
|
||||
test("parseInjectSource falls back to a safe url", () => {
|
||||
expect(parseInjectSource({ url: "https://x.example/a.ogg" })).toBe(
|
||||
"https://x.example/a.ogg",
|
||||
);
|
||||
expect(
|
||||
parseInjectSource({
|
||||
audio: new ArrayBuffer(0),
|
||||
url: "https://x.example/a.ogg",
|
||||
}),
|
||||
).toBe("https://x.example/a.ogg");
|
||||
expect(parseInjectSource({ url: "javascript" + ":alert(1)" })).toBeNull();
|
||||
expect(parseInjectSource({})).toBeNull();
|
||||
expect(parseInjectSource(undefined)).toBeNull();
|
||||
});
|
||||
|
||||
test("parseInjectSource rejects oversized or non-buffer audio", () => {
|
||||
expect(
|
||||
parseInjectSource({ audio: new ArrayBuffer(MAX_INJECT_BYTES + 1) }),
|
||||
).toBeNull();
|
||||
expect(parseInjectSource({ audio: "not bytes" })).toBeNull();
|
||||
expect(parseInjectSource({ audio: new Uint8Array(4) })).toBeNull();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user