diff options
Diffstat (limited to 'src/content')
-rw-r--r-- | src/content/content.js | 77 | ||||
-rw-r--r-- | src/content/media.js | 103 | ||||
-rw-r--r-- | src/content/webglHook.js | 10 |
3 files changed, 130 insertions, 60 deletions
diff --git a/src/content/content.js b/src/content/content.js index 886c363..8f772b1 100644 --- a/src/content/content.js +++ b/src/content/content.js @@ -1,7 +1,81 @@ 'use strict'; // debug = () => {}; // REL_ONLY - +{ + let listenersMap = new Map(); + let backlog = new Set(); + var ns = { + on(eventName, listener) { + let listeners = listenersMap.get(eventName); + if (!listeners) listenersMap.set(eventName, listeners = new Set()); + listeners.add(listener); + if (backlog.has(eventName)) this.fire(eventName, listener); + }, + detach(eventName, listener) { + let listeners = listenersMap.get(eventName); + if (listeners) listeners.delete(listener); + }, + fire(eventName, listener = null) { + if (listener) { + listener({type:eventName, source: this}); + return; + } + let listeners = listenersMap.get(eventName); + if (listeners) { + for (let l of listeners) { + this.fire(eventName, l); + } + } + backlog.add(eventName); + }, + setup(DEFAULT, MARKER) { + this.perms.DEFAULT = DEFAULT; + if(!this.perms.CURRENT) this.perms.CURRENT = DEFAULT; + + // ugly hack: since now we use registerContentScript instead of the + // filterRequest dynamic script injection hack, we use top.name + // to store per-tab information. We don't want web content to + // mess with it, though, so we wrap it around auto-hiding accessors + this.perms.MARKER = MARKER; + let eraseTabInfoRx = new RegExp(`[^]*${MARKER},?`); + if (eraseTabInfoRx.test(top.name)) { + let _name = top.name; + let tabInfoRx = new RegExp(`^${MARKER}\\[([^]*?)\\]${MARKER},`); + if (top === window) { // wrap to hide + Reflect.defineProperty(top.wrappedJSObject, "name", { + get: exportFunction(() => top.name.replace(eraseTabInfoRx, ""), top.wrappedJSObject), + set: exportFunction(value => { + let preamble = top.name.match(tabInfoRx); + top.name = `${preamble && preamble[0] || ""}${value}`; + return value; + }, top.wrappedJSObject) + }); + } + let tabInfoMatch = _name.match(tabInfoRx); + if (tabInfoMatch) try { + this.perms.tabInfo = JSON.parse(tabInfoMatch[1]); + } catch (e) { + error(e); + } + } + + if (!this.perms.DEFAULT || this.perms.tabInfo.unrestricted) { + this.allows = () => true; + } + ns.fire("perms"); + }, + perms: { DEFAULT: null, CURRENT: null, tabInfo: {}, MARKER: "" }, + allows(cap) { + let perms = this.perms.CURRENT; + return perms && perms.capabilities.includes(cap); + }, + getWindowName() { + return top !== window || !this.perms.MARKER ? window.name + : window.name.split(this.perms.MARKER + ",").pop(); + } + } +} + var canScript = true, shouldScript = false; let now = () => performance.now() + performance.timeOrigin; @@ -24,7 +98,6 @@ function probe() { var _ = browser.i18n.getMessage; - var embeddingDocument = false; var seen = { diff --git a/src/content/media.js b/src/content/media.js index ffa67e0..910fd27 100644 --- a/src/content/media.js +++ b/src/content/media.js @@ -1,60 +1,57 @@ -{ - debug("Media Hook (blocked %s)", !!window.mediaBlocker, document.URL, document.documentElement && document.documentElement.innerHTML); // DEV_ONLY - (() => { - let unpatched = new Map(); - function patch(obj, methodName, replacement) { - let methods = unpatched.get(obj) || {}; - methods[methodName] = obj[methodName]; - exportFunction(replacement, obj, {defineAs: methodName}); - unpatched.set(obj, methods); +ns.on("perms", event => { + debug("Media Hook", document.URL, document.documentElement && document.documentElement.innerHTML, ns.perms.CURRENT); // DEV_ONLY + let mediaBlocker = !ns.allows("media"); + let unpatched = new Map(); + function patch(obj, methodName, replacement) { + let methods = unpatched.get(obj) || {}; + methods[methodName] = obj[methodName]; + exportFunction(replacement, obj, {defineAs: methodName}); + unpatched.set(obj, methods); + } + let urlMap = new WeakMap(); + patch(window.URL, "createObjectURL", function(o, ...args) { + let url = unpatched.get(window.URL).createObjectURL.call(this, o, ...args); + if (o instanceof MediaSource) { + let urls = urlMap.get(o); + if (!urls) urlMap.set(o, urls = new Set()); + urls.add(url); } - let urlMap = new WeakMap(); - patch(window.URL, "createObjectURL", function(o, ...args) { - let url = unpatched.get(window.URL).createObjectURL.call(this, o, ...args); - if (o instanceof MediaSource) { - let urls = urlMap.get(o); - if (!urls) urlMap.set(o, urls = new Set()); - urls.add(url); - } - return url; - }); + return url; + }); - patch(window.MediaSource.prototype, "addSourceBuffer", function(mime, ...args) { - let ms = this; - let urls = urlMap.get(ms); + patch(window.MediaSource.prototype, "addSourceBuffer", function(mime, ...args) { + let ms = this; + let urls = urlMap.get(ms); - let request = { - id: "noscript-media", - type: "media", - url: document.URL, - documentUrl: document.URL, - embeddingDocument: true, - }; - seen.record({policyType: "media", request, allowed: false}); - notifyPage(); + let request = { + id: "noscript-media", + type: "media", + url: document.URL, + documentUrl: document.URL, + embeddingDocument: true, + }; + seen.record({policyType: "media", request, allowed: false}); + notifyPage(); - if (window.mediaBlocker) { - (async () => { - let me = Array.from(document.querySelectorAll("video,audio")) - .find(e => e.srcObject === ms || urls && urls.has(e.src)); + if (mediaBlocker) { + (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)`; + 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`); - } - - return unpatched.get(window.MediaSource.prototype).addSourceBuffer.call(ms, mime, ...args); - }); + try { + let ph = PlaceHolder.create("media", request); + ph.replace(me); + PlaceHolder.listen(); + } catch (e) { + error(e); + } + })(); + throw new Error(`${exposedMime} blocked by NoScript`); + } - })(); - document.URL; -} + return unpatched.get(window.MediaSource.prototype).addSourceBuffer.call(ms, mime, ...args); + }); +}); diff --git a/src/content/webglHook.js b/src/content/webglHook.js index d4c064a..efafcd5 100644 --- a/src/content/webglHook.js +++ b/src/content/webglHook.js @@ -1,5 +1,6 @@ -{ - debug("WebGL Hook", document.URL, document.documentElement && document.documentElement.innerHTML); // DEV_ONLY +ns.on("perms", event => { + debug("WebGL Hook", document.URL, document.documentElement && document.documentElement.innerHTML, ns.perms.CURRENT); // DEV_ONLY + if (ns.allows("webgl")) return; let proto = HTMLCanvasElement.prototype; let getContext = proto.getContext; exportFunction(function(type, ...rest) { @@ -23,6 +24,5 @@ return {}; } return getContext.call(this, type, ...rest); - }, proto, {defineAs: "getContext"}); - document.URL; -} + }, proto, {defineAs: "getContext"}); +}); |