diff options
Diffstat (limited to 'src/content')
-rw-r--r-- | src/content/PlaceHolder.js | 25 | ||||
-rw-r--r-- | src/content/content.js | 22 | ||||
-rw-r--r-- | src/content/embeddingDocument.js | 23 | ||||
-rw-r--r-- | src/content/onScriptDisabled.js | 16 |
4 files changed, 66 insertions, 20 deletions
diff --git a/src/content/PlaceHolder.js b/src/content/PlaceHolder.js index f32c812..ac4dc14 100644 --- a/src/content/PlaceHolder.js +++ b/src/content/PlaceHolder.js @@ -1,6 +1,6 @@ var PlaceHolder = (() => { const HANDLERS = new Map(); - + let checkStyle = async () => { checkStyle = () => {}; if (!ns.embeddingDocument) return; @@ -11,7 +11,7 @@ var PlaceHolder = (() => { (await fetch(browser.extension.getURL("/content/content.css"))).text(); } } - + class Handler { constructor(type, selector) { this.type = type; @@ -20,10 +20,16 @@ var PlaceHolder = (() => { HANDLERS.set(type, this); } filter(element, request) { - if (request.embeddingDocument) return true; + if (request.embeddingDocument) { + return document.URL === request.url; + } let url = request.initialUrl || request.url; return "data" in element ? element.data === url : element.src === url; } + selectFor(request) { + return [...document.querySelectorAll(this.selector)] + .filter(element => this.filter(element, request)) + } } new Handler("frame", "iframe"); @@ -59,6 +65,9 @@ var PlaceHolder = (() => { static canReplace(policyType) { return HANDLERS.has(policyType); } + static handlerFor(policyType) { + return HANDLERS.get(policyType); + } static listen() { PlaceHolder.listen = () => {}; @@ -83,7 +92,7 @@ var PlaceHolder = (() => { this.policyType = policyType; this.request = request; this.replacements = new Set(); - this.handler = HANDLERS.get(policyType); + this.handler = PlaceHolder.handlerFor(policyType); if (this.handler) { [...document.querySelectorAll(this.handler.selector)] .filter(element => this.handler.filter(element, request)) @@ -100,7 +109,11 @@ var PlaceHolder = (() => { let { url } = this.request; - this.origin = new URL(url).origin; + let objUrl = new URL(url) + this.origin = objUrl.origin; + if (this.origin === "null") { + this.origin = objUrl.protocol; + } let TYPE = `<${this.policyType.toUpperCase()}>`; let replacement = createHTMLElement("a"); @@ -129,7 +142,7 @@ var PlaceHolder = (() => { replacement._placeHolderObj = this; replacement._placeHolderElement = element; - + element.parentNode.replaceChild(replacement, element); this.replacements.add(replacement); diff --git a/src/content/content.js b/src/content/content.js index e73feb6..fb68ae4 100644 --- a/src/content/content.js +++ b/src/content/content.js @@ -1,6 +1,5 @@ 'use strict'; // debug = () => {}; // REL_ONLY - var _ = browser.i18n.getMessage; function createHTMLElement(name) { @@ -50,7 +49,7 @@ var notifyPage = async () => { if (document.readyState === "complete") { try { if (!("canScript" in ns)) { - let childPolicy = await Messages.send("fetchChildPolicy", {url: document.URL, contextUrl: top.location.href}); + let childPolicy = await Messages.send("fetchChildPolicy", {url: document.URL}); ns.config.CURRENT = childPolicy.CURRENT; ns.setup(childPolicy.DEFAULT, childPolicy.MARKER); return; @@ -82,11 +81,22 @@ ns.on("capabilities", () => { }, allowed: ns.canScript }); - - if (!ns.canScript) { + if (!ns.canScript) { + addEventListener("beforescriptexecute", e => e.preventDefault()); + let mo = new MutationObserver(mutations => { + for (let m of mutations) { + console.log(`Mutation `, m); + if (m.type !== "attribute") continue; + if (/^on\w+/i.test(m.attributeName)) { + m.target.removeAttribute(m.attributeName); + } else if (/^\s*(javascript|data):/i.test(m.target.attributes[m.attributeName])) { + m.target.setAttribute(m.attributeName, "#"); + } + } + }); + // mo.observe(document.documentElement, {attributes: true, subtree: true}); if ("serviceWorker" in navigator && navigator.serviceWorker.controller) { - addEventListener("beforescriptexecute", e => e.preventDefault()); (async () => { for (let r of await navigator.serviceWorker.getRegistrations()) { await r.unregister(); @@ -97,6 +107,6 @@ ns.on("capabilities", () => { if (document.readyState !== "loading") onScriptDisabled(); window.addEventListener("DOMContentLoaded", onScriptDisabled); } - + notifyPage(); }); diff --git a/src/content/embeddingDocument.js b/src/content/embeddingDocument.js index 75b0db0..eed04b1 100644 --- a/src/content/embeddingDocument.js +++ b/src/content/embeddingDocument.js @@ -1,18 +1,25 @@ if (ns.embeddingDocument) { ns.on("capabilities", () => { for (let policyType of ["object", "media"]) { - if (!ns.allows(policyType)) { - let request = { - id: `noscript-${policyType}-doc`, - type: policyType, - url: document.URL, - documentUrl: document.URL, - embeddingDocument: true, - }; + let request = { + id: `noscript-${policyType}-doc`, + type: policyType, + url: document.URL, + documentUrl: document.URL, + embeddingDocument: true, + }; + + if (ns.allows(policyType)) { + let handler = PlaceHolder.handlerFor(policyType); + if (handler && handler.selectFor(request).length > 0) { + seen.record({policyType, request, allowed: true}); + } + } else { let ph = PlaceHolder.create(policyType, request); if (ph.replacements.size > 0) { debug(`Created placeholder for ${policyType} at ${document.URL}`); seen.record({policyType, request, allowed: false}); + break; } } } diff --git a/src/content/onScriptDisabled.js b/src/content/onScriptDisabled.js index 3606ede..79912c9 100644 --- a/src/content/onScriptDisabled.js +++ b/src/content/onScriptDisabled.js @@ -1,4 +1,20 @@ function onScriptDisabled() { + if (document.URL.startsWith("file:")) { + // file: documents are loaded synchronously and may not be affected by + // CSP. We already intercept onbeforeexecutescript event, let's cope with + // event and URL attributes. + for (let e of document.all) { + for (let a of e.attributes) { + if (/^on\w+/i.test(a.name)) { + debug(`Removed %s.%sevent`, e.tagName, a.name); + a.value = ""; + } else if (/^\s*(?:data|javascript):/i.test(unescape(a.value))) { + debug(`Neutralized %s.%s="%s" attribute`, e.tagName, a.name, a.value); + a.value = "data:"; + } + } + } + } for (let noscript of document.querySelectorAll("noscript")) { // force show NOSCRIPT elements content let replacement = createHTMLElement("span"); |