From fae811e3576770bc9bb004b46819c13355df115a Mon Sep 17 00:00:00 2001 From: Stanislav Atroschenko Date: Fri, 12 May 2023 20:50:07 +0300 Subject: [PATCH 01/12] AG-21734 remove 'cannot apply' part of logMessage Merge in ADGUARD-FILTERS/scriptlets from fix/AG-21734 to master Squashed commit of the following: commit 2b3294a30e9876e08e5b39b4c731509f96bad87c Merge: cae7f937 b96e797b Author: Stanislav A Date: Fri May 12 20:44:58 2023 +0300 Merge branch 'master' into fix/AG-21734 commit cae7f9377175f34747a513f7b6ed4704ff40ada0 Author: Stanislav A Date: Fri May 12 15:00:32 2023 +0300 get rid of excessive variable commit ff4e538d42ebc742da5066275c52d9eb9e485b21 Author: Stanislav A Date: Thu May 11 18:31:44 2023 +0300 remove 'cannot apply' part of logMessage --- src/helpers/log-message.js | 14 +------------- tests/helpers/log-message.test.js | 3 +-- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/src/helpers/log-message.js b/src/helpers/log-message.js index 0bcd090f..d98ef304 100644 --- a/src/helpers/log-message.js +++ b/src/helpers/log-message.js @@ -12,7 +12,6 @@ export const logMessage = (source, message, forced = false, convertMessageToString = true) => { const { name, - ruleText, verbose, } = source; @@ -31,16 +30,5 @@ export const logMessage = (source, message, forced = false, convertMessageToStri return; } - let messageStr = `${name}: ${message}`; - - // Extract scriptlet part from rule text - if (ruleText) { - const RULE_MARKER = '#%#//scriptlet'; - const markerIdx = ruleText.indexOf(RULE_MARKER); - if (markerIdx > -1) { - const ruleWithoutDomains = ruleText.slice(markerIdx, ruleText.length); - messageStr += `; cannot apply rule: ${ruleWithoutDomains}`; - } - } - nativeConsole(messageStr); + nativeConsole(`${name}: ${message}`); }; diff --git a/tests/helpers/log-message.test.js b/tests/helpers/log-message.test.js index eda2de10..6167628c 100644 --- a/tests/helpers/log-message.test.js +++ b/tests/helpers/log-message.test.js @@ -16,7 +16,6 @@ module(name, { afterEach }); const RULE_TEXT = 'example.org#%#//scriptlet(\'set-cookie\', \'name\', \'value\')'; const SCRIPTLET_NAME = 'set-cookie'; const MESSAGE = 'arbitrary text message'; -const MESSAGE_EXTENSION = '; cannot apply rule: #%#//scriptlet(\'set-cookie\', \'name\', \'value\')'; test('Logs message conditionally', async (assert) => { // eslint-disable-next-line no-console @@ -26,7 +25,7 @@ test('Logs message conditionally', async (assert) => { } assert.strictEqual( input, - `${SCRIPTLET_NAME}: ${MESSAGE}${MESSAGE_EXTENSION}`, + `${SCRIPTLET_NAME}: ${MESSAGE}`, 'message logged correctly', ); }; From 898998d333ea4f8f73fb5e805bdf0bf91149565b Mon Sep 17 00:00:00 2001 From: Atlassian Bamboo Date: Fri, 12 May 2023 20:50:16 +0300 Subject: [PATCH 02/12] skipci: Automatic increment build number --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6d2fb71b..6b3902fa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@adguard/scriptlets", - "version": "1.9.11", + "version": "1.9.12", "description": "AdGuard's JavaScript library of Scriptlets and Redirect resources", "scripts": { "build": "babel-node bundler.js", From d16b49f26775ea742d50a142b8e176bc4343c31e Mon Sep 17 00:00:00 2001 From: Stanislav Atroschenko Date: Tue, 16 May 2023 11:42:32 +0300 Subject: [PATCH 03/12] AG-21419 get rid of encodeURIComponent for trusted-set-cookie-* scriptlets Merge in ADGUARD-FILTERS/scriptlets from fix/AG-21419 to master Squashed commit of the following: commit 714976413d068afb2881ded210c4f6fbbff6bc76 Merge: 511a3def 2cedcec4 Author: Stanislav A Date: Mon May 15 18:45:57 2023 +0300 Merge branch 'fix/AG-21419' of ssh://bit.adguard.com:7999/adguard-filters/scriptlets into fix/AG-21419 commit 511a3def04e7149941cfbb6853e97cd9bee3ad1c Author: Stanislav A Date: Mon May 15 18:44:27 2023 +0300 add description and logging for non-trusteds commit 2cedcec47328a48b417c37faa973017b7a1296d7 Author: Slava Leleka Date: Mon May 15 18:42:42 2023 +0300 CHANGELOG.md edited online with Bitbucket commit f23894cc0434af3685ec9f80eea6255e767ee0da Author: Stanislav A Date: Mon May 15 18:40:50 2023 +0300 improve trusteds' descriptions commit 060babb799c31719fa5e77439d3ed5cb24987a9c Author: Slava Leleka Date: Mon May 15 18:28:59 2023 +0300 CHANGELOG.md edited online with Bitbucket commit 0beae8a727dc6e9531029b759960730771ce47ac Author: Stanislav A Date: Mon May 15 13:51:34 2023 +0300 handle semicolon in names and values, add info to description commit d8ccf17d7fd37cac160270373b501c938ffd6a36 Merge: 388b6377 898998d3 Author: Stanislav A Date: Fri May 12 20:56:43 2023 +0300 merge master commit 388b6377cdbca59498e94b2cc902f4dd888b216c Author: Stanislav A Date: Fri May 12 20:55:05 2023 +0300 swap changelog items commit ac98dea11fca566ced82eca63fae08ae1627f014 Author: Stanislav A Date: Fri May 12 15:48:02 2023 +0300 update changelog commit d03e0284d61ecc8c425c2443902c6a8d54c17fd6 Author: Stanislav A Date: Thu May 11 19:24:24 2023 +0300 get rid of encodeURIComponent for trusted-set-cookie-* scriptlets --- CHANGELOG.md | 1 + src/helpers/cookie-utils.js | 15 +++++++++++---- src/scriptlets/set-cookie-reload.js | 4 ++++ src/scriptlets/set-cookie.js | 4 ++++ src/scriptlets/trusted-set-cookie-reload.js | 6 +++++- src/scriptlets/trusted-set-cookie.js | 6 +++++- .../scriptlets/trusted-set-cookie-reload.spec.js | 2 +- tests/scriptlets/trusted-set-cookie.test.js | 2 +- 8 files changed, 32 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4953241d..72737255 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- `trusted-set-cookie` and `trusted-set-cookie-reaload` scriptlets to not encode cookie name and value [#311](https://github.com/AdguardTeam/Scriptlets/issues/311) - improved `prevent-fetch` — if `responseType` is not specified, original response type is returned instead of `default` [#297](https://github.com/AdguardTeam/Scriptlets/issues/291) diff --git a/src/helpers/cookie-utils.js b/src/helpers/cookie-utils.js index 7bebf680..99ff2bd5 100644 --- a/src/helpers/cookie-utils.js +++ b/src/helpers/cookie-utils.js @@ -30,11 +30,18 @@ export const getCookiePath = (rawPath) => { * @param {string} rawName name argument of *set-cookie-* scriptlets * @param {string} rawValue value argument of *set-cookie-* scriptlets * @param {string} rawPath path argument of *set-cookie-* scriptlets - * @returns {string|null} string OR `null` if path is not supported + * @param {boolean} shouldEncode if cookie's name and value should be encoded + * @returns {string|null} string OR `null` if name or value is invalid */ -export const concatCookieNameValuePath = (rawName, rawValue, rawPath) => { - // eslint-disable-next-line max-len - return `${encodeURIComponent(rawName)}=${encodeURIComponent(rawValue)}; ${getCookiePath(rawPath)};`; +export const concatCookieNameValuePath = (rawName, rawValue, rawPath, shouldEncode = true) => { + const COOKIE_BREAKER = ';'; + // semicolon will cause the cookie to break + if (!shouldEncode && (rawName.includes(COOKIE_BREAKER) || `${rawValue}`.includes(COOKIE_BREAKER))) { + return null; + } + const name = shouldEncode ? encodeURIComponent(rawName) : rawName; + const value = shouldEncode ? encodeURIComponent(rawValue) : rawValue; + return `${name}=${value}; ${getCookiePath(rawPath)};`; }; /** diff --git a/src/scriptlets/set-cookie-reload.js b/src/scriptlets/set-cookie-reload.js index 32379dbb..8cc876a6 100644 --- a/src/scriptlets/set-cookie-reload.js +++ b/src/scriptlets/set-cookie-reload.js @@ -36,6 +36,9 @@ import { * - `/` — root path * - `none` — to set no path at all * + * > Note that the scriptlet encodes cookie names and values, + * e.g value `"{ test: 'value'}"` becomes `%7B%20test%3A%20'value'%7D`. + * * **Examples** * ``` * example.org#%#//scriptlet('set-cookie-reload', 'checking', 'ok') @@ -63,6 +66,7 @@ export function setCookieReload(source, name, value, path = '/') { const cookieToSet = concatCookieNameValuePath(name, validValue, path); if (!cookieToSet) { + logMessage(source, 'Invalid cookie name or value'); return; } diff --git a/src/scriptlets/set-cookie.js b/src/scriptlets/set-cookie.js index a2773e67..6f75fc5d 100644 --- a/src/scriptlets/set-cookie.js +++ b/src/scriptlets/set-cookie.js @@ -35,6 +35,9 @@ import { * - `/` — root path * - `none` — to set no path at all * + * > Note that the scriptlet encodes cookie names and values, + * e.g value `"{ test: 'value'}"` becomes `%7B%20test%3A%20'value'%7D`. + * * **Examples** * ``` * example.org#%#//scriptlet('set-cookie', 'CookieConsent', '1') @@ -59,6 +62,7 @@ export function setCookie(source, name, value, path = '/') { const cookieToSet = concatCookieNameValuePath(name, validValue, path); if (!cookieToSet) { + logMessage(source, 'Invalid cookie name or value'); return; } diff --git a/src/scriptlets/trusted-set-cookie-reload.js b/src/scriptlets/trusted-set-cookie-reload.js index 29f0e32a..a1caf950 100644 --- a/src/scriptlets/trusted-set-cookie-reload.js +++ b/src/scriptlets/trusted-set-cookie-reload.js @@ -42,6 +42,9 @@ import { * - `/` — root path * - `none` — to set no path at all * + * > Note that the scriptlet does not encode cookie names and values. As a result, if a cookie's name or value includes `;`, + * the scriptlet will not set the cookie since this may cause the cookie to break. + * * **Examples** * 1. Set cookie and reload the page after it * ``` @@ -93,8 +96,9 @@ export function trustedSetCookieReload(source, name, value, offsetExpiresSec = ' return; } - let cookieToSet = concatCookieNameValuePath(name, parsedValue, path); + let cookieToSet = concatCookieNameValuePath(name, parsedValue, path, false); if (!cookieToSet) { + logMessage(source, 'Invalid cookie name or value'); return; } diff --git a/src/scriptlets/trusted-set-cookie.js b/src/scriptlets/trusted-set-cookie.js index f63358e1..397a3cc7 100644 --- a/src/scriptlets/trusted-set-cookie.js +++ b/src/scriptlets/trusted-set-cookie.js @@ -39,6 +39,9 @@ import { * - `/` — root path * - `none` — to set no path at all * + * > Note that the scriptlet does not encode cookie names and values. As a result, if a cookie's name or value includes `;`, + * the scriptlet will not set the cookie since this may cause the cookie to break. + * * **Examples** * 1. Set cookie * ``` @@ -85,8 +88,9 @@ export function trustedSetCookie(source, name, value, offsetExpiresSec = '', pat return; } - let cookieToSet = concatCookieNameValuePath(name, parsedValue, path); + let cookieToSet = concatCookieNameValuePath(name, parsedValue, path, false); if (!cookieToSet) { + logMessage(source, 'Invalid cookie name or value'); return; } diff --git a/tests/scriptlets/trusted-set-cookie-reload.spec.js b/tests/scriptlets/trusted-set-cookie-reload.spec.js index 0a11357d..5a93d67f 100644 --- a/tests/scriptlets/trusted-set-cookie-reload.spec.js +++ b/tests/scriptlets/trusted-set-cookie-reload.spec.js @@ -72,7 +72,7 @@ describe('Test trusted-set-cookie-reload scriptlet', () => { // and jest running test const cookieValue = parseCookieString(document.cookie)[cName]; // Check only day, month and year - const currentDate = encodeURIComponent(Date().split(' ', 4).join(' ')); + const currentDate = Date().split(' ', 4).join(' '); const dateDiff = cookieValue.split(' ', 4).join(' '); expect(dateDiff.startsWith(currentDate)).toBeTruthy(); diff --git a/tests/scriptlets/trusted-set-cookie.test.js b/tests/scriptlets/trusted-set-cookie.test.js index 3a92e2bd..8e044c8f 100644 --- a/tests/scriptlets/trusted-set-cookie.test.js +++ b/tests/scriptlets/trusted-set-cookie.test.js @@ -44,7 +44,7 @@ test('Set cookie string', (assert) => { assert.strictEqual(window.hit, 'FIRED', 'Hit was fired'); assert.strictEqual(document.cookie.includes(cName), true, 'Cookie name has been set'); - assert.strictEqual(document.cookie.includes(encodeURIComponent(cValue)), true, 'Cookie value has been set'); + assert.strictEqual(document.cookie.includes(cValue), true, 'Cookie value has been set'); clearCookie(cName); }); From 66582ca72162a5105fad63a11d0058d21b8685a2 Mon Sep 17 00:00:00 2001 From: Atlassian Bamboo Date: Tue, 16 May 2023 11:42:48 +0300 Subject: [PATCH 04/12] skipci: Automatic increment build number --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6b3902fa..92115d4f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@adguard/scriptlets", - "version": "1.9.12", + "version": "1.9.13", "description": "AdGuard's JavaScript library of Scriptlets and Redirect resources", "scripts": { "build": "babel-node bundler.js", From 39bf026a1cf27a8f1c6656466b319a091d4ff22c Mon Sep 17 00:00:00 2001 From: Slava Leleka Date: Tue, 16 May 2023 14:16:58 +0300 Subject: [PATCH 05/12] add implemented version info to docs. #273 AG-18483 Squashed commit of the following: commit a4ed413d1c842f8580630038c8ce6982f8758342 Merge: 2de83524 66582ca7 Author: Slava Leleka Date: Tue May 16 12:31:26 2023 +0300 Merge branch 'master' into feature/AG-18483 commit 2de83524205d8be3fa2199e503f9eabba2ecab6d Author: Slava Leleka Date: Mon May 15 20:05:31 2023 +0300 throw an error if added not set commit a23d11b4710500076eef2859ff9fc9e85e8c528f Author: Slava Leleka Date: Mon May 15 18:38:24 2023 +0300 add changelog todo commit 9618dbb599b0916d18750b85334470712818de44 Author: Slava Leleka Date: Mon May 15 18:33:50 2023 +0300 update v1.0.4 commit 5189d1170bf507224807643b443c8982a1dcbd57 Author: Slava Leleka Date: Mon May 15 18:32:35 2023 +0300 update v1.0.4 commit 88964547dcd716dd7cf7a57fd7d6513074a457ac Author: Slava Leleka Date: Mon May 15 18:30:35 2023 +0300 update v1.6.2 commit cf5b9f3bc4d55ac30045a63c8e9a5522856b61ce Author: Slava Leleka Date: Mon May 15 18:29:38 2023 +0300 handle v1.9.1 commit ebfac6c550c6316508cb202a98f6554cb6d6bb01 Author: Slava Leleka Date: Mon May 15 18:29:04 2023 +0300 handle v1.8.2 commit c453c2cd96c241ba225584494c771005f9a36e84 Author: Slava Leleka Date: Mon May 15 18:27:33 2023 +0300 handle v1.7.10 commit c211874f6dc64a25d96ef53b0178744bdf03a5ce Author: Slava Leleka Date: Mon May 15 18:26:57 2023 +0300 handle v1.7.3 commit 1b1af6d5cfbe17dd71fb5d57cdf7d42e913d2847 Author: Slava Leleka Date: Mon May 15 18:23:00 2023 +0300 handle v1.6.55 commit b496d6f91936d267bdb06d02fd7c643488cbeead Author: Slava Leleka Date: Mon May 15 18:22:09 2023 +0300 handle v1.6.18 commit 6f8d1dbe57894929f6a16f9274d929b6c6a65dbf Author: Slava Leleka Date: Mon May 15 18:21:25 2023 +0300 handle v1.6.2 commit a5cd94e85c02575b9af25edf1ec720805ccd45a5 Author: Slava Leleka Date: Mon May 15 18:18:49 2023 +0300 handle v1.5.0 commit a1b3b957b955c70b31fb08a55086ac6b32f70ed8 Author: Slava Leleka Date: Mon May 15 18:15:43 2023 +0300 handle v1.4.3 commit d10aca01d634fd794df2a9fbcfe960f04f32295d Author: Slava Leleka Date: Mon May 15 18:14:39 2023 +0300 handle v1.3.19 commit d4f09e511f3cc9c6824685a41d709b9fc2621cc8 Author: Slava Leleka Date: Mon May 15 18:13:08 2023 +0300 handle v1.3.18 commit fd59952899b8768943b0d639dc5ca0af93b0eb6e Author: Slava Leleka Date: Mon May 15 18:12:18 2023 +0300 handle v1.3.14 commit 4b45062466f4a2c4b967810b4f6c733538b0e014 Author: Slava Leleka Date: Mon May 15 18:10:59 2023 +0300 handle v1.3.9 commit e4f7f8eec2ddbc93292e7c49e9e5f8c113faf07f Author: Slava Leleka Date: Mon May 15 18:10:10 2023 +0300 handle v1.2.3 ... and 11 more commits --- .eslintrc.js | 1 + CHANGELOG.md | 3 + scripts/build-docs.js | 69 ++++++++++++------- scripts/helpers.js | 20 ++++-- src/redirects/amazon-apstag.js | 3 + src/redirects/ati-smarttag.js | 3 + src/redirects/blocking-redirects.yml | 2 + src/redirects/didomi-loader.js | 3 + src/redirects/fingerprintjs2.js | 3 + src/redirects/fingerprintjs3.js | 3 + src/redirects/gemius.js | 3 + src/redirects/google-analytics-ga.js | 3 + src/redirects/google-analytics.js | 3 + src/redirects/google-ima3.js | 3 + .../googlesyndication-adsbygoogle.js | 3 + src/redirects/googletagservices-gpt.js | 3 + src/redirects/matomo.js | 3 + src/redirects/metrika-yandex-tag.js | 3 + src/redirects/metrika-yandex-watch.js | 3 + src/redirects/naver-wcslog.js | 3 + src/redirects/noeval.js | 3 + src/redirects/pardot-1.0.js | 3 + src/redirects/prebid-ads.js | 3 + src/redirects/prebid.js | 3 + src/redirects/prevent-bab.js | 3 + src/redirects/prevent-bab2.js | 3 + src/redirects/prevent-fab-3.2.0.js | 3 + src/redirects/prevent-popads-net.js | 3 + src/redirects/scorecardresearch-beacon.js | 3 + src/redirects/set-popads-dummy.js | 3 + src/redirects/static-redirects.yml | 26 +++++++ src/scriptlets/abort-current-inline-script.js | 3 + src/scriptlets/abort-on-property-read.js | 3 + src/scriptlets/abort-on-property-write.js | 3 + src/scriptlets/abort-on-stack-trace.js | 3 + src/scriptlets/adjust-setInterval.js | 3 + src/scriptlets/adjust-setTimeout.js | 3 + src/scriptlets/close-window.js | 3 + src/scriptlets/debug-current-inline-script.js | 3 + src/scriptlets/debug-on-property-read.js | 3 + src/scriptlets/debug-on-property-write.js | 3 + src/scriptlets/dir-string.js | 3 + src/scriptlets/disable-newtab-links.js | 3 + src/scriptlets/hide-in-shadow-dom.js | 3 + src/scriptlets/inject-css-in-shadow-dom.js | 3 + src/scriptlets/json-prune.js | 5 +- src/scriptlets/log-addEventListener.js | 3 + src/scriptlets/log-eval.js | 3 + src/scriptlets/log-on-stack-trace.js | 3 + src/scriptlets/log.js | 3 + src/scriptlets/m3u-prune.js | 2 + src/scriptlets/no-topics.js | 3 + src/scriptlets/noeval.js | 3 + src/scriptlets/nowebrtc.js | 3 + src/scriptlets/prevent-addEventListener.js | 3 + src/scriptlets/prevent-adfly.js | 3 + src/scriptlets/prevent-bab.js | 3 + src/scriptlets/prevent-element-src-loading.js | 3 + src/scriptlets/prevent-eval-if.js | 3 + src/scriptlets/prevent-fab-3.2.0.js | 3 + src/scriptlets/prevent-fetch.js | 3 + src/scriptlets/prevent-popads-net.js | 3 + src/scriptlets/prevent-refresh.js | 3 + .../prevent-requestAnimationFrame.js | 3 + src/scriptlets/prevent-setInterval.js | 3 + src/scriptlets/prevent-setTimeout.js | 3 + src/scriptlets/prevent-window-open.js | 3 + src/scriptlets/prevent-xhr.js | 3 + src/scriptlets/remove-attr.js | 3 + src/scriptlets/remove-class.js | 3 + src/scriptlets/remove-cookie.js | 3 + src/scriptlets/remove-in-shadow-dom.js | 3 + src/scriptlets/set-attr.js | 3 + src/scriptlets/set-constant.js | 3 + src/scriptlets/set-cookie-reload.js | 3 + src/scriptlets/set-cookie.js | 3 + src/scriptlets/set-local-storage-item.js | 3 + src/scriptlets/set-popads-dummy.js | 3 + src/scriptlets/set-session-storage-item.js | 3 + src/scriptlets/trusted-click-element.js | 3 + .../trusted-replace-fetch-response.js | 3 + .../trusted-replace-xhr-response.js | 3 + src/scriptlets/trusted-set-constant.js | 3 + src/scriptlets/trusted-set-cookie-reload.js | 3 + src/scriptlets/trusted-set-cookie.js | 3 + .../trusted-set-local-storage-item.js | 3 + src/scriptlets/xml-prune.js | 3 + 87 files changed, 331 insertions(+), 34 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index d9d38224..1adb6b36 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -37,6 +37,7 @@ module.exports = { 'scriptlet', 'trustedScriptlet', 'redirect', + 'added', 'jest-environment', ], }], diff --git a/CHANGELOG.md b/CHANGELOG.md index 72737255..9ba659b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + + + ## [Unreleased] ### Changed diff --git a/scripts/build-docs.js b/scripts/build-docs.js index 3f33fc34..699f68cc 100644 --- a/scripts/build-docs.js +++ b/scripts/build-docs.js @@ -102,18 +102,21 @@ const getMarkdownData = (dataItems) => { const output = dataItems.reduce((acc, { name, type, + versionAdded, description, source, }) => { - // low case name should be used as anchor + // low case name should be used as an anchor in the table of content acc.list.push(`* [${name}](#${name.toLowerCase()})${EOL}`); const typeOfSrc = type.toLowerCase().includes('scriptlet') ? 'Scriptlet' : 'Redirect'; - // low case name should be used as anchor - const body = `### ⚡️ ${name} + // 1. Low case name should be used as an anchor + // 2. There is no EOL after 'version' string because `description` starts with `\n` + const body = `### ⚡️ ${name}${EOL} +${versionAdded ? `> Added in ${versionAdded}` : '> Adding version is unknown.'} ${description}${EOL} -[${typeOfSrc} source](${source}) +[${typeOfSrc} source](${source})${EOL} * * *${EOL}${EOL}`; acc.body.push(body); @@ -135,18 +138,25 @@ const getMarkdownDataForStaticRedirects = () => { const staticRedirects = fs.readFileSync(path.resolve(__dirname, staticRedirectsPath), { encoding: 'utf8' }); const parsedStaticRedirects = yaml.safeLoad(staticRedirects); - const output = parsedStaticRedirects.reduce((acc, { title, description }) => { - if (description) { - acc.list.push(`* [${title}](#${title})${EOL}`); + const output = parsedStaticRedirects.reduce((acc, { title, description, added }) => { + if (!title) { + throw new Error('No title for static redirect'); + } + if (!description) { + throw new Error(`No description for static redirect '${title}'`); + } + if (!added) { + throw new Error(`No added version for static redirect '${title}'`); + } + + acc.list.push(`* [${title}](#${title})${EOL}`); - const body = `### ⚡️ ${title} -${description} -[Redirect source](${STATIC_REDIRECTS_RELATIVE_SOURCE}) + const body = `### ⚡️ ${title}${EOL} +${added ? `> Added in ${added}.` : '> Adding version is unknown.'}${EOL} +${description}${EOL} +[Redirect source](${STATIC_REDIRECTS_RELATIVE_SOURCE})${EOL} * * *${EOL}${EOL}`; - acc.body.push(body); - } else { - throw new Error(`No description for ${title}`); - } + acc.body.push(body); return acc; }, { list: [], body: [] }); @@ -170,18 +180,25 @@ const getMarkdownDataForBlockingRedirects = () => { const blockingRedirects = fs.readFileSync(blockingRedirectsPath, { encoding: 'utf8' }); const parsedBlockingRedirects = yaml.safeLoad(blockingRedirects); - const output = parsedBlockingRedirects.reduce((acc, { title, description }) => { - if (description) { - acc.list.push(`* [${title}](#${title})${EOL}`); + const output = parsedBlockingRedirects.reduce((acc, { title, description, added }) => { + if (!title) { + throw new Error('No title for blocking redirect'); + } + if (!description) { + throw new Error(`No description for blocking redirect '${title}'`); + } + if (!added) { + throw new Error(`No added version for blocking redirect '${title}'`); + } + + acc.list.push(`* [${title}](#${title})${EOL}`); - const body = `### ⚡️ ${title} -${description} -[Redirect source](${BLOCKING_REDIRECTS_RELATIVE_SOURCE}/${title}) + const body = `### ⚡️ ${title}${EOL} +${added ? `> Added in ${added}.` : '> Adding version is unknown.'}${EOL} +${description}${EOL} +[Redirect source](${BLOCKING_REDIRECTS_RELATIVE_SOURCE}/${title})${EOL} * * *${EOL}${EOL}`; - acc.body.push(body); - } else { - throw new Error(`No description for ${title}`); - } + acc.body.push(body); return acc; }, { list: [], body: [] }); @@ -206,8 +223,8 @@ const buildWikiAboutPages = () => { const staticRedirectsMarkdownData = getMarkdownDataForStaticRedirects(); const blockingRedirectsMarkdownData = getMarkdownDataForBlockingRedirects(); - const scriptletsPageContent = `## Available Scriptlets -${scriptletsMarkdownData.list}* * * + const scriptletsPageContent = `## Available Scriptlets${EOL} +${scriptletsMarkdownData.list}* * *${EOL} ${scriptletsMarkdownData.body}`; fs.writeFileSync( path.resolve(__dirname, aboutScriptletsPath), diff --git a/scripts/helpers.js b/scripts/helpers.js index 8dcec4ef..e81fb105 100644 --- a/scripts/helpers.js +++ b/scripts/helpers.js @@ -32,15 +32,15 @@ const getFilesList = (relativeDirPath) => { /** * @typedef {Object} CommentTag - * @property {string} type tag name - * @property {string} string text following the tag + * @property {string} type Tag name, e.g. `@scriptlet`, `@redirect`, `@added`. + * @property {string} string Text following the tag name. */ /** * Returns parsed tags data which we use to describe the sources: * - `@scriptlet`/`trustedScriptlet`/`@redirect` to describe the type and name of source; * - `@description` actual description for scriptlet or redirect. - * required comments from file. + * - `@added` means version when scriptlet or redirect was implemented. * In one file might be comments describing scriptlet and redirect as well. * * @param {string} filePath absolute path to file @@ -95,11 +95,17 @@ Please add one OR edit the list of NON_SCRIPTLETS_FILES / NON_REDIRECTS_FILES.`) * @returns {DescribingCommentData} */ const prepareCommentsData = (commentTags, source) => { - const [base, sup] = commentTags; + const [typeTag, descriptionTag, addedTag] = commentTags; + const name = typeTag.string; + const versionAdded = addedTag?.string; + if (!versionAdded) { + throw new Error(`No @added tag for ${name}`); + } return { - type: base.type, - name: base.string, - description: sup.string, + type: typeTag.type, + name, + description: descriptionTag.string, + versionAdded, source, }; }; diff --git a/src/redirects/amazon-apstag.js b/src/redirects/amazon-apstag.js index 959dca69..9869fce6 100644 --- a/src/redirects/amazon-apstag.js +++ b/src/redirects/amazon-apstag.js @@ -2,6 +2,7 @@ import { hit, noopFunc } from '../helpers/index'; /** * @redirect amazon-apstag + * * @description * Mocks Amazon's apstag.js * @@ -12,6 +13,8 @@ import { hit, noopFunc } from '../helpers/index'; * ``` * ||amazon-adsystem.com/aax2/apstag.js$script,redirect=amazon-apstag * ``` + * + * @added v1.2.3. */ export function AmazonApstag(source) { const apstagWrapper = { diff --git a/src/redirects/ati-smarttag.js b/src/redirects/ati-smarttag.js index 4a00ab27..99383725 100644 --- a/src/redirects/ati-smarttag.js +++ b/src/redirects/ati-smarttag.js @@ -2,6 +2,7 @@ import { hit, noopFunc } from '../helpers/index'; /** * @redirect ati-smarttag + * * @description * Mocks AT Internat SmartTag. * https://developers.atinternet-solutions.com/as2-tagging-en/javascript-en/getting-started-javascript-en/tracker-initialisation-javascript-en/ @@ -10,6 +11,8 @@ import { hit, noopFunc } from '../helpers/index'; * ``` * ||bloctel.gouv.fr/assets/scripts/smarttag.js$script,redirect=ati-smarttag * ``` + * + * @added v1.5.0. */ export function ATInternetSmartTag(source) { const setNoopFuncWrapper = { diff --git a/src/redirects/blocking-redirects.yml b/src/redirects/blocking-redirects.yml index 8925ad6b..9dfc4f62 100644 --- a/src/redirects/blocking-redirects.yml +++ b/src/redirects/blocking-redirects.yml @@ -4,6 +4,7 @@ # use ">" if property contains long string - title: click2load.html + added: v1.5.0 description: |- Redirects resource and replaces supposed content by decoy frame with button for original content recovering @@ -11,6 +12,7 @@ https://github.com/gorhill/uBlock/blob/1.31.0/src/web_accessible_resources/click2load.html **Example** + ``` ||youtube.com/embed/$frame,third-party,redirect=click2load.html ``` diff --git a/src/redirects/didomi-loader.js b/src/redirects/didomi-loader.js index 06b28f13..2ba9a60f 100644 --- a/src/redirects/didomi-loader.js +++ b/src/redirects/didomi-loader.js @@ -9,6 +9,7 @@ import { /** * @redirect didomi-loader + * * @description * Mocks Didomi's CMP loader script. * https://developers.didomi.io/ @@ -17,6 +18,8 @@ import { * ``` * ||sdk.privacy-center.org/fbf86806f86e/loader.js$script,redirect=didomi-loader * ``` + * + * @added v1.6.2. */ export function DidomiLoader(source) { function UserConsentStatusForVendorSubscribe() { } diff --git a/src/redirects/fingerprintjs2.js b/src/redirects/fingerprintjs2.js index a3f04a8d..258dd7b2 100644 --- a/src/redirects/fingerprintjs2.js +++ b/src/redirects/fingerprintjs2.js @@ -3,6 +3,7 @@ import { hit } from '../helpers/index'; /** * @redirect fingerprintjs2 + * * @description * Mocks FingerprintJS v2 * https://github.com/fingerprintjs @@ -14,6 +15,8 @@ import { hit } from '../helpers/index'; * ``` * ||the-japan-news.com/modules/js/lib/fgp/fingerprint2.js$script,redirect=fingerprintjs2 * ``` + * + * @added v1.5.0. */ export function Fingerprintjs2(source) { let browserId = ''; diff --git a/src/redirects/fingerprintjs3.js b/src/redirects/fingerprintjs3.js index 2c073b33..22a25fbd 100644 --- a/src/redirects/fingerprintjs3.js +++ b/src/redirects/fingerprintjs3.js @@ -6,6 +6,7 @@ import { /** * @redirect fingerprintjs3 + * * @description * Mocks FingerprintJS v3 * https://github.com/fingerprintjs @@ -17,6 +18,8 @@ import { * ``` * ||sephora.com/js/ufe/isomorphic/thirdparty/fp.min.js$script,redirect=fingerprintjs3 * ``` + * + * @added v1.6.2. */ export function Fingerprintjs3(source) { const visitorId = (() => { diff --git a/src/redirects/gemius.js b/src/redirects/gemius.js index cfaf6284..7c6ce9b2 100644 --- a/src/redirects/gemius.js +++ b/src/redirects/gemius.js @@ -3,6 +3,7 @@ import { hit, noopFunc } from '../helpers/index'; /** * @redirect gemius + * * @description * Mocks Gemius Analytics. * https://flowplayer.com/developers/plugins/gemius @@ -11,6 +12,8 @@ import { hit, noopFunc } from '../helpers/index'; * ``` * ||gapt.hit.gemius.pl/gplayer.js$script,redirect=gemius * ``` + * + * @added v1.5.0. */ export function Gemius(source) { const GemiusPlayer = function () {}; diff --git a/src/redirects/google-analytics-ga.js b/src/redirects/google-analytics-ga.js index 9e86a66b..0ea8fb61 100644 --- a/src/redirects/google-analytics-ga.js +++ b/src/redirects/google-analytics-ga.js @@ -7,6 +7,7 @@ import { /** * @redirect google-analytics-ga + * * @description * Mocks old Google Analytics API. * @@ -17,6 +18,8 @@ import { * ``` * ||google-analytics.com/ga.js$script,redirect=google-analytics-ga * ``` + * + * @added v1.0.10. */ export function GoogleAnalyticsGa(source) { // Gaq constructor diff --git a/src/redirects/google-analytics.js b/src/redirects/google-analytics.js index e42214d9..d1590d6c 100644 --- a/src/redirects/google-analytics.js +++ b/src/redirects/google-analytics.js @@ -7,6 +7,7 @@ import { /** * @redirect google-analytics + * * @description * Mocks Google's Analytics and Tag Manager APIs. * [Covers obsolete googletagmanager-gtm redirect functionality](https://github.com/AdguardTeam/Scriptlets/issues/127). @@ -19,6 +20,8 @@ import { * ||google-analytics.com/analytics.js$script,redirect=google-analytics * ||googletagmanager.com/gtm.js$script,redirect=googletagmanager-gtm * ``` + * + * @added v1.0.10. */ export function GoogleAnalytics(source) { // eslint-disable-next-line func-names diff --git a/src/redirects/google-ima3.js b/src/redirects/google-ima3.js index 807bbb79..fd8a2bdf 100644 --- a/src/redirects/google-ima3.js +++ b/src/redirects/google-ima3.js @@ -7,6 +7,7 @@ import { /** * @redirect google-ima3 + * * @description * Mocks the IMA SDK of Google. * @@ -14,6 +15,8 @@ import { * ``` * ||imasdk.googleapis.com/js/sdkloader/ima3.js$script,redirect=google-ima3 * ``` + * + * @added v1.6.2. */ export function GoogleIma3(source) { diff --git a/src/redirects/googlesyndication-adsbygoogle.js b/src/redirects/googlesyndication-adsbygoogle.js index 80832f5a..241b2667 100644 --- a/src/redirects/googlesyndication-adsbygoogle.js +++ b/src/redirects/googlesyndication-adsbygoogle.js @@ -3,6 +3,7 @@ import { hit } from '../helpers/index'; /* eslint-disable max-len */ /** * @redirect googlesyndication-adsbygoogle + * * @description * Mocks Google AdSense API. * @@ -13,6 +14,8 @@ import { hit } from '../helpers/index'; * ``` * ||pagead2.googlesyndication.com/pagead/js/adsbygoogle.js$script,redirect=googlesyndication-adsbygoogle * ``` + * + * @added v1.0.10. */ /* eslint-enable max-len */ export function GoogleSyndicationAdsByGoogle(source) { diff --git a/src/redirects/googletagservices-gpt.js b/src/redirects/googletagservices-gpt.js index f2ece88d..8b0cf68c 100644 --- a/src/redirects/googletagservices-gpt.js +++ b/src/redirects/googletagservices-gpt.js @@ -11,6 +11,7 @@ import { /** * @redirect googletagservices-gpt + * * @description * Mocks Google Publisher Tag API. * @@ -21,6 +22,8 @@ import { * ``` * ||googletagservices.com/tag/js/gpt.js$script,redirect=googletagservices-gpt * ``` + * + * @added v1.0.10. */ export function GoogleTagServicesGpt(source) { const slots = new Map(); diff --git a/src/redirects/matomo.js b/src/redirects/matomo.js index 649c87cc..8a51ea93 100644 --- a/src/redirects/matomo.js +++ b/src/redirects/matomo.js @@ -3,6 +3,7 @@ import { hit, noopFunc } from '../helpers/index'; /** * @redirect matomo + * * @description * Mocks the piwik.js file of Matomo (formerly Piwik). * @@ -10,6 +11,8 @@ import { hit, noopFunc } from '../helpers/index'; * ``` * ||example.org/piwik.js$script,redirect=matomo * ``` + * + * @added v1.5.0. */ export function Matomo(source) { diff --git a/src/redirects/metrika-yandex-tag.js b/src/redirects/metrika-yandex-tag.js index a432926b..3ddeab3c 100644 --- a/src/redirects/metrika-yandex-tag.js +++ b/src/redirects/metrika-yandex-tag.js @@ -2,6 +2,7 @@ import { hit, noopFunc } from '../helpers/index'; /** * @redirect metrika-yandex-tag + * * @description * Mocks Yandex Metrika API. * https://yandex.ru/support/metrica/objects/method-reference.html @@ -10,6 +11,8 @@ import { hit, noopFunc } from '../helpers/index'; * ``` * ||mc.yandex.ru/metrika/tag.js$script,redirect=metrika-yandex-tag * ``` + * + * @added v1.0.10. */ export function metrikaYandexTag(source) { const asyncCallbackFromOptions = (id, param, options = {}) => { diff --git a/src/redirects/metrika-yandex-watch.js b/src/redirects/metrika-yandex-watch.js index f2646de7..10caacc6 100644 --- a/src/redirects/metrika-yandex-watch.js +++ b/src/redirects/metrika-yandex-watch.js @@ -2,6 +2,7 @@ import { hit, noopFunc, noopArray } from '../helpers/index'; /** * @redirect metrika-yandex-watch + * * @description * Mocks the old Yandex Metrika API. * https://yandex.ru/support/metrica/objects/_method-reference.html @@ -10,6 +11,8 @@ import { hit, noopFunc, noopArray } from '../helpers/index'; * ``` * ||mc.yandex.ru/metrika/watch.js$script,redirect=metrika-yandex-watch * ``` + * + * @added v1.0.10. */ export function metrikaYandexWatch(source) { const cbName = 'yandex_metrika_callbacks'; diff --git a/src/redirects/naver-wcslog.js b/src/redirects/naver-wcslog.js index e84f0f11..df75e0b6 100644 --- a/src/redirects/naver-wcslog.js +++ b/src/redirects/naver-wcslog.js @@ -3,6 +3,7 @@ import { hit, noopFunc } from '../helpers/index'; /** * @redirect naver-wcslog + * * @description * Mocks wcslog.js of Naver Analytics. * @@ -10,6 +11,8 @@ import { hit, noopFunc } from '../helpers/index'; * ``` * ||wcs.naver.net/wcslog.js$script,redirect=naver-wcslog * ``` + * + * @added v1.6.2. */ export function NaverWcslog(source) { diff --git a/src/redirects/noeval.js b/src/redirects/noeval.js index 698f4642..b449582e 100644 --- a/src/redirects/noeval.js +++ b/src/redirects/noeval.js @@ -2,6 +2,7 @@ import { noeval } from '../scriptlets/noeval'; /** * @redirect noeval + * * @description * Redirects request to the source which sets static properties to PopAds and popns objects. * @@ -18,5 +19,7 @@ import { noeval } from '../scriptlets/noeval'; * ``` * ||example.org/index.js$script,redirect=noeval * ``` + * + * @added v1.0.4. */ export { noeval }; diff --git a/src/redirects/pardot-1.0.js b/src/redirects/pardot-1.0.js index e23f1904..426429e7 100644 --- a/src/redirects/pardot-1.0.js +++ b/src/redirects/pardot-1.0.js @@ -8,6 +8,7 @@ import { /** * @redirect pardot-1.0 + * * @description * Mocks the pd.js file of Salesforce. * https://pi.pardot.com/pd.js @@ -18,6 +19,8 @@ import { * ||pi.pardot.com/pd.js$script,redirect=pardot * ||pacedg.com.au/pd.js$redirect=pardot * ``` + * + * @added v1.6.55. */ export function Pardot(source) { diff --git a/src/redirects/prebid-ads.js b/src/redirects/prebid-ads.js index ff4fccc7..19483cc2 100644 --- a/src/redirects/prebid-ads.js +++ b/src/redirects/prebid-ads.js @@ -3,6 +3,7 @@ import { hit } from '../helpers/index'; /** * @redirect prebid-ads + * * @description * Sets predefined constants on a page: * - `canRunAds`: `true` @@ -12,6 +13,8 @@ import { hit } from '../helpers/index'; * ``` * ||playerdrive.me/assets/js/prebid-ads.js$script,redirect=prebid-ads * ``` + * + * @added v1.6.2. */ export function prebidAds(source) { window.canRunAds = true; diff --git a/src/redirects/prebid.js b/src/redirects/prebid.js index 77356c57..911aa806 100644 --- a/src/redirects/prebid.js +++ b/src/redirects/prebid.js @@ -8,6 +8,7 @@ import { /** * @redirect prebid + * * @description * Mocks the prebid.js header bidding suit. * https://docs.prebid.org/ @@ -16,6 +17,8 @@ import { * ``` * ||tmgrup.com.tr/bd/hb/prebid.js$script,redirect=prebid * ``` + * + * @added v1.6.2. */ export function Prebid(source) { diff --git a/src/redirects/prevent-bab.js b/src/redirects/prevent-bab.js index bbf4feef..3a76f087 100644 --- a/src/redirects/prevent-bab.js +++ b/src/redirects/prevent-bab.js @@ -2,6 +2,7 @@ import { preventBab as preventBabScriptlet } from '../scriptlets/prevent-bab'; /** * @redirect prevent-bab + * * @description * Prevents BlockAdblock script from detecting an ad blocker. * @@ -15,6 +16,8 @@ import { preventBab as preventBabScriptlet } from '../scriptlets/prevent-bab'; * ``` * /blockadblock.$script,redirect=prevent-bab * ``` + * + * @added v1.3.19. */ const preventBab = preventBabScriptlet; preventBab.names = [ diff --git a/src/redirects/prevent-bab2.js b/src/redirects/prevent-bab2.js index 85ac5523..674d9f15 100644 --- a/src/redirects/prevent-bab2.js +++ b/src/redirects/prevent-bab2.js @@ -3,6 +3,7 @@ import { hit } from '../helpers/index'; /** * @redirect prevent-bab2 + * * @description * Prevents BlockAdblock script from detecting an ad blocker. * @@ -15,6 +16,8 @@ import { hit } from '../helpers/index'; * ``` * /blockadblock.$script,redirect=prevent-bab2 * ``` + * + * @added v1.5.0. */ export function preventBab2(source) { const script = document.currentScript; diff --git a/src/redirects/prevent-fab-3.2.0.js b/src/redirects/prevent-fab-3.2.0.js index c4973295..04f86983 100644 --- a/src/redirects/prevent-fab-3.2.0.js +++ b/src/redirects/prevent-fab-3.2.0.js @@ -2,6 +2,7 @@ import { preventFab } from '../scriptlets/prevent-fab-3.2.0'; /** * @redirect prevent-fab-3.2.0 + * * @description * Redirects fuckadblock script to the source js file. * @@ -9,5 +10,7 @@ import { preventFab } from '../scriptlets/prevent-fab-3.2.0'; * ``` * \*\/fuckadblock-$script,redirect=prevent-fab-3.2.0 * ``` + * + * @added v1.0.4. */ export { preventFab }; diff --git a/src/redirects/prevent-popads-net.js b/src/redirects/prevent-popads-net.js index b0d2bb54..54f0b8bf 100644 --- a/src/redirects/prevent-popads-net.js +++ b/src/redirects/prevent-popads-net.js @@ -2,6 +2,7 @@ import { preventPopadsNet } from '../scriptlets/prevent-popads-net'; /** * @redirect prevent-popads-net + * * @description * Redirects request to the source which sets static properties to PopAds and popns objects. * @@ -9,5 +10,7 @@ import { preventPopadsNet } from '../scriptlets/prevent-popads-net'; * ``` * ||popads.net/pop.js$script,redirect=prevent-popads-net * ``` + * + * @added v1.0.4. */ export { preventPopadsNet }; diff --git a/src/redirects/scorecardresearch-beacon.js b/src/redirects/scorecardresearch-beacon.js index 9900706a..1644a1cd 100644 --- a/src/redirects/scorecardresearch-beacon.js +++ b/src/redirects/scorecardresearch-beacon.js @@ -2,6 +2,7 @@ import { hit } from '../helpers/index'; /** * @redirect scorecardresearch-beacon + * * @description * Mocks Scorecard Research API. * @@ -12,6 +13,8 @@ import { hit } from '../helpers/index'; * ``` * ||sb.scorecardresearch.com/beacon.js$script,redirect=scorecardresearch-beacon * ``` + * + * @added v1.0.10. */ export function ScoreCardResearchBeacon(source) { window.COMSCORE = { diff --git a/src/redirects/set-popads-dummy.js b/src/redirects/set-popads-dummy.js index 70af5001..ca7e0349 100644 --- a/src/redirects/set-popads-dummy.js +++ b/src/redirects/set-popads-dummy.js @@ -2,6 +2,7 @@ import { setPopadsDummy } from '../scriptlets/set-popads-dummy'; /** * @redirect set-popads-dummy + * * @description * Redirects request to the source which sets static properties to PopAds and popns objects. * @@ -9,5 +10,7 @@ import { setPopadsDummy } from '../scriptlets/set-popads-dummy'; * ``` * ||popads.net^$script,redirect=set-popads-dummy,domain=example.org * ``` + * + * @added v1.0.4. */ export { setPopadsDummy }; diff --git a/src/redirects/static-redirects.yml b/src/redirects/static-redirects.yml index 118952a4..300b0490 100644 --- a/src/redirects/static-redirects.yml +++ b/src/redirects/static-redirects.yml @@ -3,8 +3,10 @@ # add ";base64" into contentType if your source already in base64 - title: 1x1-transparent.gif + added: v1.0.4 description: |- **Example** + ``` ||example.org^$image,redirect=1x1-transparent.gif ``` @@ -17,8 +19,10 @@ content: R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== - title: 2x2-transparent.png + added: v1.0.4 description: |- **Example** + ``` ||example.org^$image,redirect=2x2-transparent.png ``` @@ -32,8 +36,10 @@ SUVORK5CYII= - title: 3x2-transparent.png + added: v1.0.4 description: |- **Example** + ``` ||example.org^$image,redirect=3x2-transparent.png ``` @@ -47,8 +53,10 @@ SUVORK5CYII= - title: 32x32-transparent.png + added: v1.0.4 description: |- **Example** + ``` ||example.org^$image,redirect=32x32-transparent.png ``` @@ -62,8 +70,10 @@ AO8GECAAAZf3V9cAAAAASUVORK5CYII= - title: noopframe + added: v1.0.4 description: |- **Example** + ``` ||example.com^$subdocument,redirect=noopframe,domain=example.org ``` @@ -80,8 +90,10 @@ - title: noopcss + added: v1.0.4 description: |- **Example** + ``` ||example.org/style.css$stylesheet,redirect=noopcss ``` @@ -93,6 +105,7 @@ content: '' - title: noopjs + added: v1.0.4 description: |- **Example** ``` @@ -106,6 +119,7 @@ content: (function() {})() - title: noopjson + added: v1.6.2 description: |- **Example** ``` @@ -116,8 +130,10 @@ content: '{}' - title: nooptext + added: v1.0.4 description: |- **Example** + ``` ||example.org/advert.js$xmlhttprequest,redirect=nooptext ``` @@ -129,6 +145,7 @@ content: '' - title: empty + added: v1.3.9 description: |- Pretty much the same as `nooptext`. Used for conversion of modifier `empty` so better avoid its using in production filter lists. @@ -143,10 +160,12 @@ content: '' - title: noopvmap-1.0 + added: v1.1.5 description: |- Redirects request to an empty VMAP response. **Example** + ``` ||example.org/vmap01.xml$xmlhttprequest,redirect=noopvmap-1.0 ``` @@ -157,6 +176,7 @@ content: - title: noopvast-2.0 + added: v1.0.10 description: |- Redirects request to an empty VAST 2.0 response. @@ -169,6 +189,7 @@ content: - title: noopvast-3.0 + added: v1.0.10 description: |- Redirects request to an empty VAST 3.0 response. @@ -181,6 +202,7 @@ content: - title: noopvast-4.0 + added: v1.4.3 description: |- Redirects request to an empty VAST 4.0 response. @@ -193,8 +215,10 @@ content: - title: noopmp3-0.1s + added: v1.0.4 description: |- **Example** + ``` ||example.org/advert.mp3$media,redirect=noopmp3-0.1s ``` @@ -224,8 +248,10 @@ VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV - title: noopmp4-1s + added: v1.0.4 description: |- **Example** + ``` ||example.org/advert.mp4$media,redirect=noopmp4-1s ``` diff --git a/src/scriptlets/abort-current-inline-script.js b/src/scriptlets/abort-current-inline-script.js index c3945816..f42d398b 100644 --- a/src/scriptlets/abort-current-inline-script.js +++ b/src/scriptlets/abort-current-inline-script.js @@ -16,6 +16,7 @@ import { /* eslint-disable max-len */ /** * @scriptlet abort-current-inline-script + * * @description * Aborts an inline script when it attempts to **read** or **write to** the specified property * AND when the contents of the ` * ``` + * + * @added v1.0.4. */ /* eslint-enable max-len */ export function abortCurrentInlineScript(source, property, search) { diff --git a/src/scriptlets/abort-on-property-read.js b/src/scriptlets/abort-on-property-read.js index 3f7e0101..4af0e4a1 100644 --- a/src/scriptlets/abort-on-property-read.js +++ b/src/scriptlets/abort-on-property-read.js @@ -12,6 +12,7 @@ import { /* eslint-disable max-len */ /** * @scriptlet abort-on-property-read + * * @description * Aborts a script when it attempts to **read** the specified property. * @@ -36,6 +37,8 @@ import { * ! Aborts script when it tries to access `navigator.language` * example.org#%#//scriptlet('abort-on-property-read', 'navigator.language') * ``` + * + * @added v1.0.4. */ /* eslint-enable max-len */ export function abortOnPropertyRead(source, property) { diff --git a/src/scriptlets/abort-on-property-write.js b/src/scriptlets/abort-on-property-write.js index 32539845..da3a2a66 100644 --- a/src/scriptlets/abort-on-property-write.js +++ b/src/scriptlets/abort-on-property-write.js @@ -12,6 +12,7 @@ import { /* eslint-disable max-len */ /** * @scriptlet abort-on-property-write + * * @description * Aborts a script when it attempts to **write** the specified property. * @@ -33,6 +34,8 @@ import { * ! Aborts script when it tries to set `window.adblock` value * example.org#%#//scriptlet('abort-on-property-write', 'adblock') * ``` + * + * @added v1.0.4. */ /* eslint-enable max-len */ export function abortOnPropertyWrite(source, property) { diff --git a/src/scriptlets/abort-on-stack-trace.js b/src/scriptlets/abort-on-stack-trace.js index 248e97e9..449efd88 100644 --- a/src/scriptlets/abort-on-stack-trace.js +++ b/src/scriptlets/abort-on-stack-trace.js @@ -20,6 +20,7 @@ import { /* eslint-disable max-len */ /** * @scriptlet abort-on-stack-trace + * * @description * Aborts a script when it attempts to utilize (read or write to) the specified property and it's error stack trace contains given value. * @@ -55,6 +56,8 @@ import { * ! Aborts script when it tries to access `window.Ya` and it's an injected script * example.org#%#//scriptlet('abort-on-stack-trace', 'Ya', 'injectedScript') * ``` + * + * @added v1.5.0. */ /* eslint-enable max-len */ export function abortOnStackTrace(source, property, stack) { diff --git a/src/scriptlets/adjust-setInterval.js b/src/scriptlets/adjust-setInterval.js index 4bdd55a9..a5ff61e9 100644 --- a/src/scriptlets/adjust-setInterval.js +++ b/src/scriptlets/adjust-setInterval.js @@ -15,6 +15,7 @@ import { /* eslint-disable max-len */ /** * @scriptlet adjust-setInterval + * * @description * Adjusts delay for specified setInterval() callbacks. * @@ -63,6 +64,8 @@ import { * ``` * example.org#%#//scriptlet('adjust-setInterval', '', '*', '0.02') * ``` + * + * @added v1.0.4. */ /* eslint-enable max-len */ export function adjustSetInterval(source, matchCallback, matchDelay, boost) { diff --git a/src/scriptlets/adjust-setTimeout.js b/src/scriptlets/adjust-setTimeout.js index 4f6cf388..1a24d94d 100644 --- a/src/scriptlets/adjust-setTimeout.js +++ b/src/scriptlets/adjust-setTimeout.js @@ -15,6 +15,7 @@ import { /* eslint-disable max-len */ /** * @scriptlet adjust-setTimeout + * * @description * Adjusts delay for specified setTimeout() callbacks. * @@ -63,6 +64,8 @@ import { * ``` * example.org#%#//scriptlet('adjust-setTimeout', 'test', '*') * ``` + * + * @added v1.0.4. */ /* eslint-enable max-len */ export function adjustSetTimeout(source, matchCallback, matchDelay, boost) { diff --git a/src/scriptlets/close-window.js b/src/scriptlets/close-window.js index ff5592f8..26fb1309 100644 --- a/src/scriptlets/close-window.js +++ b/src/scriptlets/close-window.js @@ -6,6 +6,7 @@ import { /** * @scriptlet close-window + * * @description * Closes the browser tab immediately. * @@ -29,6 +30,8 @@ import { * ! closes specific example.org tab * example.org#%#//scriptlet('close-window', '/example-page.html') * ``` + * + * @added v1.5.0. */ export function forceWindowClose(source, path = '') { // https://github.com/AdguardTeam/Scriptlets/issues/158#issuecomment-993423036 diff --git a/src/scriptlets/debug-current-inline-script.js b/src/scriptlets/debug-current-inline-script.js index d2f9d492..7bd3ffff 100644 --- a/src/scriptlets/debug-current-inline-script.js +++ b/src/scriptlets/debug-current-inline-script.js @@ -14,6 +14,7 @@ import { /* eslint-disable max-len */ /** * @scriptlet debug-current-inline-script + * * @description * This scriptlet is basically the same as [abort-current-inline-script](#abort-current-inline-script), but instead of aborting it starts the debugger. * @@ -24,6 +25,8 @@ import { * ! Aborts script when it tries to access `window.alert` * example.org#%#//scriptlet('debug-current-inline-script', 'alert') * ``` + * + * @added v1.0.4. */ /* eslint-enable max-len */ export function debugCurrentInlineScript(source, property, search) { diff --git a/src/scriptlets/debug-on-property-read.js b/src/scriptlets/debug-on-property-read.js index b5bc8f61..62872c59 100644 --- a/src/scriptlets/debug-on-property-read.js +++ b/src/scriptlets/debug-on-property-read.js @@ -13,6 +13,7 @@ import { /* eslint-disable max-len */ /** * @scriptlet debug-on-property-read + * * @description * This scriptlet is basically the same as [abort-on-property-read](#abort-on-property-read), but instead of aborting it starts the debugger. * @@ -25,6 +26,8 @@ import { * ! of `window.open` * example.org#%#//scriptlet('debug-on-property-read', 'open') * ``` + * + * @added v1.0.4. */ /* eslint-enable max-len */ export function debugOnPropertyRead(source, property) { diff --git a/src/scriptlets/debug-on-property-write.js b/src/scriptlets/debug-on-property-write.js index 1064dbdb..a45cc5a4 100644 --- a/src/scriptlets/debug-on-property-write.js +++ b/src/scriptlets/debug-on-property-write.js @@ -12,6 +12,7 @@ import { /* eslint-disable max-len */ /** * @scriptlet debug-on-property-write + * * @description * This scriptlet is basically the same as [abort-on-property-write](#abort-on-property-write), but instead of aborting it starts the debugger. * @@ -22,6 +23,8 @@ import { * ! Aborts script when it tries to write in property `window.test` * example.org#%#//scriptlet('debug-on-property-write', 'test') * ``` + * + * @added v1.0.4. */ /* eslint-enable max-len */ export function debugOnPropertyWrite(source, property) { diff --git a/src/scriptlets/dir-string.js b/src/scriptlets/dir-string.js index 63de2609..7b990b7d 100644 --- a/src/scriptlets/dir-string.js +++ b/src/scriptlets/dir-string.js @@ -3,6 +3,7 @@ import { hit } from '../helpers/index'; /* eslint-disable max-len */ /** * @scriptlet dir-string + * * @description * Wraps the `console.dir` API to call the `toString` method of the argument. * There are several adblock circumvention systems that detect browser devtools @@ -24,6 +25,8 @@ import { hit } from '../helpers/index'; * ! Run 2 times * example.org#%#//scriptlet('dir-string', '2') * ``` + * + * @added v1.0.4. */ /* eslint-enable max-len */ export function dirString(source, times) { diff --git a/src/scriptlets/disable-newtab-links.js b/src/scriptlets/disable-newtab-links.js index 5cc28ec8..18057ce4 100644 --- a/src/scriptlets/disable-newtab-links.js +++ b/src/scriptlets/disable-newtab-links.js @@ -2,6 +2,7 @@ import { hit } from '../helpers/index'; /** * @scriptlet disable-newtab-links + * * @description * Prevents opening new tabs and windows if there is `target` attribute in element. * @@ -12,6 +13,8 @@ import { hit } from '../helpers/index'; * ``` * example.org#%#//scriptlet('disable-newtab-links') * ``` + * + * @added v1.0.4. */ export function disableNewtabLinks(source) { document.addEventListener('click', (ev) => { diff --git a/src/scriptlets/hide-in-shadow-dom.js b/src/scriptlets/hide-in-shadow-dom.js index c424a071..d79d283d 100644 --- a/src/scriptlets/hide-in-shadow-dom.js +++ b/src/scriptlets/hide-in-shadow-dom.js @@ -11,6 +11,7 @@ import { /** * @scriptlet hide-in-shadow-dom + * * @description * Hides elements inside open shadow DOM elements. * @@ -34,6 +35,8 @@ import { * ! hides floating element * virustotal.com#%#//scriptlet('hide-in-shadow-dom', 'vt-ui-contact-fab') * ``` + * + * @added v1.3.0. */ export function hideInShadowDom(source, selector, baseSelector) { // do nothing if browser does not support ShadowRoot diff --git a/src/scriptlets/inject-css-in-shadow-dom.js b/src/scriptlets/inject-css-in-shadow-dom.js index c597d73a..94f406e0 100644 --- a/src/scriptlets/inject-css-in-shadow-dom.js +++ b/src/scriptlets/inject-css-in-shadow-dom.js @@ -7,6 +7,7 @@ import { /* eslint-disable max-len */ /** * @scriptlet inject-css-in-shadow-dom + * * @description * Injects CSS rule into selected Shadow DOM subtrees on a page * @@ -29,6 +30,8 @@ import { * ``` * example.org#%#//scriptlet('inject-css-in-shadow-dom', '#content { margin-top: 0 !important; }', '.row > #hidden') * ``` + * + * @added v1.8.2. */ /* eslint-enable max-len */ diff --git a/src/scriptlets/json-prune.js b/src/scriptlets/json-prune.js index f38b3d20..0b6526e5 100644 --- a/src/scriptlets/json-prune.js +++ b/src/scriptlets/json-prune.js @@ -12,8 +12,9 @@ import { /* eslint-disable max-len */ /** * @scriptlet json-prune + * * @description - * Removes specified properties from the result of calling JSON.parse and returns the caller + * Removes specified properties from the result of calling JSON.parse and returns the caller. * * Related UBO scriptlet: * https://github.com/gorhill/uBlock/wiki/Resources-Library#json-prunejs- @@ -83,6 +84,8 @@ import { * ``` * example.org#%#//scriptlet('json-prune', '', '"id":"117458"') * ``` + * + * @added v1.1.0. */ /* eslint-enable max-len */ export function jsonPrune(source, propsToRemove, requiredInitialProps, stack) { diff --git a/src/scriptlets/log-addEventListener.js b/src/scriptlets/log-addEventListener.js index 354556eb..f0b85998 100644 --- a/src/scriptlets/log-addEventListener.js +++ b/src/scriptlets/log-addEventListener.js @@ -13,6 +13,7 @@ import { /** * @scriptlet log-addEventListener + * * @description * Logs all addEventListener calls to the console. * @@ -23,6 +24,8 @@ import { * ``` * example.org#%#//scriptlet('log-addEventListener') * ``` + * + * @added v1.0.4. */ export function logAddEventListener(source) { const nativeAddEventListener = window.EventTarget.prototype.addEventListener; diff --git a/src/scriptlets/log-eval.js b/src/scriptlets/log-eval.js index 8da8ace9..de23e16d 100644 --- a/src/scriptlets/log-eval.js +++ b/src/scriptlets/log-eval.js @@ -3,6 +3,7 @@ import { hit, logMessage } from '../helpers/index'; /** * @scriptlet log-eval + * * @description * Logs all `eval()` or `new Function()` calls to the console. * @@ -10,6 +11,8 @@ import { hit, logMessage } from '../helpers/index'; * ``` * example.org#%#//scriptlet('log-eval') * ``` + * + * @added v1.0.4. */ export function logEval(source) { // wrap eval function diff --git a/src/scriptlets/log-on-stack-trace.js b/src/scriptlets/log-on-stack-trace.js index 8bdd7d2b..31a85028 100644 --- a/src/scriptlets/log-on-stack-trace.js +++ b/src/scriptlets/log-on-stack-trace.js @@ -11,6 +11,7 @@ import { /* eslint-disable max-len */ /** * @scriptlet log-on-stack-trace + * * @description * This scriptlet is basically the same as [abort-on-stack-trace](#abort-on-stack-trace), but instead of aborting it logs: * - function and source script names pairs that access the given property @@ -23,6 +24,8 @@ import { * ``` * * - `property` — required, path to a property. The property must be attached to window. + * + * @added v1.5.0. */ /* eslint-enable max-len */ export function logOnStacktrace(source, property) { diff --git a/src/scriptlets/log.js b/src/scriptlets/log.js index f7701a3a..ac8cc6c3 100644 --- a/src/scriptlets/log.js +++ b/src/scriptlets/log.js @@ -1,5 +1,6 @@ /** * @scriptlet log + * * @description * A simple scriptlet which only purpose is to print arguments to console. * This scriptlet can be helpful for debugging and troubleshooting other scriptlets. @@ -8,6 +9,8 @@ * ``` * example.org#%#//scriptlet('log', 'arg1', 'arg2') * ``` + * + * @added v1.0.4. */ export function log(...args) { console.log(args); // eslint-disable-line no-console diff --git a/src/scriptlets/m3u-prune.js b/src/scriptlets/m3u-prune.js index fe4b0b10..a3118991 100644 --- a/src/scriptlets/m3u-prune.js +++ b/src/scriptlets/m3u-prune.js @@ -41,6 +41,8 @@ import { * ``` * example.org#%#//scriptlet('m3u-prune', '', '.m3u8') * ``` + * + * @added v1.9.1. */ /* eslint-enable max-len */ diff --git a/src/scriptlets/no-topics.js b/src/scriptlets/no-topics.js index 6d8dd95e..f3ef6328 100644 --- a/src/scriptlets/no-topics.js +++ b/src/scriptlets/no-topics.js @@ -5,6 +5,7 @@ import { /** * @scriptlet no-topics + * * @description * Prevents using The Topics API * https://developer.chrome.com/docs/privacy-sandbox/topics/ @@ -13,6 +14,8 @@ import { * ``` * example.org#%#//scriptlet('no-topics') * ``` + * + * @added v1.6.18. */ export function noTopics(source) { const TOPICS_PROPERTY_NAME = 'browsingTopics'; diff --git a/src/scriptlets/noeval.js b/src/scriptlets/noeval.js index 1d2b89f9..66a2392e 100644 --- a/src/scriptlets/noeval.js +++ b/src/scriptlets/noeval.js @@ -3,6 +3,7 @@ import { hit, logMessage } from '../helpers/index'; /** * @scriptlet noeval + * * @description * Prevents page to use eval. * Notifies about attempts in the console @@ -17,6 +18,8 @@ import { hit, logMessage } from '../helpers/index'; * ``` * example.org#%#//scriptlet('noeval') * ``` + * + * @added v1.0.4. */ export function noeval(source) { window.eval = function evalWrapper(s) { diff --git a/src/scriptlets/nowebrtc.js b/src/scriptlets/nowebrtc.js index 376d879a..17c2957c 100644 --- a/src/scriptlets/nowebrtc.js +++ b/src/scriptlets/nowebrtc.js @@ -9,6 +9,7 @@ import { /* eslint-disable max-len */ /** * @scriptlet nowebrtc + * * @description * Disables WebRTC by overriding `RTCPeerConnection`. The overridden function will log every attempt to create a new connection. * @@ -19,6 +20,8 @@ import { * ``` * example.org#%#//scriptlet('nowebrtc') * ``` + * + * @added v1.0.4. */ /* eslint-enable max-len */ export function nowebrtc(source) { diff --git a/src/scriptlets/prevent-addEventListener.js b/src/scriptlets/prevent-addEventListener.js index 937a3071..06ac9cdf 100644 --- a/src/scriptlets/prevent-addEventListener.js +++ b/src/scriptlets/prevent-addEventListener.js @@ -9,6 +9,7 @@ import { /* eslint-disable max-len */ /** * @scriptlet prevent-addEventListener + * * @description * Prevents adding event listeners for the specified events and callbacks. * @@ -43,6 +44,8 @@ import { * window.test = 'searchString'; * }); * ``` + * + * @added v1.0.4. */ /* eslint-enable max-len */ export function preventAddEventListener(source, typeSearch, listenerSearch) { diff --git a/src/scriptlets/prevent-adfly.js b/src/scriptlets/prevent-adfly.js index a6e1d7fd..4ab787d4 100644 --- a/src/scriptlets/prevent-adfly.js +++ b/src/scriptlets/prevent-adfly.js @@ -7,6 +7,7 @@ import { /** * @scriptlet prevent-adfly + * * @description * Prevents anti-adblock scripts on adfly short links. * @@ -17,6 +18,8 @@ import { * ``` * example.org#%#//scriptlet('prevent-adfly') * ``` + * + * @added v1.0.4. */ export function preventAdfly(source) { const isDigit = (data) => /^\d$/.test(data); diff --git a/src/scriptlets/prevent-bab.js b/src/scriptlets/prevent-bab.js index b0ac712f..91d8ce75 100644 --- a/src/scriptlets/prevent-bab.js +++ b/src/scriptlets/prevent-bab.js @@ -3,6 +3,7 @@ import { hit } from '../helpers/index'; /** * @scriptlet prevent-bab + * * @description * Prevents BlockAdblock script from detecting an ad blocker. * @@ -16,6 +17,8 @@ import { hit } from '../helpers/index'; * ``` * example.org#%#//scriptlet('prevent-bab') * ``` + * + * @added v1.0.4. */ export function preventBab(source) { const nativeSetTimeout = window.setTimeout; diff --git a/src/scriptlets/prevent-element-src-loading.js b/src/scriptlets/prevent-element-src-loading.js index df99bdb4..7dc1606e 100644 --- a/src/scriptlets/prevent-element-src-loading.js +++ b/src/scriptlets/prevent-element-src-loading.js @@ -8,6 +8,7 @@ import { /* eslint-disable max-len, consistent-return */ /** * @scriptlet prevent-element-src-loading + * * @description * Prevents target element source loading without triggering 'onerror' listeners and not breaking 'onload' ones. * @@ -27,6 +28,8 @@ import { * ``` * example.org#%#//scriptlet('prevent-element-src-loading', 'script' ,'adsbygoogle') * ``` + * + * @added v1.6.2. */ /* eslint-enable max-len */ export function preventElementSrcLoading(source, tagName, match) { diff --git a/src/scriptlets/prevent-eval-if.js b/src/scriptlets/prevent-eval-if.js index 5e3024ae..8c8c1208 100644 --- a/src/scriptlets/prevent-eval-if.js +++ b/src/scriptlets/prevent-eval-if.js @@ -4,6 +4,7 @@ import { toRegExp, hit } from '../helpers/index'; /** * @scriptlet prevent-eval-if + * * @description * Prevents page to use eval matching payload. * @@ -24,6 +25,8 @@ import { toRegExp, hit } from '../helpers/index'; * ! Prevents eval if it matches 'test' * example.org#%#//scriptlet('prevent-eval-if', 'test') * ``` + * + * @added v1.0.4. */ export function preventEvalIf(source, search) { const searchRegexp = toRegExp(search); diff --git a/src/scriptlets/prevent-fab-3.2.0.js b/src/scriptlets/prevent-fab-3.2.0.js index 19eafc1e..ef0f88cb 100644 --- a/src/scriptlets/prevent-fab-3.2.0.js +++ b/src/scriptlets/prevent-fab-3.2.0.js @@ -3,6 +3,7 @@ import { hit, noopFunc, noopThis } from '../helpers/index'; /** * @scriptlet prevent-fab-3.2.0 + * * @description * Prevents execution of the FAB script v3.2.0. * @@ -13,6 +14,8 @@ import { hit, noopFunc, noopThis } from '../helpers/index'; * ``` * example.org#%#//scriptlet('prevent-fab-3.2.0') * ``` + * + * @added v1.0.4. */ export function preventFab(source) { hit(source); diff --git a/src/scriptlets/prevent-fetch.js b/src/scriptlets/prevent-fetch.js index b9bf5404..8df086e8 100644 --- a/src/scriptlets/prevent-fetch.js +++ b/src/scriptlets/prevent-fetch.js @@ -23,6 +23,7 @@ import { /* eslint-disable max-len */ /** * @scriptlet prevent-fetch + * * @description * Prevents `fetch` calls if **all** given parameters match. * @@ -94,6 +95,8 @@ import { * ``` * example.org#%#//scriptlet('prevent-fetch', '*', '', 'opaque') * ``` + * + * @added v1.3.18. */ /* eslint-enable max-len */ export function preventFetch(source, propsToMatch, responseBody = 'emptyObj', responseType) { diff --git a/src/scriptlets/prevent-popads-net.js b/src/scriptlets/prevent-popads-net.js index bbabf584..cb7e3954 100644 --- a/src/scriptlets/prevent-popads-net.js +++ b/src/scriptlets/prevent-popads-net.js @@ -4,6 +4,7 @@ import { /** * @scriptlet prevent-popads-net + * * @description * Aborts on property write (PopAds, popns), throws reference error with random id. * @@ -14,6 +15,8 @@ import { * ``` * example.org#%#//scriptlet('prevent-popads-net') * ``` + * + * @added v1.0.4. */ export function preventPopadsNet(source) { const rid = randomId(); diff --git a/src/scriptlets/prevent-refresh.js b/src/scriptlets/prevent-refresh.js index 082e5858..12198ab2 100644 --- a/src/scriptlets/prevent-refresh.js +++ b/src/scriptlets/prevent-refresh.js @@ -9,6 +9,7 @@ import { /* eslint-disable max-len */ /** * @scriptlet prevent-refresh + * * @description * Prevents reloading of a document through a meta "refresh" tag. * @@ -32,6 +33,8 @@ import { * ``` * cryptodirectories.com#%#//scriptlet('prevent-refresh', 3) * ``` + * + * @added v1.6.2. */ /* eslint-enable max-len */ export function preventRefresh(source, delaySec) { diff --git a/src/scriptlets/prevent-requestAnimationFrame.js b/src/scriptlets/prevent-requestAnimationFrame.js index 7b94a879..268107f6 100644 --- a/src/scriptlets/prevent-requestAnimationFrame.js +++ b/src/scriptlets/prevent-requestAnimationFrame.js @@ -14,6 +14,7 @@ import { /* eslint-disable max-len */ /** * @scriptlet prevent-requestAnimationFrame + * * @description * Prevents a `requestAnimationFrame` call * if the text of the callback is matching the specified search string which does not start with `!`; @@ -77,6 +78,8 @@ import { * } * }); * ``` + * + * @added v1.1.15. */ /* eslint-enable max-len */ diff --git a/src/scriptlets/prevent-setInterval.js b/src/scriptlets/prevent-setInterval.js index 81a97a4d..9fea16ea 100644 --- a/src/scriptlets/prevent-setInterval.js +++ b/src/scriptlets/prevent-setInterval.js @@ -21,6 +21,7 @@ import { /* eslint-disable max-len */ /** * @scriptlet prevent-setInterval + * * @description * Prevents a `setInterval` call if: * 1) the text of the callback is matching the specified `matchCallback` string/regexp which does not start with `!`; @@ -134,6 +135,8 @@ import { * window.test = "value"; * }, 300 + Math.random()); * ``` + * + * @added v1.0.4. */ /* eslint-enable max-len */ export function preventSetInterval(source, matchCallback, matchDelay) { diff --git a/src/scriptlets/prevent-setTimeout.js b/src/scriptlets/prevent-setTimeout.js index d5e7b105..aa42fc02 100644 --- a/src/scriptlets/prevent-setTimeout.js +++ b/src/scriptlets/prevent-setTimeout.js @@ -21,6 +21,7 @@ import { /* eslint-disable max-len */ /** * @scriptlet prevent-setTimeout + * * @description * Prevents a `setTimeout` call if: * 1) the text of the callback is matching the specified `matchCallback` string/regexp which does not start with `!`; @@ -134,6 +135,8 @@ import { * window.test = "value"; * }, 300 + Math.random()); * ``` + * + * @added v1.0.4. */ /* eslint-enable max-len */ export function preventSetTimeout(source, matchCallback, matchDelay) { diff --git a/src/scriptlets/prevent-window-open.js b/src/scriptlets/prevent-window-open.js index b0c8b34c..9e2c0d95 100644 --- a/src/scriptlets/prevent-window-open.js +++ b/src/scriptlets/prevent-window-open.js @@ -23,6 +23,7 @@ import { /* eslint-disable max-len */ /** * @scriptlet prevent-window-open + * * @description * Prevents `window.open` calls when URL either matches or not matches the specified string/regexp. Using it without parameters prevents all `window.open` calls. * @@ -79,6 +80,8 @@ import { * ``` * * > For better compatibility with uBO, old syntax is not recommended to use. + * + * @added v1.0.4. */ /* eslint-enable max-len */ export function preventWindowOpen(source, match = '*', delay, replacement) { diff --git a/src/scriptlets/prevent-xhr.js b/src/scriptlets/prevent-xhr.js index 43c99245..2f253c4a 100644 --- a/src/scriptlets/prevent-xhr.js +++ b/src/scriptlets/prevent-xhr.js @@ -25,6 +25,7 @@ import { /* eslint-disable max-len */ /** * @scriptlet prevent-xhr + * * @description * Prevents `xhr` calls if **all** given parameters match. * @@ -86,6 +87,8 @@ import { * ``` * example.org#%#//scriptlet('prevent-xhr', 'example.org', 'length:100-300') * ``` + * + * @added v1.5.0. */ /* eslint-enable max-len */ export function preventXHR(source, propsToMatch, customResponseText) { diff --git a/src/scriptlets/remove-attr.js b/src/scriptlets/remove-attr.js index 5049b464..24351e6f 100644 --- a/src/scriptlets/remove-attr.js +++ b/src/scriptlets/remove-attr.js @@ -11,6 +11,7 @@ import { /* eslint-disable max-len */ /** * @scriptlet remove-attr + * * @description * Removes the specified attributes from DOM nodes. This scriptlet runs once when the page loads * and after that periodically in order to DOM tree changes by default, @@ -66,6 +67,8 @@ import { * ``` * example.org#%#//scriptlet('remove-attr', 'example', 'html', 'asap complete') * ``` + * + * @added v1.0.4. */ /* eslint-enable max-len */ export function removeAttr(source, attrs, selector, applying = 'asap stay') { diff --git a/src/scriptlets/remove-class.js b/src/scriptlets/remove-class.js index e2f3f4b6..dcb4be2a 100644 --- a/src/scriptlets/remove-class.js +++ b/src/scriptlets/remove-class.js @@ -11,6 +11,7 @@ import { /* eslint-disable max-len */ /** * @scriptlet remove-class + * * @description * Removes the specified classes from DOM nodes. This scriptlet runs once after the page loads * and after that periodically in order to DOM tree changes. @@ -70,6 +71,8 @@ import { * ``` * example.org#%#//scriptlet('remove-class', 'branding', 'div[class^="inner"]', 'asap complete') * ``` + * + * @added v1.1.1. */ /* eslint-enable max-len */ diff --git a/src/scriptlets/remove-cookie.js b/src/scriptlets/remove-cookie.js index 1edac968..9b1edb7d 100644 --- a/src/scriptlets/remove-cookie.js +++ b/src/scriptlets/remove-cookie.js @@ -3,6 +3,7 @@ import { hit, toRegExp } from '../helpers/index'; /* eslint-disable max-len */ /** * @scriptlet remove-cookie + * * @description * Removes current page cookies by passed string matching with name. For current domain and subdomains. Runs on load and before unload. * @@ -32,6 +33,8 @@ import { hit, toRegExp } from '../helpers/index'; * ```javascript * document.cookie = '__example=randomValue'; * ``` + * + * @added v1.0.4. */ /* eslint-enable max-len */ export function removeCookie(source, match) { diff --git a/src/scriptlets/remove-in-shadow-dom.js b/src/scriptlets/remove-in-shadow-dom.js index fca9b0ea..372d0cf4 100644 --- a/src/scriptlets/remove-in-shadow-dom.js +++ b/src/scriptlets/remove-in-shadow-dom.js @@ -11,6 +11,7 @@ import { /** * @scriptlet remove-in-shadow-dom + * * @description * Removes elements inside open shadow DOM elements. * @@ -34,6 +35,8 @@ import { * ! removes floating element * virustotal.com#%#//scriptlet('remove-in-shadow-dom', 'vt-ui-contact-fab') * ``` + * + * @added v1.3.14. */ export function removeInShadowDom(source, selector, baseSelector) { // do nothing if browser does not support ShadowRoot diff --git a/src/scriptlets/set-attr.js b/src/scriptlets/set-attr.js index 769bfa9a..69996303 100644 --- a/src/scriptlets/set-attr.js +++ b/src/scriptlets/set-attr.js @@ -10,6 +10,7 @@ import { /* eslint-disable max-len */ /** * @scriptlet set-attr + * * @description * Sets the specified attribute on the specified elements. This scriptlet runs once when the page loads * and after that and after that on DOM tree changes. @@ -75,6 +76,8 @@ import { * * Some text * ``` + * + * @added v1.5.0. */ /* eslint-enable max-len */ export function setAttr(source, selector, attr, value = '') { diff --git a/src/scriptlets/set-constant.js b/src/scriptlets/set-constant.js index 0049314c..837a46c2 100644 --- a/src/scriptlets/set-constant.js +++ b/src/scriptlets/set-constant.js @@ -25,6 +25,7 @@ import { /* eslint-disable max-len */ /** * @scriptlet set-constant + * * @description * Creates a constant property and assigns it one of the values from the predefined list. * @@ -89,6 +90,8 @@ import { * * ✔ document.third() === true // if the condition described above is met * ``` + * + * @added v1.0.4. */ /* eslint-enable max-len */ export function setConstant(source, property, value, stack) { diff --git a/src/scriptlets/set-cookie-reload.js b/src/scriptlets/set-cookie-reload.js index 8cc876a6..b5dc6436 100644 --- a/src/scriptlets/set-cookie-reload.js +++ b/src/scriptlets/set-cookie-reload.js @@ -13,6 +13,7 @@ import { /** * @scriptlet set-cookie-reload + * * @description * Sets a cookie with the specified name and value, and path, * and reloads the current page after the cookie setting. @@ -47,6 +48,8 @@ import { * * example.org#%#//scriptlet('set-cookie-reload', 'cookie-set', 'true', 'none') * ``` + * + * @added v1.3.14. */ export function setCookieReload(source, name, value, path = '/') { if (isCookieSetWithValue(document.cookie, name, value)) { diff --git a/src/scriptlets/set-cookie.js b/src/scriptlets/set-cookie.js index 6f75fc5d..573ff68b 100644 --- a/src/scriptlets/set-cookie.js +++ b/src/scriptlets/set-cookie.js @@ -14,6 +14,7 @@ import { /* eslint-disable max-len */ /** * @scriptlet set-cookie + * * @description * Sets a cookie with the specified name, value, and path. * @@ -46,6 +47,8 @@ import { * * example.org#%#//scriptlet('set-cookie', 'cookie_consent', 'ok', 'none') * ``` + * + * @added v1.2.3. */ /* eslint-enable max-len */ export function setCookie(source, name, value, path = '/') { diff --git a/src/scriptlets/set-local-storage-item.js b/src/scriptlets/set-local-storage-item.js index 31989bb7..d97fb460 100644 --- a/src/scriptlets/set-local-storage-item.js +++ b/src/scriptlets/set-local-storage-item.js @@ -9,6 +9,7 @@ import { /* eslint-disable max-len */ /** * @scriptlet set-local-storage-item + * * @description * Adds specified key and its value to localStorage object, or updates the value of the key if it already exists. * Scriptlet won't set item if storage is full. @@ -38,6 +39,8 @@ import { * * example.org#%#//scriptlet('set-local-storage-item', 'exit-intent-marketing', '1') * ``` + * + * @added v1.4.3. */ /* eslint-enable max-len */ diff --git a/src/scriptlets/set-popads-dummy.js b/src/scriptlets/set-popads-dummy.js index ec8d49bd..d6487b08 100644 --- a/src/scriptlets/set-popads-dummy.js +++ b/src/scriptlets/set-popads-dummy.js @@ -3,6 +3,7 @@ import { hit } from '../helpers/index'; /** * @scriptlet set-popads-dummy + * * @description * Sets static properties PopAds and popns. * @@ -13,6 +14,8 @@ import { hit } from '../helpers/index'; * ``` * example.org#%#//scriptlet('set-popads-dummy') * ``` + * + * @added v1.0.4. */ export function setPopadsDummy(source) { delete window.PopAds; diff --git a/src/scriptlets/set-session-storage-item.js b/src/scriptlets/set-session-storage-item.js index 2c25c907..33adee8d 100644 --- a/src/scriptlets/set-session-storage-item.js +++ b/src/scriptlets/set-session-storage-item.js @@ -9,6 +9,7 @@ import { /* eslint-disable max-len */ /** * @scriptlet set-session-storage-item + * * @description * Adds specified key and its value to sessionStorage object, or updates the value of the key if it already exists. * Scriptlet won't set item if storage is full. @@ -38,6 +39,8 @@ import { * * example.org#%#//scriptlet('set-session-storage-item', 'exit-intent-marketing', '1') * ``` + * + * @added v1.4.3. */ /* eslint-enable max-len */ diff --git a/src/scriptlets/trusted-click-element.js b/src/scriptlets/trusted-click-element.js index 16e5bd62..1e8c98fd 100644 --- a/src/scriptlets/trusted-click-element.js +++ b/src/scriptlets/trusted-click-element.js @@ -10,6 +10,7 @@ import { /* eslint-disable max-len */ /** * @trustedScriptlet trusted-click-element + * * @description * Clicks selected elements in a strict sequence, ordered by selectors passed, and waiting for them to render in the DOM first. * Deactivates after all elements have been clicked or by 10s timeout. @@ -72,6 +73,8 @@ import { * ``` * example.com#%#//scriptlet('trusted-click-element', 'button[name="agree"]', '!cookie:cmpconsent, !localStorage:promo') * ``` + * + * @added v1.7.3. */ /* eslint-enable max-len */ export function trustedClickElement(source, selectors, extraMatch = '', delay = NaN) { diff --git a/src/scriptlets/trusted-replace-fetch-response.js b/src/scriptlets/trusted-replace-fetch-response.js index a6aad8c4..f3a80978 100644 --- a/src/scriptlets/trusted-replace-fetch-response.js +++ b/src/scriptlets/trusted-replace-fetch-response.js @@ -22,6 +22,7 @@ import { /* eslint-disable max-len */ /** * @trustedScriptlet trusted-replace-fetch-response + * * @description * Replaces response text content of `fetch` requests if **all** given parameters match. * @@ -73,6 +74,8 @@ import { * ``` * example.org#%#//scriptlet('trusted-replace-fetch-response', '*', '', 'example.com') * ``` + * + * @added v1.7.3. */ /* eslint-enable max-len */ export function trustedReplaceFetchResponse(source, pattern = '', replacement = '', propsToMatch = '') { diff --git a/src/scriptlets/trusted-replace-xhr-response.js b/src/scriptlets/trusted-replace-xhr-response.js index 674549f1..980ed90b 100644 --- a/src/scriptlets/trusted-replace-xhr-response.js +++ b/src/scriptlets/trusted-replace-xhr-response.js @@ -20,6 +20,7 @@ import { /* eslint-disable max-len */ /** * @trustedScriptlet trusted-replace-xhr-response + * * @description * Replaces response content of `xhr` requests if **all** given parameters match. * @@ -68,6 +69,8 @@ import { * ``` * example.org#%#//scriptlet('trusted-replace-xhr-response', '*', '', 'example.com') * ``` + * + * @added v1.7.3. */ /* eslint-enable max-len */ export function trustedReplaceXhrResponse(source, pattern = '', replacement = '', propsToMatch = '') { diff --git a/src/scriptlets/trusted-set-constant.js b/src/scriptlets/trusted-set-constant.js index f1daf729..6e7186b4 100644 --- a/src/scriptlets/trusted-set-constant.js +++ b/src/scriptlets/trusted-set-constant.js @@ -26,6 +26,7 @@ import { /* eslint-disable max-len */ /** * @trustedScriptlet trusted-set-constant + * * @description * Creates a constant property and assigns it a specified value. * @@ -79,6 +80,8 @@ import { * * ✔ document.first === 1 // if the condition described above is met * ``` + * + * @added v1.8.2. */ /* eslint-enable max-len */ export function trustedSetConstant(source, property, value, stack) { diff --git a/src/scriptlets/trusted-set-cookie-reload.js b/src/scriptlets/trusted-set-cookie-reload.js index a1caf950..9578b72e 100644 --- a/src/scriptlets/trusted-set-cookie-reload.js +++ b/src/scriptlets/trusted-set-cookie-reload.js @@ -16,6 +16,7 @@ import { /* eslint-disable max-len */ /** * @trustedScriptlet trusted-set-cookie-reload + * * @description * Sets a cookie with arbitrary name and value, * and with optional ability to offset cookie attribute 'expires' and set path. @@ -70,6 +71,8 @@ import { * ``` * example.org#%#//scriptlet('trusted-set-cookie-reload', 'cmpconsent', 'decline', '', 'none') * ``` + * + * @added v1.7.10. */ /* eslint-enable max-len */ diff --git a/src/scriptlets/trusted-set-cookie.js b/src/scriptlets/trusted-set-cookie.js index 397a3cc7..9f1c6784 100644 --- a/src/scriptlets/trusted-set-cookie.js +++ b/src/scriptlets/trusted-set-cookie.js @@ -15,6 +15,7 @@ import { /* eslint-disable max-len */ /** * @trustedScriptlet trusted-set-cookie + * * @description * Sets a cookie with arbitrary name and value, * and with optional ability to offset cookie attribute 'expires' and set path. @@ -68,6 +69,8 @@ import { * ``` * example.org#%#//scriptlet('trusted-set-cookie', 'cmpconsent', 'decline', '', 'none') * ``` + * + * @added v1.7.3. */ /* eslint-enable max-len */ diff --git a/src/scriptlets/trusted-set-local-storage-item.js b/src/scriptlets/trusted-set-local-storage-item.js index 7ef16c2d..5bfef6ca 100644 --- a/src/scriptlets/trusted-set-local-storage-item.js +++ b/src/scriptlets/trusted-set-local-storage-item.js @@ -9,6 +9,7 @@ import { /* eslint-disable max-len */ /** * @trustedScriptlet trusted-set-local-storage-item + * * @description * Adds item with arbitrary key and value to localStorage object, or updates the value of the key if it already exists. * Scriptlet won't set item if storage is full. @@ -50,6 +51,8 @@ import { * ``` * example.org#%#//scriptlet('trusted-set-local-storage-item', 'ppu_main_none', '') * ``` + * + * @added v1.7.3. */ /* eslint-enable max-len */ diff --git a/src/scriptlets/xml-prune.js b/src/scriptlets/xml-prune.js index 6efd8450..2b2b1c55 100644 --- a/src/scriptlets/xml-prune.js +++ b/src/scriptlets/xml-prune.js @@ -7,6 +7,7 @@ import { /* eslint-disable max-len */ /** * @scriptlet xml-prune + * * @description * Removes an element from the specified XML. * @@ -46,6 +47,8 @@ import { * ``` * example.org#%#//scriptlet('xml-prune', '', '', '.mpd') * ``` + * + * @added 1.7.3. */ /* eslint-enable max-len */ From 71d7683b0d628702a115cc631f8f4103a1a9d204 Mon Sep 17 00:00:00 2001 From: Atlassian Bamboo Date: Tue, 16 May 2023 14:17:06 +0300 Subject: [PATCH 06/12] skipci: Automatic increment build number --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 92115d4f..9f5d6412 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@adguard/scriptlets", - "version": "1.9.13", + "version": "1.9.14", "description": "AdGuard's JavaScript library of Scriptlets and Redirect resources", "scripts": { "build": "babel-node bundler.js", From 2cbabc7b994e2415475e0434209a528e427f147f Mon Sep 17 00:00:00 2001 From: Stanislav Atroschenko Date: Tue, 16 May 2023 15:50:00 +0300 Subject: [PATCH 07/12] Pull request #502: AG-19184 unescape quotes for callback matching argument Merge in ADGUARD-FILTERS/scriptlets from fix/AG-19184 to master Squashed commit of the following: commit bc0fcf16c82276dbd4841aca712a1b81385851ab Merge: 84298820 71d7683b Author: Stanislav A Date: Tue May 16 15:44:16 2023 +0300 Merge branch 'master' into fix/AG-19184 commit 842988208278d6121a1c0d96c4f68e0ff0678ca3 Author: Stanislav A Date: Mon May 15 20:19:14 2023 +0300 improve tests, get rid of trimmedInput variable commit c4b1dcf274d95ffda89550e5ff4e899a89e08415 Author: Stanislav A Date: Fri May 12 20:28:12 2023 +0300 unescape quotes for callback matching argument --- src/helpers/string-utils.js | 9 +- tests/helpers/string-utils.test.js | 25 ++++++ tests/scriptlets/prevent-setTimeout.test.js | 99 +++++++++++++++++++++ 3 files changed, 132 insertions(+), 1 deletion(-) diff --git a/src/helpers/string-utils.js b/src/helpers/string-utils.js index 0d44e3b8..48cddb13 100644 --- a/src/helpers/string-utils.js +++ b/src/helpers/string-utils.js @@ -48,7 +48,14 @@ export const toRegExp = (input = '') => { if (input[0] === FORWARD_SLASH && input[input.length - 1] === FORWARD_SLASH) { return new RegExp(input.slice(1, -1)); } - const escaped = input.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + + const escaped = input + // remove quotes' escapes for cases where scriptlet rule argument has own escaped quotes + // e.g #%#//scriptlet('prevent-setTimeout', '.css(\'display\',\'block\');') + .replace(/\\'/g, '\'') + .replace(/\\"/g, '"') + // escape special characters for following RegExp construction + .replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); return new RegExp(escaped); }; diff --git a/tests/helpers/string-utils.test.js b/tests/helpers/string-utils.test.js index a91bd17c..1e0aecfa 100644 --- a/tests/helpers/string-utils.test.js +++ b/tests/helpers/string-utils.test.js @@ -47,6 +47,31 @@ test('Test toRegExp for invalid inputs', (assert) => { }); }); +test('Test toRegExp for escaped inputs', (assert) => { + /** + * For cases where scriptlet rule argument has escaped quotes + * e.g #%#//scriptlet('prevent-setTimeout', '.css(\'display\',\'block\');') + * + * https://github.com/AdguardTeam/Scriptlets/issues/286 + */ + + // Single quotes, escaped + let inputStr = String.raw`.css(\'display\',\'block\');`; + let expRegex = /\.css\('display','block'\);/; + assert.deepEqual(toRegExp(inputStr), expRegex); + // Single quotes, unescaped + inputStr = ".css('display','block');"; + assert.deepEqual(toRegExp(inputStr), expRegex); + + // Double quotes, escaped + inputStr = String.raw`.css(\"display\",\"block\");`; + expRegex = /\.css\("display","block"\);/; + assert.deepEqual(toRegExp(inputStr), expRegex); + // Double quotes, unescaped + inputStr = '.css("display","block");'; + assert.deepEqual(toRegExp(inputStr), expRegex); +}); + test('inferValue works as expected with valid args', (assert) => { // convert to number let rawString = '1234'; diff --git a/tests/scriptlets/prevent-setTimeout.test.js b/tests/scriptlets/prevent-setTimeout.test.js index 5c515351..907d6ba5 100644 --- a/tests/scriptlets/prevent-setTimeout.test.js +++ b/tests/scriptlets/prevent-setTimeout.test.js @@ -482,3 +482,102 @@ test('match any callback, falsy non-numbers delays dont collide with 0 ', (asser const timeoutTest3 = setTimeout(third, undefined); testTimeouts.push(timeoutTest3); }); + +/** + * Following group tests for callback matching with escaped single and double quotes + * inside match callback argument + * https://github.com/AdguardTeam/Scriptlets/issues/286 + */ +test('match with escaped single quotes', (assert) => { + const markerProp = 'callbackFired'; + window[markerProp] = false; + const done = assert.async(); + + // We need to run our assertion after all timeouts + nativeSetTimeout(() => { + assert.notOk(window.callbackFired, 'callback was blocked'); + assert.strictEqual(window.hit, 'FIRED', 'hit fired'); + done(); + }, 100); + + const CALLBACK_MATCH = String.raw`.css(\'display\',\'block\');`; + + // run scriptlet code + const scriptletArgs = [CALLBACK_MATCH, '30']; + runScriptlet(name, scriptletArgs); + + // eslint-disable-next-line quotes + const callback = () => { window[markerProp] = ".css('display','block');"; }; + const timeoutTest1 = setTimeout(callback, 30); + testTimeouts.push(timeoutTest1); +}); + +test('match with unescaped single quotes', (assert) => { + const markerProp = 'callbackFired'; + window[markerProp] = false; + const done = assert.async(); + + // We need to run our assertion after all timeouts + nativeSetTimeout(() => { + assert.notOk(window.callbackFired, 'callback was blocked'); + assert.strictEqual(window.hit, 'FIRED', 'hit fired'); + done(); + }, 100); + + const CALLBACK_MATCH = String.raw`.css('display','block');`; + + // run scriptlet code + const scriptletArgs = [CALLBACK_MATCH, '30']; + runScriptlet(name, scriptletArgs); + + // eslint-disable-next-line quotes + const callback = () => { window[markerProp] = ".css('display','block');"; }; + const timeoutTest1 = setTimeout(callback, 30); + testTimeouts.push(timeoutTest1); +}); + +test('match with escaped double quotes', (assert) => { + const markerProp = 'callbackFired'; + window[markerProp] = false; + const done = assert.async(); + + // We need to run our assertion after all timeouts + nativeSetTimeout(() => { + assert.notOk(window.callbackFired, 'callback was blocked'); + assert.strictEqual(window.hit, 'FIRED', 'hit fired'); + done(); + }, 100); + + const CALLBACK_MATCH = String.raw`.css(\"display\",\"block\");`; + + // run scriptlet code + const scriptletArgs = [CALLBACK_MATCH, '30']; + runScriptlet(name, scriptletArgs); + + const callback = () => { window[markerProp] = '.css("display","block");'; }; + const timeoutTest1 = setTimeout(callback, 30); + testTimeouts.push(timeoutTest1); +}); + +test('match with escaped double quotes', (assert) => { + const markerProp = 'callbackFired'; + window[markerProp] = false; + const done = assert.async(); + + // We need to run our assertion after all timeouts + nativeSetTimeout(() => { + assert.notOk(window.callbackFired, 'callback was blocked'); + assert.strictEqual(window.hit, 'FIRED', 'hit fired'); + done(); + }, 100); + + const CALLBACK_MATCH = '.css("display","block");'; + + // run scriptlet code + const scriptletArgs = [CALLBACK_MATCH, '30']; + runScriptlet(name, scriptletArgs); + + const callback = () => { window[markerProp] = '.css("display","block");'; }; + const timeoutTest1 = setTimeout(callback, 30); + testTimeouts.push(timeoutTest1); +}); From adb5171a8ffd9c669fa888d81f4a91279dfee678 Mon Sep 17 00:00:00 2001 From: Atlassian Bamboo Date: Tue, 16 May 2023 15:50:06 +0300 Subject: [PATCH 08/12] skipci: Automatic increment build number --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9f5d6412..e9ae1e49 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@adguard/scriptlets", - "version": "1.9.14", + "version": "1.9.15", "description": "AdGuard's JavaScript library of Scriptlets and Redirect resources", "scripts": { "build": "babel-node bundler.js", From 1748d6e2e058ae8ff9a396650685987255b946c2 Mon Sep 17 00:00:00 2001 From: Stanislav Atroschenko Date: Tue, 16 May 2023 16:03:45 +0300 Subject: [PATCH 09/12] Pull request #503: AG-18883 refactor scriptlets 1.9 Merge in ADGUARD-FILTERS/scriptlets from fix/AG-18883 to master Squashed commit of the following: commit abdebb5aa8d74e7a298d23d9290b8eef5e36dca9 Merge: ac281a00 adb5171a Author: Stanislav A Date: Tue May 16 15:50:27 2023 +0300 Merge branch 'master' into fix/AG-18883 commit ac281a00d4a4a1c72fe80a71762c49baac0f18bc Author: Stanislav A Date: Mon May 15 20:58:40 2023 +0300 remove uneccessary .'includes' commit 6a55b6b4280054d5698665e95d0e9620881181c6 Author: Stanislav A Date: Mon May 15 20:51:37 2023 +0300 cover startsWith with optional chaining in string-utils commit 7476e32f25c4c3c16f66bf5535c29df2767fa6ee Author: Stanislav A Date: Mon May 15 18:18:01 2023 +0300 deprecate endsWith commit c3473e8fefe74ec13632db4353ed990c73451534 Author: Stanislav A Date: Mon May 15 17:58:06 2023 +0300 deprecate startsWith commit d569d7477345abdafc8ed5184d49ee7579d4511d Author: Stanislav A Date: Mon May 15 15:21:06 2023 +0300 deprecate getObjectEntries and getObjectFromEntries commit 31375bcd35a7d138a8a11f287a136d433de9fa13 Author: Stanislav A Date: Mon May 15 14:45:33 2023 +0300 swap indexOf to includes where possible --- scripts/check-sources-updates.js | 5 +-- src/helpers/converter.js | 23 +++++----- src/helpers/create-on-error-handler.js | 2 +- src/helpers/hit.js | 4 +- src/helpers/object-utils.js | 34 --------------- src/helpers/parse-flags.js | 4 +- src/helpers/prevent-window-open-utils.js | 6 +-- src/helpers/request-utils.js | 5 +-- src/helpers/script-source-utils.js | 14 +++---- src/helpers/string-utils.js | 42 +++---------------- src/helpers/validator.js | 37 +++++++--------- .../blocking-redirects/click2load.js | 6 +-- .../googlesyndication-adsbygoogle.js | 4 +- src/redirects/index.js | 2 +- src/redirects/redirects.js | 2 +- src/scriptlets/abort-current-inline-script.js | 4 +- src/scriptlets/abort-on-stack-trace.js | 2 - src/scriptlets/close-window.js | 2 +- src/scriptlets/json-prune.js | 8 +--- src/scriptlets/log-addEventListener.js | 2 - src/scriptlets/prevent-bab.js | 2 +- src/scriptlets/prevent-fetch.js | 4 -- .../prevent-requestAnimationFrame.js | 2 - src/scriptlets/prevent-setInterval.js | 2 - src/scriptlets/prevent-setTimeout.js | 2 - src/scriptlets/prevent-window-open.js | 6 +-- src/scriptlets/prevent-xhr.js | 2 - src/scriptlets/remove-attr.js | 2 +- src/scriptlets/remove-class.js | 2 +- src/scriptlets/trusted-click-element.js | 6 +-- .../trusted-replace-fetch-response.js | 4 -- .../trusted-replace-xhr-response.js | 2 - src/scriptlets/xml-prune.js | 4 +- tests/helpers/log-message.test.js | 4 +- tests/redirects/noeval.test.js | 2 +- tests/scriptlets/adjust-setInterval.test.js | 2 +- tests/scriptlets/adjust-setTimeout.test.js | 2 +- .../inject-css-in-shadow-dom.test.js | 6 +-- tests/scriptlets/log-addEventListener.test.js | 20 ++++----- tests/scriptlets/log-eval.test.js | 4 +- tests/scriptlets/log-on-stack-trace.test.js | 4 +- tests/scriptlets/noeval.test.js | 2 +- tests/scriptlets/nowebrtc.test.js | 7 ++-- .../prevent-element-src-loading.test.js | 4 +- tests/scriptlets/prevent-fetch.test.js | 2 +- tests/scriptlets/prevent-refresh.test.js | 6 +-- .../prevent-requestAnimationFrame.test.js | 2 +- tests/scriptlets/prevent-setInterval.test.js | 2 +- tests/scriptlets/prevent-setTimeout.test.js | 2 +- tests/scriptlets/prevent-window-open.test.js | 4 +- tests/scriptlets/prevent-xhr.test.js | 6 +-- tests/scriptlets/remove-attr.test.js | 2 +- tests/scriptlets/remove-class.test.js | 2 +- .../trusted-replace-fetch-response.test.js | 5 +-- .../trusted-replace-xhr-response.test.js | 5 +-- tests/scriptlets/trusted-set-cookie.test.js | 2 +- tests/scriptlets/xml-prune.test.js | 38 ++++++++--------- 57 files changed, 133 insertions(+), 250 deletions(-) diff --git a/scripts/check-sources-updates.js b/scripts/check-sources-updates.js index 302d8576..adf252dc 100644 --- a/scripts/check-sources-updates.js +++ b/scripts/check-sources-updates.js @@ -84,10 +84,7 @@ const getDiff = (oldList, newList) => { removed: [], }; - diff.removed = oldList.filter((item) => ( - !newList.includes(item) - && item.indexOf(REMOVED_MARKER) === -1 - )); + diff.removed = oldList.filter((item) => !newList.includes(item) && !item.includes(REMOVED_MARKER)); diff.added = newList.filter((item) => !oldList.includes(item)); return (diff.removed.length || diff.added.length) ? diff : null; diff --git a/src/helpers/converter.js b/src/helpers/converter.js index 2952fa4f..f3165561 100644 --- a/src/helpers/converter.js +++ b/src/helpers/converter.js @@ -128,7 +128,7 @@ const validateRemoveAttrClassArgs = (parsedArgs) => { const lastArg = restArgs.pop(); let applying; // check the last parsed arg for matching possible 'applying' vale - if (REMOVE_ATTR_CLASS_APPLYING.some((el) => lastArg.indexOf(el) > -1)) { + if (REMOVE_ATTR_CLASS_APPLYING.some((el) => lastArg.includes(el))) { applying = lastArg; } else { restArgs.push(lastArg); @@ -160,19 +160,18 @@ export const convertUboScriptletToAdg = (rule) => { const domains = getBeforeRegExp(rule, validator.UBO_SCRIPTLET_MASK_REG); const mask = rule.match(validator.UBO_SCRIPTLET_MASK_REG)[0]; let template; - if (mask.indexOf('@') > -1) { + if (mask.includes('@')) { template = ADGUARD_SCRIPTLET_EXCEPTION_TEMPLATE; } else { template = ADGUARD_SCRIPTLET_TEMPLATE; } const argsStr = getStringInBraces(rule); let parsedArgs = splitArgs(argsStr); - const scriptletName = parsedArgs[0].indexOf(UBO_SCRIPTLET_JS_ENDING) > -1 + const scriptletName = parsedArgs[0].includes(UBO_SCRIPTLET_JS_ENDING) ? `ubo-${parsedArgs[0]}` : `ubo-${parsedArgs[0]}${UBO_SCRIPTLET_JS_ENDING}`; - if (((REMOVE_ATTR_ALIASES.indexOf(scriptletName) > -1) - || (REMOVE_CLASS_ALIASES.indexOf(scriptletName) > -1))) { + if (REMOVE_ATTR_ALIASES.includes(scriptletName) || REMOVE_CLASS_ALIASES.includes(scriptletName)) { parsedArgs = validateRemoveAttrClassArgs(parsedArgs); } @@ -205,7 +204,7 @@ export const convertUboScriptletToAdg = (rule) => { */ export const convertAbpSnippetToAdg = (rule) => { const SEMICOLON_DIVIDER = /;(?=(?:(?:[^"]*"){2})*[^"]*$)/g; - const mask = rule.indexOf(validator.ABP_SCRIPTLET_MASK) > -1 + const mask = rule.includes(validator.ABP_SCRIPTLET_MASK) ? validator.ABP_SCRIPTLET_MASK : validator.ABP_SCRIPTLET_EXCEPTION_MASK; const template = mask === validator.ABP_SCRIPTLET_MASK @@ -315,7 +314,7 @@ export const convertAdgScriptletToUbo = (rule) => { || parsedParams[0] === ADG_PREVENT_FETCH_EMPTY_STRING)) { preparedParams = [UBO_NO_FETCH_IF_WILDCARD]; } else if ((parsedName === ADG_REMOVE_ATTR_NAME || parsedName === ADG_REMOVE_CLASS_NAME) - && parsedParams[1] && parsedParams[1].indexOf(COMMA_SEPARATOR) > -1) { + && parsedParams[1] && parsedParams[1].includes(COMMA_SEPARATOR)) { preparedParams = [ parsedParams[0], replaceAll(parsedParams[1], COMMA_SEPARATOR, ESCAPED_COMMA_SEPARATOR), @@ -333,7 +332,7 @@ export const convertAdgScriptletToUbo = (rule) => { return { name, aliases }; }) .find((el) => (el.name === parsedName - || el.aliases.indexOf(parsedName) >= 0)); + || el.aliases.includes(parsedName))); const { aliases } = adgScriptletObject; @@ -345,7 +344,7 @@ export const convertAdgScriptletToUbo = (rule) => { if (uboAlias) { const mask = rule.match(ADGUARD_SCRIPTLET_MASK_REG)[0]; let template; - if (mask.indexOf('@') > -1) { + if (mask.includes('@')) { template = UBO_SCRIPTLET_EXCEPTION_TEMPLATE; } else { template = UBO_SCRIPTLET_TEMPLATE; @@ -445,11 +444,11 @@ export const isValidScriptletRule = (ruleText) => { */ const getMarkerData = (modifiers, redirectsData, rule) => { let marker; - let index = modifiers.findIndex((m) => m.indexOf(redirectsData.redirectRuleMarker) > -1); + let index = modifiers.findIndex((m) => m.includes(redirectsData.redirectRuleMarker)); if (index > -1) { marker = redirectsData.redirectRuleMarker; } else { - index = modifiers.findIndex((m) => m.indexOf(redirectsData.redirectMarker) > -1); + index = modifiers.findIndex((m) => m.includes(redirectsData.redirectMarker)); if (index > -1) { marker = redirectsData.redirectMarker; } else { @@ -501,7 +500,7 @@ export const convertAbpRedirectToAdg = (rule) => { const abpModifiers = validator.parseModifiers(rule); const adgModifiers = abpModifiers .map((modifier) => { - if (modifier.indexOf(validator.REDIRECT_RULE_TYPES.ABP.redirectMarker) > -1) { + if (modifier.includes(validator.REDIRECT_RULE_TYPES.ABP.redirectMarker)) { const abpName = substringAfter( modifier, validator.REDIRECT_RULE_TYPES.ABP.redirectMarker, diff --git a/src/helpers/create-on-error-handler.js b/src/helpers/create-on-error-handler.js index 041f8094..bc493070 100644 --- a/src/helpers/create-on-error-handler.js +++ b/src/helpers/create-on-error-handler.js @@ -9,7 +9,7 @@ export function createOnErrorHandler(rid) { // eslint-disable-next-line consistent-return const nativeOnError = window.onerror; return function onError(error, ...args) { - if (typeof error === 'string' && error.indexOf(rid) !== -1) { + if (typeof error === 'string' && error.includes(rid)) { return true; } if (nativeOnError instanceof Function) { diff --git a/src/helpers/hit.js b/src/helpers/hit.js index 9f862138..69ee3210 100644 --- a/src/helpers/hit.js +++ b/src/helpers/hit.js @@ -22,9 +22,9 @@ export const hit = (source) => { const AG_SCRIPTLET_MARKER = '#%#//'; const UBO_SCRIPTLET_MARKER = '##+js'; let ruleStartIndex; - if (source.ruleText.indexOf(AG_SCRIPTLET_MARKER) > -1) { + if (source.ruleText.includes(AG_SCRIPTLET_MARKER)) { ruleStartIndex = source.ruleText.indexOf(AG_SCRIPTLET_MARKER); - } else if (source.ruleText.indexOf(UBO_SCRIPTLET_MARKER) > -1) { + } else if (source.ruleText.includes(UBO_SCRIPTLET_MARKER)) { ruleStartIndex = source.ruleText.indexOf(UBO_SCRIPTLET_MARKER); } // delete all domains from ruleText and leave just rule part diff --git a/src/helpers/object-utils.js b/src/helpers/object-utils.js index d8aa5973..a232dcbe 100644 --- a/src/helpers/object-utils.js +++ b/src/helpers/object-utils.js @@ -1,37 +1,3 @@ -/** - * Converts object to array of pairs. - * Object.entries() polyfill because it is not supported by IE - * https://caniuse.com/?search=Object.entries - * - * @param {Object} object arbitrary object - * @returns {Array} array of pairs - */ -export const getObjectEntries = (object) => { - const keys = Object.keys(object); - const entries = []; - keys.forEach((key) => entries.push([key, object[key]])); - return entries; -}; - -/** - * Converts array of pairs to object. - * Object.fromEntries() polyfill because it is not supported by IE - * https://caniuse.com/?search=Object.fromEntries - * - * @param {Array} entries - array of pairs - * @returns {Object} result object - */ -export const getObjectFromEntries = (entries) => { - const output = entries - .reduce((acc, el) => { - const key = el[0]; - const value = el[1]; - acc[key] = value; - return acc; - }, {}); - return output; -}; - /** * Checks whether the obj is an empty object * diff --git a/src/helpers/parse-flags.js b/src/helpers/parse-flags.js index 5c679f1a..fe781357 100644 --- a/src/helpers/parse-flags.js +++ b/src/helpers/parse-flags.js @@ -22,14 +22,14 @@ export const parseFlags = (flags) => { const passedFlags = flags.trim() .split(FLAGS_DIVIDER) - .filter((f) => VALID_FLAGS.indexOf(f) !== -1); + .filter((f) => VALID_FLAGS.includes(f)); return { ASAP: ASAP_FLAG, COMPLETE: COMPLETE_FLAG, STAY: STAY_FLAG, hasFlag(flag) { - return passedFlags.indexOf(flag) !== -1; + return passedFlags.includes(flag); }, }; }; diff --git a/src/helpers/prevent-window-open-utils.js b/src/helpers/prevent-window-open-utils.js index 73694f86..7f05ae5b 100644 --- a/src/helpers/prevent-window-open-utils.js +++ b/src/helpers/prevent-window-open-utils.js @@ -3,8 +3,6 @@ import { trueFunc, } from './noop-utils'; import { - startsWith, - endsWith, substringBefore, substringAfter, } from './string-utils'; @@ -16,11 +14,11 @@ export const handleOldReplacement = (replacement) => { result = noopFunc; } else if (replacement === 'trueFunc') { result = trueFunc; - } else if (replacement.indexOf('=') > -1) { + } else if (replacement.includes('=')) { // We should return noopFunc instead of window.open // but with some property if website checks it (examples 5, 6) // https://github.com/AdguardTeam/Scriptlets/issues/71 - const isProp = startsWith(replacement, '{') && endsWith(replacement, '}'); + const isProp = replacement.startsWith('{') && replacement.endsWith('}'); if (isProp) { const propertyPart = replacement.slice(1, -1); const propertyName = substringBefore(propertyPart, '='); diff --git a/src/helpers/request-utils.js b/src/helpers/request-utils.js index 240d34d1..dd72288b 100644 --- a/src/helpers/request-utils.js +++ b/src/helpers/request-utils.js @@ -1,5 +1,4 @@ import { toRegExp, isValidStrPattern } from './string-utils'; -import { getObjectFromEntries } from './object-utils'; /** * Returns array of request props that are supported by fetch/xhr scriptlets. @@ -37,7 +36,7 @@ export const getRequestData = (request) => { const value = request[key]; return [key, value]; }); - return getObjectFromEntries(entries); + return Object.fromEntries(entries); }; /** @@ -110,7 +109,7 @@ export const parseMatchProps = (propsToMatchStr) => { const dividerInd = prop.indexOf(PAIRS_MARKER); const key = prop.slice(0, dividerInd); - const hasLegalMatchProp = LEGAL_MATCH_PROPS.indexOf(key) !== -1; + const hasLegalMatchProp = LEGAL_MATCH_PROPS.includes(key); if (hasLegalMatchProp) { const value = prop.slice(dividerInd + 1); diff --git a/src/helpers/script-source-utils.js b/src/helpers/script-source-utils.js index c3ff4078..27021846 100644 --- a/src/helpers/script-source-utils.js +++ b/src/helpers/script-source-utils.js @@ -1,5 +1,3 @@ -import { startsWith } from './string-utils'; - /** * Determines if type of script is inline or injected * and when it's one of them then return true, otherwise false @@ -13,8 +11,8 @@ export const shouldAbortInlineOrInjectedScript = (stackMatch, stackTrace) => { const INLINE_SCRIPT_STRING = 'inlineScript'; const INJECTED_SCRIPT_STRING = 'injectedScript'; const INJECTED_SCRIPT_MARKER = ''; - const isInlineScript = (stackMatch) => stackMatch.indexOf(INLINE_SCRIPT_STRING) > -1; - const isInjectedScript = (stackMatch) => stackMatch.indexOf(INJECTED_SCRIPT_STRING) > -1; + const isInlineScript = (stackMatch) => stackMatch.includes(INLINE_SCRIPT_STRING); + const isInjectedScript = (stackMatch) => stackMatch.includes(INJECTED_SCRIPT_STRING); if (!(isInlineScript(stackMatch) || isInjectedScript(stackMatch))) { return false; @@ -39,15 +37,15 @@ export const shouldAbortInlineOrInjectedScript = (stackMatch, stackTrace) => { const getStackTraceURL = /(.*?@)?(\S+)(:\d+):\d+\)?$/.exec(line); if (getStackTraceURL) { let stackURL = getStackTraceURL[2]; - if (startsWith(stackURL, '(')) { + if (stackURL?.startsWith('(')) { stackURL = stackURL.slice(1); } - if (startsWith(stackURL, INJECTED_SCRIPT_MARKER)) { + if (stackURL?.startsWith(INJECTED_SCRIPT_MARKER)) { stackURL = INJECTED_SCRIPT_STRING; let stackFunction = getStackTraceURL[1] !== undefined ? getStackTraceURL[1].slice(0, -1) : line.slice(0, getStackTraceURL.index).trim(); - if (startsWith(stackFunction, 'at')) { + if (stackFunction?.startsWith('at')) { stackFunction = stackFunction.slice(2).trim(); } stack = `${stackFunction} ${stackURL}`.trim(); @@ -65,7 +63,7 @@ export const shouldAbortInlineOrInjectedScript = (stackMatch, stackTrace) => { return true; } if (isInjectedScript(stackMatch) - && startsWith(stackLines[index], INJECTED_SCRIPT_STRING)) { + && stackLines[index].startsWith(INJECTED_SCRIPT_STRING)) { return true; } } diff --git a/src/helpers/string-utils.js b/src/helpers/string-utils.js index 48cddb13..b537c185 100644 --- a/src/helpers/string-utils.js +++ b/src/helpers/string-utils.js @@ -1,4 +1,4 @@ -import { isEmptyObject, getObjectEntries } from './object-utils'; +import { isEmptyObject } from './object-utils'; import { nativeIsFinite, nativeIsNaN, @@ -94,36 +94,6 @@ export const getBeforeRegExp = (str, rx) => { return str.substring(0, index); }; -/** - * 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 - */ -export const startsWith = (str, prefix) => { - // if str === '', (str && false) will return '' - // that's why it has to be !!str - return !!str && str.indexOf(prefix) === 0; -}; - -/** - * 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 - */ -export const endsWith = (str, ending) => { - // if str === '', (str && false) will return '' - // that's why it has to be !!str - return !!str && str.lastIndexOf(ending) === str.length - ending.length; -}; - export const substringAfter = (str, separator) => { if (!str) { return str; @@ -210,7 +180,7 @@ export const convertRtcConfigToString = (config) => { export const isValidMatchStr = (match) => { const INVERT_MARKER = '!'; let str = match; - if (startsWith(match, INVERT_MARKER)) { + if (match?.startsWith(INVERT_MARKER)) { str = match.slice(1); } return isValidStrPattern(str); @@ -226,7 +196,7 @@ export const isValidMatchStr = (match) => { export const isValidMatchNumber = (match) => { const INVERT_MARKER = '!'; let str = match; - if (startsWith(match, INVERT_MARKER)) { + if (match?.startsWith(INVERT_MARKER)) { str = match.slice(1); } const num = parseFloat(str); @@ -250,7 +220,7 @@ export const isValidMatchNumber = (match) => { export const parseMatchArg = (match) => { const INVERT_MARKER = '!'; // In case if "match" is "undefined" return "false" - const isInvertedMatch = match ? match.startsWith(INVERT_MARKER) : false; + const isInvertedMatch = match ? match?.startsWith(INVERT_MARKER) : false; const matchValue = isInvertedMatch ? match.slice(1) : match; const matchRegexp = toRegExp(matchValue); return { isInvertedMatch, matchRegexp, matchValue }; @@ -271,7 +241,7 @@ export const parseMatchArg = (match) => { */ export const parseDelayArg = (delay) => { const INVERT_MARKER = '!'; - const isInvertedDelayMatch = startsWith(delay, INVERT_MARKER); + const isInvertedDelayMatch = delay?.startsWith(INVERT_MARKER); let delayValue = isInvertedDelayMatch ? delay.slice(1) : delay; delayValue = parseInt(delayValue, 10); const delayMatch = nativeIsNaN(delayValue) ? null : delayValue; @@ -292,7 +262,7 @@ export const objectToString = (obj) => { } return isEmptyObject(obj) ? '{}' - : getObjectEntries(obj) + : Object.entries(obj) .map((pair) => { const key = pair[0]; const value = pair[1]; diff --git a/src/helpers/validator.js b/src/helpers/validator.js index ee306ef6..e6354b35 100644 --- a/src/helpers/validator.js +++ b/src/helpers/validator.js @@ -1,12 +1,8 @@ import { - startsWith, - endsWith, substringAfter, toRegExp, } from './string-utils'; -import { getObjectFromEntries } from './object-utils'; - import { ADG_SCRIPTLET_MASK } from './parse-rule'; import * as scriptletsList from '../scriptlets/scriptlets-list'; @@ -22,7 +18,7 @@ const COMMENT_MARKER = '!'; * @param {string} rule rule text * @returns {boolean} if rule text is comment */ -const isComment = (rule) => startsWith(rule, COMMENT_MARKER); +const isComment = (rule) => rule.startsWith(COMMENT_MARKER); /* ************************************************************************ * @@ -56,12 +52,7 @@ const ADG_CSS_MASK_REG = /#@?\$#.+?\s*\{.*\}\s*$/g; * @param {string} rule - rule text * @returns {boolean} if given rule is adg rule */ -const isAdgScriptletRule = (rule) => { - return ( - !isComment(rule) - && rule.indexOf(ADG_SCRIPTLET_MASK) > -1 - ); -}; +const isAdgScriptletRule = (rule) => !isComment(rule) && rule.includes(ADG_SCRIPTLET_MASK); /** * Checks if the `rule` is uBO scriptlet rule @@ -71,10 +62,10 @@ const isAdgScriptletRule = (rule) => { */ const isUboScriptletRule = (rule) => { return ( - rule.indexOf(UBO_SCRIPTLET_MASK_1) > -1 - || rule.indexOf(UBO_SCRIPTLET_MASK_2) > -1 - || rule.indexOf(UBO_SCRIPTLET_EXCEPTION_MASK_1) > -1 - || rule.indexOf(UBO_SCRIPTLET_EXCEPTION_MASK_2) > -1 + rule.includes(UBO_SCRIPTLET_MASK_1) + || rule.includes(UBO_SCRIPTLET_MASK_2) + || rule.includes(UBO_SCRIPTLET_EXCEPTION_MASK_1) + || rule.includes(UBO_SCRIPTLET_EXCEPTION_MASK_2) ) && UBO_SCRIPTLET_MASK_REG.test(rule) && !isComment(rule); @@ -88,8 +79,8 @@ const isUboScriptletRule = (rule) => { */ const isAbpSnippetRule = (rule) => { return ( - rule.indexOf(ABP_SCRIPTLET_MASK) > -1 - || rule.indexOf(ABP_SCRIPTLET_EXCEPTION_MASK) > -1 + rule.includes(ABP_SCRIPTLET_MASK) + || rule.includes(ABP_SCRIPTLET_EXCEPTION_MASK) ) && rule.search(ADG_CSS_MASK_REG) === -1 && !isComment(rule); @@ -120,9 +111,9 @@ const getScriptletByName = (name, scriptlets) => { .find((s) => { return s.names // full match name checking - && (s.names.indexOf(name) > -1 + && (s.names.includes(name) // or check ubo alias name without '.js' at the end - || (!endsWith(name, '.js') && s.names.indexOf(`${name}.js`) > -1) + || (!name.endsWith('.js') && s.names.includes(`${name}.js`)) ); }); }; @@ -251,7 +242,7 @@ const validAdgRedirects = redirects.filter((el) => el.adg); * Compatibility object where KEYS = UBO redirect names and VALUES = ADG redirect names * It's used for UBO -> ADG converting */ -const uboToAdgCompatibility = getObjectFromEntries( +const uboToAdgCompatibility = Object.fromEntries( validAdgRedirects .filter((el) => el.ubo) .map((el) => { @@ -263,7 +254,7 @@ const uboToAdgCompatibility = getObjectFromEntries( * Compatibility object where KEYS = ABP redirect names and VALUES = ADG redirect names * It's used for ABP -> ADG converting */ -const abpToAdgCompatibility = getObjectFromEntries( +const abpToAdgCompatibility = Object.fromEntries( validAdgRedirects .filter((el) => el.abp) .map((el) => { @@ -275,7 +266,7 @@ const abpToAdgCompatibility = getObjectFromEntries( * Compatibility object where KEYS = UBO redirect names and VALUES = ADG redirect names * It's used for ADG -> UBO converting */ -const adgToUboCompatibility = getObjectFromEntries( +const adgToUboCompatibility = Object.fromEntries( validAdgRedirects .filter((el) => el.ubo) .map((el) => { @@ -287,7 +278,7 @@ const adgToUboCompatibility = getObjectFromEntries( * Needed for AdGuard redirect names validation where KEYS = **valid** AdGuard redirect names * 'adgToUboCompatibility' is still needed for ADG -> UBO converting */ -const validAdgCompatibility = getObjectFromEntries( +const validAdgCompatibility = Object.fromEntries( validAdgRedirects .map((el) => { return [el.adg, 'valid adg redirect']; diff --git a/src/redirects/blocking-redirects/click2load.js b/src/redirects/blocking-redirects/click2load.js index 9ddf2f05..37301ccc 100644 --- a/src/redirects/blocking-redirects/click2load.js +++ b/src/redirects/blocking-redirects/click2load.js @@ -38,7 +38,7 @@ function clickToLoad() { let queryStr = rawQueryStr.substring(1); // eslint-disable-next-line no-cond-assign while (matchedData = pattern.exec(queryStr)) { - if (neededParams.indexOf(matchedData[1]) > -1) { + if (neededParams.includes(matchedData[1])) { // destructuring will not work because of babel // eslint-disable-next-line prefer-destructuring res[matchedData[1]] = matchedData[2]; @@ -229,8 +229,8 @@ function clickToLoad() { const FRAME_MARKER = 'frame'; const SUBDOCUMENT_MARKER = 'subdocument'; const ruleModifiers = substringAfter(rule, '$').split(','); - return ruleModifiers.indexOf(FRAME_MARKER) > -1 - || ruleModifiers.indexOf(SUBDOCUMENT_MARKER) > -1; + return ruleModifiers.includes(FRAME_MARKER) + || ruleModifiers.includes(SUBDOCUMENT_MARKER); }; /** * Checks whether script runs inside a frame diff --git a/src/redirects/googlesyndication-adsbygoogle.js b/src/redirects/googlesyndication-adsbygoogle.js index 241b2667..f04941b6 100644 --- a/src/redirects/googlesyndication-adsbygoogle.js +++ b/src/redirects/googlesyndication-adsbygoogle.js @@ -64,10 +64,10 @@ export function GoogleSyndicationAdsByGoogle(source) { areIframesDefined = childNodesQuantity === 2 // the first of child nodes should be aswift iframe && adElemChildNodes[0].nodeName.toLowerCase() === 'iframe' - && adElemChildNodes[0].id.indexOf(ASWIFT_IFRAME_MARKER) > -1 + && adElemChildNodes[0].id.includes(ASWIFT_IFRAME_MARKER) // the second of child nodes should be google_ads iframe && adElemChildNodes[1].nodeName.toLowerCase() === 'iframe' - && adElemChildNodes[1].id.indexOf(GOOGLE_ADS_IFRAME_MARKER) > -1; + && adElemChildNodes[1].id.includes(GOOGLE_ADS_IFRAME_MARKER); } if (!areIframesDefined) { diff --git a/src/redirects/index.js b/src/redirects/index.js index 6b9b8244..c34adb69 100644 --- a/src/redirects/index.js +++ b/src/redirects/index.js @@ -28,7 +28,7 @@ import { redirectsMap } from '../../tmp/redirects-map'; */ const getRedirectByName = (name) => { const redirects = Object.keys(redirectsList).map((key) => redirectsList[key]); - return redirects.find((r) => r.names && r.names.indexOf(name) > -1); + return redirects.find((r) => r.names && r.names.includes(name)); }; /** diff --git a/src/redirects/redirects.js b/src/redirects/redirects.js index 5d90c806..60cc2246 100644 --- a/src/redirects/redirects.js +++ b/src/redirects/redirects.js @@ -62,7 +62,7 @@ class Redirects { if (!aliases) { return false; } - return aliases.indexOf(title) > -1; + return aliases.includes(title); }); } diff --git a/src/scriptlets/abort-current-inline-script.js b/src/scriptlets/abort-current-inline-script.js index f42d398b..3a4091b6 100644 --- a/src/scriptlets/abort-current-inline-script.js +++ b/src/scriptlets/abort-current-inline-script.js @@ -3,7 +3,6 @@ import { setPropertyAccess, getPropertyInChain, toRegExp, - startsWith, createOnErrorHandler, hit, logMessage, @@ -114,7 +113,7 @@ export function abortCurrentInlineScript(source, property, search) { // https://github.com/AdguardTeam/Scriptlets/issues/130 if (content.length === 0 && typeof scriptEl.src !== 'undefined' - && startsWith(scriptEl.src, SRC_DATA_MARKER)) { + && scriptEl.src?.startsWith(SRC_DATA_MARKER)) { const encodedContent = scriptEl.src.slice(SRC_DATA_MARKER.length); content = window.atob(encodedContent); } @@ -235,7 +234,6 @@ abortCurrentInlineScript.injections = [ setPropertyAccess, getPropertyInChain, toRegExp, - startsWith, createOnErrorHandler, hit, logMessage, diff --git a/src/scriptlets/abort-on-stack-trace.js b/src/scriptlets/abort-on-stack-trace.js index 449efd88..f5973b9c 100644 --- a/src/scriptlets/abort-on-stack-trace.js +++ b/src/scriptlets/abort-on-stack-trace.js @@ -14,7 +14,6 @@ import { toRegExp, isEmptyObject, getNativeRegexpTest, - startsWith, } from '../helpers/index'; /* eslint-disable max-len */ @@ -155,6 +154,5 @@ abortOnStackTrace.injections = [ toRegExp, isEmptyObject, getNativeRegexpTest, - startsWith, shouldAbortInlineOrInjectedScript, ]; diff --git a/src/scriptlets/close-window.js b/src/scriptlets/close-window.js index 26fb1309..3d227644 100644 --- a/src/scriptlets/close-window.js +++ b/src/scriptlets/close-window.js @@ -75,7 +75,7 @@ export function forceWindowClose(source, path = '') { if (shouldClose()) { closeImmediately(); - if (navigator.userAgent.indexOf('Chrome') > -1) { + if (navigator.userAgent.includes('Chrome')) { closeByExtension(); } } diff --git a/src/scriptlets/json-prune.js b/src/scriptlets/json-prune.js index 0b6526e5..a02bca27 100644 --- a/src/scriptlets/json-prune.js +++ b/src/scriptlets/json-prune.js @@ -126,12 +126,8 @@ export function jsonPrune(source, propsToRemove, requiredInitialProps, stack) { const requiredPath = requiredPaths[i]; const lastNestedPropName = requiredPath.split('.').pop(); - const hasWildcard = requiredPath.indexOf('.*.') > -1 - || requiredPath.indexOf('*.') > -1 - || requiredPath.indexOf('.*') > -1 - || requiredPath.indexOf('.[].') > -1 - || requiredPath.indexOf('[].') > -1 - || requiredPath.indexOf('.[]') > -1; + const wildcardSymbols = ['.*.', '*.', '.*', '.[].', '[].', '.[]']; + const hasWildcard = wildcardSymbols.some((symbol) => requiredPath.includes(symbol)); // if the path has wildcard, getPropertyInChain should 'look through' chain props const details = getWildcardPropertyInChain(root, requiredPath, hasWildcard); diff --git a/src/scriptlets/log-addEventListener.js b/src/scriptlets/log-addEventListener.js index f0b85998..b7b8d7fe 100644 --- a/src/scriptlets/log-addEventListener.js +++ b/src/scriptlets/log-addEventListener.js @@ -8,7 +8,6 @@ import { // following helpers are needed for helpers above objectToString, isEmptyObject, - getObjectEntries, } from '../helpers/index'; /** @@ -84,5 +83,4 @@ logAddEventListener.injections = [ logMessage, objectToString, isEmptyObject, - getObjectEntries, ]; diff --git a/src/scriptlets/prevent-bab.js b/src/scriptlets/prevent-bab.js index 91d8ce75..16af37d8 100644 --- a/src/scriptlets/prevent-bab.js +++ b/src/scriptlets/prevent-bab.js @@ -63,7 +63,7 @@ export function preventBab(source) { let match = 0; for (let j = 0; j < tokens.length; j += 1) { const token = tokens[j]; - const found = token instanceof RegExp ? token.test(str) : str.indexOf(token) > -1; + const found = token instanceof RegExp ? token.test(str) : str.includes(token); if (found) { match += 1; } diff --git a/src/scriptlets/prevent-fetch.js b/src/scriptlets/prevent-fetch.js index 8df086e8..0548ff85 100644 --- a/src/scriptlets/prevent-fetch.js +++ b/src/scriptlets/prevent-fetch.js @@ -13,8 +13,6 @@ import { isEmptyObject, getRequestData, getRequestProps, - getObjectEntries, - getObjectFromEntries, parseMatchProps, validateParsedData, getMatchPropsData, @@ -189,8 +187,6 @@ preventFetch.injections = [ isEmptyObject, getRequestData, getRequestProps, - getObjectEntries, - getObjectFromEntries, parseMatchProps, validateParsedData, getMatchPropsData, diff --git a/src/scriptlets/prevent-requestAnimationFrame.js b/src/scriptlets/prevent-requestAnimationFrame.js index 268107f6..246c359f 100644 --- a/src/scriptlets/prevent-requestAnimationFrame.js +++ b/src/scriptlets/prevent-requestAnimationFrame.js @@ -8,7 +8,6 @@ import { // following helpers are needed for helpers above escapeRegExp, toRegExp, - startsWith, } from '../helpers/index'; /* eslint-disable max-len */ @@ -132,5 +131,4 @@ preventRequestAnimationFrame.injections = [ // following helpers should be injected as helpers above use them escapeRegExp, toRegExp, - startsWith, ]; diff --git a/src/scriptlets/prevent-setInterval.js b/src/scriptlets/prevent-setInterval.js index 9fea16ea..1fdeb1f9 100644 --- a/src/scriptlets/prevent-setInterval.js +++ b/src/scriptlets/prevent-setInterval.js @@ -5,7 +5,6 @@ import { logMessage, // following helpers are needed for helpers above toRegExp, - startsWith, nativeIsNaN, parseMatchArg, parseDelayArg, @@ -197,7 +196,6 @@ preventSetInterval.injections = [ logMessage, // following helpers should be injected as helpers above use them toRegExp, - startsWith, nativeIsNaN, parseMatchArg, parseDelayArg, diff --git a/src/scriptlets/prevent-setTimeout.js b/src/scriptlets/prevent-setTimeout.js index aa42fc02..ce9fb9c8 100644 --- a/src/scriptlets/prevent-setTimeout.js +++ b/src/scriptlets/prevent-setTimeout.js @@ -7,7 +7,6 @@ import { parseMatchArg, parseDelayArg, toRegExp, - startsWith, nativeIsNaN, isValidCallback, isValidMatchStr, @@ -202,7 +201,6 @@ preventSetTimeout.injections = [ parseMatchArg, parseDelayArg, toRegExp, - startsWith, nativeIsNaN, isValidCallback, isValidMatchStr, diff --git a/src/scriptlets/prevent-window-open.js b/src/scriptlets/prevent-window-open.js index 9e2c0d95..89f3d822 100644 --- a/src/scriptlets/prevent-window-open.js +++ b/src/scriptlets/prevent-window-open.js @@ -14,8 +14,6 @@ import { escapeRegExp, noopFunc, trueFunc, - startsWith, - endsWith, substringBefore, substringAfter, } from '../helpers/index'; @@ -106,7 +104,7 @@ export function preventWindowOpen(source, match = '*', delay, replacement) { }; const newOpenWrapper = (url, ...args) => { - const shouldLog = replacement && replacement.indexOf('log') > -1; + const shouldLog = replacement && replacement.includes('log'); if (shouldLog) { const argsStr = args && args.length > 0 ? `, ${args.join(', ')}` @@ -191,8 +189,6 @@ preventWindowOpen.injections = [ logMessage, noopFunc, trueFunc, - startsWith, - endsWith, substringBefore, substringAfter, ]; diff --git a/src/scriptlets/prevent-xhr.js b/src/scriptlets/prevent-xhr.js index 2f253c4a..a2a62615 100644 --- a/src/scriptlets/prevent-xhr.js +++ b/src/scriptlets/prevent-xhr.js @@ -10,7 +10,6 @@ import { isValidStrPattern, escapeRegExp, isEmptyObject, - getObjectEntries, getNumberFromString, nativeIsFinite, nativeIsNaN, @@ -196,7 +195,6 @@ preventXHR.injections = [ isValidStrPattern, escapeRegExp, isEmptyObject, - getObjectEntries, getNumberFromString, nativeIsFinite, nativeIsNaN, diff --git a/src/scriptlets/remove-attr.js b/src/scriptlets/remove-attr.js index 24351e6f..3d5c09d0 100644 --- a/src/scriptlets/remove-attr.js +++ b/src/scriptlets/remove-attr.js @@ -125,7 +125,7 @@ export function removeAttr(source, attrs, selector, applying = 'asap stay') { window.addEventListener('load', run, { once: true }); } else if (flags.hasFlag(flags.STAY)) { // Only call rmattr for single 'stay' flag - if (!applying.indexOf(' ') !== -1) { + if (!applying.includes(' ')) { rmattr(); } // 'true' for observing attributes diff --git a/src/scriptlets/remove-class.js b/src/scriptlets/remove-class.js index dcb4be2a..2860cfe6 100644 --- a/src/scriptlets/remove-class.js +++ b/src/scriptlets/remove-class.js @@ -152,7 +152,7 @@ export function removeClass(source, classNames, selector, applying = 'asap stay' window.addEventListener('load', run, { once: true }); } else if (flags.hasFlag(flags.STAY)) { // Only call removeClassHandler for single 'stay' flag - if (!applying.indexOf(' ') !== -1) { + if (!applying.includes(' ')) { removeClassHandler(); } observeDOMChanges(removeClassHandler, true, CLASS_ATTR_NAME); diff --git a/src/scriptlets/trusted-click-element.js b/src/scriptlets/trusted-click-element.js index 1e8c98fd..5912f0d8 100644 --- a/src/scriptlets/trusted-click-element.js +++ b/src/scriptlets/trusted-click-element.js @@ -121,13 +121,13 @@ export function trustedClickElement(source, selectors, extraMatch = '', delay = // Filter match pairs by marker parsedExtraMatch.forEach((matchStr) => { - if (matchStr.indexOf(COOKIE_MATCH_MARKER) > -1) { + if (matchStr.includes(COOKIE_MATCH_MARKER)) { const { isInvertedMatch, matchValue } = parseMatchArg(matchStr); isInvertedMatchCookie = isInvertedMatch; const cookieMatch = matchValue.replace(COOKIE_MATCH_MARKER, ''); cookieMatches.push(cookieMatch); } - if (matchStr.indexOf(LOCAL_STORAGE_MATCH_MARKER) > -1) { + if (matchStr.includes(LOCAL_STORAGE_MATCH_MARKER)) { const { isInvertedMatch, matchValue } = parseMatchArg(matchStr); isInvertedMatchLocalStorage = isInvertedMatch; const localStorageMatch = matchValue.replace(LOCAL_STORAGE_MATCH_MARKER, ''); @@ -272,7 +272,7 @@ export function trustedClickElement(source, selectors, extraMatch = '', delay = // selectorsSequence should be modified after the loop to not break loop indexation selectorsSequence = selectorsSequence.map((selector) => { - return fulfilledSelectors.indexOf(selector) === -1 ? selector : null; + return fulfilledSelectors.includes(selector) ? null : selector; }); // Disconnect observer after finding all elements diff --git a/src/scriptlets/trusted-replace-fetch-response.js b/src/scriptlets/trusted-replace-fetch-response.js index f3a80978..74604c75 100644 --- a/src/scriptlets/trusted-replace-fetch-response.js +++ b/src/scriptlets/trusted-replace-fetch-response.js @@ -12,8 +12,6 @@ import { isEmptyObject, getRequestData, getRequestProps, - getObjectEntries, - getObjectFromEntries, parseMatchProps, validateParsedData, getMatchPropsData, @@ -204,8 +202,6 @@ trustedReplaceFetchResponse.injections = [ isEmptyObject, getRequestData, getRequestProps, - getObjectEntries, - getObjectFromEntries, parseMatchProps, validateParsedData, getMatchPropsData, diff --git a/src/scriptlets/trusted-replace-xhr-response.js b/src/scriptlets/trusted-replace-xhr-response.js index 980ed90b..f9180061 100644 --- a/src/scriptlets/trusted-replace-xhr-response.js +++ b/src/scriptlets/trusted-replace-xhr-response.js @@ -14,7 +14,6 @@ import { isValidStrPattern, escapeRegExp, isEmptyObject, - getObjectEntries, } from '../helpers/index'; /* eslint-disable max-len */ @@ -247,5 +246,4 @@ trustedReplaceXhrResponse.injections = [ isValidStrPattern, escapeRegExp, isEmptyObject, - getObjectEntries, ]; diff --git a/src/scriptlets/xml-prune.js b/src/scriptlets/xml-prune.js index 2b2b1c55..5c071872 100644 --- a/src/scriptlets/xml-prune.js +++ b/src/scriptlets/xml-prune.js @@ -81,8 +81,8 @@ export function xmlPrune(source, propsToRemove, optionalProp = '', urlToMatch) { if (typeof text === 'string') { // Check if "text" starts with "<" and check if it ends with ">" // If so, then it might be an XML file and should be pruned or logged - const trimedText = text.trim(); - if (trimedText.startsWith('<') && trimedText.endsWith('>')) { + const trimmedText = text.trim(); + if (trimmedText.startsWith('<') && trimmedText.endsWith('>')) { return true; } } diff --git a/tests/helpers/log-message.test.js b/tests/helpers/log-message.test.js index 6167628c..0ea9f02f 100644 --- a/tests/helpers/log-message.test.js +++ b/tests/helpers/log-message.test.js @@ -20,7 +20,7 @@ const MESSAGE = 'arbitrary text message'; test('Logs message conditionally', async (assert) => { // eslint-disable-next-line no-console console.log = function log(input) { - if (input.indexOf('trace') > -1) { + if (input.includes('trace')) { return; } assert.strictEqual( @@ -63,7 +63,7 @@ test('Logs message conditionally', async (assert) => { test('Logs message without ruleText', async (assert) => { // eslint-disable-next-line no-console console.log = function log(input) { - if (input.indexOf('trace') > -1) { + if (input.includes('trace')) { return; } assert.strictEqual( diff --git a/tests/redirects/noeval.test.js b/tests/redirects/noeval.test.js index bb28d562..2f143b3a 100644 --- a/tests/redirects/noeval.test.js +++ b/tests/redirects/noeval.test.js @@ -48,7 +48,7 @@ test('AG noeval alias', (assert) => { assert.expect(3); console.log = function log(input) { - if (input.indexOf('trace') > -1) { + if (input.includes('trace')) { return; } assert.ok(input.includes(`${name}: AdGuard has prevented eval:`), 'console.hit should print info'); diff --git a/tests/scriptlets/adjust-setInterval.test.js b/tests/scriptlets/adjust-setInterval.test.js index 0400c70a..dbffd371 100644 --- a/tests/scriptlets/adjust-setInterval.test.js +++ b/tests/scriptlets/adjust-setInterval.test.js @@ -297,7 +297,7 @@ test('no match -- invalid callback - undefined', (assert) => { let loggedMessage; // eslint-disable-next-line no-console console.log = function log(input) { - if (input.indexOf('trace') > -1) { + if (input.includes('trace')) { return; } loggedMessage = input; diff --git a/tests/scriptlets/adjust-setTimeout.test.js b/tests/scriptlets/adjust-setTimeout.test.js index 8c54287e..52b3ab67 100644 --- a/tests/scriptlets/adjust-setTimeout.test.js +++ b/tests/scriptlets/adjust-setTimeout.test.js @@ -297,7 +297,7 @@ test('no match -- invalid callback - undefined', (assert) => { let loggedMessage; // eslint-disable-next-line no-console console.log = function log(input) { - if (input.indexOf('trace') > -1) { + if (input.includes('trace')) { return; } loggedMessage = input; diff --git a/tests/scriptlets/inject-css-in-shadow-dom.test.js b/tests/scriptlets/inject-css-in-shadow-dom.test.js index d86d0af9..c0f6b4e1 100644 --- a/tests/scriptlets/inject-css-in-shadow-dom.test.js +++ b/tests/scriptlets/inject-css-in-shadow-dom.test.js @@ -108,7 +108,7 @@ if (!isSupported) { test('do not apply style with url function, logged correctly', (assert) => { assert.expect(3); console.log = function log(input) { - if (input.indexOf('trace') > -1) { + if (input.includes('trace')) { return; } assert.strictEqual( @@ -135,7 +135,7 @@ if (!isSupported) { test('do not apply style with image-set function, logged correctly', (assert) => { assert.expect(3); console.log = function log(input) { - if (input.indexOf('trace') > -1) { + if (input.includes('trace')) { return; } assert.strictEqual( @@ -162,7 +162,7 @@ if (!isSupported) { test('do not apply invalid style, logged correctly', (assert) => { assert.expect(3); console.log = function log(input) { - if (typeof input !== 'string' || input.indexOf('trace') > -1) { + if (typeof input !== 'string' || input.includes('trace')) { return; } diff --git a/tests/scriptlets/log-addEventListener.test.js b/tests/scriptlets/log-addEventListener.test.js index 639064c7..718d14fc 100644 --- a/tests/scriptlets/log-addEventListener.test.js +++ b/tests/scriptlets/log-addEventListener.test.js @@ -55,7 +55,7 @@ test('logs events to console', (assert) => { }; console.log = function log(input) { // Ignore hit messages with "trace" - if (input.indexOf('trace') > -1) { + if (input.includes('trace')) { return; } assert.ok(input.includes(eventName), 'console.hit input should be equal'); @@ -81,11 +81,11 @@ test('logs events to console - listener is null', (assert) => { console.log = function log(input) { // Ignore hit messages with "trace" - if (input.indexOf('trace') > -1) { + if (input.includes('trace')) { return; } - assert.ok(input.indexOf(INVALID_MESSAGE_START) > -1, 'passed invalid args'); - assert.ok(input.indexOf(INVALID_MESSAGE_PART) > -1, 'passed invalid args'); + assert.ok(input.includes(INVALID_MESSAGE_START), 'passed invalid args'); + assert.ok(input.includes(INVALID_MESSAGE_PART), 'passed invalid args'); }; runScriptlet(name); @@ -114,11 +114,11 @@ test('logs events to console - listener is not a function', (assert) => { console.log = function log(input) { // Ignore hit messages with "trace" - if (input.indexOf('trace') > -1) { + if (input.includes('trace')) { return; } - assert.ok(input.indexOf(INVALID_MESSAGE_START) > -1, 'passed invalid args'); - assert.ok(input.indexOf(INVALID_MESSAGE_PART) > -1, 'passed invalid args'); + assert.ok(input.includes(INVALID_MESSAGE_START), 'passed invalid args'); + assert.ok(input.includes(INVALID_MESSAGE_PART), 'passed invalid args'); }; runScriptlet(name); @@ -144,11 +144,11 @@ test('logs events to console - event is undefined', (assert) => { console.log = function log(input) { // Ignore hit messages with "trace" - if (input.indexOf('trace') > -1) { + if (input.includes('trace')) { return; } - assert.ok(input.indexOf(INVALID_MESSAGE_START) > -1, 'passed invalid args'); - assert.ok(input.indexOf(INVALID_MESSAGE_PART) > -1, 'passed invalid args'); + assert.ok(input.includes(INVALID_MESSAGE_START), 'passed invalid args'); + assert.ok(input.includes(INVALID_MESSAGE_PART), 'passed invalid args'); }; runScriptlet(name); diff --git a/tests/scriptlets/log-eval.test.js b/tests/scriptlets/log-eval.test.js index b12a6beb..b2dca9d8 100644 --- a/tests/scriptlets/log-eval.test.js +++ b/tests/scriptlets/log-eval.test.js @@ -29,7 +29,7 @@ test('logs eval calls', (assert) => { const evalStr = `(function () {window.${agLogEval} = 'changed';})()`; console.log = function log(input) { - if (input.indexOf('trace') > -1) { + if (input.includes('trace')) { return; } assert.strictEqual(input, `${name}: eval("${evalStr}")`, 'console.hit input should be equal'); @@ -49,7 +49,7 @@ test('logs new Function() calls', (assert) => { const args = ['propName', 'propValue', 'window[propName] = propValue']; console.log = function log(input) { - if (input.indexOf('trace') > -1) { + if (input.includes('trace')) { return; } assert.strictEqual(input, `${name}: new Function(${args.join(', ')})`, 'console.hit input should be equal'); diff --git a/tests/scriptlets/log-on-stack-trace.test.js b/tests/scriptlets/log-on-stack-trace.test.js index 55a8c265..8d922b2f 100644 --- a/tests/scriptlets/log-on-stack-trace.test.js +++ b/tests/scriptlets/log-on-stack-trace.test.js @@ -61,7 +61,7 @@ test('logs specific message', (assert) => { console.log = function log(input) { // Ignore hit messages with "trace" - if (input.indexOf('trace') > -1) { + if (input.includes('trace')) { return; } assert.strictEqual(input, `%cSet %c${PROPERTY}`, 'Log message is correct'); @@ -81,7 +81,7 @@ test('check if message is not empty', (assert) => { console.table = function log(input) { const inputString = JSON.stringify(input); const checkString = 'log-on-stack-trace'; - assert.ok(inputString.indexOf(checkString) > -1, 'Log message is not empty'); + assert.ok(inputString.includes(checkString), 'Log message is not empty'); }; setProp(PROPERTY); diff --git a/tests/scriptlets/noeval.test.js b/tests/scriptlets/noeval.test.js index 724810cb..6d872b95 100644 --- a/tests/scriptlets/noeval.test.js +++ b/tests/scriptlets/noeval.test.js @@ -48,7 +48,7 @@ test('AG noeval alias', (assert) => { assert.expect(3); console.log = function log(input) { - if (input.indexOf('trace') > -1) { + if (input.includes('trace')) { return; } assert.ok(input.includes(`${name}: AdGuard has prevented eval:`), 'console.hit should print info'); diff --git a/tests/scriptlets/nowebrtc.test.js b/tests/scriptlets/nowebrtc.test.js index ef339390..e9e802ed 100644 --- a/tests/scriptlets/nowebrtc.test.js +++ b/tests/scriptlets/nowebrtc.test.js @@ -1,7 +1,6 @@ /* eslint-disable no-underscore-dangle */ import { runScriptlet, clearGlobalProps } from '../helpers'; -import { endsWith } from '../../src/helpers/string-utils'; const { test, module } = QUnit; const name = 'nowebrtc'; @@ -83,12 +82,12 @@ if (!isSupported) { // mock console.log function for log checking // eslint-disable-next-line no-console console.log = function log(input) { - if (input.indexOf('trace') > -1) { + if (input.includes('trace')) { return; } - const EXPECTED_LOG_STR = `${name}: Document tried to create an RTCPeerConnection: ${TEST_URL_VALUE};`; - assert.ok(endsWith(input, EXPECTED_LOG_STR), 'console.hit input'); + const EXPECTED_LOG_STR = `${name}: Document tried to create an RTCPeerConnection: ${TEST_URL_VALUE}`; + assert.ok(input.endsWith(EXPECTED_LOG_STR), 'console.hit input'); }; runScriptlet(name); diff --git a/tests/scriptlets/prevent-element-src-loading.test.js b/tests/scriptlets/prevent-element-src-loading.test.js index 78eab002..c79452ac 100644 --- a/tests/scriptlets/prevent-element-src-loading.test.js +++ b/tests/scriptlets/prevent-element-src-loading.test.js @@ -198,7 +198,7 @@ test('setAttribute, mismatching element', (assert) => { SET_SRC_ATTRIBUTE, ONERROR_PROP, ); - assert.ok(window.elem.src.indexOf(TEST_SCRIPT02_FILENAME) !== -1, 'src was NOT mocked'); + assert.ok(window.elem.src.includes(TEST_SCRIPT02_FILENAME), 'src was NOT mocked'); assert.strictEqual(window.hit, undefined, 'hit should NOT fire'); }); @@ -214,7 +214,7 @@ test('src prop, mismatching element', (assert) => { SET_SRC_PROP, ONERROR_PROP, ); - assert.ok(window.elem.src.indexOf(TEST_SCRIPT02_FILENAME) !== -1, 'src was NOT mocked'); + assert.ok(window.elem.src.includes(TEST_SCRIPT02_FILENAME), 'src was NOT mocked'); assert.strictEqual(window.hit, undefined, 'hit should NOT fire'); }); diff --git a/tests/scriptlets/prevent-fetch.test.js b/tests/scriptlets/prevent-fetch.test.js index 2e71b482..8d41f7cd 100644 --- a/tests/scriptlets/prevent-fetch.test.js +++ b/tests/scriptlets/prevent-fetch.test.js @@ -66,7 +66,7 @@ if (!isSupported) { // mock console.log function for log checking console.log = function log(input) { - if (input.indexOf('trace') > -1) { + if (input.includes('trace')) { return; } const EXPECTED_LOG_STR_START = `${name}: fetch( url:"${INPUT_JSON_PATH}" method:"${TEST_METHOD}"`; diff --git a/tests/scriptlets/prevent-refresh.test.js b/tests/scriptlets/prevent-refresh.test.js index 48cbb833..8e8e6e23 100644 --- a/tests/scriptlets/prevent-refresh.test.js +++ b/tests/scriptlets/prevent-refresh.test.js @@ -54,7 +54,7 @@ test('Prevent redirect, delay from meta', (assert) => { runScriptlet(name); const done = assert.async(); setTimeout(() => { - assert.ok(location.href.indexOf('prevent-refresh') !== -1, 'Redirect prevented'); + assert.ok(location.href.includes('prevent-refresh'), 'Redirect prevented'); assert.strictEqual(window.hit, 'FIRED', 'hit function was executed'); done(); }, 1 * 1000); @@ -68,7 +68,7 @@ test('Prevent redirect, delay from arg (delay 0)', (assert) => { runScriptlet(name, ['0']); const done = assert.async(); setTimeout(() => { - assert.ok(location.href.indexOf('prevent-refresh') !== -1, 'Redirect prevented'); + assert.ok(location.href.includes('prevent-refresh'), 'Redirect prevented'); assert.strictEqual(window.hit, 'FIRED', 'hit function was executed'); removeMeta(); done(); @@ -83,7 +83,7 @@ test('Prevent redirect, delay from arg (delay 1)', (assert) => { runScriptlet(name, ['1']); const done = assert.async(); setTimeout(() => { - assert.ok(location.href.indexOf('prevent-refresh') !== -1, 'Redirect prevented'); + assert.ok(location.href.includes('prevent-refresh'), 'Redirect prevented'); assert.strictEqual(window.hit, 'FIRED', 'hit function was executed'); removeMeta(); done(); diff --git a/tests/scriptlets/prevent-requestAnimationFrame.test.js b/tests/scriptlets/prevent-requestAnimationFrame.test.js index fc030160..ce41afd1 100644 --- a/tests/scriptlets/prevent-requestAnimationFrame.test.js +++ b/tests/scriptlets/prevent-requestAnimationFrame.test.js @@ -48,7 +48,7 @@ test('prevent-requestAnimationFrame: no args -- logging', (assert) => { let loggedMessage; // eslint-disable-next-line no-console console.log = function log(input) { - if (input.indexOf('trace') > -1) { + if (input.includes('trace')) { return; } loggedMessage = input; diff --git a/tests/scriptlets/prevent-setInterval.test.js b/tests/scriptlets/prevent-setInterval.test.js index d857f0a8..588e80ba 100644 --- a/tests/scriptlets/prevent-setInterval.test.js +++ b/tests/scriptlets/prevent-setInterval.test.js @@ -52,7 +52,7 @@ test('no args -- logging', (assert) => { let loggedMessage; // eslint-disable-next-line no-console console.log = function log(input) { - if (input.indexOf('trace') > -1) { + if (input.includes('trace')) { return; } loggedMessage = input; diff --git a/tests/scriptlets/prevent-setTimeout.test.js b/tests/scriptlets/prevent-setTimeout.test.js index 907d6ba5..98c3eaaf 100644 --- a/tests/scriptlets/prevent-setTimeout.test.js +++ b/tests/scriptlets/prevent-setTimeout.test.js @@ -52,7 +52,7 @@ test('no args -- logging', (assert) => { let loggedMessage; // eslint-disable-next-line no-console console.log = function log(input) { - if (input.indexOf('trace') > -1) { + if (input.includes('trace')) { return; } loggedMessage = input; diff --git a/tests/scriptlets/prevent-window-open.test.js b/tests/scriptlets/prevent-window-open.test.js index 40eec57f..953329d5 100644 --- a/tests/scriptlets/prevent-window-open.test.js +++ b/tests/scriptlets/prevent-window-open.test.js @@ -181,7 +181,7 @@ test('new syntax: log checking - only url', (assert) => { // mock console.log function for log checking // eslint-disable-next-line no-console console.log = function log(input) { - if (input.indexOf('trace') > -1) { + if (input.includes('trace')) { return; } const EXPECTED_LOG_STR = `${name}: ${testUrl}`; @@ -204,7 +204,7 @@ test('new syntax: log checking - url + args', (assert) => { // mock console.log function for log checking // eslint-disable-next-line no-console console.log = function log(input) { - if (input.indexOf('trace') > -1) { + if (input.includes('trace')) { return; } const EXPECTED_LOG_STR = `${name}: ${testUrl}, ${testWindowName}, ${testWindowFeatures}`; diff --git a/tests/scriptlets/prevent-xhr.test.js b/tests/scriptlets/prevent-xhr.test.js index a6c8ac10..a4bace06 100644 --- a/tests/scriptlets/prevent-xhr.test.js +++ b/tests/scriptlets/prevent-xhr.test.js @@ -1,6 +1,6 @@ /* eslint-disable no-underscore-dangle, no-console */ import { runScriptlet, clearGlobalProps } from '../helpers'; -import { startsWith, logMessage } from '../../src/helpers'; +import { logMessage } from '../../src/helpers'; const { test, module } = QUnit; const name = 'prevent-xhr'; @@ -54,11 +54,11 @@ if (isSupported) { // mock console.log function for log checking console.log = function log(input) { - if (input.indexOf('trace') > -1) { + if (input.includes('trace')) { return; } const EXPECTED_LOG_STR = `${name}: xhr( method:"${METHOD}" url:"${URL}" )`; - assert.ok(startsWith(input, EXPECTED_LOG_STR), 'console.hit input'); + assert.ok(input.startsWith(EXPECTED_LOG_STR), 'console.hit input'); }; runScriptlet(name); diff --git a/tests/scriptlets/remove-attr.test.js b/tests/scriptlets/remove-attr.test.js index 80e7b863..23320ca8 100644 --- a/tests/scriptlets/remove-attr.test.js +++ b/tests/scriptlets/remove-attr.test.js @@ -303,7 +303,7 @@ test('invalid selector — no match', (assert) => { // eslint-disable-next-line no-console console.log = function log(input) { - if (input.indexOf('trace') > -1) { + if (input.includes('trace')) { return; } assert.strictEqual( diff --git a/tests/scriptlets/remove-class.test.js b/tests/scriptlets/remove-class.test.js index e3b11ba9..20da3e75 100644 --- a/tests/scriptlets/remove-class.test.js +++ b/tests/scriptlets/remove-class.test.js @@ -273,7 +273,7 @@ test('invalid selector — no match', (assert) => { // eslint-disable-next-line no-console console.log = function log(input) { - if (input.indexOf('trace') > -1) { + if (input.includes('trace')) { return; } assert.strictEqual(input, `${name}: Invalid selector arg: '${selectors}'`, 'logged error for invalid remove-class selector'); diff --git a/tests/scriptlets/trusted-replace-fetch-response.test.js b/tests/scriptlets/trusted-replace-fetch-response.test.js index d564dd5f..1376f68d 100644 --- a/tests/scriptlets/trusted-replace-fetch-response.test.js +++ b/tests/scriptlets/trusted-replace-fetch-response.test.js @@ -1,6 +1,5 @@ /* eslint-disable no-underscore-dangle, no-console */ import { runScriptlet, clearGlobalProps } from '../helpers'; -import { startsWith } from '../../src/helpers/string-utils'; const { test, module } = QUnit; const name = 'trusted-replace-fetch-response'; @@ -47,11 +46,11 @@ if (!isSupported) { // mock console.log function for log checking console.log = function log(input) { - if (input.indexOf('trace') > -1) { + if (input.includes('trace')) { return; } const EXPECTED_LOG_STR_START = `${name}: fetch( url:"${INPUT_JSON_PATH}" method:"${TEST_METHOD}"`; - assert.ok(startsWith(input, EXPECTED_LOG_STR_START), 'console.hit input'); + assert.ok(input.startsWith(EXPECTED_LOG_STR_START), 'console.hit input'); }; // no args -> just logging, no replacements diff --git a/tests/scriptlets/trusted-replace-xhr-response.test.js b/tests/scriptlets/trusted-replace-xhr-response.test.js index 92ff2171..191952a5 100644 --- a/tests/scriptlets/trusted-replace-xhr-response.test.js +++ b/tests/scriptlets/trusted-replace-xhr-response.test.js @@ -1,6 +1,5 @@ /* eslint-disable no-underscore-dangle, no-console */ import { runScriptlet, clearGlobalProps } from '../helpers'; -import { startsWith } from '../../src/helpers/string-utils'; const { test, module } = QUnit; const name = 'trusted-replace-xhr-response'; @@ -39,12 +38,12 @@ if (isSupported) { // mock console.log function for log checking console.log = function log(input) { - if (input.indexOf('trace') > -1) { + if (input.includes('trace')) { return; } // eslint-disable-next-line max-len const EXPECTED_LOG_STR = `${name}: xhr( method:"${METHOD}" url:"${URL}" async:"${ASYNC}" user:"${USER}" password:"${PASSWORD}" )`; - assert.ok(startsWith(input, EXPECTED_LOG_STR), 'console.hit input'); + assert.ok(input.startsWith(EXPECTED_LOG_STR), 'console.hit input'); }; const PATTERN = ''; const REPLACEMENT = ''; diff --git a/tests/scriptlets/trusted-set-cookie.test.js b/tests/scriptlets/trusted-set-cookie.test.js index 8e044c8f..2941be7f 100644 --- a/tests/scriptlets/trusted-set-cookie.test.js +++ b/tests/scriptlets/trusted-set-cookie.test.js @@ -109,7 +109,7 @@ test('Set cookie with invalid expires', (assert) => { assert.expect(4); // eslint-disable-next-line no-console console.log = function log(input) { - if (input.indexOf('trace') > -1) { + if (input.includes('trace')) { return; } assert.strictEqual( diff --git a/tests/scriptlets/xml-prune.test.js b/tests/scriptlets/xml-prune.test.js index e33f51ca..cac4f573 100644 --- a/tests/scriptlets/xml-prune.test.js +++ b/tests/scriptlets/xml-prune.test.js @@ -57,12 +57,12 @@ if (!isSupported) { console.log = function log(...args) { const input = args[0]; if (typeof input === 'string' && typeof args[1] === 'undefined') { - if (input.indexOf('trace') > -1) { + if (input.includes('trace')) { return; } const EXPECTED_LOG_STR_START = `xml-prune: fetch URL: ${MPD_OBJECTS_PATH}`; assert.ok(input.startsWith(EXPECTED_LOG_STR_START), 'console.hit input'); - assert.ok(input.indexOf('pre-roll-1-ad-1') > -1); + assert.ok(input.includes('pre-roll-1-ad-1')); done(); } nativeConsole(...args); @@ -73,7 +73,7 @@ if (!isSupported) { const response = await fetch(MPD_OBJECTS_PATH); const responseMPD = await response.text(); - assert.ok(responseMPD.indexOf('pre-roll-1-ad-1') > -1); + assert.ok(responseMPD.includes('pre-roll-1-ad-1')); assert.strictEqual(window.hit, undefined, 'should not hit'); done(); }); @@ -91,7 +91,7 @@ if (!isSupported) { const response = await fetch(MPD_OBJECTS_PATH); const responseMPD = await response.text(); - assert.ok(responseMPD.indexOf('pre-roll-1-ad-1') > -1); + assert.ok(responseMPD.includes('pre-roll-1-ad-1')); assert.strictEqual(window.hit, undefined, 'should not hit'); done(); }); @@ -109,7 +109,7 @@ if (!isSupported) { const response = await fetch(MPD_OBJECTS_PATH); const responseMPD = await response.text(); - assert.ok(responseMPD.indexOf('pre-roll-1-ad-1') > -1); + assert.ok(responseMPD.includes('pre-roll-1-ad-1')); assert.strictEqual(window.hit, undefined, 'should not hit'); done(); }); @@ -127,7 +127,7 @@ if (!isSupported) { const response = await fetch(MPD_OBJECTS_PATH); const responseMPD = await response.text(); - assert.ok(responseMPD.indexOf('pre-roll-1-ad-1') > -1); + assert.ok(responseMPD.includes('pre-roll-1-ad-1')); assert.strictEqual(window.hit, undefined, 'should not hit'); done(); }); @@ -142,7 +142,7 @@ if (!isSupported) { const response = await fetch(MPD_OBJECTS_PATH); const responseMPD = await response.text(); - assert.notOk(responseMPD.indexOf('pre-roll-1-ad-1') > -1); + assert.notOk(responseMPD.includes('pre-roll-1-ad-1')); assert.strictEqual(window.hit, 'FIRED', 'hit function fired'); done(); }); @@ -160,7 +160,7 @@ if (!isSupported) { const response = await fetch(MPD_OBJECTS_PATH); const responseMPD = await response.text(); - assert.notOk(responseMPD.indexOf('pre-roll-1-ad-1') > -1); + assert.notOk(responseMPD.includes('pre-roll-1-ad-1')); assert.strictEqual(window.hit, 'FIRED', 'hit function fired'); done(); }); @@ -178,7 +178,7 @@ if (!isSupported) { const response = await fetch(MPD_OBJECTS_PATH); const responseMPD = await response.text(); - assert.notOk(responseMPD.indexOf('pre-roll-1-ad-1') > -1); + assert.notOk(responseMPD.includes('pre-roll-1-ad-1')); assert.strictEqual(window.hit, 'FIRED', 'hit function fired'); done(); }); @@ -197,7 +197,7 @@ if (!isSupported) { const response = await fetch(REQUEST_URL); const responseMPD = await response.text(); - assert.notOk(responseMPD.indexOf('pre-roll-1-ad-1') > -1); + assert.notOk(responseMPD.includes('pre-roll-1-ad-1')); assert.strictEqual(window.hit, 'FIRED', 'hit function fired'); done(); }); @@ -208,12 +208,12 @@ if (!isSupported) { console.log = function log(...args) { const input = args[0]; if (typeof input === 'string' && typeof args[1] === 'undefined') { - if (input.indexOf('trace') > -1) { + if (input.includes('trace')) { return; } const EXPECTED_LOG_STR_START = `xml-prune: XMLHttpRequest.open() URL: ${MPD_OBJECTS_PATH}`; assert.ok(input.startsWith(EXPECTED_LOG_STR_START), 'console.hit input'); - assert.ok(input.indexOf('pre-roll-1-ad-1') > -1, 'console.hit input'); + assert.ok(input.includes('pre-roll-1-ad-1'), 'console.hit input'); done(); } nativeConsole(...args); @@ -224,7 +224,7 @@ if (!isSupported) { const xhr = new XMLHttpRequest(); xhr.open(GET_METHOD, MPD_OBJECTS_PATH); xhr.onload = () => { - assert.ok(xhr.responseText.indexOf('pre-roll-1-ad-1') > -1); + assert.ok(xhr.responseText.includes('pre-roll-1-ad-1')); assert.strictEqual(window.hit, undefined, 'should not hit'); done(); }; @@ -244,7 +244,7 @@ if (!isSupported) { const xhr = new XMLHttpRequest(); xhr.open(GET_METHOD, MPD_OBJECTS_PATH); xhr.onload = () => { - assert.ok(xhr.responseText.indexOf('pre-roll-1-ad-1') > -1); + assert.ok(xhr.responseText.includes('pre-roll-1-ad-1')); assert.strictEqual(window.hit, undefined, 'should not hit'); done(); }; @@ -264,7 +264,7 @@ if (!isSupported) { const xhr = new XMLHttpRequest(); xhr.open(GET_METHOD, MPD_OBJECTS_PATH); xhr.onload = () => { - assert.ok(xhr.responseText.indexOf('pre-roll-1-ad-1') > -1); + assert.ok(xhr.responseText.includes('pre-roll-1-ad-1')); assert.strictEqual(window.hit, undefined, 'should not hit'); done(); }; @@ -284,7 +284,7 @@ if (!isSupported) { const xhr = new XMLHttpRequest(); xhr.open(GET_METHOD, MPD_OBJECTS_PATH); xhr.onload = () => { - assert.ok(xhr.responseText.indexOf('pre-roll-1-ad-1') > -1); + assert.ok(xhr.responseText.includes('pre-roll-1-ad-1')); assert.strictEqual(window.hit, undefined, 'should not hit'); done(); }; @@ -301,7 +301,7 @@ if (!isSupported) { const xhr = new XMLHttpRequest(); xhr.open(GET_METHOD, MPD_OBJECTS_PATH); xhr.onload = () => { - assert.notOk(xhr.responseText.indexOf('pre-roll-1-ad-1') > -1); + assert.notOk(xhr.responseText.includes('pre-roll-1-ad-1')); assert.strictEqual(window.hit, 'FIRED', 'hit function fired'); done(); }; @@ -321,7 +321,7 @@ if (!isSupported) { const xhr = new XMLHttpRequest(); xhr.open(GET_METHOD, MPD_OBJECTS_PATH); xhr.onload = () => { - assert.notOk(xhr.responseText.indexOf('pre-roll-1-ad-1') > -1); + assert.notOk(xhr.responseText.includes('pre-roll-1-ad-1')); assert.strictEqual(window.hit, 'FIRED', 'hit function fired'); done(); }; @@ -341,7 +341,7 @@ if (!isSupported) { const xhr = new XMLHttpRequest(); xhr.open(GET_METHOD, MPD_OBJECTS_PATH); xhr.onload = () => { - assert.notOk(xhr.responseText.indexOf('pre-roll-1-ad-1') > -1); + assert.notOk(xhr.responseText.includes('pre-roll-1-ad-1')); assert.strictEqual(window.hit, 'FIRED', 'hit function fired'); done(); }; From 6af803ceda932a9682bdac403e9454a984648303 Mon Sep 17 00:00:00 2001 From: Atlassian Bamboo Date: Tue, 16 May 2023 16:03:51 +0300 Subject: [PATCH 10/12] skipci: Automatic increment build number --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e9ae1e49..764a3d63 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@adguard/scriptlets", - "version": "1.9.15", + "version": "1.9.16", "description": "AdGuard's JavaScript library of Scriptlets and Redirect resources", "scripts": { "build": "babel-node bundler.js", From 4d400948d5d46b8f60501503b248ee48c2a52b3b Mon Sep 17 00:00:00 2001 From: Slava Leleka Date: Tue, 16 May 2023 18:29:54 +0300 Subject: [PATCH 11/12] mock getResponseHeader() and getAllResponseHeaders() methods for prevent-xhr #295 AG-20196 Squashed commit of the following: commit 8bd673969f1301ff982f5eaf41d7ec869ebcc755 Author: Slava Leleka Date: Tue May 16 18:07:12 2023 +0300 no deprecated helper startsWith() usage commit a0e0db1ff93e88527cc4fc7c1862d9038e09cc5a Author: Slava Leleka Date: Tue May 16 17:59:14 2023 +0300 fix trusted-replace-xhr-response commit ef04555f2fb4264c3c54db8a8b2fc281f2ec9106 Merge: 0efb80e0 6af803ce Author: Slava Leleka Date: Tue May 16 17:42:45 2023 +0300 merge master, resolve conflicts commit 0efb80e0954c8a12c970c35798f433cd1ac1eadf Author: Slava Leleka Date: Tue May 16 14:25:41 2023 +0300 update changelog commit f9c6da7cea7b031672586cfeab898e541c42d0cf Author: Slava Leleka Date: Tue May 16 14:23:22 2023 +0300 update changelog commit e15e9231e2f01197afbe6fb56ea5e6b1f3fccfef Merge: 10c03930 71d7683b Author: Slava Leleka Date: Tue May 16 14:22:13 2023 +0300 merge master, resolve conflicts commit 10c039309ea424ec86bd1d70af8d2f4214331534 Author: Slava Leleka Date: Tue May 16 14:15:31 2023 +0300 add comments for getHeaderWrapper() and getAllHeadersWrapper() commit 8ff8421a8355929be4ce383591f8f6bc1194e1cf Author: Slava Leleka Date: Tue May 16 13:34:36 2023 +0300 add todo for array destructuring commit 776201868efc30f57b9d2ac0a378c1e35f0ca5e4 Merge: e8760f3f 66582ca7 Author: Slava Leleka Date: Tue May 16 12:16:54 2023 +0300 Merge branch 'master' into fix/AG-20196 commit e8760f3fa96fd8463cde5699057d53add158eeaa Merge: 35074e59 b13ae17d Author: Slava Leleka Date: Mon May 15 11:53:57 2023 +0300 Merge branch 'fix/AG-20196' of ssh://bit.adguard.com:7999/adguard-filters/scriptlets into fix/AG-20196 commit 35074e5983ab6227adddc49c31a1d9f66b0d9861 Merge: eb1d72a0 898998d3 Author: Slava Leleka Date: Mon May 15 11:53:11 2023 +0300 Merge branch 'master' into fix/AG-20196 commit b13ae17d79331afe27def1309b3e5b1adf0acd08 Author: Slava Leleka Date: Fri May 12 18:06:13 2023 +0300 improve error text commit 93c3b6b363207e6136101bc9688c5b0dd5170018 Author: Slava Leleka Date: Fri May 12 18:04:11 2023 +0300 fix changelog commit eb1d72a063b2576315c0062698ae8b5d2952048d Author: Slava Leleka Date: Fri May 12 14:15:39 2023 +0300 update changelog commit f62fc97e8f9f6ec577e04b27f78b628699b94dcd Merge: b378dd4b b96e797b Author: Slava Leleka Date: Fri May 12 13:50:37 2023 +0300 Merge branch 'master' into fix/AG-20196 commit b378dd4b49a587c374472fcc7d27a708689564a1 Author: Slava Leleka Date: Fri May 12 13:49:31 2023 +0300 improve prevent-xhr - add mock getResponseHeader() and getAllResponseHeaders() methods --- CHANGELOG.md | 7 +- src/scriptlets/prevent-xhr.js | 199 ++++++++++++++---- .../trusted-replace-xhr-response.js | 16 +- tests/scriptlets/prevent-xhr.test.js | 53 ++++- 4 files changed, 229 insertions(+), 46 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ba659b7..ab5a7a7c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,14 +11,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed -- `trusted-set-cookie` and `trusted-set-cookie-reaload` scriptlets to not encode cookie name and value [#311](https://github.com/AdguardTeam/Scriptlets/issues/311) -- improved `prevent-fetch` — if `responseType` is not specified, +- `trusted-set-cookie` and `trusted-set-cookie-reload` scriptlets to not encode cookie name and value + [#311](https://github.com/AdguardTeam/Scriptlets/issues/311) +- 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 - website reloading if `$now$`/`$currentDate$` value is used in `trusted-set-cookie-reload` scriptlet [#291](https://github.com/AdguardTeam/Scriptlets/issues/291) +- `getResponseHeader()` and `getAllResponseHeaders()` methods mock + in `prevent-xhr` scriptlet [#295](https://github.com/AdguardTeam/Scriptlets/issues/295) ## [v1.9.7] - 2023-03-14 diff --git a/src/scriptlets/prevent-xhr.js b/src/scriptlets/prevent-xhr.js index a2a62615..99f64fb5 100644 --- a/src/scriptlets/prevent-xhr.js +++ b/src/scriptlets/prevent-xhr.js @@ -3,6 +3,7 @@ import { objectToString, generateRandomResponse, matchRequestProps, + getXhrData, logMessage, // following helpers should be imported and injected // because they are used by helpers above @@ -97,16 +98,18 @@ export function preventXHR(source, propsToMatch, customResponseText) { return; } - let response = ''; - let responseText = ''; - let responseUrl; + const nativeOpen = window.XMLHttpRequest.prototype.open; + const nativeSend = window.XMLHttpRequest.prototype.send; + + let xhrData; + let modifiedResponse = ''; + let modifiedResponseText = ''; + const openWrapper = (target, thisArg, args) => { - // Get method and url from .open() - const xhrData = { - method: args[0], - url: args[1], - }; - responseUrl = xhrData.url; + // Get original request properties + // eslint-disable-next-line prefer-spread + xhrData = getXhrData.apply(null, args); + if (typeof propsToMatch === 'undefined') { // Log if no propsToMatch given logMessage(source, `xhr( ${objectToString(xhrData)} )`, true); @@ -115,6 +118,22 @@ export function preventXHR(source, propsToMatch, customResponseText) { thisArg.shouldBePrevented = true; } + // Trap setRequestHeader of target xhr object to mimic request headers later; + // needed for getResponseHeader() and getAllResponseHeaders() methods + if (thisArg.shouldBePrevented) { + thisArg.collectedHeaders = []; + const setRequestHeaderWrapper = (target, thisArg, args) => { + // Collect headers + thisArg.collectedHeaders.push(args); + return Reflect.apply(target, thisArg, args); + }; + const setRequestHeaderHandler = { + apply: setRequestHeaderWrapper, + }; + // setRequestHeader() can only be called on xhr.open(), + // so we can safely proxy it here + thisArg.setRequestHeader = new Proxy(thisArg.setRequestHeader, setRequestHeaderHandler); + } return Reflect.apply(target, thisArg, args); }; @@ -124,57 +143,164 @@ export function preventXHR(source, propsToMatch, customResponseText) { } if (thisArg.responseType === 'blob') { - response = new Blob(); + modifiedResponse = new Blob(); } - if (thisArg.responseType === 'arraybuffer') { - response = new ArrayBuffer(); + modifiedResponse = new ArrayBuffer(); } if (customResponseText) { const randomText = generateRandomResponse(customResponseText); if (randomText) { - responseText = randomText; + modifiedResponseText = randomText; } else { - logMessage(source, `Invalid range: ${customResponseText}`); + logMessage(source, `Invalid randomize parameter: '${customResponseText}'`); } } - // Mock response object - Object.defineProperties(thisArg, { - readyState: { value: 4, writable: false }, - response: { value: response, writable: false }, - responseText: { value: responseText, writable: false }, - responseURL: { value: responseUrl, writable: false }, - responseXML: { value: '', writable: false }, - status: { value: 200, writable: false }, - statusText: { value: 'OK', writable: false }, + + /** + * Create separate XHR request with original request's input + * to be able to collect response data without triggering + * listeners on original XHR object + */ + const forgedRequest = new XMLHttpRequest(); + forgedRequest.addEventListener('readystatechange', () => { + if (forgedRequest.readyState !== 4) { + return; + } + + const { + readyState, + responseURL, + responseXML, + status, + statusText, + } = forgedRequest; + + // Mock response object + Object.defineProperties(thisArg, { + // original values + readyState: { value: readyState, writable: false }, + status: { value: status, writable: false }, + statusText: { value: statusText, writable: false }, + responseURL: { value: responseURL, writable: false }, + responseXML: { value: responseXML, writable: false }, + // modified values + response: { value: modifiedResponse, writable: false }, + responseText: { value: modifiedResponseText, writable: false }, + }); + + // Mock events + setTimeout(() => { + const stateEvent = new Event('readystatechange'); + thisArg.dispatchEvent(stateEvent); + + const loadEvent = new Event('load'); + thisArg.dispatchEvent(loadEvent); + + const loadEndEvent = new Event('loadend'); + thisArg.dispatchEvent(loadEndEvent); + }, 1); + + hit(source); }); - // Mock events - setTimeout(() => { - const stateEvent = new Event('readystatechange'); - thisArg.dispatchEvent(stateEvent); - const loadEvent = new Event('load'); - thisArg.dispatchEvent(loadEvent); + nativeOpen.apply(forgedRequest, [xhrData.method, xhrData.url]); + + // Mimic request headers before sending + // setRequestHeader can only be called on open request objects + thisArg.collectedHeaders.forEach((header) => { + const name = header[0]; + const value = header[1]; + forgedRequest.setRequestHeader(name, value); + }); - const loadEndEvent = new Event('loadend'); - thisArg.dispatchEvent(loadEndEvent); - }, 1); + try { + nativeSend.call(forgedRequest, args); + } catch { + return Reflect.apply(target, thisArg, args); + } - hit(source); return undefined; }; + /** + * Mock XMLHttpRequest.prototype.getHeaderHandler() to avoid adblocker detection. + * + * @param {Function} target XMLHttpRequest.prototype.getHeaderHandler(). + * @param {XMLHttpRequest} thisArg The request. + * @param {string[]} args Header name is passed as first argument. + * + * @returns {string|null} Header value or null if header is not set. + */ + const getHeaderWrapper = (target, thisArg, args) => { + if (!thisArg.collectedHeaders.length) { + return null; + } + // The search for the header name is case-insensitive + // https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/getResponseHeader + const searchHeaderName = args[0].toLowerCase(); + const matchedHeader = thisArg.collectedHeaders.find((header) => { + const headerName = header[0].toLowerCase(); + return headerName === searchHeaderName; + }); + return matchedHeader + ? matchedHeader[1] + : null; + }; + + /** + * Mock XMLHttpRequest.prototype.getAllResponseHeaders() to avoid adblocker detection. + * + * @param {Function} target XMLHttpRequest.prototype.getAllResponseHeaders(). + * @param {XMLHttpRequest} thisArg The request. + * + * @returns {string} All headers as a string. For no headers an empty string is returned. + */ + const getAllHeadersWrapper = (target, thisArg) => { + if (!thisArg.collectedHeaders.length) { + return ''; + } + const allHeadersStr = thisArg.collectedHeaders + .map((header) => { + /** + * TODO: array destructuring may be used here + * after the typescript implementation and bundling refactoring + * as now there is an error: slicedToArray is not defined + */ + const headerName = header[0]; + const headerValue = header[1]; + // In modern browsers, the header names are returned in all lower case, as per the latest spec. + // https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/getAllResponseHeaders + return `${headerName.toLowerCase()}: ${headerValue}`; + }) + .join('\r\n'); + return allHeadersStr; + }; + const openHandler = { apply: openWrapper, }; - const sendHandler = { apply: sendWrapper, }; + const getHeaderHandler = { + apply: getHeaderWrapper, + }; + const getAllHeadersHandler = { + apply: getAllHeadersWrapper, + }; XMLHttpRequest.prototype.open = new Proxy(XMLHttpRequest.prototype.open, openHandler); XMLHttpRequest.prototype.send = new Proxy(XMLHttpRequest.prototype.send, sendHandler); + XMLHttpRequest.prototype.getResponseHeader = new Proxy( + XMLHttpRequest.prototype.getResponseHeader, + getHeaderHandler, + ); + XMLHttpRequest.prototype.getAllResponseHeaders = new Proxy( + XMLHttpRequest.prototype.getAllResponseHeaders, + getAllHeadersHandler, + ); } preventXHR.names = [ @@ -187,10 +313,11 @@ preventXHR.names = [ preventXHR.injections = [ hit, - logMessage, objectToString, - matchRequestProps, generateRandomResponse, + matchRequestProps, + getXhrData, + logMessage, toRegExp, isValidStrPattern, escapeRegExp, diff --git a/src/scriptlets/trusted-replace-xhr-response.js b/src/scriptlets/trusted-replace-xhr-response.js index f9180061..b32d5132 100644 --- a/src/scriptlets/trusted-replace-xhr-response.js +++ b/src/scriptlets/trusted-replace-xhr-response.js @@ -171,13 +171,15 @@ export function trustedReplaceXhrResponse(source, pattern = '', replacement = '' // Manually put required values into target XHR object // as thisArg can't be redefined and XHR objects can't be (re)assigned or copied Object.defineProperties(thisArg, { - readyState: { value: readyState }, - response: { value: modifiedContent }, - responseText: { value: modifiedContent }, - responseURL: { value: responseURL }, - responseXML: { value: responseXML }, - status: { value: status }, - statusText: { value: statusText }, + // original values + readyState: { value: readyState, writable: false }, + responseURL: { value: responseURL, writable: false }, + responseXML: { value: responseXML, writable: false }, + status: { value: status, writable: false }, + statusText: { value: statusText, writable: false }, + // modified values + response: { value: modifiedContent, writable: false }, + responseText: { value: modifiedContent, writable: false }, }); // Mock events diff --git a/tests/scriptlets/prevent-xhr.test.js b/tests/scriptlets/prevent-xhr.test.js index a4bace06..8acb5438 100644 --- a/tests/scriptlets/prevent-xhr.test.js +++ b/tests/scriptlets/prevent-xhr.test.js @@ -57,7 +57,8 @@ if (isSupported) { if (input.includes('trace')) { return; } - const EXPECTED_LOG_STR = `${name}: xhr( method:"${METHOD}" url:"${URL}" )`; + // eslint-disable-next-line max-len + const EXPECTED_LOG_STR = `${name}: xhr( method:"${METHOD}" url:"${URL}" async:"undefined" user:"undefined" password:"undefined" )`; assert.ok(input.startsWith(EXPECTED_LOG_STR), 'console.hit input'); }; @@ -96,6 +97,56 @@ if (isSupported) { xhr.send(); }); + test('Empty arg to prevent all, check getResponseHeader() and getAllResponseHeaders() methods', async (assert) => { + const METHOD = 'GET'; + const URL = `${FETCH_OBJECTS_PATH}/test01.json`; + const MATCH_DATA = ['']; + const HEADER_NAME_1 = 'Test-Type'; + const HEADER_VALUE_1 = 'application/json'; + const HEADER_NAME_2 = 'Test-Length'; + const HEADER_VALUE_2 = '12345'; + const ABSENT_HEADER_NAME = 'Test-Absent'; + + runScriptlet(name, MATCH_DATA); + + const done = assert.async(); + + const xhr = new XMLHttpRequest(); + xhr.open(METHOD, URL); + xhr.setRequestHeader(HEADER_NAME_1, HEADER_VALUE_1); + xhr.setRequestHeader(HEADER_NAME_2, HEADER_VALUE_2); + + xhr.onload = () => { + assert.strictEqual(xhr.readyState, 4, 'Response done'); + assert.strictEqual(xhr.response, '', 'Response data mocked'); + assert.strictEqual(window.hit, 'FIRED', 'hit function fired'); + done(); + }; + xhr.send(); + + assert.strictEqual( + xhr.getResponseHeader(HEADER_NAME_1), + HEADER_VALUE_1, + 'getResponseHeader() is mocked, value 1 returned', + ); + assert.strictEqual( + xhr.getResponseHeader(HEADER_NAME_2), + HEADER_VALUE_2, + 'getResponseHeader() is mocked', + ); + assert.strictEqual( + xhr.getResponseHeader(ABSENT_HEADER_NAME), + null, + 'getResponseHeader() is mocked, null returned for non-existent header', + ); + + const expectedAllHeaders = [ + `${HEADER_NAME_1.toLowerCase()}: ${HEADER_VALUE_1}`, + `${HEADER_NAME_2.toLowerCase()}: ${HEADER_VALUE_2}`, + ].join('\r\n'); + assert.strictEqual(xhr.getAllResponseHeaders(), expectedAllHeaders, 'getAllResponseHeaders() is mocked'); + }); + test('Empty arg, prevent all, randomize response text', async (assert) => { const METHOD = 'GET'; const URL = `${FETCH_OBJECTS_PATH}/test01.json`; From b3a7f6c630ba5007aed0d914ecd0e3e83579a8d7 Mon Sep 17 00:00:00 2001 From: Atlassian Bamboo Date: Tue, 16 May 2023 18:30:00 +0300 Subject: [PATCH 12/12] skipci: Automatic increment build number --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 764a3d63..f43673bd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@adguard/scriptlets", - "version": "1.9.16", + "version": "1.9.17", "description": "AdGuard's JavaScript library of Scriptlets and Redirect resources", "scripts": { "build": "babel-node bundler.js",