OLD | NEW |
1 /* | 1 /* |
2 * This file is part of Adblock Plus <https://adblockplus.org/>, | 2 * This file is part of Adblock Plus <https://adblockplus.org/>, |
3 * Copyright (C) 2006-present eyeo GmbH | 3 * Copyright (C) 2006-present eyeo GmbH |
4 * | 4 * |
5 * Adblock Plus is free software: you can redistribute it and/or modify | 5 * Adblock Plus is free software: you can redistribute it and/or modify |
6 * it under the terms of the GNU General Public License version 3 as | 6 * it under the terms of the GNU General Public License version 3 as |
7 * published by the Free Software Foundation. | 7 * published by the Free Software Foundation. |
8 * | 8 * |
9 * Adblock Plus is distributed in the hope that it will be useful, | 9 * Adblock Plus is distributed in the hope that it will be useful, |
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
52 { | 52 { |
53 return `"use strict";(${func})(${params.map(JSON.stringify).join(",")});`; | 53 return `"use strict";(${func})(${params.map(JSON.stringify).join(",")});`; |
54 } | 54 } |
55 | 55 |
56 function makeInjector(injectable, ...dependencies) | 56 function makeInjector(injectable, ...dependencies) |
57 { | 57 { |
58 return (...args) => injectCode(stringifyFunctionCall(injectable, ...args), | 58 return (...args) => injectCode(stringifyFunctionCall(injectable, ...args), |
59 dependencies); | 59 dependencies); |
60 } | 60 } |
61 | 61 |
| 62 function regexEscape(s) |
| 63 { |
| 64 return s.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&"); |
| 65 } |
| 66 |
| 67 function findProperty(path, root = window) |
| 68 { |
| 69 let owner = root; |
| 70 |
| 71 let chain = path.split("."); |
| 72 let property = chain.pop(); |
| 73 |
| 74 for (let name of chain) |
| 75 { |
| 76 if (!owner) |
| 77 break; |
| 78 |
| 79 owner = owner[name]; |
| 80 } |
| 81 |
| 82 if (!owner) |
| 83 return null; |
| 84 |
| 85 return {owner, property}; |
| 86 } |
| 87 |
| 88 function injectPropertyAccessValidator(object, property, validate) |
| 89 { |
| 90 let value = object[property]; |
| 91 |
| 92 Object.defineProperty(object, property, { |
| 93 get() |
| 94 { |
| 95 validate(); |
| 96 return value; |
| 97 }, |
| 98 set(newValue) |
| 99 { |
| 100 validate(); |
| 101 value = newValue; |
| 102 } |
| 103 }); |
| 104 } |
| 105 |
| 106 function getMagic() |
| 107 { |
| 108 return String.fromCharCode(Date.now() % 26 + 97) + |
| 109 Math.floor(Math.random() * 982451653 + 982451653).toString(36); |
| 110 } |
| 111 |
| 112 function suppressMagicError(magic) |
| 113 { |
| 114 let {onerror} = window; |
| 115 window.onerror = function(message, ...rest) |
| 116 { |
| 117 if (typeof message == "string" && message.includes(magic)) |
| 118 return true; |
| 119 |
| 120 if (typeof onerror instanceof Function) |
| 121 return onerror.call(this, message, ...rest); |
| 122 }; |
| 123 } |
| 124 |
62 function log(...args) | 125 function log(...args) |
63 { | 126 { |
64 console.log(...args); | 127 console.log(...args); |
65 } | 128 } |
66 | 129 |
67 exports.log = log; | 130 exports.log = log; |
68 | 131 |
69 function trace(...args) | 132 function trace(...args) |
70 { | 133 { |
71 log(...args); | 134 log(...args); |
72 } | 135 } |
73 | 136 |
74 exports.trace = makeInjector(trace, log); | 137 exports.trace = makeInjector(trace, log); |
| 138 |
| 139 // This is an implementation of the abort-current-inline-script technique used |
| 140 // by uBlock Origin |
| 141 // https://github.com/uBlockOrigin/uAssets/blob/68cf8a364fb55deb96264c4e546b58f4
c851d782/filters/resources.txt#L1943 |
| 142 function abortCurrentInlineScript(target, needle) |
| 143 { |
| 144 if (!target) |
| 145 return; |
| 146 |
| 147 let re = null; |
| 148 |
| 149 if (needle) |
| 150 { |
| 151 re = new RegExp(/^\/.+\/$/.test(needle) ? |
| 152 needle.slice(1, -1) : |
| 153 regexEscape(needle)); |
| 154 } |
| 155 |
| 156 let {owner, property} = findProperty(target) || {}; |
| 157 |
| 158 if (!owner) |
| 159 return; |
| 160 |
| 161 let descriptor = Object.getOwnPropertyDescriptor(owner, property); |
| 162 if (descriptor && descriptor.get) |
| 163 return; |
| 164 |
| 165 let magic = getMagic(); |
| 166 |
| 167 injectPropertyAccessValidator(owner, property, () => |
| 168 { |
| 169 let element = document.currentScript; |
| 170 if (element instanceof HTMLScriptElement && |
| 171 element.src == "" && (!re || re.test(element.textContent))) |
| 172 { |
| 173 throw new ReferenceError(magic); |
| 174 } |
| 175 }); |
| 176 |
| 177 suppressMagicError(magic); |
| 178 } |
| 179 |
| 180 exports["abort-current-inline-script"] = |
| 181 makeInjector(abortCurrentInlineScript, regexEscape, findProperty, |
| 182 getMagic, injectPropertyAccessValidator, suppressMagicError); |
OLD | NEW |