Skip to content

Commit

Permalink
Merge branch 'master' into feature/AG-18849
Browse files Browse the repository at this point in the history
  • Loading branch information
slavaleleka committed Feb 8, 2024
2 parents 8f4bc9d + 7446aa3 commit 738d900
Show file tree
Hide file tree
Showing 7 changed files with 179 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -11,6 +11,7 @@ The format is based on [Keep a Changelog], and this project adheres to [Semantic

### Added

- `call-nothrow` scriptlet [#333](https://github.com/AdguardTeam/Scriptlets/issues/333)
- `spoof-css` scriptlet [#317](https://github.com/AdguardTeam/Scriptlets/issues/317)
- `trusted-set-attr` scriptlet [#281](https://github.com/AdguardTeam/Scriptlets/issues/281)
- Ability of `set-attr` to set an attribute value as a copy of another attribute value of the same element.
Expand Down
2 changes: 1 addition & 1 deletion package.json
@@ -1,6 +1,6 @@
{
"name": "@adguard/scriptlets",
"version": "1.9.109",
"version": "1.9.110",
"description": "AdGuard's JavaScript library of Scriptlets and Redirect resources",
"scripts": {
"build": "babel-node -x .js,.ts scripts/build.js",
Expand Down
1 change: 1 addition & 0 deletions scripts/compatibility-table.json
Expand Up @@ -201,6 +201,7 @@
"ubo": "href-sanitizer.js"
},
{
"adg": "call-nothrow",
"ubo": "call-nothrow.js"
},
{
Expand Down
102 changes: 102 additions & 0 deletions src/scriptlets/call-nothrow.js
@@ -0,0 +1,102 @@
import {
hit,
getPropertyInChain,
logMessage,
// following helpers are needed for helpers above
isEmptyObject,
} from '../helpers/index';

/* eslint-disable max-len */
/**
* @scriptlet call-nothrow
*
* @description
* Prevents an exception from being thrown and returns undefined when a specific function is called.
*
* Related UBO scriptlet:
* https://github.com/gorhill/uBlock/wiki/Resources-Library#call-nothrowjs-
*
* ### Syntax
*
* ```text
* example.org#%#//scriptlet('call-nothrow', functionName)
* ```
*
* - `functionName` — required, the name of the function to trap
*
* ### Examples
*
* 1. Prevents an exception from being thrown when `Object.defineProperty` is called:
*
* ```adblock
* example.org#%#//scriptlet('call-nothrow', 'Object.defineProperty')
* ```
*
* For instance, the following call normally throws an error, but the scriptlet catches it and returns undefined:
*
* ```javascript
* Object.defineProperty(window, 'foo', { value: true });
* Object.defineProperty(window, 'foo', { value: false });
* ```
*
* 2. Prevents an exception from being thrown when `JSON.parse` is called:
*
* ```adblock
* example.org#%#//scriptlet('call-nothrow', 'JSON.parse')
* ```
*
* For instance, the following call normally throws an error, but the scriptlet catches it and returns undefined:
*
* ```javascript
* JSON.parse('foo');
* ```
*
* @added unknown.
*/
/* eslint-enable max-len */
export function callNoThrow(source, functionName) {
if (!functionName) {
return;
}

const { base, prop } = getPropertyInChain(window, functionName);
if (!base || !prop || typeof base[prop] !== 'function') {
const message = `${functionName} is not a function`;
logMessage(source, message);
return;
}

const objectWrapper = (...args) => {
let result;
try {
result = Reflect.apply(...args);
} catch (e) {
const message = `Error calling ${functionName}: ${e.message}`;
logMessage(source, message);
}
hit(source);
return result;
};

const objectHandler = {
apply: objectWrapper,
};

base[prop] = new Proxy(base[prop], objectHandler);
}

callNoThrow.names = [
'call-nothrow',
// aliases are needed for matching the related scriptlet converted into our syntax
'call-nothrow.js',
'ubo-call-nothrow.js',
'ubo-call-nothrow',
];

callNoThrow.injections = [
hit,
getPropertyInChain,
logMessage,
// following helpers are needed for helpers above
isEmptyObject,
];
1 change: 1 addition & 0 deletions src/scriptlets/scriptlets-list.js
Expand Up @@ -63,3 +63,4 @@ export * from './evaldata-prune';
export * from './trusted-prune-inbound-object';
export * from './trusted-set-attr';
export * from './spoof-css';
export * from './call-nothrow';
72 changes: 72 additions & 0 deletions tests/scriptlets/call-nothrow.test.js
@@ -0,0 +1,72 @@
/* eslint-disable no-underscore-dangle, no-console */
import { runScriptlet, clearGlobalProps } from '../helpers';

const { test, module } = QUnit;
const name = 'call-nothrow';

const beforeEach = () => {
window.__debug = () => {
window.hit = 'FIRED';
};
};

const afterEach = () => {
clearGlobalProps('hit', '__debug');
};

module(name, { beforeEach, afterEach });

test('Checking if alias name works', (assert) => {
const adgParams = {
name,
engine: 'test',
verbose: true,
};
const uboParams = {
name: 'ubo-call-nothrow.js',
engine: 'test',
verbose: true,
};

const codeByAdgParams = window.scriptlets.invoke(adgParams);
const codeByUboParams = window.scriptlets.invoke(uboParams);

assert.strictEqual(codeByAdgParams, codeByUboParams, 'ubo name - ok');
});

test('call-nothrow - JSON.parse', (assert) => {
let testPassed;

runScriptlet(name, ['JSON.parse']);

// JSON.parse('foo') throws an error,
// so scriptlet should catch it and testPassed should be true
try {
JSON.parse('foo');
testPassed = true;
} catch (e) {
testPassed = false;
}
assert.strictEqual(testPassed, true, 'testPassed set to true');
assert.strictEqual(window.hit, 'FIRED', 'hit function fired');
});

test('call-nothrow - Object.defineProperty', (assert) => {
let testPassed;
const foo = {};
Object.defineProperty(foo, 'bar', { value: true });

runScriptlet(name, ['Object.defineProperty']);

// Redefining foo.bar should throw an error,
// so scriptlet should catch it and testPassed should be true
try {
Object.defineProperty(foo, 'bar', { value: false });
testPassed = true;
} catch (e) {
testPassed = false;
}
assert.strictEqual(testPassed, true, 'testPassed set to true');
assert.strictEqual(foo.bar, true, 'foo.bar set to true');
assert.strictEqual(window.hit, 'FIRED', 'hit function fired');
});
2 changes: 1 addition & 1 deletion wiki/compatibility-table.md
Expand Up @@ -61,7 +61,7 @@
| | alert-buster.js | |
| | golem.de.js (removed) | |
| | href-sanitizer.js | |
| | call-nothrow.js | |
| [call-nothrow](../wiki/about-scriptlets.md#call-nothrow) | call-nothrow.js | |
| | | abort-on-iframe-property-read |
| | | abort-on-iframe-property-write |
| | | freeze-element |
Expand Down

0 comments on commit 738d900

Please sign in to comment.