@duckduckgo/autoconsent 14.0.1 → 14.2.0

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 (53) hide show
  1. package/.github/actions/setup-release-scripts/action.yml +1 -1
  2. package/.github/workflows/checks.yml +4 -4
  3. package/.github/workflows/release.yml +2 -2
  4. package/.github/workflows/update-filterlist.yml +2 -2
  5. package/CHANGELOG.md +43 -0
  6. package/api.md +1 -0
  7. package/dist/addon-firefox/background.bundle.js +11 -2
  8. package/dist/addon-firefox/content.bundle.js +510 -347
  9. package/dist/addon-firefox/manifest.json +1 -1
  10. package/dist/addon-firefox/rules.json +1 -1
  11. package/dist/addon-mv3/background.bundle.js +11 -2
  12. package/dist/addon-mv3/content.bundle.js +510 -347
  13. package/dist/addon-mv3/manifest.json +1 -1
  14. package/dist/addon-mv3/popup.bundle.js +19 -1
  15. package/dist/addon-mv3/popup.html +14 -0
  16. package/dist/addon-mv3/rules.json +1 -1
  17. package/dist/autoconsent.cjs.js +353 -219
  18. package/dist/autoconsent.esm.js +354 -219
  19. package/dist/autoconsent.extra.cjs.js +519 -347
  20. package/dist/autoconsent.extra.esm.js +520 -347
  21. package/dist/autoconsent.playwright.js +520 -348
  22. package/lib/cmps/admiral.ts +6 -6
  23. package/lib/cmps/base.ts +43 -8
  24. package/lib/cmps/consentmanager.ts +8 -7
  25. package/lib/cmps/cookiebot.ts +4 -4
  26. package/lib/cmps/evidon.ts +2 -2
  27. package/lib/cmps/klaro.ts +8 -8
  28. package/lib/cmps/onetrust.ts +6 -6
  29. package/lib/cmps/sourcepoint-frame.ts +12 -12
  30. package/lib/cmps/tiktok.ts +3 -3
  31. package/lib/cmps/trustarc-frame.ts +11 -11
  32. package/lib/cmps/trustarc-top.ts +2 -6
  33. package/lib/dom-actions.ts +6 -6
  34. package/lib/eval-snippets.ts +6 -1
  35. package/lib/filterlist-engine.ts +2 -2
  36. package/lib/messages.ts +6 -0
  37. package/lib/types.ts +3 -2
  38. package/lib/utils.ts +49 -0
  39. package/lib/web.ts +50 -37
  40. package/package.json +2 -2
  41. package/playwright/runner.ts +1 -1
  42. package/readme.md +1 -1
  43. package/rules/autoconsent/cookie-law-info.json +16 -5
  44. package/rules/autoconsent/cookiehub.json +61 -0
  45. package/rules/autoconsent/eu-cookie-compliance.json +13 -12
  46. package/rules/compact-rules.json +1 -1
  47. package/rules/filterlist.txt +221 -202
  48. package/rules/rules.json +1 -1
  49. package/tests/{cookielawinfo.spec.ts → cookie-law-info.spec.ts} +4 -1
  50. package/tests/cookiehub.spec.ts +8 -0
  51. package/tests/eu-cookie-compliance-banner.spec.ts +1 -1
  52. package/tests-wtr/dom-actions/dom-actions.click.ts +14 -14
  53. package/tests-wtr/utils/highlight.test.ts +166 -0
