Improve `prevent-fetch` — return original url in response
- [ ] Return original URL
- [ ] Improve
Response.type- https://github.com/AdguardTeam/Scriptlets/issues/206#issuecomment-1158621281 (first part of the comment) - [ ] Fix issue with
:in URL - https://github.com/AdguardTeam/Scriptlets/issues/216#issuecomment-1178591463
At the moment, if prevent-fetch is used then Response.url returns empty string, but sometimes websites are checking Response.url to detect ad blockers.
Steps to reproduce
- Add this rule to user rules:
example.org#%#//scriptlet('prevent-fetch', 'pagead2.googlesyndication.com')
- Go to - https://example.org/
- Run this script:
(async () => {
const ads = "https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js";
const getAds = await fetch(ads);
if (getAds.status === 200 && getAds.url === ads) {
let video =
'<iframe width="560" height="315" src="https://www.youtube.com/embed/Fy2rtb95QhY" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>';
let createDiv = document.createElement("div");
document.body.appendChild(createDiv);
createDiv.innerHTML = video;
} else {
alert("Request blocked - AdBlock");
}
})();
Alert is displayed because getAds.url returns '', if request is not blocked then video player should be loaded.
What if would add fetchData.url as another argument in:
https://github.com/AdguardTeam/Scriptlets/blob/2a72d26aaca94c9e32bc30703beca43103935346/src/scriptlets/prevent-fetch.js#L133
something like:
noopPromiseResolve(strResponseBody, fetchData.url);
and add Object.defineProperty(response, 'url', { value: url, writable: false }); to:
https://github.com/AdguardTeam/Scriptlets/blob/af1d5ad03ff80ade59a990b45b71f6589db5ff99/src/helpers/noop.js#L59-L70
For example:
export const noopPromiseResolve = (responseBody = '{}', url) => {
if (typeof Response === 'undefined') {
return;
}
// eslint-disable-next-line compat/compat
const response = new Response(responseBody, {
status: 200,
statusText: 'OK',
});
Object.defineProperty(response, 'url', { value: url, writable: false });
// eslint-disable-next-line compat/compat, consistent-return
return Promise.resolve(response);
};
It should causes that original url will be returned.
One more thing.
If there is : in URL which we want to "block" then rule doesn't work correctly.
Steps to reproduce
- Add this rule:
example.org#%#//scriptlet("prevent-fetch", "/^https?:\/\/example\.org/")
- Go to - https://example.org/
- Run this script in console
fetch('https://example.org/', { method: 'GET' });
Request should be "blocked", but it isn't.
It works fine if I replace : with .:
example.org#%#//scriptlet("prevent-fetch", "/^https?.\/\/example\.org/")
As far as I understand, problem is in parseMatchProps function
https://github.com/AdguardTeam/Scriptlets/blob/3baf8d9468d9686f478c7492c21311dfc8c46b0f/src/scriptlets/prevent-fetch.js#L114
https://github.com/AdguardTeam/Scriptlets/blob/3baf8d9468d9686f478c7492c21311dfc8c46b0f/src/helpers/fetch-utils.js#L67-L86
because it splits /^https?:\/\/example\.org/ into /^https? and \/\/example\.org/, so it doesn't work like it should.
I suppose that it's for init options, like method or headers, but currently it also splits URL.
I guess that the same issue is with prevent-xhr.