import type { Page } from 'brave-real-puppeteer-core';
/**
* AGGRESSIVE AD BLOCKING SCRIPTLETS
* Blocks: window.open popups, location redirects, overlay ads, click hijacking
*/
export async function injectScriptlets(page: Page) {
// Use CDP for earliest injection
const client = await page.target().createCDPSession();
await client.send('Page.enable');
await client.send('Page.addScriptToEvaluateOnNewDocument', {
source: `
(function() {
'use strict';
// ==========================================
// CONFIGURATION
// ==========================================
const CONFIG = {
// Time window after user interaction to allow popups (ms)
POPUP_GRACE_PERIOD: 500,
// Minimum time between popups (ms)
POPUP_COOLDOWN: 1000,
// Maximum popups per page session
MAX_POPUPS_PER_SESSION: 3,
// Block these URL patterns
BLOCKED_URL_PATTERNS: [
/ads?\\./i, /pop(up|under)?\\./i, /click\\./i, /track(er|ing)?\\./i,
/beacon\\./i, /affiliate/i, /partner\\./i, /promo\\./i, /banner/i,
/about:blank/, /javascript:/i, /\\?utm_/i, /\\/afu\\//i,
/redirect/i, /go\\.php/i, /out\\.php/i, /link\\.php/i,
/profitableratecpm/i, /engridfanlike/i, /pubfuture/i,
/clickadu/i, /propellerads/i, /popads/i, /popcash/i,
/adcash/i, /exoclick/i, /ExoLoader/i, /PopMagic/i
]
};
// ==========================================
// STATE TRACKING
// ==========================================
let lastUserInteraction = 0;
let lastPopupTime = 0;
let popupCount = 0;
let isUserInteracting = false;
// ==========================================
// HELPER FUNCTIONS
// ==========================================
function isBlockedUrl(url) {
if (!url) return true;
const urlStr = String(url);
return CONFIG.BLOCKED_URL_PATTERNS.some(pattern => pattern.test(urlStr));
}
function isUserInitiated() {
return (Date.now() - lastUserInteraction) < CONFIG.POPUP_GRACE_PERIOD;
}
function canOpenPopup() {
const now = Date.now();
if (now - lastPopupTime < CONFIG.POPUP_COOLDOWN) return false;
if (popupCount >= CONFIG.MAX_POPUPS_PER_SESSION) return false;
return true;
}
function makeNative(fn, name) {
const nativeToString = function() { return 'function ' + name + '() { [native code] }'; };
Object.defineProperty(fn, 'toString', { value: nativeToString });
Object.defineProperty(fn, 'name', { value: name, configurable: true });
return fn;
}
// ==========================================
// USER INTERACTION TRACKING
// ==========================================
['click', 'keydown', 'mousedown', 'touchstart', 'pointerdown'].forEach(event => {
document.addEventListener(event, function(e) {
// Only count as interaction if it's a trusted event
if (e.isTrusted) {
lastUserInteraction = Date.now();
isUserInteracting = true;
setTimeout(() => { isUserInteracting = false; }, CONFIG.POPUP_GRACE_PERIOD);
}
}, { capture: true, passive: true });
});
// ==========================================
// WINDOW.OPEN BLOCKING
// ==========================================
const originalOpen = window.open;
window.open = makeNative(function(url, target, features) {
const urlStr = String(url || '');
// Block if URL matches blocked patterns
if (isBlockedUrl(urlStr)) {
console.log('[AdBlocker] Blocked popup (bad URL):', urlStr.substring(0, 60));
return null;
}
// Block if not user-initiated
if (!isUserInitiated()) {
console.log('[AdBlocker] Blocked popup (no user interaction):', urlStr.substring(0, 60));
return null;
}
// Block if too many popups
if (!canOpenPopup()) {
console.log('[AdBlocker] Blocked popup (rate limit):', urlStr.substring(0, 60));
return null;
}
// Block if has popup window features (sized windows = ads)
if (features && (features.includes('width') || features.includes('height'))) {
console.log('[AdBlocker] Blocked popup (window features):', urlStr.substring(0, 60));
return null;
}
// Allow legitimate popup
lastPopupTime = Date.now();
popupCount++;
return originalOpen.call(this, url, target, features);
}, 'open');
// ==========================================
// LOCATION.HREF REDIRECT BLOCKING
// ==========================================
const locationDescriptor = Object.getOwnPropertyDescriptor(window, 'location');
let legitimateUrl = window.location.href;
// Intercept location.assign
const originalAssign = window.location.assign.bind(window.location);
window.location.assign = makeNative(function(url) {
if (isBlockedUrl(url) || !isUserInitiated()) {
console.log('[AdBlocker] Blocked redirect (assign):', String(url).substring(0, 60));
return;
}
return originalAssign(url);
}, 'assign');
// Intercept location.replace
const originalReplace = window.location.replace.bind(window.location);
window.location.replace = makeNative(function(url) {
if (isBlockedUrl(url) || !isUserInitiated()) {
console.log('[AdBlocker] Blocked redirect (replace):', String(url).substring(0, 60));
return;
}
return originalReplace(url);
}, 'replace');
// ==========================================
// SETTIMEOUT/SETINTERVAL REDIRECT BLOCKING
// ==========================================
const originalSetTimeout = window.setTimeout;
window.setTimeout = makeNative(function(callback, delay, ...args) {
// Check if callback contains redirect code
if (typeof callback === 'string') {
const code = callback.toLowerCase();
if (code.includes('location') || code.includes('redirect') || code.includes('window.open')) {
console.log('[AdBlocker] Blocked setTimeout redirect');
return 0;
}
}
return originalSetTimeout.call(this, callback, delay, ...args);
}, 'setTimeout');
const originalSetInterval = window.setInterval;
window.setInterval = makeNative(function(callback, delay, ...args) {
if (typeof callback === 'string') {
const code = callback.toLowerCase();
if (code.includes('location') || code.includes('redirect') || code.includes('window.open')) {
console.log('[AdBlocker] Blocked setInterval redirect');
return 0;
}
}
return originalSetInterval.call(this, callback, delay, ...args);
}, 'setInterval');
// ==========================================
// DOCUMENT.WRITE BLOCKING (AD INJECTION)
// ==========================================
const originalWrite = document.write.bind(document);
document.write = makeNative(function(html) {
const htmlStr = String(html || '').toLowerCase();
if (htmlStr.includes('location.href') ||
htmlStr.includes('window.open') ||
htmlStr.includes('redirect') ||
htmlStr.includes('popunder') ||
htmlStr.includes('exoclick') ||
htmlStr.includes('popads')) {
console.log('[AdBlocker] Blocked document.write ad injection');
return;
}
return originalWrite(html);
}, 'write');
// ==========================================
// ADDEVENTLISTENER CLICK HIJACK BLOCKING
// ==========================================
const originalAddEventListener = EventTarget.prototype.addEventListener;
EventTarget.prototype.addEventListener = function(type, listener, options) {
// Block suspicious click handlers on body/document
if (type === 'click' && (this === document || this === document.body || this === window)) {
const listenerStr = listener ? listener.toString().toLowerCase() : '';
if (listenerStr.includes('window.open') ||
listenerStr.includes('location') ||
listenerStr.includes('popup') ||
listenerStr.includes('redirect')) {
console.log('[AdBlocker] Blocked click hijack listener');
return;
}
}
return originalAddEventListener.call(this, type, listener, options);
};
// ==========================================
// ABORT ON PROPERTY WRITE (POPUNDER SCRIPTS)
// ==========================================
const ABORT_PROPERTIES = ['popunder', '__$pb', 'ExoLoader', 'PopMagic', 'Fingerprint2', 'adblock', 'popMagic'];
ABORT_PROPERTIES.forEach(prop => {
try {
Object.defineProperty(window, prop, {
get: function() { return undefined; },
set: function(val) {
console.log('[AdBlocker] Blocked property set:', prop);
return true;
},
configurable: false
});
} catch(e) {}
});
// ==========================================
// EVAL BLOCKING FOR AD CODE
// ==========================================
const originalEval = window.eval;
window.eval = makeNative(function(code) {
if (typeof code === 'string') {
const codeLower = code.toLowerCase();
if (codeLower.includes('popup') ||
codeLower.includes('popunder') ||
codeLower.includes('redirect') ||
codeLower.includes('exoclick') ||
codeLower.includes('popads')) {
console.log('[AdBlocker] Blocked eval ad code');
return undefined;
}
}
return originalEval.call(this, code);
}, 'eval');
// ==========================================
// FUNCTION CONSTRUCTOR BLOCKING (bypasses eval)
// ==========================================
const originalFunction = Function;
window.Function = function(...args) {
const code = args.join(' ').toLowerCase();
if (code.includes('popup') ||
code.includes('popunder') ||
code.includes('redirect') ||
code.includes('window.open') ||
code.includes('location.href')) {
console.log('[AdBlocker] Blocked Function constructor ad code');
return function() {};
}
return originalFunction.apply(this, args);
};
Object.setPrototypeOf(window.Function, originalFunction);
window.Function.prototype = originalFunction.prototype;
// ==========================================
// ANTI-ADBLOCK DETECTION BYPASS
// ==========================================
// Spoof common adblock detection methods
const ADBLOCK_DETECTION_BYPASS = {
// Common detection properties
adblock: false,
adblockEnabled: false,
adBlockEnabled: false,
adblockDetected: false,
adBlockDetected: false,
isAdBlockActive: false,
hasAdBlock: false,
adBlocker: false,
uBlockOrigin: false,
adblockplus: false,
// Detection objects
blockAdBlock: {
check: function() { return false; },
on: function() { return this; },
onDetected: function() { return this; },
onNotDetected: function(cb) { if(cb) cb(); return this; }
},
fuckAdBlock: {
check: function() { return false; },
on: function() { return this; },
onDetected: function() { return this; },
onNotDetected: function(cb) { if(cb) cb(); return this; }
},
sniffAdBlock: {
check: function() { return false; },
callback: function() {}
},
adblockDetector: {
detected: false,
init: function() {},
detect: function() { return false; }
},
// Fake ad element for detection bypass
canRunAds: true,
isAdsDisplayed: true,
adsbygoogle: { loaded: true, push: function() {} }
};
// Apply all bypass properties
Object.keys(ADBLOCK_DETECTION_BYPASS).forEach(key => {
try {
const value = ADBLOCK_DETECTION_BYPASS[key];
Object.defineProperty(window, key, {
get: function() { return value; },
set: function() { return true; },
configurable: true
});
} catch(e) {}
});
// Spoof ad element detection (sites check if ad divs are hidden)
const originalGetComputedStyle = window.getComputedStyle;
window.getComputedStyle = function(el, pseudo) {
const style = originalGetComputedStyle.call(this, el, pseudo);
// If checking an ad-related element, spoof visibility
if (el && el.className && typeof el.className === 'string') {
const className = el.className.toLowerCase();
if (className.includes('ads') ||
className.includes('banner') ||
className.includes('sponsor') ||
className.includes('adsbox')) {
// Return a proxy that spoofs display/visibility
return new Proxy(style, {
get: function(target, prop) {
if (prop === 'display') return 'block';
if (prop === 'visibility') return 'visible';
if (prop === 'opacity') return '1';
if (prop === 'height') return '250px';
if (prop === 'width') return '300px';
return target[prop];
}
});
}
}
return style;
};
// Block anti-adblock scripts from detecting hidden elements
const originalOffsetHeight = Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'offsetHeight');
const originalOffsetWidth = Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'offsetWidth');
Object.defineProperty(HTMLElement.prototype, 'offsetHeight', {
get: function() {
if (this.className && typeof this.className === 'string') {
const cn = this.className.toLowerCase();
if (cn.includes('ads') || cn.includes('banner') || cn.includes('adsbox')) {
return 250; // Fake height
}
}
return originalOffsetHeight.get.call(this);
}
});
Object.defineProperty(HTMLElement.prototype, 'offsetWidth', {
get: function() {
if (this.className && typeof this.className === 'string') {
const cn = this.className.toLowerCase();
if (cn.includes('ads') || cn.includes('banner') || cn.includes('adsbox')) {
return 300; // Fake width
}
}
return originalOffsetWidth.get.call(this);
}
});
// ==========================================
// CRYPTOCURRENCY MINER BLOCKING
// ==========================================
const MINER_DOMAINS = [
'coinhive.com', 'coin-hive.com', 'jsecoin.com', 'authedmine.com',
'cryptoloot.pro', 'crypto-loot.com', 'webmine.pro', 'ppoi.org',
'projectpoi.com', 'monerominer.rocks', 'webminepool.com',
'minero.cc', 'coinlab.biz', 'crypto.csgocpu.com', 'papoto.com',
'rocks.io', 'adminer.com', 'ad-miner.com', 'party-nngvitbizn.now.sh'
];
const MINER_SCRIPTS = [
'coinhive.min.js', 'miner.js', 'cryptonight.js', 'webminer.js',
'deepminer.js', 'coinlab.js', 'cryptoloot.js', 'minero.js',
'CoinHive', 'CryptoLoot', 'CryptoNoter', 'Miner', 'WebMiner'
];
// Block WebWorker miners
const originalWorker = window.Worker;
window.Worker = function(url, options) {
const urlStr = String(url).toLowerCase();
if (MINER_DOMAINS.some(d => urlStr.includes(d)) ||
MINER_SCRIPTS.some(s => urlStr.toLowerCase().includes(s.toLowerCase())) ||
urlStr.includes('miner') ||
urlStr.includes('crypto') ||
urlStr.includes('coin')) {
console.log('[AdBlocker] Blocked miner WebWorker:', urlStr.substring(0, 50));
// Return a dummy worker that does nothing
return {
postMessage: function() {},
terminate: function() {},
addEventListener: function() {},
removeEventListener: function() {},
onmessage: null,
onerror: null
};
}
return new originalWorker(url, options);
};
window.Worker.prototype = originalWorker.prototype;
// Block SharedWorker miners
if (window.SharedWorker) {
const originalSharedWorker = window.SharedWorker;
window.SharedWorker = function(url, options) {
const urlStr = String(url).toLowerCase();
if (MINER_DOMAINS.some(d => urlStr.includes(d)) ||
urlStr.includes('miner') || urlStr.includes('crypto')) {
console.log('[AdBlocker] Blocked miner SharedWorker');
return { port: { postMessage: function() {}, onmessage: null } };
}
return new originalSharedWorker(url, options);
};
}
// Block ServiceWorker miners
if (navigator.serviceWorker) {
const originalRegister = navigator.serviceWorker.register.bind(navigator.serviceWorker);
navigator.serviceWorker.register = function(url, options) {
const urlStr = String(url).toLowerCase();
if (MINER_DOMAINS.some(d => urlStr.includes(d)) ||
urlStr.includes('miner') || urlStr.includes('crypto')) {
console.log('[AdBlocker] Blocked miner ServiceWorker');
return Promise.reject(new Error('Miner blocked'));
}
return originalRegister(url, options);
};
}
// Block WebSocket miners
const originalWebSocket = window.WebSocket;
window.WebSocket = function(url, protocols) {
const urlStr = String(url).toLowerCase();
if (MINER_DOMAINS.some(d => urlStr.includes(d)) ||
urlStr.includes('miner') ||
urlStr.includes('stratum') ||
urlStr.includes('crypto') ||
urlStr.includes('pool')) {
console.log('[AdBlocker] Blocked miner WebSocket:', urlStr.substring(0, 50));
// Return a fake WebSocket that never connects
return {
send: function() {},
close: function() {},
addEventListener: function() {},
removeEventListener: function() {},
readyState: 3, // CLOSED
onopen: null,
onclose: null,
onmessage: null,
onerror: null
};
}
return new originalWebSocket(url, protocols);
};
window.WebSocket.prototype = originalWebSocket.prototype;
window.WebSocket.CONNECTING = 0;
window.WebSocket.OPEN = 1;
window.WebSocket.CLOSING = 2;
window.WebSocket.CLOSED = 3;
// Block WASM miners (WebAssembly for crypto mining)
const originalInstantiate = WebAssembly.instantiate;
const originalInstantiateStreaming = WebAssembly.instantiateStreaming;
// Check if WASM module looks like a miner
function isMinerWasm(bytes) {
// Miners typically have cryptonight/random-x patterns
// This is a heuristic check
try {
const arr = new Uint8Array(bytes);
// Check for known miner signatures in WASM
// CryptoNight signature patterns
const signature = arr.slice(0, 100).join(',');
return signature.includes('99,114,121,112,116') || // "crypt"
signature.includes('109,105,110,101,114'); // "miner"
} catch(e) {
return false;
}
}
WebAssembly.instantiate = async function(source, imports) {
if (source instanceof ArrayBuffer && isMinerWasm(source)) {
console.log('[AdBlocker] Blocked WASM miner');
throw new Error('WASM miner blocked');
}
return originalInstantiate.call(this, source, imports);
};
if (originalInstantiateStreaming) {
WebAssembly.instantiateStreaming = async function(source, imports) {
// Check URL if it's a Response
if (source && source.url) {
const url = source.url.toLowerCase();
if (MINER_DOMAINS.some(d => url.includes(d)) ||
url.includes('miner') || url.includes('crypto')) {
console.log('[AdBlocker] Blocked WASM streaming miner');
throw new Error('WASM miner blocked');
}
}
return originalInstantiateStreaming.call(this, source, imports);
};
}
// Block known miner global objects
const MINER_GLOBALS = [
'CoinHive', 'CryptoLoot', 'CryptoNoter', 'Coinimp', 'miner',
'ppoi', 'ProjectPoi', 'WebMiner', 'deepMiner', 'BrowserMiner',
'Client', 'Anonymous', 'CRLT'
];
MINER_GLOBALS.forEach(name => {
try {
Object.defineProperty(window, name, {
get: function() {
console.log('[AdBlocker] Blocked miner object:', name);
return undefined;
},
set: function() { return true; },
configurable: false
});
} catch(e) {}
});
// ==========================================
// WEBSOCKET AD BLOCKING
// ==========================================
const AD_WS_PATTERNS = [
/ads?[-._]/i, /pop(up|under)?[-._]/i, /track(er|ing)?[-._]/i,
/beacon[-._]/i, /analytics[-._]/i, /telemetry[-._]/i,
/doubleclick/i, /googlesyndication/i, /adservice/i
];
// Already blocked in WebSocket override above for miners
// This extends it for ad WebSockets
const wsOverride = window.WebSocket;
window.WebSocket = function(url, protocols) {
const urlStr = String(url).toLowerCase();
if (AD_WS_PATTERNS.some(p => p.test(urlStr))) {
console.log('[AdBlocker] Blocked ad WebSocket:', urlStr.substring(0, 50));
return {
send: function() {},
close: function() {},
addEventListener: function() {},
removeEventListener: function() {},
readyState: 3,
onopen: null, onclose: null, onmessage: null, onerror: null
};
}
return new wsOverride(url, protocols);
};
window.WebSocket.prototype = originalWebSocket.prototype;
window.WebSocket.CONNECTING = 0;
window.WebSocket.OPEN = 1;
window.WebSocket.CLOSING = 2;
window.WebSocket.CLOSED = 3;
console.log('[AdBlocker] Scriptlet injection active (enhanced)');
})();
`
});
// Also inject via evaluateOnNewDocument for redundancy
await page.evaluateOnNewDocument(() => {
// Mark that blocker is active
(window as any).__braveBlockerActive = true;
});
}