Work-arounds for edge cases in synchronous page loads bypassing webRequest (thanks skriptimaahinen).

This commit is contained in:
hackademix 2020-08-13 00:32:03 +02:00
parent d4c2ab2c05
commit 1e36986795
3 changed files with 20 additions and 27 deletions

View File

@ -1,5 +1,4 @@
'use strict'; 'use strict';
class DocumentCSP { class DocumentCSP {
constructor(document) { constructor(document) {
this.document = document; this.document = document;
@ -33,6 +32,9 @@ class DocumentCSP {
meta.setAttribute("http-equiv", header.name); meta.setAttribute("http-equiv", header.name);
meta.setAttribute("content", header.value); meta.setAttribute("content", header.value);
let root = document.documentElement; let root = document.documentElement;
let rootAttrs = [...root.attributes].filter(a => a.name.toLowerCase().startsWith("on"));
for (let a of rootAttrs) root.removeAttributeNode(a);
let {head} = document; let {head} = document;
let parent = head || let parent = head ||
(root instanceof HTMLElement (root instanceof HTMLElement
@ -44,6 +46,9 @@ class DocumentCSP {
debug(`Failsafe <meta> CSP inserted in %s: "%s"`, document.URL, header.value); debug(`Failsafe <meta> CSP inserted in %s: "%s"`, document.URL, header.value);
meta.remove(); meta.remove();
if (!head) parent.remove(); if (!head) parent.remove();
for (let a of rootAttrs) {
root.setAttributeNodeNS(a);
}
} catch (e) { } catch (e) {
error(e, "Error inserting CSP %s in %s", document.URL, header && header.value); error(e, "Error inserting CSP %s in %s", document.URL, header && header.value);
return false; return false;

View File

@ -66,10 +66,9 @@
} }
let originalState = document.readyState; let originalState = document.readyState;
let blockedScripts = []; let syncLoad = UA.isMozilla && /^(?:ftp|file):/.test(url);
let localPolicyKey, localPolicy; let localPolicyKey, localPolicy;
if (UA.isMozilla && /^(?:ftp|file):/.test(url)) { if (syncLoad) {
localPolicyKey = `ns.policy.${url}|${browser.runtime.getURL("")}`; localPolicyKey = `ns.policy.${url}|${browser.runtime.getURL("")}`;
let localPolicy = sessionStorage.getItem(localPolicyKey); let localPolicy = sessionStorage.getItem(localPolicyKey);
sessionStorage.removeItem(localPolicyKey); sessionStorage.removeItem(localPolicyKey);
@ -81,39 +80,27 @@
} catch(e) { } catch(e) {
error(e, "Could not setup local policy", localPolicy); error(e, "Could not setup local policy", localPolicy);
} }
} else {
addEventListener("beforescriptexecute", e => {
console.log("Blocking early script", e.target);
e.preventDefault();
});
stop();
} }
} }
let policy = null;
let setup = policy => { let setup = policy => {
debug("Fetched %o, readyState %s", policy, document.readyState); // DEV_ONLY debug("Fetched %o, readyState %s", policy, document.readyState); // DEV_ONLY
this.setup(policy); this.setup(policy);
if (this.canScript && blockedScripts.length && originalState === "loading") { if (syncLoad && !localPolicy) {
log("Running suspended scripts which are permitted by %s policy.", url); sessionStorage.setItem(localPolicyKey, JSON.stringify(policy));
// something went wrong, e.g. with session restore. return;
if (url.startsWith("file:") && !localPolicy) {
stop();
sessionStorage.setItem(localPolicyKey, JSON.stringify(policy));
location.reload(false);
return;
}
for (let s of blockedScripts) {
// reinsert the script:
// just s.cloneNode(true) doesn't work, the script wouldn't run,
// let's clone it the hard way...
try {
s.replaceWith(document.createRange().createContextualFragment(s.outerHTML));
} catch (e) {
error(e);
}
}
} }
} }
for (;;) { for (;;) {
try { try {
policy = browser.runtime.sendSyncMessage( browser.runtime.sendSyncMessage(
{id: "fetchPolicy", url, contextUrl: url}, {id: "fetchPolicy", url, contextUrl: url},
setup); setup);
break; break;

View File

@ -221,6 +221,7 @@
// or when other extensions manipulate the DOM early) we additionally // or when other extensions manipulate the DOM early) we additionally
// suspend on beforescriptexecute events // suspend on beforescriptexecute events
let startTime = Date.now(); // DEV_ONLY
let suspendURL = url + "&suspend=true"; let suspendURL = url + "&suspend=true";
let suspended = 0; let suspended = 0;
let suspendedId = 0; let suspendedId = 0;
@ -236,7 +237,7 @@
console.error(e); console.error(e);
} }
suspended--; suspended--;
console.debug("sendSyncMessage resume #%s/%s", id, suspended); console.debug("sendSyncMessage resume #%s/%s - %sms", id, suspended, Date.now() - startTime); // DEV_ONLY
}; };