Skip to content

Commit

Permalink
Merge branch 'feature/md-lint' into fix/md-lint-errors
Browse files Browse the repository at this point in the history
  • Loading branch information
slavaleleka committed May 24, 2023
2 parents ccf22c0 + 9b8651a commit b14a3a0
Show file tree
Hide file tree
Showing 10 changed files with 358 additions and 22 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- ability for `prevent-element-src-loading` scriptlet to prevent inline `onerror` and match `link` tag [#276](https://github.com/AdguardTeam/Scriptlets/issues/276)
- new special value modifiers for `set-constant` [#316](https://github.com/AdguardTeam/Scriptlets/issues/316)

### Changed

- `trusted-set-cookie` and `trusted-set-cookie-reload` scriptlets to not encode cookie name and value
Expand All @@ -18,6 +23,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed

- issue with `updateTargetingFromMap()` method
in `googletagservices-gpt` redirect [#293](https://github.com/AdguardTeam/Scriptlets/issues/293)
- 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
Expand Down
2 changes: 1 addition & 1 deletion bamboo-specs/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ plan:
key: SCRIPTLETSBUILD
name: scriptlets - build
variables:
dockerContainer: adguard/puppeteer-runner:8.0--1
dockerContainer: adguard/puppeteer-runner:18.2--1

stages:
- Build:
Expand Down
2 changes: 1 addition & 1 deletion bamboo-specs/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ plan:
key: SCRIPTLETSTEST
name: scriptlets - test new
variables:
dockerPuppeteer: adguard/puppeteer-runner:8.0--1
dockerPuppeteer: adguard/puppeteer-runner:18.2--1

stages:
- Build:
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@adguard/scriptlets",
"version": "1.9.17",
"version": "1.9.22",
"description": "AdGuard's JavaScript library of Scriptlets and Redirect resources",
"scripts": {
"build": "babel-node bundler.js",
Expand Down
11 changes: 6 additions & 5 deletions src/redirects/googletagservices-gpt.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export function GoogleTagServicesGpt(source) {
// https://github.com/AdguardTeam/Scriptlets/issues/259
f.setAttribute('data-load-complete', true);
f.setAttribute('data-google-container-id', true);
f.setAttribute('sandbox', true);
f.setAttribute('sandbox', '');
node.appendChild(f);
}
};
Expand Down Expand Up @@ -143,7 +143,7 @@ export function GoogleTagServicesGpt(source) {
return [v];
}
try {
return [Array.prototype.flat.call(v)[0]];
return Array.prototype.flat.call(v);
} catch {
// do nothing
}
Expand All @@ -152,9 +152,10 @@ export function GoogleTagServicesGpt(source) {

const updateTargeting = (targeting, map) => {
if (typeof map === 'object') {
const entries = Object.entries(map || {});
for (const [k, v] of entries) {
targeting.set(k, getTargetingValue(v));
for (const key in map) {
if (Object.prototype.hasOwnProperty.call(map, key)) {
targeting.set(key, getTargetingValue(map[key]));
}
}
}
};
Expand Down
28 changes: 27 additions & 1 deletion src/scriptlets/prevent-element-src-loading.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
* - `script`
* - `img`
* - `iframe`
* - `link`
* - `match` — required, string or regular expression for matching the element's URL;
*
* **Examples**
Expand All @@ -45,6 +46,8 @@ export function preventElementSrcLoading(source, tagName, match) {
img: 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==',
// Empty h1 tag
iframe: 'data:text/html;base64, PGRpdj48L2Rpdj4=',
// Empty data
link: 'data:text/plain;base64,',
};

let instance;
Expand All @@ -54,6 +57,8 @@ export function preventElementSrcLoading(source, tagName, match) {
instance = HTMLImageElement;
} else if (tagName === 'iframe') {
instance = HTMLIFrameElement;
} else if (tagName === 'link') {
instance = HTMLLinkElement;
} else {
return;
}
Expand All @@ -74,7 +79,7 @@ export function preventElementSrcLoading(source, tagName, match) {
});
}

const SOURCE_PROPERTY_NAME = 'src';
const SOURCE_PROPERTY_NAME = tagName === 'link' ? 'href' : 'src';
const ONERROR_PROPERTY_NAME = 'onerror';
const searchRegexp = toRegExp(match);

Expand Down Expand Up @@ -194,6 +199,27 @@ export function preventElementSrcLoading(source, tagName, match) {
};
// eslint-disable-next-line max-len
EventTarget.prototype.addEventListener = new Proxy(EventTarget.prototype.addEventListener, addEventListenerHandler);

const preventInlineOnerror = (tagName, src) => {
window.addEventListener('error', (event) => {
if (
!event.target
|| !event.target.nodeName
|| event.target.nodeName.toLowerCase() !== tagName
|| !event.target.src
|| !src.test(event.target.src)
) {
return;
}
hit(source);
if (typeof event.target.onload === 'function') {
event.target.onerror = event.target.onload;
return;
}
event.target.onerror = noopFunc;
}, true);
};
preventInlineOnerror(tagName, searchRegexp);
}

preventElementSrcLoading.names = [
Expand Down
96 changes: 88 additions & 8 deletions src/scriptlets/set-constant.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
hit,
logMessage,
getNumberFromString,
noopArray,
noopObject,
noopCallbackFunc,
Expand All @@ -11,15 +12,15 @@ import {
noopPromiseReject,
noopPromiseResolve,
getPropertyInChain,
setPropertyAccess,
toRegExp,
matchStackTrace,
nativeIsNaN,
isEmptyObject,
getNativeRegexpTest,
// following helpers should be imported and injected
// because they are used by helpers above
shouldAbortInlineOrInjectedScript,
getNativeRegexpTest,
setPropertyAccess,
toRegExp,
} from '../helpers/index';

/* eslint-disable max-len */
Expand Down Expand Up @@ -65,8 +66,13 @@ import {
* - `-1` — number value `-1`
* - `yes`
* - `no`
* - `stack` — optional, string or regular expression that must match the current function call stack trace;
* - `stack` — string or regular expression that must match the current function call stack trace, defaults to matching every call;
* if regular expression is invalid it will be skipped
* - `valueWrapper` – optional, string to modify a value to be set. Possible wrappers:
* - `asFunction` – function returning value
* - `asCallback` – function returning callback, that would return value
* - `asResolved` – Promise that would resolve with value
* - `asRejected` – Promise that would reject with value
*
* **Examples**
* ```
Expand All @@ -91,10 +97,57 @@ import {
* ✔ document.third() === true // if the condition described above is met
* ```
*
* ```
* ! Any call to `document.fourth()` will return `yes`
* example.org#%#//scriptlet('set-constant', 'document.fourth', 'yes', '', 'asFunction')
*
* ✔ document.fourth() === 'yes'
* ```
*
* ```
* ! Any call to `document.fifth()` will return `yes`
* example.org#%#//scriptlet('set-constant', 'document.fifth', '42', '', 'asRejected')
*
* ✔ document.fifth.catch((reason) => reason === 42) // promise rejects with specified number
* ```
*
* @added v1.0.4.
*/
/* eslint-enable max-len */
export function setConstant(source, property, value, stack) {
export function setConstant(source, property, value, stack = '', valueWrapper = '') {
const uboAliases = [
'set-constant.js',
'ubo-set-constant.js',
'set.js',
'ubo-set.js',
'ubo-set-constant',
'ubo-set',
];

/**
* UBO set-constant analog has it's own args sequence:
* (property, value, defer | wrapper)
* 'defer' – a stringified number, which defines execution time, or
* 'wrapper' - string which defines value wrapper name
*
* joysound.com##+js(set, document.body.oncopy, null, 3)
* kompetent.de##+js(set, Object.keys, 42, asFunction)
*/
if (uboAliases.includes(source.name)) {
/**
* Check that third argument was intended as 'valueWrapper' argument,
* by excluding 'defer' single digits case, and move it to 'valueWrapper'
*/
if (stack.length !== 1 && !getNumberFromString(stack)) {
valueWrapper = stack;
}
/**
* ubo doesn't support 'stack', while adg doesn't support 'defer'
* that goes in the same spot, so we discard it
*/
stack = undefined;
}

if (!property
|| !matchStackTrace(stack, new Error().stack)) {
return;
Expand Down Expand Up @@ -150,6 +203,32 @@ export function setConstant(source, property, value, stack) {
return;
}

const valueWrapperNames = [
'asFunction',
'asCallback',
'asResolved',
'asRejected',
];

if (valueWrapperNames.includes(valueWrapper)) {
const valueWrappersMap = {
asFunction(v) {
return () => v;
},
asCallback(v) {
return () => (() => v);
},
asResolved(v) {
return Promise.resolve(v);
},
asRejected(v) {
return Promise.reject(v);
},
};

constantValue = valueWrappersMap[valueWrapper](constantValue);
}

let canceled = false;
const mustCancel = (value) => {
if (canceled) {
Expand Down Expand Up @@ -313,6 +392,7 @@ setConstant.names = [
setConstant.injections = [
hit,
logMessage,
getNumberFromString,
noopArray,
noopObject,
noopFunc,
Expand All @@ -323,13 +403,13 @@ setConstant.injections = [
noopPromiseReject,
noopPromiseResolve,
getPropertyInChain,
setPropertyAccess,
toRegExp,
matchStackTrace,
nativeIsNaN,
isEmptyObject,
getNativeRegexpTest,
// following helpers should be imported and injected
// because they are used by helpers above
shouldAbortInlineOrInjectedScript,
getNativeRegexpTest,
setPropertyAccess,
toRegExp,
];
34 changes: 33 additions & 1 deletion tests/redirects/googletagservices-gpt.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,39 @@ test('Test recreateIframeForSlot', (assert) => {
// https://github.com/AdguardTeam/Scriptlets/issues/259
assert.ok(iframe.getAttribute('data-load-complete'), 'attr was mocked');
assert.ok(iframe.getAttribute('data-google-container-id'), 'attr was mocked');
assert.ok(iframe.getAttribute('sandbox'), 'attr was mocked');
assert.strictEqual(iframe.getAttribute('sandbox'), '', 'attr was mocked');

assert.strictEqual(window.hit, 'FIRED', 'hit function was executed');
});

test('Test updateTargetingFromMap', (assert) => {
runRedirect(name);

assert.ok(window.googletag, 'window.googletag have been created');
assert.strictEqual(typeof window.googletag.defineSlot(), 'object', 'Slot has been mocked');

const slot = window.googletag.defineSlot('/1234567/sports', [160, 600], 'div');

// https://github.com/AdguardTeam/Scriptlets/issues/293
slot.updateTargetingFromMap({
color: 'red',
interests: ['sports', 'music', 'movies'],
});

assert.strictEqual(
slot.getTargeting('color')[0],
'red',
'.getTargeting() has been mocked - color[0] = red.',
);
assert.strictEqual(
slot.getTargeting('interests')[0],
'sports',
'.getTargeting() has been mocked - interests[0] = sports.',
);
assert.strictEqual(
slot.getTargeting('interests')[1],
'music',
'.getTargeting() has been mocked - interests[1] = music.',
);
assert.strictEqual(window.hit, 'FIRED', 'hit function was executed');
});
Loading

0 comments on commit b14a3a0

Please sign in to comment.