Project

General

Profile

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

haketilo / background / page_actions_server.js @ b93f26bf

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
"use strict";
9

    
10
(() => {
11
    const get_storage = window.get_storage;
12
    const TYPE_PREFIX = window.TYPE_PREFIX;
13
    const CONNECTION_TYPE = window.CONNECTION_TYPE;
14
    const browser = window.browser;
15
    const listen_for_connection = window.listen_for_connection;
16
    const sha256 = window.sha256;
17
    const get_query_best = window.get_query_best;
18

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

    
23
    function send_scripts(url, port)
24
    {
25
	let [pattern, settings] = query_best(url);
26
	if (settings === undefined)
27
	    return;
28

    
29
	let components = settings.components;
30
	let processed_bags = new Set();
31

    
32
	if (components !== undefined)
33
	    send_scripts_rec([components], port, processed_bags);
34
    }
35

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

    
46
		var bag = storage.get(TYPE_PREFIX.BAG, name);
47

    
48
		if (bag === undefined) {
49
		    console.log(`no bag in storage for key ${name}`);
50
		    continue;
51
		}
52

    
53
		processed_bags.add(name);
54
		await send_scripts_rec(bag, port, processed_bags);
55
		processed_bags.delete(name);
56
	    } else {
57
		let script_text = await get_script_text(name);
58
		if (script_text === undefined)
59
		    continue;
60

    
61
		port.postMessage({inject : [script_text]});
62
	    }
63
	}
64
    }
65

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

    
83
    function ajax_callback()
84
    {
85
	if (this.readyState == 4)
86
	    this.resolve_callback(this);
87
    }
88

    
89
    function initiate_ajax_request(resolve, method, url)
90
    {
91
	var xhttp = new XMLHttpRequest();
92
	xhttp.resolve_callback = resolve;
93
	xhttp.onreadystatechange = ajax_callback;
94
	xhttp.open(method, url, true);
95
	xhttp.send();
96
    }
97

    
98
    function make_ajax_request(method, url)
99
    {
100
	return new Promise((resolve, reject) =>
101
			   initiate_ajax_request(resolve, method, url));
102
    }
103

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

    
124
    function handle_message(port, message, handler)
125
    {
126
	port.onMessage.removeListener(handler[0]);
127
	let url = message.url;
128
	console.log({url});
129
	send_scripts(url, port);
130
    }
131

    
132
    function new_connection(port)
133
    {
134
	console.log("new page actions connection!");
135
	let handler = [];
136
	handler.push(m => handle_message(port, m, handler));
137
	port.onMessage.addListener(handler[0]);
138
    }
139

    
140
    async function start()
141
    {
142
	storage = await get_storage();
143
	query_best = await get_query_best();
144

    
145
	listen_for_connection(CONNECTION_TYPE.PAGE_ACTIONS, new_connection);
146
    }
147

    
148
    window.start_page_actions_server = start;
149
})();
(3-3/7)