@duckduckgo/autoconsent 1.0.5 → 1.0.8

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 (66) hide show
  1. package/dist/autoconsent.cjs.js +105 -34
  2. package/dist/autoconsent.esm.js +105 -34
  3. package/dist/autoconsent.puppet.js +109 -11
  4. package/lib/cmps/all.js +2 -0
  5. package/lib/cmps/all.ts +2 -0
  6. package/lib/cmps/base.js +5 -1
  7. package/lib/cmps/base.ts +5 -1
  8. package/lib/cmps/cookiebot.js +6 -2
  9. package/lib/cmps/cookiebot.ts +8 -2
  10. package/lib/cmps/onetrust.js +34 -0
  11. package/lib/cmps/onetrust.ts +47 -0
  12. package/lib/cmps/trustarc.js +2 -2
  13. package/lib/cmps/trustarc.ts +2 -2
  14. package/lib/config.js +1 -0
  15. package/lib/config.ts +1 -0
  16. package/lib/detector.js +4 -0
  17. package/lib/detector.ts +4 -0
  18. package/lib/hider.js +1 -1
  19. package/lib/hider.ts +1 -1
  20. package/lib/messages.d.ts +3 -0
  21. package/lib/node.js +8 -3
  22. package/lib/node.ts +10 -5
  23. package/lib/puppet/tab.js +10 -3
  24. package/lib/puppet/tab.ts +13 -3
  25. package/lib/tabwrapper.js +6 -0
  26. package/lib/tabwrapper.ts +6 -0
  27. package/lib/types.d.ts +2 -2
  28. package/lib/web/content-utils.js +29 -0
  29. package/lib/web/content-utils.ts +31 -0
  30. package/lib/web/content.js +20 -22
  31. package/lib/web/content.ts +19 -22
  32. package/lib/web/tab.js +12 -6
  33. package/lib/web/tab.ts +13 -6
  34. package/lib/web.js +5 -0
  35. package/lib/web.ts +5 -0
  36. package/package.json +1 -1
  37. package/readme.md +1 -1
  38. package/rules/autoconsent/192.json +17 -0
  39. package/rules/autoconsent/ausopen.json +7 -0
  40. package/rules/autoconsent/aws-amazon.json +1 -1
  41. package/rules/autoconsent/bing.json +14 -0
  42. package/rules/autoconsent/bundesregierung-de.json +1 -1
  43. package/rules/autoconsent/dunelm.json +18 -0
  44. package/rules/autoconsent/etsy.json +13 -0
  45. package/rules/autoconsent/gov-uk.json +10 -0
  46. package/rules/autoconsent/marksandspencer.json +7 -0
  47. package/rules/autoconsent/{paypal-de.json → paypal.json} +6 -2
  48. package/rules/autoconsent/uswitch.json +8 -0
  49. package/rules/autoconsent/waitrose.json +28 -0
  50. package/rules/autoconsent/wetransfer.json +7 -0
  51. package/rules/rules.json +308 -50
  52. package/tests/192.spec.ts +7 -0
  53. package/tests/ausopen.spec.ts +7 -0
  54. package/tests/cookiebot.spec.ts +1 -0
  55. package/tests/dunelm.spec.ts +7 -0
  56. package/tests/etsy.spec.ts +7 -0
  57. package/tests/gov-uk.spec.ts +9 -0
  58. package/tests/marksandspencer.spec.ts +7 -0
  59. package/tests/onetrust.spec.ts +6 -0
  60. package/tests/paypal.spec.ts +7 -5
  61. package/tests/runner.ts +1 -1
  62. package/tests/trustarc.spec.ts +1 -0
  63. package/tests/uswitch.spec.ts +7 -0
  64. package/tests/waitrose.spec.ts +7 -0
  65. package/tests/wetransfer.spec.ts +7 -0
  66. package/rules/autoconsent/onetrust.json +0 -24
