Skip to content

Commit

Permalink
build separate wiki page for trusted scriptlets
Browse files Browse the repository at this point in the history
  • Loading branch information
stanislav-atr committed Nov 9, 2022
1 parent c4a87c6 commit 69dc7c0
Show file tree
Hide file tree
Showing 5 changed files with 290 additions and 4 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ Allowed sources of trusted scriptlets are:
* custom filters which were installed with `trusted` option checked,
* user rules.

**[Trusted scriptlets list](https://github.com/AdguardTeam/Scriptlets/blob/master/wiki/about-trusted-scriptlets.md#trusted-scriptlets)**


## Redirect resources

Expand Down
38 changes: 36 additions & 2 deletions scripts/build-docs.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ const { getDataFromFiles } = require('./helpers');
const {
WIKI_DIR_PATH,
scriptletsFilenames,
trustedScriptletsFilenames,
redirectsFilenames,
SCRIPTLETS_SRC_RELATIVE_DIR_PATH,
REDIRECTS_SRC_RELATIVE_DIR_PATH,
TRUSTED_SCRIPTLETS_TYPE,
} = require('./constants');

const STATIC_REDIRECTS_FILENAME = 'static-redirects.yml';
Expand All @@ -28,10 +30,16 @@ const blockingRedirectsPath = path.resolve(
);

const ABOUT_SCRIPTLETS_FILENAME = 'about-scriptlets.md';
const ABOUT_TRUSTED_SCRIPTLETS_FILENAME = 'about-trusted-scriptlets.md';
const ABOUT_REDIRECTS_FILENAME = 'about-redirects.md';

const aboutScriptletsPath = path.resolve(__dirname, WIKI_DIR_PATH, ABOUT_SCRIPTLETS_FILENAME);
const aboutRedirectsPath = path.resolve(__dirname, WIKI_DIR_PATH, ABOUT_REDIRECTS_FILENAME);
const aboutTrustedScriptletsPath = path.resolve(
__dirname,
WIKI_DIR_PATH,
ABOUT_TRUSTED_SCRIPTLETS_FILENAME,
);

/**
* Collects required comments from files and
Expand All @@ -42,17 +50,31 @@ const manageDataFromFiles = () => {
scriptletsFilenames,
SCRIPTLETS_SRC_RELATIVE_DIR_PATH,
);

const dataFromTrustedScriptletsFiles = getDataFromFiles(
trustedScriptletsFilenames,
SCRIPTLETS_SRC_RELATIVE_DIR_PATH,
);

const dataFromRedirectsFiles = getDataFromFiles(
redirectsFilenames,
REDIRECTS_SRC_RELATIVE_DIR_PATH,
);

const fullData = dataFromScriptletsFiles.concat(dataFromRedirectsFiles).flat(Infinity);
const fullData = dataFromScriptletsFiles
.concat(dataFromTrustedScriptletsFiles)
.concat(dataFromRedirectsFiles)
.flat(Infinity);

const scriptletsData = fullData.filter(({ type }) => type === 'scriptlet');
const trustedScriptletsData = fullData.filter(({ type }) => type === TRUSTED_SCRIPTLETS_TYPE);
const redirectsData = fullData.filter(({ type }) => type === 'redirect');

return { scriptletsData, redirectsData };
return {
scriptletsData,
trustedScriptletsData,
redirectsData,
};
};

/**
Expand Down Expand Up @@ -171,6 +193,9 @@ const buildWikiAboutPages = () => {
try {
const filesData = manageDataFromFiles();
const scriptletsMarkdownData = getMarkdownData(filesData.scriptletsData);

const trustedScriptletsMarkdownData = getMarkdownData(filesData.trustedScriptletsData);

const redirectsMarkdownData = getMarkdownData(filesData.redirectsData);
const staticRedirectsMarkdownData = getMarkdownDataForStaticRedirects();
const blockingRedirectsMarkdownData = getMarkdownDataForBlockingRedirects();
Expand All @@ -183,6 +208,15 @@ ${scriptletsMarkdownData.body}`;
scriptletsPageContent,
);

// eslint-disable-next-line max-len
const trustedScriptletsPageContent = `## <a id="trusted-scriptlets"></a> Available Trusted Scriptlets
${trustedScriptletsMarkdownData.list}* * *
${trustedScriptletsMarkdownData.body}`;
fs.writeFileSync(
path.resolve(__dirname, aboutTrustedScriptletsPath),
trustedScriptletsPageContent,
);

/* eslint-disable max-len */
const redirectsPageContent = `## <a id="redirect-resources"></a> Available Redirect resources
${staticRedirectsMarkdownData.list}${redirectsMarkdownData.list}${blockingRedirectsMarkdownData.list}* * *
Expand Down
14 changes: 13 additions & 1 deletion scripts/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ const SRC_REDIRECTS_SUB_DIR = 'redirects';
const SCRIPTLETS_SRC_RELATIVE_DIR_PATH = `${SRC_RELATIVE_DIR}/${SRC_SCRIPTLETS_SUB_DIR}`;
const REDIRECTS_SRC_RELATIVE_DIR_PATH = `${SRC_RELATIVE_DIR}/${SRC_REDIRECTS_SUB_DIR}`;

const TRUSTED_SCRIPTLETS_PREFIX = 'trusted-';
const TRUSTED_SCRIPTLETS_TYPE = 'trusted-scriptlet';

// files which are not scriptlets in the source directory
const NON_SCRIPTLETS_FILES = [
'index.js',
Expand All @@ -30,8 +33,15 @@ const NON_SCRIPTLETS_FILES = [
'scriptlets-wrapper.js',
'scriptlets-umd-wrapper.js',
];

const isUtilityFileName = (filename) => NON_SCRIPTLETS_FILES.includes(filename);
const isTrustedScriptletsFilename = (filename) => filename.startsWith(TRUSTED_SCRIPTLETS_PREFIX);

const scriptletsFilenames = getFilesList(SCRIPTLETS_SRC_RELATIVE_DIR_PATH)
.filter((el) => !NON_SCRIPTLETS_FILES.includes(el));
.filter((el) => !isUtilityFileName(el) && !isTrustedScriptletsFilename(el));

const trustedScriptletsFilenames = getFilesList(SCRIPTLETS_SRC_RELATIVE_DIR_PATH)
.filter((el) => isTrustedScriptletsFilename(el));

// files which are not redirects in the source directory
const NON_REDIRECTS_FILES = [
Expand All @@ -48,6 +58,8 @@ module.exports = {
WIKI_DIR_PATH,
SCRIPTLETS_SRC_RELATIVE_DIR_PATH,
REDIRECTS_SRC_RELATIVE_DIR_PATH,
TRUSTED_SCRIPTLETS_TYPE,
scriptletsFilenames,
trustedScriptletsFilenames,
redirectsFilenames,
};
11 changes: 10 additions & 1 deletion scripts/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,16 @@ Please add one OR edit the list of NON_SCRIPTLETS_FILES / NON_REDIRECTS_FILES.`)
}

