/******************************************************************************* 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 json-prune /******************************************************************************/ // Important! // Isolate from global scope (function() { /******************************************************************************/ // https://github.com/uBlockOrigin/uBlock-issues/issues/1545 // - Add support for "remove everything if needle matches" case const scriptlet = ( rawPrunePaths = '', rawNeedlePaths = '' ) => { const prunePaths = rawPrunePaths !== '' ? rawPrunePaths.split(/ +/) : []; let needlePaths; if ( prunePaths.length === 0 ) { return; } needlePaths = prunePaths.length !== 0 && rawNeedlePaths !== '' ? rawNeedlePaths.split(/ +/) : []; const findOwner = function(root, path, prune = false) { let owner = root; let chain = path; for (;;) { if ( typeof owner !== 'object' || owner === null ) { return false; } const pos = chain.indexOf('.'); if ( pos === -1 ) { if ( prune === false ) { return owner.hasOwnProperty(chain); } if ( chain === '*' ) { for ( const key in owner ) { if ( owner.hasOwnProperty(key) === false ) { continue; } delete owner[key]; } } else if ( owner.hasOwnProperty(chain) ) { delete owner[chain]; } return true; } const prop = chain.slice(0, pos); if ( prop === '[]' && Array.isArray(owner) || prop === '*' && owner instanceof Object ) { const next = chain.slice(pos + 1); let found = false; for ( const key of Object.keys(owner) ) { found = findOwner(owner[key], next, prune) || found; } return found; } if ( owner.hasOwnProperty(prop) === false ) { return false; } owner = owner[prop]; chain = chain.slice(pos + 1); } }; const mustProcess = function(root) { for ( const needlePath of needlePaths ) { if ( findOwner(root, needlePath) === false ) { return false; } } return true; }; const pruner = function(o) { if ( mustProcess(o) === false ) { return o; } for ( const path of prunePaths ) { findOwner(o, path, true); } return o; }; JSON.parse = new Proxy(JSON.parse, { apply: function() { return pruner(Reflect.apply(...arguments)); }, }); Response.prototype.json = new Proxy(Response.prototype.json, { apply: function() { return Reflect.apply(...arguments).then(o => pruner(o)); }, }); }; /******************************************************************************/ 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); } /******************************************************************************/ })(); /******************************************************************************/