diff options
-rw-r--r-- | background/patterns_query_manager.js | 6 | ||||
-rw-r--r-- | background/webrequest.js | 7 | ||||
-rw-r--r-- | common/broadcast.js | 2 | ||||
-rw-r--r-- | common/browser.js | 22 | ||||
-rw-r--r-- | content/content.js | 51 | ||||
-rw-r--r-- | content/repo_query_cacher.js | 2 | ||||
-rw-r--r-- | manifest.json | 2 |
7 files changed, 78 insertions, 14 deletions
diff --git a/background/patterns_query_manager.js b/background/patterns_query_manager.js index 3e2953f..d3c659a 100644 --- a/background/patterns_query_manager.js +++ b/background/patterns_query_manager.js @@ -4,7 +4,7 @@ * Function: Instantiate the Pattern Tree data structure, filled with mappings * from IndexedDB. * - * Copyright (C) 2021,2022 Wojtek Kosior + * Copyright (C) 2021, 2022 Wojtek Kosior * * 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 @@ -110,10 +110,8 @@ function register(kind, object) { pqt.register(tree, object.pattern, "~allow", object.allow + 0); } -#IF MOZILLA || MV3 const id = kind === "mappings" ? object.identifier : object.pattern; currently_registered.set(id, object); -#ENDIF } function changed(kind, change) { @@ -126,9 +124,7 @@ function changed(kind, change) { pqt.deregister(tree, change.key, "~allow"); } -#IF MOZILLA || MV3 currently_registered.delete(change.key); -#ENDIF } if (change.new_val !== undefined) diff --git a/background/webrequest.js b/background/webrequest.js index cb89a3d..bceba26 100644 --- a/background/webrequest.js +++ b/background/webrequest.js @@ -113,6 +113,9 @@ function on_before_request(details) if (details.type !== "xmlhttprequest") return {cancel: true}; + if (details.url.startsWith(redirect_url_template)) + return; + #IF DEBUG console.debug(`Settings queried using XHR for '${details.url}'.`); #ENDIF @@ -130,14 +133,14 @@ function on_before_request(details) return {cancel: true}; } - const policy = decide_policy(tree, details.url, default_allow, secret); + const policy = decide_policy(tree, queried_url, default_allow, secret); if (!policy.error) { const encoded_policy = encodeURIComponent(JSON.stringify(policy)); return {redirectUrl: redirect_url_template + encoded_policy}; } } - 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.`); + console.warn(`Bad request! Expected ${browser.runtime.getURL("dummy")}?url=<valid_urlencoded_url>. Got ${details.url}. This might be the result of page fingerprinting the browser.`); return {cancel: true}; } diff --git a/common/broadcast.js b/common/broadcast.js index 12b365a..3cc09b5 100644 --- a/common/broadcast.js +++ b/common/broadcast.js @@ -119,6 +119,6 @@ function close(conn) { if (conn.type === "sender") flush(conn); - setTimeout(conn.port.disconnect()); + setTimeout(() => conn.port.disconnect()); } #EXPORT close diff --git a/common/browser.js b/common/browser.js index 4830774..582d2a4 100644 --- a/common/browser.js +++ b/common/browser.js @@ -3,7 +3,7 @@ * * Function: Export the browser API object. * - * Copyright (C) 2021 Wojtek Kosior + * Copyright (C) 2021, 2022 Wojtek Kosior * * This program is free software: you can redistribute it and/or modify * it under the terms of the CC0 1.0 Universal License as published by @@ -21,6 +21,26 @@ #ELIF CHROMIUM +/* Use promises for sendMessage(). */ +function response_cb(resolve, reject, response) { + if (arguments.length < 3) + reject(chrome.runtime.lastError); + else + resolve(response); +} + +function replacement_sendMessage(old_sendMessage, ...args) { + let callbacks, prom = new Promise((...cbs) => callbacks = cbs); + old_sendMessage(...args, resp => response_cb(...callbacks, resp)); + return prom; +} + +for (const api_object of [chrome.tabs, chrome.runtime].filter(a => a)) { + const old_sendMessage = api_object.sendMessage; + api_object.sendMessage = + (...args) => replacement_sendMessage(old_sendMessage, ...args); +} + #EXPORT chrome AS browser #ENDIF diff --git a/content/content.js b/content/content.js index c501187..120b16d 100644 --- a/content/content.js +++ b/content/content.js @@ -45,9 +45,34 @@ #FROM common/browser.js IMPORT browser #FROM common/misc.js IMPORT is_privileged_url -#FROM common/policy.js IMPORT decide_policy +#FROM common/policy.js IMPORT decide_policy, fallback_policy #FROM content/policy_enforcing.js IMPORT enforce_blocking +#IF CHROMIUM && MV2 +function synchronously_get_policy(url) +{ + const encoded_url = encodeURIComponent(url); + const request_url = `${browser.runtime.getURL("dummy")}?url=${encoded_url}`; + + try { + var xhttp = new XMLHttpRequest(); + xhttp.open("GET", request_url, false); + xhttp.send(); + } catch(e) { + console.error("Failure to synchronously fetch policy for url.", e); + return fallback_policy(); + } + + try { + const policy = /^[^?]*\?settings=(.*)$/.exec(xhttp.responseURL)[1]; + return JSON.parse(decodeURIComponent(policy)); + } catch(e) { + console.error("Failure to process synchronously fetched policy for url.", e); + return fallback_policy() + } +} +#ENDIF + let already_run = false, resolve_page_info, page_info_prom = new Promise(cb => resolve_page_info = cb); @@ -60,7 +85,11 @@ function on_page_info_request([type], sender, respond_cb) { return true; } +#IF MOZILLA || MV3 globalThis.haketilo_content_script_main = async function() { +#ELSE +async function main() { +#ENDIF if (already_run) return; @@ -72,10 +101,20 @@ globalThis.haketilo_content_script_main = async function() { browser.runtime.onMessage.addListener(on_page_info_request); repo_query_cacher.start(); - const policy = decide_policy(globalThis.haketilo_pattern_tree, - document.URL, - globalThis.haketilo_default_allow, - globalThis.haketilo_secret); +#IF MOZILLA || MV3 + try { + var policy = decide_policy(globalThis.haketilo_pattern_tree, + document.URL, + globalThis.haketilo_default_allow, + globalThis.haketilo_secret); + } catch(e) { + console.error(e); + var policy = fallback_policy(); + } +#ELSE + const policy = synchronously_get_policy(document.URL); +#ENDIF + const page_info = Object.assign({url: document.URL}, policy); ["csp", "nonce"].forEach(prop => delete page_info[prop]); @@ -108,10 +147,12 @@ globalThis.haketilo_content_script_main = async function() { resolve_page_info(page_info); } +#IF MOZILLA || MV3 function main() { if (globalThis.haketilo_pattern_tree !== undefined) globalThis.haketilo_content_script_main(); } +#ENDIF #IF !UNIT_TEST main(); diff --git a/content/repo_query_cacher.js b/content/repo_query_cacher.js index 41487e1..3f62be7 100644 --- a/content/repo_query_cacher.js +++ b/content/repo_query_cacher.js @@ -42,6 +42,8 @@ * proprietary program, I am not going to enforce this in court. */ +#FROM common/browser.js IMPORT browser + /* * Map URLs to objects containing parsed responses, error info or promises * resolving to those. diff --git a/manifest.json b/manifest.json index 350c39a..56246ab 100644 --- a/manifest.json +++ b/manifest.json @@ -79,8 +79,10 @@ "open_in_tab": true, "browser_style": false }, +#IF CHROMIUM && MV2 #COPY_FILE dummy "web_accessible_resources": ["dummy"], +#ENDIF "background": { "persistent": true, "scripts": [ |