@duckduckgo/autoconsent 4.3.2 → 4.4.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.
@@ -108,14 +108,8 @@
108
108
  return false;
109
109
  });
110
110
  }
111
- function click(selectorOrElements, all = false) {
112
- let elem = [];
113
- if (typeof selectorOrElements === 'string') {
114
- elem = Array.from(document.querySelectorAll(selectorOrElements));
115
- }
116
- else {
117
- elem = selectorOrElements;
118
- }
111
+ function click(selector, all = false) {
112
+ const elem = elementSelector(selector);
119
113
  if (elem.length > 0) {
120
114
  if (all) {
121
115
  elem.forEach((e) => e.click());
@@ -127,12 +121,12 @@
127
121
  return elem.length > 0;
128
122
  }
129
123
  function elementExists(selector) {
130
- const exists = document.querySelector(selector) !== null;
124
+ const exists = elementSelector(selector).length > 0;
131
125
  // enableLogs && console.log("[exists?]", selector, exists);
132
126
  return exists;
133
127
  }
134
128
  function elementVisible(selector, check) {
135
- const elem = document.querySelectorAll(selector);
129
+ const elem = elementSelector(selector);
136
130
  const results = new Array(elem.length);
137
131
  elem.forEach((e, i) => {
138
132
  // check for display: none
@@ -155,7 +149,7 @@
155
149
  const interval = 200;
156
150
  const times = Math.ceil((timeout) / interval);
157
151
  // enableLogs && console.log("[waitFor]", ruleStep.waitFor);
158
- return waitFor(() => document.querySelector(selector) !== null, times, interval);
152
+ return waitFor(() => elementSelector(selector).length > 0, times, interval);
159
153
  }
160
154
  function waitForVisible(selector, timeout = 10000, check = 'any') {
161
155
  const interval = 200;
@@ -193,6 +187,50 @@
193
187
  }
194
188
  return !!existingElement;
195
189
  }
190
+ function querySingleReplySelector(selector, parent = document) {
191
+ if (selector.startsWith('aria/')) {
192
+ return [];
193
+ }
194
+ if (selector.startsWith('xpath/')) {
195
+ const xpath = selector.slice(6);
196
+ const result = document.evaluate(xpath, parent, null, XPathResult.ANY_TYPE, null);
197
+ let node = null;
198
+ const elements = [];
199
+ // eslint-disable-next-line no-cond-assign
200
+ while (node = result.iterateNext()) {
201
+ elements.push(node);
202
+ }
203
+ return elements;
204
+ }
205
+ if (selector.startsWith('text/')) {
206
+ return [];
207
+ }
208
+ if (selector.startsWith('pierce/')) {
209
+ return [];
210
+ }
211
+ if (parent.shadowRoot) {
212
+ return Array.from(parent.shadowRoot.querySelectorAll(selector));
213
+ }
214
+ return Array.from(parent.querySelectorAll(selector));
215
+ }
216
+ function querySelectorChain(selectors) {
217
+ let parent = document;
218
+ let matches;
219
+ for (const selector of selectors) {
220
+ matches = querySingleReplySelector(selector, parent);
221
+ if (matches.length === 0) {
222
+ return [];
223
+ }
224
+ parent = matches[0];
225
+ }
226
+ return matches;
227
+ }
228
+ function elementSelector(selector) {
229
+ if (typeof selector === 'string') {
230
+ return querySingleReplySelector(selector);
231
+ }
232
+ return querySelectorChain(selector);
233
+ }
196
234
 
197
235
  /* eslint-disable no-restricted-syntax,no-await-in-loop,no-underscore-dangle */
198
236
  const defaultRunContext = {
@@ -294,6 +332,14 @@
294
332
  results.push(_runRulesSequentially(rule.else));
295
333
  }
296
334
  }
335
+ if (rule.any) {
336
+ for (const step of rule.any) {
337
+ if (await evaluateRuleStep(step)) {
338
+ return true;
339
+ }
340
+ }
341
+ return false;
342
+ }
297
343
  if (results.length === 0) {
298
344
  return false;
299
345
  }
@@ -664,12 +710,12 @@
664
710
  // toggles with 2 buttons
665
711
  const toggles = document.querySelectorAll('.priv-purpose-container .sp-switch-arrow-block a.neutral.on .right');
666
712
  for (const t of toggles) {
667
- click([t]);
713
+ t.click();
668
714
  }
669
715
  // switch toggles
670
716
  const switches = document.querySelectorAll('.priv-purpose-container .sp-switch-arrow-block a.switch-bg.on');
671
717
  for (const t of switches) {
672
- click([t]);
718
+ t.click();
673
719
  }
674
720
  return click('.priv-save-btn');
675
721
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "manifest_version": 2,
3
3
  "name": "Autoconsent",
4
- "version": "2023.6.20",
4
+ "version": "2023.6.22",
5
5
  "background": {
6
6
  "scripts": [
7
7
  "background.bundle.js"
@@ -4181,9 +4181,6 @@
4181
4181
  "#truyo-consent-module"
4182
4182
  ],
4183
4183
  "detectCmp": [
4184
- {
4185
- "wait": 1000
4186
- },
4187
4184
  {
4188
4185
  "exists": "#truyo-cookieBarContent"
4189
4186
  }
@@ -4267,6 +4264,80 @@
4267
4264
  }
4268
4265
  ]
4269
4266
  },
4267
+ {
4268
+ "name": "ubuntu.com",
4269
+ "prehideSelectors": [
4270
+ "dialog.cookie-policy"
4271
+ ],
4272
+ "detectCmp": [
4273
+ {
4274
+ "any": [
4275
+ {
4276
+ "exists": "dialog.cookie-policy header"
4277
+ },
4278
+ {
4279
+ "exists": "xpath///*[@id=\"modal\"]/div/header"
4280
+ }
4281
+ ]
4282
+ }
4283
+ ],
4284
+ "detectPopup": [
4285
+ {
4286
+ "any": [
4287
+ {
4288
+ "visible": "dialog header"
4289
+ },
4290
+ {
4291
+ "visible": "xpath///*[@id=\"modal\"]/div/header"
4292
+ }
4293
+ ]
4294
+ }
4295
+ ],
4296
+ "optIn": [
4297
+ {
4298
+ "any": [
4299
+ {
4300
+ "waitForThenClick": "#cookie-policy-button-accept"
4301
+ },
4302
+ {
4303
+ "waitForThenClick": "xpath///*[@id=\"cookie-policy-button-accept\"]"
4304
+ }
4305
+ ]
4306
+ }
4307
+ ],
4308
+ "optOut": [
4309
+ {
4310
+ "any": [
4311
+ {
4312
+ "waitForThenClick": "button.p-button"
4313
+ },
4314
+ {
4315
+ "waitForThenClick": "xpath///*[@id=\"cookie-policy-content\"]/p[4]/button[2]"
4316
+ }
4317
+ ]
4318
+ },
4319
+ {
4320
+ "waitForThenClick": ".p-switch__input:checked",
4321
+ "optional": true,
4322
+ "all": true
4323
+ },
4324
+ {
4325
+ "any": [
4326
+ {
4327
+ "waitForThenClick": "div > button"
4328
+ },
4329
+ {
4330
+ "waitForThenClick": "xpath///*[@id=\"modal\"]/div/button"
4331
+ }
4332
+ ]
4333
+ }
4334
+ ],
4335
+ "test": [
4336
+ {
4337
+ "eval": "document.cookie === '_cookies_accepted=essential'"
4338
+ }
4339
+ ]
4340
+ },
4270
4341
  {
4271
4342
  "name": "UK Cookie Consent",
4272
4343
  "prehideSelectors": [
@@ -108,14 +108,8 @@
108
108
  return false;
109
109
  });
110
110
  }
111
- function click(selectorOrElements, all = false) {
112
- let elem = [];
113
- if (typeof selectorOrElements === 'string') {
114
- elem = Array.from(document.querySelectorAll(selectorOrElements));
115
- }
116
- else {
117
- elem = selectorOrElements;
118
- }
111
+ function click(selector, all = false) {
112
+ const elem = elementSelector(selector);
119
113
  if (elem.length > 0) {
120
114
  if (all) {
121
115
  elem.forEach((e) => e.click());
@@ -127,12 +121,12 @@
127
121
  return elem.length > 0;
128
122
  }
129
123
  function elementExists(selector) {
130
- const exists = document.querySelector(selector) !== null;
124
+ const exists = elementSelector(selector).length > 0;
131
125
  // enableLogs && console.log("[exists?]", selector, exists);
132
126
  return exists;
133
127
  }
134
128
  function elementVisible(selector, check) {
135
- const elem = document.querySelectorAll(selector);
129
+ const elem = elementSelector(selector);
136
130
  const results = new Array(elem.length);
137
131
  elem.forEach((e, i) => {
138
132
  // check for display: none
@@ -155,7 +149,7 @@
155
149
  const interval = 200;
156
150
  const times = Math.ceil((timeout) / interval);
157
151
  // enableLogs && console.log("[waitFor]", ruleStep.waitFor);
158
- return waitFor(() => document.querySelector(selector) !== null, times, interval);
152
+ return waitFor(() => elementSelector(selector).length > 0, times, interval);
159
153
  }
160
154
  function waitForVisible(selector, timeout = 10000, check = 'any') {
161
155
  const interval = 200;
@@ -193,6 +187,50 @@
193
187
  }
194
188
  return !!existingElement;
195
189
  }
190
+ function querySingleReplySelector(selector, parent = document) {
191
+ if (selector.startsWith('aria/')) {
192
+ return [];
193
+ }
194
+ if (selector.startsWith('xpath/')) {
195
+ const xpath = selector.slice(6);
196
+ const result = document.evaluate(xpath, parent, null, XPathResult.ANY_TYPE, null);
197
+ let node = null;
198
+ const elements = [];
199
+ // eslint-disable-next-line no-cond-assign
200
+ while (node = result.iterateNext()) {
201
+ elements.push(node);
202
+ }
203
+ return elements;
204
+ }
205
+ if (selector.startsWith('text/')) {
206
+ return [];
207
+ }
208
+ if (selector.startsWith('pierce/')) {
209
+ return [];
210
+ }
211
+ if (parent.shadowRoot) {
212
+ return Array.from(parent.shadowRoot.querySelectorAll(selector));
213
+ }
214
+ return Array.from(parent.querySelectorAll(selector));
215
+ }
216
+ function querySelectorChain(selectors) {
217
+ let parent = document;
218
+ let matches;
219
+ for (const selector of selectors) {
220
+ matches = querySingleReplySelector(selector, parent);
221
+ if (matches.length === 0) {
222
+ return [];
223
+ }
224
+ parent = matches[0];
225
+ }
226
+ return matches;
227
+ }
228
+ function elementSelector(selector) {
229
+ if (typeof selector === 'string') {
230
+ return querySingleReplySelector(selector);
231
+ }
232
+ return querySelectorChain(selector);
233
+ }
196
234
 
197
235
  /* eslint-disable no-restricted-syntax,no-await-in-loop,no-underscore-dangle */
198
236
  const defaultRunContext = {
@@ -294,6 +332,14 @@
294
332
  results.push(_runRulesSequentially(rule.else));
295
333
  }
296
334
  }
335
+ if (rule.any) {
336
+ for (const step of rule.any) {
337
+ if (await evaluateRuleStep(step)) {
338
+ return true;
339
+ }
340
+ }
341
+ return false;
342
+ }
297
343
  if (results.length === 0) {
298
344
  return false;
299
345
  }
@@ -664,12 +710,12 @@
664
710
  // toggles with 2 buttons
665
711
  const toggles = document.querySelectorAll('.priv-purpose-container .sp-switch-arrow-block a.neutral.on .right');
666
712
  for (const t of toggles) {
667
- click([t]);
713
+ t.click();
668
714
  }
669
715
  // switch toggles
670
716
  const switches = document.querySelectorAll('.priv-purpose-container .sp-switch-arrow-block a.switch-bg.on');
671
717
  for (const t of switches) {
672
- click([t]);
718
+ t.click();
673
719
  }
674
720
  return click('.priv-save-btn');
675
721
  }
@@ -1,2 +1,65 @@
1
1
  /* global chrome */
2
- chrome.devtools.panels.create('Autoconsent', '/icons/cookie.png', "/devtools/panel.html")
2
+ chrome.devtools.panels.create(
3
+ "Autoconsent",
4
+ "/icons/cookie.png",
5
+ "/devtools/panel.html"
6
+ );
7
+
8
+ if (chrome.devtools?.recorder) {
9
+ class MyPlugin {
10
+ stringify(recording) {
11
+ const autoconsentSteps = recording.steps
12
+ .filter((step) => ["click"].includes(step.type))
13
+ .map(({ selectors }) => this.convertStep(selectors));
14
+ return Promise.resolve(JSON.stringify(autoconsentSteps, undefined, 4));
15
+ }
16
+ stringifyStep(step) {
17
+ return Promise.resolve(
18
+ JSON.stringify(
19
+ this.convertStep(step.selectors),
20
+ undefined,
21
+ 4
22
+ )
23
+ );
24
+ }
25
+ convertStep(selectors) {
26
+ return {
27
+ any: selectors.filter((s) => {
28
+ return this.isSupportedSelector(s)
29
+ }).map(s => {
30
+ if (s.length === 1) {
31
+ return {
32
+ waitForThenClick: s[0]
33
+ }
34
+ }
35
+ return {
36
+ waitForThenClick: s
37
+ }
38
+ })
39
+ }
40
+ }
41
+
42
+ /**
43
+ *
44
+ * @param {string | string[]} selector
45
+ * @returns
46
+ */
47
+ isSupportedSelector(selector) {
48
+ const unsupportedPrefixes = ['aria/', 'pierce/', 'text/']
49
+ if (!Array.isArray(selector)) {
50
+ return !unsupportedPrefixes.some(p => selector.startsWith(p))
51
+ }
52
+ // Chained xpath selectors are not supported
53
+ if (selector.length > 1 && selector.some(s => s.startsWith('xpath/'))) {
54
+ return false
55
+ }
56
+ return selector.every(s => this.isSupportedSelector(s))
57
+ }
58
+ }
59
+
60
+ chrome.devtools.recorder.registerRecorderExtensionPlugin(
61
+ new MyPlugin(),
62
+ /*name=*/ "Autoconsent",
63
+ /*mediaType=*/ "application/json"
64
+ );
65
+ }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "manifest_version": 3,
3
3
  "name": "Autoconsent",
4
- "version": "2023.6.20",
4
+ "version": "2023.6.22",
5
5
  "background": {
6
6
  "service_worker": "background.bundle.js"
7
7
  },
@@ -83,6 +83,7 @@
83
83
  const cosmeticOnRadio = document.querySelector('input#cosmetic-on');
84
84
  const cosmeticOffRadio = document.querySelector('input#cosmetic-off');
85
85
  const retriesInput = document.querySelector('input#retries');
86
+ const ruleReloadButton = document.querySelector('#reload');
86
87
  // enable proceed button when necessary
87
88
  const [currentTab] = await chrome.tabs.query({ active: true, lastFocusedWindow: true });
88
89
  const tabId = currentTab.id;
@@ -167,6 +168,12 @@
167
168
  }
168
169
  cosmeticOnRadio.addEventListener('change', cosmeticChange);
169
170
  cosmeticOffRadio.addEventListener('change', cosmeticChange);
171
+ ruleReloadButton.addEventListener('click', async () => {
172
+ const res = await fetch("./rules.json");
173
+ storageSet({
174
+ rules: await res.json(),
175
+ });
176
+ });
170
177
  }
171
178
  init();
172
179
 
@@ -13,6 +13,13 @@
13
13
  cursor: pointer;
14
14
  border-radius: 3px;
15
15
  }
