Skip to content

Commit

Permalink
modify original response by prevent-fetch. AG-20293 #297
Browse files Browse the repository at this point in the history
Squashed commit of the following:

commit 5fb4979
Author: Slava Leleka <v.leleka@adguard.com>
Date:   Thu May 11 18:46:34 2023 +0300

    use await instead of then

commit 4c4046c
Author: Slava Leleka <v.leleka@adguard.com>
Date:   Wed May 10 20:42:44 2023 +0300

    mark startsWith() and endsWith() helpers as deprecated

commit c21eccc
Author: Slava Leleka <v.leleka@adguard.com>
Date:   Wed May 10 20:37:37 2023 +0300

    improve responseType checking condition

commit 68f3b60
Author: Slava Leleka <v.leleka@adguard.com>
Date:   Wed May 10 20:33:10 2023 +0300

    fix INPUT_JSON_PATH

commit 087f934
Author: Slava Leleka <v.leleka@adguard.com>
Date:   Wed May 10 20:32:36 2023 +0300

    fix assert.async()

commit dc62a81
Author: Slava Leleka <v.leleka@adguard.com>
Date:   Wed May 10 15:14:13 2023 +0300

    fix imports

commit 4423117
Author: Slava Leleka <v.leleka@adguard.com>
Date:   Wed May 10 14:44:36 2023 +0300

    Revert "update babel/runtime"

    This reverts commit abab623.

commit bb234c4
Author: Slava Leleka <v.leleka@adguard.com>
Date:   Wed May 10 14:42:45 2023 +0300

    improve invalid param error text

commit a1bd1da
Author: Slava Leleka <v.leleka@adguard.com>
Date:   Wed May 10 14:36:00 2023 +0300

    update changelog

commit 5e4e47c
Author: Slava Leleka <v.leleka@adguard.com>
Date:   Wed May 10 14:35:08 2023 +0300

    update changelog

commit 531ea12
Author: Slava Leleka <v.leleka@adguard.com>
Date:   Wed May 10 14:19:55 2023 +0300

    modify original response by prevent-fetch

commit abab623
Author: Slava Leleka <v.leleka@adguard.com>
Date:   Wed May 10 14:16:37 2023 +0300

    update babel/runtime
  • Loading branch information
slavaleleka committed May 11, 2023
1 parent e60fdd1 commit e7295bd
Show file tree
Hide file tree
Showing 6 changed files with 199 additions and 29 deletions.
46 changes: 32 additions & 14 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,33 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Changed

