@duckduckgo/autoconsent 1.0.8 → 2.1.1

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 (182) hide show
  1. package/.eslintrc.cjs +14 -0
  2. package/.vscode/.idea/.vscode.iml +9 -0
  3. package/.vscode/.idea/modules.xml +8 -0
  4. package/.vscode/.idea/workspace.xml +28 -0
  5. package/.vscode/settings.json +7 -0
  6. package/Jenkinsfile +68 -39
  7. package/api.md +104 -0
  8. package/dist/addon-firefox/background.bundle.js +1 -0
  9. package/dist/addon-firefox/content.bundle.js +1 -0
  10. package/dist/addon-firefox/icons/cog.png +0 -0
  11. package/dist/addon-firefox/icons/cookie-idle.png +0 -0
  12. package/dist/addon-firefox/icons/cookie.png +0 -0
  13. package/dist/addon-firefox/icons/party.png +0 -0
  14. package/dist/addon-firefox/icons/tick.png +0 -0
  15. package/dist/addon-firefox/icons/verified.png +0 -0
  16. package/dist/addon-firefox/manifest.json +32 -0
  17. package/dist/addon-firefox/rules.json +4167 -0
  18. package/dist/addon-mv3/background.bundle.js +1 -0
  19. package/dist/addon-mv3/content.bundle.js +1 -0
  20. package/dist/addon-mv3/icons/cog.png +0 -0
  21. package/dist/addon-mv3/icons/cookie-idle.png +0 -0
  22. package/dist/addon-mv3/icons/cookie.png +0 -0
  23. package/dist/addon-mv3/icons/party.png +0 -0
  24. package/dist/addon-mv3/icons/tick.png +0 -0
  25. package/dist/addon-mv3/icons/verified.png +0 -0
  26. package/dist/addon-mv3/manifest.json +34 -0
  27. package/dist/addon-mv3/rules.json +4167 -0
  28. package/dist/autoconsent.cjs.js +1 -1387
  29. package/dist/autoconsent.esm.js +1 -1379
  30. package/dist/autoconsent.playwright.js +1 -0
  31. package/lib/cmps/all.ts +15 -10
  32. package/lib/cmps/base.ts +95 -90
  33. package/lib/cmps/consentmanager.ts +31 -19
  34. package/lib/cmps/consentomatic.ts +89 -0
  35. package/lib/cmps/cookiebot.ts +58 -55
  36. package/lib/cmps/evidon.ts +29 -18
  37. package/lib/cmps/onetrust.ts +32 -20
  38. package/lib/cmps/sourcepoint-frame.ts +104 -0
  39. package/lib/cmps/sourcepoint-top.ts +47 -0
  40. package/lib/cmps/trustarc-frame.ts +115 -0
  41. package/lib/cmps/trustarc-top.ts +97 -0
  42. package/lib/consentomatic/index.ts +233 -70
  43. package/lib/{web/consentomatic → consentomatic}/tools.ts +0 -0
  44. package/lib/eval-handler.ts +58 -0
  45. package/lib/index.ts +0 -2
  46. package/lib/messages.ts +100 -0
  47. package/lib/rule-executors.ts +108 -0
  48. package/lib/rules.ts +82 -0
  49. package/lib/types.ts +35 -0
  50. package/lib/utils.ts +64 -0
  51. package/lib/web.ts +288 -74
  52. package/package.json +20 -16
  53. package/playwright/content.ts +21 -0
  54. package/playwright/runner.ts +162 -0
  55. package/playwright.config.ts +7 -0
  56. package/readme.md +61 -47
  57. package/rollup.config.js +38 -16
  58. package/rules/autoconsent/ausopen.json +2 -1
  59. package/rules/autoconsent/baden-wuerttemberg-de.json +7 -3
  60. package/rules/autoconsent/bundesregierung-de.json +5 -1
  61. package/rules/autoconsent/cc-banner.json +0 -1
  62. package/rules/autoconsent/cookie-law-info.json +1 -1
  63. package/rules/autoconsent/cookie-notice.json +1 -2
  64. package/rules/autoconsent/cookieconsent.json +5 -6
  65. package/rules/autoconsent/destatis-de.json +2 -2
  66. package/rules/autoconsent/dunelm.json +1 -1
  67. package/rules/autoconsent/etsy.json +4 -3
  68. package/rules/autoconsent/eu-cookie-compliance.json +0 -1
  69. package/rules/autoconsent/hl-co-uk.json +8 -9
  70. package/rules/autoconsent/johnlewis.json +5 -2
  71. package/rules/autoconsent/marksandspencer.json +2 -1
  72. package/rules/autoconsent/mediamarkt-de.json +1 -1
  73. package/rules/autoconsent/microsoft.json +1 -1
  74. package/rules/autoconsent/notice-cookie.json +0 -1
  75. package/rules/autoconsent/osano.json +4 -2
  76. package/rules/autoconsent/snigel.json +2 -1
  77. package/rules/autoconsent/tealium.json +4 -5
  78. package/rules/autoconsent/thefreedictionary.json +1 -1
  79. package/rules/rules.json +79 -45
  80. package/tests/192.spec.ts +1 -1
  81. package/tests/arzt-auskunft.spec.ts +1 -1
  82. package/tests/asus.spec.ts +1 -1
  83. package/tests/ausopen.spec.ts +1 -1
  84. package/tests/aws.amazon.spec.ts +1 -1
  85. package/tests/baden-wuerttemberg.spec.ts +1 -1
  86. package/tests/borlabs.spec.ts +1 -1
  87. package/tests/bundesregierung.spec.ts +5 -2
  88. package/tests/ccbanner.spec.ts +1 -1
  89. package/tests/consentmanager.spec.ts +3 -3
  90. package/tests/cookiebot.spec.ts +8 -2
  91. package/tests/cookieconsent.spec.ts +1 -1
  92. package/tests/cookielawinfo.spec.ts +1 -1
  93. package/tests/cookienotice.spec.ts +1 -1
  94. package/tests/corona-in-zahlen.spec.ts +1 -1
  95. package/tests/deepl.spec.ts +1 -1
  96. package/tests/destatis.spec.ts +1 -1
  97. package/tests/didomi.spec.ts +7 -3
  98. package/tests/drupal.spec.ts +8 -0
  99. package/tests/dunelm.spec.ts +1 -1
  100. package/tests/etsy.spec.ts +1 -1
  101. package/tests/eu-cookie-compliance-banner.spec.ts +1 -1
  102. package/tests/evidon.spec.ts +7 -2
  103. package/tests/fundingchoices.spec.ts +2 -1
  104. package/tests/gov-uk.spec.ts +1 -1
  105. package/tests/hl-co-uk.spec.ts +1 -1
  106. package/tests/hubspot.spec.ts +1 -1
  107. package/tests/ionos.spec.ts +1 -1
  108. package/tests/johnlewis.spec.ts +2 -2
  109. package/tests/klaro.spec.ts +1 -1
  110. package/tests/marksandspencer.spec.ts +1 -1
  111. package/tests/mediamarkt.spec.ts +1 -1
  112. package/tests/metoffice-gov-uk.spec.ts +1 -1
  113. package/tests/microsoft.spec.ts +1 -1
  114. package/tests/moneysavingexpert.spec.ts +1 -1
  115. package/tests/motor-talk.spec.ts +1 -1
  116. package/tests/national-lottery.spec.ts +1 -1
  117. package/tests/netflix.spec.ts +1 -1
  118. package/tests/nhs.spec.ts +1 -1
  119. package/tests/notice-cookie.spec.ts +1 -1
  120. package/tests/obi.spec.ts +1 -1
  121. package/tests/oil.spec.ts +2 -2
  122. package/tests/onetrust.spec.ts +27 -2
  123. package/tests/osano.spec.ts +1 -1
  124. package/tests/otto.spec.ts +1 -1
  125. package/tests/paypal.spec.ts +1 -1
  126. package/tests/quantcast.spec.ts +5 -2
  127. package/tests/snigel.spec.ts +1 -1
  128. package/tests/sourcepoint.spec.ts +8 -8
  129. package/tests/springer.spec.ts +2 -2
  130. package/tests/steampowered.spec.ts +1 -1
  131. package/tests/tealium.spec.ts +1 -1
  132. package/tests/testcmp.spec.ts +1 -1
  133. package/tests/thalia.spec.ts +1 -1
  134. package/tests/thefreedictionary.spec.ts +1 -1
  135. package/tests/trustarc.spec.ts +26 -4
  136. package/tests/usercentrics-1.spec.ts +1 -1
  137. package/tests/uswitch.spec.ts +1 -1
  138. package/tests/vodafone.spec.ts +1 -1
  139. package/tests/waitrose.spec.ts +1 -1
  140. package/tests/wetransfer.spec.ts +1 -1
  141. package/tests/wordpressgdpr.spec.ts +2 -2
  142. package/tests/xing.spec.ts +1 -1
  143. package/tsconfig.json +2 -2
  144. package/update_version.js +10 -6
  145. package/.eslintrc +0 -12
  146. package/cosmetics/rules.json +0 -110
  147. package/dist/autoconsent.puppet.js +0 -1078
  148. package/lib/cmps/all.js +0 -19
  149. package/lib/cmps/base.js +0 -174
  150. package/lib/cmps/consentmanager.js +0 -31
  151. package/lib/cmps/cookiebot.js +0 -77
  152. package/lib/cmps/evidon.js +0 -26
  153. package/lib/cmps/onetrust.js +0 -34
  154. package/lib/cmps/sourcepoint.js +0 -82
  155. package/lib/cmps/sourcepoint.ts +0 -95
  156. package/lib/cmps/trustarc.js +0 -106
  157. package/lib/cmps/trustarc.ts +0 -147
  158. package/lib/config.js +0 -1
  159. package/lib/consentomatic/index.js +0 -52
  160. package/lib/detector.js +0 -33
  161. package/lib/detector.ts +0 -34
  162. package/lib/hider.js +0 -13
  163. package/lib/hider.ts +0 -16
  164. package/lib/index.js +0 -4
  165. package/lib/messages.d.ts +0 -61
  166. package/lib/node.js +0 -35
  167. package/lib/node.ts +0 -43
  168. package/lib/puppet/tab.js +0 -121
  169. package/lib/puppet/tab.ts +0 -146
  170. package/lib/rules.d.ts +0 -80
  171. package/lib/tabwrapper.js +0 -67
  172. package/lib/tabwrapper.ts +0 -74
  173. package/lib/types.d.ts +0 -61
  174. package/lib/web/consentomatic/index.ts +0 -249
  175. package/lib/web/content-utils.js +0 -29
  176. package/lib/web/content-utils.ts +0 -31
  177. package/lib/web/content.js +0 -89
  178. package/lib/web/content.ts +0 -80
  179. package/lib/web/tab.js +0 -112
  180. package/lib/web/tab.ts +0 -178
  181. package/lib/web.js +0 -95
  182. package/tests/runner.ts +0 -61
