Skip to content

Commit 418087d

Browse files
committed
Improve no-xhr-if scriptlet
Now support AdGuard's `randomize` parameter. If `true`, the scriplet will generate a random 10-character string to be returned as the response. Reference: https://github.com/AdguardTeam/Scriptlets/blob/master/wiki/about-scriptlets.md#prevent-xhr AdGuard's `prevent-xhr` also support `length:n-m` form, but since I do not see it being used, for now it's not supported in uBO's `no-xhr-if`. Additionally, the scriptlet will now honor `responseType` and return the proper response type accordingly.
1 parent 21fe1c2 commit 418087d

File tree

1 file changed

+52
-43
lines changed

1 file changed

+52
-43
lines changed

assets/resources/scriptlets.js

Lines changed: 52 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1929,66 +1929,75 @@ builtinScriptlets.push({
19291929
],
19301930
fn: noXhrIf,
19311931
dependencies: [
1932-
'safe-self.fn',
1932+
'match-object-properties.fn',
1933+
'parse-properties-to-match.fn',
19331934
],
19341935
});
19351936
function noXhrIf(
1936-
arg1 = ''
1937+
propsToMatch = '',
1938+
randomize = ''
19371939
) {
1938-
if ( typeof arg1 !== 'string' ) { return; }
1939-
const safe = safeSelf();
1940+
if ( typeof propsToMatch !== 'string' ) { return; }
19401941
const xhrInstances = new WeakMap();
1941-
const needles = [];
1942-
for ( const condition of arg1.split(/\s+/) ) {
1943-
if ( condition === '' ) { continue; }
1944-
const pos = condition.indexOf(':');
1945-
let key, value;
1946-
if ( pos !== -1 ) {
1947-
key = condition.slice(0, pos);
1948-
value = condition.slice(pos + 1);
1949-
} else {
1950-
key = 'url';
1951-
value = condition;
1952-
}
1953-
needles.push({ key, re: safe.patternToRegex(value) });
1954-
}
1955-
const log = needles.length === 0 ? console.log.bind(console) : undefined;
1942+
const propNeedles = parsePropertiesToMatch(propsToMatch, 'url');
1943+
const log = propNeedles.size === 0 ? console.log.bind(console) : undefined;
19561944
self.XMLHttpRequest = class extends self.XMLHttpRequest {
1957-
open(...args) {
1945+
open(method, url, ...args) {
19581946
if ( log !== undefined ) {
1959-
log(`uBO: xhr.open(${args.join(', ')})`);
1947+
log(`uBO: xhr.open(${method}, ${url}, ${args.join(', ')})`);
19601948
} else {
1961-
const argNames = [ 'method', 'url' ];
1962-
const haystack = new Map();
1963-
for ( let i = 0; i < args.length && i < argNames.length; i++ ) {
1964-
haystack.set(argNames[i], args[i]);
1965-
}
1966-
if ( haystack.size !== 0 ) {
1967-
let matches = true;
1968-
for ( const { key, re } of needles ) {
1969-
matches = re.test(haystack.get(key) || '');
1970-
if ( matches === false ) { break; }
1971-
}
1972-
if ( matches ) {
1973-
xhrInstances.set(this, haystack);
1974-
}
1949+
const haystack = { method, url };
1950+
if ( matchObjectProperties(propNeedles, haystack) ) {
1951+
xhrInstances.set(this, haystack);
19751952
}
19761953
}
1977-
return super.open(...args);
1954+
return super.open(method, url, ...args);
19781955
}
19791956
send(...args) {
19801957
const haystack = xhrInstances.get(this);
19811958
if ( haystack === undefined ) {
19821959
return super.send(...args);
19831960
}
19841961
Object.defineProperties(this, {
1985-
readyState: { value: 4, writable: false },
1986-
response: { value: '', writable: false },
1987-
responseText: { value: '', writable: false },
1988-
responseURL: { value: haystack.get('url'), writable: false },
1989-
responseXML: { value: '', writable: false },
1990-
status: { value: 200, writable: false },
1991-
statusText: { value: 'OK', writable: false },
1962+
readyState: { value: 4 },
1963+
responseURL: { value: haystack.url },
1964+
status: { value: 200 },
1965+
statusText: { value: 'OK' },
1966+
});
1967+
let response = '';
1968+
let responseText = '';
1969+
let responseXML = null;
1970+
switch ( this.responseType ) {
1971+
case 'arraybuffer':
1972+
response = new ArrayBuffer(0);
1973+
break;
1974+
case 'blob':
1975+
response = new Blob([]);
1976+
break;
1977+
case 'document': {
1978+
const parser = new DOMParser();
1979+
const doc = parser.parseFromString('', 'text/html');
1980+
response = doc;
1981+
responseXML = doc;
1982+
break;
1983+
}
1984+
case 'json':
1985+
response = {};
1986+
responseText = '{}';
1987+
break;
1988+
default:
1989+
if ( randomize !== 'true' ) { break; }
1990+
do {
1991+
response += Math.random().toString(36).slice(-2);
1992+
} while ( response.length < 10 );
1993+
response = response.slice(-10);
1994+
responseText = response;
1995+
break;
1996+
}
1997+
Object.defineProperties(this, {
1998+
response: { value: response },
1999+
responseText: { value: responseText },
2000+
responseXML: { value: responseXML },
19922001
});
19932002
this.dispatchEvent(new Event('readystatechange'));
19942003
this.dispatchEvent(new Event('load'));

0 commit comments

Comments
 (0)