From 1ff3878a4920e31791547238e3e879a32357914f Mon Sep 17 00:00:00 2001 From: Raymond Hill Date: Thu, 28 Sep 2023 11:26:45 -0400 Subject: [PATCH] Add `prevent-canvas` scriptlet Prevent usage of specific or all (default) canvas APIs. Syntax ```text example.com##+js(prevent-canvas [, contextType]) ``` - `contextType`: A specific type of canvas API to prevent (default to all APIs). Can be a string or regex which will be matched against the type used in getContext() call. Prepend with `!` to test for no-match. Examples 1. Prevent `example.com` from accessing all canvas APIs ```adblock example.com##+js(prevent-canvas) ``` 2. Prevent access to any flavor of WebGL API, everywhere ```adblock *##+js(prevent-canvas, /webgl/) ``` 3. Prevent `example.com` from accessing any flavor of canvas API except `2d` ```adblock example.com##+js(prevent-canvas, !2d) ``` References https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/getContext --- assets/resources/scriptlets.js | 66 +++++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/assets/resources/scriptlets.js b/assets/resources/scriptlets.js index 3393e2484..e22b8950e 100644 --- a/assets/resources/scriptlets.js +++ b/assets/resources/scriptlets.js @@ -68,7 +68,7 @@ function safeSelf() { if ( pattern === '' ) { return { matchAll: true }; } - const expect = (options.canNegate === true && pattern.startsWith('!') === false); + const expect = (options.canNegate !== true || pattern.startsWith('!') === false); if ( expect === false ) { pattern = pattern.slice(1); } @@ -3388,6 +3388,70 @@ function setAttr( runAt(( ) => { start(); }, 'idle'); } +/******************************************************************************* + * + * @scriptlet prevent-canvas + * + * @description + * Prevent usage of specific or all (default) canvas APIs. + * + * ### Syntax + * + * ```text + * example.com##+js(prevent-canvas [, contextType]) + * ``` + * + * - `contextType`: A specific type of canvas API to prevent (default to all + * APIs). Can be a string or regex which will be matched against the type + * used in getContext() call. Prepend with `!` to test for no-match. + * + * ### Examples + * + * 1. Prevent `example.com` from accessing all canvas APIs + * + * ```adblock + * example.com##+js(prevent-canvas) + * ``` + * + * 2. Prevent access to any flavor of WebGL API, everywhere + * + * ```adblock + * *##+js(prevent-canvas, /webgl/) + * ``` + * + * 3. Prevent `example.com` from accessing any flavor of canvas API except `2d` + * + * ```adblock + * example.com##+js(prevent-canvas, !2d) + * ``` + * + * ### References + * + * https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/getContext + * + * */ + +builtinScriptlets.push({ + name: 'prevent-canvas.js', + fn: preventCanvas, + dependencies: [ + 'safe-self.fn', + ], +}); +function preventCanvas( + contextType = '' +) { + const safe = safeSelf(); + const pattern = safe.initPattern(contextType, { canNegate: true }); + const proto = globalThis.HTMLCanvasElement.prototype; + proto.getContext = new Proxy(proto.getContext, { + apply(target, thisArg, args) { + if ( safe.testPattern(pattern, args[0]) ) { return null; } + return Reflect.apply(target, thisArg, args); + } + }); +} + /******************************************************************************* *