mirror of
https://github.com/kkapsner/CanvasBlocker
synced 2024-12-22 12:50:36 +01:00
Improved iFrame protection
This commit is contained in:
parent
92ff2ff5d4
commit
2da680bfcb
38
lib/frame.js
38
lib/frame.js
@ -11,6 +11,7 @@
|
||||
const {check: originalCheck, checkStack: originalCheckStack} = require("./check");
|
||||
const {getWrapped} = require("./modifiedAPIFunctions");
|
||||
const extension = require("./extension");
|
||||
const iframeProtection = require("./iframeProtection");
|
||||
|
||||
const logging = require("./logging");
|
||||
const {error, warning, message, notice, verbose, setPrefix: setLogPrefix} = logging;
|
||||
@ -150,40 +151,15 @@
|
||||
);
|
||||
message("prepare to intercept (i)frames.");
|
||||
|
||||
[window.HTMLIFrameElement, window.HTMLFrameElement].forEach(function(constructor){
|
||||
var oldContentWindowGetter = constructor.prototype.__lookupGetter__("contentWindow");
|
||||
Object.defineProperty(
|
||||
getWrapped(constructor.prototype),
|
||||
"contentWindow",
|
||||
{
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
get: exportFunction(function(){
|
||||
var window = oldContentWindowGetter.call(this);
|
||||
if (window){
|
||||
interceptWindow(window);
|
||||
function interceptAllFrames(){
|
||||
const currentLength = window.length;
|
||||
for (let i = currentLength; i--;){
|
||||
if (!interceptedWindows.get(wrappedWindow[i])){
|
||||
interceptWindow(window[i]);
|
||||
}
|
||||
return window;
|
||||
}, window)
|
||||
}
|
||||
);
|
||||
var oldContentDocumentGetter = constructor.prototype.__lookupGetter__("contentDocument");
|
||||
Object.defineProperty(
|
||||
getWrapped(constructor.prototype),
|
||||
"contentDocument",
|
||||
{
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
get: exportFunction(function(){
|
||||
var document = oldContentDocumentGetter.call(this);
|
||||
if (document){
|
||||
interceptWindow(document.defaultView);
|
||||
}
|
||||
return document;
|
||||
}, window)
|
||||
}
|
||||
);
|
||||
});
|
||||
iframeProtection.protect(window, wrappedWindow, interceptWindow, interceptAllFrames);
|
||||
|
||||
const matchMediaDescriptor = Object.getOwnPropertyDescriptor(wrappedWindow, "matchMedia");
|
||||
const originalMatchMedia = matchMediaDescriptor.value;
|
||||
|
150
lib/iframeProtection.js
Normal file
150
lib/iframeProtection.js
Normal file
@ -0,0 +1,150 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
(function(){
|
||||
"use strict";
|
||||
|
||||
let scope;
|
||||
if ((typeof exports) !== "undefined"){
|
||||
scope = exports;
|
||||
}
|
||||
else {
|
||||
scope = require.register("./iframeProtection", {});
|
||||
}
|
||||
const {getWrapped} = require("./modifiedAPIFunctions");
|
||||
|
||||
scope.protect = function protect(window, wrappedWindow, singleCallback, allCallback){
|
||||
|
||||
|
||||
[window.HTMLIFrameElement, window.HTMLFrameElement].forEach(function(constructor){
|
||||
var oldContentWindowGetter = constructor.prototype.__lookupGetter__("contentWindow");
|
||||
Object.defineProperty(
|
||||
getWrapped(constructor.prototype),
|
||||
"contentWindow",
|
||||
{
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
get: exportFunction(function(){
|
||||
var window = oldContentWindowGetter.call(this);
|
||||
if (window){
|
||||
singleCallback(window);
|
||||
}
|
||||
return window;
|
||||
}, window)
|
||||
}
|
||||
);
|
||||
var oldContentDocumentGetter = constructor.prototype.__lookupGetter__("contentDocument");
|
||||
Object.defineProperty(
|
||||
getWrapped(constructor.prototype),
|
||||
"contentDocument",
|
||||
{
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
get: exportFunction(function(){
|
||||
var document = oldContentDocumentGetter.call(this);
|
||||
if (document){
|
||||
singleCallback(document.defaultView);
|
||||
}
|
||||
return document;
|
||||
}, window)
|
||||
}
|
||||
);
|
||||
});
|
||||
[
|
||||
// useless as length could be obtained before the iframe is created and window.frames === window
|
||||
// {
|
||||
// object: wrappedWindow,
|
||||
// methods: [],
|
||||
// getters: ["length", "frames"],
|
||||
// setters: []
|
||||
// },
|
||||
{
|
||||
object: wrappedWindow.Node.prototype,
|
||||
methods: ["appendChild", "insertBefore", "replaceChild"],
|
||||
getters: [],
|
||||
setters: []
|
||||
},
|
||||
{
|
||||
object: wrappedWindow.Element.prototype,
|
||||
methods: [
|
||||
"append", "prepend",
|
||||
"insertAdjacentElement", "insertAdjacentHTML", "insertAdjacentText",
|
||||
"replaceWith"
|
||||
],
|
||||
getters: [],
|
||||
setters: ["innerHTML", "outerHTML"]
|
||||
}
|
||||
].forEach(function(protectionDefinition){
|
||||
const object = protectionDefinition.object;
|
||||
protectionDefinition.methods.forEach(function(method){
|
||||
const descriptor = Object.getOwnPropertyDescriptor(object, method);
|
||||
const original = descriptor.value;
|
||||
descriptor.value = exportFunction(eval(`(function ${method}(){
|
||||
const value = arguments.length?
|
||||
original.apply(this, window.Array.from(arguments)):
|
||||
original.call(this);
|
||||
allCallback();
|
||||
return value;
|
||||
})`), window);
|
||||
Object.defineProperty(object, method, descriptor);
|
||||
});
|
||||
protectionDefinition.getters.forEach(function(property){
|
||||
const descriptor = Object.getOwnPropertyDescriptor(object, property);
|
||||
const temp = eval(`({
|
||||
get ${property}(){
|
||||
const ret = this.${property};
|
||||
allCallback();
|
||||
return ret;
|
||||
}
|
||||
})`);
|
||||
descriptor.get = exportFunction(Object.getOwnPropertyDescriptor(temp, property).get, window);
|
||||
Object.defineProperty(object, property, descriptor);
|
||||
});
|
||||
protectionDefinition.setters.forEach(function(property){
|
||||
const descriptor = Object.getOwnPropertyDescriptor(object, property);
|
||||
const temp = eval(`({
|
||||
set ${property}(value){
|
||||
const ret = this.${property} = value;
|
||||
allCallback();
|
||||
return ret;
|
||||
}
|
||||
})`);
|
||||
descriptor.set = exportFunction(Object.getOwnPropertyDescriptor(temp, property).set, window);
|
||||
Object.defineProperty(object, property, descriptor);
|
||||
});
|
||||
});
|
||||
|
||||
// MutationObserver to intercept iframes while generating the DOM.
|
||||
var observer = new MutationObserver(allCallback);
|
||||
observer.observe(window.document.documentElement, {subtree: true, childList: true});
|
||||
window.document.addEventListener("DOMContentLoaded", function(){
|
||||
observer.disconnect();
|
||||
});
|
||||
|
||||
// MutationObserver does not trigger fast enough when document.write is used
|
||||
const documentWriteDescriptor = Object.getOwnPropertyDescriptor(wrappedWindow.HTMLDocument.prototype, "write");
|
||||
const documentWrite = documentWriteDescriptor.value;
|
||||
documentWriteDescriptor.value = exportFunction(function write(str){
|
||||
const parts = str.split(/(?=>)/);
|
||||
const length = parts.length;
|
||||
for (let i = 0; i < length; i += 1){
|
||||
documentWrite.call(this, parts[i]);
|
||||
allCallback();
|
||||
}
|
||||
}, window);
|
||||
Object.defineProperty(wrappedWindow.HTMLDocument.prototype, "write", documentWriteDescriptor);
|
||||
|
||||
const documentWritelnDescriptor = Object.getOwnPropertyDescriptor(wrappedWindow.HTMLDocument.prototype, "writeln");
|
||||
const documentWriteln = documentWritelnDescriptor.value;
|
||||
documentWritelnDescriptor.value = exportFunction(function writeln(str){
|
||||
const parts = str.split(/(?=>)/);
|
||||
const length = parts.length - 1;
|
||||
for (let i = 0; i < length; i += 1){
|
||||
documentWrite.call(this, parts[i]);
|
||||
allCallback();
|
||||
}
|
||||
documentWriteln.call(this, parts[length]);
|
||||
}, window);
|
||||
Object.defineProperty(wrappedWindow.HTMLDocument.prototype, "writeln", documentWritelnDescriptor);
|
||||
};
|
||||
}());
|
@ -58,6 +58,7 @@
|
||||
|
||||
"lib/lists.js",
|
||||
"lib/check.js",
|
||||
"lib/iframeProtection.js",
|
||||
|
||||
"lib/frame.js"
|
||||
]
|
||||
|
@ -27,6 +27,7 @@ Version 0.5.9:
|
||||
- preventing double interception (increased performance and reduced detectability)
|
||||
- detection over navigator and DOMRect getters was possible
|
||||
- audio cache could break readout
|
||||
- improved iFrame protection
|
||||
|
||||
known issues:
|
||||
- if a data URL is blocked the page action button does not appear
|
||||
|
Loading…
x
Reference in New Issue
Block a user