@duckduckgo/autoconsent 1.0.8 → 2.0.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 (154) hide show
  1. package/.eslintrc.cjs +14 -0
  2. package/.vscode/settings.json +7 -0
  3. package/Jenkinsfile +68 -39
  4. package/api.md +104 -0
  5. package/dist/autoconsent.cjs.js +1 -1387
  6. package/dist/autoconsent.esm.js +1 -1379
  7. package/dist/autoconsent.playwright.js +1 -0
  8. package/dist/autoconsent.standalone.js +1 -0
  9. package/lib/cmps/all.ts +15 -10
  10. package/lib/cmps/base.ts +91 -91
  11. package/lib/cmps/consentmanager.ts +31 -19
  12. package/lib/cmps/consentomatic.ts +89 -0
  13. package/lib/cmps/cookiebot.ts +58 -55
  14. package/lib/cmps/evidon.ts +29 -18
  15. package/lib/cmps/onetrust.ts +32 -20
  16. package/lib/cmps/sourcepoint-frame.ts +102 -0
  17. package/lib/cmps/sourcepoint-top.ts +47 -0
  18. package/lib/cmps/trustarc-frame.ts +115 -0
  19. package/lib/cmps/trustarc-top.ts +91 -0
  20. package/lib/consentomatic/index.ts +233 -70
  21. package/lib/{web/consentomatic → consentomatic}/tools.ts +0 -0
  22. package/lib/eval-handler.ts +58 -0
  23. package/lib/index.ts +0 -2
  24. package/lib/messages.ts +100 -0
  25. package/lib/rule-executors.ts +108 -0
  26. package/lib/rules.ts +82 -0
  27. package/lib/types.ts +35 -0
  28. package/lib/utils.ts +64 -0
  29. package/lib/web.ts +283 -74
  30. package/package.json +17 -14
  31. package/playwright/content.ts +27 -0
  32. package/playwright/runner.ts +131 -0
  33. package/playwright/standalone.ts +36 -0
  34. package/playwright.config.ts +7 -0
  35. package/readme.md +57 -47
  36. package/rollup.config.js +23 -15
  37. package/rules/autoconsent/baden-wuerttemberg-de.json +7 -3
  38. package/rules/autoconsent/bundesregierung-de.json +5 -1
  39. package/rules/autoconsent/cc-banner.json +0 -1
  40. package/rules/autoconsent/cookie-notice.json +0 -1
  41. package/rules/autoconsent/cookieconsent.json +5 -6
  42. package/rules/autoconsent/destatis-de.json +0 -1
  43. package/rules/autoconsent/etsy.json +3 -2
  44. package/rules/autoconsent/eu-cookie-compliance.json +0 -1
  45. package/rules/autoconsent/hl-co-uk.json +8 -9
  46. package/rules/autoconsent/johnlewis.json +5 -2
  47. package/rules/autoconsent/notice-cookie.json +0 -1
  48. package/rules/autoconsent/osano.json +0 -1
  49. package/rules/autoconsent/tealium.json +4 -5
  50. package/rules/rules.json +44 -37
  51. package/tests/192.spec.ts +1 -1
  52. package/tests/arzt-auskunft.spec.ts +1 -1
  53. package/tests/asus.spec.ts +1 -1
  54. package/tests/ausopen.spec.ts +1 -1
  55. package/tests/aws.amazon.spec.ts +1 -1
  56. package/tests/baden-wuerttemberg.spec.ts +1 -1
  57. package/tests/borlabs.spec.ts +1 -1
  58. package/tests/bundesregierung.spec.ts +5 -2
  59. package/tests/ccbanner.spec.ts +1 -1
  60. package/tests/consentmanager.spec.ts +3 -3
  61. package/tests/cookiebot.spec.ts +8 -2
  62. package/tests/cookieconsent.spec.ts +1 -1
  63. package/tests/cookielawinfo.spec.ts +1 -1
  64. package/tests/cookienotice.spec.ts +1 -1
  65. package/tests/corona-in-zahlen.spec.ts +1 -1
  66. package/tests/deepl.spec.ts +1 -1
  67. package/tests/destatis.spec.ts +1 -1
  68. package/tests/didomi.spec.ts +6 -2
  69. package/tests/drupal.spec.ts +8 -0
  70. package/tests/dunelm.spec.ts +1 -1
  71. package/tests/etsy.spec.ts +1 -1
  72. package/tests/eu-cookie-compliance-banner.spec.ts +1 -1
  73. package/tests/evidon.spec.ts +1 -1
  74. package/tests/fundingchoices.spec.ts +2 -1
  75. package/tests/gov-uk.spec.ts +1 -1
  76. package/tests/hl-co-uk.spec.ts +1 -1
  77. package/tests/hubspot.spec.ts +1 -1
  78. package/tests/ionos.spec.ts +1 -1
  79. package/tests/johnlewis.spec.ts +2 -2
  80. package/tests/klaro.spec.ts +1 -1
  81. package/tests/marksandspencer.spec.ts +1 -1
  82. package/tests/mediamarkt.spec.ts +1 -1
  83. package/tests/metoffice-gov-uk.spec.ts +1 -1
  84. package/tests/microsoft.spec.ts +1 -1
  85. package/tests/moneysavingexpert.spec.ts +1 -1
  86. package/tests/motor-talk.spec.ts +1 -1
  87. package/tests/national-lottery.spec.ts +1 -1
  88. package/tests/netflix.spec.ts +1 -1
  89. package/tests/nhs.spec.ts +1 -1
  90. package/tests/notice-cookie.spec.ts +1 -1
  91. package/tests/obi.spec.ts +1 -1
  92. package/tests/oil.spec.ts +1 -1
  93. package/tests/onetrust.spec.ts +10 -1
  94. package/tests/osano.spec.ts +1 -1
  95. package/tests/otto.spec.ts +1 -1
  96. package/tests/paypal.spec.ts +1 -1
  97. package/tests/quantcast.spec.ts +4 -1
  98. package/tests/snigel.spec.ts +1 -1
  99. package/tests/sourcepoint.spec.ts +8 -8
  100. package/tests/springer.spec.ts +1 -1
  101. package/tests/steampowered.spec.ts +1 -1
  102. package/tests/tealium.spec.ts +1 -1
  103. package/tests/testcmp.spec.ts +1 -1
  104. package/tests/thalia.spec.ts +1 -1
  105. package/tests/thefreedictionary.spec.ts +1 -1
  106. package/tests/trustarc.spec.ts +25 -4
  107. package/tests/usercentrics-1.spec.ts +1 -1
  108. package/tests/uswitch.spec.ts +1 -1
  109. package/tests/vodafone.spec.ts +1 -1
  110. package/tests/waitrose.spec.ts +1 -1
  111. package/tests/wetransfer.spec.ts +1 -1
  112. package/tests/wordpressgdpr.spec.ts +1 -1
  113. package/tests/xing.spec.ts +1 -1
  114. package/tsconfig.json +2 -2
  115. package/.eslintrc +0 -12
  116. package/cosmetics/rules.json +0 -110
  117. package/dist/autoconsent.puppet.js +0 -1078
  118. package/lib/cmps/all.js +0 -19
  119. package/lib/cmps/base.js +0 -174
  120. package/lib/cmps/consentmanager.js +0 -31
  121. package/lib/cmps/cookiebot.js +0 -77
  122. package/lib/cmps/evidon.js +0 -26
  123. package/lib/cmps/onetrust.js +0 -34
  124. package/lib/cmps/sourcepoint.js +0 -82
  125. package/lib/cmps/sourcepoint.ts +0 -95
  126. package/lib/cmps/trustarc.js +0 -106
  127. package/lib/cmps/trustarc.ts +0 -147
  128. package/lib/config.js +0 -1
  129. package/lib/consentomatic/index.js +0 -52
  130. package/lib/detector.js +0 -33
  131. package/lib/detector.ts +0 -34
  132. package/lib/hider.js +0 -13
  133. package/lib/hider.ts +0 -16
  134. package/lib/index.js +0 -4
  135. package/lib/messages.d.ts +0 -61
  136. package/lib/node.js +0 -35
  137. package/lib/node.ts +0 -43
  138. package/lib/puppet/tab.js +0 -121
  139. package/lib/puppet/tab.ts +0 -146
  140. package/lib/rules.d.ts +0 -80
  141. package/lib/tabwrapper.js +0 -67
  142. package/lib/tabwrapper.ts +0 -74
  143. package/lib/types.d.ts +0 -61
  144. package/lib/web/consentomatic/index.js +0 -188
  145. package/lib/web/consentomatic/index.ts +0 -249
  146. package/lib/web/consentomatic/tools.js +0 -177
  147. package/lib/web/content-utils.js +0 -29
  148. package/lib/web/content-utils.ts +0 -31
  149. package/lib/web/content.js +0 -89
  150. package/lib/web/content.ts +0 -80
  151. package/lib/web/tab.js +0 -112
  152. package/lib/web/tab.ts +0 -178
  153. package/lib/web.js +0 -95
  154. package/tests/runner.ts +0 -61
