Skip to content

Commit 552f05a

Browse files
author
Ghostery Adblocker Bot
committed
Update scriptlets
1 parent 4defe56 commit 552f05a

File tree

2 files changed

+263
-15
lines changed

2 files changed

+263
-15
lines changed

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.1b0 > ubo.js",
8+
"build": "deno build.ts --tagName 1.70.1b3 > ubo.js",
99
"test": "node --test"
1010
},
1111
"author": {

ubo.js

Lines changed: 262 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20113,7 +20113,7 @@ preventAddEventListener(...args);
2011320113

2011420114
scriptlets['prevent-dialog.js'] = {
2011520115
aliases: [],
20116-
20116+
world: 'ISOLATED',
2011720117
requiresTrust: false,
2011820118
func: function (scriptletGlobals = {}, ...args) {
2011920119
function safeSelf() {
@@ -21369,7 +21369,7 @@ trustedPreventFetch(...args);
2136921369
};
2137021370

2137121371

21372-
scriptlets['prevent-innerHTML.js'] = {
21372+
scriptlets['freeze-element-property.js'] = {
2137321373
aliases: [],
2137421374

2137521375
requiresTrust: false,
@@ -21564,14 +21564,25 @@ function safeSelf() {
2156421564
}
2156521565
return safe;
2156621566
}
21567-
function preventInnerHTML(
21567+
function freezeElementProperty(
21568+
property = '',
2156821569
selector = '',
2156921570
pattern = ''
2157021571
) {
2157121572
const safe = safeSelf();
21572-
const logPrefix = safe.makeLogPrefix('prevent-innerHTML', selector, pattern);
21573+
const logPrefix = safe.makeLogPrefix('freeze-element-property', property, selector, pattern);
2157321574
const matcher = safe.initPattern(pattern, { canNegate: true });
21574-
const current = safe.Object_getOwnPropertyDescriptor(Element.prototype, 'innerHTML');
21575+
const owner = (( ) => {
21576+
if ( Object.hasOwn(Element.prototype, property) ) {
21577+
return Element.prototype;
21578+
}
21579+
if ( Object.hasOwn(HTMLElement.prototype, property) ) {
21580+
return HTMLElement.prototype;
21581+
}
21582+
return null;
21583+
})();
21584+
if ( owner === null ) { return; }
21585+
const current = safe.Object_getOwnPropertyDescriptor(owner, property);
2157521586
if ( current === undefined ) { return; }
2157621587
const shouldPreventSet = (elem, a) => {
2157721588
if ( selector !== '' ) {
@@ -21580,15 +21591,15 @@ function preventInnerHTML(
2158021591
}
2158121592
return safe.testPattern(matcher, `${a}`);
2158221593
};
21583-
Object.defineProperty(Element.prototype, 'innerHTML', {
21594+
Object.defineProperty(owner, property, {
2158421595
get: function() {
2158521596
return current.get
2158621597
? current.get.call(this)
2158721598
: current.value;
2158821599
},
2158921600
set: function(a) {
2159021601
if ( shouldPreventSet(this, a) ) {
21591-
safe.uboLog(logPrefix, 'Prevented');
21602+
safe.uboLog(logPrefix, 'Assignment prevented');
2159221603
} else if ( current.set ) {
2159321604
current.set.call(this, a);
2159421605
}
@@ -21599,12 +21610,12 @@ function preventInnerHTML(
2159921610
},
2160021611
});
2160121612
};
21602-
preventInnerHTML(...args);
21613+
freezeElementProperty(...args);
2160321614
},
2160421615
};
2160521616

2160621617

21607-
scriptlets['prevent-textContent.js'] = {
21618+
scriptlets['prevent-innerHTML.js'] = {
2160821619
aliases: [],
2160921620

2161021621
requiresTrust: false,
@@ -21799,14 +21810,25 @@ function safeSelf() {
2179921810
}
2180021811
return safe;
2180121812
}
21802-
function preventInnerHTML(
21813+
function freezeElementProperty(
21814+
property = '',
2180321815
selector = '',
2180421816
pattern = ''
2180521817
) {
2180621818
const safe = safeSelf();
21807-
const logPrefix = safe.makeLogPrefix('prevent-innerHTML', selector, pattern);
21819+
const logPrefix = safe.makeLogPrefix('freeze-element-property', property, selector, pattern);
2180821820
const matcher = safe.initPattern(pattern, { canNegate: true });
21809-
const current = safe.Object_getOwnPropertyDescriptor(Element.prototype, 'innerHTML');
21821+
const owner = (( ) => {
21822+
if ( Object.hasOwn(Element.prototype, property) ) {
21823+
return Element.prototype;
21824+
}
21825+
if ( Object.hasOwn(HTMLElement.prototype, property) ) {
21826+
return HTMLElement.prototype;
21827+
}
21828+
return null;
21829+
})();
21830+
if ( owner === null ) { return; }
21831+
const current = safe.Object_getOwnPropertyDescriptor(owner, property);
2181021832
if ( current === undefined ) { return; }
2181121833
const shouldPreventSet = (elem, a) => {
2181221834
if ( selector !== '' ) {
@@ -21815,15 +21837,15 @@ function preventInnerHTML(
2181521837
}
2181621838
return safe.testPattern(matcher, `${a}`);
2181721839
};
21818-
Object.defineProperty(Element.prototype, 'innerHTML', {
21840+
Object.defineProperty(owner, property, {
2181921841
get: function() {
2182021842
return current.get
2182121843
? current.get.call(this)
2182221844
: current.value;
2182321845
},
2182421846
set: function(a) {
2182521847
if ( shouldPreventSet(this, a) ) {
21826-
safe.uboLog(logPrefix, 'Prevented');
21848+
safe.uboLog(logPrefix, 'Assignment prevented');
2182721849
} else if ( current.set ) {
2182821850
current.set.call(this, a);
2182921851
}
@@ -21833,12 +21855,238 @@ function preventInnerHTML(
2183321855
current.value = a;
2183421856
},
2183521857
});
21858+
}
21859+
function preventInnerHTML(
21860+
selector = '',
21861+
pattern = ''
21862+
) {
21863+
freezeElementProperty('innerHTML', selector, pattern);
2183621864
};
2183721865
preventInnerHTML(...args);
2183821866
},
2183921867
};
2184021868

2184121869

21870+
scriptlets['prevent-navigation.js'] = {
21871+
aliases: [],
21872+
world: 'ISOLATED',
21873+
requiresTrust: false,
21874+
func: function (scriptletGlobals = {}, ...args) {
21875+
function safeSelf() {
21876+
if ( scriptletGlobals.safeSelf ) {
21877+
return scriptletGlobals.safeSelf;
21878+
}
21879+
const self = globalThis;
21880+
const safe = {
21881+
'Array_from': Array.from,
21882+
'Error': self.Error,
21883+
'Function_toStringFn': self.Function.prototype.toString,
21884+
'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg),
21885+
'Math_floor': Math.floor,
21886+
'Math_max': Math.max,
21887+
'Math_min': Math.min,
21888+
'Math_random': Math.random,
21889+
'Object': Object,
21890+
'Object_defineProperty': Object.defineProperty.bind(Object),
21891+
'Object_defineProperties': Object.defineProperties.bind(Object),
21892+
'Object_fromEntries': Object.fromEntries.bind(Object),
21893+
'Object_getOwnPropertyDescriptor': Object.getOwnPropertyDescriptor.bind(Object),
21894+
'Object_hasOwn': Object.hasOwn.bind(Object),
21895+
'Object_toString': Object.prototype.toString,
21896+
'RegExp': self.RegExp,
21897+
'RegExp_test': self.RegExp.prototype.test,
21898+
'RegExp_exec': self.RegExp.prototype.exec,
21899+
'Request_clone': self.Request.prototype.clone,
21900+
'String': self.String,
21901+
'String_fromCharCode': String.fromCharCode,
21902+
'String_split': String.prototype.split,
21903+
'XMLHttpRequest': self.XMLHttpRequest,
21904+
'addEventListener': self.EventTarget.prototype.addEventListener,
21905+
'removeEventListener': self.EventTarget.prototype.removeEventListener,
21906+
'fetch': self.fetch,
21907+
'JSON': self.JSON,
21908+
'JSON_parseFn': self.JSON.parse,
21909+
'JSON_stringifyFn': self.JSON.stringify,
21910+
'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args),
21911+
'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args),
21912+
'log': console.log.bind(console),
21913+
// Properties
21914+
logLevel: 0,
21915+
// Methods
21916+
makeLogPrefix(...args) {
21917+
return this.sendToLogger && `[${args.join(' \u205D ')}]` || '';
21918+
},
21919+
uboLog(...args) {
21920+
if ( this.sendToLogger === undefined ) { return; }
21921+
if ( args === undefined || args[0] === '' ) { return; }
21922+
return this.sendToLogger('info', ...args);
21923+
21924+
},
21925+
uboErr(...args) {
21926+
if ( this.sendToLogger === undefined ) { return; }
21927+
if ( args === undefined || args[0] === '' ) { return; }
21928+
return this.sendToLogger('error', ...args);
21929+
},
21930+
escapeRegexChars(s) {
21931+
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
21932+
},
21933+
initPattern(pattern, options = {}) {
21934+
if ( pattern === '' ) {
21935+
return { matchAll: true, expect: true };
21936+
}
21937+
const expect = (options.canNegate !== true || pattern.startsWith('!') === false);
21938+
if ( expect === false ) {
21939+
pattern = pattern.slice(1);
21940+
}
21941+
const match = /^\/(.+)\/([gimsu]*)$/.exec(pattern);
21942+
if ( match !== null ) {
21943+
return {
21944+
re: new this.RegExp(
21945+
match[1],
21946+
match[2] || options.flags
21947+
),
21948+
expect,
21949+
};
21950+
}
21951+
if ( options.flags !== undefined ) {
21952+
return {
21953+
re: new this.RegExp(this.escapeRegexChars(pattern),
21954+
options.flags
21955+
),
21956+
expect,
21957+
};
21958+
}
21959+
return { pattern, expect };
21960+
},
21961+
testPattern(details, haystack) {
21962+
if ( details.matchAll ) { return true; }
21963+
if ( details.re ) {
21964+
return this.RegExp_test.call(details.re, haystack) === details.expect;
21965+
}
21966+
return haystack.includes(details.pattern) === details.expect;
21967+
},
21968+
patternToRegex(pattern, flags = undefined, verbatim = false) {
21969+
if ( pattern === '' ) { return /^/; }
21970+
const match = /^\/(.+)\/([gimsu]*)$/.exec(pattern);
21971+
if ( match === null ) {
21972+
const reStr = this.escapeRegexChars(pattern);
21973+
return new RegExp(verbatim ? `^${reStr}$` : reStr, flags);
21974+
}
21975+
try {
21976+
return new RegExp(match[1], match[2] || undefined);
21977+
}
21978+
catch {
21979+
}
21980+
return /^/;
21981+
},
21982+
getExtraArgs(args, offset = 0) {
21983+
const entries = args.slice(offset).reduce((out, v, i, a) => {
21984+
if ( (i & 1) === 0 ) {
21985+
const rawValue = a[i+1];
21986+
const value = /^\d+$/.test(rawValue)
21987+
? parseInt(rawValue, 10)
21988+
: rawValue;
21989+
out.push([ a[i], value ]);
21990+
}
21991+
return out;
21992+
}, []);
21993+
return this.Object_fromEntries(entries);
21994+
},
21995+
onIdle(fn, options) {
21996+
if ( self.requestIdleCallback ) {
21997+
return self.requestIdleCallback(fn, options);
21998+
}
21999+
return self.requestAnimationFrame(fn);
22000+
},
22001+
offIdle(id) {
22002+
if ( self.requestIdleCallback ) {
22003+
return self.cancelIdleCallback(id);
22004+
}
22005+
return self.cancelAnimationFrame(id);
22006+
}
22007+
};
22008+
scriptletGlobals.safeSelf = safe;
22009+
if ( scriptletGlobals.bcSecret === undefined ) { return safe; }
22010+
// This is executed only when the logger is opened
22011+
safe.logLevel = scriptletGlobals.logLevel || 1;
22012+
let lastLogType = '';
22013+
let lastLogText = '';
22014+
let lastLogTime = 0;
22015+
safe.toLogText = (type, ...args) => {
22016+
if ( args.length === 0 ) { return; }
22017+
const text = `[${document.location.hostname || document.location.href}]${args.join(' ')}`;
22018+
if ( text === lastLogText && type === lastLogType ) {
22019+
if ( (Date.now() - lastLogTime) < 5000 ) { return; }
22020+
}
22021+
lastLogType = type;
22022+
lastLogText = text;
22023+
lastLogTime = Date.now();
22024+
return text;
22025+
};
22026+
try {
22027+
const bc = new self.BroadcastChannel(scriptletGlobals.bcSecret);
22028+
let bcBuffer = [];
22029+
safe.sendToLogger = (type, ...args) => {
22030+
const text = safe.toLogText(type, ...args);
22031+
if ( text === undefined ) { return; }
22032+
if ( bcBuffer === undefined ) {
22033+
return bc.postMessage({ what: 'messageToLogger', type, text });
22034+
}
22035+
bcBuffer.push({ type, text });
22036+
};
22037+
bc.onmessage = ev => {
22038+
const msg = ev.data;
22039+
switch ( msg ) {
22040+
case 'iamready!':
22041+
if ( bcBuffer === undefined ) { break; }
22042+
bcBuffer.forEach(({ type, text }) =>
22043+
bc.postMessage({ what: 'messageToLogger', type, text })
22044+
);
22045+
bcBuffer = undefined;
22046+
break;
22047+
case 'setScriptletLogLevelToOne':
22048+
safe.logLevel = 1;
22049+
break;
22050+
case 'setScriptletLogLevelToTwo':
22051+
safe.logLevel = 2;
22052+
break;
22053+
}
22054+
};
22055+
bc.postMessage('areyouready?');
22056+
} catch {
22057+
safe.sendToLogger = (type, ...args) => {
22058+
const text = safe.toLogText(type, ...args);
22059+
if ( text === undefined ) { return; }
22060+
safe.log(`uBO ${text}`);
22061+
};
22062+
}
22063+
return safe;
22064+
}
22065+
function preventNavigation(
22066+
pattern = ''
22067+
) {
22068+
const safe = safeSelf();
22069+
const logPrefix = safe.makeLogPrefix('prevent-navigation', pattern);
22070+
const needle = pattern === 'location.href' ? self.location.href : pattern;
22071+
const matcher = safe.initPattern(needle, { canNegate: true });
22072+
self.navigation.addEventListener('navigate', ev => {
22073+
if ( ev.userInitiated ) { return; }
22074+
const { url } = ev.destination;
22075+
if ( pattern === '' ) {
22076+
safe.uboLog(logPrefix, `Navigation to ${url}`);
22077+
return;
22078+
}
22079+
if ( safe.testPattern(matcher, url) ) {
22080+
ev.preventDefault();
22081+
safe.uboLog(logPrefix, `Prevented navigation to ${url}`);
22082+
}
22083+
});
22084+
};
22085+
preventNavigation(...args);
22086+
},
22087+
};
22088+
22089+
2184222090
scriptlets['prevent-setTimeout.js'] = {
2184322091
aliases: ["no-setTimeout-if.js","nostif.js","setTimeout-defuser.js"],
2184422092

0 commit comments

Comments
 (0)