Project

General

Profile

Download (3.49 KB) Statistics
| Branch: | Tag: | Revision:

haketilo / background / page_actions_server.js @ b7e2870f

1
/**
2
 * Myext serving of page actions to content scripts
3
 *
4
 * Copyright (C) 2021 Wojtek Kosior
5
 * Redistribution terms are gathered in the `copyright' file.
6
 */
7

    
8
/*
9
 * IMPORTS_START
10
 * IMPORT get_storage
11
 * IMPORT TYPE_PREFIX
12
 * IMPORT CONNECTION_TYPE
13
 * IMPORT browser
14
 * IMPORT listen_for_connection
15
 * IMPORT sha256
16
 * IMPORT get_query_best
17
 * IMPORTS_END
18
 */
19

    
20
var storage;
21
var query_best;
22
var handler;
23

    
24
function send_actions(url, port)
25
{
26
    let [pattern, settings] = query_best(url);
27

    
28
    port.postMessage(["settings", [pattern, settings]]);
29

    
30
    if (settings === undefined)
31
	return;
32

    
33
    let components = settings.components;
34
    let processed_bags = new Set();
35

    
36
    if (components !== undefined)
37
	send_scripts([components], port, processed_bags);
38
}
39

    
40
// TODO: parallelize script fetching
41
async function send_scripts(components, port, processed_bags)
42
{
43
    for (let [prefix, name] of components) {
44
	if (prefix === TYPE_PREFIX.BAG) {
45
	    if (processed_bags.has(name)) {
46
		console.log(`preventing recursive inclusion of bag ${name}`);
47
		continue;
48
	    }
49

    
50
	    var bag = storage.get(TYPE_PREFIX.BAG, name);
51

    
52
	    if (bag === undefined) {
53
		console.log(`no bag in storage for key ${name}`);
54
		continue;
55
	    }
56

    
57
	    processed_bags.add(name);
58
	    await send_scripts(bag, port, processed_bags);
59

    
60
	    processed_bags.delete(name);
61
	} else {
62
	    let script_text = await get_script_text(name);
63
	    if (script_text === undefined)
64
		continue;
65

    
66
	    port.postMessage(["inject", [script_text]]);
67
	}
68
    }
69
}
70

    
71
async function get_script_text(script_name)
72
{
73
    try {
74
	let script_data = storage.get(TYPE_PREFIX.SCRIPT, script_name);
75
	if (script_data === undefined) {
76
	    console.log(`missing data for ${script_name}`);
77
	    return;
78
	}
79
	let script_text = script_data.text;
80
	if (!script_text)
81
	    script_text = await fetch_remote_script(script_data);
82
	return script_text;
83
    } catch (e) {
84
	console.log(e);
85
    }
86
}
87

    
88
function ajax_callback()
89
{
90
    if (this.readyState == 4)
91
	this.resolve_callback(this);
92
}
93

    
94
function initiate_ajax_request(resolve, method, url)
95
{
96
    var xhttp = new XMLHttpRequest();
97
    xhttp.resolve_callback = resolve;
98
    xhttp.onreadystatechange = ajax_callback;
99
    xhttp.open(method, url, true);
100
    xhttp.send();
101
}
102

    
103
function make_ajax_request(method, url)
104
{
105
    return new Promise((resolve, reject) =>
106
		       initiate_ajax_request(resolve, method, url));
107
}
108

    
109
async function fetch_remote_script(script_data)
110
{
111
    try {
112
	let xhttp = await make_ajax_request("GET", script_data.url);
113
	if (xhttp.status === 200) {
114
	    let computed_hash = sha256(xhttp.responseText);
115
	    if (computed_hash !== script_data.hash) {
116
		console.log(`Bad hash for ${script_data.url}\n    got ${computed_hash} instead of ${script_data.hash}`);
117
		return;
118
	    }
119
	    return xhttp.responseText;
120
	} else {
121
	    console.log("script not fetched: " + script_data.url);
122
	    return;
123
	}
124
    } catch (e) {
125
	console.log(e);
126
    }
127
}
128

    
129
function handle_message(port, message, handler)
130
{
131
    port.onMessage.removeListener(handler[0]);
132
    let url = message.url;
133
    console.log({url});
134
    send_actions(url, port);
135
}
136

    
137
function new_connection(port)
138
{
139
    console.log("new page actions connection!");
140
    let handler = [];
141
    handler.push(m => handle_message(port, m, handler));
142
    port.onMessage.addListener(handler[0]);
143
}
144

    
145
async function start_page_actions_server()
146
{
147
    storage = await get_storage();
148
    query_best = await get_query_best();
149

    
150
    listen_for_connection(CONNECTION_TYPE.PAGE_ACTIONS, new_connection);
151
}
152

    
153
/*
154
 * EXPORTS_START
155
 * EXPORT start_page_actions_server
156
 * EXPORTS_END
157
 */
(3-3/8)