@duckduckgo/autoconsent 15.1.0 → 16.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/.github/dependabot.yml +0 -3
  2. package/.github/workflows/release.yml +0 -4
  3. package/AGENTS.md +3 -3
  4. package/CHANGELOG.md +20 -0
  5. package/build.sh +0 -2
  6. package/dist/addon-firefox/background.bundle.js +8 -24
  7. package/dist/addon-firefox/compact-rules.json +1 -1
  8. package/dist/addon-firefox/content.bundle.js +176 -686
  9. package/dist/addon-firefox/manifest.json +1 -1
  10. package/dist/addon-firefox/popup.bundle.js +31 -27
  11. package/dist/addon-firefox/popup.html +21 -13
  12. package/dist/addon-firefox/rule-index.json +1 -1
  13. package/dist/addon-firefox/rules.json +1 -1
  14. package/dist/addon-mv3/background.bundle.js +8 -24
  15. package/dist/addon-mv3/compact-rules.json +1 -1
  16. package/dist/addon-mv3/content.bundle.js +176 -686
  17. package/dist/addon-mv3/manifest.json +1 -1
  18. package/dist/addon-mv3/popup.bundle.js +31 -27
  19. package/dist/addon-mv3/popup.html +21 -13
  20. package/dist/addon-mv3/rule-index.json +1 -1
  21. package/dist/addon-mv3/rules.json +1 -1
  22. package/dist/autoconsent.cjs.js +176 -685
  23. package/dist/autoconsent.esm.js +176 -685
  24. package/dist/autoconsent.playwright.js +177 -689
  25. package/dist/autoconsent.standalone.js +177 -690
  26. package/dist/types/cmps/base.d.ts +3 -3
  27. package/dist/types/heuristics.d.ts +2 -2
  28. package/dist/types/types.d.ts +10 -23
  29. package/dist/types/web.d.ts +0 -9
  30. package/docs/api.md +1 -8
  31. package/docs/puppeteer.md +1 -3
  32. package/docs/rule-syntax.md +0 -17
  33. package/eslint.config.mjs +1 -1
  34. package/lib/cmps/base.ts +5 -6
  35. package/lib/heuristics.ts +15 -15
  36. package/lib/types.ts +9 -21
  37. package/lib/utils.ts +2 -4
  38. package/lib/web.ts +3 -53
  39. package/package.json +4 -17
  40. package/playwright/content.ts +1 -2
  41. package/readme.md +3 -6
  42. package/rules/autoconsent/dreamlab-cmp.json +13 -0
  43. package/rules/build.ts +1 -24
  44. package/rules/compact-rules.json +1 -1
  45. package/rules/rule-index-builder.ts +2 -7
  46. package/rules/rule-index.json +1 -1
  47. package/rules/rules.json +1 -1
  48. package/standalone/content.ts +0 -2
  49. package/tests/dreamlab-cmp.spec.ts +3 -0
  50. package/tests/quantcast.spec.ts +0 -6
  51. package/tests-wtr/heuristics/get-actionable-popups.ts +13 -13
  52. package/tests-wtr/heuristics/heuristic-cmp.ts +32 -33
  53. package/tests-wtr/lifecycle/find-cmp.ts +5 -8
  54. package/tests-wtr/web/do-opt-in.test.ts +0 -1
  55. package/tests-wtr/web/do-opt-out.test.ts +0 -1
  56. package/tests-wtr/web/do-self-test.test.ts +0 -1
  57. package/tests-wtr/web/filter-cmps.test.ts +0 -1
  58. package/tests-wtr/web/receive-message-callback.test.ts +1 -2
  59. package/tests-wtr/web/update-state.test.ts +1 -3
  60. package/tsconfig.build.json +1 -1
  61. package/.github/workflows/update-filterlist.yml +0 -42
  62. package/dist/autoconsent.extra.cjs.js +0 -15717
  63. package/dist/autoconsent.extra.esm.js +0 -15649
  64. package/dist/types/cmps/consentomatic.d.ts +0 -34
  65. package/dist/types/consentomatic/index.d.ts +0 -2
  66. package/dist/types/consentomatic/tools.d.ts +0 -10
  67. package/dist/types/filterlist-engine.d.ts +0 -2
  68. package/dist/types/filterlist-utils.d.ts +0 -4
  69. package/dist/types/web-extra.d.ts +0 -11
  70. package/lib/cmps/consentomatic.ts +0 -97
  71. package/lib/consentomatic/index.ts +0 -252
  72. package/lib/consentomatic/tools.ts +0 -199
  73. package/lib/filterlist-engine.ts +0 -5
  74. package/lib/filterlist-utils.ts +0 -45
  75. package/lib/web-extra.ts +0 -116
  76. package/rules/consentomatic.json +0 -1
  77. package/rules/filterlist.txt +0 -18440
  78. package/rules/filterlists/overrides.txt +0 -4
  79. package/scripts/compile-filterlist.mjs +0 -63
  80. package/scripts/fetch-easylist.sh +0 -25
  81. package/scripts/rebuild-filterlist.mjs +0 -216
  82. package/tests/oil.spec.ts +0 -7
  83. package/tests/springer.spec.ts +0 -7
  84. package/tests/wordpressgdpr.spec.ts +0 -6
