Skip to content

Commit 22745b6

Browse files
Web interventions: add scriptlet feature (#1742)
* Adguard sizing * Move to using mode of scriptlets * Ensure submodule is always checked out * Namespace attrs * Add verbose logging for now * Fix up replace node text * Add more scriptlets * Make a default object when attrs are missing * adjust list of scriptlets to meet popunder needs * add breakage flag * don't need local var for debug flag * fix typo in scriptlets.js and populate source. add exlusion rules for scriptlet submodule. * fix typo in package-lock * remove unnecessary scriptlet dependency from package.json, update package-lock.json * Update README.md * add dependabot submodule updates * temp ignore tsc in scriptlets.js * temp ignore scriptlets in eslint * change eslint ignore * try adding ignores to other eslint file * code style fixes * add scriptlets to other features * add Scriptlets to stylelint ignore * fix failing feature order unit test * set checkout-submodules to not fetch latest --------- Co-authored-by: Jonathan Kingston <[email protected]>
1 parent 36b184f commit 22745b6

File tree

12 files changed

+109
-3
lines changed

12 files changed

+109
-3
lines changed

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "injected/src/features/Scriptlets"]
2+
path = injected/src/features/Scriptlets
3+
url = https://github.com/AdguardTeam/Scriptlets.git

.prettierignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ docs/**/*
33
injected/src/types
44
special-pages/pages/**/types
55
injected/integration-test/extension/contentScope.js
6+
injected/src/features/Scriptlets
67
**/*.json
78
**/*.md
89
**/*.html

.stylelintrc.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"extends": ["stylelint-config-standard"],
33
"plugins": ["stylelint-csstree-validator"],
4-
"ignoreFiles": ["build/**/*.css", "Sources/**/*.css", "docs/**/*.css", "special-pages/pages/**/*/dist/*.css"],
4+
"ignoreFiles": ["build/**/*.css", "Sources/**/*.css", "docs/**/*.css", "special-pages/pages/**/*/dist/*.css", "injected/src/features/Scriptlets/**/*"],
55
"rules": {
66
"csstree/validator": {
77
"ignoreProperties": ["text-wrap", "view-transition-name"]

build-output.eslint.config.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
// https://github.com/eslint/eslint/discussions/18806#discussioncomment-10848750
33

44
export default [
5+
{
6+
ignores: ['injected/src/features/Scriptlets', 'injected/src/features/scriptlets.js'],
7+
},
58
{
69
languageOptions: {
710
ecmaVersion: 'latest',

eslint.config.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ export default tseslint.config(
2323
'playwright-report',
2424
'test-results',
2525
'injected/src/types',
26+
'injected/src/features/Scriptlets',
27+
'injected/src/features/scriptlets.js',
2628
'.idea',
2729
],
2830
},

injected/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,3 +196,7 @@ This will create platform specific code within the `build` folder (that is not c
196196
```shell
197197
npm run build
198198
```
199+
200+
#### Third-Party Libraries
201+
We make use of the following submodules:
202+
- [Adguard Scriptlets](https://github.com/AdguardTeam/Scriptlets)

injected/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
"scripts": {
44
"postinstall": "npm run copy-sjcl",
55
"copy-sjcl": "node scripts/generateSJCL.js",
6-
"build": "npm run build-types && npm run build-locales && npm run bundle-trackers && npm run bundle-entry-points",
6+
"checkout-submodules": "git submodule update --init --recursive --no-fetch",
7+
"build": "npm run checkout-submodules && npm run build-types && npm run build-locales && npm run bundle-trackers && npm run bundle-entry-points",
78
"bundle-config": "node scripts/bundleConfig.mjs",
89
"bundle-entry-points": "node scripts/entry-points.js",
910
"build-chrome-mv3": "node scripts/entry-points.js",

injected/src/features.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,13 @@ const otherFeatures = /** @type {const} */ ([
2828
'breakageReporting',
2929
'autofillPasswordImport',
3030
'favicon',
31+
'scriptlets',
3132
]);
3233

3334
/** @typedef {baseFeatures[number]|otherFeatures[number]} FeatureName */
3435
/** @type {Record<string, FeatureName[]>} */
3536
export const platformSupport = {
36-
apple: ['webCompat', 'duckPlayerNative', ...baseFeatures],
37+
apple: ['webCompat', 'duckPlayerNative', 'scriptlets', ...baseFeatures],
3738
'apple-isolated': [
3839
'duckPlayer',
3940
'duckPlayerNative',

injected/src/features/Scriptlets

Submodule Scriptlets added at 70ec3c0

injected/src/features/scriptlets.js

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import ContentFeature from '../content-feature.js';
2+
import { isBeingFramed } from '../utils.js';
3+
import { setCookie } from './Scriptlets/src/scriptlets/set-cookie.js';
4+
import { trustedSetCookie } from './Scriptlets/src/scriptlets/trusted-set-cookie.js';
5+
import { setCookieReload } from './Scriptlets/src/scriptlets/set-cookie-reload.js';
6+
import { removeCookie } from './Scriptlets/src/scriptlets/remove-cookie.js';
7+
import { setConstant } from './Scriptlets/src/scriptlets/set-constant.js';
8+
import { setLocalStorageItem } from './Scriptlets/src/scriptlets/set-local-storage-item.js';
9+
import { abortCurrentInlineScript } from './Scriptlets/src/scriptlets/abort-current-inline-script.js';
10+
import { abortOnPropertyRead } from './Scriptlets/src/scriptlets/abort-on-property-read.js';
11+
import { abortOnPropertyWrite } from './Scriptlets/src/scriptlets/abort-on-property-write.js';
12+
import { preventAddEventListener } from './Scriptlets/src/scriptlets/prevent-addEventListener.js';
13+
import { preventWindowOpen } from './Scriptlets/src/scriptlets/prevent-window-open.js';
14+
import { preventSetTimeout } from './Scriptlets/src/scriptlets/prevent-setTimeout.js';
15+
import { removeNodeText } from './Scriptlets/src/scriptlets/remove-node-text.js';
16+
import { preventFetch } from './Scriptlets/src/scriptlets/prevent-fetch.js';
17+
18+
export class Scriptlets extends ContentFeature {
19+
init() {
20+
if (isBeingFramed()) {
21+
return;
22+
}
23+
/* @type {import('./Scriptlets/src/scriptlets/scriptlets.ts').Source} */
24+
const source = {
25+
verbose: false,
26+
};
27+
28+
const scriptlets = this.getFeatureSetting('scriptlets');
29+
for (const scriptlet of scriptlets) {
30+
source.name = scriptlet.name;
31+
source.args = Object.values(scriptlet.attrs);
32+
this.runScriptlet(scriptlet, source);
33+
}
34+
}
35+
36+
runScriptlet(scriptlet, source) {
37+
const attrs = scriptlet.attrs || {};
38+
39+
// add debug flag to site breakage reports
40+
this.addDebugFlag();
41+
42+
if (scriptlet.name === 'setCookie') {
43+
setCookie(source, attrs.name, attrs.value, attrs.path, attrs.domain);
44+
}
45+
if (scriptlet.name === 'trustedSetCookie') {
46+
trustedSetCookie(source, attrs.name, attrs.value, attrs.path, attrs.domain);
47+
}
48+
if (scriptlet.name === 'setCookieReload') {
49+
setCookieReload(source, attrs.name, attrs.value, attrs.path, attrs.domain);
50+
}
51+
if (scriptlet.name === 'removeCookie') {
52+
removeCookie(source, attrs.match);
53+
}
54+
if (scriptlet.name === 'setConstant') {
55+
setConstant(source, attrs.property, attrs.value, attrs.stack, attrs.valueWrapper, attrs.setProxyTrap);
56+
}
57+
if (scriptlet.name === 'setLocalStorageItem') {
58+
setLocalStorageItem(source, attrs.key, attrs.value);
59+
}
60+
if (scriptlet.name === 'abortCurrentInlineScript') {
61+
abortCurrentInlineScript(source, attrs.property, attrs.search);
62+
}
63+
if (scriptlet.name === 'abortOnPropertyRead') {
64+
abortOnPropertyRead(source, attrs.property);
65+
}
66+
if (scriptlet.name === 'abortOnPropertyWrite') {
67+
abortOnPropertyWrite(source, attrs.property);
68+
}
69+
if (scriptlet.name === 'preventAddEventListener') {
70+
preventAddEventListener(source, attrs.typeSearch, attrs.listenerSearch, attrs.additionalArgName, attrs.additionalArgValue);
71+
}
72+
if (scriptlet.name === 'preventWindowOpen') {
73+
preventWindowOpen(source, attrs.match, attrs.delay, attrs.replacement);
74+
}
75+
if (scriptlet.name === 'preventSetTimeout') {
76+
preventSetTimeout(source, attrs.matchCallback, attrs.matchDelay);
77+
}
78+
if (scriptlet.name === 'removeNodeText') {
79+
removeNodeText(source, attrs.nodeName, attrs.textMatch, attrs.parentSelector);
80+
}
81+
if (scriptlet.name === 'preventFetch') {
82+
preventFetch(source, attrs.propsToMatch, attrs.responseBody, attrs.responseType);
83+
}
84+
}
85+
}
86+
87+
export default Scriptlets;

0 commit comments

Comments
 (0)