@duckduckgo/autoconsent 16.41.0 → 16.43.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.
- package/.agents/skills/proxy-testing/SKILL.md +5 -8
- package/.agents/skills/proxy-testing/scripts/regional-proxy.mjs +22 -22
- package/.agents/skills/proxy-testing/scripts/regional-proxy.test.mjs +61 -0
- package/.claude/user-settings.json.TEMPLATE +22 -0
- package/CHANGELOG.md +35 -0
- package/dist/addon-firefox/background.bundle.js +18 -0
- package/dist/addon-firefox/compact-rules.json +1 -1
- package/dist/addon-firefox/content.bundle.js +18 -0
- package/dist/addon-firefox/manifest.json +1 -1
- package/dist/addon-firefox/rule-index.json +1 -1
- package/dist/addon-firefox/rules.json +1 -1
- package/dist/addon-mv3/background.bundle.js +18 -0
- package/dist/addon-mv3/compact-rules.json +1 -1
- package/dist/addon-mv3/content.bundle.js +18 -0
- package/dist/addon-mv3/manifest.json +1 -1
- package/dist/addon-mv3/rule-index.json +1 -1
- package/dist/addon-mv3/rules.json +1 -1
- package/dist/autoconsent.cjs.js +18 -0
- package/dist/autoconsent.esm.js +18 -0
- package/dist/autoconsent.playwright.js +18 -0
- package/dist/autoconsent.standalone.js +19 -1
- package/dist/types/eval-snippets.d.ts +1 -0
- package/lib/eval-snippets.ts +20 -0
- package/package.json +1 -1
- package/readme.md +10 -0
- package/rules/autoconsent/iubenda-rti.json +20 -0
- package/rules/autoconsent/sourcepoint-top.json +3 -2
- package/rules/compact-rules.json +1 -1
- package/rules/rule-index.json +1 -1
- package/rules/rules.json +1 -1
- package/tests/iubenda-rti.spec.ts +6 -0
- package/tests/iubenda.spec.ts +3 -7
|
@@ -28,13 +28,10 @@ npm run prepublish # builds dist/autoconsent.playwright.js and rules/rules.json
|
|
|
28
28
|
|
|
29
29
|
Environment variables:
|
|
30
30
|
|
|
31
|
-
- `REGIONAL_PROXY_<TWO_LETTER_REGION_CODE>` (for example, `REGIONAL_PROXY_US`, `REGIONAL_PROXY_GB`, `REGIONAL_PROXY_AU`, etc.) -
|
|
32
|
-
- `REGIONAL_PROXY_USERNAME`
|
|
33
|
-
- `REGIONAL_PROXY_PASSWORD`
|
|
31
|
+
- `REGIONAL_PROXY_<TWO_LETTER_REGION_CODE>` (for example, `REGIONAL_PROXY_US`, `REGIONAL_PROXY_GB`, `REGIONAL_PROXY_AU`, etc.) - a complete proxy URL with an `http://`, `https://`, or `socks5://` scheme. Examples: `socks5://usc-socks-tr-cluster.duckduckgo.com:80`, `https://proxy.example.com:443`.
|
|
32
|
+
- `REGIONAL_PROXY_USERNAME` and `REGIONAL_PROXY_PASSWORD` (optional) - shared credentials, passed to Playwright for `https://` proxies only. They are ignored for `http://` and `socks5://` proxies.
|
|
34
33
|
|
|
35
|
-
|
|
36
|
-
- The library adds `https://` and port `443`.
|
|
37
|
-
- Credentials are shared across regions.
|
|
34
|
+
Never embed credentials in a proxy URL.
|
|
38
35
|
|
|
39
36
|
## Usage
|
|
40
37
|
|
|
@@ -91,7 +88,7 @@ export default defineConfig({
|
|
|
91
88
|
- `ALL_REGIONS` — all supported regions.
|
|
92
89
|
- `testPage(page, url, regionKey, options?)` — run a full test on a page you created yourself (you own the browser/context); returns a `TestResult`.
|
|
93
90
|
- `injectAutoconsent(page, options?)` — set up isolated-world injection; call before `page.goto()`. Returns a context (`received`, `hasMessage`, `waitForCompletion`, `waitForMessage`, `collectResult`).
|
|
94
|
-
- `buildProxyConfig(regionKey)` — build the Playwright `{ server, username, password }`
|
|
91
|
+
- `buildProxyConfig(regionKey)` — build the Playwright proxy object for a region from its env vars; returns `{ server, username, password }` for `https://` proxies when credentials are set, otherwise `{ server }`.
|
|
95
92
|
- `launchRegionalProxyBrowser(regionKey, options?)` — launch a Chromium browser routed through the region's proxy.
|
|
96
93
|
- `formatResult(result)` — format a `TestResult` as a human-readable summary line.
|
|
97
94
|
|
|
@@ -128,7 +125,7 @@ await browser.close();
|
|
|
128
125
|
|
|
129
126
|
## Gotchas
|
|
130
127
|
|
|
131
|
-
-
|
|
128
|
+
- HTTPS proxy credentials go in Playwright's proxy auth object (`{ server, username, password }`); Chromium cannot authenticate to SOCKS proxies.
|
|
132
129
|
- Never embed proxy credentials in URLs, command lines, logs, traces, or source.
|
|
133
130
|
- Call `injectAutoconsent(page)` before `page.goto()` so the init script is installed before page scripts run.
|
|
134
131
|
- The content script runs in an isolated world (via CDP) and `eval` snippets run in the page's main world, matching the extension. Chromium only.
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Playwright
|
|
2
|
+
* Playwright regional proxy utilities for multi-region autoconsent testing.
|
|
3
3
|
*
|
|
4
|
-
* Launches a local Chromium browser with
|
|
4
|
+
* Launches a local Chromium browser with a proxy selected by region, injects
|
|
5
5
|
* autoconsent into an isolated world (via CDP), and evaluates opt-out/opt-in flows.
|
|
6
6
|
* Chromium only - isolated worlds are reached through CDP, which Playwright exposes for
|
|
7
7
|
* Chromium alone.
|
|
8
8
|
*
|
|
9
9
|
* Requires env vars:
|
|
10
|
-
* - REGIONAL_PROXY_<REGION> (REGION is the uppercased two-letter region code)
|
|
11
|
-
* - REGIONAL_PROXY_USERNAME
|
|
12
|
-
* - REGIONAL_PROXY_PASSWORD
|
|
10
|
+
* - REGIONAL_PROXY_<REGION> (REGION is the uppercased two-letter region code): a complete proxy URL
|
|
11
|
+
* - REGIONAL_PROXY_USERNAME and REGIONAL_PROXY_PASSWORD (optional, used for https:// proxies only)
|
|
13
12
|
*/
|
|
14
13
|
|
|
15
14
|
/**
|
|
@@ -95,7 +94,7 @@ export const EXPANDED_REGIONS = ['us', 'gb', 'de', 'fr', 'nl', 'pl', 'au', 'ca',
|
|
|
95
94
|
* Build the Playwright proxy object for a region.
|
|
96
95
|
* @param {string} regionKey - Two-letter region code (e.g. 'us', 'gb').
|
|
97
96
|
* @param {NodeJS.ProcessEnv} [env]
|
|
98
|
-
* @returns {{ server: string, username
|
|
97
|
+
* @returns {{ server: string, username?: string, password?: string }}
|
|
99
98
|
*/
|
|
100
99
|
export function buildProxyConfig(regionKey, env = process.env) {
|
|
101
100
|
const envVar = `REGIONAL_PROXY_${regionKey.toUpperCase()}`;
|
|
@@ -103,27 +102,28 @@ export function buildProxyConfig(regionKey, env = process.env) {
|
|
|
103
102
|
const username = env.REGIONAL_PROXY_USERNAME;
|
|
104
103
|
const password = env.REGIONAL_PROXY_PASSWORD;
|
|
105
104
|
|
|
106
|
-
if (!endpoint
|
|
107
|
-
throw new Error(
|
|
108
|
-
`Missing proxy environment variables for region "${regionKey}". ` +
|
|
109
|
-
`Expected ${envVar}, REGIONAL_PROXY_USERNAME, and REGIONAL_PROXY_PASSWORD.`,
|
|
110
|
-
);
|
|
105
|
+
if (!endpoint) {
|
|
106
|
+
throw new Error(`Missing proxy environment variable for region "${regionKey}". Expected ${envVar}.`);
|
|
111
107
|
}
|
|
112
|
-
if (endpoint.includes('://')
|
|
113
|
-
throw new Error(
|
|
114
|
-
`${envVar} should be a bare hostname without scheme, credentials, or port. ` + 'The library adds https:// and port 443.',
|
|
115
|
-
);
|
|
108
|
+
if (!endpoint.includes('://')) {
|
|
109
|
+
throw new Error(`${envVar} must be a complete proxy URL (http://, https://, or socks5://).`);
|
|
116
110
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
111
|
+
const parsed = new URL(endpoint);
|
|
112
|
+
if (!['http:', 'https:', 'socks5:'].includes(parsed.protocol)) {
|
|
113
|
+
throw new Error(`${envVar} has unsupported proxy protocol "${parsed.protocol}".`);
|
|
114
|
+
}
|
|
115
|
+
if (parsed.username || parsed.password) {
|
|
116
|
+
throw new Error(`${envVar} must not contain embedded proxy credentials.`);
|
|
117
|
+
}
|
|
118
|
+
// Credentials are only used for HTTPS proxies; Chromium cannot authenticate to SOCKS proxies.
|
|
119
|
+
if (parsed.protocol === 'https:' && username && password) {
|
|
120
|
+
return { server: endpoint, username, password };
|
|
121
|
+
}
|
|
122
|
+
return { server: endpoint };
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
/**
|
|
126
|
-
* Launch a local Playwright browser through the
|
|
126
|
+
* Launch a local Playwright browser through the proxy for a region.
|
|
127
127
|
* @param {string} regionKey
|
|
128
128
|
* @param {Partial<TestOptions>} [options]
|
|
129
129
|
* @returns {Promise<Browser>}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { describe, it } from 'node:test';
|
|
3
|
+
|
|
4
|
+
import { buildProxyConfig } from './regional-proxy.mjs';
|
|
5
|
+
|
|
6
|
+
const credentials = {
|
|
7
|
+
REGIONAL_PROXY_PASSWORD: 'password',
|
|
8
|
+
REGIONAL_PROXY_USERNAME: 'username',
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
describe('regional proxy config', () => {
|
|
12
|
+
it('uses complete credential-free SOCKS URLs directly', () => {
|
|
13
|
+
assert.deepEqual(
|
|
14
|
+
buildProxyConfig('us', {
|
|
15
|
+
REGIONAL_PROXY_US: 'socks5://usc-socks-tr-cluster.duckduckgo.com:80',
|
|
16
|
+
}),
|
|
17
|
+
{ server: 'socks5://usc-socks-tr-cluster.duckduckgo.com:80' },
|
|
18
|
+
);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('passes credentials for HTTPS proxies', () => {
|
|
22
|
+
assert.deepEqual(buildProxyConfig('de', { REGIONAL_PROXY_DE: 'https://proxy.example:443', ...credentials }), {
|
|
23
|
+
password: 'password',
|
|
24
|
+
server: 'https://proxy.example:443',
|
|
25
|
+
username: 'username',
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('allows HTTPS proxies without credentials', () => {
|
|
30
|
+
assert.deepEqual(buildProxyConfig('de', { REGIONAL_PROXY_DE: 'https://proxy.example:443' }), {
|
|
31
|
+
server: 'https://proxy.example:443',
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('does not pass credentials for non-HTTPS proxies', () => {
|
|
36
|
+
assert.deepEqual(buildProxyConfig('us', { REGIONAL_PROXY_US: 'socks5://proxy.example:80', ...credentials }), {
|
|
37
|
+
server: 'socks5://proxy.example:80',
|
|
38
|
+
});
|
|
39
|
+
assert.deepEqual(buildProxyConfig('us', { REGIONAL_PROXY_US: 'http://proxy.example:3128', ...credentials }), {
|
|
40
|
+
server: 'http://proxy.example:3128',
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('rejects credentials embedded in URLs', () => {
|
|
45
|
+
assert.throws(
|
|
46
|
+
() => buildProxyConfig('us', { REGIONAL_PROXY_US: 'socks5://user:password@proxy.example:80' }),
|
|
47
|
+
/must not contain embedded proxy credentials/,
|
|
48
|
+
);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('requires a protocol', () => {
|
|
52
|
+
assert.throws(
|
|
53
|
+
() => buildProxyConfig('gb', { REGIONAL_PROXY_GB: 'uks.socks.duckduckgo.com', ...credentials }),
|
|
54
|
+
/must be a complete proxy URL/,
|
|
55
|
+
);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('rejects unsupported protocols', () => {
|
|
59
|
+
assert.throws(() => buildProxyConfig('gb', { REGIONAL_PROXY_GB: 'socks4://proxy.example:1080' }), /unsupported proxy protocol/);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"env": {
|
|
3
|
+
"REGIONAL_PROXY_AU": "socks5://au-proxy.example.com:1080",
|
|
4
|
+
"REGIONAL_PROXY_CA": "socks5://ca-proxy.example.com:1080",
|
|
5
|
+
"REGIONAL_PROXY_CH": "socks5://ch-proxy.example.com:1080",
|
|
6
|
+
"REGIONAL_PROXY_DE": "socks5://de-proxy.example.com:1080",
|
|
7
|
+
"REGIONAL_PROXY_DK": "socks5://dk-proxy.example.com:1080",
|
|
8
|
+
"REGIONAL_PROXY_ES": "socks5://es-proxy.example.com:1080",
|
|
9
|
+
"REGIONAL_PROXY_FR": "socks5://fr-proxy.example.com:1080",
|
|
10
|
+
"REGIONAL_PROXY_GB": "socks5://gb-proxy.example.com:1080",
|
|
11
|
+
"REGIONAL_PROXY_IT": "socks5://it-proxy.example.com:1080",
|
|
12
|
+
"REGIONAL_PROXY_JP": "socks5://jp-proxy.example.com:1080",
|
|
13
|
+
"REGIONAL_PROXY_NL": "socks5://nl-proxy.example.com:1080",
|
|
14
|
+
"REGIONAL_PROXY_NO": "socks5://no-proxy.example.com:1080",
|
|
15
|
+
"REGIONAL_PROXY_PL": "socks5://pl-proxy.example.com:1080",
|
|
16
|
+
"REGIONAL_PROXY_SE": "socks5://se-proxy.example.com:1080",
|
|
17
|
+
"REGIONAL_PROXY_US": "socks5://us-proxy.example.com:1080",
|
|
18
|
+
"REGIONAL_PROXY_USERNAME": "OPTIONAL_PROXY_USERNAME",
|
|
19
|
+
"REGIONAL_PROXY_PASSWORD": "OPTIONAL_PROXY_PASSWORD",
|
|
20
|
+
"PUBLICWWW_KEY": "REPLACE_WITH_YOUR_KEY"
|
|
21
|
+
}
|
|
22
|
+
}
|
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,38 @@
|
|
|
1
|
+
# v16.43.0 (Tue Sep 29 2026)
|
|
2
|
+
|
|
3
|
+
#### Rules
|
|
4
|
+
|
|
5
|
+
- Fix Sourcepoint scroll position restoration on back navigation [#1578](https://github.com/duckduckgo/autoconsent/pull/1578) ([@muodov](https://github.com/muodov))
|
|
6
|
+
|
|
7
|
+
#### AI / Agent Workflow
|
|
8
|
+
|
|
9
|
+
- Add Claude Code user settings template for agent skill env vars [#1579](https://github.com/duckduckgo/autoconsent/pull/1579) ([@muodov](https://github.com/muodov))
|
|
10
|
+
|
|
11
|
+
#### Authors: 1
|
|
12
|
+
|
|
13
|
+
- Maxim Tsoy ([@muodov](https://github.com/muodov))
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
# v16.42.0 (Fri Sep 25 2026)
|
|
18
|
+
|
|
19
|
+
#### Rules
|
|
20
|
+
|
|
21
|
+
- Rule update: CPM crawl cluster #90: mediaset.it (iubenda|inert, 13 sites) [#1484](https://github.com/duckduckgo/autoconsent/pull/1484) ([@cursoragent](https://github.com/cursoragent) [@daxtheduck](https://github.com/daxtheduck))
|
|
22
|
+
|
|
23
|
+
#### AI / Agent Workflow
|
|
24
|
+
|
|
25
|
+
- update proxy skill to support internal access [#1577](https://github.com/duckduckgo/autoconsent/pull/1577) ([@ladamski](https://github.com/ladamski) [@muodov](https://github.com/muodov))
|
|
26
|
+
|
|
27
|
+
#### Authors: 4
|
|
28
|
+
|
|
29
|
+
- Cursor Agent ([@cursoragent](https://github.com/cursoragent))
|
|
30
|
+
- Dax ([@daxtheduck](https://github.com/daxtheduck))
|
|
31
|
+
- Lucas Adamski ([@ladamski](https://github.com/ladamski))
|
|
32
|
+
- Maxim Tsoy ([@muodov](https://github.com/muodov))
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
1
36
|
# v16.41.0 (Tue Sep 22 2026)
|
|
2
37
|
|
|
3
38
|
#### Rules
|
|
@@ -157,6 +157,24 @@
|
|
|
157
157
|
});
|
|
158
158
|
return true;
|
|
159
159
|
},
|
|
160
|
+
EVAL_SOURCEPOINT_RESTORE_SCROLL: () => {
|
|
161
|
+
const root = document.documentElement;
|
|
162
|
+
const saved = root.dataset.previousScrollY;
|
|
163
|
+
if (saved && saved !== "null") {
|
|
164
|
+
root.dataset.previousScrollY = "null";
|
|
165
|
+
const y = -parseInt(saved, 10);
|
|
166
|
+
if (y > 0 && window.scrollY === 0) {
|
|
167
|
+
const behavior = root.style.scrollBehavior;
|
|
168
|
+
root.style.scrollBehavior = "auto";
|
|
169
|
+
window.scrollTo(0, y);
|
|
170
|
+
root.style.scrollBehavior = behavior;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
window.addEventListener("pagehide", () => {
|
|
174
|
+
if (root.dataset.previousScrollY) root.dataset.previousScrollY = "null";
|
|
175
|
+
});
|
|
176
|
+
return true;
|
|
177
|
+
},
|
|
160
178
|
EVAL_STEAMPOWERED_0: () => JSON.parse(
|
|
161
179
|
decodeURIComponent(
|
|
162
180
|
document.cookie.split(";").find((s) => s.trim().startsWith("cookieSettings")).split("=")[1]
|