@@ -2,6 +2,8 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
+ const enableLogs = false; // change this to enable debug logs
6
+
5
7
  /* eslint-disable no-restricted-syntax,no-await-in-loop,no-underscore-dangle */
6
8
  async function waitFor(predicate, maxTimes, interval) {
7
9
  let result = await predicate();
@@ -17,7 +19,7 @@ async function waitFor(predicate, maxTimes, interval) {
17
19
  async function success(action) {
18
20
  const result = await action;
19
21
  if (!result) {
20
- throw new Error(`Action failed: ${action}`);
22
+ throw new Error(`Action failed: ${action} ${result}`);
21
23
  }
22
24
  return result;
23
25
  }
@@ -181,7 +183,6 @@ class TabActions {
181
183
  this.id = tabId;
182
184
  }
183
185
  async elementExists(selector, frameId = 0) {
184
- console.log(`check for ${selector} in tab ${this.id}, frame ${frameId}`);
185
186
  return this.sendContentMessage(this.id, {
186
187
  type: "elemExists",
187
188
  selector
@@ -190,7 +191,6 @@ class TabActions {
190
191
  });
191
192
  }
192
193
  async clickElement(selector, frameId = 0) {
193
- console.log(`click element ${selector} in tab ${this.id}`);
194
194
  return this.sendContentMessage(this.id, {
195
195
  type: "click",
196
196
  selector
@@ -199,7 +199,6 @@ class TabActions {
199
199
  });
200
200
  }
201
201
  async clickElements(selector, frameId = 0) {
202
- console.log(`click elements ${selector} in tab ${this.id}`);
203
202
  return this.sendContentMessage(this.id, {
204
203
  type: "click",
205
204
  all: true,
@@ -242,10 +241,11 @@ class TabActions {
242
241
  }
243
242
  return false;
244
243
  }
245
- async hideElements(selectors, frameId = 0) {
244
+ async hideElements(selectors, frameId = 0, method = 'display') {
246
245
  return this.sendContentMessage(this.id, {
247
246
  type: "hide",
248
- selectors
247
+ selectors,
248
+ method,
249
249
  }, { frameId });
250
250
  }
251
251
  async undoHideElements(frameId = 0) {
@@ -261,7 +261,9 @@ class TabActions {
261
261
  }
262
262
  wait(ms) {
263
263
  return new Promise(resolve => {
264
- setTimeout(() => resolve(true), ms);
264
+ setTimeout(() => {
265
+ resolve(true);
266
+ }, ms);
265
267
  });
266
268
  }
267
269
  matches(matcherConfig) {
@@ -645,9 +647,37 @@ async function evalAction(config) {
645
647
  });
646
648
  }
647
649
 
650
+ // get or create a style container for CSS overrides
651
+ function getStyleElementUtil() {
652
+ const styleOverrideElementId = "autoconsent-css-rules";
653
+ const styleSelector = `style#${styleOverrideElementId}`;
654
+ const existingElement = document.querySelector(styleSelector);
655
+ if (existingElement && existingElement instanceof HTMLStyleElement) {
656
+ return existingElement;
657
+ }
658
+ else {
659
+ const parent = document.head ||
660
+ document.getElementsByTagName("head")[0] ||
661
+ document.documentElement;
662
+ const css = document.createElement("style");
663
+ css.id = styleOverrideElementId;
664
+ parent.appendChild(css);
665
+ return css;
666
+ }
667
+ }
668
+ // hide elements with a CSS rule
669
+ function hideElementsUtil(selectors, method) {
670
+ const hidingSnippet = method === 'display' ? `display: none` : `opacity: 0`;
671
+ const rule = `${selectors.join(",")} { ${hidingSnippet} !important; z-index: -1 !important; pointer-events: none !important; } `;
672
+ const styleEl = getStyleElementUtil();
673
+ if (styleEl instanceof HTMLStyleElement) {
674
+ styleEl.innerText += rule;
675
+ return selectors.length > 0;
676
+ }
677
+ return false;
678
+ }
679
+
648
680
  let actionQueue = Promise.resolve(null);
649
- const styleOverrideElementId = "autoconsent-css-rules";
650
- const styleSelector = `style#${styleOverrideElementId}`;
651
681
  function handleMessage(message, debug = false) {
652
682
  if (message.type === "click") {
653
683
  const elem = document.querySelectorAll(message.selector);
@@ -671,8 +701,19 @@ function handleMessage(message, debug = false) {
671
701
  const elem = document.querySelectorAll(message.selector);
672
702
  const results = new Array(elem.length);
673
703
  elem.forEach((e, i) => {
674
- results[i] = e.offsetParent !== null || window.getComputedStyle(e).display !== "none" || e.style?.display !== "none";
704
+ // check for display: none
705
+ results[i] = false;
706
+ if (e.offsetParent !== null) {
707
+ results[i] = true;
708
+ }
709
+ else {
710
+ const css = window.getComputedStyle(e);
711
+ if (css.position === 'fixed' && css.display !== "none") { // fixed elements may be visible even if the parent is not
712
+ results[i] = true;
713
+ }
714
+ }
675
715
  });
716
+ debug && console.log("[visible?]", message.selector, elem, results);
676
717
  if (results.length === 0) {
677
718
  return false;
678
719
  }
@@ -687,6 +728,7 @@ function handleMessage(message, debug = false) {
687
728
  }
688
729
  else if (message.type === "getAttribute") {
689
730
  const elem = document.querySelector(message.selector);
731
+ debug && console.log("[getAttribute]", message.selector, elem);
690
732
  if (!elem) {
691
733
  return false;
692
734
  }
@@ -694,31 +736,16 @@ function handleMessage(message, debug = false) {
694
736
  }
695
737
  else if (message.type === "eval") {
696
738
  // TODO: chrome support
739
+ debug && console.log("about to [eval]", message.script); // this will not show in Webkit console
697
740
  const result = window.eval(message.script); // eslint-disable-line no-eval
698
- debug && console.log("[eval]", message.script, result);
699
741
  return result;
700
742
  }
701
743
  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;
744
+ debug && console.log("[hide]", message.selectors);
745
+ return hideElementsUtil(message.selectors, message.method);
719
746
  }
720
747
  else if (message.type === "undohide") {
721
- const existingElement = document.querySelector(styleSelector);
748
+ const existingElement = getStyleElementUtil();
722
749
  debug && console.log("[unhide]", !!existingElement);
723
750
  if (existingElement) {
724
751
  existingElement.remove();
@@ -727,9 +754,11 @@ function handleMessage(message, debug = false) {
727
754
  }
728
755
  else if (message.type === "matches") {
729
756
  const matched = matches(message.config);
757
+ debug && console.log("[matches?]", message.config.type, JSON.stringify(message.config), matched);
730
758
  return matched;
731
759
  }
732
760
  else if (message.type === "executeAction") {
761
+ debug && console.log("[executeAction]", message);
733
762
  actionQueue = actionQueue.then(() => executeAction(message.config, message.param));
734
763
  return true;
735
764
  }
@@ -758,10 +787,12 @@ class TabConsent {
758
787
  }
759
788
  async doOptOut() {
760
789
  try {
790
+ enableLogs && console.log(`doing opt out ${this.getCMPName()} in tab ${this.tab.id}`);
761
791
  this.optOutStatus = await this.rule.optOut(this.tab);
762
792
  return this.optOutStatus;
763
793
  }
764
794
  catch (e) {
795
+ console.error('error during opt out', e);
765
796
  this.optOutStatus = e;
766
797
  throw e;
767
798
  }
@@ -806,6 +837,7 @@ async function detectDialog(tab, retries, rules) {
806
837
  try {
807
838
  if (await r.detectCmp(tab)) {
808
839
  earlyReturn = true;
840
+ enableLogs && console.log(`Found CMP in [${tab.id}]: ${r.name}`);
809
841
  resolve(index);
810
842
  }
811
843
  }
@@ -844,10 +876,10 @@ class TrustArc extends AutoConsentBase {
844
876
  tab.frame.url.startsWith("https://consent-pref.trustarc.com/?")) {
845
877
  return true;
846
878
  }
847
- return tab.elementExists("#truste-show-consent");
879
+ return tab.elementExists("#truste-show-consent,#truste-consent-track");
848
880
  }
849
881
  async detectPopup(tab) {
850
- return ((await tab.elementsAreVisible("#truste-consent-content,#trustarc-banner-overlay")) ||
882
+ return ((await tab.elementsAreVisible("#truste-consent-content,.truste-consent-content,#trustarc-banner-overlay")) ||
851
883
  (tab.frame &&
852
884
  (await tab.waitForElement("#defaultpreferencemanager", 5000, tab.frame.id))));
853
885
  }
@@ -937,7 +969,7 @@ class TrustArc extends AutoConsentBase {
937
969
  class Cookiebot extends AutoConsentBase {
938
970
  constructor() {
939
971
  super('Cybotcookiebot');
940
- this.prehideSelectors = ["#CybotCookiebotDialog,#dtcookie-container,#cookiebanner"];
972
+ this.prehideSelectors = ["#CybotCookiebotDialog,#dtcookie-container,#cookiebanner,#cb-cookieoverlay"];
941
973
  }
942
974
  async detectCmp(tab) {
943
975
  try {
@@ -948,7 +980,7 @@ class Cookiebot extends AutoConsentBase {
948
980
  }
949
981
  }
950
982
  detectPopup(tab) {
951
- return tab.elementExists('#CybotCookiebotDialog,#dtcookie-container,#cookiebanner');
983
+ return tab.elementExists('#CybotCookiebotDialog,#dtcookie-container,#cookiebanner,#cb-cookiebanner');
952
984
  }
953
985
  async optOut(tab) {
954
986
  if (await tab.elementExists('.cookie-alert-extended-detail-link')) {
@@ -987,6 +1019,10 @@ class Cookiebot extends AutoConsentBase {
987
1019
  await tab.eval('Cookiebot.dialog.submitConsent() || true');
988
1020
  await tab.wait(500);
989
1021
  }
1022
+ // site with 3rd confirm settings modal
1023
+ if (await tab.elementExists('#cb-confirmedSettings')) {
1024
+ await tab.eval('endCookieProcess()');
1025
+ }
990
1026
  return true;
991
1027
  }
992
1028
  async optIn(tab) {
@@ -1146,12 +1182,47 @@ class Evidon extends AutoConsentBase {
1146
1182
  }
1147
1183
  }
1148
1184
 
1185
+ class Onetrust extends AutoConsentBase {
1186
+ constructor() {
1187
+ super("Onetrust");
1188
+ this.prehideSelectors = ["#onetrust-banner-sdk,#onetrust-consent-sdk,.optanon-alert-box-wrapper,.onetrust-pc-dark-filter,.js-consent-banner"];
1189
+ }
1190
+ detectCmp(tab) {
1191
+ return tab.elementExists("#onetrust-banner-sdk,.optanon-alert-box-wrapper");
1192
+ }
1193
+ detectPopup(tab) {
1194
+ return tab.elementsAreVisible("#onetrust-banner-sdk,.optanon-alert-box-wrapper");
1195
+ }
1196
+ async optOut(tab) {
1197
+ if (await tab.elementExists("#onetrust-pc-btn-handler")) { // "show purposes" button inside a popup
1198
+ await success(tab.clickElement("#onetrust-pc-btn-handler"));
1199
+ }
1200
+ else { // otherwise look for a generic "show settings" button
1201
+ await success(tab.clickElement(".ot-sdk-show-settings,button.js-cookie-settings"));
1202
+ }
1203
+ await success(tab.waitForElement("#onetrust-consent-sdk", 2000));
1204
+ await success(tab.wait(1000));
1205
+ await tab.clickElements("#onetrust-consent-sdk input.category-switch-handler:checked,.js-editor-toggle-state:checked"); // optional step
1206
+ await success(tab.waitForThenClick(".save-preference-btn-handler,.js-consent-save", 1000));
1207
+ // popup doesn't disappear immediately
1208
+ await waitFor(async () => !(await tab.elementsAreVisible("#onetrust-banner-sdk")), 10, 500);
1209
+ return true;
1210
+ }
1211
+ async optIn(tab) {
1212
+ return tab.clickElement("onetrust-accept-btn-handler,js-accept-cookies");
1213
+ }
1214
+ async test(tab) {
1215
+ return tab.eval("window.OnetrustActiveGroups.split(',').filter(s => s.length > 0).length <= 1");
1216
+ }
1217
+ }
1218
+
1149
1219
  const rules = [
1150
1220
  new TrustArc(),
1151
1221
  new Cookiebot(),
1152
1222
  new SourcePoint(),
1153
1223
  new ConsentManager(),
1154
1224
  new Evidon(),
1225
+ new Onetrust(),
1155
1226
  ];
1156
1227
  function createAutoCMP(config) {
1157
1228
  return new AutoConsent(config);
@@ -1223,7 +1294,7 @@ async function prehideElements(tab, rules) {
1223
1294
  }
1224
1295
  return selectorList;
1225
1296
  }, globalHidden);
1226
- await tab.hideElements(selectors);
1297
+ await tab.hideElements(selectors, undefined, 'opacity');
1227
1298
  }
1228
1299
 
1229
1300
  class AutoConsent$1 {
@@ -1,3 +1,5 @@
1
+ const enableLogs = false; // change this to enable debug logs
2
+
1
3
  /* eslint-disable no-restricted-syntax,no-await-in-loop,no-underscore-dangle */
2
4
  async function waitFor(predicate, maxTimes, interval) {
3
5
  let result = await predicate();
@@ -13,7 +15,7 @@ async function waitFor(predicate, maxTimes, interval) {
13
15
  async function success(action) {
14
16
  const result = await action;
15
17
  if (!result) {
16
- throw new Error(`Action failed: ${action}`);
18
+ throw new Error(`Action failed: ${action} ${result}`);
17
19
  }
18
20
  return result;
19
21
  }
@@ -177,7 +179,6 @@ class TabActions {
177
179
  this.id = tabId;
178
180
  }
179
181
  async elementExists(selector, frameId = 0) {
180
- console.log(`check for ${selector} in tab ${this.id}, frame ${frameId}`);
181
182
  return this.sendContentMessage(this.id, {
182
183
  type: "elemExists",
183
184
  selector
@@ -186,7 +187,6 @@ class TabActions {
186
187
  });
187
188
  }
188
189
  async clickElement(selector, frameId = 0) {
189
- console.log(`click element ${selector} in tab ${this.id}`);
190
190
  return this.sendContentMessage(this.id, {
191
191
  type: "click",
192
192
  selector
@@ -195,7 +195,6 @@ class TabActions {
195
195
  });
196
196
  }
197
197
  async clickElements(selector, frameId = 0) {
198
- console.log(`click elements ${selector} in tab ${this.id}`);
199
198
  return this.sendContentMessage(this.id, {
200
199
  type: "click",
201
200
  all: true,
@@ -238,10 +237,11 @@ class TabActions {
238
237
  }
239
238
  return false;
240
239
  }
241
- async hideElements(selectors, frameId = 0) {
240
+ async hideElements(selectors, frameId = 0, method = 'display') {
242
241
  return this.sendContentMessage(this.id, {
243
242
  type: "hide",
244
- selectors
243
+ selectors,
244
+ method,
245
245
  }, { frameId });
246
246
  }
247
247
  async undoHideElements(frameId = 0) {
@@ -257,7 +257,9 @@ class TabActions {
257
257
  }
258
258
  wait(ms) {
259
259
  return new Promise(resolve => {
260
- setTimeout(() => resolve(true), ms);
260
+ setTimeout(() => {
261
+ resolve(true);
262
+ }, ms);
261
263
  });
262
264
  }
263
265
  matches(matcherConfig) {
@@ -641,9 +643,37 @@ async function evalAction(config) {
641
643
  });
642
644
  }
643
645
 
646
+ // get or create a style container for CSS overrides
647
+ function getStyleElementUtil() {
648
+ const styleOverrideElementId = "autoconsent-css-rules";
649
+ const styleSelector = `style#${styleOverrideElementId}`;
650
+ const existingElement = document.querySelector(styleSelector);
651
+ if (existingElement && existingElement instanceof HTMLStyleElement) {
652
+ return existingElement;
653
+ }
654
+ else {
655
+ const parent = document.head ||
656
+ document.getElementsByTagName("head")[0] ||
657
+ document.documentElement;
658
+ const css = document.createElement("style");
659
+ css.id = styleOverrideElementId;
660
+ parent.appendChild(css);
661
+ return css;
662
+ }
663
+ }
664
+ // hide elements with a CSS rule
665
+ function hideElementsUtil(selectors, method) {
666
+ const hidingSnippet = method === 'display' ? `display: none` : `opacity: 0`;
667
+ const rule = `${selectors.join(",")} { ${hidingSnippet} !important; z-index: -1 !important; pointer-events: none !important; } `;
668
+ const styleEl = getStyleElementUtil();
669
+ if (styleEl instanceof HTMLStyleElement) {
670
+ styleEl.innerText += rule;
671
+ return selectors.length > 0;
672
+ }
673
+ return false;
674
+ }
675
+
644
676
  let actionQueue = Promise.resolve(null);
645
- const styleOverrideElementId = "autoconsent-css-rules";
646
- const styleSelector = `style#${styleOverrideElementId}`;
647
677
  function handleMessage(message, debug = false) {
648
678
  if (message.type === "click") {
649
679
  const elem = document.querySelectorAll(message.selector);
@@ -667,8 +697,19 @@ function handleMessage(message, debug = false) {
667
697
  const elem = document.querySelectorAll(message.selector);
668
698
  const results = new Array(elem.length);
669
699
  elem.forEach((e, i) => {
670
- results[i] = e.offsetParent !== null || window.getComputedStyle(e).display !== "none" || e.style?.display !== "none";
700
+ // check for display: none
701
+ results[i] = false;
702
+ if (e.offsetParent !== null) {
703
+ results[i] = true;
704
+ }
705
+ else {
706
+ const css = window.getComputedStyle(e);
707
+ if (css.position === 'fixed' && css.display !== "none") { // fixed elements may be visible even if the parent is not
708
+ results[i] = true;
709
+ }
710
+ }
671
711
  });
712
+ debug && console.log("[visible?]", message.selector, elem, results);
672
713
  if (results.length === 0) {
673
714
  return false;
674
715
  }
@@ -683,6 +724,7 @@ function handleMessage(message, debug = false) {
683
724
  }
684
725
  else if (message.type === "getAttribute") {
685
726
  const elem = document.querySelector(message.selector);
727
+ debug && console.log("[getAttribute]", message.selector, elem);
686
728
  if (!elem) {
687
729
  return false;
688
730
  }
@@ -690,31 +732,16 @@ function handleMessage(message, debug = false) {
690
732
  }
691
733
  else if (message.type === "eval") {
692
734
  // TODO: chrome support
735
+ debug && console.log("about to [eval]", message.script); // this will not show in Webkit console
693
736
  const result = window.eval(message.script); // eslint-disable-line no-eval
694
- debug && console.log("[eval]", message.script, result);
695
737
  return result;
696
738
  }
697
739
  else if (message.type === "hide") {
698
- const parent = document.head ||
699
- document.getElementsByTagName("head")[0] ||
700
- document.documentElement;
701
- const rule = `${message.selectors.join(",")} { display: none !important; z-index: -1 !important; } `;
702
- const existingElement = document.querySelector(styleSelector);
703
- debug && console.log("[hide]", message.selectors, !!existingElement);
704
- if (existingElement && existingElement instanceof HTMLStyleElement) {
705
- existingElement.innerText += rule;
706
- }
707
- else {
708
- const css = document.createElement("style");
709
- css.type = "text/css";
710
- css.id = styleOverrideElementId;
711
- css.appendChild(document.createTextNode(rule));
712
- parent.appendChild(css);
713
- }
714
- return message.selectors.length > 0;
740
+ debug && console.log("[hide]", message.selectors);
741
+ return hideElementsUtil(message.selectors, message.method);
715
742
  }
716
743
  else if (message.type === "undohide") {
717
- const existingElement = document.querySelector(styleSelector);
744
+ const existingElement = getStyleElementUtil();
718
745
  debug && console.log("[unhide]", !!existingElement);
719
746
  if (existingElement) {
720
747
  existingElement.remove();
@@ -723,9 +750,11 @@ function handleMessage(message, debug = false) {
723
750
  }
724
751
  else if (message.type === "matches") {
725
752
  const matched = matches(message.config);
753
+ debug && console.log("[matches?]", message.config.type, JSON.stringify(message.config), matched);
726
754
  return matched;
727
755
  }
728
756
  else if (message.type === "executeAction") {
757
+ debug && console.log("[executeAction]", message);
729
758
  actionQueue = actionQueue.then(() => executeAction(message.config, message.param));
730
759
  return true;
731
760
  }
@@ -754,10 +783,12 @@ class TabConsent {
754
783
  }
755
784
  async doOptOut() {
756
785
  try {
786
+ enableLogs && console.log(`doing opt out ${this.getCMPName()} in tab ${this.tab.id}`);
757
787
  this.optOutStatus = await this.rule.optOut(this.tab);
758
788
  return this.optOutStatus;
759
789
  }
760
790
  catch (e) {
791
+ console.error('error during opt out', e);
761
792
  this.optOutStatus = e;
762
793
  throw e;
763
794
  }
@@ -802,6 +833,7 @@ async function detectDialog(tab, retries, rules) {
802
833
  try {
803
834
  if (await r.detectCmp(tab)) {
804
835
  earlyReturn = true;
836
+ enableLogs && console.log(`Found CMP in [${tab.id}]: ${r.name}`);
805
837
  resolve(index);
806
838
  }
807
839
  }
@@ -840,10 +872,10 @@ class TrustArc extends AutoConsentBase {
840
872
  tab.frame.url.startsWith("https://consent-pref.trustarc.com/?")) {
841
873
  return true;
842
874
  }
843
- return tab.elementExists("#truste-show-consent");
875
+ return tab.elementExists("#truste-show-consent,#truste-consent-track");
844
876
  }
845
877
  async detectPopup(tab) {
846
- return ((await tab.elementsAreVisible("#truste-consent-content,#trustarc-banner-overlay")) ||
878
+ return ((await tab.elementsAreVisible("#truste-consent-content,.truste-consent-content,#trustarc-banner-overlay")) ||
847
879
  (tab.frame &&
848
880
  (await tab.waitForElement("#defaultpreferencemanager", 5000, tab.frame.id))));
849
881
  }
@@ -933,7 +965,7 @@ class TrustArc extends AutoConsentBase {
933
965
  class Cookiebot extends AutoConsentBase {
934
966
  constructor() {
935
967
  super('Cybotcookiebot');
936
- this.prehideSelectors = ["#CybotCookiebotDialog,#dtcookie-container,#cookiebanner"];
968
+ this.prehideSelectors = ["#CybotCookiebotDialog,#dtcookie-container,#cookiebanner,#cb-cookieoverlay"];
937
969
  }
938
970
  async detectCmp(tab) {
939
971
  try {
@@ -944,7 +976,7 @@ class Cookiebot extends AutoConsentBase {
944
976
  }
945
977
  }
946
978
  detectPopup(tab) {
947
- return tab.elementExists('#CybotCookiebotDialog,#dtcookie-container,#cookiebanner');
979
+ return tab.elementExists('#CybotCookiebotDialog,#dtcookie-container,#cookiebanner,#cb-cookiebanner');
948
980
  }
949
981
  async optOut(tab) {
950
982
  if (await tab.elementExists('.cookie-alert-extended-detail-link')) {
@@ -983,6 +1015,10 @@ class Cookiebot extends AutoConsentBase {
983
1015
  await tab.eval('Cookiebot.dialog.submitConsent() || true');
984
1016
  await tab.wait(500);
985
1017
  }
1018
+ // site with 3rd confirm settings modal
1019
+ if (await tab.elementExists('#cb-confirmedSettings')) {
1020
+ await tab.eval('endCookieProcess()');
1021
+ }
986
1022
  return true;
987
1023
  }
988
1024
  async optIn(tab) {
@@ -1142,12 +1178,47 @@ class Evidon extends AutoConsentBase {
1142
1178
  }
1143
1179
  }
1144
1180
 
1181
+ class Onetrust extends AutoConsentBase {
1182
+ constructor() {
1183
+ super("Onetrust");
1184
+ this.prehideSelectors = ["#onetrust-banner-sdk,#onetrust-consent-sdk,.optanon-alert-box-wrapper,.onetrust-pc-dark-filter,.js-consent-banner"];
1185
+ }
1186
+ detectCmp(tab) {
1187
+ return tab.elementExists("#onetrust-banner-sdk,.optanon-alert-box-wrapper");
1188
+ }
1189
+ detectPopup(tab) {
1190
+ return tab.elementsAreVisible("#onetrust-banner-sdk,.optanon-alert-box-wrapper");
1191
+ }
1192
+ async optOut(tab) {
1193
+ if (await tab.elementExists("#onetrust-pc-btn-handler")) { // "show purposes" button inside a popup
1194
+ await success(tab.clickElement("#onetrust-pc-btn-handler"));
1195
+ }
1196
+ else { // otherwise look for a generic "show settings" button
1197
+ await success(tab.clickElement(".ot-sdk-show-settings,button.js-cookie-settings"));
1198
+ }
1199
+ await success(tab.waitForElement("#onetrust-consent-sdk", 2000));
1200
+ await success(tab.wait(1000));
1201
+ await tab.clickElements("#onetrust-consent-sdk input.category-switch-handler:checked,.js-editor-toggle-state:checked"); // optional step
1202
+ await success(tab.waitForThenClick(".save-preference-btn-handler,.js-consent-save", 1000));
1203
+ // popup doesn't disappear immediately
1204
+ await waitFor(async () => !(await tab.elementsAreVisible("#onetrust-banner-sdk")), 10, 500);
1205
+ return true;
1206
+ }
1207
+ async optIn(tab) {
1208
+ return tab.clickElement("onetrust-accept-btn-handler,js-accept-cookies");
1209
+ }
1210
+ async test(tab) {
1211
+ return tab.eval("window.OnetrustActiveGroups.split(',').filter(s => s.length > 0).length <= 1");
1212
+ }
1213
+ }
1214
+
1145
1215
  const rules = [
1146
1216
  new TrustArc(),
1147
1217
  new Cookiebot(),
1148
1218
  new SourcePoint(),
1149
1219
  new ConsentManager(),
1150
1220
  new Evidon(),
1221
+ new Onetrust(),
1151
1222
  ];
1152
1223
  function createAutoCMP(config) {
1153
1224
  return new AutoConsent(config);
@@ -1219,7 +1290,7 @@ async function prehideElements(tab, rules) {
1219
1290
  }
1220
1291
  return selectorList;
1221
1292
  }, globalHidden);
1222
- await tab.hideElements(selectors);
1293
+ await tab.hideElements(selectors, undefined, 'opacity');
1223
1294
  }
1224
1295
 
1225
1296
  class AutoConsent$1 {