diff --git a/assets/assets.json b/assets/assets.json index 6b6256fdc..4d58991b7 100644 --- a/assets/assets.json +++ b/assets/assets.json @@ -19,10 +19,7 @@ "ublock-resources": { "content": "internal", "updateAfter": 7, - "contentURL": [ - "https://raw.githubusercontent.com/uBlockOrigin/uAssets/master/filters/resources.txt", - "assets/ublock/resources.txt" - ] + "contentURL": "assets/ublock/resources.txt" }, "ublock-filters": { "content": "filters", diff --git a/assets/resources/scriptlets.js b/assets/resources/scriptlets.js new file mode 100644 index 000000000..e688b8dde --- /dev/null +++ b/assets/resources/scriptlets.js @@ -0,0 +1,975 @@ +/******************************************************************************* + + 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. +*/ + + +/// abort-current-inline-script.js +/// alias acis.js +(function() { + 'use strict'; + const target = '{{1}}'; + if ( target === '' || target === '{{1}}' ) { return; } + const needle = '{{2}}'; + let reText = '.?'; + if ( needle !== '' && needle !== '{{2}}' ) { + reText = /^\/.+\/$/.test(needle) + ? needle.slice(1,-1) + : needle.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + } + const thisScript = document.currentScript; + const re = new RegExp(reText); + const chain = target.split('.'); + let owner = window; + let prop; + for (;;) { + prop = chain.shift(); + if ( chain.length === 0 ) { break; } + owner = owner[prop]; + if ( owner instanceof Object === false ) { return; } + } + const desc = Object.getOwnPropertyDescriptor(owner, prop); + if ( desc && desc.get !== undefined ) { return; } + const magic = String.fromCharCode(Date.now() % 26 + 97) + + Math.floor(Math.random() * 982451653 + 982451653).toString(36); + let value = owner[prop]; + const validate = function() { + const e = document.currentScript; + if ( + e instanceof HTMLScriptElement && + e.src === '' && + e !== thisScript && + re.test(e.textContent) + ) { + throw new ReferenceError(magic); + } + }; + Object.defineProperty(owner, prop, { + get: function() { + validate(); + return value; + }, + set: function(a) { + validate(); + value = a; + } + }); + const oe = window.onerror; + window.onerror = function(msg) { + if ( typeof msg === 'string' && msg.indexOf(magic) !== -1 ) { + return true; + } + if ( oe instanceof Function ) { + return oe.apply(this, arguments); + } + }.bind(); +})(); + + +/// abort-on-property-read.js +/// alias aopr.js +(function() { + 'use strict'; + 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 = Object.getOwnPropertyDescriptor(owner, chain); + if ( !desc || desc.get !== abort ) { + Object.defineProperty(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 = Object.getOwnPropertyDescriptor(owner, prop); + if ( desc && desc.set !== undefined ) { return; } + Object.defineProperty(owner, prop, { + get: function() { return v; }, + set: function(a) { + v = a; + if ( a instanceof Object ) { + makeProxy(a, chain); + } + } + }); + }; + const owner = window; + let chain = '{{1}}'; + 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(); +})(); + + +/// abort-on-property-write.js +/// alias aopw.js +(function() { + 'use strict'; + const magic = String.fromCharCode(Date.now() % 26 + 97) + + Math.floor(Math.random() * 982451653 + 982451653).toString(36); + let prop = '{{1}}'; + let owner = window; + for (;;) { + const pos = prop.indexOf('.'); + if ( pos === -1 ) { break; } + owner = owner[prop.slice(0, pos)]; + if ( owner instanceof Object === false ) { return; } + prop = prop.slice(pos + 1); + } + delete owner[prop]; + Object.defineProperty(owner, prop, { + set: function() { + throw new ReferenceError(magic); + } + }); + 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(); +})(); + + +/// addEventListener-defuser.js +/// alias aeld.js +(function() { + 'use strict'; + let needle1 = '{{1}}'; + if ( needle1 === '' || needle1 === '{{1}}' ) { + needle1 = '.?'; + } else if ( /^\/.+\/$/.test(needle1) ) { + needle1 = needle1.slice(1,-1); + } else { + needle1 = needle1.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + } + needle1 = new RegExp(needle1); + let needle2 = '{{2}}'; + if ( needle2 === '' || needle2 === '{{2}}' ) { + needle2 = '.?'; + } else if ( /^\/.+\/$/.test(needle2) ) { + needle2 = needle2.slice(1,-1); + } else { + needle2 = needle2.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + } + needle2 = new RegExp(needle2); + self.EventTarget.prototype.addEventListener = new Proxy( + self.EventTarget.prototype.addEventListener, + { + apply: function(target, thisArg, args) { + const type = args[0].toString(); + const handler = String(args[1]); + if ( + needle1.test(type) === false || + needle2.test(handler) === false + ) { + return target.apply(thisArg, args); + } + } + } + ); +})(); + + +/// addEventListener-logger.js +/// alias aell.js +(function() { + 'use strict'; + const log = console.log.bind(console); + self.EventTarget.prototype.addEventListener = new Proxy( + self.EventTarget.prototype.addEventListener, + { + apply: function(target, thisArg, args) { + const type = args[0].toString(); + const handler = String(args[1]); + log('addEventListener("%s", %s)', type, handler); + return target.apply(thisArg, args); + } + } + ); +})(); + + +/// nano-setInterval-booster.js +/// alias nano-sib.js +(function() { + 'use strict'; + let needle = '{{1}}'; + let delay = parseInt('{{2}}', 10); + let boost = parseFloat('{{3}}'); + if ( needle === '' || needle === '{{1}}' ) { + needle = '.?'; + } else if ( needle.charAt(0) === '/' && needle.slice(-1) === '/' ) { + needle = needle.slice(1, -1); + } else { + needle = needle.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + } + needle = new RegExp(needle); + if ( isNaN(delay) || !isFinite(delay) ) { + delay = 1000; + } + if ( isNaN(boost) || !isFinite(boost) ) { + boost = 0.05; + } + if ( boost < 0.02 ) { + boost = 0.02; + } + if ( boost > 50 ) { + boost = 50; + } + window.setInterval = new Proxy(window.setInterval, { + apply: function(target, thisArg, args) { + const a = args[0]; + const b = args[1]; + if ( b === delay && needle.test(a.toString()) ) { + args[1] = b * boost; + } + return target.apply(thisArg, args); + } + }); +})(); + + +/// nano-setTimeout-booster.js +/// alias nano-stb.js +(function() { + 'use strict'; + let needle = '{{1}}'; + let delay = parseInt('{{2}}', 10); + let boost = parseFloat('{{3}}'); + if ( needle === '' || needle === '{{1}}' ) { + needle = '.?'; + } else if ( needle.startsWith('/') && needle.endsWith('/') ) { + needle = needle.slice(1, -1); + } else { + needle = needle.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + } + needle = new RegExp(needle); + if ( isNaN(delay) || !isFinite(delay) ) { + delay = 1000; + } + if ( isNaN(boost) || !isFinite(boost) ) { + boost = 0.05; + } + if ( boost < 0.02 ) { + boost = 0.02; + } + if ( boost > 50 ) { + boost = 50; + } + window.setTimeout = new Proxy(window.setTimeout, { + apply: function(target, thisArg, args) { + const a = args[0]; + const b = args[1]; + if ( b === delay && needle.test(a.toString()) ) { + args[1] = b * boost; + } + return target.apply(thisArg, args); + } + }); +})(); + + +/// noeval-if.js +(function() { + 'use strict'; + let needle = '{{1}}'; + if ( needle === '' || needle === '{{1}}' ) { + needle = '.?'; + } else if ( needle.slice(0,1) === '/' && needle.slice(-1) === '/' ) { + needle = needle.slice(1,-1); + } else { + needle = needle.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + } + needle = new RegExp(needle); + window.eval = new Proxy(window.eval, { // jshint ignore: line + apply: function(target, thisArg, args) { + const a = args[0]; + if ( needle.test(a.toString()) === false ) { + return target.apply(thisArg, args); + } + } + }); +})(); + + +/// remove-attr.js +/// alias ra.js +(function() { + 'use strict'; + const token = '{{1}}'; + if ( token === '' || token === '{{1}}' ) { return; } + const tokens = token.split(/\s*\|\s*/); + let selector = '{{2}}'; + if ( selector === '' || selector === '{{2}}' ) { + selector = `[${tokens.join('],[')}]`; + } + const rmattr = function(ev) { + if ( ev ) { + window.removeEventListener(ev.type, rmattr, true); + } + try { + const nodes = document.querySelectorAll(selector); + for ( const node of nodes ) { + for ( const attr of tokens ) { + node.removeAttribute(attr); + } + } + } catch(ex) { + } + }; + if ( document.readyState === 'loading' ) { + window.addEventListener('DOMContentLoaded', rmattr, true); + } else { + rmattr(); + } +})(); + + +/// set-constant.js +(function() { + 'use strict'; + const thisScript = document.currentScript; + let cValue = '{{2}}'; + if ( cValue === 'undefined' ) { + cValue = undefined; + } else if ( cValue === 'false' ) { + cValue = false; + } else if ( cValue === 'true' ) { + cValue = true; + } else if ( cValue === 'null' ) { + cValue = null; + } else if ( cValue === 'noopFunc' ) { + cValue = function(){}; + } else if ( cValue === 'trueFunc' ) { + cValue = function(){ return true; }; + } else if ( cValue === 'falseFunc' ) { + cValue = function(){ return false; }; + } else if ( /^\d+$/.test(cValue) ) { + cValue = parseFloat(cValue); + if ( isNaN(cValue) ) { return; } + if ( Math.abs(cValue) > 0x7FFF ) { return; } + } else if ( cValue === "''" ) { + cValue = ''; + } else { + return; + } + let aborted = false; + const mustAbort = function(v) { + if ( aborted ) { return true; } + aborted = v !== undefined && cValue !== undefined && typeof v !== typeof cValue; + return aborted; + }; + const makeProxy = function(owner, chain) { + const pos = chain.indexOf('.'); + if ( pos === -1 ) { + const original = owner[chain]; + if ( mustAbort(original) ) { return; } + const desc = Object.getOwnPropertyDescriptor(owner, chain); + if ( desc === undefined || desc.get === undefined ) { + Object.defineProperty(owner, chain, { + get: function() { + return document.currentScript === thisScript + ? original + : cValue; + }, + set: function(a) { + if ( mustAbort(a) ) { + cValue = a; + } + } + }); + } + return; + } + const prop = chain.slice(0, pos); + let v = owner[prop]; + chain = chain.slice(pos + 1); + if ( v !== undefined ) { + makeProxy(v, chain); + return; + } + const desc = Object.getOwnPropertyDescriptor(owner, prop); + if ( desc && desc.set !== undefined ) { return; } + Object.defineProperty(owner, prop, { + get: function() { + return v; + }, + set: function(a) { + v = a; + if ( a instanceof Object ) { + makeProxy(a, chain); + } + } + }); + }; + makeProxy(window, '{{1}}'); +})(); + + +/// setInterval-defuser.js +/// alias sid.js +(function() { + 'use strict'; + let needle = '{{1}}'; + const delay = parseInt('{{2}}', 10); + if ( needle === '' || needle === '{{1}}' ) { + needle = '.?'; + } else if ( needle.startsWith('/') && needle.endsWith('/') ) { + needle = needle.slice(1,-1); + } else { + needle = needle.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + } + needle = new RegExp(needle); + window.setInterval = new Proxy(window.setInterval, { + apply: function(target, thisArg, args) { + const a = args[0]; + const b = args[1]; + if ( (isNaN(delay) || b === delay) && needle.test(a.toString()) ) { + args[0] = function(){}; + } + return target.apply(thisArg, args); + } + }); +})(); + + +/// setInterval-logger.js +/// alias sil.js +(function() { + 'use strict'; + const log = console.log.bind(console); + window.setInterval = new Proxy(window.setInterval, { + apply: function(target, thisArg, args) { + const a = args[0]; + const b = args[1]; + log('uBO: setInterval("%s", %s)', a.toString(), b); + return target.apply(thisArg, args); + } + }); +})(); + + +/// setTimeout-defuser.js +/// alias std.js +(function() { + 'use strict'; + let needle = '{{1}}'; + const delay = parseInt('{{2}}', 10); + if ( needle === '' || needle === '{{1}}' ) { + needle = '.?'; + } else if ( needle.startsWith('/') && needle.endsWith('/') ) { + needle = needle.slice(1,-1); + } else { + needle = needle.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + } + needle = new RegExp(needle); + window.setTimeout = new Proxy(window.setTimeout, { + apply: function(target, thisArg, args) { + const a = args[0]; + const b = args[1]; + if ( (isNaN(delay) || b === delay) && needle.test(a.toString()) ) { + args[0] = function(){}; + } + return target.apply(thisArg, args); + } + }); +})(); + + +/// setTimeout-logger.js +/// alias stl.js +(function() { + 'use strict'; + const log = console.log.bind(console); + window.setTimeout = new Proxy(window.setTimeout, { + apply: function(target, thisArg, args) { + const a = args[0]; + const b = args[1]; + log('uBO: setTimeout("%s", %s)', a.toString(), b); + return target.apply(thisArg, args); + } + }); +})(); + + +/// webrtc-if.js +(function() { + 'use strict'; + let good = '{{1}}'; + if ( good.startsWith('/') && good.endsWith('/') ) { + good = good.slice(1, -1); + } else { + good = good.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + } + let reGood; + try { + reGood = new RegExp(good); + } catch(ex) { + return; + } + const rtcName = window.RTCPeerConnection + ? 'RTCPeerConnection' + : (window.webkitRTCPeerConnection ? 'webkitRTCPeerConnection' : ''); + if ( rtcName === '' ) { return; } + const log = console.log.bind(console); + const neuteredPeerConnections = new WeakSet(); + const isGoodConfig = function(instance, config) { + if ( neuteredPeerConnections.has(instance) ) { return false; } + if ( config instanceof Object === false ) { return true; } + if ( Array.isArray(config.iceServers) === false ) { return true; } + for ( const server of config.iceServers ) { + const urls = typeof server.urls === 'string' + ? [ server.urls ] + : server.urls; + if ( Array.isArray(urls) ) { + for ( const url of urls ) { + if ( reGood.test(url) ) { return true; } + } + } + if ( typeof server.username === 'string' ) { + if ( reGood.test(server.username) ) { return true; } + } + if ( typeof server.credential === 'string' ) { + if ( reGood.test(server.credential) ) { return true; } + } + } + neuteredPeerConnections.add(instance); + return false; + }; + const peerConnectionCtor = window[rtcName]; + const peerConnectionProto = peerConnectionCtor.prototype; + peerConnectionProto.createDataChannel = + new Proxy(peerConnectionProto.createDataChannel, { + apply: function(target, thisArg, args) { + if ( isGoodConfig(target, args[1]) === false ) { + log(args[1]); + return target.apply(thisArg, args.slice(0, 1)); + } + return target.apply(thisArg, args); + }, + }); + window[rtcName] = + new Proxy(peerConnectionCtor, { + construct: function(target, args) { + if ( isGoodConfig(target, args[0]) === false ) { + log(args[0]); + return new target(); + } + return new target(...args); + } + }); +})(); + + +// https://github.com/gorhill/uBlock/issues/1228 +/// window.name-defuser +(function() { + 'use strict'; + if ( window === window.top ) { + window.name = ''; + } +})(); + + +// Experimental: Generic nuisance overlay buster. +// if this works well and proves to be useful, this may end up +// as a stock tool in uBO's popup panel. +/// overlay-buster.js +(function() { + 'use strict'; + if ( window !== window.top ) { + return; + } + var tstart; + var ttl = 30000; + var delay = 0; + var delayStep = 50; + var buster = function() { + var docEl = document.documentElement, + bodyEl = document.body, + vw = Math.min(docEl.clientWidth, window.innerWidth), + vh = Math.min(docEl.clientHeight, window.innerHeight), + tol = Math.min(vw, vh) * 0.05, + el = document.elementFromPoint(vw/2, vh/2), + style, rect; + for (;;) { + if ( el === null || el.parentNode === null || el === bodyEl ) { + break; + } + style = window.getComputedStyle(el); + if ( parseInt(style.zIndex, 10) >= 1000 || style.position === 'fixed' ) { + rect = el.getBoundingClientRect(); + if ( rect.left <= tol && rect.top <= tol && (vw - rect.right) <= tol && (vh - rect.bottom) < tol ) { + el.parentNode.removeChild(el); + tstart = Date.now(); + el = document.elementFromPoint(vw/2, vh/2); + bodyEl.style.setProperty('overflow', 'auto', 'important'); + docEl.style.setProperty('overflow', 'auto', 'important'); + continue; + } + } + el = el.parentNode; + } + if ( (Date.now() - tstart) < ttl ) { + delay = Math.min(delay + delayStep, 1000); + setTimeout(buster, delay); + } + }; + var domReady = function(ev) { + if ( ev ) { + document.removeEventListener(ev.type, domReady); + } + tstart = Date.now(); + setTimeout(buster, delay); + }; + if ( document.readyState === 'loading' ) { + document.addEventListener('DOMContentLoaded', domReady); + } else { + domReady(); + } +})(); + + +// https://github.com/uBlockOrigin/uAssets/issues/8 +/// alert-buster.js +(function() { + 'use strict'; + window.alert = function(a) { + console.info(a); + }; +})(); + + +// https://github.com/uBlockOrigin/uAssets/issues/58 +/// gpt-defuser.js application/javascript +(function() { + 'use strict'; + const noopfn = function() { + }; + let props = '_resetGPT resetGPT resetAndLoadGPTRecovery _resetAndLoadGPTRecovery setupGPT setupGPTuo'; + props = props.split(/\s+/); + while ( props.length ) { + var prop = props.pop(); + if ( typeof window[prop] === 'function' ) { + window[prop] = noopfn; + } else { + Object.defineProperty(window, prop, { + get: function() { return noopfn; }, + set: noopfn + }); + } + } +})(); + + +// Prevent web pages from using RTCPeerConnection(), and report attempts in console. +/// nowebrtc.js +(function() { + 'use strict'; + var rtcName = window.RTCPeerConnection ? 'RTCPeerConnection' : ( + window.webkitRTCPeerConnection ? 'webkitRTCPeerConnection' : '' + ); + if ( rtcName === '' ) { return; } + var log = console.log.bind(console); + var pc = function(cfg) { + log('Document tried to create an RTCPeerConnection: %o', cfg); + }; + const noop = function() { + }; + pc.prototype = { + close: noop, + createDataChannel: noop, + createOffer: noop, + setRemoteDescription: noop, + toString: function() { + return '[object RTCPeerConnection]'; + } + }; + var z = window[rtcName]; + window[rtcName] = pc.bind(window); + if ( z.prototype ) { + z.prototype.createDataChannel = function() { + return { + close: function() {}, + send: function() {} + }; + }.bind(null); + } +})(); + + +// https://github.com/uBlockOrigin/uAssets/issues/88 +/// golem.de.js +(function() { + 'use strict'; + const rael = window.addEventListener; + window.addEventListener = function(a, b) { + rael(...arguments); + let haystack; + try { + haystack = b.toString(); + } catch(ex) { + } + if ( + typeof haystack === 'string' && + /^\s*function\s*\(\)\s*\{\s*window\.clearTimeout\(r\)\s*\}\s*$/.test(haystack) + ) { + b(); + } + }.bind(window); +})(); + + +// https://forums.lanik.us/viewtopic.php?f=64&t=32278 +// https://www.reddit.com/r/chrome/comments/58eix6/ublock_origin_not_working_on_certain_sites/ +/// upmanager-defuser.js +(function() { + 'use strict'; + var onerror = window.onerror; + window.onerror = function(msg, source, lineno, colno, error) { + if ( typeof msg === 'string' && msg.indexOf('upManager') !== -1 ) { + return true; + } + if ( onerror instanceof Function ) { + onerror.call(window, msg, source, lineno, colno, error); + } + }; + Object.defineProperty(window, 'upManager', { value: function() {} }); +})(); + + +// https://github.com/uBlockOrigin/uAssets/issues/110 +/// smartadserver.com.js +(function() { + 'use strict'; + Object.defineProperties(window, { + SmartAdObject: { value: function(){} }, + SmartAdServerAjax: { value: function(){} }, + smartAd: { value: { LoadAds: function() {}, Register: function() {} } } + }); +})(); + + +// https://github.com/reek/anti-adblock-killer/issues/3774#issuecomment-348536138 +// https://github.com/uBlockOrigin/uAssets/issues/883 +/// adfly-defuser.js +(function() { + 'use strict'; + // Based on AdsBypasser + // License: + // https://github.com/adsbypasser/adsbypasser/blob/master/LICENSE + var isDigit = /^\d$/; + var handler = function(encodedURL) { + var var1 = "", var2 = "", i; + for (i = 0; i < encodedURL.length; i++) { + if (i % 2 === 0) { + var1 = var1 + encodedURL.charAt(i); + } else { + var2 = encodedURL.charAt(i) + var2; + } + } + var data = (var1 + var2).split(""); + for (i = 0; i < data.length; i++) { + if (isDigit.test(data[i])) { + for (var ii = i + 1; ii < data.length; ii++) { + if (isDigit.test(data[ii])) { + var temp = parseInt(data[i],10) ^ parseInt(data[ii],10); + if (temp < 10) { + data[i] = temp.toString(); + } + i = ii; + break; + } + } + } + } + data = data.join(""); + var decodedURL = window.atob(data).slice(16, -16); + window.stop(); + window.onbeforeunload = null; + window.location.href = decodedURL; + }; + try { + var val; + var flag = true; + window.Object.defineProperty(window, "ysmm", { + configurable: false, + set: function(value) { + if (flag) { + flag = false; + try { + if (typeof value === "string") { + handler(value); + } + } catch (err) { } + } + val = value; + }, + get: function() { + return val; + } + }); + } catch (err) { + window.console.error("Failed to set up Adfly bypasser!"); + } +})(); + + +// https://github.com/uBlockOrigin/uAssets/issues/913 +/// disable-newtab-links.js +(function() { + 'use strict'; + document.addEventListener('click', function(ev) { + var target = ev.target; + while ( target !== null ) { + if ( target.localName === 'a' && target.hasAttribute('target') ) { + ev.stopPropagation(); + ev.preventDefault(); + break; + } + target = target.parentNode; + } + }); +})(); + + +/// damoh-defuser.js +(function() { + 'use strict'; + var handled = new WeakSet(); + var asyncTimer; + var cleanVideo = function() { + asyncTimer = undefined; + var v = document.querySelector('video'); + if ( v === null ) { return; } + if ( handled.has(v) ) { return; } + handled.add(v); + v.pause(); + v.controls = true; + var el = v.querySelector('meta[itemprop="contentURL"][content]'); + if ( el === null ) { return; } + v.src = el.getAttribute('content'); + el = v.querySelector('meta[itemprop="thumbnailUrl"][content]'); + if ( el !== null ) { v.poster = el.getAttribute('content'); } + }; + var cleanVideoAsync = function() { + if ( asyncTimer !== undefined ) { return; } + asyncTimer = window.requestAnimationFrame(cleanVideo); + }; + var observer = new MutationObserver(cleanVideoAsync); + observer.observe(document.documentElement, { childList: true, subtree: true }); +})(); + + +// https://github.com/uBlockOrigin/uAssets/pull/3517 +/// twitch-videoad.js +(function() { + 'use strict'; + if ( /(^|\.)twitch\.tv$/.test(document.location.hostname) === false ) { return; } + var realFetch = window.fetch; + window.fetch = function(input) { + if ( arguments.length >= 2 && typeof input === 'string' && input.includes('/access_token') ) { + var url = new URL(arguments[0]); + url.searchParams.set('platform', '_'); + arguments[0] = url.href; + } + return realFetch.apply(this, arguments); + }; +})(); + + +// https://github.com/uBlockOrigin/uAssets/issues/2912 +/// fingerprint2.js +(function() { + 'use strict'; + let fp2 = function(){}; + fp2.prototype = { + get: function(cb) { + setTimeout(function() { cb('', []); }, 1); + } + }; + window.Fingerprint2 = fp2; +})(); + + +// https://github.com/NanoAdblocker/NanoFilters/issues/149 +/// cookie-remover.js +(function() { + 'use strict'; + let needle = '{{1}}', + reName = /./; + if ( /^\/.+\/$/.test(needle) ) { + reName = new RegExp(needle.slice(1,-1)); + } else if ( needle !== '' && needle !== '{{1}}' ) { + reName = new RegExp(needle.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')); + } + let removeCookie = function() { + document.cookie.split(';').forEach(cookieStr => { + let pos = cookieStr.indexOf('='); + if ( pos === -1 ) { return; } + let cookieName = cookieStr.slice(0, pos).trim(); + if ( !reName.test(cookieName) ) { return; } + let part1 = cookieName + '='; + let part2a = '; domain=' + document.location.hostname; + let part2b = '; domain=.' + document.location.hostname; + let domain = document.domain; + let part2c = domain && domain !== document.location.hostname ? '; domain=.' + domain : undefined; + let part3 = '; path=/'; + let part4 = '; Max-Age=-1000; expires=Thu, 01 Jan 1970 00:00:00 GMT'; + document.cookie = part1 + part4; + document.cookie = part1 + part2a + part4; + document.cookie = part1 + part2b + part4; + document.cookie = part1 + part3 + part4; + document.cookie = part1 + part2a + part3 + part4; + document.cookie = part1 + part2b + part3 + part4; + if ( part2c !== undefined ) { + document.cookie = part1 + part2c + part3 + part4; + } + }); + }; + removeCookie(); + window.addEventListener('beforeunload', removeCookie); +})(); diff --git a/src/js/messaging.js b/src/js/messaging.js index c196980f6..a08a23db3 100644 --- a/src/js/messaging.js +++ b/src/js/messaging.js @@ -1094,11 +1094,6 @@ const onMessage = function(request, sender, callback) { case 'purgeCache': µb.assets.purge(request.assetKey); µb.assets.remove('compiled/' + request.assetKey); - // https://github.com/gorhill/uBlock/pull/2314#issuecomment-278716960 - if ( request.assetKey === 'ublock-filters' ) { - µb.assets.purge('ublock-resources'); - µb.redirectEngine.invalidateResourcesSelfie(); - } break; case 'readHiddenSettings': diff --git a/src/js/redirect-engine.js b/src/js/redirect-engine.js index f76d3c0e0..9aff50ed3 100644 --- a/src/js/redirect-engine.js +++ b/src/js/redirect-engine.js @@ -28,7 +28,7 @@ /******************************************************************************/ /******************************************************************************/ -const immutableResources = new Map([ +const redirectableResources = new Map([ [ '1x1.gif', { alias: '1x1-transparent.gif', inject: false @@ -45,26 +45,6 @@ const immutableResources = new Map([ alias: '32x32-transparent.png', inject: false } ], - [ 'abort-current-inline-script.js', { - alias: 'acis.js', - redirect: false - } ], - [ 'abort-on-property-read.js', { - alias: 'aopr.js', - redirect: false - } ], - [ 'abort-on-property-write.js', { - alias: 'aopw.js', - redirect: false - } ], - [ 'addEventListener-defuser.js', { - alias: 'aeld.js', - redirect: false - } ], - [ 'addEventListener-logger.js', { - alias: 'aell.js', - redirect: false - } ], [ 'addthis_widget.js', { alias: 'addthis.com/addthis_widget.js', inject: false @@ -138,19 +118,8 @@ const immutableResources = new Map([ alias: 'd3pkae9owd2lcf.cloudfront.net/mb105.js', inject: false } ], - [ 'nano-setInterval-booster.js', { - alias: 'nano-sib.js', - redirect: false - } ], - [ 'nano-setTimeout-booster.js', { - alias: 'nano-stb.js', - redirect: false - } ], [ 'noeval.js', { } ], - [ 'noeval-if.js', { - redirect: false - } ], [ 'noeval-silent.js', { alias: 'silent-noeval.js', } ], @@ -182,36 +151,10 @@ const immutableResources = new Map([ [ 'popads-dummy.js', { alias: 'popads-dummy.js', } ], - [ 'remove-attr.js', { - alias: 'ra.js', - redirect: false - } ], [ 'scorecardresearch_beacon.js', { alias: 'scorecardresearch.com/beacon.js', inject: false } ], - [ 'set-constant.js', { - redirect: false - } ], - [ 'setInterval-defuser.js', { - alias: 'sid.js', - redirect: false - } ], - [ 'setInterval-logger.js', { - alias: 'sil.js', - redirect: false - } ], - [ 'setTimeout-defuser.js', { - alias: 'std.js', - redirect: false - } ], - [ 'setTimeout-logger.js', { - alias: 'stl.js', - redirect: false - } ], - [ 'webrtc-if.js', { - redirect: false - } ], [ 'window.open-defuser.js', { } ], ]); @@ -226,6 +169,13 @@ const mimeMap = { txt: 'text/plain', }; +const mimeFromName = function(name) { + const match = /\.([^.]+)$/.exec(name); + if ( match !== null ) { + return mimeMap[match[1]]; + } +}; + // https://github.com/gorhill/uBlock/issues/3639 // https://github.com/EFForg/https-everywhere/issues/14961 // https://bugs.chromium.org/p/chromium/issues/detail?id=111700 @@ -278,8 +228,8 @@ RedirectEntry.prototype.toURL = function(fctxt) { RedirectEntry.prototype.toContent = function() { if ( this.data.startsWith('data:') ) { - var pos = this.data.indexOf(','); - var base64 = this.data.endsWith(';base64', pos); + const pos = this.data.indexOf(','); + const base64 = this.data.endsWith(';base64', pos); this.data = this.data.slice(pos + 1); if ( base64 ) { this.data = atob(this.data); @@ -290,19 +240,17 @@ RedirectEntry.prototype.toContent = function() { /******************************************************************************/ -RedirectEntry.fromFields = function(mime, lines) { +RedirectEntry.fromContent = function(mime, content) { const r = new RedirectEntry(); r.mime = mime; - r.data = µBlock.orphanizeString( - lines.join(mime.indexOf(';') !== -1 ? '' : '\n') - ); + r.data = content; return r; }; /******************************************************************************/ RedirectEntry.fromSelfie = function(selfie) { - var r = new RedirectEntry(); + const r = new RedirectEntry(); r.mime = selfie.mime; r.data = selfie.data; r.warURL = selfie.warURL; @@ -313,6 +261,7 @@ RedirectEntry.fromSelfie = function(selfie) { /******************************************************************************/ const RedirectEngine = function() { + this.aliases = new Map(); this.resources = new Map(); this.reset(); this.resourceNameRegister = ''; @@ -337,7 +286,7 @@ RedirectEngine.prototype.freeze = function() { /******************************************************************************/ RedirectEngine.prototype.toBroaderHostname = function(hostname) { - var pos = hostname.indexOf('.'); + const pos = hostname.indexOf('.'); if ( pos !== -1 ) { return hostname.slice(pos + 1); } @@ -395,7 +344,7 @@ RedirectEngine.prototype.lookupToken = function(entries, reqURL) { RedirectEngine.prototype.toURL = function(fctxt) { let token = this.lookup(fctxt); if ( token === undefined ) { return; } - let entry = this.resources.get(token); + const entry = this.resources.get(this.aliases.get(token) || token); if ( entry !== undefined ) { return entry.toURL(fctxt); } @@ -404,8 +353,9 @@ RedirectEngine.prototype.toURL = function(fctxt) { /******************************************************************************/ RedirectEngine.prototype.matches = function(context) { - var token = this.lookup(context); - return token !== undefined && this.resources.has(token); + const token = this.lookup(context); + return token !== undefined && + this.resources.has(this.aliases.get(token) || token); }; /******************************************************************************/ @@ -414,14 +364,14 @@ RedirectEngine.prototype.addRule = function(src, des, type, pattern, redirect) { this.ruleSources.add(src); this.ruleDestinations.add(des); this.ruleTypes.add(type); - var key = src + ' ' + des + ' ' + type, + const key = `${src} ${des} ${type}`, entries = this.rules.get(key); if ( entries === undefined ) { this.rules.set(key, [ { tok: redirect, pat: pattern } ]); this.modifyTime = Date.now(); return; } - var entry; + let entry; for ( var i = 0, n = entries.length; i < n; i++ ) { entry = entries[i]; if ( redirect === entry.tok ) { break; } @@ -430,12 +380,12 @@ RedirectEngine.prototype.addRule = function(src, des, type, pattern, redirect) { entries.push({ tok: redirect, pat: pattern }); return; } - var p = entry.pat; + let p = entry.pat; if ( p instanceof RegExp ) { p = p.source; } // Duplicate? - var pos = p.indexOf(pattern); + let pos = p.indexOf(pattern); if ( pos !== -1 ) { if ( pos === 0 || p.charAt(pos - 1) === '|' ) { pos += pattern.length; @@ -526,7 +476,7 @@ RedirectEngine.prototype.compileRuleFromStaticFilter = function(line) { for ( const srchn of srchns ) { if ( srchn === '' ) { continue; } if ( srchn.startsWith('~') ) { continue; } - out.push(srchn + '\t' + deshn + '\t' + type + '\t' + pattern + '\t' + redirect); + out.push(`${srchn}\t${deshn}\t${type}\t${pattern}\t${redirect}`); } return out; @@ -603,8 +553,11 @@ RedirectEngine.prototype.fromSelfie = function(path) { /******************************************************************************/ RedirectEngine.prototype.resourceURIFromName = function(name, mime) { - var entry = this.resources.get(name); - if ( entry && (mime === undefined || entry.mime.startsWith(mime)) ) { + const entry = this.resources.get(this.aliases.get(name) || name); + if ( + (entry !== undefined) && + (mime === undefined || entry.mime.startsWith(mime)) + ) { return entry.toURL(); } }; @@ -612,15 +565,8 @@ RedirectEngine.prototype.resourceURIFromName = function(name, mime) { /******************************************************************************/ RedirectEngine.prototype.resourceContentFromName = function(name, mime) { - var entry; - for (;;) { - entry = this.resources.get(name); - if ( entry === undefined ) { return; } - if ( entry.mime.startsWith('alias/') === false ) { - break; - } - name = entry.mime.slice(6); - } + const entry = this.resources.get(this.aliases.get(name) || name); + if ( entry === undefined ) { return; } if ( mime === undefined || entry.mime.startsWith(mime) ) { return entry.toContent(); } @@ -633,24 +579,38 @@ RedirectEngine.prototype.resourceContentFromName = function(name, mime) { // https://github.com/uBlockOrigin/uAssets/commit/deefe875551197d655f79cb540e62dfc17c95f42 // Consider 'none' a reserved keyword, to be used to disable redirection. -RedirectEngine.prototype.resourcesFromString = function( - text, - override = true -) { - const lineIter = new µBlock.LineIterator(text); +RedirectEngine.prototype.resourcesFromString = function(text) { + const lineIter = new µBlock.LineIterator(removeTopCommentBlock(text)); const reNonEmptyLine = /\S/; - let fields, encoded; + let fields, encoded, details; while ( lineIter.eot() === false ) { let line = lineIter.next(); if ( line.startsWith('#') ) { continue; } + if ( line.startsWith('// ') ) { continue; } if ( fields === undefined ) { - let head = line.trim().split(/\s+/); - if ( head.length !== 2 ) { continue; } - if ( head[0] === 'none' ) { continue; } - encoded = head[1].indexOf(';') !== -1; - fields = head; + if ( line.startsWith('/// ') ) { + const name = line.slice(4).trim(); + fields = [ name, mimeFromName(name) ]; + } else { + const head = line.trim().split(/\s+/); + if ( head.length !== 2 ) { continue; } + if ( head[0] === 'none' ) { continue; } + encoded = head[1].indexOf(';') !== -1; + fields = head; + } + continue; + } + + if ( line.startsWith('/// ') ) { + if ( details === undefined ) { + details = {}; + } + const [ prop, value ] = line.slice(4).trim().split(/\s+/); + if ( value !== undefined ) { + details[prop] = value; + } continue; } @@ -659,45 +619,62 @@ RedirectEngine.prototype.resourcesFromString = function( continue; } + const name = fields[0]; + const mime = fields[1]; + const content = µBlock.orphanizeString( + fields.slice(2).join(encoded ? '' : '\n') + ); + // No more data, add the resource. - if ( - this.resources.has(fields[0]) === false || - override !== false - ) { - this.resources.set( - fields[0], - RedirectEntry.fromFields(fields[1], fields.slice(2)) - ); + this.resources.set( + name, + RedirectEntry.fromContent(mime, content) + ); + + if ( details instanceof Object && details.alias ) { + this.aliases.set(details.alias, name); } fields = undefined; + details = undefined; } // Process pending resource data. if ( fields !== undefined ) { - this.resources.set( - fields[0], - RedirectEntry.fromFields(fields[1], fields.slice(2)) + const name = fields[0]; + const mime = fields[1]; + const content = µBlock.orphanizeString( + fields.slice(2).join(encoded ? '' : '\n') ); + this.resources.set( + name, + RedirectEntry.fromContent(mime, content) + ); + if ( details instanceof Object && details.alias ) { + this.aliases.set(details.alias, name); + } } this.modifyTime = Date.now(); }; +const removeTopCommentBlock = function(text) { + return text.replace(/^\/\*[\S\s]+?\n\*\/\s*/, ''); +}; + /******************************************************************************/ RedirectEngine.prototype.loadBuiltinResources = function() { this.resources = new Map(); - const mimeFromName = function(name) { - const match = /\.([^.]+)$/.exec(name); - if ( match !== null ) { - return mimeMap[match[1]]; - } - }; + this.aliases = new Map(); const fetches = [ - µBlock.assets.get('ublock-resources'), + µBlock.assets.fetchText('/assets/resources/scriptlets.js'), ]; - for ( const [ name, details ] of immutableResources ) { + + // TODO: remove once usage of uBO 1.20.4 is widespread. + µBlock.assets.remove('ublock-resources'); + + for ( const [ name, details ] of redirectableResources ) { if ( details.inject !== false ) { fetches.push( µBlock.assets.fetchText( @@ -712,48 +689,48 @@ RedirectEngine.prototype.loadBuiltinResources = function() { }); this.resources.set(name, entry); if ( details.alias !== undefined ) { - this.resources.set(details.alias, entry); + this.aliases.set(details.alias, name); } } + return Promise.all(fetches).then(results => { - // Immutable resources + // Built-in redirectable resources for ( let i = 1; i < results.length; i++ ) { const result = results[i]; const match = /^\/web_accessible_resources\/([^?]+)/.exec(result.url); if ( match === null ) { continue; } const name = match[1]; - const content = result.content.replace(/^\/\*[\S\s]+?\n\*\/\s*/, ''); - const details = immutableResources.get(name); + const content = removeTopCommentBlock(result.content); + const details = redirectableResources.get(name); const entry = RedirectEntry.fromSelfie({ mime: mimeFromName(name), data: content, - warURL: details.redirect !== false - ? vAPI.getURL(`/web_accessible_resources/${name}`) - : undefined, + warURL: vAPI.getURL(`/web_accessible_resources/${name}`), }); this.resources.set(name, entry); if ( details.alias !== undefined ) { - this.resources.set(details.alias, entry); + this.aliases.set(details.alias, name); } } - // Mutable resources + // Additional resources const content = results[0].content; if ( typeof content === 'string' && content.length !== 0 ) { - this.resourcesFromString(content, false); + this.resourcesFromString(content); } }); }; /******************************************************************************/ -const resourcesSelfieVersion = 3; +const resourcesSelfieVersion = 4; RedirectEngine.prototype.selfieFromResources = function() { µBlock.assets.put( 'compiled/redirectEngine/resources', JSON.stringify({ version: resourcesSelfieVersion, - resources: Array.from(this.resources) + aliases: Array.from(this.aliases), + resources: Array.from(this.resources), }) ); }; @@ -774,6 +751,7 @@ RedirectEngine.prototype.resourcesFromSelfie = function() { ) { return false; } + this.aliases = new Map(selfie.aliases); this.resources = new Map(); for ( const [ token, entry ] of selfie.resources ) { this.resources.set(token, RedirectEntry.fromSelfie(entry)); diff --git a/src/js/storage.js b/src/js/storage.js index f44ea5838..7c13de79c 100644 --- a/src/js/storage.js +++ b/src/js/storage.js @@ -1327,14 +1327,9 @@ return; } } - // https://github.com/gorhill/uBlock/issues/2594 + // This asset is deprecated. if ( details.assetKey === 'ublock-resources' ) { - if ( - this.hiddenSettings.ignoreRedirectFilters === true && - this.hiddenSettings.ignoreScriptInjectFilters === true - ) { - return; - } + return; } return true; } @@ -1367,8 +1362,6 @@ if ( cached ) { this.compilePublicSuffixList(details.content); } - } else if ( details.assetKey === 'ublock-resources' ) { - this.redirectEngine.invalidateResourcesSelfie(); } vAPI.messaging.broadcast({ what: 'assetUpdated', @@ -1395,6 +1388,10 @@ // Reload all filter lists if needed. if ( topic === 'after-assets-updated' ) { if ( details.assetKeys.length !== 0 ) { + // https://github.com/gorhill/uBlock/pull/2314#issuecomment-278716960 + if ( this.hiddenSettings.userResourcesLocation !== 'unset' ) { + this.redirectEngine.invalidateResourcesSelfie(); + } this.loadFilterLists(); } if ( this.userSettings.autoUpdate ) { diff --git a/src/web_accessible_resources/abort-current-inline-script.js b/src/web_accessible_resources/abort-current-inline-script.js deleted file mode 100644 index 97d654620..000000000 --- a/src/web_accessible_resources/abort-current-inline-script.js +++ /dev/null @@ -1,79 +0,0 @@ -/******************************************************************************* - - 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 -*/ - -(function() { - 'use strict'; - const target = '{{1}}'; - if ( target === '' || target === '{{1}}' ) { return; } - const needle = '{{2}}'; - let reText = '.?'; - if ( needle !== '' && needle !== '{{2}}' ) { - reText = /^\/.+\/$/.test(needle) - ? needle.slice(1,-1) - : needle.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); - } - const thisScript = document.currentScript; - const re = new RegExp(reText); - const chain = target.split('.'); - let owner = window; - let prop; - for (;;) { - prop = chain.shift(); - if ( chain.length === 0 ) { break; } - owner = owner[prop]; - if ( owner instanceof Object === false ) { return; } - } - const desc = Object.getOwnPropertyDescriptor(owner, prop); - if ( desc && desc.get !== undefined ) { return; } - const magic = String.fromCharCode(Date.now() % 26 + 97) + - Math.floor(Math.random() * 982451653 + 982451653).toString(36); - let value = owner[prop]; - const validate = function() { - const e = document.currentScript; - if ( - e instanceof HTMLScriptElement && - e.src === '' && - e !== thisScript && - re.test(e.textContent) - ) { - throw new ReferenceError(magic); - } - }; - Object.defineProperty(owner, prop, { - get: function() { - validate(); - return value; - }, - set: function(a) { - validate(); - value = a; - } - }); - const oe = window.onerror; - window.onerror = function(msg) { - if ( typeof msg === 'string' && msg.indexOf(magic) !== -1 ) { - return true; - } - if ( oe instanceof Function ) { - return oe.apply(this, arguments); - } - }.bind(); -})(); diff --git a/src/web_accessible_resources/abort-on-property-read.js b/src/web_accessible_resources/abort-on-property-read.js deleted file mode 100644 index 157bf10da..000000000 --- a/src/web_accessible_resources/abort-on-property-read.js +++ /dev/null @@ -1,72 +0,0 @@ -/******************************************************************************* - - 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 -*/ - -(function() { - 'use strict'; - 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 = Object.getOwnPropertyDescriptor(owner, chain); - if ( !desc || desc.get !== abort ) { - Object.defineProperty(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 = Object.getOwnPropertyDescriptor(owner, prop); - if ( desc && desc.set !== undefined ) { return; } - Object.defineProperty(owner, prop, { - get: function() { return v; }, - set: function(a) { - v = a; - if ( a instanceof Object ) { - makeProxy(a, chain); - } - } - }); - }; - const owner = window; - let chain = '{{1}}'; - 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(); -})(); diff --git a/src/web_accessible_resources/abort-on-property-write.js b/src/web_accessible_resources/abort-on-property-write.js deleted file mode 100644 index 5ff3fb577..000000000 --- a/src/web_accessible_resources/abort-on-property-write.js +++ /dev/null @@ -1,50 +0,0 @@ -/******************************************************************************* - - 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 -*/ - -(function() { - 'use strict'; - const magic = String.fromCharCode(Date.now() % 26 + 97) + - Math.floor(Math.random() * 982451653 + 982451653).toString(36); - let prop = '{{1}}'; - let owner = window; - for (;;) { - const pos = prop.indexOf('.'); - if ( pos === -1 ) { break; } - owner = owner[prop.slice(0, pos)]; - if ( owner instanceof Object === false ) { return; } - prop = prop.slice(pos + 1); - } - delete owner[prop]; - Object.defineProperty(owner, prop, { - set: function() { - throw new ReferenceError(magic); - } - }); - 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(); -})(); diff --git a/src/web_accessible_resources/addEventListener-defuser.js b/src/web_accessible_resources/addEventListener-defuser.js deleted file mode 100644 index ad6480b4b..000000000 --- a/src/web_accessible_resources/addEventListener-defuser.js +++ /dev/null @@ -1,57 +0,0 @@ -/******************************************************************************* - - 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 -*/ - -(function() { - 'use strict'; - let needle1 = '{{1}}'; - if ( needle1 === '' || needle1 === '{{1}}' ) { - needle1 = '.?'; - } else if ( /^\/.+\/$/.test(needle1) ) { - needle1 = needle1.slice(1,-1); - } else { - needle1 = needle1.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); - } - needle1 = new RegExp(needle1); - let needle2 = '{{2}}'; - if ( needle2 === '' || needle2 === '{{2}}' ) { - needle2 = '.?'; - } else if ( /^\/.+\/$/.test(needle2) ) { - needle2 = needle2.slice(1,-1); - } else { - needle2 = needle2.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); - } - needle2 = new RegExp(needle2); - self.EventTarget.prototype.addEventListener = new Proxy( - self.EventTarget.prototype.addEventListener, - { - apply: function(target, thisArg, args) { - const type = args[0].toString(); - const handler = String(args[1]); - if ( - needle1.test(type) === false || - needle2.test(handler) === false - ) { - return target.apply(thisArg, args); - } - } - } - ); -})(); diff --git a/src/web_accessible_resources/addEventListener-logger.js b/src/web_accessible_resources/addEventListener-logger.js deleted file mode 100644 index cd19161cf..000000000 --- a/src/web_accessible_resources/addEventListener-logger.js +++ /dev/null @@ -1,36 +0,0 @@ -/******************************************************************************* - - 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 -*/ - -(function() { - 'use strict'; - const log = console.log.bind(console); - self.EventTarget.prototype.addEventListener = new Proxy( - self.EventTarget.prototype.addEventListener, - { - apply: function(target, thisArg, args) { - const type = args[0].toString(); - const handler = String(args[1]); - log('addEventListener("%s", %s)', type, handler); - return target.apply(thisArg, args); - } - } - ); -})(); diff --git a/src/web_accessible_resources/nano-setInterval-booster.js b/src/web_accessible_resources/nano-setInterval-booster.js deleted file mode 100644 index f08c6401f..000000000 --- a/src/web_accessible_resources/nano-setInterval-booster.js +++ /dev/null @@ -1,51 +0,0 @@ -/******************************************************************************* - - Imported from: - https://github.com/NanoAdblocker/NanoFilters/blob/1f3be7211bb0809c5106996f52564bf10c4525f7/NanoFiltersSource/NanoResources.txt#L126 - - Speed up or down setInterval, 3 optional arguments. - funcMatcher - The payload matcher, a string literal or a JavaScript RegExp, - defaults to match all. - delayMatcher - The delay matcher, an integer, defaults to 1000. - boostRatio - The delay multiplier when there is a match, 0.5 speeds up by - 2 times and 2 slows down by 2 times, defaults to 0.05 or speed up 20 times. - Speed up and down both cap at 50 times. - -*/ - -(function() { - 'use strict'; - let needle = '{{1}}'; - let delay = parseInt('{{2}}', 10); - let boost = parseFloat('{{3}}'); - if ( needle === '' || needle === '{{1}}' ) { - needle = '.?'; - } else if ( needle.charAt(0) === '/' && needle.slice(-1) === '/' ) { - needle = needle.slice(1, -1); - } else { - needle = needle.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); - } - needle = new RegExp(needle); - if ( isNaN(delay) || !isFinite(delay) ) { - delay = 1000; - } - if ( isNaN(boost) || !isFinite(boost) ) { - boost = 0.05; - } - if ( boost < 0.02 ) { - boost = 0.02; - } - if ( boost > 50 ) { - boost = 50; - } - window.setInterval = new Proxy(window.setInterval, { - apply: function(target, thisArg, args) { - const a = args[0]; - const b = args[1]; - if ( b === delay && needle.test(a.toString()) ) { - args[1] = b * boost; - } - return target.apply(thisArg, args); - } - }); -})(); diff --git a/src/web_accessible_resources/nano-setTimeout-booster.js b/src/web_accessible_resources/nano-setTimeout-booster.js deleted file mode 100644 index afce15579..000000000 --- a/src/web_accessible_resources/nano-setTimeout-booster.js +++ /dev/null @@ -1,51 +0,0 @@ -/******************************************************************************* - - Originally imported from: - https://github.com/NanoAdblocker/NanoFilters/blob/1f3be7211bb0809c5106996f52564bf10c4525f7/NanoFiltersSource/NanoResources.txt#L82 - - Speed up or down setTimeout, 3 optional arguments. - funcMatcher - The payload matcher, a string literal or a JavaScript RegExp, - defaults to match all. - delayMatcher - The delay matcher, an integer, defaults to 1000. - boostRatio - The delay multiplier when there is a match, 0.5 speeds up by - 2 times and 2 slows down by 2 times, defaults to 0.05 or speed up 20 times. - Speed up and down both cap at 50 times. - -*/ - -(function() { - 'use strict'; - let needle = '{{1}}'; - let delay = parseInt('{{2}}', 10); - let boost = parseFloat('{{3}}'); - if ( needle === '' || needle === '{{1}}' ) { - needle = '.?'; - } else if ( needle.startsWith('/') && needle.endsWith('/') ) { - needle = needle.slice(1, -1); - } else { - needle = needle.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); - } - needle = new RegExp(needle); - if ( isNaN(delay) || !isFinite(delay) ) { - delay = 1000; - } - if ( isNaN(boost) || !isFinite(boost) ) { - boost = 0.05; - } - if ( boost < 0.02 ) { - boost = 0.02; - } - if ( boost > 50 ) { - boost = 50; - } - window.setTimeout = new Proxy(window.setTimeout, { - apply: function(target, thisArg, args) { - const a = args[0]; - const b = args[1]; - if ( b === delay && needle.test(a.toString()) ) { - args[1] = b * boost; - } - return target.apply(thisArg, args); - } - }); -})(); diff --git a/src/web_accessible_resources/noeval-if.js b/src/web_accessible_resources/noeval-if.js deleted file mode 100644 index 994772f4a..000000000 --- a/src/web_accessible_resources/noeval-if.js +++ /dev/null @@ -1,41 +0,0 @@ -/******************************************************************************* - - 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 -*/ - -(function() { - 'use strict'; - let needle = '{{1}}'; - if ( needle === '' || needle === '{{1}}' ) { - needle = '.?'; - } else if ( needle.slice(0,1) === '/' && needle.slice(-1) === '/' ) { - needle = needle.slice(1,-1); - } else { - needle = needle.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); - } - needle = new RegExp(needle); - window.eval = new Proxy(window.eval, { // jshint ignore: line - apply: function(target, thisArg, args) { - const a = args[0]; - if ( needle.test(a.toString()) === false ) { - return target.apply(thisArg, args); - } - } - }); -})(); diff --git a/src/web_accessible_resources/remove-attr.js b/src/web_accessible_resources/remove-attr.js deleted file mode 100644 index c3edc7c50..000000000 --- a/src/web_accessible_resources/remove-attr.js +++ /dev/null @@ -1,50 +0,0 @@ -/******************************************************************************* - - 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 -*/ - -(function() { - 'use strict'; - const token = '{{1}}'; - if ( token === '' || token === '{{1}}' ) { return; } - const tokens = token.split(/\s*\|\s*/); - let selector = '{{2}}'; - if ( selector === '' || selector === '{{2}}' ) { - selector = `[${tokens.join('],[')}]`; - } - const rmattr = function(ev) { - if ( ev ) { - window.removeEventListener(ev.type, rmattr, true); - } - try { - const nodes = document.querySelectorAll(selector); - for ( const node of nodes ) { - for ( const attr of tokens ) { - node.removeAttribute(attr); - } - } - } catch(ex) { - } - }; - if ( document.readyState === 'loading' ) { - window.addEventListener('DOMContentLoaded', rmattr, true); - } else { - rmattr(); - } -})(); diff --git a/src/web_accessible_resources/set-constant.js b/src/web_accessible_resources/set-constant.js deleted file mode 100644 index 1c3ec876e..000000000 --- a/src/web_accessible_resources/set-constant.js +++ /dev/null @@ -1,99 +0,0 @@ -/******************************************************************************* - - 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 -*/ - -(function() { - 'use strict'; - const thisScript = document.currentScript; - let cValue = '{{2}}'; - if ( cValue === 'undefined' ) { - cValue = undefined; - } else if ( cValue === 'false' ) { - cValue = false; - } else if ( cValue === 'true' ) { - cValue = true; - } else if ( cValue === 'null' ) { - cValue = null; - } else if ( cValue === 'noopFunc' ) { - cValue = function(){}; - } else if ( cValue === 'trueFunc' ) { - cValue = function(){ return true; }; - } else if ( cValue === 'falseFunc' ) { - cValue = function(){ return false; }; - } else if ( /^\d+$/.test(cValue) ) { - cValue = parseFloat(cValue); - if ( isNaN(cValue) ) { return; } - if ( Math.abs(cValue) > 0x7FFF ) { return; } - } else if ( cValue === "''" ) { - cValue = ''; - } else { - return; - } - let aborted = false; - const mustAbort = function(v) { - if ( aborted ) { return true; } - aborted = v !== undefined && cValue !== undefined && typeof v !== typeof cValue; - return aborted; - }; - const makeProxy = function(owner, chain) { - const pos = chain.indexOf('.'); - if ( pos === -1 ) { - const original = owner[chain]; - if ( mustAbort(original) ) { return; } - const desc = Object.getOwnPropertyDescriptor(owner, chain); - if ( desc === undefined || desc.get === undefined ) { - Object.defineProperty(owner, chain, { - get: function() { - return document.currentScript === thisScript - ? original - : cValue; - }, - set: function(a) { - if ( mustAbort(a) ) { - cValue = a; - } - } - }); - } - return; - } - const prop = chain.slice(0, pos); - let v = owner[prop]; - chain = chain.slice(pos + 1); - if ( v !== undefined ) { - makeProxy(v, chain); - return; - } - const desc = Object.getOwnPropertyDescriptor(owner, prop); - if ( desc && desc.set !== undefined ) { return; } - Object.defineProperty(owner, prop, { - get: function() { - return v; - }, - set: function(a) { - v = a; - if ( a instanceof Object ) { - makeProxy(a, chain); - } - } - }); - }; - makeProxy(window, '{{1}}'); -})(); diff --git a/src/web_accessible_resources/setInterval-defuser.js b/src/web_accessible_resources/setInterval-defuser.js deleted file mode 100644 index c443ffcdf..000000000 --- a/src/web_accessible_resources/setInterval-defuser.js +++ /dev/null @@ -1,44 +0,0 @@ -/******************************************************************************* - - 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 -*/ - -(function() { - 'use strict'; - let needle = '{{1}}'; - const delay = parseInt('{{2}}', 10); - if ( needle === '' || needle === '{{1}}' ) { - needle = '.?'; - } else if ( needle.startsWith('/') && needle.endsWith('/') ) { - needle = needle.slice(1,-1); - } else { - needle = needle.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); - } - needle = new RegExp(needle); - window.setInterval = new Proxy(window.setInterval, { - apply: function(target, thisArg, args) { - const a = args[0]; - const b = args[1]; - if ( (isNaN(delay) || b === delay) && needle.test(a.toString()) ) { - args[0] = function(){}; - } - return target.apply(thisArg, args); - } - }); -})(); diff --git a/src/web_accessible_resources/setInterval-logger.js b/src/web_accessible_resources/setInterval-logger.js deleted file mode 100644 index 49e05bc73..000000000 --- a/src/web_accessible_resources/setInterval-logger.js +++ /dev/null @@ -1,33 +0,0 @@ -/******************************************************************************* - - 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 -*/ - -(function() { - 'use strict'; - const log = console.log.bind(console); - window.setInterval = new Proxy(window.setInterval, { - apply: function(target, thisArg, args) { - const a = args[0]; - const b = args[1]; - log('uBO: setInterval("%s", %s)', a.toString(), b); - return target.apply(thisArg, args); - } - }); -})(); diff --git a/src/web_accessible_resources/setTimeout-defuser.js b/src/web_accessible_resources/setTimeout-defuser.js deleted file mode 100644 index 8bc08c1e4..000000000 --- a/src/web_accessible_resources/setTimeout-defuser.js +++ /dev/null @@ -1,44 +0,0 @@ -/******************************************************************************* - - 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 -*/ - -(function() { - 'use strict'; - let needle = '{{1}}'; - const delay = parseInt('{{2}}', 10); - if ( needle === '' || needle === '{{1}}' ) { - needle = '.?'; - } else if ( needle.startsWith('/') && needle.endsWith('/') ) { - needle = needle.slice(1,-1); - } else { - needle = needle.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); - } - needle = new RegExp(needle); - window.setTimeout = new Proxy(window.setTimeout, { - apply: function(target, thisArg, args) { - const a = args[0]; - const b = args[1]; - if ( (isNaN(delay) || b === delay) && needle.test(a.toString()) ) { - args[0] = function(){}; - } - return target.apply(thisArg, args); - } - }); -})(); diff --git a/src/web_accessible_resources/setTimeout-logger.js b/src/web_accessible_resources/setTimeout-logger.js deleted file mode 100644 index 604eef004..000000000 --- a/src/web_accessible_resources/setTimeout-logger.js +++ /dev/null @@ -1,33 +0,0 @@ -/******************************************************************************* - - 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 -*/ - -(function() { - 'use strict'; - const log = console.log.bind(console); - window.setTimeout = new Proxy(window.setTimeout, { - apply: function(target, thisArg, args) { - const a = args[0]; - const b = args[1]; - log('uBO: setTimeout("%s", %s)', a.toString(), b); - return target.apply(thisArg, args); - } - }); -})(); diff --git a/src/web_accessible_resources/webrtc-if.js b/src/web_accessible_resources/webrtc-if.js deleted file mode 100644 index dfbb8ab6a..000000000 --- a/src/web_accessible_resources/webrtc-if.js +++ /dev/null @@ -1,87 +0,0 @@ -/******************************************************************************* - - 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 -*/ - -(function() { - 'use strict'; - let good = '{{1}}'; - if ( good.startsWith('/') && good.endsWith('/') ) { - good = good.slice(1, -1); - } else { - good = good.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); - } - let reGood; - try { - reGood = new RegExp(good); - } catch(ex) { - return; - } - const rtcName = window.RTCPeerConnection - ? 'RTCPeerConnection' - : (window.webkitRTCPeerConnection ? 'webkitRTCPeerConnection' : ''); - if ( rtcName === '' ) { return; } - const log = console.log.bind(console); - const neuteredPeerConnections = new WeakSet(); - const isGoodConfig = function(instance, config) { - if ( neuteredPeerConnections.has(instance) ) { return false; } - if ( config instanceof Object === false ) { return true; } - if ( Array.isArray(config.iceServers) === false ) { return true; } - for ( const server of config.iceServers ) { - const urls = typeof server.urls === 'string' - ? [ server.urls ] - : server.urls; - if ( Array.isArray(urls) ) { - for ( const url of urls ) { - if ( reGood.test(url) ) { return true; } - } - } - if ( typeof server.username === 'string' ) { - if ( reGood.test(server.username) ) { return true; } - } - if ( typeof server.credential === 'string' ) { - if ( reGood.test(server.credential) ) { return true; } - } - } - neuteredPeerConnections.add(instance); - return false; - }; - const peerConnectionCtor = window[rtcName]; - const peerConnectionProto = peerConnectionCtor.prototype; - peerConnectionProto.createDataChannel = - new Proxy(peerConnectionProto.createDataChannel, { - apply: function(target, thisArg, args) { - if ( isGoodConfig(target, args[1]) === false ) { - log(args[1]); - return target.apply(thisArg, args.slice(0, 1)); - } - return target.apply(thisArg, args); - }, - }); - window[rtcName] = - new Proxy(peerConnectionCtor, { - construct: function(target, args) { - if ( isGoodConfig(target, args[0]) === false ) { - log(args[0]); - return new target(); - } - return new target(...args); - } - }); -})(); diff --git a/tools/make-assets.sh b/tools/make-assets.sh index 59b93f49e..2d06f3678 100755 --- a/tools/make-assets.sh +++ b/tools/make-assets.sh @@ -13,8 +13,7 @@ if [ -n "${TRAVIS_TAG}" ]; then fi rm -rf $DES -mkdir $DES -cp ./assets/assets.json $DES/ +cp -R ./assets $DES/ if [ -f ./tmp/requests.json.gz ]; then gunzip -c ./tmp/requests.json.gz > $DES/requests.json @@ -31,5 +30,6 @@ mkdir $DES/ublock cp -R ../uAssets/filters/* $DES/ublock/ # Optional filter lists: do not include in package rm $DES/ublock/annoyances.txt +rm $DES/ublock/resources.txt echo "done."