diff options
Diffstat (limited to 'background/main.js')
-rw-r--r-- | background/main.js | 238 |
1 files changed, 0 insertions, 238 deletions
diff --git a/background/main.js b/background/main.js deleted file mode 100644 index 61c96ac..0000000 --- a/background/main.js +++ /dev/null @@ -1,238 +0,0 @@ -/** - * This file is part of Haketilo. - * - * Function: Main background script. - * - * Copyright (C) 2021 Wojtek Kosior <koszko@koszko.org> - * Copyright (C) 2021 Jahoti <jahoti@envs.net> - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * As additional permission under GNU GPL version 3 section 7, you - * may distribute forms of that code without the copy of the GNU - * GPL normally required by section 4, provided you include this - * license notice and, in case of non-source distribution, a URL - * through which recipients can access the Corresponding Source. - * If you modify file(s) with this exception, you may extend this - * exception to your version of the file(s), but you are not - * obligated to do so. If you do not wish to do so, delete this - * exception statement from your version. - * - * As a special exception to the GPL, any HTML file which merely - * makes function calls to this code, and for that purpose - * includes it by reference shall be deemed a separate work for - * copyright law purposes. If you modify this code, you may extend - * this exception to your version of the code, but you are not - * obligated to do so. If you do not wish to do so, delete this - * exception statement from your version. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * I, Wojtek Kosior, thereby promise not to sue for violation of this file's - * license. Although I request that you do not make use of this code in a - * proprietary program, I am not going to enforce this in court. - */ - -#IMPORT common/storage_light.js AS light_storage - -#IMPORT background/storage_server.js -#IMPORT background/page_actions_server.js -#IMPORT background/stream_filter.js - -#FROM common/browser.js IMPORT browser -#FROM common/stored_types.js IMPORT TYPE_PREFIX -#FROM background/storage.js IMPORT get_storage -#FROM common/misc.js IMPORT is_privileged_url -#FROM common/settings_query.js IMPORT query_best -#FROM background/policy_injector.js IMPORT inject_csp_headers - -const initial_data = ( -#INCLUDE_VERBATIM default_settings.json -); - -storage_server.start(); -page_actions_server.start(); - -async function init_ext(install_details) -{ - if (install_details.reason != "install") - return; - - let storage = await get_storage(); - - await storage.clear(); - - /* Below we add sample settings to the extension. */ - for (let setting of initial_data) { - let [key, value] = Object.entries(setting)[0]; - storage.set(key[0], key.substring(1), value); - } -} - -browser.runtime.onInstalled.addListener(init_ext); - -/* - * The function below implements a more practical interface for what it does by - * wrapping the old query_best() function. - */ -function decide_policy_for_url(storage, policy_observable, url) -{ - if (storage === undefined) - return {allow: false}; - - const settings = - {allow: policy_observable !== undefined && policy_observable.value}; - - const [pattern, queried_settings] = query_best(storage, url); - - if (queried_settings) { - settings.payload = queried_settings.components; - settings.allow = !!queried_settings.allow && !settings.payload; - settings.pattern = pattern; - } - - return settings; -} - -let storage; -let policy_observable = {}; - -function sanitize_web_page(details) -{ - const url = details.url; - if (is_privileged_url(details.url)) - return; - - const policy = - decide_policy_for_url(storage, policy_observable, details.url); - - let headers = details.responseHeaders; - - headers = inject_csp_headers(headers, policy); - - let skip = false; - for (const header of headers) { - if ((header.name.toLowerCase().trim() === "content-disposition" && - /^\s*attachment\s*(;.*)$/i.test(header.value))) - skip = true; - } - skip = skip || (details.statusCode >= 300 && details.statusCode < 400); - - if (!skip) { - /* Check for API availability. */ - if (browser.webRequest.filterResponseData) - headers = stream_filter.apply(details, headers, policy); - } - - return {responseHeaders: headers}; -} - -const request_url_regex = /^[^?]*\?url=(.*)$/; -const redirect_url_template = browser.runtime.getURL("dummy") + "?settings="; - -function synchronously_smuggle_policy(details) -{ - /* - * Content script will make a synchronous XmlHttpRequest to extension's - * `dummy` file to query settings for given URL. We smuggle that - * information in query parameter of the URL we redirect to. - * A risk of fingerprinting arises if a page with script execution allowed - * guesses the dummy file URL and makes an AJAX call to it. It is currently - * a problem in ManifestV2 Chromium-family port of Haketilo because Chromium - * uses predictable URLs for web-accessible resources. We plan to fix it in - * the future ManifestV3 port. - */ - if (details.type !== "xmlhttprequest") - return {cancel: true}; - - console.debug(`Settings queried using XHR for '${details.url}'.`); - - let policy = {allow: false}; - - try { - /* - * request_url should be of the following format: - * <url_for_extension's_dummy_file>?url=<valid_urlencoded_url> - */ - const match = request_url_regex.exec(details.url); - const queried_url = decodeURIComponent(match[1]); - - if (details.initiator && !queried_url.startsWith(details.initiator)) { - console.warn(`Blocked suspicious query of '${url}' by '${details.initiator}'. This might be the result of page fingerprinting the browser.`); - return {cancel: true}; - } - - policy = decide_policy_for_url(storage, policy_observable, queried_url); - } catch (e) { - console.warn(`Bad request! Expected ${browser.runtime.getURL("dummy")}?url=<valid_urlencoded_url>. Got ${request_url}. This might be the result of page fingerprinting the browser.`); - } - - const encoded_policy = encodeURIComponent(JSON.stringify(policy)); - - return {redirectUrl: redirect_url_template + encoded_policy}; -} - -const all_types = [ - "main_frame", "sub_frame", "stylesheet", "script", "image", "font", - "object", "xmlhttprequest", "ping", "csp_report", "media", "websocket", - "other", "main_frame", "sub_frame" -]; - -async function start_webRequest_operations() -{ - storage = await get_storage(); - -#IF CHROMIUM - const extra_opts = ["blocking", "extraHeaders"]; -#ELSE - const extra_opts = ["blocking"]; -#ENDIF - - browser.webRequest.onHeadersReceived.addListener( - sanitize_web_page, - {urls: ["<all_urls>"], types: ["main_frame", "sub_frame"]}, - extra_opts.concat("responseHeaders") - ); - - const dummy_url_pattern = browser.runtime.getURL("dummy") + "?url=*"; - browser.webRequest.onBeforeRequest.addListener( - synchronously_smuggle_policy, - {urls: [dummy_url_pattern], types: ["xmlhttprequest"]}, - extra_opts - ); - - policy_observable = await light_storage.observe_var("default_allow"); -} - -start_webRequest_operations(); - -#IF MOZILLA -const code = `\ -console.warn("Hi, I'm Mr Dynamic!"); - -console.debug("let's see how window.haketilo_exports looks like now"); - -console.log("haketilo_exports", window.haketilo_exports); -` - -async function test_dynamic_content_scripts() -{ - browser.contentScripts.register({ - "js": [{code}], - "matches": ["<all_urls>"], - "allFrames": true, - "runAt": "document_start" -}); -} - -test_dynamic_content_scripts(); -#ENDIF |