From 538376341e9a50ebd350897fe26f43c433f0ee06 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Fri, 27 Aug 2021 10:01:32 +0200 Subject: enable whitelisting of `file://' protocol\n\nThis commit additionally also changes the semantics of triple asterisk wildcard in URL path. --- content/freezer.js | 1 + content/main.js | 86 +++++++++++++++++++++++++++++++++++++++++++------ content/page_actions.js | 22 +++++++++---- 3 files changed, 93 insertions(+), 16 deletions(-) (limited to 'content') diff --git a/content/freezer.js b/content/freezer.js index 9dbc95e..0ea362e 100644 --- a/content/freezer.js +++ b/content/freezer.js @@ -49,6 +49,7 @@ function mozilla_suppress_scripts(e) { console.log('Script suppressor has detached.'); return; } + console.log("script event", e); if (e.isTrusted && !e.target._hachette_payload) { e.preventDefault(); console.log('Suppressed script', e.target); diff --git a/content/main.js b/content/main.js index 984b3cb..06d3bf1 100644 --- a/content/main.js +++ b/content/main.js @@ -10,6 +10,7 @@ * IMPORTS_START * IMPORT handle_page_actions * IMPORT extract_signed + * IMPORT sign_data * IMPORT gen_nonce * IMPORT is_privileged_url * IMPORT mozilla_suppress_scripts @@ -31,13 +32,13 @@ function accept_node(node, parent) parent.hachette_corresponding.appendChild(clone); } -if (!is_privileged_url(document.URL)) { - /* Signature valid for half an hour. */ - const min_time = new Date().getTime() - 1800 * 1000; +function extract_cookie_policy(cookie, min_time) +{ let best_result = {time: -1}; let policy = null; const extracted_signatures = []; - for (const match of document.cookie.matchAll(/hachette-(\w*)=([^;]*)/g)) { + + for (const match of cookie.matchAll(/hachette-(\w*)=([^;]*)/g)) { const new_result = extract_signed(...match.slice(1, 3)); if (new_result.fail) continue; @@ -56,17 +57,84 @@ if (!is_privileged_url(document.URL)) { policy = new_policy; } + return [policy, extracted_signatures]; +} + +function extract_url_policy(url, min_time) +{ + const [base_url, payload, anchor] = + /^([^#]*)#?([^#]*)(#?.*)$/.exec(url).splice(1, 4); + + const match = /^hachette_([^_]+)_(.*)$/.exec(payload); + if (!match) + return [null, url]; + + const result = extract_signed(...match.slice(1, 3)); + if (result.fail) + return [null, url]; + + const original_url = base_url + anchor; + const policy = result.time < min_time ? null : + JSON.parse(decodeURIComponent(result.data)); + + return [policy.url === original_url ? policy : null, original_url]; +} + +function employ_nonhttp_policy(policy) +{ + if (!policy.allow) + return; + + policy.nonce = gen_nonce(); + const [base_url, target] = /^([^#]*)(#?.*)$/.exec(policy.url).slice(1, 3); + const encoded_policy = encodeURIComponent(JSON.stringify(policy)); + const payload = "hachette_" + + sign_data(encoded_policy, new Date().getTime()).join("_"); + const resulting_url = `${base_url}#${payload}${target}`; + location.href = resulting_url; + location.reload(); +} + +if (!is_privileged_url(document.URL)) { + let policy_received_callback = () => undefined; + let policy; + + /* Signature valid for half an hour. */ + const min_time = new Date().getTime() - 1800 * 1000; + + if (/^https?:/.test(document.URL)) { + let signatures; + [policy, signatures] = extract_cookie_policy(document.cookie, min_time); + for (const signature of signatures) + document.cookie = `hachette-${signature}=; Max-Age=-1;`; + } else { + const scheme = /^([^:]*)/.exec(document.URL)[1]; + const known_scheme = ["file"].includes(scheme); + + if (!known_scheme) + console.warn(`Unknown url scheme: \`${scheme}'!`); + + let original_url; + [policy, original_url] = extract_url_policy(document.URL, min_time); + history.replaceState(null, "", original_url); + + if (known_scheme && !policy) + policy_received_callback = employ_nonhttp_policy; + } + if (!policy) { - console.warn("WARNING! Using default policy!!!"); + console.warn("Using default policy!"); policy = {allow: false, nonce: gen_nonce()}; } - for (const signature of extracted_signatures) - document.cookie = `hachette-${signature}=; Max-Age=-1;`; - - handle_page_actions(policy.nonce); + handle_page_actions(policy.nonce, policy_received_callback); if (!policy.allow) { + if (is_mozilla) { + const script = document.querySelector("script"); + if (script) + script.textContent = "throw 'blocked';\n" + script.textContent; + } const old_html = document.documentElement; const new_html = document.createElement("html"); old_html.replaceWith(new_html); diff --git a/content/page_actions.js b/content/page_actions.js index aff56b8..6a6b3a0 100644 --- a/content/page_actions.js +++ b/content/page_actions.js @@ -14,10 +14,13 @@ * IMPORTS_END */ -var port; -var loaded = false; -var scripts_awaiting = []; -var nonce; +let policy_received_callback; +/* Snapshot url early because document.URL can be changed by other code. */ +let url; +let port; +let loaded = false; +let scripts_awaiting = []; +let nonce; function handle_message(message) { @@ -31,8 +34,10 @@ function handle_message(message) scripts_awaiting.push(script_text); } } - if (action === "settings") + if (action === "settings") { report_settings(data); + policy_received_callback({url, allow: !!data[1] && data[1].allow}); + } } function document_loaded(event) @@ -56,11 +61,14 @@ function add_script(script_text) report_script(script_text); } -function handle_page_actions(script_nonce) { +function handle_page_actions(script_nonce, policy_received_cb) { + policy_received_callback = policy_received_cb; + url = document.URL; + document.addEventListener("DOMContentLoaded", document_loaded); port = browser.runtime.connect({name : CONNECTION_TYPE.PAGE_ACTIONS}); port.onMessage.addListener(handle_message); - port.postMessage({url: document.URL}); + port.postMessage({url}); nonce = script_nonce; } -- cgit v1.2.3