Skip to content

Commit e785b99

Browse files
committed
Improve prevent-fetch scriptlet
Related discussion: uBlockOrigin/uBlock-discussions#848 (comment) Added support for AdGuard's `responseType` parameter. Extended the meaning of that 3rd parameter to also be a JSON string with properties to set on the returned response instance. Currently supported properties: - `ok`, supported values: `false`, `true` - `type, supported values: `"basic"`, `"cors"`, `"opaque"` Reference: https://github.com/AdguardTeam/Scriptlets/blob/master/wiki/about-scriptlets.md#-%EF%B8%8F-prevent-fetch
1 parent a54d416 commit e785b99

File tree

1 file changed

+29
-22
lines changed

1 file changed

+29
-22
lines changed

assets/resources/scriptlets.js

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ function safeSelf() {
5757
'Math_random': Math.random,
5858
'Object': Object,
5959
'Object_defineProperty': Object.defineProperty.bind(Object),
60+
'Object_defineProperties': Object.defineProperties.bind(Object),
6061
'Object_fromEntries': Object.fromEntries.bind(Object),
6162
'Object_getOwnPropertyDescriptor': Object.getOwnPropertyDescriptor.bind(Object),
6263
'RegExp': self.RegExp,
@@ -2067,11 +2068,11 @@ builtinScriptlets.push({
20672068
});
20682069
function noFetchIf(
20692070
propsToMatch = '',
2070-
responseBody = ''
2071+
responseBody = '',
2072+
responseType = ''
20712073
) {
2072-
if ( typeof propsToMatch !== 'string' ) { return; }
20732074
const safe = safeSelf();
2074-
const logPrefix = safe.makeLogPrefix('prevent-fetch', propsToMatch, responseBody);
2075+
const logPrefix = safe.makeLogPrefix('prevent-fetch', propsToMatch, responseBody, responseType);
20752076
const needles = [];
20762077
for ( const condition of propsToMatch.split(/\s+/) ) {
20772078
if ( condition === '' ) { continue; }
@@ -2086,6 +2087,26 @@ function noFetchIf(
20862087
}
20872088
needles.push({ key, re: safe.patternToRegex(value) });
20882089
}
2090+
const validResponseProps = {
2091+
ok: [ false, true ],
2092+
type: [ 'basic', 'cors', 'opaque' ],
2093+
};
2094+
let responseProps;
2095+
if ( /^\{.*\}$/.test(responseType) ) {
2096+
responseProps = {};
2097+
try {
2098+
Object.entries(JSON.parse(responseType)).forEach(([ p, v ]) => {
2099+
if ( validResponseProps[p] === undefined ) { return; }
2100+
if ( validResponseProps[p].includes(v) === false ) { return; }
2101+
responseProps[p] = { value: v };
2102+
});
2103+
}
2104+
catch(ex) {}
2105+
} else if ( responseType !== '' ) {
2106+
if ( validResponseProps.type.includes(responseType) ) {
2107+
responseProps = { type: { value: responseType } };
2108+
}
2109+
}
20892110
self.fetch = new Proxy(self.fetch, {
20902111
apply: function(target, thisArg, args) {
20912112
const details = args[0] instanceof self.Request
@@ -2123,17 +2144,6 @@ function noFetchIf(
21232144
if ( proceed ) {
21242145
return Reflect.apply(target, thisArg, args);
21252146
}
2126-
let responseType = '';
2127-
if ( details.mode === undefined || details.mode === 'cors' ) {
2128-
try {
2129-
const desURL = new URL(details.url);
2130-
responseType = desURL.origin !== document.location.origin
2131-
? 'cors'
2132-
: 'basic';
2133-
} catch(ex) {
2134-
safe.uboErr(logPrefix, `Error: ${ex}`);
2135-
}
2136-
}
21372147
return generateContentFn(responseBody).then(text => {
21382148
safe.uboLog(logPrefix, `Prevented with response "${text}"`);
21392149
const response = new Response(text, {
@@ -2142,14 +2152,11 @@ function noFetchIf(
21422152
'Content-Length': text.length,
21432153
}
21442154
});
2145-
safe.Object_defineProperty(response, 'url', {
2146-
value: details.url
2147-
});
2148-
if ( responseType !== '' ) {
2149-
safe.Object_defineProperty(response, 'type', {
2150-
value: responseType
2151-
});
2152-
}
2155+
const props = Object.assign(
2156+
{ url: { value: details.url } },
2157+
responseProps
2158+
);
2159+
safe.Object_defineProperties(response, props);
21532160
return response;
21542161
});
21552162
}

0 commit comments

Comments
 (0)