diff --git a/src/helpers/get-descriptor-addon.js b/src/helpers/get-descriptor-addon.js index 2740826f..f8fb9bb6 100644 --- a/src/helpers/get-descriptor-addon.js +++ b/src/helpers/get-descriptor-addon.js @@ -1,7 +1,9 @@ +import { randomId } from './random-id'; /** * Prevent infinite loops when trapping props that could be used by scriptlet's own helpers * Example: window.RegExp, that is used by matchStackTrace > toRegExp * + * https://github.com/AdguardTeam/Scriptlets/issues/251 * https://github.com/AdguardTeam/Scriptlets/issues/226 * https://github.com/AdguardTeam/Scriptlets/issues/232 * @@ -12,9 +14,21 @@ export function getDescriptorAddon() { isAbortingSuspended: false, isolateCallback(cb, ...args) { this.isAbortingSuspended = true; - const result = cb(...args); - this.isAbortingSuspended = false; - return result; + // try...catch is required in case if there are more than one inline scripts + // which should be aborted. + // so after the first successful abortion, `cb(...args);` will throw error, + // and we should not stop on that and continue to abort other scripts + try { + const result = cb(...args); + this.isAbortingSuspended = false; + return result; + } catch { + this.isAbortingSuspended = false; + const rid = randomId(); + // It's necessary to throw error + // otherwise script will be not aborted + throw new ReferenceError(rid); + } }, }; } diff --git a/src/redirects/googlesyndication-adsbygoogle.js b/src/redirects/googlesyndication-adsbygoogle.js index 326c01c2..d65b7243 100644 --- a/src/redirects/googlesyndication-adsbygoogle.js +++ b/src/redirects/googlesyndication-adsbygoogle.js @@ -32,7 +32,9 @@ export function GoogleSyndicationAdsByGoogle(source) { for (const key of Object.keys(arg)) { if (typeof arg[key] === 'function') { try { - arg[key].call(); + // https://github.com/AdguardTeam/Scriptlets/issues/252 + // argument "{}" is needed to fix issue with undefined argument + arg[key].call(this, {}); } catch { /* empty */ } diff --git a/tests/redirects/googlesyndication-adsbygoogle.test.js b/tests/redirects/googlesyndication-adsbygoogle.test.js index 0a10fcdf..72f6dc2f 100644 --- a/tests/redirects/googlesyndication-adsbygoogle.test.js +++ b/tests/redirects/googlesyndication-adsbygoogle.test.js @@ -69,8 +69,17 @@ test('Redirect testing', (assert) => { assert.strictEqual(window.adsbygoogle.length, undefined, 'adsbygoogle.length check'); assert.strictEqual(window.adsbygoogle.push.length, 1, 'push.length check'); - const pushCallback = () => { - assert.ok(true, 'callback was called'); + const pushCallback = (arg) => { + try { + // Test for https://github.com/AdguardTeam/Scriptlets/issues/252 + // If arg is not defined then error will be thrown + if (arg.whatever) { + arg.whatever = 1; + } + assert.ok(typeof arg !== 'undefined', 'arg is defined'); + } catch (error) { + assert.ok(false, 'something went wrong'); + } }; const pushArg = { test: 'test', diff --git a/tests/scriptlets/abort-current-inline-script.test.js b/tests/scriptlets/abort-current-inline-script.test.js index 05d16053..71199fe7 100644 --- a/tests/scriptlets/abort-current-inline-script.test.js +++ b/tests/scriptlets/abort-current-inline-script.test.js @@ -20,9 +20,9 @@ module(name, { beforeEach, afterEach }); const onError = (assert) => (message) => { const browserErrorMessage = 'Script error.'; - const nodePuppeteerErrorMessageRgx = /Reference error/g; + const nodePuppeteerErrorMessageRgx = /Reference error|ReferenceError/g; const checkResult = message === browserErrorMessage - || message.test(nodePuppeteerErrorMessageRgx); + || nodePuppeteerErrorMessageRgx.test(message); assert.ok(checkResult); }; @@ -246,3 +246,24 @@ test('Protected from infinite loop when prop is used in a helper', (assert) => { assert.strictEqual(window.hit, undefined, 'hit should NOT fire'); }); + +test('searches script by regexp - abort few inline scripts', (assert) => { + window.onerror = onError(assert); + window.shouldBeAborted = true; + window.shouldNotBeAborted = false; + const property = 'console.log'; + const shouldBeAborted = 'shouldBeAborted'; + const shouldNotBeAborted = 'shouldNotBeAborted'; + const search = '/test|abcd|1234|qwerty/'; + const scriptletArgs = [property, search]; + runScriptlet(name, scriptletArgs); + addAndRemoveInlineScript(`window.${property}('test'); window.${shouldBeAborted} = false;`); + addAndRemoveInlineScript(`window.${property}('abcd'); window.${shouldBeAborted} = false;`); + addAndRemoveInlineScript(`window.${property}('1234'); window.${shouldBeAborted} = false;`); + addAndRemoveInlineScript(`window.${property}('should not be aborted'); window.${shouldNotBeAborted} = true;`); + addAndRemoveInlineScript(`window.${property}('qwerty'); window.${shouldBeAborted} = false;`); + + assert.strictEqual(window.shouldBeAborted, true, 'initial value of shouldBeAborted has not changed'); + assert.strictEqual(window.shouldNotBeAborted, true, 'value of shouldBeAborted has been changed from false to true'); + assert.strictEqual(window.hit, 'FIRED', 'hit fired'); +});