From cfeac10c952f6bcde420ba486065a138353b29c2 Mon Sep 17 00:00:00 2001 From: Raymond Hill Date: Tue, 20 Sep 2022 08:49:52 -0400 Subject: [PATCH] [mv3] Add support for abort-on-property-read scriptlet --- .../mv3/scriptlets/abort-on-property-read.js | 132 ++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 platform/mv3/scriptlets/abort-on-property-read.js diff --git a/platform/mv3/scriptlets/abort-on-property-read.js b/platform/mv3/scriptlets/abort-on-property-read.js new file mode 100644 index 000000000..0753fffe6 --- /dev/null +++ b/platform/mv3/scriptlets/abort-on-property-read.js @@ -0,0 +1,132 @@ +/******************************************************************************* + + uBlock Origin - a browser extension to block requests. + Copyright (C) 2019-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock + + The scriptlets below are meant to be injected only into a + web page context. +*/ + +/* jshint esversion:11 */ + +'use strict'; + +/******************************************************************************/ + +/// name abort-on-property-read +/// alias aopr + +/******************************************************************************/ + +// Important! +// Isolate from global scope +(function() { + +/******************************************************************************/ + +const ObjGetOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; +const ObjDefineProperty = Object.defineProperty; + +const magic = + String.fromCharCode(Date.now() % 26 + 97) + + Math.floor(Math.random() * 982451653 + 982451653).toString(36); + +const abort = function() { + throw new ReferenceError(magic); +}; + +const makeProxy = function(owner, chain) { + const pos = chain.indexOf('.'); + if ( pos === -1 ) { + const desc = ObjGetOwnPropertyDescriptor(owner, chain); + if ( !desc || desc.get !== abort ) { + ObjDefineProperty(owner, chain, { + get: abort, + set: function(){} + }); + } + return; + } + + const prop = chain.slice(0, pos); + let v = owner[prop]; + chain = chain.slice(pos + 1); + if ( v ) { + makeProxy(v, chain); + return; + } + + const desc = ObjGetOwnPropertyDescriptor(owner, prop); + if ( desc && desc.set !== undefined ) { return; } + + ObjDefineProperty(owner, prop, { + get: function() { return v; }, + set: function(a) { + v = a; + if ( a instanceof Object ) { + makeProxy(a, chain); + } + } + }); +}; + +const scriptlet = ( + chain = '' +) => { + const owner = window; + makeProxy(owner, chain); + const oe = window.onerror; + window.onerror = function(msg, src, line, col, error) { + if ( typeof msg === 'string' && msg.indexOf(magic) !== -1 ) { + return true; + } + if ( oe instanceof Function ) { + return oe(msg, src, line, col, error); + } + }.bind(); +}; + +/******************************************************************************/ + +const argsMap = new Map(self.$argsMap$); + +const hostnamesMap = new Map(self.$hostnamesMap$); + +let hn; +try { hn = document.location.hostname; } catch(ex) { } +while ( hn ) { + if ( hostnamesMap.has(hn) ) { + let argsHashes = hostnamesMap.get(hn); + if ( typeof argsHashes === 'number' ) { argsHashes = [ argsHashes ]; } + for ( const argsHash of argsHashes ) { + const details = argsMap.get(argsHash); + if ( details.n && details.n.includes(hn) ) { continue; } + try { scriptlet(...details.a); } catch(ex) {} + } + } + const pos = hn.indexOf('.'); + if ( pos === -1 ) { break; } + hn = hn.slice(pos + 1); +} + +/******************************************************************************/ + +})(); + +/******************************************************************************/ +