// eventually only one comment data item should left
return describingComment[0].tags;
const { tags } = describingComment[0];

// Manually set type for trusted scriptlets
// to separate them from the common ones
if (filePath.includes('trusted-')) {
const [base] = tags;
base.type = 'trusted-scriptlet';
}

return tags;
};

/**
Expand Down
229 changes: 229 additions & 0 deletions wiki/about-trusted-scriptlets.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
## <a id="trusted-scriptlets"></a> Available Trusted Scriptlets
* [trusted-click-element](#trusted-click-element)
* [trusted-replace-fetch-response](#trusted-replace-fetch-response)
* [trusted-replace-xhr-response](#trusted-replace-xhr-response)
* [trusted-set-cookie](#trusted-set-cookie)
* * *
### <a id="trusted-click-element"></a> ⚡️ trusted-click-element

Clicks selected elements in a strict sequence, ordered by selectors passed, and waiting for them to render in the DOM first.
Deactivates after all elements have been clicked or by 10s timeout.

**Syntax**
```
example.com#%#//scriptlet('trusted-click-element', selectors[, extraMatch[, delay]])
```

- `selectors` — required, string with query selectors delimited by comma
- `extraMatch` — optional, extra condition to check on a page; allows to match `cookie` and `localStorage`; can be set as `name:key[=value]` where `value` is optional.
Multiple conditions are allowed inside one `extraMatch` but they should be delimited by comma and each of them should match the syntax. Possible `name`s:
- `cookie` - test string or regex against cookies on a page
- `localStorage` - check if localStorage item is present
- 'delay' - optional, time in ms to delay scriptlet execution, defaults to instant execution.
**Examples**
1. Click single element by selector
```
example.com#%#//scriptlet('trusted-click-element', 'button[name="agree"]')
```

2. Delay click execution by 500ms
```
example.com#%#//scriptlet('trusted-click-element', 'button[name="agree"]', '', '500')
```

3. Click multiple elements by selector with a delay
```
example.com#%#//scriptlet('trusted-click-element', 'button[name="agree"], button[name='check"], input[type="submit"][value="akkoord"]', '', '500')
```

4. Match cookies by keys using regex and string
```
example.com#%#//scriptlet('trusted-click-element', 'button[name="agree"]', 'cookie:userConsentCommunity, cookie:/cmpconsent|cmp/')
```

5. Match by cookie key=value pairs using regex and string
```
example.com#%#//scriptlet('trusted-click-element', 'button[name="agree"]', 'cookie:userConsentCommunity=true, cookie:/cmpconsent|cmp/=/[a-z]{1,5}/')
```

6. Match by localStorage item 'promo' key
```
example.com#%#//scriptlet('trusted-click-element', 'button[name="agree"]', 'localStorage:promo')
```

7. Click multiple elements with delay and matching by both cookie string and localStorage item
```
example.com#%#//scriptlet('trusted-click-element', 'button[name="agree"], input[type="submit"][value="akkoord"]', 'cookie:cmpconsent, localStorage:promo', '250')
```

[Redirect source](../src/scriptlets/trusted-click-element.js)
* * *

### <a id="trusted-replace-fetch-response"></a> ⚡️ trusted-replace-fetch-response

Replaces response text content of `fetch` requests if **all** given parameters match.

**Syntax**
```
example.org#%#//scriptlet('trusted-replace-fetch-response'[, pattern, replacement[, propsToMatch]])
```

- pattern - optional, argument for matching contents of responseText that should be replaced. If set, `replacement` is required;
possible values:
- '*' to match all text content
- non-empty string
- regular expression
- replacement — optional, should be set if `pattern` is set. String to replace the response text content matched by `pattern`.
Empty string to remove content. Defaults to empty string.
- propsToMatch - optional, string of space-separated properties to match; possible props:
- string or regular expression for matching the URL passed to fetch call; empty string, wildcard `*` or invalid regular expression will match all fetch calls
- colon-separated pairs `name:value` where
- `name` is [`init` option name](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#parameters)
- `value` is string or regular expression for matching the value of the option passed to fetch call; invalid regular expression will cause any value matching

> Usage with no arguments will log fetch calls to browser console;
which is useful for debugging but only allowed for production filter lists.

> Scriptlet does nothing if response body can't be converted to text.
**Examples**
1. Log all fetch calls
```
example.org#%#//scriptlet('trusted-replace-fetch-response')
```

2. Replace response text content of fetch requests with specific url
```
example.org#%#//scriptlet('trusted-replace-fetch-response', 'adb_detect:true', 'adb_detect:false', 'example.org')
example.org#%#//scriptlet('trusted-replace-fetch-response', '/#EXT-X-VMAP-AD-BREAK[\s\S]*?/', '#EXT-X-ENDLIST', 'example.org')
```

3. Remove all text content of fetch responses with specific request method
```
example.org#%#//scriptlet('trusted-replace-fetch-response', '*', '', 'method:GET')
```

4. Replace response text content of fetch requests matching by URL regex and request methods
```
example.org#%#//scriptlet('trusted-replace-fetch-response', '/#EXT-X-VMAP-AD-BREAK[\s\S]*?/', '#EXT-X-ENDLIST', '/\.m3u8/ method:/GET|HEAD/')
```
5. Remove text content of all fetch responses for example.com
```
example.org#%#//scriptlet('trusted-replace-fetch-response', '*', '', 'example.com')
```

[Redirect source](../src/scriptlets/trusted-replace-fetch-response.js)
* * *

### <a id="trusted-replace-xhr-response"></a> ⚡️ trusted-replace-xhr-response

Replaces response content of `xhr` requests if **all** given parameters match.

**Syntax**
```
example.org#%#//scriptlet('trusted-replace-xhr-response'[, pattern, replacement[, propsToMatch]])
```

- pattern - optional, argument for matching contents of responseText that should be replaced. If set, `replacement` is required;
possible values:
- '*' to match all text content
- non-empty string
- regular expression
- replacement — optional, should be set if `pattern` is set. String to replace matched content with. Empty string to remove content.
- propsToMatch — optional, string of space-separated properties to match for extra condition; possible props:
- string or regular expression for matching the URL passed to `.open()` call;
- colon-separated pairs name:value where
- name - name is string or regular expression for matching XMLHttpRequest property name
- value is string or regular expression for matching the value of the option passed to `.open()` call

> Usage with no arguments will log XMLHttpRequest objects to browser console;
which is useful for debugging but not permitted for production filter lists.

**Examples**
1. Log all XMLHttpRequests
```
example.org#%#//scriptlet('trusted-replace-xhr-response')
```

2. Replace text content of XMLHttpRequests with specific url
```
example.org#%#//scriptlet('trusted-replace-xhr-response', 'adb_detect:true', 'adb_detect:false', 'example.org')
example.org#%#//scriptlet('trusted-replace-xhr-response', '/#EXT-X-VMAP-AD-BREAK[\s\S]*?/', '#EXT-X-ENDLIST', 'example.org')
```

3. Remove all text content of XMLHttpRequests with specific request method
```
example.org#%#//scriptlet('trusted-replace-xhr-response', '*', '', 'method:GET')
```

4. Replace text content of XMLHttpRequests matching by URL regex and request methods
```
example.org#%#//scriptlet('trusted-replace-xhr-response', '/#EXT-X-VMAP-AD-BREAK[\s\S]*?/', '#EXT-X-ENDLIST', '/\.m3u8/ method:/GET|HEAD/')
```
5. Remove all text content of all XMLHttpRequests for example.com
```
example.org#%#//scriptlet('trusted-replace-xhr-response', '*', '', 'example.com')
```

[Redirect source](../src/scriptlets/trusted-replace-xhr-response.js)
* * *

### <a id="trusted-set-cookie"></a> ⚡️ trusted-set-cookie

Sets a cookie with arbitrary name and value, with optional path
and the ability to reload the page after cookie was set.

**Syntax**
```
example.org#%#//scriptlet('trusted-set-cookie', name, value[, offsetExpiresSec[, reload[, path]]])
```

- `name` - required, cookie name to be set
- `value` - required, cookie value. Possible values:
- arbitrary value
- empty string for no value
- `$now$` keyword for setting current time
- 'offsetExpiresSec' - optional, offset from current time in seconds, after which cookie should expire; defaults to no offset
Possible values:
- positive integer in seconds
- `1year` keyword for setting expiration date to one year
- `1day` keyword for setting expiration date to one day
- 'reload' - optional, boolean. Argument for reloading page after cookie is set. Defaults to `false`
- `path` - optional, argument for setting cookie path, defaults to `/`; possible values:
- `/` — root path
- `none` — to set no path at all

**Examples**
1. Set cookie
```
example.org#%#//scriptlet('trusted-set-cookie', 'cmpconsent', 'accept')
example.org#%#//scriptlet('trusted-set-cookie', 'cmpconsent', '1-accept_1')
```

2. Set cookie with `new Date().getTime()` value
```
example.org#%#//scriptlet('trusted-set-cookie', 'cmpconsent', '$now')
```

3. Set cookie which will expire in 3 days
```
example.org#%#//scriptlet('trusted-set-cookie', 'cmpconsent', 'accept', '259200')
```

4. Set cookie which will expire in one year
```
example.org#%#//scriptlet('trusted-set-cookie', 'cmpconsent', 'accept', '1year')
```
5. Reload the page if cookie was successfully set
```
example.org#%#//scriptlet('trusted-set-cookie', 'cmpconsent', 'decline', '', 'true')
```

6. Set cookie with no path
```
example.org#%#//scriptlet('trusted-set-cookie', 'cmpconsent', 'decline', '', '', 'none')
```

[Redirect source](../src/scriptlets/trusted-set-cookie.js)
* * *

0 comments on commit 69dc7c0

Please sign in to comment.