const addContentWindowProxy = (iframe) => { const contentWindowProxy = { get(target, key) { if (key === "self") return this; if (key === "frameElement") return iframe; if (key === "0") return undefined; return Reflect.get(target, key); }, }; if (!iframe.contentWindow) { const proxy = new Window_Proxy(window, contentWindowProxy); Object_defineProperty(iframe, "contentWindow", { get() { return proxy; }, set(newValue) { return newValue; }, enumerable: true, configurable: false, }); } }; // The native accessor, captured from the prototype so the shim below can hand // off to it. Without this the shim has nothing to delegate to. const nativeSrcdocDescriptor = Object_getOwnPropertyDescriptor(HTMLIFrameElement.prototype, "srcdoc"); const handleIframeCreation = (target, thisArg, args) => { const iframe = target.apply(thisArg, args); // A one-shot shim: install the contentWindow proxy on the first srcdoc // assignment, then step aside so the element behaves natively. // // It must step aside by DELETING itself. An earlier version redefined srcdoc // as a non-writable data property and then assigned through the same element, // so the write silently failed against its own frozen property and the native // setter was never reached: srcdoc stayed "", the attribute was never set, and // every dynamically created srcdoc iframe loaded empty. Object_defineProperty(iframe, "srcdoc", { configurable: true, get() { return nativeSrcdocDescriptor?.get ? nativeSrcdocDescriptor.get.call(this) : ""; }, set(newValue) { addContentWindowProxy(this); delete iframe.srcdoc; if (nativeSrcdocDescriptor?.set) { nativeSrcdocDescriptor.set.call(iframe, newValue); } else { iframe.setAttribute("srcdoc", newValue); } }, }); return iframe; }; const addIframeCreationSniffer = () => { const originalCreateElement = document.createElement; const handler = { apply(target, thisArg, args) { const isIframe = args && args.length && `${args[0]}`.toLowerCase() === "iframe"; if (!isIframe) { return target.apply(thisArg, args); } return handleIframeCreation(target, thisArg, args); }, get(target, key) { return Reflect.get(target, key); }, }; const proxied = new Window_Proxy(originalCreateElement, handler); Object_defineProperty(document, "createElement", { value: proxied, writable: true, configurable: true, }); Object_defineProperty(document.createElement, "toString", { value: Function_toString.bind(originalCreateElement), writable: false, configurable: true, enumerable: false, }); }; try { addIframeCreationSniffer(); } catch {}