Webgl hook refactored on nscl/content/patchWindow.js and made Chromium-compatibile.
This commit is contained in:
parent
ab3eab6e18
commit
9639ea49ac
|
@ -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
|
debug("WebGL Hook", document.URL, document.documentElement && document.documentElement.innerHTML, ns.capabilities); // DEV_ONLY
|
||||||
if (ns.allows("webgl")) return;
|
if (ns.allows("webgl")) return;
|
||||||
|
let env = {eventName: `nsWebgl:${uuid()}`};
|
||||||
// win: window object to modify.
|
window.addEventListener(env.eventName, e => {
|
||||||
// modifyTarget: callback to function that modifies the desired properties
|
let canvas = e.target;
|
||||||
// or methods. Callback must take target window as argument.
|
if (!(canvas instanceof HTMLCanvasElement)) return;
|
||||||
function modifyWindow(win, modifyTarget) {
|
let request = {
|
||||||
|
id: "noscript-webgl",
|
||||||
|
type: "webgl",
|
||||||
|
url: document.URL,
|
||||||
|
documentUrl: document.URL,
|
||||||
|
embeddingDocument: true,
|
||||||
|
};
|
||||||
|
seen.record({policyType: "webgl", request, allowed: false});
|
||||||
try {
|
try {
|
||||||
modifyTarget(win);
|
let ph = PlaceHolder.create("webgl", request);
|
||||||
modifyWindowOpenMethod(win, modifyTarget);
|
ph.replace(canvas);
|
||||||
modifyFramingElements(win, modifyTarget);
|
PlaceHolder.listen();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof DOMException && e.name === "SecurityError") {
|
error(e);
|
||||||
// In case someone tries to access SOP restricted window.
|
|
||||||
// We can just ignore this.
|
|
||||||
} else throw e;
|
|
||||||
}
|
}
|
||||||
}
|
notifyPage();
|
||||||
|
}, true);
|
||||||
|
|
||||||
function modifyWindowOpenMethod(win, modifyTarget) {
|
function modifyGetContext(win, env) {
|
||||||
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) {
|
|
||||||
let proto = win.HTMLCanvasElement.prototype;
|
let proto = win.HTMLCanvasElement.prototype;
|
||||||
let getContext = proto.getContext;
|
let getContext = proto.getContext;
|
||||||
exportFunction(function(type, ...rest) {
|
exportFunction(function(type, ...rest) {
|
||||||
if (type && type.toLowerCase().includes("webgl")) {
|
if (type && type.toLowerCase().includes("webgl")) {
|
||||||
let request = {
|
this.dispatchEvent(new Event(env.eventName));
|
||||||
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();
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return getContext.call(this, type, ...rest);
|
return getContext.call(this, type, ...rest);
|
||||||
}, proto, {defineAs: "getContext"});
|
}, proto, {defineAs: "getContext"});
|
||||||
}
|
}
|
||||||
|
|
||||||
modifyWindow(window, modifyGetContext);
|
patchWindow(modifyGetContext, env);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
function patchWindow(patchingCallback, targetWindow = window) {
|
function patchWindow(patchingCallback, env = {}) {
|
||||||
let nativeExport = this && this.exportFunction || typeof exportFunction == "function";
|
let nativeExport = this && this.exportFunction || typeof exportFunction == "function";
|
||||||
if (!nativeExport) {
|
if (!nativeExport) {
|
||||||
// Chromium
|
// Chromium
|
||||||
|
@ -26,7 +26,7 @@ function patchWindow(patchingCallback, targetWindow = window) {
|
||||||
patchWindow,
|
patchWindow,
|
||||||
exportFunction,
|
exportFunction,
|
||||||
cloneInto,
|
cloneInto,
|
||||||
}).patchWindow(${patchingCallback});
|
}).patchWindow(${patchingCallback}, ${JSON.stringify(env)});
|
||||||
})();
|
})();
|
||||||
`;
|
`;
|
||||||
document.documentElement.insertBefore(script, document.documentElement.firstChild);
|
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.
|
// or methods. Callback must take target window as argument.
|
||||||
function modifyWindow(win, modifyTarget) {
|
function modifyWindow(win, modifyTarget) {
|
||||||
try {
|
try {
|
||||||
modifyTarget(win.wrappedJSObject || win);
|
modifyTarget(win.wrappedJSObject || win, env);
|
||||||
modifyWindowOpenMethod(win, modifyTarget);
|
modifyWindowOpenMethod(win, modifyTarget);
|
||||||
modifyFramingElements(win, modifyTarget);
|
modifyFramingElements(win, modifyTarget);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -88,6 +88,6 @@ function patchWindow(patchingCallback, targetWindow = window) {
|
||||||
let wrappedProto = proto.wrappedJSObject || proto;
|
let wrappedProto = proto.wrappedJSObject || proto;
|
||||||
Object.defineProperty(wrappedProto, property, descriptor);
|
Object.defineProperty(wrappedProto, property, descriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
return modifyWindow(targetWindow, patchingCallback);
|
return modifyWindow(window, patchingCallback);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue