summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhackademix2018-07-02 01:50:32 +0200
committerhackademix2018-07-02 01:50:32 +0200
commit81bd93a72d0b49fd78908f7c467ae9f324791e23 (patch)
treedaacfeb158f1f6512532d7e4ccafc6da68494aa4
parent673c881559e4f9274be5b54ca35552e12cd8cd76 (diff)
downloadnoscript-81bd93a72d0b49fd78908f7c467ae9f324791e23.tar.gz
noscript-81bd93a72d0b49fd78908f7c467ae9f324791e23.tar.xz
noscript-81bd93a72d0b49fd78908f7c467ae9f324791e23.zip
Simplified and apparently more reliable+flexible+efficient dynamic script injection method.
-rw-r--r--src/bg/RequestGuard.js2
-rw-r--r--src/bg/RequestUtil.js161
-rw-r--r--src/content/media.js27
-rw-r--r--src/content/webglHook.js2
-rw-r--r--src/lib/log.js2
5 files changed, 65 insertions, 129 deletions
diff --git a/src/bg/RequestGuard.js b/src/bg/RequestGuard.js
index 0f1558c..3304d02 100644
--- a/src/bg/RequestGuard.js
+++ b/src/bg/RequestGuard.js
@@ -422,7 +422,7 @@ var RequestGuard = (() => {
}
}
- debug(`CSP blocker:`, blocker);
+ debug(`CSP blocker on %s:`, request.url, blocker);
if (blocker) {
if (header) {
header.value = CSP.inject(header.value, blocker);
diff --git a/src/bg/RequestUtil.js b/src/bg/RequestUtil.js
index 1ebbbaa..2020286 100644
--- a/src/bg/RequestUtil.js
+++ b/src/bg/RequestUtil.js
@@ -1,130 +1,61 @@
'use strict';
{
- let runningScripts = new Map();
-
+ let pendingRequests = new Map();
+ let cleanup = r => {
+ pendingRequests.delete(r.requestId);
+ };
+ let filter = {
+ urls: ["<all_urls>"],
+ types: ["main_frame", "sub_frame", "object"]
+ };
+ browser.webRequest.onCompleted.addListener(cleanup, filter);
+ browser.webRequest.onErrorOccurred.addListener(cleanup, filter);
var RequestUtil = {
async executeOnStart(request, details) {
let {requestId, tabId, frameId} = request;
- details = Object.assign({
- runAt: "document_start",
- frameId,
- }, details);
- browser.tabs.executeScript(tabId, details);
- return;
- let filter = browser.webRequest.filterResponseData(requestId);
- filter.onstart = event => {
- browser.tabs.executeScript(tabId, details);
- debug("Execute on start", details);
- filter.write(new Uint8Array());
- };
- filter.ondata = event => {
- filter.write(event.data);
- filter.disconnect();
-
- }
- },
- async executeOnStartCS(request, details) {
- let {url, requestId, tabId, frameId} = request;
-
- let urlObj = new URL(url);
- if (urlObj.hash || urlObj.port || urlObj.username) {
- urlObj.hash = urlObj.port = urlObj.username = "";
- url = urlObj.toString();
+ let scripts = pendingRequests.get(requestId);
+ let scriptKey = JSON.stringify(details);
+ if (!scripts) {
+ pendingRequests.set(requestId, scripts = new Map());
+ scripts.set(scriptKey, details);
+ } else {
+ scripts.set(scriptKey, details);
+ return;
}
- let wr = browser.webRequest;
- let filter = {
- urls: [`${urlObj.origin}/*`],
- types: ["main_frame", "sub_frame", "object"]
- };
- let finalize;
- let cleanup = r => {
- if (cleanup && r.requestId === requestId) {
- wr.onCompleted.removeListener(cleanup);
- wr.onErrorOccurred.removeListener(cleanup);
- cleanup = null;
- if (finalize) {
- finalize();
- }
- }
- };
- wr.onCompleted.addListener(cleanup, filter);
- wr.onErrorOccurred.addListener(cleanup, filter);
-
- details = Object.assign({
- runAt: "document_start",
- frameId,
- }, details);
-
- if (browser.contentScripts) {
- let js = [{}];
- if (details.file) js[0].file = details.file;
- else if (details.code) js[0].code = details.code;
- let settings = {
- "runAt": details.runAt,
- js,
- matches: [url],
- allFrames: frameId !== 0,
- }
- // let's try to avoid duplicates
- let key = JSON.stringify(settings);
- if (runningScripts.has(key)) {
- let scriptRef = runningScripts.get(key);
- scriptRef.count++;
- return;
- }
- if (settings.allFrames) {
- // let's check whether the same script is registered for top frames:
- // if it is, let's unregister it first to avoid duplicates
- settings.allFrames = false;
- let topKey = JSON.stringify(settings);
- settings.allFrames = true;
- if (runningScripts.has(topKey)) {
- let topScript = runningScripts.get(topKey);
- try {
- topScript.unregister();
- } catch (e) {
- error(e);
- } finally {
- runningScripts.delete(topKey);
- }
- }
- }
- let script = await browser.contentScripts.register(settings);
- debug("Content script %o registered.", settings);
- finalize = () => {
- debug("Finalizing content script %o...", settings);
+ let filter = browser.webRequest.filterResponseData(requestId);
+ let buffer = [];
+ filter.onstart = async event => {
+ filter.write(new Uint8Array());
+ for (let details of scripts.values()) {
+ details = Object.assign({
+ runAt: "document_start",
+ frameId,
+ }, details);
try {
- script.unregister();
- runningScripts.delete(key);
- debug("Content script %o unregistered!", settings);
- } finally {
- finalize = null;
+ await browser.tabs.executeScript(tabId, details);
+ debug("Execute on start OK", request.url, details);
+ } catch (e) {
+ error(e, "Execute on start failed", request.url, details);
}
}
- runningScripts.set(key, script);
- if (!cleanup) { // the request has already been interrupted
- finalize();
+ if (buffer.length) {
+ debug("Flushing %s buffer chunks", buffer.length);
+ for (let chunk of buffer) {
+ filter.write(chunk);
+ }
+ filter.disconnect();
+ buffer = null;
}
-
- return;
- }
-
- function listener(r) {
- if (r.requestId === requestId) {
- browser.tabs.executeScript(tabId, details);
- finalize();
- finalize = null;
+ };
+ filter.ondata = event => {
+ if (buffer) {
+ buffer.push(event.data);
+ return;
}
+ filter.write(event.data);
+ filter.disconnect();
}
- finalize = () => {
- wr.onResponseStarted.removeListener(listener);
- }
- wr.onResponseStarted.addListener(listener, filter);
- debug("Executing %o", details);
-
- },
-
-
+ }
}
}
diff --git a/src/content/media.js b/src/content/media.js
index 22bf014..4ca8942 100644
--- a/src/content/media.js
+++ b/src/content/media.js
@@ -1,4 +1,4 @@
-console.log("Media Hook", document.documentElement.innerHTML);
+debug("Media Hook (blocked %s)", !!window.mediaBlocker, document.URL, document.documentElement && document.documentElement.innerHTML);
try {
(() => {
let unpatched = new Map();
@@ -25,9 +25,6 @@ try {
patch(window.MediaSource.prototype, "addSourceBuffer", function(mime, ...args) {
let ms = this;
let urls = urlMap.get(ms);
- let me = Array.from(document.querySelectorAll("video,audio"))
- .find(e => e.srcObject === ms || urls && urls.has(e.src));
- let exposedMime = `${mime} (MSE)`;
let request = {
id: "noscript-media",
@@ -40,13 +37,21 @@ try {
notifyPage();
if (window.mediaBlocker) {
- try {
- let ph = PlaceHolder.create("media", request);
- ph.replace(me);
- PlaceHolder.listen();
- } catch (e) {
- error(e);
- }
+ (async () => {
+ let me = Array.from(document.querySelectorAll("video,audio"))
+ .find(e => e.srcObject === ms || urls && urls.has(e.src));
+
+ if (!me) return;
+ let exposedMime = `${mime} (MSE)`;
+
+ try {
+ let ph = PlaceHolder.create("media", request);
+ ph.replace(me);
+ PlaceHolder.listen();
+ } catch (e) {
+ error(e);
+ }
+ })();
throw new Error(`${exposedMime} blocked by NoScript`);
}
diff --git a/src/content/webglHook.js b/src/content/webglHook.js
index ba0d769..5b83025 100644
--- a/src/content/webglHook.js
+++ b/src/content/webglHook.js
@@ -1,4 +1,4 @@
-console.log("WebGL Hook", document.documentElement.innerHTML);
+console.log("WebGL Hook", document.URL, document.documentElement && document.documentElement.innerHTML);
try {
let proto = HTMLCanvasElement.prototype;
let getContext = proto.getContext;
diff --git a/src/lib/log.js b/src/lib/log.js
index fe38b87..0f12698 100644
--- a/src/lib/log.js
+++ b/src/lib/log.js
@@ -9,6 +9,6 @@
console.debug(`${PREFIX} ${msg}`, ...rest);
}
function error(e, msg, ...rest) {
- console.error(`${PREFIX} ${msg}`, e, e.message, e.stack);
+ console.error(`${PREFIX} ${msg}`, ...rest, e, e.message, e.stack);
}
}