From f3f6df229fce508312c6600537ea2ac86932cb0c Mon Sep 17 00:00:00 2001 From: kkapsner Date: Thu, 23 Jan 2020 13:56:14 +0100 Subject: [PATCH] Undo interception in top windows Fixes #431 --- lib/extension.js | 41 ++++++++++++++++++++++++++++ lib/frame.js | 60 ++++++++++++++++++++++++++--------------- lib/iframeProtection.js | 15 ++--------- lib/intercept.js | 60 +++++++++++++++++++++++++---------------- versions/updates.json | 4 +++ 5 files changed, 122 insertions(+), 58 deletions(-) diff --git a/lib/extension.js b/lib/extension.js index f8790f7..0f017bf 100644 --- a/lib/extension.js +++ b/lib/extension.js @@ -90,5 +90,46 @@ } }; + const changedPropertiesByWindow = new WeakMap(); + scope.changeProperty = function(window, group, {object, name, type, changed}){ + let changedProperties = changedPropertiesByWindow.get(scope.getWrapped(window)); + if (!changedProperties){ + changedProperties = []; + changedPropertiesByWindow.set(scope.getWrapped(window), changedProperties); + } + const descriptor = Object.getOwnPropertyDescriptor(object, name); + const original = descriptor[type]; + descriptor[type] = changed; + Object.defineProperty(object, name, descriptor); + changedProperties.push({group, object, name, type, original}); + }; + scope.revertProperties = function(window, group){ + window = scope.getWrapped(window); + let changedProperties = changedPropertiesByWindow.get(window); + if (!changedProperties){ + return; + } + if (group){ + const remainingProperties = changedProperties.filter(function({group}){ + return group !== group; + }); + changedPropertiesByWindow.set(window, remainingProperties); + changedProperties = changedProperties.filter(function({group}){ + return group === group; + }); + } + else { + changedPropertiesByWindow.delete(window); + } + + for (let i = changedProperties.length - 1; i >= 0; i -= 1){ + const {object, name, type, original} = changedProperties[i]; + logging.verbose("reverting", name, "on", object); + const descriptor = Object.getOwnPropertyDescriptor(object, name); + descriptor[type] = original; + Object.defineProperty(object, name, descriptor); + } + }; + Object.seal(scope); }()); \ No newline at end of file diff --git a/lib/frame.js b/lib/frame.js index b7ccb72..3f9eb5c 100644 --- a/lib/frame.js +++ b/lib/frame.js @@ -45,13 +45,13 @@ let extensionSecret; function computeExtensionSecret(){ - function hashString(string){ - return hashing(new Uint16Array( - string.split("").map(function(c){ - return c.charCodeAt(0); - }) - )); - } + function hashString(string){ + return hashing(new Uint16Array( + string.split("").map(function(c){ + return c.charCodeAt(0); + }) + )); + } const now = new Date(); const lastTenMinutes = Math.floor(now.getMinutes() / 10) * 10; const nextRun = new Date( @@ -125,7 +125,6 @@ return settings.get(...args); } - const interceptedWindows = new WeakMap(); function interceptWindow(window){ let wrappedTry; @@ -144,9 +143,15 @@ if (!enabled || interceptedWindows.get(wrappedWindow)){ return false; } - if (wrappedWindow.matchMedia(extensionSecret[0]) === extensionSecret[1]){ - interceptedWindows.set(wrappedWindow, true); - return false; + const canvasBlockerData = wrappedWindow.matchMedia(extensionSecret[0]); + if (canvasBlockerData.secret === extensionSecret[1]){ + if (wrappedWindow.top === wrappedWindow){ + canvasBlockerData.undoIntercept(extension.extensionID); + } + else { + interceptedWindows.set(wrappedWindow, true); + return false; + } } logging.message("intercepting window", window); @@ -168,17 +173,28 @@ const matchMediaDescriptor = Object.getOwnPropertyDescriptor(wrappedWindow, "matchMedia"); const originalMatchMedia = matchMediaDescriptor.value; - matchMediaDescriptor.value = extension.exportFunctionWithName(function matchMedia(query){ - if (query === extensionSecret[0]){ - return extensionSecret[1]; - } - else { - return arguments.length > 1? - originalMatchMedia.call(this, ...arguments): - originalMatchMedia.call(this, query); - } - }, window, originalMatchMedia.name); - Object.defineProperty(wrappedWindow, "matchMedia", matchMediaDescriptor); + extension.changeProperty(window, "matchMedia", { + object: wrappedWindow, + name: "matchMedia", + type: "value", + changed: extension.exportFunctionWithName(function matchMedia(query){ + if (query === extensionSecret[0]){ + return { + secret: extensionSecret[1], + undoIntercept: function(token){ + if (token === extension.extensionID){ + extension.revertProperties(window); + } + } + }; + } + else { + return arguments.length > 1? + originalMatchMedia.call(this, ...arguments): + originalMatchMedia.call(this, query); + } + }, window, originalMatchMedia.name) + }); interceptedWindows.set(wrappedWindow, true); return true; diff --git a/lib/iframeProtection.js b/lib/iframeProtection.js index 9936f92..c9d6d9b 100644 --- a/lib/iframeProtection.js +++ b/lib/iframeProtection.js @@ -27,23 +27,12 @@ if ((typeof changed) === "function"){ changed = extension.exportFunctionWithName(changed, window, original.name); } - descriptor[type] = changed; - Object.defineProperty(object, name, descriptor); - registerChangedProperty(object, name, descriptor, type, original); - } - const changedProperties = []; - // eslint-disable-next-line max-params - function registerChangedProperty(object, name, descriptor, type, original){ - changedProperties.push({object, name, descriptor, type, original}); + extension.changeProperty(window, "iframeProtection", {object, name, type, changed}); } if (settings.isStillDefault){ settings.onloaded(function(){ if (isWhitelisted(window.location)){ - changedProperties.forEach(function({object, name, descriptor, type, original}){ - descriptor[type] = original; - Object.defineProperty(object, name, descriptor); - }); - changedProperties.length = 0; + extension.revertProperties(window, "iframeProtection"); } }); } diff --git a/lib/intercept.js b/lib/intercept.js index 5504056..024b13f 100644 --- a/lib/intercept.js +++ b/lib/intercept.js @@ -331,21 +331,22 @@ }); const descriptor = Object.getOwnPropertyDescriptor(object, name); if (!descriptor) return; - - if (descriptor.hasOwnProperty("value")){ + const type = descriptor.hasOwnProperty("value")? "value": "get"; + let changed; + if (type ==="value"){ if (changedFunction.fakeGenerator){ - descriptor.value = extension.exportFunctionWithName( + changed = extension.exportFunctionWithName( changedFunction.fakeGenerator(checker, original, windowToProcess), windowToProcess, original.name ); } else { - descriptor.value = null; + changed = null; } } else { - descriptor.get = extension.exportFunctionWithName(function(){ + changed = extension.exportFunctionWithName(function(){ return extension.exportFunctionWithName( changedFunction.fakeGenerator(checker), windowToProcess, @@ -353,7 +354,9 @@ ); }, windowToProcess, descriptor.get.name); } - Object.defineProperty(object, name, descriptor); + extension.changeProperty(windowToProcess, changedFunction.api, { + object, name, type, changed + }); }); }); } @@ -378,7 +381,12 @@ window: windowToProcess, prefs, checkStack, ask, notify }); const getter = changedGetter.getterGenerator(checker, original, windowToProcess); - descriptor.get = extension.exportFunctionWithName(getter, windowToProcess, original.name); + extension.changeProperty(windowToProcess, changedGetter.api, + { + object, name, type: "get", + changed: extension.exportFunctionWithName(getter, windowToProcess, original.name) + } + ); if (descriptor.hasOwnProperty("set") && descriptor.set && changedGetter.setterGenerator){ const original = descriptor.set; @@ -387,10 +395,14 @@ original, prefs ); - descriptor.set = extension.exportFunctionWithName(setter, windowToProcess, original.name); + extension.changeProperty(windowToProcess, changedGetter.api, + { + object, name, type: "set", + changed: extension.exportFunctionWithName(setter, windowToProcess, original.name) + } + ); } - Object.defineProperty(object, name, descriptor); } else if ( changedGetter.valueGenerator && @@ -405,21 +417,23 @@ } switch (functionStatus.mode){ case "ask": case "block": case "fake": - descriptor.value = changedGetter.valueGenerator({ - mode: functionStatus.mode, - original: descriptor.value, - notify: function notifyCallback(messageId){ - notify({ - url: getURL(windowToProcess), - errorStack: (new Error()).stack, - messageId, - timestamp: new Date(), - functionName: name, - api: changedGetter.api - }); - } + extension.changeProperty(windowToProcess, changedGetter.api, { + object, name, type: "value", + changed: changedGetter.valueGenerator({ + mode: functionStatus.mode, + original: descriptor.value, + notify: function notifyCallback(messageId){ + notify({ + url: getURL(windowToProcess), + errorStack: (new Error()).stack, + messageId, + timestamp: new Date(), + functionName: name, + api: changedGetter.api + }); + } + }) }); - Object.defineProperty(object, name, descriptor); break; } } diff --git a/versions/updates.json b/versions/updates.json index 893a025..95f45bf 100644 --- a/versions/updates.json +++ b/versions/updates.json @@ -109,6 +109,10 @@ { "version": "1.1Alpha20192001", "update_link": "https://canvasblocker.kkapsner.de/versions/canvasblocker_beta-1.1Alpha20192001-an+fx.xpi" + }, + { + "version": "1.1Alpha20192301", + "update_link": "https://canvasblocker.kkapsner.de/versions/canvasblocker_beta-1.1Alpha20192301-an+fx.xpi" } ] }