@duckduckgo/autoconsent 1.0.5 → 1.0.6

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.
@@ -1,9 +1,8 @@
1
1
  import { matches, executeAction } from "./consentomatic/index";
2
2
  import { ContentScriptMessage } from "../messages";
3
+ import { hideElementsUtil, getStyleElementUtil } from "./content-utils";
3
4
 
4
5
  let actionQueue = Promise.resolve(null);
5
- const styleOverrideElementId = "autoconsent-css-rules";
6
- const styleSelector = `style#${styleOverrideElementId}`;
7
6
 
8
7
  export default function handleMessage(message: ContentScriptMessage, debug = false) {
9
8
  if (message.type === "click") {
@@ -25,8 +24,9 @@ export default function handleMessage(message: ContentScriptMessage, debug = fal
25
24
  const elem = document.querySelectorAll<HTMLElement>(message.selector);
26
25
  const results = new Array(elem.length);
27
26
  elem.forEach((e, i) => {
28
- results[i] = e.offsetParent !== null || window.getComputedStyle(e).display !== "none" || e.style?.display !== "none";
27
+ results[i] = e.offsetParent !== null || window.getComputedStyle(e).display !== "none"; // TODO: handle visibility and z-index?
29
28
  });
29
+ debug && console.log("[visible?]", message.selector, elem, results);
30
30
  if (results.length === 0) {
31
31
  return false;
32
32
  } else if (message.check === "any") {
@@ -38,35 +38,21 @@ export default function handleMessage(message: ContentScriptMessage, debug = fal
38
38
  return results.every(r => r);
39
39
  } else if (message.type === "getAttribute") {
40
40
  const elem = document.querySelector(message.selector);
41
+ debug && console.log("[getAttribute]", message.selector, elem);
41
42
  if (!elem) {
42
43
  return false;
43
44
  }
44
45
  return elem.getAttribute(message.attribute);
45
46
  } else if (message.type === "eval") {
46
47
  // TODO: chrome support
48
+ debug && console.log("about to [eval]", message.script); // this will not show in Webkit console
47
49
  const result = window.eval(message.script); // eslint-disable-line no-eval
48
- debug && console.log("[eval]", message.script, result);
49
50
  return result;
50
51
  } else if (message.type === "hide") {
51
- const parent =
52
- document.head ||
53
- document.getElementsByTagName("head")[0] ||
54
- document.documentElement;
55
- const rule = `${message.selectors.join(",")} { display: none !important; z-index: -1 !important; } `;
56
- const existingElement = document.querySelector(styleSelector);
57
- debug && console.log("[hide]", message.selectors, !!existingElement);
58
- if (existingElement && existingElement instanceof HTMLStyleElement) {
59
- existingElement.innerText += rule;
60
- } else {
61
- const css = document.createElement("style");
62
- css.type = "text/css";
63
- css.id = styleOverrideElementId;
64
- css.appendChild(document.createTextNode(rule));
65
- parent.appendChild(css);
66
- }
67
- return message.selectors.length > 0;
52
+ debug && console.log("[hide]", message.selectors);
53
+ return hideElementsUtil(message.selectors, message.method);
68
54
  } else if (message.type === "undohide") {
69
- const existingElement = document.querySelector(styleSelector);
55
+ const existingElement = getStyleElementUtil();
70
56
  debug && console.log("[unhide]", !!existingElement);
71
57
  if (existingElement) {
72
58
  existingElement.remove();
@@ -74,8 +60,10 @@ export default function handleMessage(message: ContentScriptMessage, debug = fal
74
60
  return !!existingElement
75
61
  } else if (message.type === "matches") {
76
62
  const matched = matches(message.config);
63
+ debug && console.log("[matches?]", message.config.type, JSON.stringify(message.config), matched);
77
64
  return matched;
78
65
  } else if (message.type === "executeAction") {
66
+ debug && console.log("[executeAction]", message);
79
67
  actionQueue = actionQueue.then(() => executeAction(message.config, message.param));
80
68
  return true;
81
69
  }
package/lib/web/tab.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { waitFor } from "../cmps/base";
2
+ import { enableLogs } from "../config";
2
3
  export default class TabActions {
3
4
  constructor(tabId, frame, sendContentMessage, browser) {
4
5
  this.frame = frame;
@@ -7,7 +8,6 @@ export default class TabActions {
7
8
  this.id = tabId;
8
9
  }
9
10
  async elementExists(selector, frameId = 0) {
10
- console.log(`check for ${selector} in tab ${this.id}, frame ${frameId}`);
11
11
  return this.sendContentMessage(this.id, {
12
12
  type: "elemExists",
13
13
  selector
@@ -16,7 +16,7 @@ export default class TabActions {
16
16
  });
17
17
  }
18
18
  async clickElement(selector, frameId = 0) {
19
- console.log(`click element ${selector} in tab ${this.id}`);
19
+ enableLogs && console.log(`click element ${selector} in tab ${this.id}`);
20
20
  return this.sendContentMessage(this.id, {
21
21
  type: "click",
22
22
  selector
@@ -25,7 +25,7 @@ export default class TabActions {
25
25
  });
26
26
  }
27
27
  async clickElements(selector, frameId = 0) {
28
- console.log(`click elements ${selector} in tab ${this.id}`);
28
+ enableLogs && console.log(`click elements ${selector} in tab ${this.id}`);
29
29
  return this.sendContentMessage(this.id, {
30
30
  type: "click",
31
31
  all: true,
@@ -68,10 +68,12 @@ export default class TabActions {
68
68
  }
69
69
  return false;
70
70
  }
71
- async hideElements(selectors, frameId = 0) {
71
+ async hideElements(selectors, frameId = 0, method = 'display') {
72
+ enableLogs && console.log('Sending hide elements to', this.id, selectors);
72
73
  return this.sendContentMessage(this.id, {
73
74
  type: "hide",
74
- selectors
75
+ selectors,
76
+ method,
75
77
  }, { frameId });
76
78
  }
77
79
  async undoHideElements(frameId = 0) {
@@ -86,8 +88,12 @@ export default class TabActions {
86
88
  return this.browser.tabs.update(this.id, { url });
87
89
  }
88
90
  wait(ms) {
91
+ enableLogs && console.log(`waiting for ${ms}ms in tab ${this.id}`);
89
92
  return new Promise(resolve => {
90
- setTimeout(() => resolve(true), ms);
93
+ setTimeout(() => {
94
+ enableLogs && console.log(`done waiting in tab ${this.id}`);
95
+ resolve(true);
96
+ }, ms);
91
97
  });
92
98
  }
93
99
  matches(matcherConfig) {
package/lib/web/tab.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  import { waitFor } from "../cmps/base";
2
+ import { enableLogs } from "../config";
3
+ import { HideMethod } from "../messages";
2
4
  import { TabActor, MessageSender, Browser } from "../types";
3
5
 
4
6
  export default class TabActions implements TabActor {
@@ -14,7 +16,6 @@ export default class TabActions implements TabActor {
14
16
  }
15
17
 
16
18
  async elementExists(selector: string, frameId = 0) {
17
- console.log(`check for ${selector} in tab ${this.id}, frame ${frameId}`);
18
19
  return this.sendContentMessage(
19
20
  this.id,
20
21
  {
@@ -28,7 +29,7 @@ export default class TabActions implements TabActor {
28
29
  }
29
30
 
30
31
  async clickElement(selector: string, frameId = 0) {
31
- console.log(`click element ${selector} in tab ${this.id}`);
32
+ enableLogs && console.log(`click element ${selector} in tab ${this.id}`);
32
33
  return this.sendContentMessage(
33
34
  this.id,
34
35
  {
@@ -42,7 +43,7 @@ export default class TabActions implements TabActor {
42
43
  }
43
44
 
44
45
  async clickElements(selector: string, frameId = 0) {
45
- console.log(`click elements ${selector} in tab ${this.id}`);
46
+ enableLogs && console.log(`click elements ${selector} in tab ${this.id}`);
46
47
  return this.sendContentMessage(
47
48
  this.id,
48
49
  {
@@ -111,12 +112,14 @@ export default class TabActions implements TabActor {
111
112
  return false;
112
113
  }
113
114
 
114
- async hideElements(selectors: string[], frameId = 0) {
115
+ async hideElements(selectors: string[], frameId = 0, method: HideMethod = 'display') {
116
+ enableLogs && console.log('Sending hide elements to', this.id, selectors);
115
117
  return this.sendContentMessage(
116
118
  this.id,
117
119
  {
118
120
  type: "hide",
119
- selectors
121
+ selectors,
122
+ method,
120
123
  },
121
124
  { frameId }
122
125
  );
@@ -141,8 +144,12 @@ export default class TabActions implements TabActor {
141
144
  }
142
145
 
143
146
  wait(ms: number): Promise<true> {
147
+ enableLogs && console.log(`waiting for ${ms}ms in tab ${this.id}`);
144
148
  return new Promise(resolve => {
145
- setTimeout(() => resolve(true), ms);
149
+ setTimeout(() => {
150
+ enableLogs && console.log(`done waiting in tab ${this.id}`);
151
+ resolve(true);
152
+ }, ms);
146
153
  });
147
154
  }
148
155
 
package/lib/web.js CHANGED
@@ -5,6 +5,7 @@ import detectDialog from './detector';
5
5
  import { rules, createAutoCMP } from './index';
6
6
  import { ConsentOMaticCMP } from './consentomatic/index';
7
7
  import prehideElements from './hider';
8
+ import { enableLogs } from './config';
8
9
  export * from './index';
9
10
  export { Tab, handleContentMessage, };
10
11
  export default class AutoConsent {
@@ -29,6 +30,7 @@ export default class AutoConsent {
29
30
  return new Tab(tabId, this.consentFrames.get(tabId), this.sendContentMessage, this.browser);
30
31
  }
31
32
  async checkTab(tabId, prehide = true) {
33
+ enableLogs && console.log('checking tab', tabId, this.consentFrames, this.tabCmps);
32
34
  const tab = this.createTab(tabId);
33
35
  if (prehide) {
34
36
  this.prehideElements(tab);
@@ -39,12 +41,15 @@ export default class AutoConsent {
39
41
  consent.checked.then((rule) => {
40
42
  if (this.consentFrames.has(tabId) && rule) {
41
43
  const frame = this.consentFrames.get(tabId);
44
+ enableLogs && console.log(`Found ${rule.name} in a nested iframe ${frame.id} inside tab ${tabId}`);
42
45
  if (frame.type === rule.name) {
43
46
  consent.tab.frame = frame;
44
47
  }
45
48
  }
49
+ enableLogs && console.log('finished checking tab', tabId, this.consentFrames, this.tabCmps);
46
50
  // no CMP detected, undo hiding
47
51
  if (!rule && prehide) {
52
+ enableLogs && console.log('no CMP detected, undo hiding');
48
53
  tab.undoHideElements();
49
54
  }
50
55
  });
package/lib/web.ts CHANGED
@@ -7,6 +7,7 @@ import { Browser, MessageSender, AutoCMP, TabActor } from './types';
7
7
  import { ConsentOMaticCMP, ConsentOMaticConfig } from './consentomatic/index';
8
8
  import { AutoConsentCMPRule } from './rules';
9
9
  import prehideElements from './hider';
10
+ import { enableLogs } from './config';
10
11
 
11
12
  export * from './index';
12
13
  export {
@@ -44,6 +45,7 @@ export default class AutoConsent {
44
45
  }
45
46
 
46
47
  async checkTab(tabId: number, prehide = true) {
48
+ enableLogs && console.log('checking tab', tabId, this.consentFrames, this.tabCmps);
47
49
  const tab = this.createTab(tabId);
48
50
  if (prehide) {
49
51
  this.prehideElements(tab);
@@ -54,12 +56,15 @@ export default class AutoConsent {
54
56
  consent.checked.then((rule) => {
55
57
  if (this.consentFrames.has(tabId) && rule) {
56
58
  const frame = this.consentFrames.get(tabId);
59
+ enableLogs && console.log(`Found ${rule.name} in a nested iframe ${frame.id} inside tab ${tabId}`);
57
60
  if (frame.type === rule.name) {
58
61
  consent.tab.frame = frame;
59
62
  }
60
63
  }
64
+ enableLogs && console.log('finished checking tab', tabId, this.consentFrames, this.tabCmps);
61
65
  // no CMP detected, undo hiding
62
66
  if (!rule && prehide) {
67
+ enableLogs && console.log('no CMP detected, undo hiding');
63
68
  tab.undoHideElements();
64
69
  }
65
70
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@duckduckgo/autoconsent",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "description": "",
5
5
  "main": "dist/autoconsent.cjs.js",
6
6
  "module": "dist/autoconsent.esm.js",
package/readme.md CHANGED
@@ -84,7 +84,7 @@ Returns true if an element returned from `document.querySelect(selector)` is cur
84
84
  "eval": "code"
85
85
  }
86
86
  ```
87
- Evaluates `code` in the context of the page and returns the truthiness of the result.
87
+ Evaluates `code` in the context of the page. NB: the result of this action depends on the truthiness of the evaluated expression, make sure it returns `true` in case of success.
88
88
 
89
89
  #### Wait for element
90
90
 
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "etsy",
3
+ "detectCmp": [{ "exists": "#gdpr-single-choice-overlay" }],
4
+ "detectPopup": [{ "visible": "#gdpr-single-choice-overlay" }],
5
+ "optOut": [
6
+ {"hide": ["#gdpr-single-choice-overlay", "#gdpr-privacy-settings"]},
7
+ {"click": "button[data-gdpr-open-full-settings]"},
8
+ {"wait": 500},
9
+ {"eval": "document.querySelectorAll('.gdpr-overlay-body input').forEach(toggle => { toggle.checked = false; }) || true"},
10
+ {"eval": "document.querySelector('.gdpr-overlay-view button[data-wt-overlay-close]').click() || true"}
11
+ ],
12
+ "optIn": [{"click": "button[data-gdpr-single-choice-accept]"}]
13
+ }
package/rules/rules.json CHANGED
@@ -392,6 +392,44 @@
392
392
  }
393
393
  ]
394
394
  },
395
+ {
396
+ "name": "etsy",
397
+ "detectCmp": [
398
+ {
399
+ "exists": "#gdpr-single-choice-overlay"
400
+ }
401
+ ],
402
+ "detectPopup": [
403
+ {
404
+ "visible": "#gdpr-single-choice-overlay"
405
+ }
406
+ ],
407
+ "optOut": [
408
+ {
409
+ "hide": [
410
+ "#gdpr-single-choice-overlay",
411
+ "#gdpr-privacy-settings"
412
+ ]
413
+ },
414
+ {
415
+ "click": "button[data-gdpr-open-full-settings]"
416
+ },
417
+ {
418
+ "wait": 500
419
+ },
420
+ {
421
+ "eval": "document.querySelectorAll('.gdpr-overlay-body input').forEach(toggle => { toggle.checked = false; }) || true"
422
+ },
423
+ {
424
+ "eval": "document.querySelector('.gdpr-overlay-view button[data-wt-overlay-close]').click() || true"
425
+ }
426
+ ],
427
+ "optIn": [
428
+ {
429
+ "click": "button[data-gdpr-single-choice-accept]"
430
+ }
431
+ ]
432
+ },
395
433
  {
396
434
  "name": "eu-cookie-compliance-banner",
397
435
  "isHidingRule": true,
@@ -909,54 +947,6 @@
909
947
  }
910
948
  ]
911
949
  },
912
- {
913
- "name": "Onetrust",
914
- "prehideSelectors": [
915
- "#onetrust-banner-sdk,#onetrust-consent-sdk,.optanon-alert-box-wrapper,.onetrust-pc-dark-filter,.js-consent-banner"
916
- ],
917
- "isHidingRule": true,
918
- "detectCmp": [
919
- {
920
- "exists": "#onetrust-banner-sdk,.optanon-alert-box-wrapper"
921
- }
922
- ],
923
- "detectPopup": [
924
- {
925
- "visible": "#onetrust-banner-sdk,.optanon-alert-box-wrapper"
926
- }
927
- ],
928
- "optOut": [
929
- {
930
- "click": "#onetrust-pc-btn-handler,.ot-sdk-show-settings,button.js-cookie-settings"
931
- },
932
- {
933
- "waitFor": "#onetrust-consent-sdk",
934
- "timeout": 2000
935
- },
936
- {
937
- "wait": 1000
938
- },
939
- {
940
- "click": "#onetrust-consent-sdk input.category-switch-handler:checked,.js-editor-toggle-state:checked",
941
- "all": true,
942
- "optional": true
943
- },
944
- {
945
- "waitForThenClick": ".save-preference-btn-handler,.js-consent-save",
946
- "timeout": 1000
947
- }
948
- ],
949
- "optIn": [
950
- {
951
- "click": "onetrust-accept-btn-handler,js-accept-cookies"
952
- }
953
- ],
954
- "test": [
955
- {
956
- "eval": "window.OnetrustActiveGroups.split(',').filter(s => s.length > 0).length <= 1"
957
- }
958
- ]
959
- },
960
950
  {
961
951
  "name": "osano",
962
952
  "prehideSelectors": [
@@ -0,0 +1,7 @@
1
+ import generateCMPTests from "./runner";
2
+
3
+ generateCMPTests('etsy', [
4
+ 'https://www.etsy.com/',
5
+ ], {
6
+ skipRegions: ["US"],
7
+ });
@@ -12,3 +12,9 @@ generateCMPTests('Onetrust', [
12
12
  ], {
13
13
  skipRegions: ['US', 'GB']
14
14
  });
15
+
16
+ generateCMPTests('Onetrust', [
17
+ "https://www.newyorker.com/",
18
+ ], {
19
+ skipRegions: ['US']
20
+ });
package/tests/runner.ts CHANGED
@@ -39,7 +39,7 @@ export function generateTest(url: string, expectedCmp: string, options: TestOpti
39
39
  }
40
40
  await page.goto(url, { waitUntil: 'commit' });
41
41
 
42
- const tab = autoconsent.attachToPage(page, url, rules, 20);
42
+ const tab = autoconsent.attachToPage(page, url, rules, 20, true);
43
43
  await tab.checked;
44
44
  expect(tab.getCMPName()).toBe(expectedCmp);
45
45
  expect(await tab.isPopupOpen(50, 100)).toBeTruthy();
@@ -1,24 +0,0 @@
1
- {
2
- "name": "Onetrust",
3
- "prehideSelectors": ["#onetrust-banner-sdk,#onetrust-consent-sdk,.optanon-alert-box-wrapper,.onetrust-pc-dark-filter,.js-consent-banner"],
4
- "isHidingRule": true,
5
- "detectCmp": [{ "exists": "#onetrust-banner-sdk,.optanon-alert-box-wrapper" }],
6
- "detectPopup": [{ "visible": "#onetrust-banner-sdk,.optanon-alert-box-wrapper" }],
7
- "optOut": [
8
- { "click": "#onetrust-pc-btn-handler,.ot-sdk-show-settings,button.js-cookie-settings" },
9
- { "waitFor": "#onetrust-consent-sdk", "timeout": 2000 },
10
- { "wait": 1000 },
11
- {
12
- "click": "#onetrust-consent-sdk input.category-switch-handler:checked,.js-editor-toggle-state:checked",
13
- "all": true,
14
- "optional": true
15
- },
16
- { "waitForThenClick": ".save-preference-btn-handler,.js-consent-save", "timeout": 1000 }
17
- ],
18
- "optIn": [{ "click": "onetrust-accept-btn-handler,js-accept-cookies" }],
19
- "test": [
20
- {
21
- "eval": "window.OnetrustActiveGroups.split(',').filter(s => s.length > 0).length <= 1"
22
- }
23
- ]
24
- }