@@ -1,4 +0,0 @@
1
- @@||duckduckgo.com^$document
2
- @@||duckduckgo.com^$elemhide
3
- ! domain-level exceptions above are not working with the adblocker library
4
- privacy-test-pages.site,first-party.example###privacy-test-page-cmp-test-banner-filterlist
@@ -1,63 +0,0 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
- import { fileURLToPath } from 'url';
4
- import { FiltersEngine } from '@ghostery/adblocker';
5
-
6
- const rulesDir = path.join(path.dirname(fileURLToPath(import.meta.url)), '../rules');
7
-
8
- const filterlistContent = fs.readFileSync(path.join(rulesDir, 'filterlist.txt'), 'utf-8');
9
-
10
- const engine = FiltersEngine.parse(filterlistContent, {
11
- enableMutationObserver: false, // we don't monitor DOM changes at the moment
12
- loadNetworkFilters: false,
13
- enableHtmlFiltering: false,
14
- loadCSPFilters: false,
15
- });
16
- const serializedEngine = engine.serialize();
17
- const properlySizedBuffer = ensure32BitAlignment(serializedEngine.buffer);
18
- const engineJson = JSON.stringify(Array.from(new Uint32Array(properlySizedBuffer)));
19
- const engineLength = serializedEngine.length;
20
-
21
- /**
22
- * Ensures the buffer is aligned to a 32-bit boundary by padding if necessary
23
- * @param {Buffer} originalBuffer
24
- * @returns {Buffer} - The aligned buffer
25
- */
26
-
27
- function ensure32BitAlignment(originalBuffer) {
28
- // Calculate the necessary padding for 32-bit alignment
29
- const padding = originalBuffer.byteLength % 4 === 0 ? 0 : 4 - (originalBuffer.byteLength % 4);
30
-
31
- if (padding !== 0) {
32
- // Create a new buffer with the required padding for 32-bit alignment
33
- const paddedBuffer = new ArrayBuffer(originalBuffer.byteLength + padding);
34
-
35
- // Create a Uint8Array view over the original and new buffers
36
- const originalView = new Uint8Array(originalBuffer);
37
- const paddedView = new Uint8Array(paddedBuffer);
38
-
39
- // Copy the original data into the new buffer
40
- paddedView.set(originalView);
41
-
42
- // Set the padding bytes to zero
43
- for (let i = originalBuffer.byteLength; i < paddedBuffer.byteLength; i++) {
44
- paddedView[i] = 0;
45
- }
46
-
47
- return paddedBuffer;
48
- }
49
-
50
- // If already aligned, return the original buffer
51
- return originalBuffer;
52
- }
53
-
54
- fs.writeFile(
55
- path.join(rulesDir, '../lib/filterlist-engine.ts'),
56
- `
57
- const serializedEngine = /* @__PURE__ */ new Uint8Array(new Uint32Array(
58
- ${engineJson}
59
- ).buffer).slice(0, ${engineLength});
60
- export default serializedEngine;
61
- `,
62
- () => console.log('Written filterlist-engine.ts'),
63
- );
@@ -1,25 +0,0 @@
1
- #!/bin/bash
2
- set -e
3
-
4
- SCRIPT_DIR="`dirname $0`"
5
- RULES_DIR="${SCRIPT_DIR}/../rules/filterlists/"
6
-
7
- # set EASYLIST_REVISION to a specific commit hash to lock to a specific revision. By default we use the latest revision.
8
- if [ "${EASYLIST_REVISION}" = "" ];
9
- then
10
- echo "Looking up the latest Easylist revision..."
11
- EASYLIST_REVISION=`git ls-remote https://github.com/easylist/easylist.git refs/heads/master | cut -f 1`
12
- fi
13
-
14
- echo "Using Easylist revision: ${EASYLIST_REVISION}"
15
-
16
- rm -f rules/filterlists/easylist_cookie_*
17
- wget --directory-prefix="${RULES_DIR}" \
18
- "https://raw.githubusercontent.com/easylist/easylist/${EASYLIST_REVISION}/easylist_cookie/easylist_cookie_general_hide.txt" \
19
- "https://raw.githubusercontent.com/easylist/easylist/${EASYLIST_REVISION}/easylist_cookie/easylist_cookie_specific_hide.txt" \
20
- "https://raw.githubusercontent.com/easylist/easylist/${EASYLIST_REVISION}/easylist_cookie/easylist_cookie_specific_uBO.txt" \
21
- "https://raw.githubusercontent.com/easylist/easylist/${EASYLIST_REVISION}/easylist_cookie/easylist_cookie_international_specific_hide.txt" \
22
- "https://raw.githubusercontent.com/easylist/easylist/${EASYLIST_REVISION}/easylist_cookie/easylist_cookie_allowlist_general_hide.txt"
23
-
24
- echo "${EASYLIST_REVISION}" > "${RULES_DIR}/easylist_revision.txt"
25
- echo "Saved the Easylist revision to ${RULES_DIR}/easylist_revision.txt"
@@ -1,216 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import fs from 'fs';
4
- import path from 'path';
5
- import { fileURLToPath } from 'url';
6
- import { parse } from 'csv-parse/sync';
7
- import { getDomain } from 'tldts-experimental';
8
- import { Readable } from 'stream';
9
- import { finished } from 'stream/promises';
10
-
11
- const rulesDir = path.join(path.dirname(fileURLToPath(import.meta.url)), '../rules');
12
- const dataDir = path.join(path.dirname(fileURLToPath(import.meta.url)), '../data');
13
-
14
- const easylistRevision = fs.readFileSync(path.join(rulesDir, 'filterlists', 'easylist_revision.txt'), 'utf-8');
15
- const domainSpecificLists = [
16
- 'easylist_cookie_specific_uBO.txt',
17
- 'easylist_cookie_specific_hide.txt',
18
- 'easylist_cookie_international_specific_hide.txt',
19
- ];
20
-
21
- const MAX_DOMAIN_RANK = 100000;
22
-
23
- /** @typedef {{ rules: Record<string, string[]>}} FilterlistJSON */
24
-
25
- /** @type {Map<string, string>} */
26
- let domainMap;
27
-
28
- /**
29
- * Processes a list containing domain-specific cosmetic rules, filters
30
- * out unsupported rules and removes longtail domain rules
31
- * @param {String} listFileName
32
- */
33
- async function processDomainSpecificFilterList(listFileName) {
34
- console.log(`Processing ${listFileName}`);
35
- const data = fs.readFileSync(path.join(rulesDir, 'filterlists', listFileName), 'utf-8');
36
- const lines = data.split('\n');
37
- /** @type {FilterlistJSON} */
38
- const filterlistJSON = { rules: {} };
39
-
40
- // Remove comments and network rules, which take a different format:
41
- // ! at start of line indicates comment
42
- // || at start of line indicates network rule
43
- const filteredLines = lines.filter((line) => !line.startsWith('!') && !line.startsWith('||'));
44
- // Dump rules into json structure for parsing
45
- for (const rule of filteredLines) {
46
- const splitRule = rule.split('##');
47
- const target = splitRule[0];
48
- const action = splitRule[1];
49
-
50
- if (!action) {
51
- continue;
52
- }
53
-
54
- if (!filterlistJSON.rules[target]) {
55
- filterlistJSON.rules[target] = [action];
56
- } else {
57
- filterlistJSON.rules[target].push(action);
58
- }
59
- }
60
-
61
- // Remove any targets that contain a +js rule. we do it this way because
62
- // when a target has a :js rule, we must also remove any css rules
63
- for (const item in filterlistJSON.rules) {
64
- const containsJS = filterlistJSON.rules[item].some((filter) => filter.includes('+js'));
65
- if (containsJS) {
66
- delete filterlistJSON.rules[item];
67
- }
68
- }
69
-
70
- for (const item in filterlistJSON.rules) {
71
- let domains;
72
-
73
- if (item.includes(',')) {
74
- domains = item.split(',');
75
- } else {
76
- domains = [item];
77
- }
78
-
79
- const filteredDomains = domains.filter((domain) => {
80
- // Don't filter global rules which don't have a domain
81
- if (domain === '') {
82
- return true;
83
- }
84
-
85
- const tlDomain = getDomain(domain);
86
- return domainMap.has(tlDomain);
87
- });
88
-
89
- // If no domains meet cutoff, remove rule entirely. If one or more
90
- // domains meet cutoff, remove those that don't
91
- if (filteredDomains.length === 0) {
92
- delete filterlistJSON.rules[item];
93
- } else if (filteredDomains.length !== domains.length) {
94
- const filteredDomainString = filteredDomains.join(',');
95
- filterlistJSON.rules[filteredDomainString] = filterlistJSON.rules[item];
96
- delete filterlistJSON.rules[item];
97
- }
98
- }
99
-
100
- await convertAndWriteABP(filterlistJSON, listFileName);
101
- }
102
-
103
- /**
104
- * Fetch domain popularity data from Tranco and load it into a Map for querying
105
- */
106
- async function loadTrancoList() {
107
- const csvLocation = path.resolve(path.join(dataDir, 'top-1m.csv'));
108
- if (!fs.existsSync(csvLocation)) {
109
- console.log('Fetching latest Tranco list..');
110
- // Download most recent list from https://tranco-list.eu using API
111
- const date = new Date();
112
- let available;
113
- let download;
114
-
115
- do {
116
- const formattedDate = date.toISOString().split('T')[0].replace('/', '');
117
- const res = await (await fetch(`https://tranco-list.eu/api/lists/date/${formattedDate}`)).json();
118
-
119
- available = res.available;
120
- download = res.download;
121
-
122
- // Decrement date until a daily list is available
123
- date.setTime(date.getTime() - 7 * 24 * 3600000);
124
- } while (!available);
125
-
126
- const listData = await fetch(download);
127
- await finished(Readable.fromWeb(listData.body).pipe(fs.createWriteStream(csvLocation)));
128
- }
129
-
130
- if (typeof domainMap !== 'object') {
131
- const trancoCSV = fs.readFileSync(path.join(dataDir, 'top-1m.csv'), 'utf-8');
132
- /** @type {string[][]} */
133
- const records = parse(trancoCSV, {
134
- columns: false,
135
- skip_empty_lines: true,
136
- });
137
-
138
- domainMap = new Map();
139
-
140
- records.slice(0, MAX_DOMAIN_RANK).forEach(([key, value]) => {
141
- domainMap.set(value, key);
142
- });
143
- }
144
- }
145
-
146
- /**
147
- * Convert filter list to ABP format and write to disk
148
- * @param {FilterlistJSON} JSONList
149
- * @param {String} fileName
150
- */
151
- function convertAndWriteABP(JSONList, fileName) {
152
- return new Promise((resolve, reject) => {
153
- const fileLocation = path.join(rulesDir, 'filterlists', fileName);
154
- const stream = fs.createWriteStream(fileLocation, { flags: 'w' });
155
-
156
- stream.once('open', () => {
157
- for (const item in JSONList.rules) {
158
- JSONList.rules[item].forEach((filter) => {
159
- const abpRule = item + '##' + filter;
160
- stream.write(abpRule + '\n');
161
- });
162
- }
163
- stream.end();
164
- });
165
-
166
- stream.on('finish', () => {
167
- console.log(`ABP format list written to ${fileLocation}`);
168
- resolve();
169
- });
170
-
171
- stream.on('error', (err) => {
172
- console.error(`An error occurred while writing ${fileLocation}: ${err.message}`);
173
- });
174
- });
175
- }
176
-
177
- /**
178
- * Combine all filter lists into a single filterlist.txt
179
- */
180
- function combineFilterLists() {
181
- // TODO: consider using python-abp (flrender) to generate filterlist properly
182
- const filterlistContent = `[Adblock Plus 2.0]
183
- ! Title: CPM Cosmetic Filter List
184
- ! Based on EasyList ${easylistRevision}
185
- ! DO NOT EDIT MANUALLY, your changes will be lost
186
- ! Generated on ${new Date().toISOString()}
187
- !------------------------General element hiding rules-------------------------!
188
- ${fs.readFileSync(path.join(rulesDir, 'filterlists', 'easylist_cookie_general_hide.txt'), 'utf-8')}
189
- !------------------------Specific element hiding rules------------------------!
190
- ${fs.readFileSync(path.join(rulesDir, 'filterlists', 'easylist_cookie_specific_hide.txt'), 'utf-8')}
191
- ${fs.readFileSync(path.join(rulesDir, 'filterlists', 'easylist_cookie_specific_uBO.txt'), 'utf-8')}
192
- !------------------------Rules for international sites------------------------!
193
- ${fs.readFileSync(path.join(rulesDir, 'filterlists', 'easylist_cookie_international_specific_hide.txt'), 'utf-8')}
194
- !---------------------------------Allowlists----------------------------------!
195
- ${fs.readFileSync(path.join(rulesDir, 'filterlists', 'easylist_cookie_allowlist_general_hide.txt'), 'utf-8')}
196
- !--------------------------------DDG overrides--------------------------------!
197
- ${fs.readFileSync(path.join(rulesDir, 'filterlists', 'overrides.txt'), 'utf-8')}
198
- `;
199
-
200
- fs.writeFile(path.join(rulesDir, 'filterlist.txt'), filterlistContent, () => console.log('Written filterlist.txt'));
201
- }
202
-
203
- /**
204
- * Parse and refine lists using domain popularity, then combine them and write filterlist.txt
205
- */
206
- async function rebuildFilterList() {
207
- await loadTrancoList();
208
-
209
- for (const list of domainSpecificLists) {
210
- await processDomainSpecificFilterList(list);
211
- }
212
-
213
- combineFilterLists();
214
- }
215
-
216
- rebuildFilterList();
package/tests/oil.spec.ts DELETED
@@ -1,7 +0,0 @@
1
- import generateCMPTests from '../playwright/runner';
2
-
3
- generateCMPTests('com_oil', ['https://www.farbtoner.com/', 'https://www.elektro4000.de/', 'http://edelholzverkauf.de/'], {
4
- skipRegions: ['GB'],
5
- testOptIn: false,
6
- testSelfTest: false,
7
- });
@@ -1,7 +0,0 @@
1
- import generateCMPTests from '../playwright/runner';
2
-
3
- generateCMPTests('com_springer', ['https://www.beobachter.ch/', 'https://www.blick.ch/', 'https://www.onet.pl/'], {
4
- skipRegions: ['GB'],
5
- testOptIn: false,
6
- testSelfTest: false,
7
- });
@@ -1,6 +0,0 @@
1
- import generateCMPTests from '../playwright/runner';
2
-
3
- generateCMPTests('com_wordpressgdpr', ['https://www.yourpension.gov.uk/'], {
4
- testOptIn: false,
5
- testSelfTest: false,
6
- });