Skip to content

Commit

Permalink
resolve conflicts
Browse files Browse the repository at this point in the history
  • Loading branch information
stanislav-atr committed Nov 17, 2022
2 parents cb86ba7 + 48bd360 commit fa95a0b
Show file tree
Hide file tree
Showing 9 changed files with 195 additions and 5 deletions.
2 changes: 1 addition & 1 deletion src/helpers/get-descriptor-addon.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ export function getDescriptorAddon() {
this.isAbortingSuspended = false;
return result;
} catch {
this.isAbortingSuspended = false;
const rid = randomId();
this.isAbortingSuspended = false;
// It's necessary to throw error
// otherwise script will be not aborted
throw new ReferenceError(rid);
Expand Down
2 changes: 2 additions & 0 deletions src/helpers/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/**
* This file must export all used dependencies
*/

export * from './add-event-listener-utils';
export * from './adjust-set-utils';
export * from './array-utils';
Expand All @@ -9,6 +10,7 @@ export * from './log-utils';
export * from './noop-utils';
export * from './number-utils';
export * from './object-utils';
export * from './script-source-utils';
export * from './open-shadow-dom-utils';
export * from './prevent-utils';
export * from './prevent-window-open-utils';
Expand Down
5 changes: 5 additions & 0 deletions src/helpers/match-stack.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { toRegExp } from './string-utils';
import { shouldAbortInlineOrInjectedScript } from './script-source-utils';
import { getNativeRegexpTest } from './regexp-utils';

/**
Expand All @@ -13,6 +14,10 @@ export const matchStackTrace = (stackMatch, stackTrace) => {
return true;
}

if (shouldAbortInlineOrInjectedScript(stackMatch, stackTrace)) {
return true;
}

const stackRegexp = toRegExp(stackMatch);
const refinedStackTrace = stackTrace
.split('\n')
Expand Down
73 changes: 73 additions & 0 deletions src/helpers/script-source-utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
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
* https://github.com/AdguardTeam/Scriptlets/issues/201
* @param {string|undefined} stackMatch - input stack value to match
* @param {string} stackTrace - script error stack trace
* @returns {boolean}
*/
export const shouldAbortInlineOrInjectedScript = (stackMatch, stackTrace) => {
const INLINE_SCRIPT_STRING = 'inlineScript';
const INJECTED_SCRIPT_STRING = 'injectedScript';
const INJECTED_SCRIPT_MARKER = '<anonymous>';
const isInlineScript = (stackMatch) => stackMatch.indexOf(INLINE_SCRIPT_STRING) > -1;
const isInjectedScript = (stackMatch) => stackMatch.indexOf(INJECTED_SCRIPT_STRING) > -1;

if (!(isInlineScript(stackMatch) || isInjectedScript(stackMatch))) {
return false;
}

let documentURL = window.location.href;
const pos = documentURL.indexOf('#');
// Remove URL hash
// in Chrome, URL in stackTrace doesn't contain hash
// so, it's necessary to remove it, otherwise location.href
// will not match with location from stackTrace
if (pos !== -1) {
documentURL = documentURL.slice(0, pos);
}
const stackSteps = stackTrace.split('\n').slice(2).map((line) => line.trim());
const stackLines = stackSteps.map((line) => {
let stack;
// Get stack trace URL
// in Firefox stack trace looks like this: advanceTaskQueue@http://127.0.0.1:8080/scriptlets/tests/dist/qunit.js:1834:20
// in Chrome like this: at Assert.throws (http://127.0.0.1:8080/scriptlets/tests/dist/qunit.js:3178:16)
// so, first group "(.*?@)" is required for Firefox, second group contains URL
const getStackTraceURL = /(.*?@)?(\S+)(:\d+):\d+\)?$/.exec(line);
if (getStackTraceURL) {
let stackURL = getStackTraceURL[2];
if (startsWith(stackURL, '(')) {
stackURL = stackURL.slice(1);
}
if (startsWith(stackURL, 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')) {
stackFunction = stackFunction.slice(2).trim();
}
stack = `${stackFunction} ${stackURL}`.trim();
} else {
stack = stackURL;
}
} else {
stack = line;
}
return stack;
});
if (stackLines) {
for (let index = 0; index < stackLines.length; index += 1) {
if (isInlineScript(stackMatch) && documentURL === stackLines[index]) {
return true;
}
if (isInjectedScript(stackMatch)
&& startsWith(stackLines[index], INJECTED_SCRIPT_STRING)) {
return true;
}
}
}
return false;
};
15 changes: 14 additions & 1 deletion src/scriptlets/abort-on-stack-trace.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ import {
matchStackTrace,
getDescriptorAddon,
logVerbose,
shouldAbortInlineOrInjectedScript,
// following helpers are needed for helpers above
escapeRegExp,
toRegExp,
isEmptyObject,
getNativeRegexpTest,
startsWith,
} from '../helpers/index';