@@ -31,7 +31,7 @@ export default class Admiral extends AutoConsentCMPBase {
31
31
  "xpath///button[contains(., 'Afvis alle') or contains(., 'Reject all') or contains(., 'Odbaci sve') or contains(., 'Rechazar todo') or contains(., 'Atmesti visus') or contains(., 'Odmítnout vše') or contains(., 'Απόρριψη όλων') or contains(., 'Rejeitar tudo') or contains(., 'Tümünü reddet') or contains(., 'Отклонить все') or contains(., 'Noraidīt visu') or contains(., 'Avvisa alla') or contains(., 'Odrzuć wszystkie') or contains(., 'Alles afwijzen') or contains(., 'Отхвърляне на всички') or contains(., 'Rifiuta tutto') or contains(., 'Zavrni vse') or contains(., 'Az összes elutasítása') or contains(., 'Respingeți tot') or contains(., 'Alles ablehnen') or contains(., 'Tout rejeter') or contains(., 'Odmietnuť všetko') or contains(., 'Lükka kõik tagasi') or contains(., 'Hylkää kaikki')]";
32
32
 
33
33
  if (await this.waitForElement(rejectAllSelector, 500)) {
34
- return this.click(rejectAllSelector);
34
+ return await this.click(rejectAllSelector);
35
35
  }
36
36
 
37
37
  const purposesButtonSelector =
@@ -41,18 +41,18 @@ export default class Admiral extends AutoConsentCMPBase {
41
41
  "xpath///button[contains(., 'Spara & avsluta') or contains(., 'Save & exit') or contains(., 'Uložit a ukončit') or contains(., 'Enregistrer et quitter') or contains(., 'Speichern & Verlassen') or contains(., 'Tallenna ja poistu') or contains(., 'Išsaugoti ir išeiti') or contains(., 'Opslaan & afsluiten') or contains(., 'Guardar y salir') or contains(., 'Shrani in zapri') or contains(., 'Uložiť a ukončiť') or contains(., 'Kaydet ve çıkış yap') or contains(., 'Сохранить и выйти') or contains(., 'Salvesta ja välju') or contains(., 'Salva ed esci') or contains(., 'Gem & afslut') or contains(., 'Αποθήκευση και έξοδος') or contains(., 'Saglabāt un iziet') or contains(., 'Mentés és kilépés') or contains(., 'Guardar e sair') or contains(., 'Zapisz & zakończ') or contains(., 'Salvare și ieșire') or contains(., 'Spremi i izađi') or contains(., 'Запазване и изход')]";
42
42
 
43
43
  if ((await this.waitForThenClick(purposesButtonSelector)) && (await this.waitForVisible(saveAndExitSelector))) {
44
- const popupBody = this.elementSelector(saveAndExitSelector)[0].parentElement.parentElement;
45
- const checkboxes = popupBody.querySelectorAll('input[type=checkbox]:checked');
46
- checkboxes.forEach((checkbox: HTMLElement) => checkbox.click());
44
+ const popupBody = this.elementSelector(saveAndExitSelector)[0].parentElement?.parentElement;
45
+ const checkboxes = popupBody?.querySelectorAll<HTMLElement>('input[type=checkbox]:checked');
46
+ checkboxes?.forEach((checkbox) => checkbox.click());
47
47
 
48
- return this.click(saveAndExitSelector);
48
+ return await this.click(saveAndExitSelector);
49
49
  }
50
50
 
51
51
  return false;
52
52
  }
53
53
 
54
54
  async optIn() {
55
- return this.click(
55
+ return await this.click(
56
56
  "xpath///button[contains(., 'Sprejmi vse') or contains(., 'Prihvati sve') or contains(., 'Godkänn alla') or contains(., 'Prijať všetko') or contains(., 'Принять все') or contains(., 'Aceptar todo') or contains(., 'Αποδοχή όλων') or contains(., 'Zaakceptuj wszystkie') or contains(., 'Accetta tutto') or contains(., 'Priimti visus') or contains(., 'Pieņemt visu') or contains(., 'Tümünü kabul et') or contains(., 'Az összes elfogadása') or contains(., 'Accept all') or contains(., 'Приемане на всички') or contains(., 'Accepter alle') or contains(., 'Hyväksy kaikki') or contains(., 'Tout accepter') or contains(., 'Alles accepteren') or contains(., 'Aktsepteeri kõik') or contains(., 'Přijmout vše') or contains(., 'Alles akzeptieren') or contains(., 'Aceitar tudo') or contains(., 'Acceptați tot')]",
57
57
  );
58
58
  }
package/lib/cmps/base.ts CHANGED
@@ -3,6 +3,7 @@ import { AutoConsentCMPRule, AutoConsentRuleStep, ElementSelector, HideMethod, R
3
3
  import { requestEval } from '../eval-handler';
4
4
  import AutoConsent from '../web';
5
5
  import { getFunctionBody, snippets } from '../eval-snippets';
6
+ import { highlightNode, unhighlightNode } from '../utils';
6
7
 
7
8
  export async function success(action: Promise<boolean>): Promise<boolean> {
8
9
  const result = await action;
@@ -19,7 +20,7 @@ export const defaultRunContext: RunContext = {
19
20
  };
20
21
 
21
22
  export default class AutoConsentCMPBase implements AutoCMP, DomActionsProvider {
22
- name: string;
23
+ name: string = 'BASERULE';
23
24
  runContext: RunContext = defaultRunContext;
24
25
  autoconsent: AutoConsent;
25
26
 
@@ -94,7 +95,7 @@ export default class AutoConsentCMPBase implements AutoCMP, DomActionsProvider {
94
95
  }
95
96
 
96
97
  hasMatchingUrlPattern(): boolean {
97
- return this.runContext?.urlPattern && !!window.location.href.match(this.runContext.urlPattern);
98
+ return Boolean(this.runContext?.urlPattern && window.location.href.match(this.runContext.urlPattern));
98
99
  }
99
100
 
100
101
  detectCmp(): Promise<boolean> {
@@ -122,8 +123,35 @@ export default class AutoConsentCMPBase implements AutoCMP, DomActionsProvider {
122
123
  return Promise.resolve(true);
123
124
  }
124
125
 
126
+ async highlightElements(selector: ElementSelector, all = false, delayTimeout = 2000) {
127
+ let elements = this.elementSelector(selector);
128
+ if (elements.length === 0) {
129
+ return;
130
+ }
131
+ if (!all) {
132
+ elements = [elements[0]];
133
+ }
134
+
135
+ this.autoconsent.sendContentMessage({
136
+ type: 'visualDelay',
137
+ timeout: delayTimeout,
138
+ });
139
+
140
+ for (const el of elements) {
141
+ this.autoconsent.config.logs.rulesteps && console.log('highlighting', el);
142
+ highlightNode(el);
143
+ }
144
+ await this.wait(delayTimeout);
145
+ for (const el of elements) {
146
+ unhighlightNode(el);
147
+ }
148
+ }
149
+
125
150
  // Implementing DomActionsProvider below:
126
- click(selector: ElementSelector, all = false) {
151
+ async click(selector: ElementSelector, all = false) {
152
+ if (this.autoconsent.config.visualTest) {
153
+ await this.highlightElements(selector, all);
154
+ }
127
155
  return this.autoconsent.domActions.click(selector, all);
128
156
  }
129
157
 
@@ -131,7 +159,7 @@ export default class AutoConsentCMPBase implements AutoCMP, DomActionsProvider {
131
159
  return this.autoconsent.domActions.elementExists(selector);
132
160
  }
133
161
 
134
- elementVisible(selector: ElementSelector, check: VisibilityCheck) {
162
+ elementVisible(selector: ElementSelector, check?: VisibilityCheck) {
135
163
  return this.autoconsent.domActions.elementVisible(selector, check);
136
164
  }
137
165
 
@@ -143,7 +171,10 @@ export default class AutoConsentCMPBase implements AutoCMP, DomActionsProvider {
143
171
  return this.autoconsent.domActions.waitForVisible(selector, timeout, check);
144
172
  }
145
173
 
146
- waitForThenClick(selector: ElementSelector, timeout?: number, all?: boolean) {
174
+ async waitForThenClick(selector: ElementSelector, timeout?: number, all?: boolean) {
175
+ if (this.autoconsent.config.visualTest) {
176
+ await this.highlightElements(selector, all);
177
+ }
147
178
  return this.autoconsent.domActions.waitForThenClick(selector, timeout, all);
148
179
  }
149
180
 
@@ -151,7 +182,7 @@ export default class AutoConsentCMPBase implements AutoCMP, DomActionsProvider {
151
182
  return this.autoconsent.domActions.wait(ms);
152
183
  }
153
184
 
154
- hide(selector: string, method: HideMethod) {
185
+ hide(selector: string, method?: HideMethod) {
155
186
  return this.autoconsent.domActions.hide(selector, method);
156
187
  }
157
188
 
@@ -207,7 +238,7 @@ export class AutoConsentCMP extends AutoConsentCMPBase {
207
238
  }
208
239
 
209
240
  get prehideSelectors(): string[] {
210
- return this.rule.prehideSelectors;
241
+ return this.rule.prehideSelectors || [];
211
242
  }
212
243
 
213
244
  async detectCmp() {
@@ -250,7 +281,7 @@ export class AutoConsentCMP extends AutoConsentCMPBase {
250
281
  }
251
282
 
252
283
  async test() {
253
- if (this.hasSelfTest) {
284
+ if (this.hasSelfTest && this.rule.test) {
254
285
  return this._runRulesSequentially(this.rule.test, this.autoconsent.config.logs.rulesteps);
255
286
  }
256
287
  return super.test();
@@ -295,6 +326,10 @@ export class AutoConsentCMP extends AutoConsentCMPBase {
295
326
  console.error('invalid conditional rule', rule.if);
296
327
  return false;
297
328
  }
329
+ if (!rule.then) {
330
+ console.error('invalid conditional rule, missing "then" step', rule.if);
331
+ return false;
332
+ }
298
333
  const condition = await this.evaluateRuleStep(rule.if);
299
334
  logsConfig.rulesteps && console.log('Condition is', condition);
300
335
  if (condition) {
@@ -45,20 +45,20 @@ export default class ConsentManager extends AutoConsentCMPBase {
45
45
  return await this.mainWorldEval('EVAL_CONSENTMANAGER_3');
46
46
  }
47
47
 
48
- if (this.click('.cmpboxbtnno')) {
48
+ if (await this.click('.cmpboxbtnno')) {
49
49
  return true;
50
50
  }
51
51
 
52
52
  if (this.elementExists('.cmpwelcomeprpsbtn')) {
53
- this.click('.cmpwelcomeprpsbtn > a[aria-checked=true]', true);
54
- this.click('.cmpboxbtnsave');
53
+ await this.click('.cmpwelcomeprpsbtn > a[aria-checked=true]', true);
54
+ await this.click('.cmpboxbtnsave');
55
55
  return true;
56
56
  }
57
57
 
58
- this.click('.cmpboxbtncustom');
58
+ await this.click('.cmpboxbtncustom');
59
59
  await this.waitForElement('.cmptblbox', 2000);
60
- this.click('.cmptdchoice > a[aria-checked=true]', true);
61
- this.click('.cmpboxbtnyescustomchoices');
60
+ await this.click('.cmptdchoice > a[aria-checked=true]', true);
61
+ await this.click('.cmpboxbtnyescustomchoices');
62
62
 
63
63
  this.hide('#cmpwrapper,#cmpbox', 'display');
64
64
  return true;
@@ -68,12 +68,13 @@ export default class ConsentManager extends AutoConsentCMPBase {
68
68
  if (this.apiAvailable) {
69
69
  return await this.mainWorldEval('EVAL_CONSENTMANAGER_4');
70
70
  }
71
- return this.click('.cmpboxbtnyes');
71
+ return await this.click('.cmpboxbtnyes');
72
72
  }
73
73
 
74
74
  async test() {
75
75
  if (this.apiAvailable) {
76
76
  return await this.mainWorldEval('EVAL_CONSENTMANAGER_5');
77
77
  }
78
+ return false;
78
79
  }
79
80
  }
@@ -36,12 +36,12 @@ export default class Cookiebot extends AutoConsentCMPBase {
36
36
 
37
37
  async optIn() {
38
38
  if (this.elementExists('#dtcookie-container')) {
39
- return this.click('.h-dtcookie-accept');
39
+ return await this.click('.h-dtcookie-accept');
40
40
  }
41
41
 
42
- this.click('.CybotCookiebotDialogBodyLevelButton:not(:checked):enabled', true);
43
- this.click('#CybotCookiebotDialogBodyLevelButtonAccept');
44
- this.click('#CybotCookiebotDialogBodyButtonAccept');
42
+ await this.click('.CybotCookiebotDialogBodyLevelButton:not(:checked):enabled', true);
43
+ await this.click('#CybotCookiebotDialogBodyLevelButtonAccept');
44
+ await this.click('#CybotCookiebotDialogBodyButtonAccept');
45
45
  return true;
46
46
  }
47
47
 
@@ -25,7 +25,7 @@ export default class Evidon extends AutoConsentCMPBase {
25
25
  }
26
26
 
27
27
  async optOut() {
28
- if (this.click('#_evidon-decline-button')) {
28
+ if (await this.click('#_evidon-decline-button')) {
29
29
  return true;
30
30
  }
31
31
 
@@ -40,6 +40,6 @@ export default class Evidon extends AutoConsentCMPBase {
40
40
  }
41
41
 
42
42
  async optIn() {
43
- return this.click('#_evidon-accept-button');
43
+ return await this.click('#_evidon-accept-button');
44
44
  }
45
45
  }
package/lib/cmps/klaro.ts CHANGED
@@ -36,33 +36,33 @@ export default class Klaro extends AutoConsentCMPBase {
36
36
  }
37
37
  // if the API is broken for some reason, try clicking instead
38
38
 
39
- if (this.click('.klaro .cn-decline')) {
39
+ if (await this.click('.klaro .cn-decline')) {
40
40
  return true;
41
41
  }
42
42
 
43
43
  // open popup via Javascript API
44
44
  await this.mainWorldEval('EVAL_KLARO_OPEN_POPUP');
45
45
 
46
- if (this.click('.klaro .cn-decline')) {
46
+ if (await this.click('.klaro .cn-decline')) {
47
47
  return true;
48
48
  }
49
49
 
50
- this.click(
50
+ await this.click(
51
51
  '.cm-purpose:not(.cm-toggle-all) > input:not(.half-checked,.required,.only-required),.cm-purpose:not(.cm-toggle-all) > div > input:not(.half-checked,.required,.only-required)',
52
52
  true,
53
53
  );
54
- return this.click('.cm-btn-accept,.cm-button');
54
+ return await this.click('.cm-btn-accept,.cm-button');
55
55
  }
56
56
 
57
57
  async optIn() {
58
- if (this.click('.klaro .cm-btn-accept-all')) {
58
+ if (await this.click('.klaro .cm-btn-accept-all')) {
59
59
  return true;
60
60
  }
61
61
  if (this.settingsOpen) {
62
- this.click('.cm-purpose:not(.cm-toggle-all) > input.half-checked', true);
63
- return this.click('.cm-btn-accept');
62
+ await this.click('.cm-purpose:not(.cm-toggle-all) > input.half-checked', true);
63
+ return await this.click('.cm-btn-accept');
64
64
  }
65
- return this.click('.klaro .cookie-notice .cm-btn-success');
65
+ return await this.click('.klaro .cookie-notice .cm-btn-success');
66
66
  }
67
67
 
68
68
  async test() {
@@ -28,24 +28,24 @@ export default class Onetrust extends AutoConsentCMPBase {
28
28
  async optOut() {
29
29
  if (this.elementVisible('#onetrust-reject-all-handler,.ot-pc-refuse-all-handler,.js-reject-cookies', 'any')) {
30
30
  // 'reject all' shortcut
31
- return this.click('#onetrust-reject-all-handler,.ot-pc-refuse-all-handler,.js-reject-cookies');
31
+ return await this.click('#onetrust-reject-all-handler,.ot-pc-refuse-all-handler,.js-reject-cookies');
32
32
  }
33
33
 
34
34
  if (this.elementExists('#onetrust-pc-btn-handler')) {
35
35
  // "show purposes" button inside a popup
36
- this.click('#onetrust-pc-btn-handler');
36
+ await this.click('#onetrust-pc-btn-handler');
37
37
  } else {
38
38
  // otherwise look for a generic "show settings" button
39
- this.click('.ot-sdk-show-settings,button.js-cookie-settings');
39
+ await this.click('.ot-sdk-show-settings,button.js-cookie-settings');
40
40
  }
41
41
 
42
42
  await this.waitForElement('#onetrust-consent-sdk', 2000);
43
43
  await this.wait(1000); // ideally we want to wait for popup visivility, but it's tricky on e.g. stackoverflow.com
44
- this.click('#onetrust-consent-sdk input.category-switch-handler:checked,.js-editor-toggle-state:checked', true); // optional step
44
+ await this.click('#onetrust-consent-sdk input.category-switch-handler:checked,.js-editor-toggle-state:checked', true); // optional step
45
45
 
46
46
  await this.wait(1000); // ideally we want to wait for popup visivility, but it's tricky on e.g. stackoverflow.com
47
47
  await this.waitForElement('.save-preference-btn-handler,.js-consent-save', 2000);
48
- this.click('.save-preference-btn-handler,.js-consent-save');
48
+ await this.click('.save-preference-btn-handler,.js-consent-save');
49
49
 
50
50
  // popup doesn't disappear immediately
51
51
  await this.waitForVisible('#onetrust-banner-sdk', 5000, 'none');
@@ -53,7 +53,7 @@ export default class Onetrust extends AutoConsentCMPBase {
53
53
  }
54
54
 
55
55
  async optIn() {
56
- return this.click('#onetrust-accept-btn-handler,#accept-recommended-btn-handler,.js-accept-cookies');
56
+ return await this.click('#onetrust-accept-btn-handler,#accept-recommended-btn-handler,.js-accept-cookies');
57
57
  }
58
58
 
59
59
  async test() {
@@ -62,11 +62,11 @@ export default class SourcePoint extends AutoConsentCMPBase {
62
62
 
63
63
  async optIn() {
64
64
  await this.waitForElement('.sp_choice_type_11,.sp_choice_type_ACCEPT_ALL', 2000);
65
- if (this.click('.sp_choice_type_11')) {
65
+ if (await this.click('.sp_choice_type_11')) {
66
66
  return true;
67
67
  }
68
68
 
69
- if (this.click('.sp_choice_type_ACCEPT_ALL')) {
69
+ if (await this.click('.sp_choice_type_ACCEPT_ALL')) {
70
70
  return true;
71
71
  }
72
72
  return false;
@@ -96,20 +96,20 @@ export default class SourcePoint extends AutoConsentCMPBase {
96
96
  for (const t of switches) {
97
97
  t.click();
98
98
  }
99
- return this.click('.priv-save-btn');
99
+ return await this.click('.priv-save-btn');
100
100
  }
101
101
 
102
102
  // sometimes there's a "Save and Exit" / "Essential cookies" button
103
103
  if (this.elementVisible('.sp_choice_type_SE', 'any')) {
104
104
  // click the "Do Not Sell" toggle if it exists
105
- this.click(
105
+ await this.click(
106
106
  [
107
107
  "xpath///div[contains(., 'Do not share my personal information') and contains(@class, 'switch-container')]",
108
108
  '.pm-switch[aria-checked=false] .slider',
109
109
  ],
110
110
  false,
111
111
  );
112
- return this.click('.sp_choice_type_SE');
112
+ return await this.click('.sp_choice_type_SE');
113
113
  }
114
114
 
115
115
  if (!this.isManagerOpen()) {
@@ -120,10 +120,10 @@ export default class SourcePoint extends AutoConsentCMPBase {
120
120
 
121
121
  if (!this.elementExists('.sp_choice_type_12,[data-choice="1739968508799"]')) {
122
122
  // do not sell button
123
- return this.click('.sp_choice_type_13');
123
+ return await this.click('.sp_choice_type_13');
124
124
  }
125
125
 
126
- this.click('.sp_choice_type_12,[data-choice="1739968508799"]');
126
+ await this.click('.sp_choice_type_12,[data-choice="1739968508799"]');
127
127
  // the page may navigate at this point but that's okay
128
128
  await waitFor(() => this.isManagerOpen(), 200, 100);
129
129
  }
@@ -148,18 +148,18 @@ export default class SourcePoint extends AutoConsentCMPBase {
148
148
 
149
149
  if (path === 0) {
150
150
  await this.waitForVisible(rejectSelector1);
151
- return this.click(rejectSelector1);
151
+ return await this.click(rejectSelector1);
152
152
  } else if (path === 1) {
153
- this.click(rejectSelector2);
153
+ await this.click(rejectSelector2);
154
154
  } else if (path === 2) {
155
155
  await this.waitForElement('.pm-features', 10000);
156
- this.click('.checked > span', true);
157
- this.click('.chevron');
156
+ await this.click('.checked > span', true);
157
+ await this.click('.chevron');
158
158
  }
159
159
  } catch (e) {
160
160
  logsConfig.errors && console.warn(e);
161
161
  }
162
162
  // TODO: race condition: if the reject button was clicked, the popup disappears very quickly, so the background script may not receive a success report.
163
- return this.click('.sp_choice_type_SAVE_AND_EXIT');
163
+ return await this.click('.sp_choice_type_SAVE_AND_EXIT');
164
164
  }
165
165
  }
@@ -34,13 +34,13 @@ export default class Tiktok extends AutoConsentCMPBase {
34
34
  }
35
35
 
36
36
  async detectPopup() {
37
- const banner = this.getShadowRoot().querySelector('.tiktok-cookie-banner') as HTMLElement;
37
+ const banner = this.getShadowRoot()?.querySelector('.tiktok-cookie-banner') as HTMLElement;
38
38
  return isElementVisible(banner);
39
39
  }
40
40
 
41
41
  async optOut() {
42
42
  const logsConfig = this.autoconsent.config.logs;
43
- const declineButton = this.getShadowRoot().querySelector('.button-wrapper button:first-child') as HTMLElement;
43
+ const declineButton = this.getShadowRoot()?.querySelector('.button-wrapper button:first-child') as HTMLElement;
44
44
  if (declineButton) {
45
45
  logsConfig.rulesteps && console.log('[clicking]', declineButton);
46
46
  declineButton.click();
@@ -53,7 +53,7 @@ export default class Tiktok extends AutoConsentCMPBase {
53
53
 
54
54
  async optIn() {
55
55
  const logsConfig = this.autoconsent.config.logs;
56
- const acceptButton = this.getShadowRoot().querySelector('.button-wrapper button:last-child') as HTMLElement;
56
+ const acceptButton = this.getShadowRoot()?.querySelector('.button-wrapper button:last-child') as HTMLElement;
57
57
  if (acceptButton) {
58
58
  logsConfig.rulesteps && console.log('[clicking]', acceptButton);
59
59
  acceptButton.click();
@@ -45,14 +45,14 @@ export default class TrustArcFrame extends AutoConsentCMPBase {
45
45
  );
46
46
  // splash screen -> hit more information
47
47
  if (this.elementExists('.shp')) {
48
- this.click('.shp');
48
+ await this.click('.shp');
49
49
  }
50
50
 
51
51
  await this.waitForElement('.prefPanel', 5000);
52
52
 
53
53
  // go to advanced settings if not yet shown
54
54
  if (this.elementVisible('.advance', 'any')) {
55
- this.click('.advance');
55
+ await this.click('.advance');
56
56
  }
57
57
 
58
58
  // takes a while to load the opt-in/opt-out buttons
@@ -74,7 +74,7 @@ export default class TrustArcFrame extends AutoConsentCMPBase {
74
74
  await waitFor(() => document.readyState === 'complete', 20, 100);
75
75
  await this.waitForElement('.mainContent[aria-hidden=false]', timeout);
76
76
 
77
- if (this.click('.rejectAll')) {
77
+ if (await this.click('.rejectAll')) {
78
78
  return true;
79
79
  }
80
80
 
@@ -82,22 +82,22 @@ export default class TrustArcFrame extends AutoConsentCMPBase {
82
82
  await this.waitForElement('.prefPanel[style="visibility: visible;"]', timeout);
83
83
  }
84
84
 
85
- if (this.click('#catDetails0')) {
86
- this.click('.submit');
85
+ if (await this.click('#catDetails0')) {
86
+ await this.click('.submit');
87
87
  this.waitForThenClick('#gwt-debug-close_id', timeout);
88
88
  return true;
89
89
  }
90
90
 
91
- if (this.click('.required')) {
91
+ if (await this.click('.required')) {
92
92
  this.waitForThenClick('#gwt-debug-close_id', timeout);
93
93
  return true;
94
94
  }
95
95
 
96
96
  await this.navigateToSettings();
97
97
 
98
- this.click('.switch span:nth-child(1):not(.active)', true);
98
+ await this.click('.switch span:nth-child(1):not(.active)', true);
99
99
 
100
- this.click('.submit');
100
+ await this.click('.submit');
101
101
 
102
102
  // at this point, iframe usually closes. Sometimes we need to close manually, but we don't wait for it to report success
103
103
  this.waitForThenClick('#gwt-debug-close_id', timeout * 10);
@@ -106,13 +106,13 @@ export default class TrustArcFrame extends AutoConsentCMPBase {
106
106
  }
107
107
 
108
108
  async optIn() {
109
- if (this.click('.call')) {
109
+ if (await this.click('.call')) {
110
110
  return true;
111
111
  }
112
112
  await this.navigateToSettings();
113
- this.click('.switch span:nth-child(2)', true);
113
+ await this.click('.switch span:nth-child(2)', true);
114
114
 
115
- this.click('.submit');
115
+ await this.click('.submit');
116
116
 
117
117
  // at this point, iframe usually closes. Sometimes we need to close manually, but we don't wait for it to report success
118
118
  this.waitForElement('#gwt-debug-close_id', 300000).then(() => {
@@ -56,10 +56,6 @@ export default class TrustArcTop extends AutoConsentCMPBase {
56
56
  return this.elementVisible(`${popupContent},${bannerOverlay},${bannerContainer}`, 'any');
57
57
  }
58
58
 
59
- openFrame() {
60
- this.click(cookieSettingsButton);
61
- }
62
-
63
59
  async optOut() {
64
60
  if (this._shortcutButton) {
65
61
  this._shortcutButton.click();
@@ -68,7 +64,7 @@ export default class TrustArcTop extends AutoConsentCMPBase {
68
64
 
69
65
  // hide elements permanently, so user doesn't see the popup
70
66
  hideElements(getStyleElement(), `.truste_popframe, .truste_overlay, .truste_box_overlay, ${bannerContainer}`);
71
- this.click(cookieSettingsButton);
67
+ await this.click(cookieSettingsButton);
72
68
 
73
69
  // schedule cleanup
74
70
  setTimeout(() => {
@@ -80,7 +76,7 @@ export default class TrustArcTop extends AutoConsentCMPBase {
80
76
 
81
77
  async optIn() {
82
78
  this._optInDone = true; // just a hack to force autoconsentDone
83
- return this.click(shortcutOptIn);
79
+ return await this.click(shortcutOptIn);
84
80
  }
85
81
 
86
82
  async openCmp() {
@@ -7,7 +7,7 @@ export class DomActions implements DomActionsProvider {
7
7
  // eslint-disable-next-line no-useless-constructor
8
8
  constructor(public autoconsentInstance: AutoConsent) {}
9
9
 
10
- click(selector: ElementSelector, all = false): boolean {
10
+ async click(selector: ElementSelector, all = false): Promise<boolean> {
11
11
  const elem = this.elementSelector(selector);
12
12
  this.autoconsentInstance.config.logs.rulesteps && console.log('[click]', selector, all, elem);
13
13
  if (elem.length > 0) {
@@ -25,7 +25,7 @@ export class DomActions implements DomActionsProvider {
25
25
  return exists;
26
26
  }
27
27
 
28
- elementVisible(selector: ElementSelector, check: VisibilityCheck): boolean {
28
+ elementVisible(selector: ElementSelector, check: VisibilityCheck = 'all'): boolean {
29
29
  const elem = this.elementSelector(selector);
30
30
  const results = new Array(elem.length);
31
31
  elem.forEach((e, i) => {
@@ -59,7 +59,7 @@ export class DomActions implements DomActionsProvider {
59
59
 
60
60
  async waitForThenClick(selector: ElementSelector, timeout = 10000, all = false): Promise<boolean> {
61
61
  await this.waitForElement(selector, timeout);
62
- return this.click(selector, all);
62
+ return await this.click(selector, all);
63
63
  }
64
64
 
65
65
  wait(ms: number): Promise<true> {
@@ -76,7 +76,7 @@ export class DomActions implements DomActionsProvider {
76
76
  return document.cookie.includes(substring);
77
77
  }
78
78
 
79
- hide(selector: string, method: HideMethod): boolean {
79
+ hide(selector: string, method?: HideMethod): boolean {
80
80
  this.autoconsentInstance.config.logs.rulesteps && console.log('[hide]', selector);
81
81
  const styleEl = getStyleElement();
82
82
  return hideElements(styleEl, selector, method);
@@ -118,7 +118,7 @@ export class DomActions implements DomActionsProvider {
118
118
  if (selector.startsWith('xpath/')) {
119
119
  const xpath = selector.slice(6);
120
120
  const result = document.evaluate(xpath, parent, null, XPathResult.ANY_TYPE, null);
121
- let node: Node = null;
121
+ let node: Node | null = null;
122
122
  const elements: HTMLElement[] = [];
123
123
  while ((node = result.iterateNext())) {
124
124
  elements.push(node as HTMLElement);
@@ -142,7 +142,7 @@ export class DomActions implements DomActionsProvider {
142
142
 
143
143
  querySelectorChain(selectors: string[]): HTMLElement[] {
144
144
  let parent: ParentNode = document;
145
- let matches: HTMLElement[];
145
+ let matches: HTMLElement[] = [];
146
146
  for (const selector of selectors) {
147
147
  matches = this.querySingleReplySelector(selector, parent);
148
148
  if (matches.length === 0) {
@@ -79,7 +79,12 @@ export const snippets = {
79
79
  EVAL_COINBASE_0: () =>
80
80
  JSON.parse(decodeURIComponent(document.cookie.match(/cm_(eu|default)_preferences=([0-9a-zA-Z\\{\\}\\[\\]%:]*);?/)[2])).consent
81
81
  .length <= 1,
82
- EVAL_COOKIE_LAW_INFO_0: () => CLI.disableAllCookies() || CLI.reject_close() || true,
82
+ EVAL_COOKIE_LAW_INFO_0: () => {
83
+ if (CLI.disableAllCookies) CLI.disableAllCookies();
84
+ if (CLI.reject_close) CLI.reject_close();
85
+ document.body.classList.remove('cli-barmodal-open');
86
+ return true;
87
+ },
83
88
  EVAL_COOKIE_LAW_INFO_DETECT: () => !!window.CLI,
84
89
  EVAL_COOKIE_MANAGER_POPUP_0: () =>
85
90
  JSON.parse(