Project

General

Profile

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

haketilo / background / main.js @ 2bd35bc4

1
/**
2
 * This file is part of Haketilo.
3
 *
4
 * Function: Main background script.
5
 *
6
 * Copyright (C) 2021 Wojtek Kosior
7
 * Redistribution terms are gathered in the `copyright' file.
8
 */
9

    
10
/*
11
 * IMPORTS_START
12
 * IMPORT TYPE_PREFIX
13
 * IMPORT get_storage
14
 * IMPORT light_storage
15
 * IMPORT start_storage_server
16
 * IMPORT start_page_actions_server
17
 * IMPORT browser
18
 * IMPORT is_privileged_url
19
 * IMPORT query_best
20
 * IMPORT gen_nonce
21
 * IMPORT inject_csp_headers
22
 * IMPORT apply_stream_filter
23
 * IMPORT filter_cookie_headers
24
 * IMPORT is_chrome
25
 * IMPORTS_END
26
 */
27

    
28
start_storage_server();
29
start_page_actions_server();
30

    
31
async function init_ext(install_details)
32
{
33
    if (install_details.reason != "install")
34
	return;
35

    
36
    let storage = await get_storage();
37

    
38
    await storage.clear();
39

    
40
    /*
41
     * Below we add sample settings to the extension.
42
     */
43

    
44
    for (let setting of // The next line is replaced with the contents of /default_settings.json by the build script
45
        `DEFAULT SETTINGS`
46
    ) {
47
	let [key, value] = Object.entries(setting)[0];
48
	storage.set(key[0], key.substring(1), value);
49
    }
50
}
51

    
52
browser.runtime.onInstalled.addListener(init_ext);
53

    
54

    
55
let storage;
56
let policy_observable = {};
57

    
58
function on_headers_received(details)
59
{
60
    const url = details.url;
61
    if (is_privileged_url(details.url))
62
	return;
63

    
64
    const [pattern, settings] = query_best(storage, details.url);
65
    const has_payload = !!(settings && settings.components);
66
    const allow = !has_payload &&
67
	  !!(settings ? settings.allow : policy_observable.value);
68
    const nonce = gen_nonce();
69
    const policy = {allow, url, nonce, has_payload};
70

    
71
    let headers = details.responseHeaders;
72
    let skip = false;
73
    for (const header of headers) {
74
	if ((header.name.toLowerCase().trim() === "content-disposition" &&
75
	     /^\s*attachment\s*(;.*)$/i.test(header.value)))
76
	    skip = true;
77
    }
78

    
79
    headers = inject_csp_headers(headers, policy);
80

    
81
    skip = skip || (details.statusCode >= 300 && details.statusCode < 400);
82
    if (!skip) {
83
	/* Check for API availability. */
84
	if (browser.webRequest.filterResponseData)
85
	    headers = apply_stream_filter(details, headers, policy);
86
    }
87

    
88
    return {responseHeaders: headers};
89
}
90

    
91
function on_before_send_headers(details)
92
{
93
    let headers = details.requestHeaders;
94
    headers = filter_cookie_headers(headers);
95
    return {requestHeaders: headers};
96
}
97

    
98
const all_types = [
99
    "main_frame", "sub_frame", "stylesheet", "script", "image", "font",
100
    "object", "xmlhttprequest", "ping", "csp_report", "media", "websocket",
101
    "other", "main_frame", "sub_frame"
102
];
103

    
104
async function start_webRequest_operations()
105
{
106
    storage = await get_storage();
107

    
108
    const extra_opts = ["blocking"];
109
    if (is_chrome)
110
	extra_opts.push("extraHeaders");
111

    
112
    browser.webRequest.onHeadersReceived.addListener(
113
	on_headers_received,
114
	{urls: ["<all_urls>"], types: ["main_frame", "sub_frame"]},
115
	extra_opts.concat("responseHeaders")
116
    );
117

    
118
    browser.webRequest.onBeforeSendHeaders.addListener(
119
	on_before_send_headers,
120
	{urls: ["<all_urls>"], types: all_types},
121
	extra_opts.concat("requestHeaders")
122
    );
123

    
124
    policy_observable = await light_storage.observe_var("default_allow");
125
}
126

    
127
start_webRequest_operations();
(2-2/7)