@duckduckgo/autoconsent 1.0.2
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/.eslintrc +12 -0
- package/Dockerfile +9 -0
- package/Jenkinsfile +50 -0
- package/LICENSE +373 -0
- package/cosmetics/rules.json +110 -0
- package/dist/autoconsent.cjs.js +1316 -0
- package/dist/autoconsent.esm.js +1308 -0
- package/dist/autoconsent.puppet.js +980 -0
- package/lib/cmps/all.js +17 -0
- package/lib/cmps/all.ts +21 -0
- package/lib/cmps/base.js +170 -0
- package/lib/cmps/base.ts +199 -0
- package/lib/cmps/consentmanager.js +31 -0
- package/lib/cmps/consentmanager.ts +39 -0
- package/lib/cmps/cookiebot.js +73 -0
- package/lib/cmps/cookiebot.ts +81 -0
- package/lib/cmps/evidon.js +26 -0
- package/lib/cmps/evidon.ts +32 -0
- package/lib/cmps/sourcepoint.js +82 -0
- package/lib/cmps/sourcepoint.ts +95 -0
- package/lib/cmps/trustarc.js +106 -0
- package/lib/cmps/trustarc.ts +147 -0
- package/lib/consentomatic/index.js +52 -0
- package/lib/consentomatic/index.ts +86 -0
- package/lib/detector.js +29 -0
- package/lib/detector.ts +30 -0
- package/lib/hider.js +13 -0
- package/lib/hider.ts +16 -0
- package/lib/index.js +4 -0
- package/lib/index.ts +6 -0
- package/lib/messages.d.ts +58 -0
- package/lib/node.js +30 -0
- package/lib/node.ts +38 -0
- package/lib/puppet/tab.js +114 -0
- package/lib/puppet/tab.ts +136 -0
- package/lib/rules.d.ts +80 -0
- package/lib/tabwrapper.js +61 -0
- package/lib/tabwrapper.ts +68 -0
- package/lib/types.d.ts +61 -0
- package/lib/web/consentomatic/index.js +188 -0
- package/lib/web/consentomatic/index.ts +249 -0
- package/lib/web/consentomatic/tools.js +177 -0
- package/lib/web/consentomatic/tools.ts +198 -0
- package/lib/web/content.js +91 -0
- package/lib/web/content.ts +83 -0
- package/lib/web/tab.js +106 -0
- package/lib/web/tab.ts +171 -0
- package/lib/web.js +90 -0
- package/lib/web.ts +109 -0
- package/package.json +41 -0
- package/playwright.config.ts +31 -0
- package/readme.md +151 -0
- package/rollup.config.js +54 -0
- package/rules/autoconsent/asus.json +7 -0
- package/rules/autoconsent/cc-banner.json +9 -0
- package/rules/autoconsent/cookie-law-info.json +14 -0
- package/rules/autoconsent/cookie-notice.json +9 -0
- package/rules/autoconsent/cookieconsent.json +9 -0
- package/rules/autoconsent/drupal.json +7 -0
- package/rules/autoconsent/eu-cookie-compliance.json +14 -0
- package/rules/autoconsent/fundingchoices.json +12 -0
- package/rules/autoconsent/hubspot.json +7 -0
- package/rules/autoconsent/klaro.json +10 -0
- package/rules/autoconsent/notice-cookie.json +9 -0
- package/rules/autoconsent/onetrust.json +24 -0
- package/rules/autoconsent/osano.json +11 -0
- package/rules/autoconsent/quantcast.json +14 -0
- package/rules/autoconsent/tealium.json +19 -0
- package/rules/autoconsent/testcmp.json +12 -0
- package/rules/build.js +63 -0
- package/rules/rules.json +3030 -0
- package/tests/asus.spec.ts +5 -0
- package/tests/ccbanner.spec.ts +11 -0
- package/tests/consentmanager.spec.ts +10 -0
- package/tests/cookiebot.spec.ts +9 -0
- package/tests/cookieconsent.spec.ts +8 -0
- package/tests/cookielawinfo.spec.ts +9 -0
- package/tests/cookienotice.spec.ts +6 -0
- package/tests/didomi.spec.ts +9 -0
- package/tests/eu-cookie-compliance-banner.spec.ts +7 -0
- package/tests/evidon.spec.ts +6 -0
- package/tests/fundingchoices.spec.ts +10 -0
- package/tests/hubspot.spec.ts +6 -0
- package/tests/klaro.spec.ts +5 -0
- package/tests/notice-cookie.spec.ts +7 -0
- package/tests/oil.spec.ts +10 -0
- package/tests/onetrust.spec.ts +15 -0
- package/tests/optanon.spec.ts +10 -0
- package/tests/osano.spec.ts +5 -0
- package/tests/quantcast.spec.ts +16 -0
- package/tests/runner.ts +61 -0
- package/tests/sourcepoint.spec.ts +17 -0
- package/tests/springer.spec.ts +11 -0
- package/tests/tealium.spec.ts +6 -0
- package/tests/testcmp.spec.ts +5 -0
- package/tests/trustarc.spec.ts +13 -0
- package/tests/wordpressgdpr.spec.ts +9 -0
- package/tsconfig.json +14 -0
- package/update_version.js +8 -0
package/lib/web.js
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import Tab from './web/tab';
|
|
2
|
+
import handleContentMessage from './web/content';
|
|
3
|
+
import TabConsent from './tabwrapper';
|
|
4
|
+
import detectDialog from './detector';
|
|
5
|
+
import { rules, createAutoCMP } from './index';
|
|
6
|
+
import { ConsentOMaticCMP } from './consentomatic/index';
|
|
7
|
+
import prehideElements from './hider';
|
|
8
|
+
export * from './index';
|
|
9
|
+
export { Tab, handleContentMessage, };
|
|
10
|
+
export default class AutoConsent {
|
|
11
|
+
constructor(browser, sendContentMessage) {
|
|
12
|
+
this.browser = browser;
|
|
13
|
+
this.sendContentMessage = sendContentMessage;
|
|
14
|
+
this.consentFrames = new Map();
|
|
15
|
+
this.tabCmps = new Map();
|
|
16
|
+
this.sendContentMessage = sendContentMessage;
|
|
17
|
+
this.rules = [...rules];
|
|
18
|
+
}
|
|
19
|
+
addCMP(config) {
|
|
20
|
+
this.rules.push(createAutoCMP(config));
|
|
21
|
+
}
|
|
22
|
+
disableCMPs(cmpNames) {
|
|
23
|
+
this.rules = this.rules.filter((cmp) => !cmpNames.includes(cmp.name));
|
|
24
|
+
}
|
|
25
|
+
addConsentomaticCMP(name, config) {
|
|
26
|
+
this.rules.push(new ConsentOMaticCMP(`com_${name}`, config));
|
|
27
|
+
}
|
|
28
|
+
createTab(tabId) {
|
|
29
|
+
return new Tab(tabId, this.consentFrames.get(tabId), this.sendContentMessage, this.browser);
|
|
30
|
+
}
|
|
31
|
+
async checkTab(tabId, prehide = true) {
|
|
32
|
+
const tab = this.createTab(tabId);
|
|
33
|
+
if (prehide) {
|
|
34
|
+
this.prehideElements(tab);
|
|
35
|
+
}
|
|
36
|
+
const consent = new TabConsent(tab, this.detectDialog(tab, 20));
|
|
37
|
+
this.tabCmps.set(tabId, consent);
|
|
38
|
+
// check tabs
|
|
39
|
+
consent.checked.then((rule) => {
|
|
40
|
+
if (this.consentFrames.has(tabId) && rule) {
|
|
41
|
+
const frame = this.consentFrames.get(tabId);
|
|
42
|
+
if (frame.type === rule.name) {
|
|
43
|
+
consent.tab.frame = frame;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
// no CMP detected, undo hiding
|
|
47
|
+
if (!rule && prehide) {
|
|
48
|
+
tab.undoHideElements();
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
return this.tabCmps.get(tabId);
|
|
52
|
+
}
|
|
53
|
+
removeTab(tabId) {
|
|
54
|
+
this.tabCmps.delete(tabId);
|
|
55
|
+
this.consentFrames.delete(tabId);
|
|
56
|
+
}
|
|
57
|
+
onFrame({ tabId, url, frameId }) {
|
|
58
|
+
// ignore main frames
|
|
59
|
+
if (frameId === 0) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
try {
|
|
63
|
+
const frame = {
|
|
64
|
+
id: frameId,
|
|
65
|
+
url: url,
|
|
66
|
+
};
|
|
67
|
+
const tab = this.createTab(tabId);
|
|
68
|
+
const frameMatch = this.rules.findIndex(r => r.detectFrame(tab, frame));
|
|
69
|
+
if (frameMatch > -1) {
|
|
70
|
+
this.consentFrames.set(tabId, {
|
|
71
|
+
type: this.rules[frameMatch].name,
|
|
72
|
+
url,
|
|
73
|
+
id: frameId,
|
|
74
|
+
});
|
|
75
|
+
if (this.tabCmps.has(tabId)) {
|
|
76
|
+
this.tabCmps.get(tabId).tab.frame = this.consentFrames.get(tabId);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
catch (e) {
|
|
81
|
+
console.error(e);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
async detectDialog(tab, retries) {
|
|
85
|
+
return detectDialog(tab, retries, this.rules);
|
|
86
|
+
}
|
|
87
|
+
async prehideElements(tab) {
|
|
88
|
+
return prehideElements(tab, this.rules);
|
|
89
|
+
}
|
|
90
|
+
}
|
package/lib/web.ts
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import Tab from './web/tab';
|
|
2
|
+
import handleContentMessage from './web/content';
|
|
3
|
+
import TabConsent from './tabwrapper';
|
|
4
|
+
import detectDialog from './detector';
|
|
5
|
+
import { rules, createAutoCMP } from './index';
|
|
6
|
+
import { Browser, MessageSender, AutoCMP, TabActor } from './types';
|
|
7
|
+
import { ConsentOMaticCMP, ConsentOMaticConfig } from './consentomatic/index';
|
|
8
|
+
import { AutoConsentCMPRule } from './rules';
|
|
9
|
+
import prehideElements from './hider';
|
|
10
|
+
|
|
11
|
+
export * from './index';
|
|
12
|
+
export {
|
|
13
|
+
Tab,
|
|
14
|
+
handleContentMessage,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default class AutoConsent {
|
|
18
|
+
consentFrames: Map<number, any> = new Map()
|
|
19
|
+
tabCmps: Map<number, TabConsent> = new Map()
|
|
20
|
+
rules: AutoCMP[]
|
|
21
|
+
|
|
22
|
+
constructor(protected browser: Browser, protected sendContentMessage: MessageSender) {
|
|
23
|
+
this.sendContentMessage = sendContentMessage;
|
|
24
|
+
this.rules = [...rules];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
addCMP(config: AutoConsentCMPRule) {
|
|
28
|
+
this.rules.push(createAutoCMP(config));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
disableCMPs(cmpNames: String[]) {
|
|
32
|
+
this.rules = this.rules.filter((cmp) => !cmpNames.includes(cmp.name))
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
addConsentomaticCMP(name: string, config: ConsentOMaticConfig) {
|
|
36
|
+
this.rules.push(new ConsentOMaticCMP(`com_${name}`, config));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
createTab(tabId: number) {
|
|
40
|
+
return new Tab(tabId,
|
|
41
|
+
this.consentFrames.get(tabId),
|
|
42
|
+
this.sendContentMessage,
|
|
43
|
+
this.browser);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async checkTab(tabId: number, prehide = true) {
|
|
47
|
+
const tab = this.createTab(tabId);
|
|
48
|
+
if (prehide) {
|
|
49
|
+
this.prehideElements(tab);
|
|
50
|
+
}
|
|
51
|
+
const consent = new TabConsent(tab, this.detectDialog(tab, 20));
|
|
52
|
+
this.tabCmps.set(tabId, consent);
|
|
53
|
+
// check tabs
|
|
54
|
+
consent.checked.then((rule) => {
|
|
55
|
+
if (this.consentFrames.has(tabId) && rule) {
|
|
56
|
+
const frame = this.consentFrames.get(tabId);
|
|
57
|
+
if (frame.type === rule.name) {
|
|
58
|
+
consent.tab.frame = frame;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// no CMP detected, undo hiding
|
|
62
|
+
if (!rule && prehide) {
|
|
63
|
+
tab.undoHideElements();
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
return this.tabCmps.get(tabId);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
removeTab(tabId: number) {
|
|
71
|
+
this.tabCmps.delete(tabId);
|
|
72
|
+
this.consentFrames.delete(tabId);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
onFrame({ tabId, url, frameId }: { tabId: number, url: string, frameId: number }) {
|
|
76
|
+
// ignore main frames
|
|
77
|
+
if (frameId === 0) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
try {
|
|
81
|
+
const frame = {
|
|
82
|
+
id: frameId,
|
|
83
|
+
url: url,
|
|
84
|
+
};
|
|
85
|
+
const tab = this.createTab(tabId);
|
|
86
|
+
const frameMatch = this.rules.findIndex(r => r.detectFrame(tab, frame));
|
|
87
|
+
if (frameMatch > -1) {
|
|
88
|
+
this.consentFrames.set(tabId, {
|
|
89
|
+
type: this.rules[frameMatch].name,
|
|
90
|
+
url,
|
|
91
|
+
id: frameId,
|
|
92
|
+
});
|
|
93
|
+
if (this.tabCmps.has(tabId)) {
|
|
94
|
+
this.tabCmps.get(tabId).tab.frame = this.consentFrames.get(tabId);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
} catch (e) {
|
|
98
|
+
console.error(e);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async detectDialog(tab: TabActor, retries: number): Promise<AutoCMP> {
|
|
103
|
+
return detectDialog(tab, retries, this.rules);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async prehideElements(tab: TabActor): Promise<void> {
|
|
107
|
+
return prehideElements(tab, this.rules);
|
|
108
|
+
}
|
|
109
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@duckduckgo/autoconsent",
|
|
3
|
+
"version": "1.0.2",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "dist/autoconsent.cjs.js",
|
|
6
|
+
"module": "dist/autoconsent.esm.js",
|
|
7
|
+
"directories": {
|
|
8
|
+
"lib": "lib"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"clean": "rm -r dist lib/**/*.js lib/*.js",
|
|
12
|
+
"build": "tsc",
|
|
13
|
+
"bundle": "rollup -c",
|
|
14
|
+
"watch": "rollup -c -w",
|
|
15
|
+
"start": "web-ext run -s ./addon --firefox firefoxdeveloperedition",
|
|
16
|
+
"test": "playwright test",
|
|
17
|
+
"test:webkit": "playwright test --project webkit",
|
|
18
|
+
"test:firefox": "playwright test --project firefox",
|
|
19
|
+
"fetch-fanboy-list": "wget https://www.fanboy.co.nz/fanboy-cookiemonster.txt",
|
|
20
|
+
"fetch-site-list": "curl https://s3.amazonaws.com/cdn.cliqz.com/re-consent/supported_sites.txt > sites.txt",
|
|
21
|
+
"build-rules": "node rules/build.js && cp rules/rules.json addon/",
|
|
22
|
+
"version": "node update_version.js && git add addon/manifest.json",
|
|
23
|
+
"vendor-copy": "mkdir -p addon/vendor && cp node_modules/mocha/mocha.* addon/vendor/ && cp node_modules/chai/chai.js addon/vendor/",
|
|
24
|
+
"prepublish": "npm run build-rules && npm run build && npm run bundle"
|
|
25
|
+
},
|
|
26
|
+
"author": "Sam Macbeth",
|
|
27
|
+
"license": "MPL-2.0",
|
|
28
|
+
"dependencies": {},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@playwright/test": "^1.17.1",
|
|
31
|
+
"@rollup/plugin-typescript": "^4.0.0",
|
|
32
|
+
"@types/chai": "^4.2.11",
|
|
33
|
+
"@types/mocha": "^8.0.0",
|
|
34
|
+
"chai": "^4.2.0",
|
|
35
|
+
"mocha": "^8.0.1",
|
|
36
|
+
"rollup": "^1.32.1",
|
|
37
|
+
"typescript": "^3.8.3",
|
|
38
|
+
"web-ext": "^4.2.0",
|
|
39
|
+
"web-ext-types": "^3.2.1"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { PlaywrightTestConfig, devices } from '@playwright/test';
|
|
2
|
+
|
|
3
|
+
const proxy = process.env.PROXY_SERVER ? { server: process.env.PROXY_SERVER } : undefined
|
|
4
|
+
|
|
5
|
+
const config: PlaywrightTestConfig = {
|
|
6
|
+
forbidOnly: !!process.env.CI,
|
|
7
|
+
retries: process.env.CI ? 2 : 0,
|
|
8
|
+
testDir: 'tests',
|
|
9
|
+
use: {
|
|
10
|
+
trace: 'on-first-retry',
|
|
11
|
+
},
|
|
12
|
+
projects: [
|
|
13
|
+
{
|
|
14
|
+
name: 'webkit',
|
|
15
|
+
use: {
|
|
16
|
+
...devices['Desktop Safari'],
|
|
17
|
+
proxy,
|
|
18
|
+
screenshot: 'only-on-failure',
|
|
19
|
+
userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.1 Safari/605.1.15',
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
name: 'firefox',
|
|
24
|
+
use: {
|
|
25
|
+
...devices['Desktop Firefox'],
|
|
26
|
+
proxy,
|
|
27
|
+
},
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
};
|
|
31
|
+
export default config;
|
package/readme.md
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
## Autoconsent
|
|
2
|
+
|
|
3
|
+
This is a library of rules for navigating through common consent popups on the web. These rules
|
|
4
|
+
can be run in a Firefox webextension, or in a puppeteer orchestrated headless browser. Using
|
|
5
|
+
these rules, opt-in and opt-out options can be selected automatically, without requiring
|
|
6
|
+
user-input.
|
|
7
|
+
|
|
8
|
+
### Install Standalone
|
|
9
|
+
|
|
10
|
+
The standalone addon can be built with the following steps:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
# Download dependencies
|
|
14
|
+
npm ci
|
|
15
|
+
# Build JS bundles
|
|
16
|
+
npm run bundle
|
|
17
|
+
# Build consent ruleset
|
|
18
|
+
npm run build-rules
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The standalone addon can be found in the `addon` directory and can be run with `npm start`.
|
|
22
|
+
Alternatively, you can use `web-ext build -s addon/` to generate a packaged addon that can
|
|
23
|
+
be installed in an existing Firefox profile.
|
|
24
|
+
|
|
25
|
+
### Rules
|
|
26
|
+
|
|
27
|
+
The library's functionality is implemented as a set of rules that define how to manage consent on
|
|
28
|
+
a subset of sites. These generally correspond to specific Consent Management Providers (CMPs)
|
|
29
|
+
that are installed on multiple sites. Each CMP ruleset defines:
|
|
30
|
+
|
|
31
|
+
* If the site is using that CMP
|
|
32
|
+
* If a popup is displayed
|
|
33
|
+
* Steps to specify an 'opt-in' or 'opt-out' consent for the CMP.
|
|
34
|
+
* Optionally, a test if the consent was correctly applied.
|
|
35
|
+
|
|
36
|
+
There are currently three ways of implementing a CMP:
|
|
37
|
+
|
|
38
|
+
1. As a [JSON ruleset](./rules/autoconsent/), intepreted by the `AutoConsent` class.
|
|
39
|
+
1. As a class implementing the `AutoCMP` interface. This enables more complex logic than the linear AutoConsent
|
|
40
|
+
rulesets allow.
|
|
41
|
+
3. As a [Consent-O-Matic](https://github.com/cavi-au/Consent-O-Matic) rule. The `ConsentOMaticCMP` class implements
|
|
42
|
+
compability with rules written for the Consent-O-Matic extension.
|
|
43
|
+
|
|
44
|
+
### Rule Syntax
|
|
45
|
+
|
|
46
|
+
An autoconsent CMP rule can be written as either:
|
|
47
|
+
* a class implementing the `AutoCMP` interface, or
|
|
48
|
+
* a JSON file adhering to the `AutoConsentCMPRule` type.
|
|
49
|
+
|
|
50
|
+
In most cases the JSON syntax should be sufficient, unless non-linear logic is required, in which case a class is required.
|
|
51
|
+
|
|
52
|
+
Both JSON and class implementations require 5 main components:
|
|
53
|
+
* `name` - to identify this CMP.
|
|
54
|
+
* `detectCMP` - which determines if this CMP is included on the page.
|
|
55
|
+
* `detectPopup` - which determines if a popup is being shown by the CMP.
|
|
56
|
+
* `optOut` - executes actions to do an 'opt-out' from the popup screen. i.e. denying all consents possible.
|
|
57
|
+
* `optIn` - execut actions for an 'opt-in' from the popup screen.
|
|
58
|
+
|
|
59
|
+
Except for `name` this are defined as a set of checks or actions on the page. In the JSON syntax this is a list of `AutoConsentRuleStep` objects. For `detect` checks, we return true for the check if all steps return true. For opt in and out, we execute actions in order, exiting if one fails. The following checks/actions are supported:
|
|
60
|
+
|
|
61
|
+
#### Element exists
|
|
62
|
+
|
|
63
|
+
```json
|
|
64
|
+
{
|
|
65
|
+
"exists": "selector"
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
Returns true if `document.querySelect(selector)` returns elements.
|
|
69
|
+
|
|
70
|
+
#### Element visible
|
|
71
|
+
|
|
72
|
+
```json
|
|
73
|
+
{
|
|
74
|
+
"visible": "selector",
|
|
75
|
+
"check": "any" | "all" | "none"
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
Returns true if an element returned from `document.querySelect(selector)` is current visible on the page. If `check` is `all`, every element must be visible. If `check` is `none`, no element should be visible.
|
|
79
|
+
|
|
80
|
+
#### Eval
|
|
81
|
+
|
|
82
|
+
```json
|
|
83
|
+
{
|
|
84
|
+
"eval": "code"
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
Evaluates `code` in the context of the page and returns the truthiness of the result.
|
|
88
|
+
|
|
89
|
+
#### Wait for element
|
|
90
|
+
|
|
91
|
+
```json
|
|
92
|
+
{
|
|
93
|
+
"waitFor": "selector",
|
|
94
|
+
"timeout": 1000
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
Waits until `selector` exists in the page. After `timeout` ms the step fails.
|
|
98
|
+
|
|
99
|
+
#### Click and element
|
|
100
|
+
```json
|
|
101
|
+
{
|
|
102
|
+
"click": "selector",
|
|
103
|
+
"all": true | false,
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
Click on an element returned by `selector`. If `all` is `true`, all matching elements are clicked.
|
|
107
|
+
|
|
108
|
+
#### Wait for then click
|
|
109
|
+
```json
|
|
110
|
+
{
|
|
111
|
+
"waitForThenClick": "selector",
|
|
112
|
+
"timeout": 1000
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
Combines `waitFor` and `click`.
|
|
116
|
+
|
|
117
|
+
#### Wait
|
|
118
|
+
```json
|
|
119
|
+
{
|
|
120
|
+
"wait": 1000,
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
Wait for the specified number of milliseconds.
|
|
124
|
+
|
|
125
|
+
#### Go to URL
|
|
126
|
+
```json
|
|
127
|
+
{
|
|
128
|
+
"goto": "url"
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
Navigate the page to the given URL.
|
|
132
|
+
|
|
133
|
+
#### Hide rule
|
|
134
|
+
```json
|
|
135
|
+
{
|
|
136
|
+
"hide": ["selector", ...]
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
Set the elements matched by the selectors to `display: none`.
|
|
140
|
+
|
|
141
|
+
#### Frames
|
|
142
|
+
|
|
143
|
+
In some cases, rules have to interact with `iframes` in the page. The CMP rule defintion can optionally include a `frame` component that should be the _prefix_ of the expected frame URL. Checks and actions can then add `"frame": true` to indicate that the check or action should be done on the iframe's document (rather than main frame).
|
|
144
|
+
|
|
145
|
+
#### Optional actions
|
|
146
|
+
|
|
147
|
+
Any rule can include the `"optional": true` to ignore failure.
|
|
148
|
+
|
|
149
|
+
### License
|
|
150
|
+
|
|
151
|
+
MPLv2.
|
package/rollup.config.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import typescript from '@rollup/plugin-typescript';
|
|
2
|
+
import pkg from './package.json';
|
|
3
|
+
|
|
4
|
+
export default [{
|
|
5
|
+
input: './lib/node.ts',
|
|
6
|
+
output: [{
|
|
7
|
+
file: 'dist/autoconsent.puppet.js',
|
|
8
|
+
format: 'cjs'
|
|
9
|
+
}],
|
|
10
|
+
plugins: [
|
|
11
|
+
typescript(),
|
|
12
|
+
]
|
|
13
|
+
}, {
|
|
14
|
+
input: './lib/web.ts',
|
|
15
|
+
output: [{
|
|
16
|
+
file: pkg.module,
|
|
17
|
+
format: 'es',
|
|
18
|
+
globals: ['browser'],
|
|
19
|
+
}, {
|
|
20
|
+
file: pkg.main,
|
|
21
|
+
format: 'cjs',
|
|
22
|
+
}],
|
|
23
|
+
plugins: [
|
|
24
|
+
typescript(),
|
|
25
|
+
]
|
|
26
|
+
}, {
|
|
27
|
+
input: './addon/background.ts',
|
|
28
|
+
output: [{
|
|
29
|
+
file: './addon/background.bundle.js',
|
|
30
|
+
format: 'iife',
|
|
31
|
+
}],
|
|
32
|
+
plugins: [
|
|
33
|
+
typescript(),
|
|
34
|
+
]
|
|
35
|
+
}, {
|
|
36
|
+
input: './addon/content.ts',
|
|
37
|
+
output: [{
|
|
38
|
+
file: './addon/content.bundle.js',
|
|
39
|
+
format: 'iife',
|
|
40
|
+
}],
|
|
41
|
+
plugins: [
|
|
42
|
+
typescript(),
|
|
43
|
+
]
|
|
44
|
+
}, {
|
|
45
|
+
input: './addon/test.ts',
|
|
46
|
+
output: [{
|
|
47
|
+
file: './addon/test.bundle.js',
|
|
48
|
+
format: 'iife',
|
|
49
|
+
external: ['chai', 'mocha']
|
|
50
|
+
}],
|
|
51
|
+
plugins: [
|
|
52
|
+
typescript(),
|
|
53
|
+
]
|
|
54
|
+
}];
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "cc_banner",
|
|
3
|
+
"prehideSelectors": [".cc_banner-wrapper"],
|
|
4
|
+
"isHidingRule": true,
|
|
5
|
+
"detectCmp": [{ "exists": ".cc_banner-wrapper" }],
|
|
6
|
+
"detectPopup": [{ "visible": ".cc_banner" }],
|
|
7
|
+
"optIn": [{ "click": ".cc_btn_accept_all" }],
|
|
8
|
+
"optOut": [{ "hide": [".cc_banner-wrapper"] }]
|
|
9
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "cookie-law-info",
|
|
3
|
+
"prehideSelectors": ["#cookie-law-info-bar"],
|
|
4
|
+
"detectCmp": [{ "exists": "#cookie-law-info-bar" }],
|
|
5
|
+
"detectPopup": [{ "visible": "#cookie-law-info-bar" }],
|
|
6
|
+
"optIn": [{ "click": "[data-cli_action=\"accept\"]" }],
|
|
7
|
+
"optOut": [
|
|
8
|
+
{ "hide": ["#cookie-law-info-bar"] },
|
|
9
|
+
{
|
|
10
|
+
"eval": "CLI.disableAllCookies() || CLI.reject_close() || true"
|
|
11
|
+
}
|
|
12
|
+
],
|
|
13
|
+
"test": [{ "eval": "document.cookie.indexOf('cookielawinfo-checkbox-non-necessary=yes') === -1" }]
|
|
14
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "cookie-notice",
|
|
3
|
+
"prehideSelectors": ["#cookie-notice"],
|
|
4
|
+
"isHidingRule": true,
|
|
5
|
+
"detectCmp": [{ "exists": "#cookie-notice" }],
|
|
6
|
+
"detectPopup": [{ "visible": "#cookie-notice" }],
|
|
7
|
+
"optIn": [{ "hide": ["#cn-accept-cookie"] }],
|
|
8
|
+
"optOut": [{ "hide": ["#cookie-notice"] }]
|
|
9
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "cookieconsent",
|
|
3
|
+
"prehideSelectors": ["[aria-label=\"cookieconsent\"]"],
|
|
4
|
+
"isHidingRule": true,
|
|
5
|
+
"detectCmp": [{ "exists": "[aria-label=\"cookieconsent\"]" }],
|
|
6
|
+
"detectPopup": [{ "visible": "[aria-label=\"cookieconsent\"]" }],
|
|
7
|
+
"optIn": [{ "click": ".cc-dismiss" }],
|
|
8
|
+
"optOut": [{ "hide": ["[aria-label=\"cookieconsent\"]"] }]
|
|
9
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "eu-cookie-compliance-banner",
|
|
3
|
+
"isHidingRule": true,
|
|
4
|
+
"detectCmp": [{ "exists": ".eu-cookie-compliance-banner-info" }],
|
|
5
|
+
"detectPopup": [{ "visible": ".eu-cookie-compliance-banner-info" }],
|
|
6
|
+
"optIn": [{ "click": ".agree-button" }],
|
|
7
|
+
"optOut": [
|
|
8
|
+
{ "click": ".decline-button,.eu-cookie-compliance-save-preferences-button", "optional": true },
|
|
9
|
+
{ "hide": [".eu-cookie-compliance-banner-info", "#sliding-popup"] }
|
|
10
|
+
],
|
|
11
|
+
"test": [
|
|
12
|
+
{ "eval": "document.cookie.indexOf('cookie-agreed=2') === -1" }
|
|
13
|
+
]
|
|
14
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "funding-choices",
|
|
3
|
+
"prehideSelectors": [".fc-consent-root,.fc-dialog-container,.fc-dialog-overlay,.fc-dialog-content"],
|
|
4
|
+
"detectCmp": [{ "exists": ".fc-consent-root" }],
|
|
5
|
+
"detectPopup": [{ "exists": ".fc-dialog-container" }],
|
|
6
|
+
"optOut": [
|
|
7
|
+
{ "click": ".fc-cta-do-not-consent,.fc-cta-manage-options" },
|
|
8
|
+
{ "click": ".fc-preference-consent:checked,.fc-preference-legitimate-interest:checked", "all": true, "optional": true },
|
|
9
|
+
{ "click": ".fc-confirm-choices", "optional": true }
|
|
10
|
+
],
|
|
11
|
+
"optIn": [{ "click": ".fc-cta-consent" }]
|
|
12
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "klaro",
|
|
3
|
+
"detectCmp": [{ "exists": ".klaro > .cookie-notice" }],
|
|
4
|
+
"detectPopup": [{ "visible": ".klaro > .cookie-notice" }],
|
|
5
|
+
"optIn": [{ "click": ".cm-btn-success" }],
|
|
6
|
+
"optOut": [{ "click": ".cn-decline" }],
|
|
7
|
+
"test": [
|
|
8
|
+
{ "eval": "Object.values(klaro.getManager().consents).every(c => !c)" }
|
|
9
|
+
]
|
|
10
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "notice-cookie",
|
|
3
|
+
"prehideSelectors": [".button--notice"],
|
|
4
|
+
"isHidingRule": true,
|
|
5
|
+
"detectCmp": [{ "exists": ".notice--cookie" }],
|
|
6
|
+
"detectPopup": [{ "visible": ".notice--cookie" }],
|
|
7
|
+
"optIn": [{ "click": ".button--notice" }],
|
|
8
|
+
"optOut": [{ "hide": [".notice--cookie"] }]
|
|
9
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Onetrust",
|
|
3
|
+
"prehideSelectors": ["#onetrust-banner-sdk,#onetrust-consent-sdk,.optanon-alert-box-wrapper,.onetrust-pc-dark-filter,.js-consent-banner"],
|
|
4
|
+
"isHidingRule": true,
|
|
5
|
+
"detectCmp": [{ "exists": "#onetrust-banner-sdk,.optanon-alert-box-wrapper" }],
|
|
6
|
+
"detectPopup": [{ "visible": "#onetrust-banner-sdk,.optanon-alert-box-wrapper" }],
|
|
7
|
+
"optOut": [
|
|
8
|
+
{ "click": "#onetrust-pc-btn-handler,.ot-sdk-show-settings,button.js-cookie-settings" },
|
|
9
|
+
{ "waitFor": "#onetrust-consent-sdk", "timeout": 2000 },
|
|
10
|
+
{ "wait": 1000 },
|
|
11
|
+
{
|
|
12
|
+
"click": "#onetrust-consent-sdk input.category-switch-handler:checked,.js-editor-toggle-state:checked",
|
|
13
|
+
"all": true,
|
|
14
|
+
"optional": true
|
|
15
|
+
},
|
|
16
|
+
{ "waitForThenClick": ".save-preference-btn-handler,.js-consent-save", "timeout": 1000 }
|
|
17
|
+
],
|
|
18
|
+
"optIn": [{ "click": "onetrust-accept-btn-handler,js-accept-cookies" }],
|
|
19
|
+
"test": [
|
|
20
|
+
{
|
|
21
|
+
"eval": "window.OnetrustActiveGroups.split(',').filter(s => s.length > 0).length <= 1"
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "osano",
|
|
3
|
+
"prehideSelectors": [".osano-cm-window"],
|
|
4
|
+
"isHidingRule": true,
|
|
5
|
+
"detectCmp": [{ "exists": ".osano-cm-window" }],
|
|
6
|
+
"detectPopup": [{ "visible": ".osano-cm-dialog" }],
|
|
7
|
+
"optIn": [{ "click": ".osano-cm-accept-all" }],
|
|
8
|
+
"optOut": [
|
|
9
|
+
{ "hide": [".osano-cm-window"] }
|
|
10
|
+
]
|
|
11
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "quantcast",
|
|
3
|
+
"prehideSelectors": ["#qc-cmp2-main,#qc-cmp2-container"],
|
|
4
|
+
"detectCmp": [{ "exists": "#qc-cmp2-container" }],
|
|
5
|
+
"detectPopup": [{ "visible": "#qc-cmp2-ui" }],
|
|
6
|
+
"optOut": [
|
|
7
|
+
{ "click": ".qc-cmp2-summary-buttons > button[mode=\"secondary\"]" },
|
|
8
|
+
{ "waitFor": "#qc-cmp2-ui" },
|
|
9
|
+
{ "click": ".qc-cmp2-toggle-switch > button[aria-checked=\"true\"]", "all": true, "optional": true },
|
|
10
|
+
{ "click": ".qc-cmp2-main button[aria-label=\"REJECT ALL\"]", "optional": true },
|
|
11
|
+
{ "waitForThenClick": ".qc-cmp2-main button[aria-label=\"SAVE & EXIT\"],.qc-cmp2-buttons-desktop > button[mode=\"primary\"]", "timeout": 5000 }
|
|
12
|
+
],
|
|
13
|
+
"optIn": [{ "click": ".qc-cmp2-summary-buttons > button[mode=\"primary\"]" }]
|
|
14
|
+
}
|