mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-11 23:00:03 +00:00
fix(studio): guard cross-origin iframe access to prevent SecurityError crashes
Wrap all contentWindow/contentDocument access and addEventListener/removeEventListener calls in try/catch across usePlaybackKeyboard, useAppHotkeys, and CompositionsTab. Prevents SecurityError from propagating to the React error boundary (white screen). Affects 1,885 crashes / 648 unique users in the last 7 days.
This commit is contained in:
@@ -62,33 +62,46 @@ function parsePositiveNumber(value: string | null): number | null {
|
||||
return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
|
||||
}
|
||||
|
||||
// fallow-ignore-next-line complexity
|
||||
function resolveIframeDuration(iframe: HTMLIFrameElement | null): number | null {
|
||||
const win = iframe?.contentWindow as PreviewWindow | null;
|
||||
const playerDuration = win?.__player?.getDuration?.();
|
||||
if (Number.isFinite(playerDuration) && playerDuration != null && playerDuration > 0) {
|
||||
return playerDuration;
|
||||
try {
|
||||
const win = iframe?.contentWindow as PreviewWindow | null;
|
||||
const playerDuration = win?.__player?.getDuration?.();
|
||||
if (Number.isFinite(playerDuration) && playerDuration != null && playerDuration > 0) {
|
||||
return playerDuration;
|
||||
}
|
||||
} catch {
|
||||
/* cross-origin iframe */
|
||||
}
|
||||
|
||||
const doc = iframe?.contentDocument;
|
||||
const root = doc?.querySelector("[data-composition-id]") ?? doc?.documentElement ?? null;
|
||||
return (
|
||||
parsePositiveNumber(root?.getAttribute("data-composition-duration") ?? null) ??
|
||||
parsePositiveNumber(root?.getAttribute("data-duration") ?? null)
|
||||
);
|
||||
try {
|
||||
const doc = iframe?.contentDocument;
|
||||
const root = doc?.querySelector("[data-composition-id]") ?? doc?.documentElement ?? null;
|
||||
return (
|
||||
parsePositiveNumber(root?.getAttribute("data-composition-duration") ?? null) ??
|
||||
parsePositiveNumber(root?.getAttribute("data-duration") ?? null)
|
||||
);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function syncIframePlayback(iframe: HTMLIFrameElement | null, shouldPlay: boolean): boolean {
|
||||
const player = (iframe?.contentWindow as PreviewWindow | null)?.__player;
|
||||
if (!player) return false;
|
||||
try {
|
||||
const player = (iframe?.contentWindow as PreviewWindow | null)?.__player;
|
||||
if (!player) return false;
|
||||
|
||||
if (shouldPlay) {
|
||||
player.play?.();
|
||||
if (shouldPlay) {
|
||||
player.play?.();
|
||||
return true;
|
||||
}
|
||||
|
||||
player.pause?.();
|
||||
player.seek?.(resolveThumbnailSeekTime(resolveIframeDuration(iframe)));
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
|
||||
player.pause?.();
|
||||
player.seek?.(resolveThumbnailSeekTime(resolveIframeDuration(iframe)));
|
||||
return true;
|
||||
}
|
||||
|
||||
function CompCard({
|
||||
|
||||
Reference in New Issue
Block a user