summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--background/patterns_query_manager.js6
-rw-r--r--background/webrequest.js7
-rw-r--r--common/broadcast.js2
-rw-r--r--common/browser.js22
-rw-r--r--content/content.js51
-rw-r--r--content/repo_query_cacher.js2
-rw-r--r--manifest.json2
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": [