@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,1316 @@
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
+ class TabActions {
177
+ constructor(tabId, frame, sendContentMessage, browser) {
178
+ this.frame = frame;
179
+ this.sendContentMessage = sendContentMessage;
180
+ this.browser = browser;
181
+ this.id = tabId;
182
+ }
183
+ async elementExists(selector, frameId = 0) {
184
+ console.log(`check for ${selector} in tab ${this.id}, frame ${frameId}`);
185
+ return this.sendContentMessage(this.id, {
186
+ type: "elemExists",
187
+ selector
188
+ }, {
189
+ frameId
190
+ });
191
+ }
192
+ async clickElement(selector, frameId = 0) {
193
+ console.log(`click element ${selector} in tab ${this.id}`);
194
+ return this.sendContentMessage(this.id, {
195
+ type: "click",
196
+ selector
197
+ }, {
198
+ frameId
199
+ });
200
+ }
201
+ async clickElements(selector, frameId = 0) {
202
+ console.log(`click elements ${selector} in tab ${this.id}`);
203
+ return this.sendContentMessage(this.id, {
204
+ type: "click",
205
+ all: true,
206
+ selector
207
+ }, {
208
+ frameId
209
+ });
210
+ }
211
+ async elementsAreVisible(selector, check, frameId = 0) {
212
+ return this.sendContentMessage(this.id, {
213
+ type: "elemVisible",
214
+ selector,
215
+ check
216
+ }, {
217
+ frameId
218
+ });
219
+ }
220
+ async getAttribute(selector, attribute, frameId = 0) {
221
+ return this.sendContentMessage(this.id, {
222
+ type: "getAttribute",
223
+ selector,
224
+ attribute
225
+ }, { frameId });
226
+ }
227
+ async eval(script, frameId = 0) {
228
+ // console.log(`run ${script} in tab ${this.id}`);
229
+ return await this.sendContentMessage(this.id, {
230
+ type: "eval",
231
+ script
232
+ }, { frameId });
233
+ }
234
+ async waitForElement(selector, timeout, frameId = 0) {
235
+ const interval = 200;
236
+ const times = Math.ceil(timeout / interval);
237
+ return waitFor(() => this.elementExists(selector, frameId), times, interval);
238
+ }
239
+ async waitForThenClick(selector, timeout, frameId = 0) {
240
+ if (await this.waitForElement(selector, timeout, frameId)) {
241
+ return await this.clickElement(selector, frameId);
242
+ }
243
+ return false;
244
+ }
245
+ async hideElements(selectors, frameId = 0) {
246
+ return this.sendContentMessage(this.id, {
247
+ type: "hide",
248
+ selectors
249
+ }, { frameId });
250
+ }
251
+ async undoHideElements(frameId = 0) {
252
+ return this.sendContentMessage(this.id, {
253
+ type: "undohide",
254
+ }, { frameId });
255
+ }
256
+ async getBrowserTab() {
257
+ return this.browser.tabs.get(this.id);
258
+ }
259
+ async goto(url) {
260
+ return this.browser.tabs.update(this.id, { url });
261
+ }
262
+ wait(ms) {
263
+ return new Promise(resolve => {
264
+ setTimeout(() => resolve(true), ms);
265
+ });
266
+ }
267
+ matches(matcherConfig) {
268
+ return this.sendContentMessage(this.id, {
269
+ type: "matches",
270
+ config: matcherConfig
271
+ }, { frameId: 0 });
272
+ }
273
+ executeAction(config, param) {
274
+ return this.sendContentMessage(this.id, {
275
+ type: "executeAction",
276
+ config,
277
+ param
278
+ }, { frameId: 0 });
279
+ }
280
+ }
281
+
282
+ /**
283
+ * This code is in most parts copied from https://github.com/cavi-au/Consent-O-Matic/blob/master/Extension/Tools.js
284
+ * which is licened under the MIT.
285
+ */
286
+ class Tools {
287
+ static setBase(base) {
288
+ Tools.base = base;
289
+ }
290
+ static findElement(options, parent = null, multiple = false) {
291
+ let possibleTargets = null;
292
+ if (parent != null) {
293
+ possibleTargets = Array.from(parent.querySelectorAll(options.selector));
294
+ }
295
+ else {
296
+ if (Tools.base != null) {
297
+ possibleTargets = Array.from(Tools.base.querySelectorAll(options.selector));
298
+ }
299
+ else {
300
+ possibleTargets = Array.from(document.querySelectorAll(options.selector));
301
+ }
302
+ }
303
+ if (options.textFilter != null) {
304
+ possibleTargets = possibleTargets.filter(possibleTarget => {
305
+ let textContent = possibleTarget.textContent.toLowerCase();
306
+ if (Array.isArray(options.textFilter)) {
307
+ let foundText = false;
308
+ for (let text of options.textFilter) {
309
+ if (textContent.indexOf(text.toLowerCase()) !== -1) {
310
+ foundText = true;
311
+ break;
312
+ }
313
+ }
314
+ return foundText;
315
+ }
316
+ else if (options.textFilter != null) {
317
+ return textContent.indexOf(options.textFilter.toLowerCase()) !== -1;
318
+ }
319
+ });
320
+ }
321
+ if (options.styleFilters != null) {
322
+ possibleTargets = possibleTargets.filter(possibleTarget => {
323
+ let styles = window.getComputedStyle(possibleTarget);
324
+ let keep = true;
325
+ for (let styleFilter of options.styleFilters) {
326
+ let option = styles[styleFilter.option];
327
+ if (styleFilter.negated) {
328
+ keep = keep && option !== styleFilter.value;
329
+ }
330
+ else {
331
+ keep = keep && option === styleFilter.value;
332
+ }
333
+ }
334
+ return keep;
335
+ });
336
+ }
337
+ if (options.displayFilter != null) {
338
+ possibleTargets = possibleTargets.filter(possibleTarget => {
339
+ if (options.displayFilter) {
340
+ //We should be displayed
341
+ return possibleTarget.offsetHeight !== 0;
342
+ }
343
+ else {
344
+ //We should not be displayed
345
+ return possibleTarget.offsetHeight === 0;
346
+ }
347
+ });
348
+ }
349
+ if (options.iframeFilter != null) {
350
+ possibleTargets = possibleTargets.filter(possibleTarget => {
351
+ if (options.iframeFilter) {
352
+ //We should be inside an iframe
353
+ return window.location !== window.parent.location;
354
+ }
355
+ else {
356
+ //We should not be inside an iframe
357
+ return window.location === window.parent.location;
358
+ }
359
+ });
360
+ }
361
+ if (options.childFilter != null) {
362
+ possibleTargets = possibleTargets.filter(possibleTarget => {
363
+ let oldBase = Tools.base;
364
+ Tools.setBase(possibleTarget);
365
+ let childResults = Tools.find(options.childFilter);
366
+ Tools.setBase(oldBase);
367
+ return childResults.target != null;
368
+ });
369
+ }
370
+ if (multiple) {
371
+ return possibleTargets;
372
+ }
373
+ else {
374
+ if (possibleTargets.length > 1) {
375
+ console.warn("Multiple possible targets: ", possibleTargets, options, parent);
376
+ }
377
+ return possibleTargets[0];
378
+ }
379
+ }
380
+ static find(options, multiple = false) {
381
+ let results = [];
382
+ if (options.parent != null) {
383
+ let parent = Tools.findElement(options.parent, null, multiple);
384
+ if (parent != null) {
385
+ if (parent instanceof Array) {
386
+ parent.forEach(p => {
387
+ let targets = Tools.findElement(options.target, p, multiple);
388
+ if (targets instanceof Array) {
389
+ targets.forEach(target => {
390
+ results.push({
391
+ parent: p,
392
+ target: target
393
+ });
394
+ });
395
+ }
396
+ else {
397
+ results.push({
398
+ parent: p,
399
+ target: targets
400
+ });
401
+ }
402
+ });
403
+ return results;
404
+ }
405
+ else {
406
+ let targets = Tools.findElement(options.target, parent, multiple);
407
+ if (targets instanceof Array) {
408
+ targets.forEach(target => {
409
+ results.push({
410
+ parent: parent,
411
+ target: target
412
+ });
413
+ });
414
+ }
415
+ else {
416
+ results.push({
417
+ parent: parent,
418
+ target: targets
419
+ });
420
+ }
421
+ }
422
+ }
423
+ }
424
+ else {
425
+ let targets = Tools.findElement(options.target, null, multiple);
426
+ if (targets instanceof Array) {
427
+ targets.forEach(target => {
428
+ results.push({
429
+ parent: null,
430
+ target: target
431
+ });
432
+ });
433
+ }
434
+ else {
435
+ results.push({
436
+ parent: null,
437
+ target: targets
438
+ });
439
+ }
440
+ }
441
+ if (results.length === 0) {
442
+ results.push({
443
+ parent: null,
444
+ target: null
445
+ });
446
+ }
447
+ if (multiple) {
448
+ return results;
449
+ }
450
+ else {
451
+ if (results.length !== 1) {
452
+ console.warn("Multiple results found, even though multiple false", results);
453
+ }
454
+ return results[0];
455
+ }
456
+ }
457
+ }
458
+ Tools.base = null;
459
+
460
+ function matches(config) {
461
+ const result = Tools.find(config);
462
+ if (config.type === "css") {
463
+ return !!result.target;
464
+ }
465
+ else if (config.type === "checkbox") {
466
+ return !!result.target && result.target.checked;
467
+ }
468
+ }
469
+ async function executeAction(config, param) {
470
+ switch (config.type) {
471
+ case "click":
472
+ return clickAction(config);
473
+ case "list":
474
+ return listAction(config, param);
475
+ case "consent":
476
+ return consentAction(config, param);
477
+ case "ifcss":
478
+ return ifCssAction(config, param);
479
+ case "waitcss":
480
+ return waitCssAction(config);
481
+ case "foreach":
482
+ return forEachAction(config, param);
483
+ case "hide":
484
+ return hideAction(config);
485
+ case "slide":
486
+ return slideAction(config);
487
+ case "close":
488
+ return closeAction();
489
+ case "wait":
490
+ return waitAction(config);
491
+ case "eval":
492
+ return evalAction(config);
493
+ default:
494
+ throw "Unknown action type: " + config.type;
495
+ }
496
+ }
497
+ const STEP_TIMEOUT = 0;
498
+ function waitTimeout(timeout) {
499
+ return new Promise(resolve => {
500
+ setTimeout(() => {
501
+ resolve();
502
+ }, timeout);
503
+ });
504
+ }
505
+ async function clickAction(config) {
506
+ const result = Tools.find(config);
507
+ if (result.target != null) {
508
+ result.target.click();
509
+ }
510
+ return waitTimeout(STEP_TIMEOUT);
511
+ }
512
+ async function listAction(config, param) {
513
+ for (let action of config.actions) {
514
+ await executeAction(action, param);
515
+ }
516
+ }
517
+ async function consentAction(config, consentTypes) {
518
+ for (const consentConfig of config.consents) {
519
+ const shouldEnable = consentTypes.indexOf(consentConfig.type) !== -1;
520
+ if (consentConfig.matcher && consentConfig.toggleAction) {
521
+ const isEnabled = matches(consentConfig.matcher);
522
+ if (isEnabled !== shouldEnable) {
523
+ await executeAction(consentConfig.toggleAction);
524
+ }
525
+ }
526
+ else {
527
+ if (shouldEnable) {
528
+ await executeAction(consentConfig.trueAction);
529
+ }
530
+ else {
531
+ await executeAction(consentConfig.falseAction);
532
+ }
533
+ }
534
+ }
535
+ }
536
+ async function ifCssAction(config, param) {
537
+ const result = Tools.find(config);
538
+ if (!result.target) {
539
+ if (config.trueAction) {
540
+ await executeAction(config.trueAction, param);
541
+ }
542
+ }
543
+ else {
544
+ if (config.falseAction) {
545
+ await executeAction(config.falseAction, param);
546
+ }
547
+ }
548
+ }
549
+ async function waitCssAction(config) {
550
+ await new Promise(resolve => {
551
+ let numRetries = config.retries || 10;
552
+ const waitTime = config.waitTime || 250;
553
+ const checkCss = () => {
554
+ const result = Tools.find(config);
555
+ if ((config.negated && result.target) ||
556
+ (!config.negated && !result.target)) {
557
+ if (numRetries > 0) {
558
+ numRetries -= 1;
559
+ setTimeout(checkCss, waitTime);
560
+ }
561
+ else {
562
+ resolve();
563
+ }
564
+ }
565
+ else {
566
+ resolve();
567
+ }
568
+ };
569
+ checkCss();
570
+ });
571
+ }
572
+ async function forEachAction(config, param) {
573
+ const results = Tools.find(config, true);
574
+ const oldBase = Tools.base;
575
+ for (const result of results) {
576
+ if (result.target) {
577
+ Tools.setBase(result.target);
578
+ await executeAction(config.action, param);
579
+ }
580
+ }
581
+ Tools.setBase(oldBase);
582
+ }
583
+ async function hideAction(config) {
584
+ const result = Tools.find(config);
585
+ if (result.target) {
586
+ result.target.classList.add("Autoconsent-Hidden");
587
+ // result.target.setAttribute("style", "display: none;");
588
+ }
589
+ }
590
+ async function slideAction(config) {
591
+ const result = Tools.find(config);
592
+ const dragResult = Tools.find(config.dragTarget);
593
+ if (result.target) {
594
+ let targetBounds = result.target.getBoundingClientRect();
595
+ let dragTargetBounds = dragResult.target.getBoundingClientRect();
596
+ let yDiff = dragTargetBounds.top - targetBounds.top;
597
+ let xDiff = dragTargetBounds.left - targetBounds.left;
598
+ if (this.config.axis.toLowerCase() === "y") {
599
+ xDiff = 0;
600
+ }
601
+ if (this.config.axis.toLowerCase() === "x") {
602
+ yDiff = 0;
603
+ }
604
+ let screenX = window.screenX + targetBounds.left + targetBounds.width / 2.0;
605
+ let screenY = window.screenY + targetBounds.top + targetBounds.height / 2.0;
606
+ let clientX = targetBounds.left + targetBounds.width / 2.0;
607
+ let clientY = targetBounds.top + targetBounds.height / 2.0;
608
+ let mouseDown = document.createEvent("MouseEvents");
609
+ mouseDown.initMouseEvent("mousedown", true, true, window, 0, screenX, screenY, clientX, clientY, false, false, false, false, 0, result.target);
610
+ let mouseMove = document.createEvent("MouseEvents");
611
+ mouseMove.initMouseEvent("mousemove", true, true, window, 0, screenX + xDiff, screenY + yDiff, clientX + xDiff, clientY + yDiff, false, false, false, false, 0, result.target);
612
+ let mouseUp = document.createEvent("MouseEvents");
613
+ mouseUp.initMouseEvent("mouseup", true, true, window, 0, screenX + xDiff, screenY + yDiff, clientX + xDiff, clientY + yDiff, false, false, false, false, 0, result.target);
614
+ result.target.dispatchEvent(mouseDown);
615
+ await this.waitTimeout(10);
616
+ result.target.dispatchEvent(mouseMove);
617
+ await this.waitTimeout(10);
618
+ result.target.dispatchEvent(mouseUp);
619
+ }
620
+ }
621
+ async function waitAction(config) {
622
+ await waitTimeout(config.waitTime);
623
+ }
624
+ async function closeAction(config) {
625
+ window.close();
626
+ }
627
+ async function evalAction(config) {
628
+ console.log("eval!", config.code);
629
+ return new Promise(resolve => {
630
+ try {
631
+ if (config.async) {
632
+ window.eval(config.code);
633
+ setTimeout(() => {
634
+ resolve(window.eval("window.__consentCheckResult"));
635
+ }, config.timeout || 250);
636
+ }
637
+ else {
638
+ resolve(window.eval(config.code));
639
+ }
640
+ }
641
+ catch (e) {
642
+ console.warn("eval error", e, config.code);
643
+ resolve(false);
644
+ }
645
+ });
646
+ }
647
+
648
+ let actionQueue = Promise.resolve(null);
649
+ const styleOverrideElementId = "autoconsent-css-rules";
650
+ const styleSelector = `style#${styleOverrideElementId}`;
651
+ function handleMessage(message, debug = false) {
652
+ if (message.type === "click") {
653
+ const elem = document.querySelectorAll(message.selector);
654
+ debug && console.log("[click]", message.selector, elem);
655
+ if (elem.length > 0) {
656
+ if (message.all === true) {
657
+ elem.forEach(e => e.click());
658
+ }
659
+ else {
660
+ elem[0].click();
661
+ }
662
+ }
663
+ return elem.length > 0;
664
+ }
665
+ else if (message.type === "elemExists") {
666
+ const exists = document.querySelector(message.selector) !== null;
667
+ debug && console.log("[exists?]", message.selector, exists);
668
+ return exists;
669
+ }
670
+ else if (message.type === "elemVisible") {
671
+ const elem = document.querySelectorAll(message.selector);
672
+ const results = new Array(elem.length);
673
+ elem.forEach((e, i) => {
674
+ results[i] = e.offsetParent !== null || window.getComputedStyle(e).display !== "none" || e.style?.display !== "none";
675
+ });
676
+ if (results.length === 0) {
677
+ return false;
678
+ }
679
+ else if (message.check === "any") {
680
+ return results.some(r => r);
681
+ }
682
+ else if (message.check === "none") {
683
+ return results.every(r => !r);
684
+ }
685
+ // all
686
+ return results.every(r => r);
687
+ }
688
+ else if (message.type === "getAttribute") {
689
+ const elem = document.querySelector(message.selector);
690
+ if (!elem) {
691
+ return false;
692
+ }
693
+ return elem.getAttribute(message.attribute);
694
+ }
695
+ else if (message.type === "eval") {
696
+ // TODO: chrome support
697
+ const result = window.eval(message.script); // eslint-disable-line no-eval
698
+ debug && console.log("[eval]", message.script, result);
699
+ return result;
700
+ }
701
+ else if (message.type === "hide") {
702
+ const parent = document.head ||
703
+ document.getElementsByTagName("head")[0] ||
704
+ document.documentElement;
705
+ const rule = `${message.selectors.join(",")} { display: none !important; z-index: -1 !important; } `;
706
+ const existingElement = document.querySelector(styleSelector);
707
+ debug && console.log("[hide]", message.selectors, !!existingElement);
708
+ if (existingElement && existingElement instanceof HTMLStyleElement) {
709
+ existingElement.innerText += rule;
710
+ }
711
+ else {
712
+ const css = document.createElement("style");
713
+ css.type = "text/css";
714
+ css.id = styleOverrideElementId;
715
+ css.appendChild(document.createTextNode(rule));
716
+ parent.appendChild(css);
717
+ }
718
+ return message.selectors.length > 0;
719
+ }
720
+ else if (message.type === "undohide") {
721
+ const existingElement = document.querySelector(styleSelector);
722
+ debug && console.log("[unhide]", !!existingElement);
723
+ if (existingElement) {
724
+ existingElement.remove();
725
+ }
726
+ return !!existingElement;
727
+ }
728
+ else if (message.type === "matches") {
729
+ const matched = matches(message.config);
730
+ return matched;
731
+ }
732
+ else if (message.type === "executeAction") {
733
+ actionQueue = actionQueue.then(() => executeAction(message.config, message.param));
734
+ return true;
735
+ }
736
+ return null;
737
+ }
738
+
739
+ class TabConsent {
740
+ constructor(tab, ruleCheckPromise) {
741
+ this.tab = tab;
742
+ this.optOutStatus = null;
743
+ this.checked = ruleCheckPromise;
744
+ ruleCheckPromise.then(rule => this.rule = rule);
745
+ }
746
+ getCMPName() {
747
+ if (this.rule) {
748
+ return this.rule.name;
749
+ }
750
+ return null;
751
+ }
752
+ async isPopupOpen(retries = 1, interval = 1000) {
753
+ const isOpen = await this.rule.detectPopup(this.tab);
754
+ if (!isOpen && retries > 0) {
755
+ return new Promise((resolve) => setTimeout(() => resolve(this.isPopupOpen(retries - 1, interval)), interval));
756
+ }
757
+ return isOpen;
758
+ }
759
+ async doOptOut() {
760
+ try {
761
+ this.optOutStatus = await this.rule.optOut(this.tab);
762
+ return this.optOutStatus;
763
+ }
764
+ catch (e) {
765
+ this.optOutStatus = e;
766
+ throw e;
767
+ }
768
+ finally {
769
+ if (!this.rule.isHidingRule) {
770
+ if (this.getCMPName().startsWith('com_')) {
771
+ this.tab.wait(5000).then(() => this.tab.undoHideElements());
772
+ }
773
+ else {
774
+ await this.tab.undoHideElements();
775
+ }
776
+ }
777
+ }
778
+ }
779
+ async doOptIn() {
780
+ try {
781
+ return this.rule.optIn(this.tab);
782
+ }
783
+ finally {
784
+ if (!this.rule.isHidingRule) {
785
+ await this.tab.undoHideElements();
786
+ }
787
+ }
788
+ }
789
+ hasTest() {
790
+ return !!this.rule.hasSelfTest;
791
+ }
792
+ async testOptOutWorked() {
793
+ return this.rule.test(this.tab);
794
+ }
795
+ async applyCosmetics(selectors) {
796
+ const hidden = await this.tab.hideElements(selectors);
797
+ return hidden;
798
+ }
799
+ }
800
+
801
+ async function detectDialog(tab, retries, rules) {
802
+ let breakEarly = false;
803
+ const found = await new Promise(async (resolve) => {
804
+ let earlyReturn = false;
805
+ await Promise.all(rules.map(async (r, index) => {
806
+ try {
807
+ if (await r.detectCmp(tab)) {
808
+ earlyReturn = true;
809
+ resolve(index);
810
+ }
811
+ }
812
+ catch (e) {
813
+ breakEarly = true;
814
+ }
815
+ }));
816
+ if (!earlyReturn) {
817
+ resolve(-1);
818
+ }
819
+ });
820
+ if (found === -1 && retries > 0 && !breakEarly) {
821
+ return new Promise((resolve) => {
822
+ setTimeout(async () => {
823
+ const result = detectDialog(tab, retries - 1, rules);
824
+ resolve(result);
825
+ }, 500);
826
+ });
827
+ }
828
+ return found > -1 ? rules[found] : null;
829
+ }
830
+
831
+ class TrustArc extends AutoConsentBase {
832
+ constructor() {
833
+ super("TrustArc");
834
+ this.prehideSelectors = [
835
+ ".trustarc-banner-container",
836
+ ".truste_popframe,.truste_overlay,.truste_box_overlay,#truste-consent-track",
837
+ ];
838
+ }
839
+ detectFrame(_, frame) {
840
+ return frame.url.startsWith("https://consent-pref.trustarc.com/?");
841
+ }
842
+ async detectCmp(tab) {
843
+ if (tab.frame &&
844
+ tab.frame.url.startsWith("https://consent-pref.trustarc.com/?")) {
845
+ return true;
846
+ }
847
+ return tab.elementExists("#truste-show-consent");
848
+ }
849
+ async detectPopup(tab) {
850
+ return ((await tab.elementsAreVisible("#truste-consent-content,#trustarc-banner-overlay")) ||
851
+ (tab.frame &&
852
+ (await tab.waitForElement("#defaultpreferencemanager", 5000, tab.frame.id))));
853
+ }
854
+ async openFrame(tab) {
855
+ if (await tab.elementExists("#truste-show-consent")) {
856
+ await tab.clickElement("#truste-show-consent");
857
+ }
858
+ }
859
+ async navigateToSettings(tab, frameId) {
860
+ // wait for it to load
861
+ await waitFor(async () => {
862
+ return ((await tab.elementExists(".shp", frameId)) ||
863
+ (await tab.elementsAreVisible(".advance", "any", frameId)) ||
864
+ tab.elementExists(".switch span:first-child", frameId));
865
+ }, 10, 500);
866
+ // splash screen -> hit more information
867
+ if (await tab.elementExists(".shp", frameId)) {
868
+ await tab.clickElement(".shp", frameId);
869
+ }
870
+ await tab.waitForElement(".prefPanel", 5000, frameId);
871
+ // go to advanced settings if not yet shown
872
+ if (await tab.elementsAreVisible(".advance", "any", frameId)) {
873
+ await tab.clickElement(".advance", frameId);
874
+ }
875
+ // takes a while to load the opt-in/opt-out buttons
876
+ return await waitFor(() => tab.elementsAreVisible(".switch span:first-child", "any", frameId), 5, 1000);
877
+ }
878
+ async optOut(tab) {
879
+ // await tab.hideElements(['.truste_overlay', '.truste_box_overlay', '.trustarc-banner', '.truste-banner']);
880
+ if (await tab.elementExists("#truste-consent-required")) {
881
+ return tab.clickElement("#truste-consent-required");
882
+ }
883
+ if (!tab.frame) {
884
+ await tab.clickElement("#truste-show-consent");
885
+ await waitFor(async () => !!tab.frame &&
886
+ (await tab.elementsAreVisible(".mainContent", "any", tab.frame.id)), 50, 100);
887
+ }
888
+ const frameId = tab.frame.id;
889
+ await waitFor(() => tab.eval("document.readyState === 'complete'", frameId), 20, 100);
890
+ tab.hideElements([".truste_popframe", ".truste_overlay", ".truste_box_overlay", "#truste-consent-track"]);
891
+ if (await tab.elementExists('.rejectAll', frameId)) {
892
+ return tab.clickElement('.rejectAll', frameId);
893
+ }
894
+ if (await tab.waitForElement('#catDetails0', 1000, frameId)) {
895
+ await tab.clickElement("#catDetails0", frameId);
896
+ return tab.clickElement(".submit", frameId);
897
+ }
898
+ if (await tab.elementExists(".required", frameId)) {
899
+ await tab.clickElement(".required", frameId);
900
+ }
901
+ else {
902
+ await this.navigateToSettings(tab, frameId);
903
+ await tab.clickElements(".switch span:nth-child(1):not(.active)", frameId);
904
+ await tab.clickElement(".submit", frameId);
905
+ }
906
+ try {
907
+ await tab.waitForThenClick("#gwt-debug-close_id", 20000, tab.frame.id);
908
+ }
909
+ catch (e) {
910
+ // ignore frame disappearing
911
+ }
912
+ return true;
913
+ }
914
+ async optIn(tab) {
915
+ if (!tab.frame) {
916
+ await this.openFrame(tab);
917
+ await waitFor(() => !!tab.frame, 10, 200);
918
+ }
919
+ const frameId = tab.frame.id;
920
+ await this.navigateToSettings(tab, frameId);
921
+ await tab.clickElements(".switch span:nth-child(2)", frameId);
922
+ await tab.clickElement(".submit", frameId);
923
+ await waitFor(() => tab.elementExists("#gwt-debug-close_id", frameId), 300, 1000);
924
+ await tab.clickElement("#gwt-debug-close_id", frameId);
925
+ return true;
926
+ }
927
+ async openCmp(tab) {
928
+ await tab.eval("truste.eu.clickListener()");
929
+ return true;
930
+ }
931
+ async test() {
932
+ // TODO: find out how to test TrustArc
933
+ return true;
934
+ }
935
+ }
936
+
937
+ class Cookiebot extends AutoConsentBase {
938
+ constructor() {
939
+ super('Cybotcookiebot');
940
+ this.prehideSelectors = ["#CybotCookiebotDialog,#dtcookie-container,#cookiebanner"];
941
+ }
942
+ async detectCmp(tab) {
943
+ try {
944
+ return await tab.eval('typeof window.CookieConsent === "object" && typeof window.CookieConsent.name === "string"');
945
+ }
946
+ catch (e) {
947
+ return false;
948
+ }
949
+ }
950
+ detectPopup(tab) {
951
+ return tab.elementExists('#CybotCookiebotDialog,#dtcookie-container,#cookiebanner');
952
+ }
953
+ async optOut(tab) {
954
+ if (await tab.elementExists('.cookie-alert-extended-detail-link')) {
955
+ await tab.clickElement('.cookie-alert-extended-detail-link');
956
+ await tab.waitForElement('.cookie-alert-configuration', 1000);
957
+ await tab.clickElements('.cookie-alert-configuration-input:checked');
958
+ return tab.clickElement('.cookie-alert-extended-button-secondary');
959
+ }
960
+ if (await tab.elementExists('#dtcookie-container')) {
961
+ return tab.clickElement('.h-dtcookie-decline');
962
+ }
963
+ if (await tab.elementExists('.cookiebot__button--settings')) {
964
+ await tab.clickElement('.cookiebot__button--settings');
965
+ }
966
+ if (await tab.elementsAreVisible('#CybotCookiebotDialogBodyButtonDecline', 'all')) {
967
+ return await tab.clickElement('#CybotCookiebotDialogBodyButtonDecline');
968
+ }
969
+ if (await tab.elementExists('.cookiebanner__link--details')) {
970
+ await tab.clickElement('.cookiebanner__link--details');
971
+ }
972
+ await tab.clickElements('.CybotCookiebotDialogBodyLevelButton:checked:enabled,input[id*="CybotCookiebotDialogBodyLevelButton"]:checked:enabled');
973
+ if (await tab.elementExists('#CybotCookiebotDialogBodyButtonDecline')) {
974
+ await tab.clickElement('#CybotCookiebotDialogBodyButtonDecline');
975
+ }
976
+ if (await tab.elementExists('input[id^=CybotCookiebotDialogBodyLevelButton]:checked')) {
977
+ await tab.clickElements('input[id^=CybotCookiebotDialogBodyLevelButton]:checked');
978
+ }
979
+ if (await tab.elementExists('#CybotCookiebotDialogBodyButtonAcceptSelected')) {
980
+ await tab.clickElement('#CybotCookiebotDialogBodyButtonAcceptSelected');
981
+ }
982
+ else {
983
+ await tab.clickElements('#CybotCookiebotDialogBodyLevelButtonAccept,#CybotCookiebotDialogBodyButtonAccept,#CybotCookiebotDialogBodyLevelButtonLevelOptinAllowallSelection');
984
+ }
985
+ // some sites have custom submit buttons with no obvious selectors. In this case we just call the submitConsent API.
986
+ if (await tab.eval('CookieConsent.hasResponse !== true')) {
987
+ await tab.eval('Cookiebot.dialog.submitConsent() || true');
988
+ await tab.wait(500);
989
+ }
990
+ return true;
991
+ }
992
+ async optIn(tab) {
993
+ if (await tab.elementExists('#dtcookie-container')) {
994
+ return tab.clickElement('.h-dtcookie-accept');
995
+ }
996
+ await tab.clickElements('.CybotCookiebotDialogBodyLevelButton:not(:checked):enabled');
997
+ await tab.clickElement('#CybotCookiebotDialogBodyLevelButtonAccept');
998
+ await tab.clickElement('#CybotCookiebotDialogBodyButtonAccept');
999
+ return true;
1000
+ }
1001
+ async openCmp(tab) {
1002
+ await tab.eval('CookieConsent.renew() || true');
1003
+ return tab.waitForElement('#CybotCookiebotDialog', 10000);
1004
+ }
1005
+ async test(tab) {
1006
+ return tab.eval('CookieConsent.declined === true');
1007
+ }
1008
+ }
1009
+
1010
+ class SourcePoint extends AutoConsentBase {
1011
+ constructor() {
1012
+ super("Sourcepoint");
1013
+ this.ccpaMode = false;
1014
+ this.prehideSelectors = ["div[id^='sp_message_container_'],.message-overlay"];
1015
+ }
1016
+ detectFrame(_, frame) {
1017
+ try {
1018
+ const url = new URL(frame.url);
1019
+ if (url.searchParams.has('message_id') && url.hostname === 'ccpa-notice.sp-prod.net') {
1020
+ this.ccpaMode = true;
1021
+ return true;
1022
+ }
1023
+ return (url.pathname === '/index.html' || url.pathname === '/privacy-manager/index.html')
1024
+ && url.searchParams.has('message_id') && url.searchParams.has('requestUUID');
1025
+ }
1026
+ catch (e) {
1027
+ return false;
1028
+ }
1029
+ }
1030
+ async detectCmp(tab) {
1031
+ return await tab.elementExists("div[id^='sp_message_container_']") || !!tab.frame;
1032
+ }
1033
+ async detectPopup(tab) {
1034
+ return await tab.elementsAreVisible("div[id^='sp_message_container_']");
1035
+ }
1036
+ async optIn(tab) {
1037
+ return tab.clickElement(".sp_choice_type_11", tab.frame.id);
1038
+ }
1039
+ isManagerOpen(tab) {
1040
+ return tab.frame && new URL(tab.frame.url).pathname === "/privacy-manager/index.html";
1041
+ }
1042
+ async optOut(tab) {
1043
+ try {
1044
+ tab.hideElements(["div[id^='sp_message_container_']"]);
1045
+ if (!this.isManagerOpen(tab)) {
1046
+ if (!await waitFor(() => !!tab.frame, 30, 100)) {
1047
+ throw "Frame never opened";
1048
+ }
1049
+ if (!await tab.elementExists("button.sp_choice_type_12", tab.frame.id)) {
1050
+ // do not sell button
1051
+ return tab.clickElement('button.sp_choice_type_13', tab.frame.id);
1052
+ }
1053
+ await success(tab.clickElement("button.sp_choice_type_12", tab.frame.id));
1054
+ await waitFor(() => new URL(tab.frame.url).pathname === "/privacy-manager/index.html", 200, 100);
1055
+ }
1056
+ await tab.waitForElement('.type-modal', 20000, tab.frame.id);
1057
+ // reject all button is offered by some sites
1058
+ try {
1059
+ const path = await Promise.race([
1060
+ tab.waitForElement('.sp_choice_type_REJECT_ALL', 2000, tab.frame.id).then(r => 0),
1061
+ tab.waitForElement('.reject-toggle', 2000, tab.frame.id).then(() => 1),
1062
+ tab.waitForElement('.pm-features', 2000, tab.frame.id).then(r => 2),
1063
+ ]);
1064
+ if (path === 0) {
1065
+ await tab.wait(1000);
1066
+ return await success(tab.clickElement('.sp_choice_type_REJECT_ALL', tab.frame.id));
1067
+ }
1068
+ else if (path === 1) {
1069
+ await tab.clickElement('.reject-toggle', tab.frame.id);
1070
+ }
1071
+ else {
1072
+ await tab.waitForElement('.pm-features', 10000, tab.frame.id);
1073
+ await tab.clickElements('.checked > span', tab.frame.id);
1074
+ if (await tab.elementExists('.chevron', tab.frame.id)) {
1075
+ await tab.clickElement('.chevron', tab.frame.id);
1076
+ }
1077
+ }
1078
+ }
1079
+ catch (e) { }
1080
+ return await tab.clickElement('.sp_choice_type_SAVE_AND_EXIT', tab.frame.id);
1081
+ }
1082
+ finally {
1083
+ tab.undoHideElements();
1084
+ }
1085
+ }
1086
+ async test(tab) {
1087
+ await tab.eval("__tcfapi('getTCData', 2, r => window.__rcsResult = r)");
1088
+ return tab.eval("Object.values(window.__rcsResult.purpose.consents).every(c => !c)");
1089
+ }
1090
+ }
1091
+
1092
+ // Note: JS API is also available:
1093
+ // https://help.consentmanager.net/books/cmp/page/javascript-api
1094
+ class ConsentManager extends AutoConsentBase {
1095
+ constructor() {
1096
+ super("consentmanager.net");
1097
+ this.prehideSelectors = ["#cmpbox,#cmpbox2"];
1098
+ }
1099
+ detectCmp(tab) {
1100
+ return tab.elementExists("#cmpbox");
1101
+ }
1102
+ detectPopup(tab) {
1103
+ return tab.elementsAreVisible("#cmpbox .cmpmore", "any");
1104
+ }
1105
+ async optOut(tab) {
1106
+ if (await tab.elementExists(".cmpboxbtnno")) {
1107
+ return tab.clickElement(".cmpboxbtnno");
1108
+ }
1109
+ if (await tab.elementExists(".cmpwelcomeprpsbtn")) {
1110
+ await tab.clickElements(".cmpwelcomeprpsbtn > a[aria-checked=true]");
1111
+ return await tab.clickElement(".cmpboxbtnsave");
1112
+ }
1113
+ await tab.clickElement(".cmpboxbtncustom");
1114
+ await tab.waitForElement(".cmptblbox", 2000);
1115
+ await tab.clickElements(".cmptdchoice > a[aria-checked=true]");
1116
+ return tab.clickElement(".cmpboxbtnyescustomchoices");
1117
+ }
1118
+ async optIn(tab) {
1119
+ return tab.clickElement(".cmpboxbtnyes");
1120
+ }
1121
+ }
1122
+
1123
+ // Note: JS API is also available:
1124
+ // https://help.consentmanager.net/books/cmp/page/javascript-api
1125
+ class Evidon extends AutoConsentBase {
1126
+ constructor() {
1127
+ super("Evidon");
1128
+ }
1129
+ detectCmp(tab) {
1130
+ return tab.elementExists("#_evidon_banner");
1131
+ }
1132
+ detectPopup(tab) {
1133
+ return tab.elementsAreVisible("#_evidon_banner");
1134
+ }
1135
+ async optOut(tab) {
1136
+ if (await tab.elementExists("#_evidon-decline-button")) {
1137
+ return tab.clickElement("#_evidon-decline-button");
1138
+ }
1139
+ tab.hideElements(["#evidon-prefdiag-overlay", "#evidon-prefdiag-background"]);
1140
+ await tab.clickElement("#_evidon-option-button");
1141
+ await tab.waitForElement("#evidon-prefdiag-overlay", 5000);
1142
+ return tab.clickElement("#evidon-prefdiag-decline");
1143
+ }
1144
+ async optIn(tab) {
1145
+ return tab.clickElement("#_evidon-accept-button");
1146
+ }
1147
+ }
1148
+
1149
+ const rules = [
1150
+ new TrustArc(),
1151
+ new Cookiebot(),
1152
+ new SourcePoint(),
1153
+ new ConsentManager(),
1154
+ new Evidon(),
1155
+ ];
1156
+ function createAutoCMP(config) {
1157
+ return new AutoConsent(config);
1158
+ }
1159
+
1160
+ const rules$1 = rules;
1161
+
1162
+ class ConsentOMaticCMP {
1163
+ constructor(name, config) {
1164
+ this.name = name;
1165
+ this.config = config;
1166
+ this.methods = new Map();
1167
+ config.methods.forEach(methodConfig => {
1168
+ if (methodConfig.action) {
1169
+ this.methods.set(methodConfig.name, methodConfig.action);
1170
+ }
1171
+ });
1172
+ this.hasSelfTest = this.methods.has("TEST_CONSENT");
1173
+ }
1174
+ async detectCmp(tab) {
1175
+ return (await Promise.all(this.config.detectors.map(detectorConfig => tab.matches(detectorConfig.presentMatcher)))).some(matched => matched);
1176
+ }
1177
+ async detectPopup(tab) {
1178
+ return (await Promise.all(this.config.detectors.map(detectorConfig => tab.matches(detectorConfig.showingMatcher)))).some(matched => matched);
1179
+ }
1180
+ async executeAction(tab, method, param) {
1181
+ if (this.methods.has(method)) {
1182
+ return tab.executeAction(this.methods.get(method), param);
1183
+ }
1184
+ return true;
1185
+ }
1186
+ async optOut(tab) {
1187
+ await this.executeAction(tab, "HIDE_CMP");
1188
+ await this.executeAction(tab, "OPEN_OPTIONS");
1189
+ await this.executeAction(tab, "HIDE_CMP");
1190
+ await this.executeAction(tab, "DO_CONSENT", []);
1191
+ await this.executeAction(tab, "SAVE_CONSENT");
1192
+ return true;
1193
+ }
1194
+ async optIn(tab) {
1195
+ await this.executeAction(tab, "HIDE_CMP");
1196
+ await this.executeAction(tab, "OPEN_OPTIONS");
1197
+ await this.executeAction(tab, "HIDE_CMP");
1198
+ await this.executeAction(tab, "DO_CONSENT", ['D', 'A', 'B', 'E', 'F', 'X']);
1199
+ await this.executeAction(tab, "SAVE_CONSENT");
1200
+ return true;
1201
+ }
1202
+ async openCmp(tab) {
1203
+ await this.executeAction(tab, "HIDE_CMP");
1204
+ await this.executeAction(tab, "OPEN_OPTIONS");
1205
+ return true;
1206
+ }
1207
+ test(tab) {
1208
+ return this.executeAction(tab, "TEST_CONSENT");
1209
+ }
1210
+ detectFrame(tab, frame) {
1211
+ return false;
1212
+ }
1213
+ }
1214
+
1215
+ // hide rules not specific to a single CMP rule
1216
+ const globalHidden = [
1217
+ "#didomi-popup,.didomi-popup-container,.didomi-popup-notice,.didomi-consent-popup-preferences,#didomi-notice,.didomi-popup-backdrop,.didomi-screen-medium",
1218
+ ];
1219
+ async function prehideElements(tab, rules) {
1220
+ const selectors = rules.reduce((selectorList, rule) => {
1221
+ if (rule.prehideSelectors) {
1222
+ return [...selectorList, ...rule.prehideSelectors];
1223
+ }
1224
+ return selectorList;
1225
+ }, globalHidden);
1226
+ await tab.hideElements(selectors);
1227
+ }
1228
+
1229
+ class AutoConsent$1 {
1230
+ constructor(browser, sendContentMessage) {
1231
+ this.browser = browser;
1232
+ this.sendContentMessage = sendContentMessage;
1233
+ this.consentFrames = new Map();
1234
+ this.tabCmps = new Map();
1235
+ this.sendContentMessage = sendContentMessage;
1236
+ this.rules = [...rules$1];
1237
+ }
1238
+ addCMP(config) {
1239
+ this.rules.push(createAutoCMP(config));
1240
+ }
1241
+ disableCMPs(cmpNames) {
1242
+ this.rules = this.rules.filter((cmp) => !cmpNames.includes(cmp.name));
1243
+ }
1244
+ addConsentomaticCMP(name, config) {
1245
+ this.rules.push(new ConsentOMaticCMP(`com_${name}`, config));
1246
+ }
1247
+ createTab(tabId) {
1248
+ return new TabActions(tabId, this.consentFrames.get(tabId), this.sendContentMessage, this.browser);
1249
+ }
1250
+ async checkTab(tabId, prehide = true) {
1251
+ const tab = this.createTab(tabId);
1252
+ if (prehide) {
1253
+ this.prehideElements(tab);
1254
+ }
1255
+ const consent = new TabConsent(tab, this.detectDialog(tab, 20));
1256
+ this.tabCmps.set(tabId, consent);
1257
+ // check tabs
1258
+ consent.checked.then((rule) => {
1259
+ if (this.consentFrames.has(tabId) && rule) {
1260
+ const frame = this.consentFrames.get(tabId);
1261
+ if (frame.type === rule.name) {
1262
+ consent.tab.frame = frame;
1263
+ }
1264
+ }
1265
+ // no CMP detected, undo hiding
1266
+ if (!rule && prehide) {
1267
+ tab.undoHideElements();
1268
+ }
1269
+ });
1270
+ return this.tabCmps.get(tabId);
1271
+ }
1272
+ removeTab(tabId) {
1273
+ this.tabCmps.delete(tabId);
1274
+ this.consentFrames.delete(tabId);
1275
+ }
1276
+ onFrame({ tabId, url, frameId }) {
1277
+ // ignore main frames
1278
+ if (frameId === 0) {
1279
+ return;
1280
+ }
1281
+ try {
1282
+ const frame = {
1283
+ id: frameId,
1284
+ url: url,
1285
+ };
1286
+ const tab = this.createTab(tabId);
1287
+ const frameMatch = this.rules.findIndex(r => r.detectFrame(tab, frame));
1288
+ if (frameMatch > -1) {
1289
+ this.consentFrames.set(tabId, {
1290
+ type: this.rules[frameMatch].name,
1291
+ url,
1292
+ id: frameId,
1293
+ });
1294
+ if (this.tabCmps.has(tabId)) {
1295
+ this.tabCmps.get(tabId).tab.frame = this.consentFrames.get(tabId);
1296
+ }
1297
+ }
1298
+ }
1299
+ catch (e) {
1300
+ console.error(e);
1301
+ }
1302
+ }
1303
+ async detectDialog(tab, retries) {
1304
+ return detectDialog(tab, retries, this.rules);
1305
+ }
1306
+ async prehideElements(tab) {
1307
+ return prehideElements(tab, this.rules);
1308
+ }
1309
+ }
1310
+
1311
+ exports.Tab = TabActions;
1312
+ exports.createAutoCMP = createAutoCMP;
1313
+ exports.default = AutoConsent$1;
1314
+ exports.handleContentMessage = handleMessage;
1315
+ exports.rules = rules$1;
1316
+ exports.waitFor = waitFor;