@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.
Files changed (99) hide show
  1. package/.eslintrc +12 -0
  2. package/Dockerfile +9 -0
  3. package/Jenkinsfile +50 -0
  4. package/LICENSE +373 -0
  5. package/cosmetics/rules.json +110 -0
  6. package/dist/autoconsent.cjs.js +1316 -0
  7. package/dist/autoconsent.esm.js +1308 -0
  8. package/dist/autoconsent.puppet.js +980 -0
  9. package/lib/cmps/all.js +17 -0
  10. package/lib/cmps/all.ts +21 -0
  11. package/lib/cmps/base.js +170 -0
  12. package/lib/cmps/base.ts +199 -0
  13. package/lib/cmps/consentmanager.js +31 -0
  14. package/lib/cmps/consentmanager.ts +39 -0
  15. package/lib/cmps/cookiebot.js +73 -0
  16. package/lib/cmps/cookiebot.ts +81 -0
  17. package/lib/cmps/evidon.js +26 -0
  18. package/lib/cmps/evidon.ts +32 -0
  19. package/lib/cmps/sourcepoint.js +82 -0
  20. package/lib/cmps/sourcepoint.ts +95 -0
  21. package/lib/cmps/trustarc.js +106 -0
  22. package/lib/cmps/trustarc.ts +147 -0
  23. package/lib/consentomatic/index.js +52 -0
  24. package/lib/consentomatic/index.ts +86 -0
  25. package/lib/detector.js +29 -0
  26. package/lib/detector.ts +30 -0
  27. package/lib/hider.js +13 -0
  28. package/lib/hider.ts +16 -0
  29. package/lib/index.js +4 -0
  30. package/lib/index.ts +6 -0
  31. package/lib/messages.d.ts +58 -0
  32. package/lib/node.js +30 -0
  33. package/lib/node.ts +38 -0
  34. package/lib/puppet/tab.js +114 -0
  35. package/lib/puppet/tab.ts +136 -0
  36. package/lib/rules.d.ts +80 -0
  37. package/lib/tabwrapper.js +61 -0
  38. package/lib/tabwrapper.ts +68 -0
  39. package/lib/types.d.ts +61 -0
  40. package/lib/web/consentomatic/index.js +188 -0
  41. package/lib/web/consentomatic/index.ts +249 -0
  42. package/lib/web/consentomatic/tools.js +177 -0
  43. package/lib/web/consentomatic/tools.ts +198 -0
  44. package/lib/web/content.js +91 -0
  45. package/lib/web/content.ts +83 -0
  46. package/lib/web/tab.js +106 -0
  47. package/lib/web/tab.ts +171 -0
  48. package/lib/web.js +90 -0
  49. package/lib/web.ts +109 -0
  50. package/package.json +41 -0
  51. package/playwright.config.ts +31 -0
  52. package/readme.md +151 -0
  53. package/rollup.config.js +54 -0
  54. package/rules/autoconsent/asus.json +7 -0
  55. package/rules/autoconsent/cc-banner.json +9 -0
  56. package/rules/autoconsent/cookie-law-info.json +14 -0
  57. package/rules/autoconsent/cookie-notice.json +9 -0
  58. package/rules/autoconsent/cookieconsent.json +9 -0
  59. package/rules/autoconsent/drupal.json +7 -0
  60. package/rules/autoconsent/eu-cookie-compliance.json +14 -0
  61. package/rules/autoconsent/fundingchoices.json +12 -0
  62. package/rules/autoconsent/hubspot.json +7 -0
  63. package/rules/autoconsent/klaro.json +10 -0
  64. package/rules/autoconsent/notice-cookie.json +9 -0
  65. package/rules/autoconsent/onetrust.json +24 -0
  66. package/rules/autoconsent/osano.json +11 -0
  67. package/rules/autoconsent/quantcast.json +14 -0
  68. package/rules/autoconsent/tealium.json +19 -0
  69. package/rules/autoconsent/testcmp.json +12 -0
  70. package/rules/build.js +63 -0
  71. package/rules/rules.json +3030 -0
  72. package/tests/asus.spec.ts +5 -0
  73. package/tests/ccbanner.spec.ts +11 -0
  74. package/tests/consentmanager.spec.ts +10 -0
  75. package/tests/cookiebot.spec.ts +9 -0
  76. package/tests/cookieconsent.spec.ts +8 -0
  77. package/tests/cookielawinfo.spec.ts +9 -0
  78. package/tests/cookienotice.spec.ts +6 -0
  79. package/tests/didomi.spec.ts +9 -0
  80. package/tests/eu-cookie-compliance-banner.spec.ts +7 -0
  81. package/tests/evidon.spec.ts +6 -0
  82. package/tests/fundingchoices.spec.ts +10 -0
  83. package/tests/hubspot.spec.ts +6 -0
  84. package/tests/klaro.spec.ts +5 -0
  85. package/tests/notice-cookie.spec.ts +7 -0
  86. package/tests/oil.spec.ts +10 -0
  87. package/tests/onetrust.spec.ts +15 -0
  88. package/tests/optanon.spec.ts +10 -0
  89. package/tests/osano.spec.ts +5 -0
  90. package/tests/quantcast.spec.ts +16 -0
  91. package/tests/runner.ts +61 -0
  92. package/tests/sourcepoint.spec.ts +17 -0
  93. package/tests/springer.spec.ts +11 -0
  94. package/tests/tealium.spec.ts +6 -0
  95. package/tests/testcmp.spec.ts +5 -0
  96. package/tests/trustarc.spec.ts +13 -0
  97. package/tests/wordpressgdpr.spec.ts +9 -0
  98. package/tsconfig.json +14 -0
  99. 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.
@@ -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,7 @@
1
+ {
2
+ "name": "asus",
3
+ "detectCmp": [{ "exists": "#cookie-policy-info" }],
4
+ "detectPopup": [{ "visible": "#cookie-policy-info" }],
5
+ "optIn": [{ "click": ".btn-read-ck" }],
6
+ "optOut": [{ "click": ".btn-setting" }, { "click": ".btn-save" }]
7
+ }
@@ -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,7 @@
1
+ {
2
+ "name": "Drupal",
3
+ "detectCmp": [{ "exists": "#drupalorg-crosssite-gdpr" }],
4
+ "detectPopup": [{ "visible": "#drupalorg-crosssite-gdpr" }],
5
+ "optOut": [{ "click": ".no" }],
6
+ "optIn": [{ "click": ".yes" }]
7
+ }
@@ -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,7 @@
1
+ {
2
+ "name": "hubspot",
3
+ "detectCmp": [{ "exists": "#hs-eu-cookie-confirmation" }],
4
+ "detectPopup": [{ "visible": "#hs-eu-cookie-confirmation" }],
5
+ "optIn": [{ "click": "#hs-eu-confirmation-button" }],
6
+ "optOut": [{ "click": "#hs-eu-decline-button" }]
7
+ }
@@ -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
+ }