1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
/**
* 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;
|