@@ -1,86 +1,249 @@
1
- import { AutoCMP, TabActor } from "../types";
2
-
3
- export type DetectorConfig = {
4
- presentMatcher: {};
5
- showingMatcher: {};
6
- };
7
- export type MethodConfig = {
8
- action?: any;
9
- name: string;
10
- };
11
-
12
- export type ConsentOMaticConfig = {
13
- detectors: DetectorConfig[];
14
- methods: MethodConfig[];
15
- };
16
-
17
- export class ConsentOMaticCMP implements AutoCMP {
18
- methods = new Map<string, {}>();
19
- hasSelfTest: boolean;
20
-
21
- constructor(public name: string, public config: ConsentOMaticConfig) {
22
- config.methods.forEach(methodConfig => {
23
- if (methodConfig.action) {
24
- this.methods.set(methodConfig.name, methodConfig.action);
25
- }
26
- });
27
- this.hasSelfTest = this.methods.has("TEST_CONSENT");
1
+ import Tools from "./tools";
2
+
3
+ export function matches(config: any) {
4
+ const result = Tools.find(config);
5
+ if (config.type === "css") {
6
+ return !!result.target;
7
+ } else if (config.type === "checkbox") {
8
+ return !!result.target && result.target.checked;
28
9
  }
10
+ }
29
11
 
30
- async detectCmp(tab: TabActor): Promise<boolean> {
31
- return (
32
- await Promise.all(
33
- this.config.detectors.map(detectorConfig =>
34
- tab.matches(detectorConfig.presentMatcher)
35
- )
36
- )
37
- ).some(matched => matched);
12
+ export async function executeAction(config: any, param?: any): Promise<boolean | void> {
13
+ switch (config.type) {
14
+ case "click":
15
+ return clickAction(config);
16
+ case "list":
17
+ return listAction(config, param);
18
+ case "consent":
19
+ return consentAction(config, param);
20
+ case "ifcss":
21
+ return ifCssAction(config, param);
22
+ case "waitcss":
23
+ return waitCssAction(config);
24
+ case "foreach":
25
+ return forEachAction(config, param);
26
+ case "hide":
27
+ return hideAction(config);
28
+ case "slide":
29
+ return slideAction(config);
30
+ case "close":
31
+ return closeAction(config);
32
+ case "wait":
33
+ return waitAction(config);
34
+ case "eval":
35
+ return evalAction(config);
36
+ default:
37
+ throw "Unknown action type: " + config.type;
38
38
  }
39
+ }
40
+
41
+ const STEP_TIMEOUT = 0;
39
42
 
40
- async detectPopup(tab: TabActor): Promise<boolean> {
41
- return (
42
- await Promise.all(
43
- this.config.detectors.map(detectorConfig =>
44
- tab.matches(detectorConfig.showingMatcher)
45
- )
46
- )
47
- ).some(matched => matched);
43
+ function waitTimeout(timeout: number): Promise<void> {
44
+ return new Promise(resolve => {
45
+ setTimeout(() => {
46
+ resolve();
47
+ }, timeout);
48
+ });
49
+ }
50
+
51
+ async function clickAction(config: any) {
52
+ const result = Tools.find(config);
53
+ if (result.target != null) {
54
+ result.target.click();
48
55
  }
56
+ return waitTimeout(STEP_TIMEOUT);
57
+ }
49
58
 
50
- async executeAction(tab: TabActor, method: string, param?: any) {
51
- if (this.methods.has(method)) {
52
- return tab.executeAction(this.methods.get(method), param);
53
- }
54
- return true;
59
+ async function listAction(config: any, param: any) {
60
+ for (let action of config.actions) {
61
+ await executeAction(action, param);
55
62
  }
63
+ }
56
64
 
57
- async optOut(tab: TabActor): Promise<boolean> {
58
- await this.executeAction(tab, "HIDE_CMP");
59
- await this.executeAction(tab, "OPEN_OPTIONS");
60
- await this.executeAction(tab, "HIDE_CMP");
61
- await this.executeAction(tab, "DO_CONSENT", []);
62
- await this.executeAction(tab, "SAVE_CONSENT");
63
- return true;
65
+ async function consentAction(config: any, consentTypes: any) {
66
+ for (const consentConfig of config.consents) {
67
+ const shouldEnable = consentTypes.indexOf(consentConfig.type) !== -1;
68
+ if (consentConfig.matcher && consentConfig.toggleAction) {
69
+ const isEnabled = matches(consentConfig.matcher);
70
+ if (isEnabled !== shouldEnable) {
71
+ await executeAction(consentConfig.toggleAction);
72
+ }
73
+ } else {
74
+ if (shouldEnable) {
75
+ await executeAction(consentConfig.trueAction);
76
+ } else {
77
+ await executeAction(consentConfig.falseAction);
78
+ }
79
+ }
64
80
  }
81
+ }
65
82
 
66
- async optIn(tab: TabActor): Promise<boolean> {
67
- await this.executeAction(tab, "HIDE_CMP");
68
- await this.executeAction(tab, "OPEN_OPTIONS");
69
- await this.executeAction(tab, "HIDE_CMP");
70
- await this.executeAction(tab, "DO_CONSENT", ['D', 'A', 'B', 'E', 'F', 'X']);
71
- await this.executeAction(tab, "SAVE_CONSENT");
72
- return true;
83
+ async function ifCssAction(config: any, param: any) {
84
+ const result = Tools.find(config);
85
+ if (!result.target) {
86
+ if (config.trueAction) {
87
+ await executeAction(config.trueAction, param);
88
+ }
89
+ } else {
90
+ if (config.falseAction) {
91
+ await executeAction(config.falseAction, param);
92
+ }
73
93
  }
74
- async openCmp(tab: TabActor): Promise<boolean> {
75
- await this.executeAction(tab, "HIDE_CMP");
76
- await this.executeAction(tab, "OPEN_OPTIONS");
77
- return true;
94
+ }
95
+
96
+ async function waitCssAction(config: any) {
97
+ await new Promise<void>(resolve => {
98
+ let numRetries = config.retries || 10;
99
+ const waitTime = config.waitTime || 250;
100
+ const checkCss = () => {
101
+ const result = Tools.find(config);
102
+ if (
103
+ (config.negated && result.target) ||
104
+ (!config.negated && !result.target)
105
+ ) {
106
+ if (numRetries > 0) {
107
+ numRetries -= 1;
108
+ setTimeout(checkCss, waitTime);
109
+ } else {
110
+ resolve();
111
+ }
112
+ } else {
113
+ resolve();
114
+ }
115
+ };
116
+ checkCss();
117
+ });
118
+ }
119
+
120
+ async function forEachAction(config: any, param: any) {
121
+ const results = Tools.find(config, true);
122
+ const oldBase = Tools.base;
123
+ for (const result of results) {
124
+ if (result.target) {
125
+ Tools.setBase(result.target);
126
+ await executeAction(config.action, param);
127
+ }
78
128
  }
129
+ Tools.setBase(oldBase);
130
+ }
79
131
 
80
- test(tab: TabActor): Promise<boolean> {
81
- return this.executeAction(tab, "TEST_CONSENT");
132
+ async function hideAction(config: any) {
133
+ const result = Tools.find(config);
134
+ if (result.target) {
135
+ result.target.classList.add("Autoconsent-Hidden");
136
+ // result.target.setAttribute("style", "display: none;");
82
137
  }
83
- detectFrame(tab: TabActor, frame: { url: string }): boolean {
84
- return false;
138
+ }
139
+
140
+ async function slideAction(config: any) {
141
+ const result = Tools.find(config);
142
+ const dragResult = Tools.find(config.dragTarget);
143
+ if (result.target) {
144
+ let targetBounds = result.target.getBoundingClientRect();
145
+ let dragTargetBounds = dragResult.target.getBoundingClientRect();
146
+
147
+ let yDiff = dragTargetBounds.top - targetBounds.top;
148
+ let xDiff = dragTargetBounds.left - targetBounds.left;
149
+
150
+ if (this.config.axis.toLowerCase() === "y") {
151
+ xDiff = 0;
152
+ }
153
+ if (this.config.axis.toLowerCase() === "x") {
154
+ yDiff = 0;
155
+ }
156
+
157
+ let screenX = window.screenX + targetBounds.left + targetBounds.width / 2.0;
158
+ let screenY = window.screenY + targetBounds.top + targetBounds.height / 2.0;
159
+ let clientX = targetBounds.left + targetBounds.width / 2.0;
160
+ let clientY = targetBounds.top + targetBounds.height / 2.0;
161
+
162
+ let mouseDown = document.createEvent("MouseEvents");
163
+ mouseDown.initMouseEvent(
164
+ "mousedown",
165
+ true,
166
+ true,
167
+ window,
168
+ 0,
169
+ screenX,
170
+ screenY,
171
+ clientX,
172
+ clientY,
173
+ false,
174
+ false,
175
+ false,
176
+ false,
177
+ 0,
178
+ result.target
179
+ );
180
+ let mouseMove = document.createEvent("MouseEvents");
181
+ mouseMove.initMouseEvent(
182
+ "mousemove",
183
+ true,
184
+ true,
185
+ window,
186
+ 0,
187
+ screenX + xDiff,
188
+ screenY + yDiff,
189
+ clientX + xDiff,
190
+ clientY + yDiff,
191
+ false,
192
+ false,
193
+ false,
194
+ false,
195
+ 0,
196
+ result.target
197
+ );
198
+ let mouseUp = document.createEvent("MouseEvents");
199
+ mouseUp.initMouseEvent(
200
+ "mouseup",
201
+ true,
202
+ true,
203
+ window,
204
+ 0,
205
+ screenX + xDiff,
206
+ screenY + yDiff,
207
+ clientX + xDiff,
208
+ clientY + yDiff,
209
+ false,
210
+ false,
211
+ false,
212
+ false,
213
+ 0,
214
+ result.target
215
+ );
216
+ result.target.dispatchEvent(mouseDown);
217
+ await this.waitTimeout(10);
218
+ result.target.dispatchEvent(mouseMove);
219
+ await this.waitTimeout(10);
220
+ result.target.dispatchEvent(mouseUp);
85
221
  }
86
222
  }
223
+
224
+ async function waitAction(config: any) {
225
+ await waitTimeout(config.waitTime);
226
+ }
227
+
228
+ async function closeAction(config: any) {
229
+ window.close();
230
+ }
231
+
232
+ async function evalAction(config: any): Promise<boolean> {
233
+ console.log("eval!", config.code);
234
+ return new Promise(resolve => {
235
+ try {
236
+ if (config.async) {
237
+ window.eval(config.code);
238
+ setTimeout(() => {
239
+ resolve(window.eval("window.__consentCheckResult"));
240
+ }, config.timeout || 250);
241
+ } else {
242
+ resolve(window.eval(config.code));
243
+ }
244
+ } catch (e) {
245
+ console.warn("eval error", e, config.code);
246
+ resolve(false);
247
+ }
248
+ });
249
+ }
@@ -0,0 +1,58 @@
1
+ import { ContentScriptMessage } from "./messages";
2
+
3
+ class Deferred<T> {
4
+ id: string;
5
+ promise: Promise<T>;
6
+ resolve: (value?: T) => void;
7
+ reject: (reason?: any) => void;
8
+ timer: number;
9
+
10
+ constructor(id: string, timeout = 1000) {
11
+ this.id = id;
12
+ this.promise = new Promise((resolve, reject) => {
13
+ this.resolve = resolve;
14
+ this.reject = reject;
15
+ });
16
+ this.timer = window.setTimeout(() => {
17
+ this.reject(new Error("timeout"));
18
+ }, timeout);
19
+ }
20
+ }
21
+
22
+ type EvalState = {
23
+ pending: Map<string, Deferred<boolean>>;
24
+ sendContentMessage: (message: ContentScriptMessage) => void;
25
+ }
26
+
27
+ export const evalState: EvalState = {
28
+ pending: new Map(),
29
+ sendContentMessage: null,
30
+ }
31
+
32
+ export function requestEval(code: string): Promise<boolean> {
33
+ let id;
34
+ if (crypto && typeof crypto.randomUUID !== 'undefined') {
35
+ id = crypto.randomUUID();
36
+ } else {
37
+ id = Math.random().toString();
38
+ }
39
+ evalState.sendContentMessage({
40
+ type: 'eval',
41
+ id,
42
+ code,
43
+ });
44
+ const deferred = new Deferred<boolean>(id);
45
+ evalState.pending.set(deferred.id, deferred);
46
+ return deferred.promise;
47
+ }
48
+
49
+ export function resolveEval(id: string, value: boolean) {
50
+ const deferred = evalState.pending.get(id);
51
+ if (deferred) {
52
+ evalState.pending.delete(id);
53
+ deferred.timer && window.clearTimeout(deferred.timer);
54
+ deferred.resolve(value);
55
+ } else {
56
+ console.warn('no eval #', id);
57
+ }
58
+ }
package/lib/index.ts CHANGED
@@ -1,6 +1,4 @@
1
1
  import _rules, { createAutoCMP } from './cmps/all';
2
2
 
3
- export { waitFor } from './cmps/base';
4
-
5
3
  export { createAutoCMP };
6
4
  export const rules = _rules;
@@ -0,0 +1,100 @@
1
+ import { Config, RuleBundle } from "./types";
2
+
3
+ export type BackgroundMessage =
4
+ InitResponseMessage
5
+ | EvalResponseMessage
6
+ | OptOutMessage
7
+ | OptInMessage
8
+ | SelfTestMessage;
9
+
10
+ export type ContentScriptMessage =
11
+ InitMessage
12
+ | EvalMessage
13
+ | DetectedMessage
14
+ | FoundMessage
15
+ | OptOutResultMessage
16
+ | OptInResultMessage
17
+ | SelfTestResultMessage
18
+ | DoneMessage
19
+ | ErrorMessage;
20
+
21
+ export type InitMessage = {
22
+ type: "init";
23
+ url: string;
24
+ };
25
+
26
+ export type EvalMessage = {
27
+ type: "eval";
28
+ id: string;
29
+ code: string;
30
+ };
31
+
32
+ export type DetectedMessage = {
33
+ type: "cmpDetected";
34
+ cmp: string;
35
+ url: string;
36
+ }
37
+
38
+ export type FoundMessage = {
39
+ type: "popupFound";
40
+ cmp: string;
41
+ url: string;
42
+ }
43
+
44
+ export type OptOutResultMessage = {
45
+ type: "optOutResult";
46
+ cmp: string;
47
+ result: boolean;
48
+ scheduleSelfTest: boolean;
49
+ url: string;
50
+ };
51
+
52
+ export type OptInResultMessage = {
53
+ type: "optInResult";
54
+ cmp: string;
55
+ result: boolean;
56
+ scheduleSelfTest: boolean;
57
+ url: string;
58
+ };
59
+
60
+ export type SelfTestResultMessage = {
61
+ type: "selfTestResult";
62
+ cmp: string;
63
+ result: boolean;
64
+ url: string;
65
+ };
66
+
67
+ export type DoneMessage = {
68
+ type: "autoconsentDone";
69
+ cmp: string;
70
+ url: string;
71
+ }
72
+
73
+ export type ErrorMessage = {
74
+ type: "autoconsentError";
75
+ details: any;
76
+ }
77
+
78
+ export type InitResponseMessage = {
79
+ type: "initResp";
80
+ rules: RuleBundle;
81
+ config: Config;
82
+ }
83
+
84
+ export type EvalResponseMessage = {
85
+ type: "evalResp";
86
+ id: string;
87
+ result: any;
88
+ }
89
+
90
+ export type OptOutMessage = {
91
+ type: "optOut";
92
+ }
93
+
94
+ export type OptInMessage = {
95
+ type: "optIn";
96
+ }
97
+
98
+ export type SelfTestMessage = {
99
+ type: "selfTest";
100
+ }
@@ -0,0 +1,108 @@
1
+ import { enableLogs } from "./config";
2
+ import { requestEval } from "./eval-handler";
3
+ import { HideMethod, VisibilityCheck } from "./rules";
4
+ import { getStyleElement, hideElements, isElementVisible, waitFor } from "./utils";
5
+
6
+ export function doEval(expr: string): Promise<boolean> {
7
+ return requestEval(expr).catch((e) => {
8
+ enableLogs && console.error('error evaluating rule', expr, e);
9
+ return false;
10
+ });
11
+ }
12
+
13
+ export function click(selector: string, all = false): boolean {
14
+ const elem = document.querySelectorAll<HTMLElement>(selector);
15
+ enableLogs && console.log("[click]", selector, all, elem);
16
+ if (elem.length > 0) {
17
+ if (all) {
18
+ elem.forEach((e) => e.click());
19
+ } else {
20
+ elem[0].click();
21
+ }
22
+ }
23
+ return elem.length > 0;
24
+ }
25
+
26
+ export function elementExists(selector: string): boolean {
27
+ const exists = document.querySelector(selector) !== null;
28
+ // enableLogs && console.log("[exists?]", selector, exists);
29
+ return exists;
30
+ }
31
+
32
+ export function elementVisible(selector: string, check: VisibilityCheck): boolean {
33
+ const elem = document.querySelectorAll<HTMLElement>(selector);
34
+ const results = new Array(elem.length);
35
+ elem.forEach((e, i) => {
36
+ // check for display: none
37
+ results[i] = isElementVisible(e);
38
+ });
39
+ // enableLogs && console.log("[visible?]", selector, check, elem, results);
40
+ if (results.length === 0) {
41
+ return false;
42
+ } else if (check === "any") {
43
+ return results.some(r => r);
44
+ } else if (check === "none") {
45
+ return results.every(r => !r);
46
+ }
47
+ // all
48
+ return results.every(r => r);
49
+ }
50
+
51
+ export function waitForElement(selector: string, timeout = 10000): Promise<boolean> {
52
+ const interval = 200;
53
+ const times = Math.ceil((timeout) / interval);
54
+ // enableLogs && console.log("[waitFor]", ruleStep.waitFor);
55
+ return waitFor(
56
+ () => document.querySelector(selector) !== null,
57
+ times,
58
+ interval
59
+ );
60
+ }
61
+
62
+ export function waitForVisible(selector: string, timeout = 10000, check: VisibilityCheck = 'any'): Promise<boolean> {
63
+ const interval = 200;
64
+ const times = Math.ceil((timeout) / interval);
65
+ // enableLogs && console.log("[waitForVisible]", ruleStep.waitFor);
66
+ return waitFor(
67
+ () => elementVisible(selector, check),
68
+ times,
69
+ interval
70
+ );
71
+ }
72
+
73
+ export async function waitForThenClick(selector: string, timeout = 10000, all = false): Promise<boolean> {
74
+ // enableLogs && console.log("[waitForThenClick]", ruleStep.waitForThenClick);
75
+ await waitForElement(selector, timeout);
76
+ return click(selector, all);
77
+ }
78
+
79
+ export function wait(ms: number): Promise<true> {
80
+ // enableLogs && console.log(`waiting for ${ruleStep.wait}ms`);
81
+ return new Promise(resolve => {
82
+ setTimeout(() => {
83
+ // enableLogs && console.log(`done waiting`);
84
+ resolve(true);
85
+ }, ms);
86
+ });
87
+ }
88
+
89
+ export function hide(selectors: string[], method: HideMethod): boolean {
90
+ // enableLogs && console.log("[hide]", ruleStep.hide, ruleStep.method);
91
+ const styleEl = getStyleElement();
92
+ return hideElements(styleEl, selectors, method);
93
+ }
94
+
95
+ export function prehide(selectors: string[]): boolean {
96
+ const styleEl = getStyleElement('autoconsent-prehide');
97
+ enableLogs && console.log("[prehide]", styleEl, location.href);
98
+ return hideElements(styleEl, selectors, "opacity");
99
+ }
100
+
101
+ export function undoPrehide(): boolean {
102
+ const existingElement = getStyleElement('autoconsent-prehide');
103
+ enableLogs && console.log("[undoprehide]", existingElement, location.href);
104
+ if (existingElement) {
105
+ existingElement.remove();
106
+ }
107
+ return !!existingElement;
108
+ }
package/lib/rules.ts ADDED
@@ -0,0 +1,82 @@
1
+ export type AutoConsentCMPRule = {
2
+ name: string
3
+ prehideSelectors?: string[]
4
+ runContext?: RunContext,
5
+ intermediate?: boolean
6
+ detectCmp: AutoConsentRuleStep[]
7
+ detectPopup: AutoConsentRuleStep[]
8
+ optOut: AutoConsentRuleStep[]
9
+ optIn: AutoConsentRuleStep[]
10
+ openCmp?: AutoConsentRuleStep[]
11
+ test?: AutoConsentRuleStep[]
12
+ }
13
+
14
+ export type RunContext = {
15
+ main?: boolean,
16
+ frame?: boolean,
17
+ url?: string,
18
+ }
19
+
20
+ export type AutoConsentRuleStep = { optional?: boolean } & Partial<
21
+ ElementExistsRule
22
+ > &
23
+ Partial<ElementVisibleRule> &
24
+ Partial<EvalRule> &
25
+ Partial<WaitForRule> &
26
+ Partial<WaitForVisibleRule> &
27
+ Partial<ClickRule> &
28
+ Partial<WaitForThenClickRule> &
29
+ Partial<WaitRule> &
30
+ Partial<UrlRule> &
31
+ Partial<HideRule>;
32
+
33
+ export type ElementExistsRule = {
34
+ exists: string;
35
+ };
36
+
37
+ export type VisibilityCheck = "any" | "all" | "none";
38
+
39
+ export type ElementVisibleRule = {
40
+ visible: string;
41
+ check?: VisibilityCheck;
42
+ };
43
+
44
+ export type EvalRule = {
45
+ eval: string;
46
+ };
47
+
48
+ export type WaitForRule = {
49
+ waitFor: string;
50
+ timeout?: number;
51
+ };
52
+
53
+ export type WaitForVisibleRule = {
54
+ waitForVisible: string;
55
+ timeout?: number;
56
+ check?: VisibilityCheck;
57
+ };
58
+
59
+ export type ClickRule = {
60
+ click: string;
61
+ all?: boolean;
62
+ };
63
+
64
+ export type WaitForThenClickRule = {
65
+ waitForThenClick: string;
66
+ timeout?: number;
67
+ };
68
+
69
+ export type WaitRule = {
70
+ wait: number;
71
+ };
72
+
73
+ export type UrlRule = {
74
+ url: string;
75
+ };
76
+
77
+ export type HideMethod = 'display' | 'opacity';
78
+
79
+ export type HideRule = {
80
+ hide: string[];
81
+ method?: HideMethod;
82
+ };