| Index: lib/content/snippets.js | 
| =================================================================== | 
| --- a/lib/content/snippets.js | 
| +++ b/lib/content/snippets.js | 
| @@ -15,16 +15,60 @@ | 
| * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. | 
| */ | 
| /* eslint-env webextensions */ | 
| /* eslint no-console: "off" */ | 
| "use strict"; | 
| +function regexEscape(s) | 
| +{ | 
| + return s.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&"); | 
| +} | 
| + | 
| +function findProperty(path, root = window) | 
| +{ | 
| + let owner = root; | 
| + | 
| + let chain = path.split("."); | 
| + let property = chain.pop(); | 
| + | 
| + for (let name of chain) | 
| + { | 
| + if (!owner) | 
| + break; | 
| + | 
| + owner = owner[name]; | 
| + } | 
| + | 
| + if (!owner) | 
| + return null; | 
| + | 
| + return {owner, property}; | 
| +} | 
| + | 
| +function injectPropertyAccessValidator(object, property, validate) | 
| +{ | 
| + let value = object[property]; | 
| + | 
| + Object.defineProperty(object, property, { | 
| + get() | 
| + { | 
| + validate(); | 
| + return value; | 
| + }, | 
| + set(newValue) | 
| + { | 
| + validate(); | 
| + value = newValue; | 
| + } | 
| + }); | 
| +} | 
| + | 
| function injectCode(code) | 
| { | 
| let script = document.createElement("script"); | 
| script.type = "application/javascript"; | 
| script.async = false; | 
| // Firefox 58 only bypasses site CSPs when assigning to 'src', | 
| @@ -50,24 +94,80 @@ | 
| return `"use strict";(${func})(${params.map(JSON.stringify).join(",")});`; | 
| } | 
| function makeInjector(injectable) | 
| { | 
| return (...args) => injectCode(stringifyFunctionCall(injectable, ...args)); | 
| } | 
| +function getMagic() | 
| +{ | 
| + return String.fromCharCode(Date.now() % 26 + 97) + | 
| + Math.floor(Math.random() * 982451653 + 982451653).toString(36); | 
| +} | 
| + | 
| +function suppressMagicError(magic) | 
| +{ | 
| + let {onerror} = window; | 
| + window.onerror = function(message, ...rest) | 
| + { | 
| + if (typeof message == "string" && message.includes(magic)) | 
| + return true; | 
| + | 
| + if (typeof onerror instanceof Function) | 
| + return onerror.call(this, message, ...rest); | 
| + }; | 
| +} | 
| + | 
| function log(...args) | 
| { | 
| console.log(...args); | 
| } | 
| exports.log = log; | 
| function uabinjectDefuser() | 
| { | 
| window.trckd = true; | 
| window.uabpdl = true; | 
| window.uabInject = true; | 
| window.uabDetect = true; | 
| } | 
| exports["uabinject-defuser"] = makeInjector(uabinjectDefuser); | 
| + | 
| +function abortCurrentInlineScript(target, needle) | 
| +{ | 
| + if (!target) | 
| + return; | 
| + | 
| + let re = null; | 
| + | 
| + if (needle) | 
| + { | 
| + re = new RegExp(/^\/.+\/$/.test(needle) ? | 
| + needle.slice(1, -1) : | 
| + regexEscape(needle)); | 
| + } | 
| + | 
| + let {owner, property} = findProperty(target) || {}; | 
| + | 
| + let descriptor = Object.getOwnPropertyDescriptor(owner, property); | 
| + if (descriptor && descriptor.get) | 
| + return; | 
| + | 
| + let magic = getMagic(); | 
| + | 
| + injectPropertyAccessValidator(owner, property, () => | 
| + { | 
| + let element = document.currentScript; | 
| + if (element instanceof HTMLScriptElement && | 
| + element.src == "" && (!re || re.test(element.textContent))) | 
| + { | 
| + throw new ReferenceError(magic); | 
| + } | 
| + }); | 
| + | 
| + suppressMagicError(magic); | 
| +} | 
| + | 
| +exports["abort-current-inline-script"] = makeInjector(abortCurrentInlineScript); |