/** * Myext script injector * * Copyright (C) 2021 Wojtek Kosior * * Dual-licensed under: * - 0BSD license * - GPLv3 or (at your option) any later version */ import {TYPE_PREFIX} from '/common/stored_types.mjs'; import sha256 from './sha256.mjs'; import {url_item} from './ResponseProcessor.mjs'; import get_storage from './storage.mjs'; "use strict"; var storage; function ajax_callback() { if (this.readyState == 4) this.resolve_callback(this); } function initiate_ajax_request(resolve, method, url) { var xhttp = new XMLHttpRequest(); xhttp.resolve_callback = resolve; xhttp.onreadystatechange = ajax_callback; xhttp.open(method, url, true); xhttp.send(); } function make_ajax_request(method, url) { return new Promise((resolve, reject) => initiate_ajax_request(resolve, method, url)); } async function fetch_remote_script(script_data) { try { let xhttp = await make_ajax_request("GET", script_data.url); if (xhttp.status === 200) { let computed_hash = sha256(xhttp.responseText); if (computed_hash !== script_data.hash) { console.log(`Bad hash for ${script_data.url}\n got ${computed_hash} instead of ${script_data.hash}`); return; } return xhttp.responseText; } else { console.log("script not fetched: " + script_data.url); return; } } catch (e) { console.log(e); } } async function get_script_text(script_name) { try { let script_data = storage.get(TYPE_PREFIX.SCRIPT, script_name); if (script_data === undefined) { console.log(`missing data for ${script_name}`); return; } let script_text = script_data.text; if (!script_text) script_text = await fetch_remote_script(script_data); return script_text; } catch (e) { console.log(e); } } // TODO: parallelize script fetching // TODO: guard against infinite recursion async function inject_scripts_rec(components, doc) { for (let [prefix, name] of components) { if (prefix === TYPE_PREFIX.BUNDLE) { var bundle = storage.get(TYPE_PREFIX.BUNDLE, name); if (bundle === undefined) { console.log(`no bundle in storage for key ${elem_key}`); continue; } await inject_scripts_rec(bundle, doc); } else { let script_text = await get_script_text(name,); if (script_text === undefined) continue; let script = doc.createElement("script"); script.textContent = script_text; doc.body.appendChild(script); } } } async function inject_scripts(url, doc) { storage = await get_storage(); url = url_item(url); let components = storage.get(TYPE_PREFIX.PAGE, url); if (components === undefined) { console.log(`got nothing for ${url}`); return } else { console.log(`got ${components.length} component(s) for ${url}`); } await inject_scripts_rec(components, doc); } export default inject_scripts;