@@ -0,0 +1,97 @@
1
+ import { click, elementExists, elementVisible } from "../rule-executors";
2
+ import { RunContext } from "../rules";
3
+ import { getStyleElement, hideElements } from "../utils";
4
+ import AutoConsentCMPBase from "./base";
5
+
6
+ const cookieSettingsButton = "#truste-show-consent";
7
+ const shortcutOptOut = '#truste-consent-required';
8
+ const shortcutOptIn = '#truste-consent-button';
9
+ const popupContent = '#truste-consent-content';
10
+ const bannerOverlay = '#trustarc-banner-overlay';
11
+ const bannerContainer = '#truste-consent-track';
12
+
13
+ export default class TrustArcTop extends AutoConsentCMPBase {
14
+
15
+ prehideSelectors = [
16
+ ".trustarc-banner-container",
17
+ `.truste_popframe,.truste_overlay,.truste_box_overlay,${bannerContainer}`,
18
+ ]
19
+ runContext: RunContext = {
20
+ main: true,
21
+ frame: false,
22
+ }
23
+
24
+ _shortcutButton: HTMLElement;
25
+ _optInDone: boolean;
26
+
27
+ constructor() {
28
+ super("TrustArc-top");
29
+ this._shortcutButton = null; // indicates if the "reject all" button is detected
30
+ this._optInDone = false;
31
+ }
32
+
33
+ get hasSelfTest(): boolean {
34
+ return false;
35
+ }
36
+
37
+ get isIntermediate(): boolean {
38
+ if (this._optInDone) {
39
+ return false;
40
+ }
41
+ return !this._shortcutButton;
42
+ }
43
+
44
+ async detectCmp() {
45
+ const result = elementExists(`${cookieSettingsButton},${bannerContainer}`);
46
+ if (result) {
47
+ // additionally detect the opt-out button
48
+ this._shortcutButton = document.querySelector(shortcutOptOut);
49
+ }
50
+ return result;
51
+ }
52
+
53
+ async detectPopup() {
54
+ // not every element should exist, but if it does, it's a popup
55
+ return elementVisible(`${popupContent},${bannerOverlay},${bannerContainer}`, 'all');
56
+ }
57
+
58
+ openFrame() {
59
+ click(cookieSettingsButton);
60
+ }
61
+
62
+ async optOut() {
63
+ if (this._shortcutButton) {
64
+ this._shortcutButton.click();
65
+ return true;
66
+ }
67
+
68
+ // hide elements permanently, so user doesn't see the popup
69
+ hideElements(
70
+ getStyleElement(),
71
+ [".truste_popframe", ".truste_overlay", ".truste_box_overlay", bannerContainer],
72
+ );
73
+ click(cookieSettingsButton);
74
+
75
+ // schedule cleanup
76
+ setTimeout(() => {
77
+ getStyleElement().remove();
78
+ }, 10000);
79
+
80
+ return true;
81
+ }
82
+
83
+ async optIn() {
84
+ this._optInDone = true; // just a hack to force autoconsentDone
85
+ return click(shortcutOptIn);
86
+ }
87
+
88
+ async openCmp() {
89
+ // await tab.eval("truste.eu.clickListener()");
90
+ return true;
91
+ }
92
+
93
+ async test() {
94
+ // TODO: find out how to test TrustArc
95
+ return true;
96
+ }
97
+ }
@@ -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
+ }