Webgl hook refactored on nscl/content/patchWindow.js and made Chromium-compatibile.

This commit is contained in:
hackademix 2021-01-24 18:38:36 +01:00
parent ab3eab6e18
commit 9639ea49ac
2 changed files with 29 additions and 79 deletions

View File

@ -1,91 +1,41 @@
if (typeof exportFunction === "function") ns.on("capabilities", event => {
// depends on nscl/content/patchWindow.js
"use strict";
ns.on("capabilities", event => {
debug("WebGL Hook", document.URL, document.documentElement && document.documentElement.innerHTML, ns.capabilities); // DEV_ONLY
if (ns.allows("webgl")) return;
// win: window object to modify.
// modifyTarget: callback to function that modifies the desired properties
// or methods. Callback must take target window as argument.
function modifyWindow(win, modifyTarget) {
let env = {eventName: `nsWebgl:${uuid()}`};
window.addEventListener(env.eventName, e => {
let canvas = e.target;
if (!(canvas instanceof HTMLCanvasElement)) return;
let request = {
id: "noscript-webgl",
type: "webgl",
url: document.URL,
documentUrl: document.URL,
embeddingDocument: true,
};
seen.record({policyType: "webgl", request, allowed: false});
try {
modifyTarget(win);
modifyWindowOpenMethod(win, modifyTarget);
modifyFramingElements(win, modifyTarget);
let ph = PlaceHolder.create("webgl", request);
ph.replace(canvas);
PlaceHolder.listen();
} catch (e) {
if (e instanceof DOMException && e.name === "SecurityError") {
// In case someone tries to access SOP restricted window.
// We can just ignore this.
} else throw e;
error(e);
}
}
notifyPage();
}, true);
function modifyWindowOpenMethod(win, modifyTarget) {
let windowOpen = win.wrappedJSObject ? win.wrappedJSObject.open : win.open;
exportFunction(function(...args) {
let newWin = windowOpen.call(this, ...args);
if (newWin) modifyWindow(newWin, modifyTarget);
return newWin;
}, win, {defineAs: "open"});
}
function modifyFramingElements(win, modifyTarget) {
for (let property of ["contentWindow", "contentDocument"]) {
for (let interface of ["Frame", "IFrame", "Object"]) {
let proto = win[`HTML${interface}Element`].prototype;
modifyContentProperties(proto, property, modifyTarget)
}
}
}
function modifyContentProperties(proto, property, modifyTarget) {
let descriptor = Object.getOwnPropertyDescriptor(proto, property);
let origGetter = descriptor.get;
let replacementFn;
if (property === "contentWindow") { replacementFn = function() {
let win = origGetter.call(this);
if (win) modifyWindow(win, modifyTarget);
return win;
}}
if (property === "contentDocument") { replacementFn = function() {
let document = origGetter.call(this);
if (document && document.defaultView) modifyWindow(document.defaultView, modifyTarget);
return document;
}}
descriptor.get = exportFunction(replacementFn, proto, {defineAs: `get $property`});
let wrappedProto = proto.wrappedJSObject || proto;
Object.defineProperty(wrappedProto, property, descriptor);
}
//
function modifyGetContext(win) {
function modifyGetContext(win, env) {
let proto = win.HTMLCanvasElement.prototype;
let getContext = proto.getContext;
exportFunction(function(type, ...rest) {
if (type && type.toLowerCase().includes("webgl")) {
let request = {
id: "noscript-webgl",
type: "webgl",
url: document.URL,
documentUrl: document.URL,
embeddingDocument: true,
};
seen.record({policyType: "webgl", request, allowed: false});
try {
let ph = PlaceHolder.create("webgl", request);
ph.replace(this);
PlaceHolder.listen();
} catch (e) {
error(e);
}
notifyPage();
this.dispatchEvent(new Event(env.eventName));
return null;
}
return getContext.call(this, type, ...rest);
}, proto, {defineAs: "getContext"});
}
modifyWindow(window, modifyGetContext);
patchWindow(modifyGetContext, env);
});

View File

@ -1,6 +1,6 @@
"use strict";
function patchWindow(patchingCallback, targetWindow = window) {
function patchWindow(patchingCallback, env = {}) {
let nativeExport = this && this.exportFunction || typeof exportFunction == "function";
if (!nativeExport) {
// Chromium
@ -26,7 +26,7 @@ function patchWindow(patchingCallback, targetWindow = window) {
patchWindow,
exportFunction,
cloneInto,
}).patchWindow(${patchingCallback});
}).patchWindow(${patchingCallback}, ${JSON.stringify(env)});
})();
`;
document.documentElement.insertBefore(script, document.documentElement.firstChild);
@ -39,7 +39,7 @@ function patchWindow(patchingCallback, targetWindow = window) {
// or methods. Callback must take target window as argument.
function modifyWindow(win, modifyTarget) {
try {
modifyTarget(win.wrappedJSObject || win);
modifyTarget(win.wrappedJSObject || win, env);
modifyWindowOpenMethod(win, modifyTarget);
modifyFramingElements(win, modifyTarget);
} catch (e) {
@ -89,5 +89,5 @@ function patchWindow(patchingCallback, targetWindow = window) {
Object.defineProperty(wrappedProto, property, descriptor);
}
return modifyWindow(targetWindow, patchingCallback);
return modifyWindow(window, patchingCallback);
}