Skip to content

Commit

Permalink
Improve trusted-replace-fetch-response — do not replace content if UR…
Browse files Browse the repository at this point in the history
…L is set by Object.defineProperty
  • Loading branch information
AdamWr committed Oct 12, 2023
1 parent 6211520 commit 6deea9d
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 1 deletion.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed

- issue with `trusted-replace-fetch-response` scriptlet in case if data URL was used and properties was set by
`Object.defineProperty` to deceive scriptlet [#367](https://github.com/AdguardTeam/Scriptlets/issues/367)
- issue with adding the same header value in `trusted-replace-xhr-response` scriptlet
when it is used multiple times for the same request [#359](https://github.com/AdguardTeam/Scriptlets/issues/359)
- issue with not pruning in `m3u-prune` scriptlet if file contains carriage return
Expand Down
6 changes: 5 additions & 1 deletion src/helpers/request-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,17 @@ export const getRequestData = (request: Request): Partial<Request> => {
* @returns data object
*/
export const getFetchData = (args: [FetchResource, RequestInit]) => {
const requestClone = Request.prototype.clone;
const fetchPropsObj: Record<string, unknown> = {};

let fetchUrl: FetchResource;
let fetchInit: RequestInit;
if (args[0] instanceof Request) {
// Get real properties in case if data URL was used properties were set by Object.defineProperty
// https://github.com/AdguardTeam/Scriptlets/issues/367
const realData = requestClone.call(args[0]);
// if Request passed to fetch, it will be in array
const requestData = getRequestData(args[0]);
const requestData = getRequestData(realData);
fetchUrl = requestData.url as string;
fetchInit = requestData;
} else {
Expand Down
46 changes: 46 additions & 0 deletions tests/scriptlets/trusted-replace-fetch-response.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -253,4 +253,50 @@ if (!isSupported) {
assert.strictEqual(url, urlExpected, 'response prop is copied');
done();
});

test('Data URL request, URL set by Object.defineProperty, content should NOT be replaced', async (assert) => {
const JSON_CONTENT = '{"adPlacements":true,"playerAds":true,}';
const BASE64 = btoa(JSON_CONTENT);
const DATA_REQUEST = `data:application/json;base64,${BASE64}`;
const REQUEST = new Request(DATA_REQUEST);
Object.defineProperty(REQUEST, 'url', {
get() {
return 'https://www.example.org/ad_url_test';
},
});
Object.defineProperty(REQUEST, 'method', {
get() {
return 'POST';
},
});
Object.defineProperty(REQUEST, 'bodyUsed', {
get() {
return !0;
},
});
Object.defineProperty(REQUEST, 'mode', {
get() {
return 'same-origin';
},
});
Object.defineProperty(REQUEST, 'body', {
get() {
return new ReadableStream();
},
});

const done = assert.async();

const PATTERN = 'adPlacements';
const REPLACEMENT = '';
const PROPS_TO_MATCH = 'ad_url_test';
runScriptlet(name, [PATTERN, REPLACEMENT, PROPS_TO_MATCH]);

const response = await fetch(REQUEST);
const actualTextContent = await response.text();

assert.strictEqual(window.hit, undefined, 'hit should NOT fire');
assert.strictEqual(actualTextContent, JSON_CONTENT, 'Content is intact');
done();
});
}

0 comments on commit 6deea9d

Please sign in to comment.