@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
|
@@ -0,0 +1,980 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
/* eslint-disable no-restricted-syntax,no-await-in-loop,no-underscore-dangle */
|
|
6
|
+
async function waitFor(predicate, maxTimes, interval) {
|
|
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
|
+
async function success(action) {
|
|
18
|
+
const result = await action;
|
|
19
|
+
if (!result) {
|
|
20
|
+
throw new Error(`Action failed: ${action}`);
|
|
21
|
+
}
|
|
22
|
+
return result;
|
|
23
|
+
}
|
|
24
|
+
class AutoConsentBase {
|
|
25
|
+
constructor(name) {
|
|
26
|
+
this.hasSelfTest = true;
|
|
27
|
+
this.name = name;
|
|
28
|
+
}
|
|
29
|
+
detectCmp(tab) {
|
|
30
|
+
throw new Error('Not Implemented');
|
|
31
|
+
}
|
|
32
|
+
async detectPopup(tab) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
detectFrame(tab, frame) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
optOut(tab) {
|
|
39
|
+
throw new Error('Not Implemented');
|
|
40
|
+
}
|
|
41
|
+
optIn(tab) {
|
|
42
|
+
throw new Error('Not Implemented');
|
|
43
|
+
}
|
|
44
|
+
openCmp(tab) {
|
|
45
|
+
throw new Error('Not Implemented');
|
|
46
|
+
}
|
|
47
|
+
async test(tab) {
|
|
48
|
+
// try IAB by default
|
|
49
|
+
return Promise.resolve(true);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
async function evaluateRule(rule, tab) {
|
|
53
|
+
if (rule.frame && !tab.frame) {
|
|
54
|
+
await waitFor(() => Promise.resolve(!!tab.frame), 10, 500);
|
|
55
|
+
}
|
|
56
|
+
const frameId = rule.frame && tab.frame ? tab.frame.id : undefined;
|
|
57
|
+
const results = [];
|
|
58
|
+
if (rule.exists) {
|
|
59
|
+
results.push(tab.elementExists(rule.exists, frameId));
|
|
60
|
+
}
|
|
61
|
+
if (rule.visible) {
|
|
62
|
+
results.push(tab.elementsAreVisible(rule.visible, rule.check, frameId));
|
|
63
|
+
}
|
|
64
|
+
if (rule.eval) {
|
|
65
|
+
results.push(new Promise(async (resolve) => {
|
|
66
|
+
// catch eval error silently
|
|
67
|
+
try {
|
|
68
|
+
resolve(await tab.eval(rule.eval, frameId));
|
|
69
|
+
}
|
|
70
|
+
catch (e) {
|
|
71
|
+
resolve(false);
|
|
72
|
+
}
|
|
73
|
+
}));
|
|
74
|
+
}
|
|
75
|
+
if (rule.waitFor) {
|
|
76
|
+
results.push(tab.waitForElement(rule.waitFor, rule.timeout || 10000, frameId));
|
|
77
|
+
}
|
|
78
|
+
if (rule.click) {
|
|
79
|
+
if (rule.all === true) {
|
|
80
|
+
results.push(tab.clickElements(rule.click, frameId));
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
results.push(tab.clickElement(rule.click, frameId));
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (rule.waitForThenClick) {
|
|
87
|
+
results.push(tab.waitForElement(rule.waitForThenClick, rule.timeout || 10000, frameId)
|
|
88
|
+
.then(() => tab.clickElement(rule.waitForThenClick, frameId)));
|
|
89
|
+
}
|
|
90
|
+
if (rule.wait) {
|
|
91
|
+
results.push(tab.wait(rule.wait));
|
|
92
|
+
}
|
|
93
|
+
if (rule.goto) {
|
|
94
|
+
results.push(tab.goto(rule.goto));
|
|
95
|
+
}
|
|
96
|
+
if (rule.hide) {
|
|
97
|
+
results.push(tab.hideElements(rule.hide, frameId));
|
|
98
|
+
}
|
|
99
|
+
if (rule.undoHide) {
|
|
100
|
+
results.push(tab.undoHideElements(frameId));
|
|
101
|
+
}
|
|
102
|
+
if (rule.waitForFrame) {
|
|
103
|
+
results.push(waitFor(() => !!tab.frame, 40, 500));
|
|
104
|
+
}
|
|
105
|
+
// boolean and of results
|
|
106
|
+
return (await Promise.all(results)).reduce((a, b) => a && b, true);
|
|
107
|
+
}
|
|
108
|
+
class AutoConsent extends AutoConsentBase {
|
|
109
|
+
constructor(config) {
|
|
110
|
+
super(config.name);
|
|
111
|
+
this.config = config;
|
|
112
|
+
}
|
|
113
|
+
get prehideSelectors() {
|
|
114
|
+
return this.config.prehideSelectors;
|
|
115
|
+
}
|
|
116
|
+
get isHidingRule() {
|
|
117
|
+
return this.config.isHidingRule;
|
|
118
|
+
}
|
|
119
|
+
async _runRulesParallel(tab, rules) {
|
|
120
|
+
const detections = await Promise.all(rules.map(rule => evaluateRule(rule, tab)));
|
|
121
|
+
return detections.every(r => !!r);
|
|
122
|
+
}
|
|
123
|
+
async _runRulesSequentially(tab, rules) {
|
|
124
|
+
for (const rule of rules) {
|
|
125
|
+
const result = await evaluateRule(rule, tab);
|
|
126
|
+
if (!result && !rule.optional) {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
async detectCmp(tab) {
|
|
133
|
+
if (this.config.detectCmp) {
|
|
134
|
+
return this._runRulesParallel(tab, this.config.detectCmp);
|
|
135
|
+
}
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
async detectPopup(tab) {
|
|
139
|
+
if (this.config.detectPopup) {
|
|
140
|
+
return this._runRulesParallel(tab, this.config.detectPopup);
|
|
141
|
+
}
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
detectFrame(tab, frame) {
|
|
145
|
+
if (this.config.frame) {
|
|
146
|
+
return frame.url.startsWith(this.config.frame);
|
|
147
|
+
}
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
async optOut(tab) {
|
|
151
|
+
if (this.config.optOut) {
|
|
152
|
+
return this._runRulesSequentially(tab, this.config.optOut);
|
|
153
|
+
}
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
async optIn(tab) {
|
|
157
|
+
if (this.config.optIn) {
|
|
158
|
+
return this._runRulesSequentially(tab, this.config.optIn);
|
|
159
|
+
}
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
async openCmp(tab) {
|
|
163
|
+
if (this.config.openCmp) {
|
|
164
|
+
return this._runRulesSequentially(tab, this.config.openCmp);
|
|
165
|
+
}
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
async test(tab) {
|
|
169
|
+
if (this.config.test) {
|
|
170
|
+
return this._runRulesSequentially(tab, this.config.test);
|
|
171
|
+
}
|
|
172
|
+
return super.test(tab);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* This code is in most parts copied from https://github.com/cavi-au/Consent-O-Matic/blob/master/Extension/Tools.js
|
|
178
|
+
* which is licened under the MIT.
|
|
179
|
+
*/
|
|
180
|
+
class Tools {
|
|
181
|
+
static setBase(base) {
|
|
182
|
+
Tools.base = base;
|
|
183
|
+
}
|
|
184
|
+
static findElement(options, parent = null, multiple = false) {
|
|
185
|
+
let possibleTargets = null;
|
|
186
|
+
if (parent != null) {
|
|
187
|
+
possibleTargets = Array.from(parent.querySelectorAll(options.selector));
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
if (Tools.base != null) {
|
|
191
|
+
possibleTargets = Array.from(Tools.base.querySelectorAll(options.selector));
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
possibleTargets = Array.from(document.querySelectorAll(options.selector));
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
if (options.textFilter != null) {
|
|
198
|
+
possibleTargets = possibleTargets.filter(possibleTarget => {
|
|
199
|
+
let textContent = possibleTarget.textContent.toLowerCase();
|
|
200
|
+
if (Array.isArray(options.textFilter)) {
|
|
201
|
+
let foundText = false;
|
|
202
|
+
for (let text of options.textFilter) {
|
|
203
|
+
if (textContent.indexOf(text.toLowerCase()) !== -1) {
|
|
204
|
+
foundText = true;
|
|
205
|
+
break;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return foundText;
|
|
209
|
+
}
|
|
210
|
+
else if (options.textFilter != null) {
|
|
211
|
+
return textContent.indexOf(options.textFilter.toLowerCase()) !== -1;
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
if (options.styleFilters != null) {
|
|
216
|
+
possibleTargets = possibleTargets.filter(possibleTarget => {
|
|
217
|
+
let styles = window.getComputedStyle(possibleTarget);
|
|
218
|
+
let keep = true;
|
|
219
|
+
for (let styleFilter of options.styleFilters) {
|
|
220
|
+
let option = styles[styleFilter.option];
|
|
221
|
+
if (styleFilter.negated) {
|
|
222
|
+
keep = keep && option !== styleFilter.value;
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
keep = keep && option === styleFilter.value;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return keep;
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
if (options.displayFilter != null) {
|
|
232
|
+
possibleTargets = possibleTargets.filter(possibleTarget => {
|
|
233
|
+
if (options.displayFilter) {
|
|
234
|
+
//We should be displayed
|
|
235
|
+
return possibleTarget.offsetHeight !== 0;
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
//We should not be displayed
|
|
239
|
+
return possibleTarget.offsetHeight === 0;
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
if (options.iframeFilter != null) {
|
|
244
|
+
possibleTargets = possibleTargets.filter(possibleTarget => {
|
|
245
|
+
if (options.iframeFilter) {
|
|
246
|
+
//We should be inside an iframe
|
|
247
|
+
return window.location !== window.parent.location;
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
//We should not be inside an iframe
|
|
251
|
+
return window.location === window.parent.location;
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
if (options.childFilter != null) {
|
|
256
|
+
possibleTargets = possibleTargets.filter(possibleTarget => {
|
|
257
|
+
let oldBase = Tools.base;
|
|
258
|
+
Tools.setBase(possibleTarget);
|
|
259
|
+
let childResults = Tools.find(options.childFilter);
|
|
260
|
+
Tools.setBase(oldBase);
|
|
261
|
+
return childResults.target != null;
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
if (multiple) {
|
|
265
|
+
return possibleTargets;
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
if (possibleTargets.length > 1) {
|
|
269
|
+
console.warn("Multiple possible targets: ", possibleTargets, options, parent);
|
|
270
|
+
}
|
|
271
|
+
return possibleTargets[0];
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
static find(options, multiple = false) {
|
|
275
|
+
let results = [];
|
|
276
|
+
if (options.parent != null) {
|
|
277
|
+
let parent = Tools.findElement(options.parent, null, multiple);
|
|
278
|
+
if (parent != null) {
|
|
279
|
+
if (parent instanceof Array) {
|
|
280
|
+
parent.forEach(p => {
|
|
281
|
+
let targets = Tools.findElement(options.target, p, multiple);
|
|
282
|
+
if (targets instanceof Array) {
|
|
283
|
+
targets.forEach(target => {
|
|
284
|
+
results.push({
|
|
285
|
+
parent: p,
|
|
286
|
+
target: target
|
|
287
|
+
});
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
else {
|
|
291
|
+
results.push({
|
|
292
|
+
parent: p,
|
|
293
|
+
target: targets
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
return results;
|
|
298
|
+
}
|
|
299
|
+
else {
|
|
300
|
+
let targets = Tools.findElement(options.target, parent, multiple);
|
|
301
|
+
if (targets instanceof Array) {
|
|
302
|
+
targets.forEach(target => {
|
|
303
|
+
results.push({
|
|
304
|
+
parent: parent,
|
|
305
|
+
target: target
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
else {
|
|
310
|
+
results.push({
|
|
311
|
+
parent: parent,
|
|
312
|
+
target: targets
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
else {
|
|
319
|
+
let targets = Tools.findElement(options.target, null, multiple);
|
|
320
|
+
if (targets instanceof Array) {
|
|
321
|
+
targets.forEach(target => {
|
|
322
|
+
results.push({
|
|
323
|
+
parent: null,
|
|
324
|
+
target: target
|
|
325
|
+
});
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
results.push({
|
|
330
|
+
parent: null,
|
|
331
|
+
target: targets
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
if (results.length === 0) {
|
|
336
|
+
results.push({
|
|
337
|
+
parent: null,
|
|
338
|
+
target: null
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
if (multiple) {
|
|
342
|
+
return results;
|
|
343
|
+
}
|
|
344
|
+
else {
|
|
345
|
+
if (results.length !== 1) {
|
|
346
|
+
console.warn("Multiple results found, even though multiple false", results);
|
|
347
|
+
}
|
|
348
|
+
return results[0];
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
Tools.base = null;
|
|
353
|
+
|
|
354
|
+
function matches(config) {
|
|
355
|
+
const result = Tools.find(config);
|
|
356
|
+
if (config.type === "css") {
|
|
357
|
+
return !!result.target;
|
|
358
|
+
}
|
|
359
|
+
else if (config.type === "checkbox") {
|
|
360
|
+
return !!result.target && result.target.checked;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
const DEBUG = false;
|
|
365
|
+
class Tab {
|
|
366
|
+
constructor(page, url, frames) {
|
|
367
|
+
// puppeteer doesn't have tab IDs
|
|
368
|
+
this.id = 1;
|
|
369
|
+
this.page = page;
|
|
370
|
+
this.url = url;
|
|
371
|
+
this.frames = frames;
|
|
372
|
+
}
|
|
373
|
+
async elementExists(selector, frameId = 0) {
|
|
374
|
+
const elements = await this.frames[frameId].$$(selector);
|
|
375
|
+
return elements.length > 0;
|
|
376
|
+
}
|
|
377
|
+
async clickElement(selector, frameId = 0) {
|
|
378
|
+
if (await this.elementExists(selector, frameId)) {
|
|
379
|
+
try {
|
|
380
|
+
const result = await this.frames[frameId].evaluate((s) => {
|
|
381
|
+
try {
|
|
382
|
+
document.querySelector(s).click();
|
|
383
|
+
return true;
|
|
384
|
+
}
|
|
385
|
+
catch (e) {
|
|
386
|
+
return e.toString();
|
|
387
|
+
}
|
|
388
|
+
}, selector);
|
|
389
|
+
DEBUG && console.log('[click]', selector, result);
|
|
390
|
+
return result;
|
|
391
|
+
}
|
|
392
|
+
catch (e) {
|
|
393
|
+
return false;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
return false;
|
|
397
|
+
}
|
|
398
|
+
async clickElements(selector, frameId = 0) {
|
|
399
|
+
const elements = await this.frames[frameId].$$(selector);
|
|
400
|
+
await this.frames[frameId].evaluate((s) => {
|
|
401
|
+
const elem = document.querySelectorAll(s);
|
|
402
|
+
elem.forEach(e => e.click());
|
|
403
|
+
}, selector);
|
|
404
|
+
return true;
|
|
405
|
+
}
|
|
406
|
+
async elementsAreVisible(selector, check, frameId = 0) {
|
|
407
|
+
if (!await this.elementExists(selector, frameId)) {
|
|
408
|
+
return false;
|
|
409
|
+
}
|
|
410
|
+
const visible = await this.frames[frameId].$$eval(selector, (nodes) => nodes.map((n) => n.offsetParent !== null || window.getComputedStyle(n).display !== "none"));
|
|
411
|
+
if (visible.length === 0) {
|
|
412
|
+
return false;
|
|
413
|
+
}
|
|
414
|
+
else if (check === 'any') {
|
|
415
|
+
return visible.some(r => r);
|
|
416
|
+
}
|
|
417
|
+
else if (check === 'none') {
|
|
418
|
+
return visible.every(r => !r);
|
|
419
|
+
}
|
|
420
|
+
return visible.every(r => r);
|
|
421
|
+
}
|
|
422
|
+
async getAttribute(selector, attribute, frameId = 0) {
|
|
423
|
+
const elem = await this.frames[frameId].$(selector);
|
|
424
|
+
if (elem) {
|
|
425
|
+
return (await elem.getProperty(attribute)).jsonValue();
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
async eval(script, frameId = 0) {
|
|
429
|
+
const result = await this.frames[frameId].evaluate(script);
|
|
430
|
+
return result;
|
|
431
|
+
}
|
|
432
|
+
async waitForElement(selector, timeout, frameId = 0) {
|
|
433
|
+
const interval = 200;
|
|
434
|
+
const times = Math.ceil(timeout / interval);
|
|
435
|
+
return waitFor(() => this.elementExists(selector, frameId), times, interval);
|
|
436
|
+
}
|
|
437
|
+
async waitForThenClick(selector, timeout, frameId = 0) {
|
|
438
|
+
if (await this.waitForElement(selector, timeout, frameId)) {
|
|
439
|
+
return await this.clickElement(selector, frameId);
|
|
440
|
+
}
|
|
441
|
+
return false;
|
|
442
|
+
}
|
|
443
|
+
async hideElements(selectors, frameId = 0) {
|
|
444
|
+
// TODO implement this
|
|
445
|
+
return Promise.resolve(true);
|
|
446
|
+
}
|
|
447
|
+
undoHideElements(frameId) {
|
|
448
|
+
return Promise.resolve(true);
|
|
449
|
+
}
|
|
450
|
+
async goto(url) {
|
|
451
|
+
return this.page.goto(url);
|
|
452
|
+
}
|
|
453
|
+
wait(ms) {
|
|
454
|
+
return new Promise((resolve) => {
|
|
455
|
+
setTimeout(() => resolve(true), ms);
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
matches(options) {
|
|
459
|
+
const script = `(() => {
|
|
460
|
+
const Tools = ${Tools.toString()};
|
|
461
|
+
const matches = ${matches.toString()};
|
|
462
|
+
return matches(${JSON.stringify(options)})
|
|
463
|
+
})();
|
|
464
|
+
`;
|
|
465
|
+
return this.frames[0].evaluate(script);
|
|
466
|
+
}
|
|
467
|
+
executeAction(config, param) {
|
|
468
|
+
throw new Error("Method not implemented.");
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
async function detectDialog(tab, retries, rules) {
|
|
473
|
+
let breakEarly = false;
|
|
474
|
+
const found = await new Promise(async (resolve) => {
|
|
475
|
+
let earlyReturn = false;
|
|
476
|
+
await Promise.all(rules.map(async (r, index) => {
|
|
477
|
+
try {
|
|
478
|
+
if (await r.detectCmp(tab)) {
|
|
479
|
+
earlyReturn = true;
|
|
480
|
+
resolve(index);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
catch (e) {
|
|
484
|
+
breakEarly = true;
|
|
485
|
+
}
|
|
486
|
+
}));
|
|
487
|
+
if (!earlyReturn) {
|
|
488
|
+
resolve(-1);
|
|
489
|
+
}
|
|
490
|
+
});
|
|
491
|
+
if (found === -1 && retries > 0 && !breakEarly) {
|
|
492
|
+
return new Promise((resolve) => {
|
|
493
|
+
setTimeout(async () => {
|
|
494
|
+
const result = detectDialog(tab, retries - 1, rules);
|
|
495
|
+
resolve(result);
|
|
496
|
+
}, 500);
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
return found > -1 ? rules[found] : null;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
class TabConsent {
|
|
503
|
+
constructor(tab, ruleCheckPromise) {
|
|
504
|
+
this.tab = tab;
|
|
505
|
+
this.optOutStatus = null;
|
|
506
|
+
this.checked = ruleCheckPromise;
|
|
507
|
+
ruleCheckPromise.then(rule => this.rule = rule);
|
|
508
|
+
}
|
|
509
|
+
getCMPName() {
|
|
510
|
+
if (this.rule) {
|
|
511
|
+
return this.rule.name;
|
|
512
|
+
}
|
|
513
|
+
return null;
|
|
514
|
+
}
|
|
515
|
+
async isPopupOpen(retries = 1, interval = 1000) {
|
|
516
|
+
const isOpen = await this.rule.detectPopup(this.tab);
|
|
517
|
+
if (!isOpen && retries > 0) {
|
|
518
|
+
return new Promise((resolve) => setTimeout(() => resolve(this.isPopupOpen(retries - 1, interval)), interval));
|
|
519
|
+
}
|
|
520
|
+
return isOpen;
|
|
521
|
+
}
|
|
522
|
+
async doOptOut() {
|
|
523
|
+
try {
|
|
524
|
+
this.optOutStatus = await this.rule.optOut(this.tab);
|
|
525
|
+
return this.optOutStatus;
|
|
526
|
+
}
|
|
527
|
+
catch (e) {
|
|
528
|
+
this.optOutStatus = e;
|
|
529
|
+
throw e;
|
|
530
|
+
}
|
|
531
|
+
finally {
|
|
532
|
+
if (!this.rule.isHidingRule) {
|
|
533
|
+
if (this.getCMPName().startsWith('com_')) {
|
|
534
|
+
this.tab.wait(5000).then(() => this.tab.undoHideElements());
|
|
535
|
+
}
|
|
536
|
+
else {
|
|
537
|
+
await this.tab.undoHideElements();
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
async doOptIn() {
|
|
543
|
+
try {
|
|
544
|
+
return this.rule.optIn(this.tab);
|
|
545
|
+
}
|
|
546
|
+
finally {
|
|
547
|
+
if (!this.rule.isHidingRule) {
|
|
548
|
+
await this.tab.undoHideElements();
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
hasTest() {
|
|
553
|
+
return !!this.rule.hasSelfTest;
|
|
554
|
+
}
|
|
555
|
+
async testOptOutWorked() {
|
|
556
|
+
return this.rule.test(this.tab);
|
|
557
|
+
}
|
|
558
|
+
async applyCosmetics(selectors) {
|
|
559
|
+
const hidden = await this.tab.hideElements(selectors);
|
|
560
|
+
return hidden;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
class TrustArc extends AutoConsentBase {
|
|
565
|
+
constructor() {
|
|
566
|
+
super("TrustArc");
|
|
567
|
+
this.prehideSelectors = [
|
|
568
|
+
".trustarc-banner-container",
|
|
569
|
+
".truste_popframe,.truste_overlay,.truste_box_overlay,#truste-consent-track",
|
|
570
|
+
];
|
|
571
|
+
}
|
|
572
|
+
detectFrame(_, frame) {
|
|
573
|
+
return frame.url.startsWith("https://consent-pref.trustarc.com/?");
|
|
574
|
+
}
|
|
575
|
+
async detectCmp(tab) {
|
|
576
|
+
if (tab.frame &&
|
|
577
|
+
tab.frame.url.startsWith("https://consent-pref.trustarc.com/?")) {
|
|
578
|
+
return true;
|
|
579
|
+
}
|
|
580
|
+
return tab.elementExists("#truste-show-consent");
|
|
581
|
+
}
|
|
582
|
+
async detectPopup(tab) {
|
|
583
|
+
return ((await tab.elementsAreVisible("#truste-consent-content,#trustarc-banner-overlay")) ||
|
|
584
|
+
(tab.frame &&
|
|
585
|
+
(await tab.waitForElement("#defaultpreferencemanager", 5000, tab.frame.id))));
|
|
586
|
+
}
|
|
587
|
+
async openFrame(tab) {
|
|
588
|
+
if (await tab.elementExists("#truste-show-consent")) {
|
|
589
|
+
await tab.clickElement("#truste-show-consent");
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
async navigateToSettings(tab, frameId) {
|
|
593
|
+
// wait for it to load
|
|
594
|
+
await waitFor(async () => {
|
|
595
|
+
return ((await tab.elementExists(".shp", frameId)) ||
|
|
596
|
+
(await tab.elementsAreVisible(".advance", "any", frameId)) ||
|
|
597
|
+
tab.elementExists(".switch span:first-child", frameId));
|
|
598
|
+
}, 10, 500);
|
|
599
|
+
// splash screen -> hit more information
|
|
600
|
+
if (await tab.elementExists(".shp", frameId)) {
|
|
601
|
+
await tab.clickElement(".shp", frameId);
|
|
602
|
+
}
|
|
603
|
+
await tab.waitForElement(".prefPanel", 5000, frameId);
|
|
604
|
+
// go to advanced settings if not yet shown
|
|
605
|
+
if (await tab.elementsAreVisible(".advance", "any", frameId)) {
|
|
606
|
+
await tab.clickElement(".advance", frameId);
|
|
607
|
+
}
|
|
608
|
+
// takes a while to load the opt-in/opt-out buttons
|
|
609
|
+
return await waitFor(() => tab.elementsAreVisible(".switch span:first-child", "any", frameId), 5, 1000);
|
|
610
|
+
}
|
|
611
|
+
async optOut(tab) {
|
|
612
|
+
// await tab.hideElements(['.truste_overlay', '.truste_box_overlay', '.trustarc-banner', '.truste-banner']);
|
|
613
|
+
if (await tab.elementExists("#truste-consent-required")) {
|
|
614
|
+
return tab.clickElement("#truste-consent-required");
|
|
615
|
+
}
|
|
616
|
+
if (!tab.frame) {
|
|
617
|
+
await tab.clickElement("#truste-show-consent");
|
|
618
|
+
await waitFor(async () => !!tab.frame &&
|
|
619
|
+
(await tab.elementsAreVisible(".mainContent", "any", tab.frame.id)), 50, 100);
|
|
620
|
+
}
|
|
621
|
+
const frameId = tab.frame.id;
|
|
622
|
+
await waitFor(() => tab.eval("document.readyState === 'complete'", frameId), 20, 100);
|
|
623
|
+
tab.hideElements([".truste_popframe", ".truste_overlay", ".truste_box_overlay", "#truste-consent-track"]);
|
|
624
|
+
if (await tab.elementExists('.rejectAll', frameId)) {
|
|
625
|
+
return tab.clickElement('.rejectAll', frameId);
|
|
626
|
+
}
|
|
627
|
+
if (await tab.waitForElement('#catDetails0', 1000, frameId)) {
|
|
628
|
+
await tab.clickElement("#catDetails0", frameId);
|
|
629
|
+
return tab.clickElement(".submit", frameId);
|
|
630
|
+
}
|
|
631
|
+
if (await tab.elementExists(".required", frameId)) {
|
|
632
|
+
await tab.clickElement(".required", frameId);
|
|
633
|
+
}
|
|
634
|
+
else {
|
|
635
|
+
await this.navigateToSettings(tab, frameId);
|
|
636
|
+
await tab.clickElements(".switch span:nth-child(1):not(.active)", frameId);
|
|
637
|
+
await tab.clickElement(".submit", frameId);
|
|
638
|
+
}
|
|
639
|
+
try {
|
|
640
|
+
await tab.waitForThenClick("#gwt-debug-close_id", 20000, tab.frame.id);
|
|
641
|
+
}
|
|
642
|
+
catch (e) {
|
|
643
|
+
// ignore frame disappearing
|
|
644
|
+
}
|
|
645
|
+
return true;
|
|
646
|
+
}
|
|
647
|
+
async optIn(tab) {
|
|
648
|
+
if (!tab.frame) {
|
|
649
|
+
await this.openFrame(tab);
|
|
650
|
+
await waitFor(() => !!tab.frame, 10, 200);
|
|
651
|
+
}
|
|
652
|
+
const frameId = tab.frame.id;
|
|
653
|
+
await this.navigateToSettings(tab, frameId);
|
|
654
|
+
await tab.clickElements(".switch span:nth-child(2)", frameId);
|
|
655
|
+
await tab.clickElement(".submit", frameId);
|
|
656
|
+
await waitFor(() => tab.elementExists("#gwt-debug-close_id", frameId), 300, 1000);
|
|
657
|
+
await tab.clickElement("#gwt-debug-close_id", frameId);
|
|
658
|
+
return true;
|
|
659
|
+
}
|
|
660
|
+
async openCmp(tab) {
|
|
661
|
+
await tab.eval("truste.eu.clickListener()");
|
|
662
|
+
return true;
|
|
663
|
+
}
|
|
664
|
+
async test() {
|
|
665
|
+
// TODO: find out how to test TrustArc
|
|
666
|
+
return true;
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
class Cookiebot extends AutoConsentBase {
|
|
671
|
+
constructor() {
|
|
672
|
+
super('Cybotcookiebot');
|
|
673
|
+
this.prehideSelectors = ["#CybotCookiebotDialog,#dtcookie-container,#cookiebanner"];
|
|
674
|
+
}
|
|
675
|
+
async detectCmp(tab) {
|
|
676
|
+
try {
|
|
677
|
+
return await tab.eval('typeof window.CookieConsent === "object" && typeof window.CookieConsent.name === "string"');
|
|
678
|
+
}
|
|
679
|
+
catch (e) {
|
|
680
|
+
return false;
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
detectPopup(tab) {
|
|
684
|
+
return tab.elementExists('#CybotCookiebotDialog,#dtcookie-container,#cookiebanner');
|
|
685
|
+
}
|
|
686
|
+
async optOut(tab) {
|
|
687
|
+
if (await tab.elementExists('.cookie-alert-extended-detail-link')) {
|
|
688
|
+
await tab.clickElement('.cookie-alert-extended-detail-link');
|
|
689
|
+
await tab.waitForElement('.cookie-alert-configuration', 1000);
|
|
690
|
+
await tab.clickElements('.cookie-alert-configuration-input:checked');
|
|
691
|
+
return tab.clickElement('.cookie-alert-extended-button-secondary');
|
|
692
|
+
}
|
|
693
|
+
if (await tab.elementExists('#dtcookie-container')) {
|
|
694
|
+
return tab.clickElement('.h-dtcookie-decline');
|
|
695
|
+
}
|
|
696
|
+
if (await tab.elementExists('.cookiebot__button--settings')) {
|
|
697
|
+
await tab.clickElement('.cookiebot__button--settings');
|
|
698
|
+
}
|
|
699
|
+
if (await tab.elementsAreVisible('#CybotCookiebotDialogBodyButtonDecline', 'all')) {
|
|
700
|
+
return await tab.clickElement('#CybotCookiebotDialogBodyButtonDecline');
|
|
701
|
+
}
|
|
702
|
+
if (await tab.elementExists('.cookiebanner__link--details')) {
|
|
703
|
+
await tab.clickElement('.cookiebanner__link--details');
|
|
704
|
+
}
|
|
705
|
+
await tab.clickElements('.CybotCookiebotDialogBodyLevelButton:checked:enabled,input[id*="CybotCookiebotDialogBodyLevelButton"]:checked:enabled');
|
|
706
|
+
if (await tab.elementExists('#CybotCookiebotDialogBodyButtonDecline')) {
|
|
707
|
+
await tab.clickElement('#CybotCookiebotDialogBodyButtonDecline');
|
|
708
|
+
}
|
|
709
|
+
if (await tab.elementExists('input[id^=CybotCookiebotDialogBodyLevelButton]:checked')) {
|
|
710
|
+
await tab.clickElements('input[id^=CybotCookiebotDialogBodyLevelButton]:checked');
|
|
711
|
+
}
|
|
712
|
+
if (await tab.elementExists('#CybotCookiebotDialogBodyButtonAcceptSelected')) {
|
|
713
|
+
await tab.clickElement('#CybotCookiebotDialogBodyButtonAcceptSelected');
|
|
714
|
+
}
|
|
715
|
+
else {
|
|
716
|
+
await tab.clickElements('#CybotCookiebotDialogBodyLevelButtonAccept,#CybotCookiebotDialogBodyButtonAccept,#CybotCookiebotDialogBodyLevelButtonLevelOptinAllowallSelection');
|
|
717
|
+
}
|
|
718
|
+
// some sites have custom submit buttons with no obvious selectors. In this case we just call the submitConsent API.
|
|
719
|
+
if (await tab.eval('CookieConsent.hasResponse !== true')) {
|
|
720
|
+
await tab.eval('Cookiebot.dialog.submitConsent() || true');
|
|
721
|
+
await tab.wait(500);
|
|
722
|
+
}
|
|
723
|
+
return true;
|
|
724
|
+
}
|
|
725
|
+
async optIn(tab) {
|
|
726
|
+
if (await tab.elementExists('#dtcookie-container')) {
|
|
727
|
+
return tab.clickElement('.h-dtcookie-accept');
|
|
728
|
+
}
|
|
729
|
+
await tab.clickElements('.CybotCookiebotDialogBodyLevelButton:not(:checked):enabled');
|
|
730
|
+
await tab.clickElement('#CybotCookiebotDialogBodyLevelButtonAccept');
|
|
731
|
+
await tab.clickElement('#CybotCookiebotDialogBodyButtonAccept');
|
|
732
|
+
return true;
|
|
733
|
+
}
|
|
734
|
+
async openCmp(tab) {
|
|
735
|
+
await tab.eval('CookieConsent.renew() || true');
|
|
736
|
+
return tab.waitForElement('#CybotCookiebotDialog', 10000);
|
|
737
|
+
}
|
|
738
|
+
async test(tab) {
|
|
739
|
+
return tab.eval('CookieConsent.declined === true');
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
class SourcePoint extends AutoConsentBase {
|
|
744
|
+
constructor() {
|
|
745
|
+
super("Sourcepoint");
|
|
746
|
+
this.ccpaMode = false;
|
|
747
|
+
this.prehideSelectors = ["div[id^='sp_message_container_'],.message-overlay"];
|
|
748
|
+
}
|
|
749
|
+
detectFrame(_, frame) {
|
|
750
|
+
try {
|
|
751
|
+
const url = new URL(frame.url);
|
|
752
|
+
if (url.searchParams.has('message_id') && url.hostname === 'ccpa-notice.sp-prod.net') {
|
|
753
|
+
this.ccpaMode = true;
|
|
754
|
+
return true;
|
|
755
|
+
}
|
|
756
|
+
return (url.pathname === '/index.html' || url.pathname === '/privacy-manager/index.html')
|
|
757
|
+
&& url.searchParams.has('message_id') && url.searchParams.has('requestUUID');
|
|
758
|
+
}
|
|
759
|
+
catch (e) {
|
|
760
|
+
return false;
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
async detectCmp(tab) {
|
|
764
|
+
return await tab.elementExists("div[id^='sp_message_container_']") || !!tab.frame;
|
|
765
|
+
}
|
|
766
|
+
async detectPopup(tab) {
|
|
767
|
+
return await tab.elementsAreVisible("div[id^='sp_message_container_']");
|
|
768
|
+
}
|
|
769
|
+
async optIn(tab) {
|
|
770
|
+
return tab.clickElement(".sp_choice_type_11", tab.frame.id);
|
|
771
|
+
}
|
|
772
|
+
isManagerOpen(tab) {
|
|
773
|
+
return tab.frame && new URL(tab.frame.url).pathname === "/privacy-manager/index.html";
|
|
774
|
+
}
|
|
775
|
+
async optOut(tab) {
|
|
776
|
+
try {
|
|
777
|
+
tab.hideElements(["div[id^='sp_message_container_']"]);
|
|
778
|
+
if (!this.isManagerOpen(tab)) {
|
|
779
|
+
if (!await waitFor(() => !!tab.frame, 30, 100)) {
|
|
780
|
+
throw "Frame never opened";
|
|
781
|
+
}
|
|
782
|
+
if (!await tab.elementExists("button.sp_choice_type_12", tab.frame.id)) {
|
|
783
|
+
// do not sell button
|
|
784
|
+
return tab.clickElement('button.sp_choice_type_13', tab.frame.id);
|
|
785
|
+
}
|
|
786
|
+
await success(tab.clickElement("button.sp_choice_type_12", tab.frame.id));
|
|
787
|
+
await waitFor(() => new URL(tab.frame.url).pathname === "/privacy-manager/index.html", 200, 100);
|
|
788
|
+
}
|
|
789
|
+
await tab.waitForElement('.type-modal', 20000, tab.frame.id);
|
|
790
|
+
// reject all button is offered by some sites
|
|
791
|
+
try {
|
|
792
|
+
const path = await Promise.race([
|
|
793
|
+
tab.waitForElement('.sp_choice_type_REJECT_ALL', 2000, tab.frame.id).then(r => 0),
|
|
794
|
+
tab.waitForElement('.reject-toggle', 2000, tab.frame.id).then(() => 1),
|
|
795
|
+
tab.waitForElement('.pm-features', 2000, tab.frame.id).then(r => 2),
|
|
796
|
+
]);
|
|
797
|
+
if (path === 0) {
|
|
798
|
+
await tab.wait(1000);
|
|
799
|
+
return await success(tab.clickElement('.sp_choice_type_REJECT_ALL', tab.frame.id));
|
|
800
|
+
}
|
|
801
|
+
else if (path === 1) {
|
|
802
|
+
await tab.clickElement('.reject-toggle', tab.frame.id);
|
|
803
|
+
}
|
|
804
|
+
else {
|
|
805
|
+
await tab.waitForElement('.pm-features', 10000, tab.frame.id);
|
|
806
|
+
await tab.clickElements('.checked > span', tab.frame.id);
|
|
807
|
+
if (await tab.elementExists('.chevron', tab.frame.id)) {
|
|
808
|
+
await tab.clickElement('.chevron', tab.frame.id);
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
catch (e) { }
|
|
813
|
+
return await tab.clickElement('.sp_choice_type_SAVE_AND_EXIT', tab.frame.id);
|
|
814
|
+
}
|
|
815
|
+
finally {
|
|
816
|
+
tab.undoHideElements();
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
async test(tab) {
|
|
820
|
+
await tab.eval("__tcfapi('getTCData', 2, r => window.__rcsResult = r)");
|
|
821
|
+
return tab.eval("Object.values(window.__rcsResult.purpose.consents).every(c => !c)");
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
// Note: JS API is also available:
|
|
826
|
+
// https://help.consentmanager.net/books/cmp/page/javascript-api
|
|
827
|
+
class ConsentManager extends AutoConsentBase {
|
|
828
|
+
constructor() {
|
|
829
|
+
super("consentmanager.net");
|
|
830
|
+
this.prehideSelectors = ["#cmpbox,#cmpbox2"];
|
|
831
|
+
}
|
|
832
|
+
detectCmp(tab) {
|
|
833
|
+
return tab.elementExists("#cmpbox");
|
|
834
|
+
}
|
|
835
|
+
detectPopup(tab) {
|
|
836
|
+
return tab.elementsAreVisible("#cmpbox .cmpmore", "any");
|
|
837
|
+
}
|
|
838
|
+
async optOut(tab) {
|
|
839
|
+
if (await tab.elementExists(".cmpboxbtnno")) {
|
|
840
|
+
return tab.clickElement(".cmpboxbtnno");
|
|
841
|
+
}
|
|
842
|
+
if (await tab.elementExists(".cmpwelcomeprpsbtn")) {
|
|
843
|
+
await tab.clickElements(".cmpwelcomeprpsbtn > a[aria-checked=true]");
|
|
844
|
+
return await tab.clickElement(".cmpboxbtnsave");
|
|
845
|
+
}
|
|
846
|
+
await tab.clickElement(".cmpboxbtncustom");
|
|
847
|
+
await tab.waitForElement(".cmptblbox", 2000);
|
|
848
|
+
await tab.clickElements(".cmptdchoice > a[aria-checked=true]");
|
|
849
|
+
return tab.clickElement(".cmpboxbtnyescustomchoices");
|
|
850
|
+
}
|
|
851
|
+
async optIn(tab) {
|
|
852
|
+
return tab.clickElement(".cmpboxbtnyes");
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
// Note: JS API is also available:
|
|
857
|
+
// https://help.consentmanager.net/books/cmp/page/javascript-api
|
|
858
|
+
class Evidon extends AutoConsentBase {
|
|
859
|
+
constructor() {
|
|
860
|
+
super("Evidon");
|
|
861
|
+
}
|
|
862
|
+
detectCmp(tab) {
|
|
863
|
+
return tab.elementExists("#_evidon_banner");
|
|
864
|
+
}
|
|
865
|
+
detectPopup(tab) {
|
|
866
|
+
return tab.elementsAreVisible("#_evidon_banner");
|
|
867
|
+
}
|
|
868
|
+
async optOut(tab) {
|
|
869
|
+
if (await tab.elementExists("#_evidon-decline-button")) {
|
|
870
|
+
return tab.clickElement("#_evidon-decline-button");
|
|
871
|
+
}
|
|
872
|
+
tab.hideElements(["#evidon-prefdiag-overlay", "#evidon-prefdiag-background"]);
|
|
873
|
+
await tab.clickElement("#_evidon-option-button");
|
|
874
|
+
await tab.waitForElement("#evidon-prefdiag-overlay", 5000);
|
|
875
|
+
return tab.clickElement("#evidon-prefdiag-decline");
|
|
876
|
+
}
|
|
877
|
+
async optIn(tab) {
|
|
878
|
+
return tab.clickElement("#_evidon-accept-button");
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
const rules = [
|
|
883
|
+
new TrustArc(),
|
|
884
|
+
new Cookiebot(),
|
|
885
|
+
new SourcePoint(),
|
|
886
|
+
new ConsentManager(),
|
|
887
|
+
new Evidon(),
|
|
888
|
+
];
|
|
889
|
+
function createAutoCMP(config) {
|
|
890
|
+
return new AutoConsent(config);
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
const rules$1 = rules;
|
|
894
|
+
|
|
895
|
+
class ConsentOMaticCMP {
|
|
896
|
+
constructor(name, config) {
|
|
897
|
+
this.name = name;
|
|
898
|
+
this.config = config;
|
|
899
|
+
this.methods = new Map();
|
|
900
|
+
config.methods.forEach(methodConfig => {
|
|
901
|
+
if (methodConfig.action) {
|
|
902
|
+
this.methods.set(methodConfig.name, methodConfig.action);
|
|
903
|
+
}
|
|
904
|
+
});
|
|
905
|
+
this.hasSelfTest = this.methods.has("TEST_CONSENT");
|
|
906
|
+
}
|
|
907
|
+
async detectCmp(tab) {
|
|
908
|
+
return (await Promise.all(this.config.detectors.map(detectorConfig => tab.matches(detectorConfig.presentMatcher)))).some(matched => matched);
|
|
909
|
+
}
|
|
910
|
+
async detectPopup(tab) {
|
|
911
|
+
return (await Promise.all(this.config.detectors.map(detectorConfig => tab.matches(detectorConfig.showingMatcher)))).some(matched => matched);
|
|
912
|
+
}
|
|
913
|
+
async executeAction(tab, method, param) {
|
|
914
|
+
if (this.methods.has(method)) {
|
|
915
|
+
return tab.executeAction(this.methods.get(method), param);
|
|
916
|
+
}
|
|
917
|
+
return true;
|
|
918
|
+
}
|
|
919
|
+
async optOut(tab) {
|
|
920
|
+
await this.executeAction(tab, "HIDE_CMP");
|
|
921
|
+
await this.executeAction(tab, "OPEN_OPTIONS");
|
|
922
|
+
await this.executeAction(tab, "HIDE_CMP");
|
|
923
|
+
await this.executeAction(tab, "DO_CONSENT", []);
|
|
924
|
+
await this.executeAction(tab, "SAVE_CONSENT");
|
|
925
|
+
return true;
|
|
926
|
+
}
|
|
927
|
+
async optIn(tab) {
|
|
928
|
+
await this.executeAction(tab, "HIDE_CMP");
|
|
929
|
+
await this.executeAction(tab, "OPEN_OPTIONS");
|
|
930
|
+
await this.executeAction(tab, "HIDE_CMP");
|
|
931
|
+
await this.executeAction(tab, "DO_CONSENT", ['D', 'A', 'B', 'E', 'F', 'X']);
|
|
932
|
+
await this.executeAction(tab, "SAVE_CONSENT");
|
|
933
|
+
return true;
|
|
934
|
+
}
|
|
935
|
+
async openCmp(tab) {
|
|
936
|
+
await this.executeAction(tab, "HIDE_CMP");
|
|
937
|
+
await this.executeAction(tab, "OPEN_OPTIONS");
|
|
938
|
+
return true;
|
|
939
|
+
}
|
|
940
|
+
test(tab) {
|
|
941
|
+
return this.executeAction(tab, "TEST_CONSENT");
|
|
942
|
+
}
|
|
943
|
+
detectFrame(tab, frame) {
|
|
944
|
+
return false;
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
function attachToPage(page, url, rules, retries = 1) {
|
|
949
|
+
const frames = {};
|
|
950
|
+
const tab = new Tab(page, url, frames);
|
|
951
|
+
frames[0] = page.mainFrame();
|
|
952
|
+
async function onFrame(frame) {
|
|
953
|
+
const allFrames = await page.frames();
|
|
954
|
+
allFrames.forEach((frame, frameId) => {
|
|
955
|
+
const frameMatch = rules.findIndex(r => r.detectFrame(tab, {
|
|
956
|
+
url: frame.url(),
|
|
957
|
+
}));
|
|
958
|
+
if (frameMatch > -1) {
|
|
959
|
+
tab.frame = {
|
|
960
|
+
type: rules[frameMatch].name,
|
|
961
|
+
url: frame.url(),
|
|
962
|
+
id: frameId,
|
|
963
|
+
};
|
|
964
|
+
frames[frameId] = frame;
|
|
965
|
+
}
|
|
966
|
+
});
|
|
967
|
+
}
|
|
968
|
+
page.on('framenavigated', onFrame);
|
|
969
|
+
page.frames().forEach(onFrame);
|
|
970
|
+
return new TabConsent(tab, detectDialog(tab, retries, rules));
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
exports.ConsentOMaticCMP = ConsentOMaticCMP;
|
|
974
|
+
exports.Tab = Tab;
|
|
975
|
+
exports.TabConsent = TabConsent;
|
|
976
|
+
exports.attachToPage = attachToPage;
|
|
977
|
+
exports.createAutoCMP = createAutoCMP;
|
|
978
|
+
exports.detectDialog = detectDialog;
|
|
979
|
+
exports.rules = rules$1;
|
|
980
|
+
exports.waitFor = waitFor;
|