@duckduckgo/autoconsent 15.0.0 → 15.1.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.
- package/CHANGELOG.md +12 -0
- package/build.sh +3 -0
- package/dist/addon-firefox/content.bundle.js +15 -7
- package/dist/addon-firefox/manifest.json +1 -1
- package/dist/addon-firefox/popup.bundle.js +180 -13
- package/dist/addon-firefox/popup.html +93 -8
- package/dist/addon-firefox/rule-index.json +1 -0
- package/dist/addon-mv3/content.bundle.js +15 -7
- package/dist/addon-mv3/manifest.json +1 -1
- package/dist/addon-mv3/popup.bundle.js +180 -13
- package/dist/addon-mv3/popup.html +93 -8
- package/dist/addon-mv3/rule-index.json +1 -0
- package/dist/autoconsent.cjs.js +15 -7
- package/dist/autoconsent.esm.js +15 -7
- package/dist/autoconsent.extra.cjs.js +15 -7
- package/dist/autoconsent.extra.esm.js +15 -7
- package/dist/autoconsent.playwright.js +15 -7
- package/dist/autoconsent.standalone.js +4138 -0
- package/dist/types/cmps/trustarc-top.d.ts +1 -1
- package/dist/types/eval-handler.d.ts +3 -3
- package/lib/cmps/conversant.ts +7 -4
- package/lib/cmps/trustarc-top.ts +1 -1
- package/lib/cmps/uniconsent.ts +4 -4
- package/lib/eval-handler.ts +6 -3
- package/lib/utils.ts +11 -5
- package/package.json +1 -1
- package/rules/build.ts +4 -0
- package/rules/rule-index-builder.ts +63 -0
- package/rules/rule-index.json +1 -0
- package/standalone/content.ts +103 -0
|
@@ -913,6 +913,7 @@
|
|
|
913
913
|
}
|
|
914
914
|
|
|
915
915
|
// addon/popup.ts
|
|
916
|
+
var maxRenderedRules = 100;
|
|
916
917
|
async function init() {
|
|
917
918
|
const autoconsentConfig = await storageGet("config");
|
|
918
919
|
const enabledCheckbox = document.querySelector("input#enabled");
|
|
@@ -926,8 +927,7 @@
|
|
|
926
927
|
const cosmeticOffRadio = document.querySelector("input#cosmetic-off");
|
|
927
928
|
const generatedOnRadio = document.querySelector("input#generated-on");
|
|
928
929
|
const generatedOffRadio = document.querySelector("input#generated-off");
|
|
929
|
-
const
|
|
930
|
-
const heuristicActionOffRadio = document.querySelector("input#heuristic-action-off");
|
|
930
|
+
const heuristicActionCheckbox = document.querySelector("input#heuristic-action");
|
|
931
931
|
const visualTestOnRadio = document.querySelector("input#visual-test-on");
|
|
932
932
|
const visualTestOffRadio = document.querySelector("input#visual-test-off");
|
|
933
933
|
const popupMutationOnRadio = document.querySelector("input#popup-mutation-on");
|
|
@@ -942,6 +942,47 @@
|
|
|
942
942
|
const logsMessagesCheckbox = document.querySelector("input#logs-messages");
|
|
943
943
|
const ruleReloadButton = document.querySelector("#reload");
|
|
944
944
|
const resetButton = document.querySelector("#reset");
|
|
945
|
+
const ruleSectionControls = {
|
|
946
|
+
generated: {
|
|
947
|
+
details: document.querySelector("#generated-rules-section"),
|
|
948
|
+
count: document.querySelector("#generated-rules-count"),
|
|
949
|
+
search: document.querySelector("#generated-rules-search"),
|
|
950
|
+
enableAll: document.querySelector("#generated-rules-enable-all"),
|
|
951
|
+
disableAll: document.querySelector("#generated-rules-disable-all"),
|
|
952
|
+
status: document.querySelector("#generated-rules-status"),
|
|
953
|
+
list: document.querySelector("#generated-rules-list")
|
|
954
|
+
},
|
|
955
|
+
generic: {
|
|
956
|
+
details: document.querySelector("#generic-rules-section"),
|
|
957
|
+
count: document.querySelector("#generic-rules-count"),
|
|
958
|
+
search: document.querySelector("#generic-rules-search"),
|
|
959
|
+
enableAll: document.querySelector("#generic-rules-enable-all"),
|
|
960
|
+
disableAll: document.querySelector("#generic-rules-disable-all"),
|
|
961
|
+
status: document.querySelector("#generic-rules-status"),
|
|
962
|
+
list: document.querySelector("#generic-rules-list")
|
|
963
|
+
},
|
|
964
|
+
code: {
|
|
965
|
+
details: document.querySelector("#code-rules-section"),
|
|
966
|
+
count: document.querySelector("#code-rules-count"),
|
|
967
|
+
search: document.querySelector("#code-rules-search"),
|
|
968
|
+
enableAll: document.querySelector("#code-rules-enable-all"),
|
|
969
|
+
disableAll: document.querySelector("#code-rules-disable-all"),
|
|
970
|
+
status: document.querySelector("#code-rules-status"),
|
|
971
|
+
list: document.querySelector("#code-rules-list")
|
|
972
|
+
},
|
|
973
|
+
consentomatic: {
|
|
974
|
+
details: document.querySelector("#consentomatic-rules-section"),
|
|
975
|
+
count: document.querySelector("#consentomatic-rules-count"),
|
|
976
|
+
search: document.querySelector("#consentomatic-rules-search"),
|
|
977
|
+
enableAll: document.querySelector("#consentomatic-rules-enable-all"),
|
|
978
|
+
disableAll: document.querySelector("#consentomatic-rules-disable-all"),
|
|
979
|
+
status: document.querySelector("#consentomatic-rules-status"),
|
|
980
|
+
list: document.querySelector("#consentomatic-rules-list")
|
|
981
|
+
}
|
|
982
|
+
};
|
|
983
|
+
let ruleIndexPromise = null;
|
|
984
|
+
let ruleIndex = null;
|
|
985
|
+
autoconsentConfig.disabledCmps = autoconsentConfig.disabledCmps || [];
|
|
945
986
|
const [currentTab] = await chrome.tabs.query({ active: true, lastFocusedWindow: true });
|
|
946
987
|
if (!currentTab.url || !currentTab.id) {
|
|
947
988
|
console.error("Current tab is not valid");
|
|
@@ -1007,11 +1048,7 @@
|
|
|
1007
1048
|
} else {
|
|
1008
1049
|
generatedOffRadio.checked = true;
|
|
1009
1050
|
}
|
|
1010
|
-
|
|
1011
|
-
heuristicActionOnRadio.checked = true;
|
|
1012
|
-
} else {
|
|
1013
|
-
heuristicActionOffRadio.checked = true;
|
|
1014
|
-
}
|
|
1051
|
+
heuristicActionCheckbox.checked = autoconsentConfig.enableHeuristicAction;
|
|
1015
1052
|
if (autoconsentConfig.visualTest) {
|
|
1016
1053
|
visualTestOnRadio.checked = true;
|
|
1017
1054
|
} else {
|
|
@@ -1061,11 +1098,10 @@
|
|
|
1061
1098
|
generatedOnRadio.addEventListener("change", generatedChange);
|
|
1062
1099
|
generatedOffRadio.addEventListener("change", generatedChange);
|
|
1063
1100
|
function heuristicActionChange() {
|
|
1064
|
-
autoconsentConfig.enableHeuristicAction =
|
|
1101
|
+
autoconsentConfig.enableHeuristicAction = heuristicActionCheckbox.checked;
|
|
1065
1102
|
storageSet({ config: autoconsentConfig });
|
|
1066
1103
|
}
|
|
1067
|
-
|
|
1068
|
-
heuristicActionOffRadio.addEventListener("change", heuristicActionChange);
|
|
1104
|
+
heuristicActionCheckbox.addEventListener("change", heuristicActionChange);
|
|
1069
1105
|
function visualTestChange() {
|
|
1070
1106
|
autoconsentConfig.visualTest = visualTestOnRadio.checked;
|
|
1071
1107
|
storageSet({ config: autoconsentConfig });
|
|
@@ -1111,10 +1147,141 @@
|
|
|
1111
1147
|
logsMessagesCheckbox.addEventListener("change", () => {
|
|
1112
1148
|
updateLogsConfig();
|
|
1113
1149
|
});
|
|
1150
|
+
async function loadRuleIndex() {
|
|
1151
|
+
if (!ruleIndexPromise) {
|
|
1152
|
+
ruleIndexPromise = fetch("./rule-index.json").then(async (res) => await res.json());
|
|
1153
|
+
}
|
|
1154
|
+
ruleIndex = await ruleIndexPromise;
|
|
1155
|
+
updateRuleCounts();
|
|
1156
|
+
return ruleIndex;
|
|
1157
|
+
}
|
|
1158
|
+
function updateRuleCounts() {
|
|
1159
|
+
if (!ruleIndex) {
|
|
1160
|
+
return;
|
|
1161
|
+
}
|
|
1162
|
+
const disabledCmps = autoconsentConfig.disabledCmps || [];
|
|
1163
|
+
Object.keys(ruleSectionControls).forEach((section) => {
|
|
1164
|
+
const sectionRules = ruleIndex?.filter((rule) => rule.section === section) || [];
|
|
1165
|
+
const disabledInSection = sectionRules.filter((rule) => disabledCmps.includes(rule.name)).length;
|
|
1166
|
+
const count = ruleSectionControls[section].count;
|
|
1167
|
+
count.textContent = `(${disabledInSection}/${sectionRules.length} disabled)`;
|
|
1168
|
+
count.classList.toggle("rule-count-disabled", disabledInSection > 0);
|
|
1169
|
+
});
|
|
1170
|
+
}
|
|
1171
|
+
function setRuleEnabled(ruleName, enabled) {
|
|
1172
|
+
const disabledCmps = new Set(autoconsentConfig.disabledCmps || []);
|
|
1173
|
+
if (enabled) {
|
|
1174
|
+
disabledCmps.delete(ruleName);
|
|
1175
|
+
} else {
|
|
1176
|
+
disabledCmps.add(ruleName);
|
|
1177
|
+
}
|
|
1178
|
+
autoconsentConfig.disabledCmps = Array.from(disabledCmps).sort();
|
|
1179
|
+
storageSet({ config: autoconsentConfig });
|
|
1180
|
+
updateRuleCounts();
|
|
1181
|
+
}
|
|
1182
|
+
function renderOpenRuleSections() {
|
|
1183
|
+
Object.keys(ruleSectionControls).forEach((section) => {
|
|
1184
|
+
if (ruleSectionControls[section].details.open) {
|
|
1185
|
+
renderRuleSection(section);
|
|
1186
|
+
}
|
|
1187
|
+
});
|
|
1188
|
+
}
|
|
1189
|
+
function setRuleSectionEnabled(section, enabled) {
|
|
1190
|
+
if (!ruleIndex) {
|
|
1191
|
+
return;
|
|
1192
|
+
}
|
|
1193
|
+
const disabledCmps = new Set(autoconsentConfig.disabledCmps || []);
|
|
1194
|
+
ruleIndex.filter((rule) => rule.section === section).forEach((rule) => {
|
|
1195
|
+
if (enabled) {
|
|
1196
|
+
disabledCmps.delete(rule.name);
|
|
1197
|
+
} else {
|
|
1198
|
+
disabledCmps.add(rule.name);
|
|
1199
|
+
}
|
|
1200
|
+
});
|
|
1201
|
+
autoconsentConfig.disabledCmps = Array.from(disabledCmps).sort();
|
|
1202
|
+
storageSet({ config: autoconsentConfig });
|
|
1203
|
+
updateRuleCounts();
|
|
1204
|
+
renderOpenRuleSections();
|
|
1205
|
+
}
|
|
1206
|
+
function renderRuleSection(section) {
|
|
1207
|
+
const controls = ruleSectionControls[section];
|
|
1208
|
+
if (!ruleIndex) {
|
|
1209
|
+
controls.status.textContent = "Rules are not loaded yet.";
|
|
1210
|
+
return;
|
|
1211
|
+
}
|
|
1212
|
+
const disabledCmps = autoconsentConfig.disabledCmps || [];
|
|
1213
|
+
const searchQuery = controls.search.value.trim().toLowerCase();
|
|
1214
|
+
const sectionRules = ruleIndex.filter((rule) => rule.section === section);
|
|
1215
|
+
const matchingRules = sectionRules.filter((rule) => {
|
|
1216
|
+
if (!searchQuery) {
|
|
1217
|
+
return disabledCmps.includes(rule.name);
|
|
1218
|
+
}
|
|
1219
|
+
return rule.name.toLowerCase().includes(searchQuery) || !!rule.urlPattern?.toLowerCase().includes(searchQuery);
|
|
1220
|
+
});
|
|
1221
|
+
const renderedRules = matchingRules.slice(0, maxRenderedRules);
|
|
1222
|
+
const disabledInSection = sectionRules.filter((rule) => disabledCmps.includes(rule.name)).length;
|
|
1223
|
+
controls.status.textContent = searchQuery ? `Showing ${renderedRules.length} of ${matchingRules.length} matches. ${disabledInSection} disabled.` : `Showing ${renderedRules.length} of ${disabledInSection} disabled rules. Search to find enabled rules.`;
|
|
1224
|
+
controls.list.replaceChildren(
|
|
1225
|
+
...renderedRules.map((rule) => {
|
|
1226
|
+
const checkbox = document.createElement("input");
|
|
1227
|
+
checkbox.type = "checkbox";
|
|
1228
|
+
checkbox.checked = !disabledCmps.includes(rule.name);
|
|
1229
|
+
checkbox.addEventListener("change", () => {
|
|
1230
|
+
setRuleEnabled(rule.name, checkbox.checked);
|
|
1231
|
+
renderRuleSection(section);
|
|
1232
|
+
});
|
|
1233
|
+
const label = document.createElement("label");
|
|
1234
|
+
label.className = "rule-row";
|
|
1235
|
+
label.title = rule.urlPattern ? `${rule.name}
|
|
1236
|
+
${rule.urlPattern}` : rule.name;
|
|
1237
|
+
label.append(checkbox, document.createTextNode(` ${rule.name}${rule.cosmetic ? " (cosmetic)" : ""}`));
|
|
1238
|
+
return label;
|
|
1239
|
+
})
|
|
1240
|
+
);
|
|
1241
|
+
}
|
|
1242
|
+
async function loadAndRenderRuleSection(section) {
|
|
1243
|
+
ruleSectionControls[section].status.textContent = "Loading rules...";
|
|
1244
|
+
try {
|
|
1245
|
+
await loadRuleIndex();
|
|
1246
|
+
renderRuleSection(section);
|
|
1247
|
+
} catch (e) {
|
|
1248
|
+
console.error("Failed to load rule index", e);
|
|
1249
|
+
ruleSectionControls[section].status.textContent = "Failed to load rules.";
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
Object.keys(ruleSectionControls).forEach((section) => {
|
|
1253
|
+
const controls = ruleSectionControls[section];
|
|
1254
|
+
controls.details.addEventListener("toggle", () => {
|
|
1255
|
+
if (controls.details.open) {
|
|
1256
|
+
loadAndRenderRuleSection(section);
|
|
1257
|
+
}
|
|
1258
|
+
});
|
|
1259
|
+
controls.search.addEventListener("input", () => renderRuleSection(section));
|
|
1260
|
+
controls.enableAll.addEventListener("click", async () => {
|
|
1261
|
+
await loadRuleIndex();
|
|
1262
|
+
setRuleSectionEnabled(section, true);
|
|
1263
|
+
});
|
|
1264
|
+
controls.disableAll.addEventListener("click", async () => {
|
|
1265
|
+
await loadRuleIndex();
|
|
1266
|
+
setRuleSectionEnabled(section, false);
|
|
1267
|
+
});
|
|
1268
|
+
});
|
|
1269
|
+
loadRuleIndex().catch((e) => {
|
|
1270
|
+
console.error("Failed to load rule index", e);
|
|
1271
|
+
});
|
|
1114
1272
|
ruleReloadButton.addEventListener("click", async () => {
|
|
1115
|
-
const
|
|
1116
|
-
|
|
1117
|
-
|
|
1273
|
+
const [compactRulesRes, fullRulesRes] = await Promise.all([fetch("./compact-rules.json"), fetch("./rules.json")]);
|
|
1274
|
+
const fullRules = await fullRulesRes.json();
|
|
1275
|
+
await storageSet({
|
|
1276
|
+
rules: await compactRulesRes.json(),
|
|
1277
|
+
fullRules: fullRules.autoconsent
|
|
1278
|
+
});
|
|
1279
|
+
ruleIndexPromise = null;
|
|
1280
|
+
ruleIndex = null;
|
|
1281
|
+
Object.keys(ruleSectionControls).forEach((section) => {
|
|
1282
|
+
if (ruleSectionControls[section].details.open) {
|
|
1283
|
+
loadAndRenderRuleSection(section);
|
|
1284
|
+
}
|
|
1118
1285
|
});
|
|
1119
1286
|
});
|
|
1120
1287
|
resetButton.addEventListener("click", async () => {
|
|
@@ -23,6 +23,52 @@
|
|
|
23
23
|
cursor: pointer;
|
|
24
24
|
border-radius: 2px;
|
|
25
25
|
}
|
|
26
|
+
|
|
27
|
+
.rule-section {
|
|
28
|
+
margin: 0.5em 0;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.rule-search {
|
|
32
|
+
box-sizing: border-box;
|
|
33
|
+
margin: 0.5em 0;
|
|
34
|
+
width: 100%;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.rule-actions {
|
|
38
|
+
display: flex;
|
|
39
|
+
gap: 0.5em;
|
|
40
|
+
margin: 0.5em 0;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.rule-actions button {
|
|
44
|
+
flex: 1;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.rule-list {
|
|
48
|
+
border: 1px solid #ddd;
|
|
49
|
+
max-height: 12em;
|
|
50
|
+
overflow-y: auto;
|
|
51
|
+
padding: 0.25em;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.rule-row {
|
|
55
|
+
display: block;
|
|
56
|
+
overflow: hidden;
|
|
57
|
+
padding: 0.15em 0;
|
|
58
|
+
text-overflow: ellipsis;
|
|
59
|
+
white-space: nowrap;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.rule-list-status {
|
|
63
|
+
color: #666;
|
|
64
|
+
font-size: 0.9em;
|
|
65
|
+
margin: 0.25em 0;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.rule-count-disabled {
|
|
69
|
+
color: #b00020;
|
|
70
|
+
font-weight: bold;
|
|
71
|
+
}
|
|
26
72
|
</style>
|
|
27
73
|
</head>
|
|
28
74
|
|
|
@@ -96,16 +142,55 @@
|
|
|
96
142
|
</fieldset>
|
|
97
143
|
|
|
98
144
|
<fieldset>
|
|
99
|
-
<legend>
|
|
145
|
+
<legend>Rules</legend>
|
|
100
146
|
|
|
101
|
-
<
|
|
102
|
-
<
|
|
103
|
-
<
|
|
104
|
-
|
|
147
|
+
<details class="rule-section" id="generated-rules-section">
|
|
148
|
+
<summary>Generated rules <span id="generated-rules-count"></span></summary>
|
|
149
|
+
<input class="rule-search" type="search" id="generated-rules-search" placeholder="Search generated rules" />
|
|
150
|
+
<div class="rule-actions">
|
|
151
|
+
<button id="generated-rules-enable-all">Enable all</button>
|
|
152
|
+
<button id="generated-rules-disable-all">Disable all</button>
|
|
153
|
+
</div>
|
|
154
|
+
<div class="rule-list-status" id="generated-rules-status"></div>
|
|
155
|
+
<div class="rule-list" id="generated-rules-list"></div>
|
|
156
|
+
</details>
|
|
105
157
|
|
|
106
|
-
<
|
|
107
|
-
<
|
|
108
|
-
<
|
|
158
|
+
<details class="rule-section" id="generic-rules-section">
|
|
159
|
+
<summary>Generic rules <span id="generic-rules-count"></span></summary>
|
|
160
|
+
<input class="rule-search" type="search" id="generic-rules-search" placeholder="Search generic rules" />
|
|
161
|
+
<div class="rule-actions">
|
|
162
|
+
<button id="generic-rules-enable-all">Enable all</button>
|
|
163
|
+
<button id="generic-rules-disable-all">Disable all</button>
|
|
164
|
+
</div>
|
|
165
|
+
<div class="rule-list-status" id="generic-rules-status"></div>
|
|
166
|
+
<div class="rule-list" id="generic-rules-list"></div>
|
|
167
|
+
</details>
|
|
168
|
+
|
|
169
|
+
<details class="rule-section" id="code-rules-section">
|
|
170
|
+
<summary>Code-based rules <span id="code-rules-count"></span></summary>
|
|
171
|
+
<input class="rule-search" type="search" id="code-rules-search" placeholder="Search code-based rules" />
|
|
172
|
+
<div class="rule-actions">
|
|
173
|
+
<button id="code-rules-enable-all">Enable all</button>
|
|
174
|
+
<button id="code-rules-disable-all">Disable all</button>
|
|
175
|
+
</div>
|
|
176
|
+
<div class="rule-list-status" id="code-rules-status"></div>
|
|
177
|
+
<div class="rule-list" id="code-rules-list"></div>
|
|
178
|
+
</details>
|
|
179
|
+
|
|
180
|
+
<details class="rule-section" id="consentomatic-rules-section">
|
|
181
|
+
<summary>Consent-O-Matic rules <span id="consentomatic-rules-count"></span></summary>
|
|
182
|
+
<input class="rule-search" type="search" id="consentomatic-rules-search" placeholder="Search Consent-O-Matic rules" />
|
|
183
|
+
<div class="rule-actions">
|
|
184
|
+
<button id="consentomatic-rules-enable-all">Enable all</button>
|
|
185
|
+
<button id="consentomatic-rules-disable-all">Disable all</button>
|
|
186
|
+
</div>
|
|
187
|
+
<div class="rule-list-status" id="consentomatic-rules-status"></div>
|
|
188
|
+
<div class="rule-list" id="consentomatic-rules-list"></div>
|
|
189
|
+
</details>
|
|
190
|
+
|
|
191
|
+
<div class="rule-section">
|
|
192
|
+
<input type="checkbox" id="heuristic-action" name="heuristic-action" />
|
|
193
|
+
<label for="heuristic-action">Handle unknown popups (heuristic rule)</label>
|
|
109
194
|
</div>
|
|
110
195
|
</fieldset>
|
|
111
196
|
|