@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
@@ -0,0 +1,17 @@
1
+ import { AutoConsent } from './base';
2
+ import TrustArc from './trustarc';
3
+ import CookieBot from './cookiebot';
4
+ import SourcePoint from './sourcepoint';
5
+ import ContentManager from './consentmanager';
6
+ import Evidon from './evidon';
7
+ const rules = [
8
+ new TrustArc(),
9
+ new CookieBot(),
10
+ new SourcePoint(),
11
+ new ContentManager(),
12
+ new Evidon(),
13
+ ];
14
+ export function createAutoCMP(config) {
15
+ return new AutoConsent(config);
16
+ }
17
+ export default rules;
@@ -0,0 +1,21 @@
1
+ import { AutoConsent } from './base';
2
+ import TrustArc from './trustarc';
3
+ import CookieBot from './cookiebot';
4
+ import SourcePoint from './sourcepoint';
5
+ import ContentManager from './consentmanager';
6
+ import Evidon from './evidon';
7
+ import { AutoConsentCMPRule } from '../rules';
8
+
9
+ const rules = [
10
+ new TrustArc(),
11
+ new CookieBot(),
12
+ new SourcePoint(),
13
+ new ContentManager(),
14
+ new Evidon(),
15
+ ];
16
+
17
+ export function createAutoCMP(config: AutoConsentCMPRule): AutoConsent {
18
+ return new AutoConsent(config);
19
+ }
20
+
21
+ export default rules;
@@ -0,0 +1,170 @@
1
+ /* eslint-disable no-restricted-syntax,no-await-in-loop,no-underscore-dangle */
2
+ export async function waitFor(predicate, maxTimes, interval) {
3
+ let result = await predicate();
4
+ if (!result && maxTimes > 0) {
5
+ return new Promise((resolve) => {
6
+ setTimeout(async () => {
7
+ resolve(waitFor(predicate, maxTimes - 1, interval));
8
+ }, interval);
9
+ });
10
+ }
11
+ return Promise.resolve(result);
12
+ }
13
+ export async function success(action) {
14
+ const result = await action;
15
+ if (!result) {
16
+ throw new Error(`Action failed: ${action}`);
17
+ }
18
+ return result;
19
+ }
20
+ export default class AutoConsentBase {
21
+ constructor(name) {
22
+ this.hasSelfTest = true;
23
+ this.name = name;
24
+ }
25
+ detectCmp(tab) {
26
+ throw new Error('Not Implemented');
27
+ }
28
+ async detectPopup(tab) {
29
+ return false;
30
+ }
31
+ detectFrame(tab, frame) {
32
+ return false;
33
+ }
34
+ optOut(tab) {
35
+ throw new Error('Not Implemented');
36
+ }
37
+ optIn(tab) {
38
+ throw new Error('Not Implemented');
39
+ }
40
+ openCmp(tab) {
41
+ throw new Error('Not Implemented');
42
+ }
43
+ async test(tab) {
44
+ // try IAB by default
45
+ return Promise.resolve(true);
46
+ }
47
+ }
48
+ async function evaluateRule(rule, tab) {
49
+ if (rule.frame && !tab.frame) {
50
+ await waitFor(() => Promise.resolve(!!tab.frame), 10, 500);
51
+ }
52
+ const frameId = rule.frame && tab.frame ? tab.frame.id : undefined;
53
+ const results = [];
54
+ if (rule.exists) {
55
+ results.push(tab.elementExists(rule.exists, frameId));
56
+ }
57
+ if (rule.visible) {
58
+ results.push(tab.elementsAreVisible(rule.visible, rule.check, frameId));
59
+ }
60
+ if (rule.eval) {
61
+ results.push(new Promise(async (resolve) => {
62
+ // catch eval error silently
63
+ try {
64
+ resolve(await tab.eval(rule.eval, frameId));
65
+ }
66
+ catch (e) {
67
+ resolve(false);
68
+ }
69
+ }));
70
+ }
71
+ if (rule.waitFor) {
72
+ results.push(tab.waitForElement(rule.waitFor, rule.timeout || 10000, frameId));
73
+ }
74
+ if (rule.click) {
75
+ if (rule.all === true) {
76
+ results.push(tab.clickElements(rule.click, frameId));
77
+ }
78
+ else {
79
+ results.push(tab.clickElement(rule.click, frameId));
80
+ }
81
+ }
82
+ if (rule.waitForThenClick) {
83
+ results.push(tab.waitForElement(rule.waitForThenClick, rule.timeout || 10000, frameId)
84
+ .then(() => tab.clickElement(rule.waitForThenClick, frameId)));
85
+ }
86
+ if (rule.wait) {
87
+ results.push(tab.wait(rule.wait));
88
+ }
89
+ if (rule.goto) {
90
+ results.push(tab.goto(rule.goto));
91
+ }
92
+ if (rule.hide) {
93
+ results.push(tab.hideElements(rule.hide, frameId));
94
+ }
95
+ if (rule.undoHide) {
96
+ results.push(tab.undoHideElements(frameId));
97
+ }
98
+ if (rule.waitForFrame) {
99
+ results.push(waitFor(() => !!tab.frame, 40, 500));
100
+ }
101
+ // boolean and of results
102
+ return (await Promise.all(results)).reduce((a, b) => a && b, true);
103
+ }
104
+ export class AutoConsent extends AutoConsentBase {
105
+ constructor(config) {
106
+ super(config.name);
107
+ this.config = config;
108
+ }
109
+ get prehideSelectors() {
110
+ return this.config.prehideSelectors;
111
+ }
112
+ get isHidingRule() {
113
+ return this.config.isHidingRule;
114
+ }
115
+ async _runRulesParallel(tab, rules) {
116
+ const detections = await Promise.all(rules.map(rule => evaluateRule(rule, tab)));
117
+ return detections.every(r => !!r);
118
+ }
119
+ async _runRulesSequentially(tab, rules) {
120
+ for (const rule of rules) {
121
+ const result = await evaluateRule(rule, tab);
122
+ if (!result && !rule.optional) {
123
+ return false;
124
+ }
125
+ }
126
+ return true;
127
+ }
128
+ async detectCmp(tab) {
129
+ if (this.config.detectCmp) {
130
+ return this._runRulesParallel(tab, this.config.detectCmp);
131
+ }
132
+ return false;
133
+ }
134
+ async detectPopup(tab) {
135
+ if (this.config.detectPopup) {
136
+ return this._runRulesParallel(tab, this.config.detectPopup);
137
+ }
138
+ return false;
139
+ }
140
+ detectFrame(tab, frame) {
141
+ if (this.config.frame) {
142
+ return frame.url.startsWith(this.config.frame);
143
+ }
144
+ return false;
145
+ }
146
+ async optOut(tab) {
147
+ if (this.config.optOut) {
148
+ return this._runRulesSequentially(tab, this.config.optOut);
149
+ }
150
+ return false;
151
+ }
152
+ async optIn(tab) {
153
+ if (this.config.optIn) {
154
+ return this._runRulesSequentially(tab, this.config.optIn);
155
+ }
156
+ return false;
157
+ }
158
+ async openCmp(tab) {
159
+ if (this.config.openCmp) {
160
+ return this._runRulesSequentially(tab, this.config.openCmp);
161
+ }
162
+ return false;
163
+ }
164
+ async test(tab) {
165
+ if (this.config.test) {
166
+ return this._runRulesSequentially(tab, this.config.test);
167
+ }
168
+ return super.test(tab);
169
+ }
170
+ }
@@ -0,0 +1,199 @@
1
+ /* eslint-disable no-restricted-syntax,no-await-in-loop,no-underscore-dangle */
2
+
3
+ import { AutoCMP, TabActor } from "../types";
4
+ import { AutoConsentCMPRule, AutoConsentRuleStep } from "../rules";
5
+
6
+ export async function waitFor(predicate: () => Promise<boolean> | boolean, maxTimes: number, interval: number): Promise<boolean> {
7
+ let result = await predicate();
8
+ if (!result && maxTimes > 0) {
9
+ return new Promise((resolve) => {
10
+ setTimeout(async () => {
11
+ resolve(waitFor(predicate, maxTimes - 1, interval));
12
+ }, interval);
13
+ });
14
+ }
15
+ return Promise.resolve(result);
16
+ }
17
+
18
+
19
+ export async function success(action: Promise<boolean>): Promise<boolean> {
20
+ const result = await action;
21
+ if (!result) {
22
+ throw new Error(`Action failed: ${action}`)
23
+ }
24
+ return result
25
+ }
26
+
27
+
28
+ export default class AutoConsentBase implements AutoCMP {
29
+
30
+ name: string
31
+ hasSelfTest = true
32
+
33
+ constructor(name: string) {
34
+ this.name = name;
35
+ }
36
+
37
+ detectCmp(tab: TabActor): Promise<boolean> {
38
+ throw new Error('Not Implemented');
39
+ }
40
+
41
+ async detectPopup(tab: TabActor) {
42
+ return false;
43
+ }
44
+
45
+ detectFrame(tab: TabActor, frame: { url: string }) {
46
+ return false;
47
+ }
48
+
49
+ optOut(tab: TabActor): Promise<boolean> {
50
+ throw new Error('Not Implemented');
51
+ }
52
+
53
+ optIn(tab: TabActor): Promise<boolean> {
54
+ throw new Error('Not Implemented');
55
+ }
56
+
57
+ openCmp(tab: TabActor): Promise<boolean> {
58
+ throw new Error('Not Implemented');
59
+ }
60
+
61
+ async test(tab: TabActor): Promise<boolean> {
62
+ // try IAB by default
63
+ return Promise.resolve(true);
64
+ }
65
+ }
66
+
67
+ async function evaluateRule(rule: AutoConsentRuleStep, tab: TabActor) {
68
+ if (rule.frame && !tab.frame) {
69
+ await waitFor(() => Promise.resolve(!!tab.frame), 10, 500);
70
+ }
71
+ const frameId = rule.frame && tab.frame ? tab.frame.id : undefined;
72
+ const results = [];
73
+ if (rule.exists) {
74
+ results.push(tab.elementExists(rule.exists, frameId));
75
+ }
76
+ if (rule.visible) {
77
+ results.push(tab.elementsAreVisible(rule.visible, rule.check, frameId));
78
+ }
79
+ if (rule.eval) {
80
+ results.push(new Promise(async (resolve) => {
81
+ // catch eval error silently
82
+ try {
83
+ resolve(await tab.eval(rule.eval!, frameId));
84
+ } catch (e) {
85
+ resolve(false);
86
+ }
87
+ }));
88
+ }
89
+ if (rule.waitFor) {
90
+ results.push(tab.waitForElement(rule.waitFor, rule.timeout || 10000, frameId));
91
+ }
92
+ if (rule.click) {
93
+ if (rule.all === true) {
94
+ results.push(tab.clickElements(rule.click, frameId));
95
+ } else {
96
+ results.push(tab.clickElement(rule.click, frameId));
97
+ }
98
+ }
99
+ if (rule.waitForThenClick) {
100
+ results.push(tab.waitForElement(rule.waitForThenClick, rule.timeout || 10000, frameId)
101
+ .then(() => tab.clickElement(rule.waitForThenClick!, frameId)));
102
+ }
103
+ if (rule.wait) {
104
+ results.push(tab.wait(rule.wait));
105
+ }
106
+ if (rule.goto) {
107
+ results.push(tab.goto(rule.goto));
108
+ }
109
+ if (rule.hide) {
110
+ results.push(tab.hideElements(rule.hide, frameId));
111
+ }
112
+ if (rule.undoHide) {
113
+ results.push(tab.undoHideElements(frameId));
114
+ }
115
+ if (rule.waitForFrame) {
116
+ results.push(waitFor(() => !!tab.frame, 40, 500))
117
+ }
118
+ // boolean and of results
119
+ return (await Promise.all(results)).reduce((a, b) => a && b, true);
120
+ }
121
+
122
+ export class AutoConsent extends AutoConsentBase {
123
+
124
+ constructor(public config: AutoConsentCMPRule) {
125
+ super(config.name);
126
+ }
127
+
128
+ get prehideSelectors(): string[] {
129
+ return this.config.prehideSelectors;
130
+ }
131
+
132
+ get isHidingRule(): boolean {
133
+ return this.config.isHidingRule;
134
+ }
135
+
136
+ async _runRulesParallel(tab: TabActor, rules: AutoConsentRuleStep[]): Promise<boolean> {
137
+ const detections = await Promise.all(rules.map(rule => evaluateRule(rule, tab)));
138
+ return detections.every(r => !!r);
139
+ }
140
+
141
+ async _runRulesSequentially(tab: TabActor, rules: AutoConsentRuleStep[]): Promise<boolean> {
142
+ for (const rule of rules) {
143
+ const result = await evaluateRule(rule, tab);
144
+ if (!result && !rule.optional) {
145
+ return false;
146
+ }
147
+ }
148
+ return true;
149
+ }
150
+
151
+ async detectCmp(tab: TabActor) {
152
+ if (this.config.detectCmp) {
153
+ return this._runRulesParallel(tab, this.config.detectCmp);
154
+ }
155
+ return false;
156
+ }
157
+
158
+ async detectPopup(tab: TabActor) {
159
+ if (this.config.detectPopup) {
160
+ return this._runRulesParallel(tab, this.config.detectPopup);
161
+ }
162
+ return false;
163
+ }
164
+
165
+ detectFrame(tab: TabActor, frame: { url: string }) {
166
+ if (this.config.frame) {
167
+ return frame.url.startsWith(this.config.frame);
168
+ }
169
+ return false;
170
+ }
171
+
172
+ async optOut(tab: TabActor) {
173
+ if (this.config.optOut) {
174
+ return this._runRulesSequentially(tab, this.config.optOut);
175
+ }
176
+ return false;
177
+ }
178
+
179
+ async optIn(tab: TabActor) {
180
+ if (this.config.optIn) {
181
+ return this._runRulesSequentially(tab, this.config.optIn);
182
+ }
183
+ return false;
184
+ }
185
+
186
+ async openCmp(tab: TabActor) {
187
+ if (this.config.openCmp) {
188
+ return this._runRulesSequentially(tab, this.config.openCmp);
189
+ }
190
+ return false;
191
+ }
192
+
193
+ async test(tab: TabActor) {
194
+ if (this.config.test) {
195
+ return this._runRulesSequentially(tab, this.config.test);
196
+ }
197
+ return super.test(tab);
198
+ }
199
+ }
@@ -0,0 +1,31 @@
1
+ import AutoConsentBase from "./base";
2
+ // Note: JS API is also available:
3
+ // https://help.consentmanager.net/books/cmp/page/javascript-api
4
+ export default class ConsentManager extends AutoConsentBase {
5
+ constructor() {
6
+ super("consentmanager.net");
7
+ this.prehideSelectors = ["#cmpbox,#cmpbox2"];
8
+ }
9
+ detectCmp(tab) {
10
+ return tab.elementExists("#cmpbox");
11
+ }
12
+ detectPopup(tab) {
13
+ return tab.elementsAreVisible("#cmpbox .cmpmore", "any");
14
+ }
15
+ async optOut(tab) {
16
+ if (await tab.elementExists(".cmpboxbtnno")) {
17
+ return tab.clickElement(".cmpboxbtnno");
18
+ }
19
+ if (await tab.elementExists(".cmpwelcomeprpsbtn")) {
20
+ await tab.clickElements(".cmpwelcomeprpsbtn > a[aria-checked=true]");
21
+ return await tab.clickElement(".cmpboxbtnsave");
22
+ }
23
+ await tab.clickElement(".cmpboxbtncustom");
24
+ await tab.waitForElement(".cmptblbox", 2000);
25
+ await tab.clickElements(".cmptdchoice > a[aria-checked=true]");
26
+ return tab.clickElement(".cmpboxbtnyescustomchoices");
27
+ }
28
+ async optIn(tab) {
29
+ return tab.clickElement(".cmpboxbtnyes");
30
+ }
31
+ }
@@ -0,0 +1,39 @@
1
+ import AutoConsentBase from "./base";
2
+ import { TabActor } from "../types";
3
+
4
+ // Note: JS API is also available:
5
+ // https://help.consentmanager.net/books/cmp/page/javascript-api
6
+ export default class ConsentManager extends AutoConsentBase {
7
+
8
+ prehideSelectors = ["#cmpbox,#cmpbox2"]
9
+
10
+ constructor() {
11
+ super("consentmanager.net");
12
+ }
13
+
14
+ detectCmp(tab: TabActor) {
15
+ return tab.elementExists("#cmpbox");
16
+ }
17
+
18
+ detectPopup(tab: TabActor) {
19
+ return tab.elementsAreVisible("#cmpbox .cmpmore", "any");
20
+ }
21
+
22
+ async optOut(tab: TabActor) {
23
+ if (await tab.elementExists(".cmpboxbtnno")) {
24
+ return tab.clickElement(".cmpboxbtnno");
25
+ }
26
+ if (await tab.elementExists(".cmpwelcomeprpsbtn")) {
27
+ await tab.clickElements(".cmpwelcomeprpsbtn > a[aria-checked=true]");
28
+ return await tab.clickElement(".cmpboxbtnsave");
29
+ }
30
+ await tab.clickElement(".cmpboxbtncustom");
31
+ await tab.waitForElement(".cmptblbox", 2000);
32
+ await tab.clickElements(".cmptdchoice > a[aria-checked=true]");
33
+ return tab.clickElement(".cmpboxbtnyescustomchoices");
34
+ }
35
+
36
+ async optIn(tab: TabActor) {
37
+ return tab.clickElement(".cmpboxbtnyes");
38
+ }
39
+ }
@@ -0,0 +1,73 @@
1
+ import AutoConsentBase from './base';
2
+ export default class Cookiebot extends AutoConsentBase {
3
+ constructor() {
4
+ super('Cybotcookiebot');
5
+ this.prehideSelectors = ["#CybotCookiebotDialog,#dtcookie-container,#cookiebanner"];
6
+ }
7
+ async detectCmp(tab) {
8
+ try {
9
+ return await tab.eval('typeof window.CookieConsent === "object" && typeof window.CookieConsent.name === "string"');
10
+ }
11
+ catch (e) {
12
+ return false;
13
+ }
14
+ }
15
+ detectPopup(tab) {
16
+ return tab.elementExists('#CybotCookiebotDialog,#dtcookie-container,#cookiebanner');
17
+ }
18
+ async optOut(tab) {
19
+ if (await tab.elementExists('.cookie-alert-extended-detail-link')) {
20
+ await tab.clickElement('.cookie-alert-extended-detail-link');
21
+ await tab.waitForElement('.cookie-alert-configuration', 1000);
22
+ await tab.clickElements('.cookie-alert-configuration-input:checked');
23
+ return tab.clickElement('.cookie-alert-extended-button-secondary');
24
+ }
25
+ if (await tab.elementExists('#dtcookie-container')) {
26
+ return tab.clickElement('.h-dtcookie-decline');
27
+ }
28
+ if (await tab.elementExists('.cookiebot__button--settings')) {
29
+ await tab.clickElement('.cookiebot__button--settings');
30
+ }
31
+ if (await tab.elementsAreVisible('#CybotCookiebotDialogBodyButtonDecline', 'all')) {
32
+ return await tab.clickElement('#CybotCookiebotDialogBodyButtonDecline');
33
+ }
34
+ if (await tab.elementExists('.cookiebanner__link--details')) {
35
+ await tab.clickElement('.cookiebanner__link--details');
36
+ }
37
+ await tab.clickElements('.CybotCookiebotDialogBodyLevelButton:checked:enabled,input[id*="CybotCookiebotDialogBodyLevelButton"]:checked:enabled');
38
+ if (await tab.elementExists('#CybotCookiebotDialogBodyButtonDecline')) {
39
+ await tab.clickElement('#CybotCookiebotDialogBodyButtonDecline');
40
+ }
41
+ if (await tab.elementExists('input[id^=CybotCookiebotDialogBodyLevelButton]:checked')) {
42
+ await tab.clickElements('input[id^=CybotCookiebotDialogBodyLevelButton]:checked');
43
+ }
44
+ if (await tab.elementExists('#CybotCookiebotDialogBodyButtonAcceptSelected')) {
45
+ await tab.clickElement('#CybotCookiebotDialogBodyButtonAcceptSelected');
46
+ }
47
+ else {
48
+ await tab.clickElements('#CybotCookiebotDialogBodyLevelButtonAccept,#CybotCookiebotDialogBodyButtonAccept,#CybotCookiebotDialogBodyLevelButtonLevelOptinAllowallSelection');
49
+ }
50
+ // some sites have custom submit buttons with no obvious selectors. In this case we just call the submitConsent API.
51
+ if (await tab.eval('CookieConsent.hasResponse !== true')) {
52
+ await tab.eval('Cookiebot.dialog.submitConsent() || true');
53
+ await tab.wait(500);
54
+ }
55
+ return true;
56
+ }
57
+ async optIn(tab) {
58
+ if (await tab.elementExists('#dtcookie-container')) {
59
+ return tab.clickElement('.h-dtcookie-accept');
60
+ }
61
+ await tab.clickElements('.CybotCookiebotDialogBodyLevelButton:not(:checked):enabled');
62
+ await tab.clickElement('#CybotCookiebotDialogBodyLevelButtonAccept');
63
+ await tab.clickElement('#CybotCookiebotDialogBodyButtonAccept');
64
+ return true;
65
+ }
66
+ async openCmp(tab) {
67
+ await tab.eval('CookieConsent.renew() || true');
68
+ return tab.waitForElement('#CybotCookiebotDialog', 10000);
69
+ }
70
+ async test(tab) {
71
+ return tab.eval('CookieConsent.declined === true');
72
+ }
73
+ }
@@ -0,0 +1,81 @@
1
+ import AutoConsentBase from './base';
2
+ import { TabActor } from '../types';
3
+
4
+ export default class Cookiebot extends AutoConsentBase {
5
+
6
+ prehideSelectors = ["#CybotCookiebotDialog,#dtcookie-container,#cookiebanner"]
7
+
8
+ constructor() {
9
+ super('Cybotcookiebot');
10
+ }
11
+
12
+ async detectCmp(tab: TabActor) {
13
+ try {
14
+ return await tab.eval('typeof window.CookieConsent === "object" && typeof window.CookieConsent.name === "string"');
15
+ } catch (e) {
16
+ return false;
17
+ }
18
+ }
19
+
20
+ detectPopup(tab: TabActor) {
21
+ return tab.elementExists('#CybotCookiebotDialog,#dtcookie-container,#cookiebanner');
22
+ }
23
+
24
+ async optOut(tab: TabActor) {
25
+ if (await tab.elementExists('.cookie-alert-extended-detail-link')) {
26
+ await tab.clickElement('.cookie-alert-extended-detail-link');
27
+ await tab.waitForElement('.cookie-alert-configuration', 1000);
28
+ await tab.clickElements('.cookie-alert-configuration-input:checked');
29
+ return tab.clickElement('.cookie-alert-extended-button-secondary');
30
+ }
31
+ if (await tab.elementExists('#dtcookie-container')) {
32
+ return tab.clickElement('.h-dtcookie-decline');
33
+ }
34
+ if (await tab.elementExists('.cookiebot__button--settings')) {
35
+ await tab.clickElement('.cookiebot__button--settings');
36
+ }
37
+ if (await tab.elementsAreVisible('#CybotCookiebotDialogBodyButtonDecline', 'all')) {
38
+ return await tab.clickElement('#CybotCookiebotDialogBodyButtonDecline');
39
+ }
40
+ if (await tab.elementExists('.cookiebanner__link--details')) {
41
+ await tab.clickElement('.cookiebanner__link--details')
42
+ }
43
+ await tab.clickElements('.CybotCookiebotDialogBodyLevelButton:checked:enabled,input[id*="CybotCookiebotDialogBodyLevelButton"]:checked:enabled');
44
+ if (await tab.elementExists('#CybotCookiebotDialogBodyButtonDecline')) {
45
+ await tab.clickElement('#CybotCookiebotDialogBodyButtonDecline');
46
+ }
47
+ if (await tab.elementExists('input[id^=CybotCookiebotDialogBodyLevelButton]:checked')) {
48
+ await tab.clickElements('input[id^=CybotCookiebotDialogBodyLevelButton]:checked')
49
+ }
50
+ if (await tab.elementExists('#CybotCookiebotDialogBodyButtonAcceptSelected')) {
51
+ await tab.clickElement('#CybotCookiebotDialogBodyButtonAcceptSelected');
52
+ } else {
53
+ await tab.clickElements('#CybotCookiebotDialogBodyLevelButtonAccept,#CybotCookiebotDialogBodyButtonAccept,#CybotCookiebotDialogBodyLevelButtonLevelOptinAllowallSelection');
54
+ }
55
+ // some sites have custom submit buttons with no obvious selectors. In this case we just call the submitConsent API.
56
+ if (await tab.eval('CookieConsent.hasResponse !== true')) {
57
+ await tab.eval('Cookiebot.dialog.submitConsent() || true');
58
+ await tab.wait(500);
59
+ }
60
+ return true;
61
+ }
62
+
63
+ async optIn(tab: TabActor) {
64
+ if (await tab.elementExists('#dtcookie-container')) {
65
+ return tab.clickElement('.h-dtcookie-accept');
66
+ }
67
+ await tab.clickElements('.CybotCookiebotDialogBodyLevelButton:not(:checked):enabled');
68
+ await tab.clickElement('#CybotCookiebotDialogBodyLevelButtonAccept');
69
+ await tab.clickElement('#CybotCookiebotDialogBodyButtonAccept');
70
+ return true;
71
+ }
72
+
73
+ async openCmp(tab: TabActor) {
74
+ await tab.eval('CookieConsent.renew() || true');
75
+ return tab.waitForElement('#CybotCookiebotDialog', 10000);
76
+ }
77
+
78
+ async test(tab: TabActor) {
79
+ return tab.eval('CookieConsent.declined === true');
80
+ }
81
+ }
@@ -0,0 +1,26 @@
1
+ import AutoConsentBase from "./base";
2
+ // Note: JS API is also available:
3
+ // https://help.consentmanager.net/books/cmp/page/javascript-api
4
+ export default class Evidon extends AutoConsentBase {
5
+ constructor() {
6
+ super("Evidon");
7
+ }
8
+ detectCmp(tab) {
9
+ return tab.elementExists("#_evidon_banner");
10
+ }
11
+ detectPopup(tab) {
12
+ return tab.elementsAreVisible("#_evidon_banner");
13
+ }
14
+ async optOut(tab) {
15
+ if (await tab.elementExists("#_evidon-decline-button")) {
16
+ return tab.clickElement("#_evidon-decline-button");
17
+ }
18
+ tab.hideElements(["#evidon-prefdiag-overlay", "#evidon-prefdiag-background"]);
19
+ await tab.clickElement("#_evidon-option-button");
20
+ await tab.waitForElement("#evidon-prefdiag-overlay", 5000);
21
+ return tab.clickElement("#evidon-prefdiag-decline");
22
+ }
23
+ async optIn(tab) {
24
+ return tab.clickElement("#_evidon-accept-button");
25
+ }
26
+ }
@@ -0,0 +1,32 @@
1
+ import AutoConsentBase from "./base";
2
+ import { TabActor } from "../types";
3
+
4
+ // Note: JS API is also available:
5
+ // https://help.consentmanager.net/books/cmp/page/javascript-api
6
+ export default class Evidon extends AutoConsentBase {
7
+ constructor() {
8
+ super("Evidon");
9
+ }
10
+
11
+ detectCmp(tab: TabActor) {
12
+ return tab.elementExists("#_evidon_banner");
13
+ }
14
+
15
+ detectPopup(tab: TabActor) {
16
+ return tab.elementsAreVisible("#_evidon_banner");
17
+ }
18
+
19
+ async optOut(tab: TabActor) {
20
+ if (await tab.elementExists("#_evidon-decline-button")) {
21
+ return tab.clickElement("#_evidon-decline-button");
22
+ }
23
+ tab.hideElements(["#evidon-prefdiag-overlay", "#evidon-prefdiag-background"])
24
+ await tab.clickElement("#_evidon-option-button");
25
+ await tab.waitForElement("#evidon-prefdiag-overlay", 5000);
26
+ return tab.clickElement("#evidon-prefdiag-decline");
27
+ }
28
+
29
+ async optIn(tab: TabActor) {
30
+ return tab.clickElement("#_evidon-accept-button");
31
+ }
32
+ }