UNPKG

sandstone-proxy

Version:

An experimental web proxy utilizing sandboxed iframes and no service worker.

113 lines (103 loc) 3.46 kB
import { ctx, convert_url, intercept_property, proxy_function } from "../context.mjs"; import * as network from "../network.mjs"; import * as loader from "../loader.mjs"; import * as util from "../../util.mjs"; import * as rpc from "../../rpc.mjs"; export function rewrite_iframe(iframe_element) { let iframe_src = iframe_element.src; let iframe_url = ""; let fetch_src = async (value) => { //download the proxied html iframe_element.setAttribute("__src", value); iframe_url = convert_url(value, ctx.location.href); console.log("navigating iframe to", iframe_url); let final_url = iframe_url; let error; //possible network error let html; try { let response = await network.fetch(iframe_url); html = await response.text(); final_url = response.url; } catch (e) { error = util.format_error(e); } //load the frame runtime let loader_blob = new Blob([loader.frame_html], {type: "text/html"}); iframe_element.src = network.create_blob_url(loader_blob); await new Promise((resolve) => { iframe_element.addEventListener("load", (event) => { event.stopImmediatePropagation(); resolve(); }); }) //create the rpc message channel let msg_channel = new MessageChannel(); rpc.attach_host(msg_channel.port1); rpc.set_host(iframe_element, msg_channel.port2); //create additional rpc target for sending the html let msg_channel_2 = new MessageChannel(); let rpc_target = new rpc.RPCTarget(msg_channel_2.port1); rpc_target.onmessage = rpc.message_listener; msg_channel.port1.start(); rpc.set_host(iframe_element, msg_channel_2.port2); let send_page = rpc.create_rpc_wrapper(rpc_target, "html"); //load persisted local storage if needed let iframe_origin = new URL(iframe_url).origin; let local_storage; if (iframe_origin === ctx.location.origin) local_storage = ctx.localStorage._get_entries(); let frame_id = Math.random() + ""; try { await send_page({ url: final_url, html: html, frame_id: frame_id, error: error, local_storage: local_storage, settings: {}, default_settings: loader.default_settings, version: loader.version, iframe: true }); } catch (error) { let error_msg = util.format_error(error); await send_page({ url: final_url, html: html, frame_id: frame_id, error: error_msg, local_storage: undefined, settings: {}, default_settings: loader.default_settings, version: loader.version }); } iframe_element.dispatchEvent(new Event("load")); } let src_descriptor = intercept_property(iframe_element, "src", { get() { return iframe_url || src_descriptor.get.call(iframe_element); }, set(value) { if (!util.url_is_http(value) || !value) src_descriptor.set.call(iframe_element, value); else { iframe_element.src = ""; fetch_src(value); } } }); proxy_function(iframe_element, "setAttribute", (target, this_arg, args) => { if (args[0] === "src") { iframe_element.src = args[1]; return; } return Reflect.apply(target, this_arg, args); }) if (!iframe_src || iframe_src.startsWith("data:") || iframe_src.startsWith("blob:")) { return; } iframe_element.src = iframe_src; }