import { safeRun } from "../util"; // @ts-ignore import sandboxHtml from "bundle-text:./iframe_sandbox.html"; import { Sandbox } from "../sandbox"; import { WorkerLike } from "./worker"; import { Plug } from "../plug"; class IFrameWrapper implements WorkerLike { private iframe: HTMLIFrameElement; onMessage?: (message: any) => Promise; ready: Promise; private messageListener: (evt: any) => void; constructor() { const iframe = document.createElement("iframe", {}); this.iframe = iframe; iframe.style.display = "none"; // Let's lock this down significantly iframe.setAttribute("sandbox", "allow-scripts"); iframe.srcdoc = sandboxHtml; this.messageListener = (evt: any) => { if (evt.source !== iframe.contentWindow) { return; } let data = evt.data; if (!data) return; safeRun(async () => { await this.onMessage!(data); }); }; window.addEventListener("message", this.messageListener); document.body.appendChild(iframe); this.ready = new Promise((resolve) => { iframe.onload = () => { resolve(); iframe.onload = null; }; }); } postMessage(message: any): void { this.iframe.contentWindow!.postMessage(message, "*"); } terminate() { console.log("Terminating iframe sandbox"); window.removeEventListener("message", this.messageListener); return this.iframe.remove(); } } export function createSandbox(plug: Plug) { return new Sandbox(plug, new IFrameWrapper()); }