|
1 | | -if (typeof exportFunction === "function") ns.on("capabilities", event => { |
| 1 | +// depends on nscl/content/patchWindow.js |
| 2 | +"use strict"; |
| 3 | +ns.on("capabilities", event => { |
2 | 4 | debug("WebGL Hook", document.URL, document.documentElement && document.documentElement.innerHTML, ns.capabilities); // DEV_ONLY |
3 | 5 | if (ns.allows("webgl")) return; |
4 | | - |
5 | | - // win: window object to modify. |
6 | | - // modifyTarget: callback to function that modifies the desired properties |
7 | | - // or methods. Callback must take target window as argument. |
8 | | - function modifyWindow(win, modifyTarget) { |
| 6 | + let env = {eventName: `nsWebgl:${uuid()}`}; |
| 7 | + window.addEventListener(env.eventName, e => { |
| 8 | + let canvas = e.target; |
| 9 | + if (!(canvas instanceof HTMLCanvasElement)) return; |
| 10 | + let request = { |
| 11 | + id: "noscript-webgl", |
| 12 | + type: "webgl", |
| 13 | + url: document.URL, |
| 14 | + documentUrl: document.URL, |
| 15 | + embeddingDocument: true, |
| 16 | + }; |
| 17 | + seen.record({policyType: "webgl", request, allowed: false}); |
9 | 18 | try { |
10 | | - modifyTarget(win); |
11 | | - modifyWindowOpenMethod(win, modifyTarget); |
12 | | - modifyFramingElements(win, modifyTarget); |
| 19 | + let ph = PlaceHolder.create("webgl", request); |
| 20 | + ph.replace(canvas); |
| 21 | + PlaceHolder.listen(); |
13 | 22 | } catch (e) { |
14 | | - if (e instanceof DOMException && e.name === "SecurityError") { |
15 | | - // In case someone tries to access SOP restricted window. |
16 | | - // We can just ignore this. |
17 | | - } else throw e; |
| 23 | + error(e); |
18 | 24 | } |
19 | | - } |
20 | | - |
21 | | - function modifyWindowOpenMethod(win, modifyTarget) { |
22 | | - let windowOpen = win.wrappedJSObject ? win.wrappedJSObject.open : win.open; |
23 | | - exportFunction(function(...args) { |
24 | | - let newWin = windowOpen.call(this, ...args); |
25 | | - if (newWin) modifyWindow(newWin, modifyTarget); |
26 | | - return newWin; |
27 | | - }, win, {defineAs: "open"}); |
28 | | - } |
29 | | - |
30 | | - function modifyFramingElements(win, modifyTarget) { |
31 | | - for (let property of ["contentWindow", "contentDocument"]) { |
32 | | - for (let interface of ["Frame", "IFrame", "Object"]) { |
33 | | - let proto = win[`HTML${interface}Element`].prototype; |
34 | | - modifyContentProperties(proto, property, modifyTarget) |
35 | | - } |
36 | | - } |
37 | | - } |
| 25 | + notifyPage(); |
| 26 | + }, true); |
38 | 27 |
|
39 | | - function modifyContentProperties(proto, property, modifyTarget) { |
40 | | - let descriptor = Object.getOwnPropertyDescriptor(proto, property); |
41 | | - let origGetter = descriptor.get; |
42 | | - let replacementFn; |
43 | | - |
44 | | - if (property === "contentWindow") { replacementFn = function() { |
45 | | - let win = origGetter.call(this); |
46 | | - if (win) modifyWindow(win, modifyTarget); |
47 | | - return win; |
48 | | - }} |
49 | | - if (property === "contentDocument") { replacementFn = function() { |
50 | | - let document = origGetter.call(this); |
51 | | - if (document && document.defaultView) modifyWindow(document.defaultView, modifyTarget); |
52 | | - return document; |
53 | | - }} |
54 | | - |
55 | | - descriptor.get = exportFunction(replacementFn, proto, {defineAs: `get $property`}); |
56 | | - let wrappedProto = proto.wrappedJSObject || proto; |
57 | | - Object.defineProperty(wrappedProto, property, descriptor); |
58 | | - } |
59 | | - |
60 | | - // |
61 | | - |
62 | | - function modifyGetContext(win) { |
| 28 | + function modifyGetContext(win, env) { |
63 | 29 | let proto = win.HTMLCanvasElement.prototype; |
64 | 30 | let getContext = proto.getContext; |
65 | 31 | exportFunction(function(type, ...rest) { |
66 | 32 | if (type && type.toLowerCase().includes("webgl")) { |
67 | | - let request = { |
68 | | - id: "noscript-webgl", |
69 | | - type: "webgl", |
70 | | - url: document.URL, |
71 | | - documentUrl: document.URL, |
72 | | - embeddingDocument: true, |
73 | | - }; |
74 | | - seen.record({policyType: "webgl", request, allowed: false}); |
75 | | - try { |
76 | | - let ph = PlaceHolder.create("webgl", request); |
77 | | - ph.replace(this); |
78 | | - PlaceHolder.listen(); |
79 | | - } catch (e) { |
80 | | - error(e); |
81 | | - } |
82 | | - notifyPage(); |
| 33 | + this.dispatchEvent(new Event(env.eventName)); |
83 | 34 | return null; |
84 | 35 | } |
85 | 36 | return getContext.call(this, type, ...rest); |
86 | 37 | }, proto, {defineAs: "getContext"}); |
87 | 38 | } |
88 | 39 |
|
89 | | - modifyWindow(window, modifyGetContext); |
90 | | - |
| 40 | + patchWindow(modifyGetContext, env); |
91 | 41 | }); |
0 commit comments