16
+ #reload {
17
+ width: 100%;
18
+ height: 2em;
19
+ margin: 0.5em auto;
20
+ cursor: pointer;
21
+ border-radius: 2px;
22
+ }
16
23
  </style>
17
24
  </head>
18
25
  <body>
@@ -75,6 +82,7 @@
75
82
  <input type="number" id="retries" name="retries" value="20">
76
83
  <label for="retries">Detection attempts</label>
77
84
  </div>
85
+ <button id="reload">Reload rules</button>
78
86
  </fieldset>
79
87
  <script src="popup.bundle.js"></script>
80
88
  </body>
@@ -4181,9 +4181,6 @@
4181
4181
  "#truyo-consent-module"
4182
4182
  ],
4183
4183
  "detectCmp": [
4184
- {
4185
- "wait": 1000
4186
- },
4187
4184
  {
4188
4185
  "exists": "#truyo-cookieBarContent"
4189
4186
  }
@@ -4267,6 +4264,80 @@
4267
4264
  }
4268
4265
  ]
4269
4266
  },
4267
+ {
4268
+ "name": "ubuntu.com",
4269
+ "prehideSelectors": [
4270
+ "dialog.cookie-policy"
4271
+ ],
4272
+ "detectCmp": [
4273
+ {
4274
+ "any": [
4275
+ {
4276
+ "exists": "dialog.cookie-policy header"
4277
+ },
4278
+ {
4279
+ "exists": "xpath///*[@id=\"modal\"]/div/header"
4280
+ }
4281
+ ]
4282
+ }
4283
+ ],
4284
+ "detectPopup": [
4285
+ {
4286
+ "any": [
4287
+ {
4288
+ "visible": "dialog header"
4289
+ },
4290
+ {
4291
+ "visible": "xpath///*[@id=\"modal\"]/div/header"
4292
+ }
4293
+ ]
4294
+ }
4295
+ ],
4296
+ "optIn": [
4297
+ {
4298
+ "any": [
4299
+ {
4300
+ "waitForThenClick": "#cookie-policy-button-accept"
4301
+ },
4302
+ {
4303
+ "waitForThenClick": "xpath///*[@id=\"cookie-policy-button-accept\"]"
4304
+ }
4305
+ ]
4306
+ }
4307
+ ],
4308
+ "optOut": [
4309
+ {
4310
+ "any": [
4311
+ {
4312
+ "waitForThenClick": "button.p-button"
4313
+ },
4314
+ {
4315
+ "waitForThenClick": "xpath///*[@id=\"cookie-policy-content\"]/p[4]/button[2]"
4316
+ }
4317
+ ]
4318
+ },
4319
+ {
4320
+ "waitForThenClick": ".p-switch__input:checked",
4321
+ "optional": true,
4322
+ "all": true
4323
+ },
4324
+ {
4325
+ "any": [
4326
+ {
4327
+ "waitForThenClick": "div > button"
4328
+ },
4329
+ {
4330
+ "waitForThenClick": "xpath///*[@id=\"modal\"]/div/button"
4331
+ }
4332
+ ]
4333
+ }
4334
+ ],
4335
+ "test": [
4336
+ {
4337
+ "eval": "document.cookie === '_cookies_accepted=essential'"
4338
+ }
4339
+ ]
4340
+ },
4270
4341
  {
4271
4342
  "name": "UK Cookie Consent",
4272
4343
  "prehideSelectors": [