Skip to content

Commit 4defe56

Browse files
ghostery-adblocker-bot[bot]Ghostery Adblocker Bot
andauthored
Update scriptlets (#46)
Co-authored-by: Ghostery Adblocker Bot <ghostery-adblocker-bot@users.noreply.github.com>
1 parent 9246c75 commit 4defe56

2 files changed

Lines changed: 237 additions & 2 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"main": "index.js",
66
"type": "module",
77
"scripts": {
8-
"build": "deno build.ts --tagName 1.70.0 > ubo.js",
8+
"build": "deno build.ts --tagName 1.70.1b0 > ubo.js",
99
"test": "node --test"
1010
},
1111
"author": {

ubo.js

Lines changed: 236 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1184,7 +1184,7 @@ function trustedCreateHTML(
11841184
// We do not want to recursively create elements
11851185
self.trustedCreateHTML = true;
11861186
let ancestor = self.frameElement;
1187-
while ( ancestor !== null ) {
1187+
while ( ancestor ) {
11881188
const doc = ancestor.ownerDocument;
11891189
if ( doc === null ) { break; }
11901190
const win = doc.defaultView;
@@ -21604,6 +21604,241 @@ preventInnerHTML(...args);
2160421604
};
2160521605

2160621606

21607+
scriptlets['prevent-textContent.js'] = {
21608+
aliases: [],
21609+
21610+
requiresTrust: false,
21611+
func: function (scriptletGlobals = {}, ...args) {
21612+
function safeSelf() {
21613+
if ( scriptletGlobals.safeSelf ) {
21614+
return scriptletGlobals.safeSelf;
21615+
}
21616+
const self = globalThis;
21617+
const safe = {
21618+
'Array_from': Array.from,
21619+
'Error': self.Error,
21620+
'Function_toStringFn': self.Function.prototype.toString,
21621+
'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg),
21622+
'Math_floor': Math.floor,
21623+
'Math_max': Math.max,
21624+
'Math_min': Math.min,
21625+
'Math_random': Math.random,
21626+
'Object': Object,
21627+
'Object_defineProperty': Object.defineProperty.bind(Object),
21628+
'Object_defineProperties': Object.defineProperties.bind(Object),
21629+
'Object_fromEntries': Object.fromEntries.bind(Object),
21630+
'Object_getOwnPropertyDescriptor': Object.getOwnPropertyDescriptor.bind(Object),
21631+
'Object_hasOwn': Object.hasOwn.bind(Object),
21632+
'Object_toString': Object.prototype.toString,
21633+
'RegExp': self.RegExp,
21634+
'RegExp_test': self.RegExp.prototype.test,
21635+
'RegExp_exec': self.RegExp.prototype.exec,
21636+
'Request_clone': self.Request.prototype.clone,
21637+
'String': self.String,
21638+
'String_fromCharCode': String.fromCharCode,
21639+
'String_split': String.prototype.split,
21640+
'XMLHttpRequest': self.XMLHttpRequest,
21641+
'addEventListener': self.EventTarget.prototype.addEventListener,
21642+
'removeEventListener': self.EventTarget.prototype.removeEventListener,
21643+
'fetch': self.fetch,
21644+
'JSON': self.JSON,
21645+
'JSON_parseFn': self.JSON.parse,
21646+
'JSON_stringifyFn': self.JSON.stringify,
21647+
'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args),
21648+
'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args),
21649+
'log': console.log.bind(console),
21650+
// Properties
21651+
logLevel: 0,
21652+
// Methods
21653+
makeLogPrefix(...args) {
21654+
return this.sendToLogger && `[${args.join(' \u205D ')}]` || '';
21655+
},
21656+
uboLog(...args) {
21657+
if ( this.sendToLogger === undefined ) { return; }
21658+
if ( args === undefined || args[0] === '' ) { return; }
21659+
return this.sendToLogger('info', ...args);
21660+
21661+
},
21662+
uboErr(...args) {
21663+
if ( this.sendToLogger === undefined ) { return; }
21664+
if ( args === undefined || args[0] === '' ) { return; }
21665+
return this.sendToLogger('error', ...args);
21666+
},
21667+
escapeRegexChars(s) {
21668+
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
21669+
},
21670+
initPattern(pattern, options = {}) {
21671+
if ( pattern === '' ) {
21672+
return { matchAll: true, expect: true };
21673+
}
21674+
const expect = (options.canNegate !== true || pattern.startsWith('!') === false);
21675+
if ( expect === false ) {
21676+
pattern = pattern.slice(1);
21677+
}
21678+
const match = /^\/(.+)\/([gimsu]*)$/.exec(pattern);
21679+
if ( match !== null ) {
21680+
return {
21681+
re: new this.RegExp(
21682+
match[1],
21683+
match[2] || options.flags
21684+
),
21685+
expect,
21686+
};
21687+
}
21688+
if ( options.flags !== undefined ) {
21689+
return {
21690+
re: new this.RegExp(this.escapeRegexChars(pattern),
21691+
options.flags
21692+
),
21693+
expect,
21694+
};
21695+
}
21696+
return { pattern, expect };
21697+
},
21698+
testPattern(details, haystack) {
21699+
if ( details.matchAll ) { return true; }
21700+
if ( details.re ) {
21701+
return this.RegExp_test.call(details.re, haystack) === details.expect;
21702+
}
21703+
return haystack.includes(details.pattern) === details.expect;
21704+
},
21705+
patternToRegex(pattern, flags = undefined, verbatim = false) {
21706+
if ( pattern === '' ) { return /^/; }
21707+
const match = /^\/(.+)\/([gimsu]*)$/.exec(pattern);
21708+
if ( match === null ) {
21709+
const reStr = this.escapeRegexChars(pattern);
21710+
return new RegExp(verbatim ? `^${reStr}$` : reStr, flags);
21711+
}
21712+
try {
21713+
return new RegExp(match[1], match[2] || undefined);
21714+
}
21715+
catch {
21716+
}
21717+
return /^/;
21718+
},
21719+
getExtraArgs(args, offset = 0) {
21720+
const entries = args.slice(offset).reduce((out, v, i, a) => {
21721+
if ( (i & 1) === 0 ) {
21722+
const rawValue = a[i+1];
21723+
const value = /^\d+$/.test(rawValue)
21724+
? parseInt(rawValue, 10)
21725+
: rawValue;
21726+
out.push([ a[i], value ]);
21727+
}
21728+
return out;
21729+
}, []);
21730+
return this.Object_fromEntries(entries);
21731+
},
21732+
onIdle(fn, options) {
21733+
if ( self.requestIdleCallback ) {
21734+
return self.requestIdleCallback(fn, options);
21735+
}
21736+
return self.requestAnimationFrame(fn);
21737+
},
21738+
offIdle(id) {
21739+
if ( self.requestIdleCallback ) {
21740+
return self.cancelIdleCallback(id);
21741+
}
21742+
return self.cancelAnimationFrame(id);
21743+
}
21744+
};
21745+
scriptletGlobals.safeSelf = safe;
21746+
if ( scriptletGlobals.bcSecret === undefined ) { return safe; }
21747+
// This is executed only when the logger is opened
21748+
safe.logLevel = scriptletGlobals.logLevel || 1;
21749+
let lastLogType = '';
21750+
let lastLogText = '';
21751+
let lastLogTime = 0;
21752+
safe.toLogText = (type, ...args) => {
21753+
if ( args.length === 0 ) { return; }
21754+
const text = `[${document.location.hostname || document.location.href}]${args.join(' ')}`;
21755+
if ( text === lastLogText && type === lastLogType ) {
21756+
if ( (Date.now() - lastLogTime) < 5000 ) { return; }
21757+
}
21758+
lastLogType = type;
21759+
lastLogText = text;
21760+
lastLogTime = Date.now();
21761+
return text;
21762+
};
21763+
try {
21764+
const bc = new self.BroadcastChannel(scriptletGlobals.bcSecret);
21765+
let bcBuffer = [];
21766+
safe.sendToLogger = (type, ...args) => {
21767+
const text = safe.toLogText(type, ...args);
21768+
if ( text === undefined ) { return; }
21769+
if ( bcBuffer === undefined ) {
21770+
return bc.postMessage({ what: 'messageToLogger', type, text });
21771+
}
21772+
bcBuffer.push({ type, text });
21773+
};
21774+
bc.onmessage = ev => {
21775+
const msg = ev.data;
21776+
switch ( msg ) {
21777+
case 'iamready!':
21778+
if ( bcBuffer === undefined ) { break; }
21779+
bcBuffer.forEach(({ type, text }) =>
21780+
bc.postMessage({ what: 'messageToLogger', type, text })
21781+
);
21782+
bcBuffer = undefined;
21783+
break;
21784+
case 'setScriptletLogLevelToOne':
21785+
safe.logLevel = 1;
21786+
break;
21787+
case 'setScriptletLogLevelToTwo':
21788+
safe.logLevel = 2;
21789+
break;
21790+
}
21791+
};
21792+
bc.postMessage('areyouready?');
21793+
} catch {
21794+
safe.sendToLogger = (type, ...args) => {
21795+
const text = safe.toLogText(type, ...args);
21796+
if ( text === undefined ) { return; }
21797+
safe.log(`uBO ${text}`);
21798+
};
21799+
}
21800+
return safe;
21801+
}
21802+
function preventInnerHTML(
21803+
selector = '',
21804+
pattern = ''
21805+
) {
21806+
const safe = safeSelf();
21807+
const logPrefix = safe.makeLogPrefix('prevent-innerHTML', selector, pattern);
21808+
const matcher = safe.initPattern(pattern, { canNegate: true });
21809+
const current = safe.Object_getOwnPropertyDescriptor(Element.prototype, 'innerHTML');
21810+
if ( current === undefined ) { return; }
21811+
const shouldPreventSet = (elem, a) => {
21812+
if ( selector !== '' ) {
21813+
if ( typeof elem.matches !== 'function' ) { return false; }
21814+
if ( elem.matches(selector) === false ) { return false; }
21815+
}
21816+
return safe.testPattern(matcher, `${a}`);
21817+
};
21818+
Object.defineProperty(Element.prototype, 'innerHTML', {
21819+
get: function() {
21820+
return current.get
21821+
? current.get.call(this)
21822+
: current.value;
21823+
},
21824+
set: function(a) {
21825+
if ( shouldPreventSet(this, a) ) {
21826+
safe.uboLog(logPrefix, 'Prevented');
21827+
} else if ( current.set ) {
21828+
current.set.call(this, a);
21829+
}
21830+
if ( safe.logLevel > 1 ) {
21831+
safe.uboLog(logPrefix, `Assigned:\n${a}`);
21832+
}
21833+
current.value = a;
21834+
},
21835+
});
21836+
};
21837+
preventInnerHTML(...args);
21838+
},
21839+
};
21840+
21841+
2160721842
scriptlets['prevent-setTimeout.js'] = {
2160821843
aliases: ["no-setTimeout-if.js","nostif.js","setTimeout-defuser.js"],
2160921844

0 commit comments

Comments
 (0)