Skip to content

Commit 96e64b2

Browse files
ghostery-adblocker-bot[bot]Ghostery Adblocker Bot
andauthored
Update scriptlets (#34)
Co-authored-by: Ghostery Adblocker Bot <[email protected]>
1 parent 89ffb85 commit 96e64b2

File tree

2 files changed

+278
-51
lines changed

2 files changed

+278
-51
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.67.1b5 > ubo.js",
8+
"build": "deno build.ts --tagName 1.68.1b0 > ubo.js",
99
"test": "node --test"
1010
},
1111
"author": {

ubo.js

Lines changed: 277 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -19129,6 +19129,231 @@ noEvalIf(...args);
1912919129
};
1913019130

1913119131

19132+
scriptlets['prevent-dialog.js'] = {
19133+
aliases: [],
19134+
19135+
requiresTrust: false,
19136+
func: function (scriptletGlobals = {}, ...args) {
19137+
function safeSelf() {
19138+
if ( scriptletGlobals.safeSelf ) {
19139+
return scriptletGlobals.safeSelf;
19140+
}
19141+
const self = globalThis;
19142+
const safe = {
19143+
'Array_from': Array.from,
19144+
'Error': self.Error,
19145+
'Function_toStringFn': self.Function.prototype.toString,
19146+
'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg),
19147+
'Math_floor': Math.floor,
19148+
'Math_max': Math.max,
19149+
'Math_min': Math.min,
19150+
'Math_random': Math.random,
19151+
'Object': Object,
19152+
'Object_defineProperty': Object.defineProperty.bind(Object),
19153+
'Object_defineProperties': Object.defineProperties.bind(Object),
19154+
'Object_fromEntries': Object.fromEntries.bind(Object),
19155+
'Object_getOwnPropertyDescriptor': Object.getOwnPropertyDescriptor.bind(Object),
19156+
'Object_hasOwn': Object.hasOwn.bind(Object),
19157+
'RegExp': self.RegExp,
19158+
'RegExp_test': self.RegExp.prototype.test,
19159+
'RegExp_exec': self.RegExp.prototype.exec,
19160+
'Request_clone': self.Request.prototype.clone,
19161+
'String': self.String,
19162+
'String_fromCharCode': String.fromCharCode,
19163+
'String_split': String.prototype.split,
19164+
'XMLHttpRequest': self.XMLHttpRequest,
19165+
'addEventListener': self.EventTarget.prototype.addEventListener,
19166+
'removeEventListener': self.EventTarget.prototype.removeEventListener,
19167+
'fetch': self.fetch,
19168+
'JSON': self.JSON,
19169+
'JSON_parseFn': self.JSON.parse,
19170+
'JSON_stringifyFn': self.JSON.stringify,
19171+
'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args),
19172+
'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args),
19173+
'log': console.log.bind(console),
19174+
// Properties
19175+
logLevel: 0,
19176+
// Methods
19177+
makeLogPrefix(...args) {
19178+
return this.sendToLogger && `[${args.join(' \u205D ')}]` || '';
19179+
},
19180+
uboLog(...args) {
19181+
if ( this.sendToLogger === undefined ) { return; }
19182+
if ( args === undefined || args[0] === '' ) { return; }
19183+
return this.sendToLogger('info', ...args);
19184+
19185+
},
19186+
uboErr(...args) {
19187+
if ( this.sendToLogger === undefined ) { return; }
19188+
if ( args === undefined || args[0] === '' ) { return; }
19189+
return this.sendToLogger('error', ...args);
19190+
},
19191+
escapeRegexChars(s) {
19192+
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
19193+
},
19194+
initPattern(pattern, options = {}) {
19195+
if ( pattern === '' ) {
19196+
return { matchAll: true, expect: true };
19197+
}
19198+
const expect = (options.canNegate !== true || pattern.startsWith('!') === false);
19199+
if ( expect === false ) {
19200+
pattern = pattern.slice(1);
19201+
}
19202+
const match = /^\/(.+)\/([gimsu]*)$/.exec(pattern);
19203+
if ( match !== null ) {
19204+
return {
19205+
re: new this.RegExp(
19206+
match[1],
19207+
match[2] || options.flags
19208+
),
19209+
expect,
19210+
};
19211+
}
19212+
if ( options.flags !== undefined ) {
19213+
return {
19214+
re: new this.RegExp(this.escapeRegexChars(pattern),
19215+
options.flags
19216+
),
19217+
expect,
19218+
};
19219+
}
19220+
return { pattern, expect };
19221+
},
19222+
testPattern(details, haystack) {
19223+
if ( details.matchAll ) { return true; }
19224+
if ( details.re ) {
19225+
return this.RegExp_test.call(details.re, haystack) === details.expect;
19226+
}
19227+
return haystack.includes(details.pattern) === details.expect;
19228+
},
19229+
patternToRegex(pattern, flags = undefined, verbatim = false) {
19230+
if ( pattern === '' ) { return /^/; }
19231+
const match = /^\/(.+)\/([gimsu]*)$/.exec(pattern);
19232+
if ( match === null ) {
19233+
const reStr = this.escapeRegexChars(pattern);
19234+
return new RegExp(verbatim ? `^${reStr}$` : reStr, flags);
19235+
}
19236+
try {
19237+
return new RegExp(match[1], match[2] || undefined);
19238+
}
19239+
catch {
19240+
}
19241+
return /^/;
19242+
},
19243+
getExtraArgs(args, offset = 0) {
19244+
const entries = args.slice(offset).reduce((out, v, i, a) => {
19245+
if ( (i & 1) === 0 ) {
19246+
const rawValue = a[i+1];
19247+
const value = /^\d+$/.test(rawValue)
19248+
? parseInt(rawValue, 10)
19249+
: rawValue;
19250+
out.push([ a[i], value ]);
19251+
}
19252+
return out;
19253+
}, []);
19254+
return this.Object_fromEntries(entries);
19255+
},
19256+
onIdle(fn, options) {
19257+
if ( self.requestIdleCallback ) {
19258+
return self.requestIdleCallback(fn, options);
19259+
}
19260+
return self.requestAnimationFrame(fn);
19261+
},
19262+
offIdle(id) {
19263+
if ( self.requestIdleCallback ) {
19264+
return self.cancelIdleCallback(id);
19265+
}
19266+
return self.cancelAnimationFrame(id);
19267+
}
19268+
};
19269+
scriptletGlobals.safeSelf = safe;
19270+
if ( scriptletGlobals.bcSecret === undefined ) { return safe; }
19271+
// This is executed only when the logger is opened
19272+
safe.logLevel = scriptletGlobals.logLevel || 1;
19273+
let lastLogType = '';
19274+
let lastLogText = '';
19275+
let lastLogTime = 0;
19276+
safe.toLogText = (type, ...args) => {
19277+
if ( args.length === 0 ) { return; }
19278+
const text = `[${document.location.hostname || document.location.href}]${args.join(' ')}`;
19279+
if ( text === lastLogText && type === lastLogType ) {
19280+
if ( (Date.now() - lastLogTime) < 5000 ) { return; }
19281+
}
19282+
lastLogType = type;
19283+
lastLogText = text;
19284+
lastLogTime = Date.now();
19285+
return text;
19286+
};
19287+
try {
19288+
const bc = new self.BroadcastChannel(scriptletGlobals.bcSecret);
19289+
let bcBuffer = [];
19290+
safe.sendToLogger = (type, ...args) => {
19291+
const text = safe.toLogText(type, ...args);
19292+
if ( text === undefined ) { return; }
19293+
if ( bcBuffer === undefined ) {
19294+
return bc.postMessage({ what: 'messageToLogger', type, text });
19295+
}
19296+
bcBuffer.push({ type, text });
19297+
};
19298+
bc.onmessage = ev => {
19299+
const msg = ev.data;
19300+
switch ( msg ) {
19301+
case 'iamready!':
19302+
if ( bcBuffer === undefined ) { break; }
19303+
bcBuffer.forEach(({ type, text }) =>
19304+
bc.postMessage({ what: 'messageToLogger', type, text })
19305+
);
19306+
bcBuffer = undefined;
19307+
break;
19308+
case 'setScriptletLogLevelToOne':
19309+
safe.logLevel = 1;
19310+
break;
19311+
case 'setScriptletLogLevelToTwo':
19312+
safe.logLevel = 2;
19313+
break;
19314+
}
19315+
};
19316+
bc.postMessage('areyouready?');
19317+
} catch {
19318+
safe.sendToLogger = (type, ...args) => {
19319+
const text = safe.toLogText(type, ...args);
19320+
if ( text === undefined ) { return; }
19321+
safe.log(`uBO ${text}`);
19322+
};
19323+
}
19324+
return safe;
19325+
}
19326+
function preventDialog(
19327+
selector = '',
19328+
) {
19329+
const safe = safeSelf();
19330+
const logPrefix = safe.makeLogPrefix('prevent-dialog', selector);
19331+
const prevent = ( ) => {
19332+
debouncer = undefined;
19333+
const elems = document.querySelectorAll(`dialog${selector}`);
19334+
for ( const elem of elems ) {
19335+
if ( typeof elem.close !== 'function' ) { continue; }
19336+
if ( elem.open === false ) { continue; }
19337+
elem.close();
19338+
safe.uboLog(logPrefix, 'Closed');
19339+
}
19340+
};
19341+
let debouncer;
19342+
const observer = new MutationObserver(( ) => {
19343+
if ( debouncer !== undefined ) { return; }
19344+
debouncer = requestAnimationFrame(prevent);
19345+
});
19346+
observer.observe(document, {
19347+
attributes: true,
19348+
childList: true,
19349+
subtree: true,
19350+
});
19351+
};
19352+
preventDialog(...args);
19353+
},
19354+
};
19355+
19356+
1913219357
scriptlets['prevent-fetch.js'] = {
1913319358
aliases: ["no-fetch-if.js"],
1913419359

@@ -19547,40 +19772,41 @@ function preventFetchFn(
1954719772
responseProps.type = { value: responseType };
1954819773
}
1954919774
}
19775+
const fetchProps = (src, out) => {
19776+
if ( typeof src !== 'object' || src === null ) { return; }
19777+
const props = [
19778+
'body', 'cache', 'credentials', 'duplex', 'headers',
19779+
'integrity', 'keepalive', 'method', 'mode', 'priority',
19780+
'redirect', 'referrer', 'referrerPolicy', 'signal',
19781+
];
19782+
for ( const prop of props ) {
19783+
if ( src[prop] === undefined ) { continue; }
19784+
out[prop] = src[prop];
19785+
}
19786+
};
19787+
const fetchDetails = args => {
19788+
const out = {};
19789+
if ( args[0] instanceof self.Request ) {
19790+
out.url = `${args[0].url}`;
19791+
fetchProps(args[0], out);
19792+
} else {
19793+
out.url = `${args[0]}`;
19794+
}
19795+
fetchProps(args[1], out);
19796+
return out;
19797+
};
1955019798
proxyApplyFn('fetch', function fetch(context) {
1955119799
const { callArgs } = context;
19552-
const details = (( ) => {
19553-
const fetchProps = (src, out) => {
19554-
if ( typeof src !== 'object' || src === null ) { return; }
19555-
const props = [
19556-
'body', 'cache', 'credentials', 'duplex', 'headers',
19557-
'integrity', 'keepalive', 'method', 'mode', 'priority',
19558-
'redirect', 'referrer', 'referrerPolicy', 'signal',
19559-
];
19560-
for ( const prop of props ) {
19561-
if ( src[prop] === undefined ) { continue; }
19562-
out[prop] = src[prop];
19563-
}
19564-
};
19565-
const out = {};
19566-
if ( callArgs[0] instanceof self.Request ) {
19567-
out.url = `${callArgs[0].url}`;
19568-
fetchProps(callArgs[0], out);
19569-
} else {
19570-
out.url = `${callArgs[0]}`;
19571-
}
19572-
fetchProps(callArgs[1], out);
19573-
return out;
19574-
})();
19800+
const details = fetchDetails(callArgs);
1957519801
if ( safe.logLevel > 1 || propsToMatch === '' && responseBody === '' ) {
19576-
const out = Array.from(details).map(a => `${a[0]}:${a[1]}`);
19802+
const out = Array.from(Object.entries(details)).map(a => `${a[0]}:${a[1]}`);
1957719803
safe.uboLog(logPrefix, `Called: ${out.join('\n')}`);
1957819804
}
1957919805
if ( propsToMatch === '' && responseBody === '' ) {
1958019806
return context.reflect();
1958119807
}
1958219808
const matched = matchObjectPropertiesFn(propNeedles, details);
19583-
if ( matched === undefined ) {
19809+
if ( matched === undefined || matched.length === 0 ) {
1958419810
return context.reflect();
1958519811
}
1958619812
return Promise.resolve(generateContentFn(trusted, responseBody)).then(text => {
@@ -20030,40 +20256,41 @@ function preventFetchFn(
2003020256
responseProps.type = { value: responseType };
2003120257
}
2003220258
}
20259+
const fetchProps = (src, out) => {
20260+
if ( typeof src !== 'object' || src === null ) { return; }
20261+
const props = [
20262+
'body', 'cache', 'credentials', 'duplex', 'headers',
20263+
'integrity', 'keepalive', 'method', 'mode', 'priority',
20264+
'redirect', 'referrer', 'referrerPolicy', 'signal',
20265+
];
20266+
for ( const prop of props ) {
20267+
if ( src[prop] === undefined ) { continue; }
20268+
out[prop] = src[prop];
20269+
}
20270+
};
20271+
const fetchDetails = args => {
20272+
const out = {};
20273+
if ( args[0] instanceof self.Request ) {
20274+
out.url = `${args[0].url}`;
20275+
fetchProps(args[0], out);
20276+
} else {
20277+
out.url = `${args[0]}`;
20278+
}
20279+
fetchProps(args[1], out);
20280+
return out;
20281+
};
2003320282
proxyApplyFn('fetch', function fetch(context) {
2003420283
const { callArgs } = context;
20035-
const details = (( ) => {
20036-
const fetchProps = (src, out) => {
20037-
if ( typeof src !== 'object' || src === null ) { return; }
20038-
const props = [
20039-
'body', 'cache', 'credentials', 'duplex', 'headers',
20040-
'integrity', 'keepalive', 'method', 'mode', 'priority',
20041-
'redirect', 'referrer', 'referrerPolicy', 'signal',
20042-
];
20043-
for ( const prop of props ) {
20044-
if ( src[prop] === undefined ) { continue; }
20045-
out[prop] = src[prop];
20046-
}
20047-
};
20048-
const out = {};
20049-
if ( callArgs[0] instanceof self.Request ) {
20050-
out.url = `${callArgs[0].url}`;
20051-
fetchProps(callArgs[0], out);
20052-
} else {
20053-
out.url = `${callArgs[0]}`;
20054-
}
20055-
fetchProps(callArgs[1], out);
20056-
return out;
20057-
})();
20284+
const details = fetchDetails(callArgs);
2005820285
if ( safe.logLevel > 1 || propsToMatch === '' && responseBody === '' ) {
20059-
const out = Array.from(details).map(a => `${a[0]}:${a[1]}`);
20286+
const out = Array.from(Object.entries(details)).map(a => `${a[0]}:${a[1]}`);
2006020287
safe.uboLog(logPrefix, `Called: ${out.join('\n')}`);
2006120288
}
2006220289
if ( propsToMatch === '' && responseBody === '' ) {
2006320290
return context.reflect();
2006420291
}
2006520292
const matched = matchObjectPropertiesFn(propNeedles, details);
20066-
if ( matched === undefined ) {
20293+
if ( matched === undefined || matched.length === 0 ) {
2006720294
return context.reflect();
2006820295
}
2006920296
return Promise.resolve(generateContentFn(trusted, responseBody)).then(text => {

0 commit comments

Comments
 (0)