@duckduckgo/autoconsent 5.0.0 → 5.0.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.
@@ -1,320 +1,316 @@
1
- (function () {
2
- 'use strict';
1
+ (() => {
2
+ // lib/config.ts
3
+ var enableLogs = false;
3
4
 
4
- const manifestVersion = chrome.runtime.getManifest().manifest_version;
5
- // Storage abstraction: MV2 keeps everything in memory, MV3 uses chrome.storage
6
- const storage = {};
7
- async function storageSet(obj) {
8
- if (manifestVersion === 2) {
9
- Object.assign(storage, obj);
10
- return;
11
- }
12
- return chrome.storage.local.set(obj);
5
+ // addon/mv-compat.ts
6
+ var manifestVersion = chrome.runtime.getManifest().manifest_version;
7
+ var storage = {};
8
+ async function storageSet(obj) {
9
+ if (manifestVersion === 2) {
10
+ Object.assign(storage, obj);
11
+ return;
13
12
  }
14
- async function storageGet(key) {
15
- if (key === null) {
16
- if (manifestVersion === 2) {
17
- return storage;
18
- }
19
- return await chrome.storage.local.get(null);
20
- }
21
- if (manifestVersion === 2) {
22
- return storage[key];
23
- }
24
- return (await chrome.storage.local.get(key))?.[key];
13
+ return chrome.storage.local.set(obj);
14
+ }
15
+ async function storageGet(key) {
16
+ if (key === null) {
17
+ if (manifestVersion === 2) {
18
+ return storage;
19
+ }
20
+ return await chrome.storage.local.get(null);
25
21
  }
26
- async function storageRemove(key) {
27
- if (manifestVersion === 2) {
28
- delete storage[key];
29
- return;
30
- }
31
- return chrome.storage.local.remove(key);
22
+ if (manifestVersion === 2) {
23
+ return storage[key];
32
24
  }
33
-
34
- async function showOptOutStatus(tabId, status, cmp = '') {
35
- let title = "";
36
- let icon = "icons/cookie-idle.png";
37
- if (status === "success") {
38
- title = `Opt out successful! (${cmp})`;
39
- icon = "icons/party.png";
40
- }
41
- else if (status === "complete") {
42
- title = `Opt out complete! (${cmp})`;
43
- icon = "icons/tick.png";
44
- }
45
- else if (status === "working") {
46
- title = `Processing... (${cmp})`;
47
- icon = "icons/cog.png";
48
- }
49
- else if (status === "verified") {
50
- title = `Verified (${cmp})`;
51
- icon = "icons/verified.png";
52
- }
53
- else if (status === "idle") {
54
- title = "Idle";
55
- icon = "icons/cookie-idle.png";
56
- }
57
- else if (status === "available") {
58
- title = `Click to opt out (${cmp})`;
59
- icon = "icons/cookie.png";
60
- }
61
- const action = chrome.action || chrome.pageAction;
62
- if (chrome.pageAction) {
63
- chrome.pageAction.show(tabId);
64
- }
65
- await action.setTitle({
66
- tabId,
67
- title,
68
- });
69
- await action.setIcon({
70
- tabId,
71
- path: icon,
72
- });
25
+ return (await chrome.storage.local.get(key))?.[key];
26
+ }
27
+ async function storageRemove(key) {
28
+ if (manifestVersion === 2) {
29
+ delete storage[key];
30
+ return;
73
31
  }
32
+ return chrome.storage.local.remove(key);
33
+ }
74
34
 
75
- /**
76
- * Mapping of tabIds to Port connections to open devtools panels.
77
- * This is kept in memory, as the values are only relevant while the background service worker is
78
- * alive. Once the service worker stops, Ports to devtools will be severed, and the panel will
79
- * reestablish the connection.
80
- */
81
- const openDevToolsPanels = new Map();
82
- async function loadRules() {
83
- const res = await fetch("./rules.json");
84
- storageSet({
85
- rules: await res.json(),
86
- });
35
+ // addon/utils.ts
36
+ async function showOptOutStatus(tabId, status, cmp = "") {
37
+ let title = "";
38
+ let icon = "icons/cookie-idle.png";
39
+ if (status === "success") {
40
+ title = `Opt out successful! (${cmp})`;
41
+ icon = "icons/party.png";
42
+ } else if (status === "complete") {
43
+ title = `Opt out complete! (${cmp})`;
44
+ icon = "icons/tick.png";
45
+ } else if (status === "working") {
46
+ title = `Processing... (${cmp})`;
47
+ icon = "icons/cog.png";
48
+ } else if (status === "verified") {
49
+ title = `Verified (${cmp})`;
50
+ icon = "icons/verified.png";
51
+ } else if (status === "idle") {
52
+ title = "Idle";
53
+ icon = "icons/cookie-idle.png";
54
+ } else if (status === "available") {
55
+ title = `Click to opt out (${cmp})`;
56
+ icon = "icons/cookie.png";
87
57
  }
88
- async function initConfig() {
89
- console.log('init sw');
90
- const storedConfig = await storageGet('config');
91
- console.log('storedConfig', storedConfig);
92
- const defaultConfig = {
93
- enabled: true,
94
- autoAction: 'optOut',
95
- disabledCmps: [],
96
- enablePrehide: true,
97
- enableCosmeticRules: true,
98
- detectRetries: 20,
99
- prehideTimeout: 2000,
100
- };
101
- if (!storedConfig) {
102
- console.log('init config');
103
- await storageSet({
104
- config: defaultConfig,
105
- });
106
- }
107
- else { // clean up the old stored config in case there are new fields
108
- const updatedConfig = structuredClone(defaultConfig);
109
- for (const key of Object.keys(defaultConfig)) {
110
- if (typeof storedConfig[key] !== 'undefined') {
111
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
112
- // @ts-ignore - TS doesn't know that we've checked for undefined
113
- updatedConfig[key] = storedConfig[key];
114
- }
115
- }
116
- await storageSet({
117
- config: updatedConfig,
118
- });
119
- }
58
+ enableLogs && console.log("Setting action state to", status);
59
+ const action = chrome.action || chrome.pageAction;
60
+ if (chrome.pageAction) {
61
+ chrome.pageAction.show(tabId);
120
62
  }
121
- async function evalInTab(tabId, frameId, code) {
122
- if (manifestVersion === 2) {
123
- return new Promise((resolve) => {
124
- chrome.tabs.executeScript(tabId, {
125
- frameId,
126
- code: `!!window.eval(decodeURIComponent("${encodeURIComponent(code)}"))`
127
- }, (resultArr) => {
128
- resolve([{
129
- result: resultArr[0],
130
- frameId,
131
- }]);
132
- });
133
- });
63
+ await action.setTitle({
64
+ tabId,
65
+ title
66
+ });
67
+ await action.setIcon({
68
+ tabId,
69
+ path: icon
70
+ });
71
+ }
72
+
73
+ // addon/background.ts
74
+ var openDevToolsPanels = /* @__PURE__ */ new Map();
75
+ async function loadRules() {
76
+ const res = await fetch("./rules.json");
77
+ storageSet({
78
+ rules: await res.json()
79
+ });
80
+ }
81
+ async function initConfig() {
82
+ console.log("init sw");
83
+ const storedConfig = await storageGet("config");
84
+ console.log("storedConfig", storedConfig);
85
+ const defaultConfig = {
86
+ enabled: true,
87
+ autoAction: "optOut",
88
+ // if falsy, the extension will wait for an explicit user signal before opting in/out
89
+ disabledCmps: [],
90
+ enablePrehide: true,
91
+ enableCosmeticRules: true,
92
+ detectRetries: 20,
93
+ prehideTimeout: 2e3
94
+ };
95
+ if (!storedConfig) {
96
+ console.log("init config");
97
+ await storageSet({
98
+ config: defaultConfig
99
+ });
100
+ } else {
101
+ const updatedConfig = structuredClone(defaultConfig);
102
+ for (const key of Object.keys(defaultConfig)) {
103
+ if (typeof storedConfig[key] !== "undefined") {
104
+ updatedConfig[key] = storedConfig[key];
134
105
  }
135
- return chrome.scripting.executeScript({
136
- target: {
137
- tabId,
138
- frameIds: [frameId],
139
- },
140
- world: "MAIN",
141
- args: [code],
142
- func: (code) => {
143
- try {
144
- return window.eval(code);
145
- }
146
- catch (e) {
147
- // ignore CSP errors
148
- console.warn('eval error', code, e);
149
- return;
150
- }
151
- },
152
- });
153
- }
154
- async function getTabReports(tabId) {
155
- const storageKey = `reports-${tabId}`;
156
- return (await chrome.storage.session.get(storageKey))[storageKey] || {};
106
+ }
107
+ await storageSet({
108
+ config: updatedConfig
109
+ });
157
110
  }
158
- async function updateTabReports(tabId, frameId, msg) {
159
- const reportsForTab = await getTabReports(tabId);
160
- reportsForTab[frameId] = msg;
161
- await chrome.storage.session.set({ [`reports-${tabId}`]: reportsForTab });
162
- }
163
- chrome.runtime.onInstalled.addListener(() => {
164
- loadRules();
165
- initConfig();
166
- });
111
+ }
112
+ async function evalInTab(tabId, frameId, code) {
167
113
  if (manifestVersion === 2) {
168
- // always load rules on startup in MV2
169
- loadRules();
170
- initConfig();
114
+ return new Promise((resolve) => {
115
+ chrome.tabs.executeScript(tabId, {
116
+ frameId,
117
+ code: `!!window.eval(decodeURIComponent("${encodeURIComponent(code)}"))`
118
+ }, (resultArr) => {
119
+ resolve([{
120
+ result: resultArr[0],
121
+ frameId
122
+ }]);
123
+ });
124
+ });
171
125
  }
172
- chrome.tabs.onRemoved.addListener((tabId) => {
173
- storageRemove(`detected${tabId}`);
174
- });
175
- chrome.runtime.onMessage.addListener(async (msg, sender) => {
176
- const tabId = sender.tab.id;
177
- const frameId = sender.frameId;
178
- const rules = await storageGet("rules");
179
- const autoconsentConfig = await storageGet('config');
180
- switch (msg.type) {
181
- case "init":
182
- if (frameId === 0) {
183
- await showOptOutStatus(tabId, 'idle');
184
- }
185
- chrome.tabs.sendMessage(tabId, {
186
- type: "initResp",
187
- rules,
188
- config: autoconsentConfig,
189
- }, {
190
- frameId,
191
- });
192
- break;
193
- case "eval":
194
- evalInTab(tabId, frameId, msg.code).then(([result]) => {
195
- chrome.tabs.sendMessage(tabId, {
196
- id: msg.id,
197
- type: "evalResp",
198
- result: result.result,
199
- }, {
200
- frameId,
201
- });
202
- });
203
- break;
204
- case "popupFound":
205
- await showOptOutStatus(tabId, "available", msg.cmp);
206
- storageSet({
207
- [`detected${tabId}`]: frameId,
208
- });
209
- break;
210
- case "optOutResult":
211
- case "optInResult":
212
- if (msg.result) {
213
- await showOptOutStatus(tabId, "working", msg.cmp);
214
- if (msg.scheduleSelfTest) {
215
- await storageSet({
216
- [`selfTest${tabId}`]: frameId,
217
- });
218
- }
219
- }
220
- break;
221
- case "selfTestResult":
222
- if (msg.result) {
223
- await showOptOutStatus(tabId, "verified", msg.cmp);
224
- }
225
- break;
226
- case "autoconsentDone": {
227
- await showOptOutStatus(tabId, "success", msg.cmp);
228
- // sometimes self-test needs to be done in another frame
229
- const selfTestKey = `selfTest${tabId}`;
230
- const selfTestFrameId = (await chrome.storage.local.get(selfTestKey))?.[selfTestKey];
231
- if (typeof selfTestFrameId === 'number') {
232
- storageRemove(selfTestKey);
233
- chrome.tabs.sendMessage(tabId, {
234
- type: "selfTest",
235
- }, {
236
- frameId: selfTestFrameId,
237
- });
238
- }
239
- break;
240
- }
241
- case "autoconsentError":
242
- console.error('Error:', msg.details);
243
- break;
244
- case "report":
245
- if (sender.tab && openDevToolsPanels.has(sender.tab.id)) {
246
- openDevToolsPanels.get(sender.tab.id).postMessage({
247
- tabId: sender.tab.id,
248
- frameId: sender.frameId,
249
- ...msg,
250
- });
251
- }
252
- updateTabReports(sender.tab.id, sender.frameId, msg);
253
- break;
126
+ return chrome.scripting.executeScript({
127
+ target: {
128
+ tabId,
129
+ frameIds: [frameId]
130
+ },
131
+ world: "MAIN",
132
+ args: [code],
133
+ func: (code2) => {
134
+ try {
135
+ return window.eval(code2);
136
+ } catch (e) {
137
+ console.warn("eval error", code2, e);
138
+ return;
254
139
  }
140
+ }
255
141
  });
256
- if (manifestVersion === 2) { // MV3 handles this inside the popup
257
- chrome.pageAction.onClicked.addListener(async (tab) => {
258
- const tabId = tab.id;
259
- const detectedKey = `detected${tabId}`;
260
- const frameId = await storageGet(detectedKey);
261
- if (typeof frameId === 'number') {
262
- storageRemove(detectedKey);
263
- await showOptOutStatus(tabId, "working");
264
- chrome.tabs.sendMessage(tabId, {
265
- type: "optOut",
266
- }, {
267
- frameId,
268
- });
142
+ }
143
+ async function getTabReports(tabId) {
144
+ const storageKey = `reports-${tabId}`;
145
+ return (await chrome.storage.session.get(storageKey))[storageKey] || {};
146
+ }
147
+ async function updateTabReports(tabId, frameId, msg) {
148
+ const reportsForTab = await getTabReports(tabId);
149
+ reportsForTab[frameId] = msg;
150
+ await chrome.storage.session.set({ [`reports-${tabId}`]: reportsForTab });
151
+ }
152
+ chrome.runtime.onInstalled.addListener(() => {
153
+ loadRules();
154
+ initConfig();
155
+ });
156
+ if (manifestVersion === 2) {
157
+ loadRules();
158
+ initConfig();
159
+ }
160
+ chrome.tabs.onRemoved.addListener((tabId) => {
161
+ storageRemove(`detected${tabId}`);
162
+ });
163
+ chrome.runtime.onMessage.addListener(
164
+ async (msg, sender) => {
165
+ const tabId = sender.tab.id;
166
+ const frameId = sender.frameId;
167
+ if (enableLogs) {
168
+ console.groupCollapsed(`${msg.type} from ${sender.origin || sender.url}`);
169
+ console.log(msg, sender);
170
+ console.groupEnd();
171
+ }
172
+ const rules = await storageGet("rules");
173
+ const autoconsentConfig = await storageGet("config");
174
+ enableLogs && console.log("got config", autoconsentConfig);
175
+ switch (msg.type) {
176
+ case "init":
177
+ if (frameId === 0) {
178
+ await showOptOutStatus(tabId, "idle");
179
+ }
180
+ chrome.tabs.sendMessage(tabId, {
181
+ type: "initResp",
182
+ rules,
183
+ config: autoconsentConfig
184
+ }, {
185
+ frameId
186
+ });
187
+ break;
188
+ case "eval":
189
+ evalInTab(tabId, frameId, msg.code).then(([result]) => {
190
+ if (enableLogs) {
191
+ console.groupCollapsed(`eval result for ${sender.origin || sender.url}`);
192
+ console.log(msg.code, result.result);
193
+ console.groupEnd();
269
194
  }
270
- });
271
- }
272
- // Communicate with devtools panels
273
- chrome.runtime.onConnect.addListener(function (devToolsConnection) {
274
- if (devToolsConnection.name.startsWith('instance-')) {
275
- // connection from an autoconsent instance - used to detect frame destruction
276
- const tabId = devToolsConnection.sender?.tab?.id;
277
- const instanceId = devToolsConnection.name.slice('instance-'.length);
278
- if (tabId && instanceId) {
279
- devToolsConnection.onDisconnect.addListener(() => {
280
- if (openDevToolsPanels.has(tabId)) {
281
- openDevToolsPanels.get(tabId).postMessage({
282
- type: 'instanceTerminated',
283
- tabId,
284
- instanceId,
285
- });
286
- }
287
- // remove stored frame data
288
- updateTabReports(tabId, devToolsConnection.sender.frameId, undefined);
289
- });
195
+ chrome.tabs.sendMessage(tabId, {
196
+ id: msg.id,
197
+ type: "evalResp",
198
+ result: result.result
199
+ }, {
200
+ frameId
201
+ });
202
+ });
203
+ break;
204
+ case "popupFound":
205
+ await showOptOutStatus(tabId, "available", msg.cmp);
206
+ storageSet({
207
+ [`detected${tabId}`]: frameId
208
+ });
209
+ break;
210
+ case "optOutResult":
211
+ case "optInResult":
212
+ if (msg.result) {
213
+ await showOptOutStatus(tabId, "working", msg.cmp);
214
+ if (msg.scheduleSelfTest) {
215
+ await storageSet({
216
+ [`selfTest${tabId}`]: frameId
217
+ });
290
218
  }
219
+ }
220
+ break;
221
+ case "selfTestResult":
222
+ if (msg.result) {
223
+ await showOptOutStatus(tabId, "verified", msg.cmp);
224
+ }
225
+ break;
226
+ case "autoconsentDone": {
227
+ await showOptOutStatus(tabId, "success", msg.cmp);
228
+ const selfTestKey = `selfTest${tabId}`;
229
+ const selfTestFrameId = (await chrome.storage.local.get(selfTestKey))?.[selfTestKey];
230
+ if (typeof selfTestFrameId === "number") {
231
+ enableLogs && console.log(`Requesting self-test in ${selfTestFrameId}`);
232
+ storageRemove(selfTestKey);
233
+ chrome.tabs.sendMessage(tabId, {
234
+ type: "selfTest"
235
+ }, {
236
+ frameId: selfTestFrameId
237
+ });
238
+ } else {
239
+ enableLogs && console.log(`No self-test scheduled`);
240
+ }
241
+ break;
291
242
  }
292
- else if (devToolsConnection.name === 'devtools-panel') {
293
- let tabId = -1;
294
- // add the listener
295
- devToolsConnection.onMessage.addListener(async (message) => {
296
- tabId = message.tabId;
297
- if (message.type === 'init') {
298
- // save the message channel for this tab
299
- openDevToolsPanels.set(tabId, devToolsConnection);
300
- // dump data cached in bg to the panel
301
- const reportsForTab = await getTabReports(tabId);
302
- Object.keys(reportsForTab || {}).forEach((frameId) => {
303
- devToolsConnection.postMessage({
304
- tabId,
305
- frameId,
306
- ...reportsForTab[parseInt(frameId, 10)]
307
- });
308
- });
309
- }
243
+ case "autoconsentError":
244
+ console.error("Error:", msg.details);
245
+ break;
246
+ case "report":
247
+ if (sender.tab && openDevToolsPanels.has(sender.tab.id)) {
248
+ openDevToolsPanels.get(sender.tab.id).postMessage({
249
+ tabId: sender.tab.id,
250
+ frameId: sender.frameId,
251
+ ...msg
252
+ });
253
+ }
254
+ updateTabReports(sender.tab.id, sender.frameId, msg);
255
+ break;
256
+ }
257
+ }
258
+ );
259
+ if (manifestVersion === 2) {
260
+ chrome.pageAction.onClicked.addListener(async (tab) => {
261
+ const tabId = tab.id;
262
+ const detectedKey = `detected${tabId}`;
263
+ const frameId = await storageGet(detectedKey);
264
+ if (typeof frameId === "number") {
265
+ storageRemove(detectedKey);
266
+ enableLogs && console.log("action.onClicked", tabId, frameId);
267
+ await showOptOutStatus(tabId, "working");
268
+ chrome.tabs.sendMessage(tabId, {
269
+ type: "optOut"
270
+ }, {
271
+ frameId
272
+ });
273
+ }
274
+ });
275
+ }
276
+ chrome.runtime.onConnect.addListener(function(devToolsConnection) {
277
+ if (devToolsConnection.name.startsWith("instance-")) {
278
+ const tabId = devToolsConnection.sender?.tab?.id;
279
+ const instanceId = devToolsConnection.name.slice("instance-".length);
280
+ if (tabId && instanceId) {
281
+ devToolsConnection.onDisconnect.addListener(() => {
282
+ if (openDevToolsPanels.has(tabId)) {
283
+ openDevToolsPanels.get(tabId).postMessage({
284
+ type: "instanceTerminated",
285
+ tabId,
286
+ instanceId
310
287
  });
311
- devToolsConnection.onDisconnect.addListener(function () {
312
- openDevToolsPanels.delete(tabId);
288
+ }
289
+ updateTabReports(tabId, devToolsConnection.sender.frameId, void 0);
290
+ });
291
+ }
292
+ } else if (devToolsConnection.name === "devtools-panel") {
293
+ let tabId = -1;
294
+ devToolsConnection.onMessage.addListener(async (message) => {
295
+ tabId = message.tabId;
296
+ if (message.type === "init") {
297
+ openDevToolsPanels.set(tabId, devToolsConnection);
298
+ const reportsForTab = await getTabReports(tabId);
299
+ Object.keys(reportsForTab || {}).forEach((frameId) => {
300
+ devToolsConnection.postMessage({
301
+ tabId,
302
+ frameId,
303
+ ...reportsForTab[parseInt(frameId, 10)]
313
304
  });
305
+ });
314
306
  }
315
- });
316
- chrome.tabs.onRemoved.addListener((tabId) => {
317
- chrome.storage.session.remove(`reports-${tabId}`);
318
- });
319
-
307
+ });
308
+ devToolsConnection.onDisconnect.addListener(function() {
309
+ openDevToolsPanels.delete(tabId);
310
+ });
311
+ }
312
+ });
313
+ chrome.tabs.onRemoved.addListener((tabId) => {
314
+ chrome.storage.session.remove(`reports-${tabId}`);
315
+ });
320
316
  })();