fix(calls): read the EC iframe document defensively when the widget failed to load
When the Element Call frame's navigation fails (offline, blocked) it becomes a cross-origin error page and `iframe.contentWindow.document` throws a SecurityError. Every DOM-driven call hook (CallControl selectors, deafen DOM fallback, useCallSpeakers/useRemoteAllMuted observers, CallEmbed theme injection) read it unguarded, so the moment the 25 s load watchdog fired the page logged a burst of uncaught SecurityErrors. Reproduced headless by aborting the EC index request. One `getCallDocument()` helper now treats "can't read" as "not loaded yet"; the watchdog overlay itself was already correct. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
This commit is contained in:
@@ -2,6 +2,7 @@ import { ClientWidgetApi } from 'matrix-widget-api';
|
||||
import { EventEmitter } from 'events';
|
||||
import { CallControlState } from './CallControlState';
|
||||
import { ElementMediaStateDetail, ElementMediaStatePayload, ElementWidgetActions } from './types';
|
||||
import { getCallDocument } from './utils';
|
||||
|
||||
export enum CallControlEvent {
|
||||
StateUpdate = 'state_update',
|
||||
@@ -62,7 +63,7 @@ export class CallControl extends EventEmitter implements CallControlState {
|
||||
private joined = false;
|
||||
|
||||
private get document(): Document | undefined {
|
||||
return this.iframe.contentDocument ?? this.iframe.contentWindow?.document;
|
||||
return getCallDocument(this.iframe);
|
||||
}
|
||||
|
||||
private get screenshareButton(): HTMLElement | undefined {
|
||||
@@ -265,7 +266,7 @@ export class CallControl extends EventEmitter implements CallControlState {
|
||||
}
|
||||
|
||||
private setSound(sound: boolean): void {
|
||||
const callDocument = this.iframe.contentDocument ?? this.iframe.contentWindow?.document;
|
||||
const callDocument = getCallDocument(this.iframe);
|
||||
if (callDocument) {
|
||||
callDocument.querySelectorAll('audio').forEach((el) => {
|
||||
const isScreenshareAudio = el.getAttribute('data-lk-source') === 'screen_share_audio';
|
||||
@@ -277,7 +278,7 @@ export class CallControl extends EventEmitter implements CallControlState {
|
||||
|
||||
private applyScreenshareAudioMuted(): void {
|
||||
if (!this.sound) return;
|
||||
const callDocument = this.iframe.contentDocument ?? this.iframe.contentWindow?.document;
|
||||
const callDocument = getCallDocument(this.iframe);
|
||||
if (callDocument) {
|
||||
callDocument
|
||||
.querySelectorAll<HTMLAudioElement>('audio[data-lk-source="screen_share_audio"]')
|
||||
|
||||
Reference in New Issue
Block a user