- improved `prevent-fetch` — if `responseType` is not specified,
original response type is returned instead of `default` [#297](https://github.com/AdguardTeam/Scriptlets/issues/291)

### Fixed

- issue with reloading website if `$now$`/`$currentDate$` value is used in `trusted-set-cookie-reload` scriptlet [#291](https://github.com/AdguardTeam/Scriptlets/issues/291)
- website reloading if `$now$`/`$currentDate$` value is used
in `trusted-set-cookie-reload` scriptlet [#291](https://github.com/AdguardTeam/Scriptlets/issues/291)

## <a name="v1.9.7"></a> [v1.9.7] - 2023-03-14

### Added

- ability for `trusted-click-element` scriptlet to click element if `cookie`/`localStorage` item doesn't exist [#298](https://github.com/AdguardTeam/Scriptlets/issues/298)
- static delay between multiple clicks in `trusted-click-element` [#284](https://github.com/AdguardTeam/Scriptlets/issues/284)
- ability for `trusted-click-element` scriptlet to click element
if `cookie`/`localStorage` item doesn't exist [#298](https://github.com/AdguardTeam/Scriptlets/issues/298)
- static delay between multiple clicks in `trusted-click-element`
[#284](https://github.com/AdguardTeam/Scriptlets/issues/284)

### Changed

- improved the `convertScriptletToAdg()` method — now it validates the input rule syntax if it is an ADG rule

### Fixed

- issue with `MutationObserver.disconnect()` in `trusted-click-element` [#284](https://github.com/AdguardTeam/Scriptlets/issues/284)
- issue with `MutationObserver.disconnect()`
in `trusted-click-element` [#284](https://github.com/AdguardTeam/Scriptlets/issues/284)


## <a name="v1.9.1"></a> [v1.9.1] - 2023-03-07
Expand All @@ -36,13 +45,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- decreased the minimal value for the `boost` parameter to `0.001` for `adjust-setTimeout` and `adjust-setInterval` [#262](https://github.com/AdguardTeam/Scriptlets/issues/262)
- decreased the minimal value for the `boost` parameter to `0.001`
for `adjust-setTimeout` and `adjust-setInterval` [#262](https://github.com/AdguardTeam/Scriptlets/issues/262)

### Fixed

- `prevent-element-src-loading` throwing error if `thisArg` is `undefined` [#270](https://github.com/AdguardTeam/Scriptlets/issues/270)
- `prevent-element-src-loading` throwing error
if `thisArg` is `undefined` [#270](https://github.com/AdguardTeam/Scriptlets/issues/270)
- logging `null` in `json-prune` [#282](https://github.com/AdguardTeam/Scriptlets/issues/282)
- `xml-prune` does not prune a request if `new Request()` is used and issue with throwing error while logging some requests [#289](https://github.com/AdguardTeam/Scriptlets/issues/289)
- `xml-prune`: no pruning a request if `new Request()` is used,
throwing an error while logging some requests [#289](https://github.com/AdguardTeam/Scriptlets/issues/289)
- improve performance of the `isValidScriptletName()` method


Expand All @@ -53,17 +65,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- new `trusted-set-constant` scriptlet [#137](https://github.com/AdguardTeam/Scriptlets/issues/137)
- new `inject-css-in-shadow-dom` scriptlet [#267](https://github.com/AdguardTeam/Scriptlets/issues/267)
- `throwFunc` and `noopCallbackFunc` prop values for `set-constant` scriptlet
- `recreateIframeForSlot` method mock to `googletagservices-gpt` redirect [#259](https://github.com/AdguardTeam/Scriptlets/issues/259)
- `recreateIframeForSlot` method mock
to `googletagservices-gpt` redirect [#259](https://github.com/AdguardTeam/Scriptlets/issues/259)

### Changed

- add decimal delay matching for `prevent-setInterval` and `prevent-setTimeout` [#247](https://github.com/AdguardTeam/Scriptlets/issues/247)
- add decimal delay matching for `prevent-setInterval` and `prevent-setTimeout`
[#247](https://github.com/AdguardTeam/Scriptlets/issues/247)
- debug logging to include rule text when available
- `getScriptletFunction` calls to throw error on unknown scriptlet names

### Fixed

- `prevent-xhr` and `trusted-replace-xhr-response` closure bug on multiple requests [#261](https://github.com/AdguardTeam/Scriptlets/issues/261)
- `prevent-xhr` and `trusted-replace-xhr-response` closure bug on multiple requests
[#261](https://github.com/AdguardTeam/Scriptlets/issues/261)
- missing `googletagmanager-gtm` in compatibility table


Expand All @@ -83,22 +98,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed

- `prevent-addEventListener` and `log-addEventListener` loosing context when encountering already bound `.addEventListener`
- `prevent-addEventListener` and `log-addEventListener` loosing context
when encountering already bound `.addEventListener`
- `google-ima3` conversion


## <a name="v1.7.14"></a> [v1.7.14] - 2022-12-16

### Added

* `set-constant` ADG→UBO conversion for [`emptyArr` and `emptyObj`](https://github.com/uBlockOrigin/uBlock-issues/issues/2411)
- `set-constant` ADG→UBO conversion
for [`emptyArr` and `emptyObj`](https://github.com/uBlockOrigin/uBlock-issues/issues/2411)


## <a name="v1.7.13"></a> [v1.7.13] - 2022-12-13

### Fixed

* `isEmptyObject` helper not counting `prototype` as an object property
- `isEmptyObject` helper not counting `prototype` as an object property


## <a name="v1.7.10"></a> [v1.7.10] - 2022-12-07
Expand All @@ -110,7 +127,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed

- `set-cookie-reload` infinite page reloading [#265](https://github.com/AdguardTeam/Scriptlets/issues/265)
- breakage of `prevent-element-src-loading` due to `window` getting into `apply` wrapper [#264](https://github.com/AdguardTeam/Scriptlets/issues/264)
- breakage of `prevent-element-src-loading` due to `window` getting into `apply` wrapper
[#264](https://github.com/AdguardTeam/Scriptlets/issues/264)
- spread of args bug at `getXhrData` call for `trusted-replace-xhr-response`
- request properties array not being served to `getRequestData` and `parseMatchProps` helpers

Expand Down
1 change: 1 addition & 0 deletions src/helpers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export * from './open-shadow-dom-utils';
export * from './prevent-utils';
export * from './prevent-window-open-utils';
export * from './regexp-utils';
export * from './response-utils';
export * from './request-utils';
export * from './storage-utils';
export * from './string-utils';
Expand Down
40 changes: 40 additions & 0 deletions src/helpers/response-utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* Modifies original response with the given replacement data.
*
* @param {Response} origResponse Original response.
* @param {Object} replacement Replacement data for response with possible keys:
* - `body`: optional, string, default to '{}';
* - `type`: optional, string, original response type is used if not specified.
*
* @returns {Response} Modified response.
*/
export const modifyResponse = (
origResponse,
replacement = {
body: '{}',
},
) => {
const headers = {};
origResponse?.headers?.forEach((value, key) => {
headers[key] = value;
});

const modifiedResponse = new Response(replacement.body, {
status: origResponse.status,
statusText: origResponse.statusText,
headers,
});

// Mock response url and type to avoid adblocker detection
// https://github.com/AdguardTeam/Scriptlets/issues/216
Object.defineProperties(modifiedResponse, {
url: {
value: origResponse.url,
},
type: {
value: replacement.type || origResponse.type,
},
});

return modifiedResponse;
};
4 changes: 4 additions & 0 deletions src/helpers/string-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ export const getBeforeRegExp = (str, rx) => {
/**
* Checks whether the string starts with the substring
*
* @deprecated use String.prototype.startsWith() instead. AG-18883
*
* @param {string} str full string
* @param {string} prefix substring
* @returns {boolean} if string start with the substring
Expand All @@ -103,6 +105,8 @@ export const startsWith = (str, prefix) => {
/**
* Checks whether the string ends with the substring
*
* @deprecated use String.prototype.endsWith() instead. AG-18883
*
* @param {string} str full string
* @param {string} ending substring
* @returns {boolean} string ends with the substring
Expand Down
48 changes: 35 additions & 13 deletions src/scriptlets/prevent-fetch.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import {
hit,
getFetchData,
objectToString,
noopPromiseResolve,
matchRequestProps,
logMessage,
modifyResponse,
// following helpers should be imported and injected
// because they are used by helpers above
toRegExp,
Expand All @@ -24,7 +24,7 @@ import {
/**
* @scriptlet prevent-fetch
* @description
* Prevents `fetch` calls if **all** given parameters match
* Prevents `fetch` calls if **all** given parameters match.
*
* Related UBO scriptlet:
* https://github.com/gorhill/uBlock/wiki/Resources-Library#no-fetch-ifjs-
Expand All @@ -35,14 +35,18 @@ import {
* ```
*
* - `propsToMatch` — optional, string of space-separated properties to match; possible props:
* - string or regular expression for matching the URL passed to fetch call; empty string, wildcard `*` or invalid regular expression will match all fetch calls
* - string or regular expression for matching the URL passed to fetch call;
* empty string, wildcard `*` or invalid regular expression will match all fetch calls
* - colon-separated pairs `name:value` where
* - `name` is [`init` option name](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#parameters)
* - `value` is string or regular expression for matching the value of the option passed to fetch call; invalid regular expression will cause any value matching
* - `responseBody` — optional, string for defining response body value, defaults to `emptyObj`. Possible values:
* - `value` is string or regular expression for matching the value of the option passed to fetch call;
* invalid regular expression will cause any value matching
* - `responseBody` — optional, string for defining response body value,
* defaults to `emptyObj`. Possible values:
* - `emptyObj` — empty object
* - `emptyArr` — empty array
* - `responseType` — optional, string for defining response type, defaults to `default`. Possible values:
* - `responseType` — optional, string for defining response type,
* original response type is used if not specified. Possible values:
* - `default`
* - `opaque`
*
Expand Down Expand Up @@ -92,7 +96,7 @@ import {
* ```
*/
/* eslint-enable max-len */
export function preventFetch(source, propsToMatch, responseBody = 'emptyObj', responseType = 'default') {
export function preventFetch(source, propsToMatch, responseBody = 'emptyObj', responseType) {
// do nothing if browser does not support fetch or Proxy (e.g. Internet Explorer)
// https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy
Expand All @@ -108,16 +112,27 @@ export function preventFetch(source, propsToMatch, responseBody = 'emptyObj', re
} else if (responseBody === 'emptyArr') {
strResponseBody = '[]';
} else {
logMessage(source, `Invalid responseBody parameter: '${responseBody}'`);
return;
}

// Skip disallowed response types
if (!(responseType === 'default' || responseType === 'opaque')) {
logMessage(source, `Invalid parameter: ${responseType}`);
const isResponseTypeSpecified = typeof responseType !== 'undefined';
const isResponseTypeSupported = (responseType) => {
const SUPPORTED_TYPES = [
'default',
'opaque',
];
return SUPPORTED_TYPES.includes(responseType);
};
// Skip disallowed response types,
// specified responseType has limited list of possible values
if (isResponseTypeSpecified
&& !isResponseTypeSupported(responseType)) {
logMessage(source, `Invalid responseType parameter: '${responseType}'`);
return;
}

const handlerWrapper = (target, thisArg, args) => {
const handlerWrapper = async (target, thisArg, args) => {
let shouldPrevent = false;
const fetchData = getFetchData(args);
if (typeof propsToMatch === 'undefined') {
Expand All @@ -130,7 +145,14 @@ export function preventFetch(source, propsToMatch, responseBody = 'emptyObj', re

if (shouldPrevent) {
hit(source);
return noopPromiseResolve(strResponseBody, fetchData.url, responseType);
const origResponse = await Reflect.apply(target, thisArg, args);
return modifyResponse(
origResponse,
{
body: strResponseBody,
type: responseType,
},
);
}

return Reflect.apply(target, thisArg, args);
Expand All @@ -155,9 +177,9 @@ preventFetch.injections = [
hit,
getFetchData,
objectToString,
noopPromiseResolve,
matchRequestProps,
logMessage,
modifyResponse,
toRegExp,
isValidStrPattern,
escapeRegExp,
Expand Down
Loading

0 comments on commit e7295bd

Please sign in to comment.