/* eslint-disable max-len */
Expand All @@ -32,6 +34,9 @@ import {
*
* - `property` - required, path to a property. The property must be attached to window.
* - `stack` - required, string that must match the current function call stack trace.
* - values to abort inline or injected script, accordingly:
* - `inlineScript`
* - `injectedScript`
*
* **Examples**
* ```
Expand All @@ -44,6 +49,12 @@ import {
* ! Aborts script when stack trace matches with any of these parameters
* example.org#%#//scriptlet('abort-on-stack-trace', 'Ya', 'yandexFuncName')
* example.org#%#//scriptlet('abort-on-stack-trace', 'Ya', 'yandexScriptName')
*
* ! Aborts script when it tries to access `window.Ya` and it's an inline script
* example.org#%#//scriptlet('abort-on-stack-trace', 'Ya', 'inlineScript')
*
* ! Aborts script when it tries to access `window.Ya` and it's an injected script
* example.org#%#//scriptlet('abort-on-stack-trace', 'Ya', 'injectedScript')
* ```
*/
/* eslint-enable max-len */
Expand Down Expand Up @@ -76,7 +87,7 @@ export function abortOnStackTrace(source, property, stack) {
return;
}

if (!isValidStrPattern(stack)) {
if (!stack.match(/^(inlineScript|injectedScript)$/) && !isValidStrPattern(stack)) {
logVerbose(`Invalid parameter: ${stack}`, source.verbose);
return;
}
Expand Down Expand Up @@ -142,4 +153,6 @@ abortOnStackTrace.injections = [
toRegExp,
isEmptyObject,
getNativeRegexpTest,
startsWith,
shouldAbortInlineOrInjectedScript,
];
7 changes: 6 additions & 1 deletion src/scriptlets/log-on-stack-trace.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,15 @@ export function logOnStacktrace(source, property) {
let funcFullPath;
/* eslint-disable-next-line no-useless-escape */
const reg = /\(([^\)]+)\)/;
const regFirefox = /(.*?@)(\S+)(:\d+):\d+\)?$/;
if (line.match(reg)) {
funcName = line.split(' ').slice(0, -1).join(' ');
/* eslint-disable-next-line prefer-destructuring, no-useless-escape */
/* eslint-disable-next-line prefer-destructuring */
funcFullPath = line.match(reg)[1];
} else if (line.match(regFirefox)) {
funcName = line.split('@').slice(0, -1).join(' ');
/* eslint-disable-next-line prefer-destructuring */
funcFullPath = line.match(regFirefox)[2];
} else {
// For when func name is not available
funcName = 'function name is not available';
Expand Down
6 changes: 4 additions & 2 deletions tests/helpers/match-stack.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ const name = 'scriptlets-redirects helpers';
module(name);

test('Test matchStackTrace for working with getNativeRegexpTest helper', async (assert) => {
const match = matchStackTrace('stack', new Error().stack);
const notMatched = matchStackTrace('not_present', new Error().stack);
const matched = matchStackTrace('stack', new Error().stack);

assert.ok(!match);
assert.true(matched);
assert.false(notMatched);
});
71 changes: 71 additions & 0 deletions tests/scriptlets/abort-on-stack-trace.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,77 @@ test('Protected from infinite loop when prop is used in a helper', (assert) => {
assert.strictEqual(window.hit, undefined, 'hit should NOT fire');
});

test('abort Math.random, injected script', (assert) => {
const property = 'Math.random';
const stackMatch = 'injectedScript';
const scriptletArgs = [property, stackMatch];
runScriptlet(name, scriptletArgs);

window.testPassed = false;
const scriptElement = document.createElement('script');
scriptElement.type = 'text/javascript';
// set window.testPassed to true if script is aborted
scriptElement.innerText = 'try { Math.random(); } catch(error) { window.testPassed = true; console.log("Script aborted:", error); }';
document.body.appendChild(scriptElement);
scriptElement.parentNode.removeChild(scriptElement);

assert.strictEqual(window.testPassed, true, 'testPassed set to true, script has been aborted');
assert.strictEqual(window.hit, 'FIRED', 'hit fired');
});

test('abort String.fromCharCode, inline script', (assert) => {
const property = 'String.fromCharCode';
const stackMatch = 'inlineScript';
const scriptletArgs = [property, stackMatch];
runScriptlet(name, scriptletArgs);
assert.throws(
() => String.fromCharCode(65),
/ReferenceError/,
'Reference error thrown when trying to access property String.fromCharCode',
);
assert.strictEqual(window.hit, 'FIRED', 'hit fired');
});

test('do NOT abort Math.round, test for injected script', (assert) => {
const property = 'Math.round';
const stackMatch = 'injectedScript';
const scriptletArgs = [property, stackMatch];
runScriptlet(name, scriptletArgs);

let testPassed = false;
try {
const testNumber = Math.round(1.5);
// eslint-disable-next-line no-console
console.log('Number:', testNumber);
testPassed = true;
} catch (error) {
// eslint-disable-next-line no-console
console.log('Something went wrong', error);
}
assert.strictEqual(testPassed, true, 'testPassed set to true, script has been aborted');
assert.strictEqual(window.hit, undefined, 'hit should NOT fire');
});

test('abort Math.max in injected script, but not abort inline script', (assert) => {
const property = 'Math.max';
const stackMatch = 'injectedScript';
const scriptletArgs = [property, stackMatch];
runScriptlet(name, scriptletArgs);

window.testPassed = false;
const number = Math.max(20, 10);
if (number) {
const scriptElement = document.createElement('script');
scriptElement.type = 'text/javascript';
// set window.testPassed to true if script is aborted
scriptElement.innerText = 'try { debugger; Math.max(10, 20); } catch(error) { window.testPassed = true; console.log("Script aborted:", error); }';
document.body.appendChild(scriptElement);
scriptElement.parentNode.removeChild(scriptElement);
}
assert.strictEqual(window.testPassed, true, 'testPassed set to true, script has been aborted');
assert.strictEqual(window.hit, 'FIRED', 'hit fired');
});

test('abort RegExp, matches stack', (assert) => {
const property = 'RegExp';
const stackMatch = 'abort-on-stack';
Expand Down
19 changes: 19 additions & 0 deletions tests/scriptlets/log-on-stack-trace.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const { test, module } = QUnit;
const name = 'log-on-stack-trace';
const PROPERTY = 'testMe';
const nativeConsole = console.log;
const tableConsole = console.table;

const changingProps = [PROPERTY, 'hit', '__debug'];

Expand All @@ -17,6 +18,7 @@ const beforeEach = () => {
const afterEach = () => {
clearGlobalProps(...changingProps);
console.log = nativeConsole;
console.table = tableConsole;
};

module(name, { beforeEach, afterEach });
Expand Down Expand Up @@ -69,6 +71,23 @@ test('logs specific message', (assert) => {
assert.strictEqual(window.hit, 'FIRED', 'hit fired');
});

test('check if message is not empty', (assert) => {
const scriptletArgs = [PROPERTY];
const setProp = (prop) => {
window[prop] = 'init';
};
runScriptlet(name, scriptletArgs);

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');
};
setProp(PROPERTY);

assert.strictEqual(window.hit, 'FIRED', 'hit fired');
});

test('works with an empty object in chain', (assert) => {
const PROPERTY = 'window.aaa.bbb';
const scriptletArgs = [PROPERTY];
Expand Down

0 comments on commit fa95a0b

Please sign in to comment.