@duckduckgo/autoconsent 16.63.0 → 17.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.
- package/CHANGELOG.md +41 -0
- package/dist/addon-firefox/background.bundle.js +1 -0
- package/dist/addon-firefox/compact-rules.json +1 -1
- package/dist/addon-firefox/content.bundle.js +162 -35
- package/dist/addon-firefox/manifest.json +1 -1
- package/dist/addon-firefox/popup.bundle.js +1 -0
- package/dist/addon-firefox/rule-index.json +1 -1
- package/dist/addon-firefox/rules.json +1 -1
- package/dist/addon-mv3/background.bundle.js +1 -0
- package/dist/addon-mv3/compact-rules.json +1 -1
- package/dist/addon-mv3/content.bundle.js +162 -35
- package/dist/addon-mv3/manifest.json +1 -1
- package/dist/addon-mv3/popup.bundle.js +1 -0
- package/dist/addon-mv3/rule-index.json +1 -1
- package/dist/addon-mv3/rules.json +1 -1
- package/dist/autoconsent.cjs.js +162 -35
- package/dist/autoconsent.esm.js +162 -35
- package/dist/autoconsent.playwright.js +165 -35
- package/dist/autoconsent.standalone.js +163 -36
- package/dist/types/heuristics.d.ts +12 -3
- package/dist/types/types.d.ts +12 -1
- package/lib/cmps/base.ts +5 -1
- package/lib/heuristics.ts +240 -45
- package/lib/types.ts +16 -1
- package/lib/utils.ts +1 -0
- package/package.json +1 -1
- package/readme.md +1 -1
- package/rules/autoconsent/asrock.json +44 -0
- package/rules/autoconsent/consentmo.json +5 -2
- package/rules/autoconsent/cookie-script.json +34 -15
- package/rules/autoconsent/epaas.json +18 -1
- package/rules/autoconsent/fnsp-cookieconsent.json +30 -0
- package/rules/autoconsent/fod-fujitv.json +13 -0
- package/rules/autoconsent/hkdir.json +33 -0
- package/rules/autoconsent/jokul-cookie-consent.json +28 -0
- package/rules/autoconsent/lego.json +27 -5
- package/rules/autoconsent/mars-cookies-prompt.json +20 -0
- package/rules/autoconsent/niedziela-pl.json +35 -0
- package/rules/autoconsent/nikkeibp.json +10 -0
- package/rules/autoconsent/onecom-cookie-banner.json +25 -0
- package/rules/autoconsent/oslosportslager.no.json +34 -0
- package/rules/autoconsent/plex.tv.json +52 -0
- package/rules/autoconsent/radio-canada.json +28 -0
- package/rules/autoconsent/regjeringen.no.json +13 -0
- package/rules/autoconsent/roll20.json +50 -0
- package/rules/autoconsent/sirdata.json +8 -3
- package/rules/autoconsent/site-notifications-cookie-usage.json +25 -0
- package/rules/autoconsent/sparebank1-optin.json +10 -0
- package/rules/autoconsent/tri-table.json +6 -2
- package/rules/autoconsent/vinnova-se.json +50 -0
- package/rules/autoconsent/vortex-consent.json +33 -0
- package/rules/compact-rules.json +1 -1
- package/rules/rule-index.json +1 -1
- package/rules/rules.json +1 -1
- package/tests/asrock.spec.ts +3 -0
- package/tests/consentmo.spec.ts +2 -0
- package/tests/cookie-script.spec.ts +5 -0
- package/tests/epaas.spec.ts +3 -0
- package/tests/fnsp-cookieconsent.spec.ts +9 -0
- package/tests/fod-fujitv.spec.ts +3 -0
- package/tests/hkdir.spec.ts +10 -0
- package/tests/jokul-cookie-consent.spec.ts +3 -0
- package/tests/mars-cookies-prompt.spec.ts +3 -0
- package/tests/niedziela-pl.spec.ts +3 -0
- package/tests/nikkeibp.spec.ts +8 -0
- package/tests/onecom-cookie-banner.spec.ts +5 -0
- package/tests/oslosportslager.no.spec.ts +3 -0
- package/tests/plex.tv.spec.ts +5 -0
- package/tests/radio-canada.spec.ts +15 -0
- package/tests/regjeringen.no.spec.ts +3 -0
- package/tests/roll20.spec.ts +3 -0
- package/tests/sirdata.spec.ts +13 -1
- package/tests/site-notifications-cookie-usage.spec.ts +3 -0
- package/tests/sparebank1-optin.spec.ts +8 -0
- package/tests/tri-table.spec.ts +1 -1
- package/tests/vinnova-se.spec.ts +6 -0
- package/tests/vortex-consent.spec.ts +18 -0
- package/tests-wtr/heuristics/get-actionable-popups.ts +41 -7
- package/tests-wtr/heuristics/get-potential-popups.test.ts +235 -4
- package/tests-wtr/heuristics/heuristic-cmp.ts +16 -1
- package/rules/generated/auto_CA_plex.tv_ee4.json +0 -40
- package/rules/generated/auto_CA_support.plex.tv_gn3.json +0 -40
- package/tests/generated/auto_CA_plex.tv_ee4.spec.ts +0 -2
- package/tests/generated/auto_CA_support.plex.tv_gn3.spec.ts +0 -6
|
@@ -159,6 +159,7 @@
|
|
|
159
159
|
},
|
|
160
160
|
performanceLoggingEnabled: false,
|
|
161
161
|
heuristicPopupSearchTimeout: 100,
|
|
162
|
+
enableHeuristicHitTest: false,
|
|
162
163
|
heuristicMode: "off"
|
|
163
164
|
// heuristic disabled by default
|
|
164
165
|
};
|
|
@@ -1334,28 +1335,73 @@
|
|
|
1334
1335
|
// lib/heuristics.ts
|
|
1335
1336
|
var BUTTON_LIKE_ELEMENT_SELECTOR = 'button, input[type="button"], input[type="submit"], a, [role="button"], [class*="button"]';
|
|
1336
1337
|
var POPUP_SEARCH_MAX_TIME = 100;
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
return popups.sort((a, b) => (a
|
|
1338
|
+
var ACCEPTED_LEVELS = {
|
|
1339
|
+
off: [],
|
|
1340
|
+
reject: ["reject"],
|
|
1341
|
+
tier1: ["reject", "tier1"],
|
|
1342
|
+
tier2: ["reject", "tier1", "tier2"]
|
|
1343
|
+
};
|
|
1344
|
+
function getActionablePopups(mode = "reject", timeout = POPUP_SEARCH_MAX_TIME, hitTest = false) {
|
|
1345
|
+
const acceptedLevels = ACCEPTED_LEVELS[mode];
|
|
1346
|
+
const isActionable = (popup) => acceptedLevels.includes(popup.regexClassification) && isConsentPopup(popup);
|
|
1347
|
+
const popups = searchPopups(timeout, hitTest, DEFAULT_HIT_TEST_GRID, true).filter(isActionable);
|
|
1348
|
+
return popups.sort((a, b) => classificationRank(a) - classificationRank(b));
|
|
1348
1349
|
}
|
|
1349
|
-
function getPotentialPopups(timeout = POPUP_SEARCH_MAX_TIME) {
|
|
1350
|
+
function getPotentialPopups(timeout = POPUP_SEARCH_MAX_TIME, hitTest = false, hitTestGrid = DEFAULT_HIT_TEST_GRID) {
|
|
1351
|
+
return searchPopups(timeout, hitTest, hitTestGrid);
|
|
1352
|
+
}
|
|
1353
|
+
function searchPopups(timeout, hitTest, hitTestGrid, stopOnReject = false) {
|
|
1350
1354
|
if (!isTopFrame()) {
|
|
1351
|
-
|
|
1352
|
-
return [];
|
|
1353
|
-
}
|
|
1354
|
-
const frameElement = getFramePopupElement(document);
|
|
1355
|
-
const popup = frameElement && toPopupData(frameElement);
|
|
1356
|
-
return popup ? [popup] : [];
|
|
1355
|
+
return getFramePopups();
|
|
1357
1356
|
}
|
|
1358
1357
|
const deadline = performance.now() + timeout;
|
|
1358
|
+
const hitTestPopups = hitTest ? findPopupsByHitTest(deadline, hitTestGrid) : [];
|
|
1359
|
+
if (stopOnReject && hitTestPopups.some((p) => p.regexClassification === "reject" && isConsentPopup(p))) {
|
|
1360
|
+
return hitTestPopups;
|
|
1361
|
+
}
|
|
1362
|
+
const walkPopups = collectPositionedPopups(deadline);
|
|
1363
|
+
return [...walkPopups, ...mergeWalkOverlaps(hitTestPopups, walkPopups)];
|
|
1364
|
+
}
|
|
1365
|
+
var consentPopups = /* @__PURE__ */ new WeakMap();
|
|
1366
|
+
function classificationRank(popup) {
|
|
1367
|
+
return ACCEPTED_LEVELS.tier2.indexOf(popup.regexClassification);
|
|
1368
|
+
}
|
|
1369
|
+
function isConsentPopup(popup) {
|
|
1370
|
+
if (!ACCEPTED_LEVELS.tier2.includes(popup.regexClassification)) {
|
|
1371
|
+
return false;
|
|
1372
|
+
}
|
|
1373
|
+
let result = consentPopups.get(popup);
|
|
1374
|
+
if (result === void 0) {
|
|
1375
|
+
const popupText = popup.text.trim();
|
|
1376
|
+
result = !!popupText && !isExcludedPopup(popupText) && hasHeuristicPatterns(popupText);
|
|
1377
|
+
consentPopups.set(popup, result);
|
|
1378
|
+
}
|
|
1379
|
+
return result;
|
|
1380
|
+
}
|
|
1381
|
+
function mergeWalkOverlaps(hitTestPopups, walkPopups) {
|
|
1382
|
+
return hitTestPopups.filter((h) => {
|
|
1383
|
+
const hitIsConsent = isConsentPopup(h);
|
|
1384
|
+
const absorbs = (p) => !hitIsConsent || isConsentPopup(p) && classificationRank(p) <= classificationRank(h);
|
|
1385
|
+
const walkPopup = walkPopups.find((p) => composedOverlaps(p.element, h.element) && absorbs(p));
|
|
1386
|
+
if (walkPopup) {
|
|
1387
|
+
(walkPopup.hitPoints ??= []).push(...h.hitPoints ?? []);
|
|
1388
|
+
}
|
|
1389
|
+
return !walkPopup;
|
|
1390
|
+
});
|
|
1391
|
+
}
|
|
1392
|
+
function getFramePopups() {
|
|
1393
|
+
if (window.parent && window.parent !== window.top) {
|
|
1394
|
+
return [];
|
|
1395
|
+
}
|
|
1396
|
+
const frameElement = getFramePopupElement(document);
|
|
1397
|
+
const popup = frameElement && toPopupData(frameElement);
|
|
1398
|
+
if (!popup) {
|
|
1399
|
+
return [];
|
|
1400
|
+
}
|
|
1401
|
+
popup.source = "frame";
|
|
1402
|
+
return [popup];
|
|
1403
|
+
}
|
|
1404
|
+
function collectPositionedPopups(deadline) {
|
|
1359
1405
|
const { elements, shadowHosts } = getPopupLikeElements(deadline);
|
|
1360
1406
|
const potentialPopups = [];
|
|
1361
1407
|
const expanded = [];
|
|
@@ -1371,17 +1417,86 @@
|
|
|
1371
1417
|
if (root !== popup) {
|
|
1372
1418
|
expanded.push(root.element);
|
|
1373
1419
|
}
|
|
1420
|
+
root.source = "walk";
|
|
1374
1421
|
potentialPopups.push(root);
|
|
1375
1422
|
}
|
|
1376
1423
|
return potentialPopups.filter((p) => !expanded.some((root) => root !== p.element && composedContains(root, p.element)));
|
|
1377
1424
|
}
|
|
1425
|
+
var DEFAULT_HIT_TEST_GRID = {
|
|
1426
|
+
columns: [0.1, 0.5, 0.9],
|
|
1427
|
+
// banners sit along the top and bottom edges and modals in the middle; rows 150px in added almost nothing in crawls
|
|
1428
|
+
edgeRows: [30, 90]
|
|
1429
|
+
};
|
|
1430
|
+
function findPopupsByHitTest(deadline, grid) {
|
|
1431
|
+
const climbed = /* @__PURE__ */ new Map();
|
|
1432
|
+
const found = [];
|
|
1433
|
+
const toPopup = (el) => el.querySelector(TEXT_ENTRY_SELECTOR) ? null : toPopupRoot(el);
|
|
1434
|
+
for (const [x, y] of getHitTestPoints(grid)) {
|
|
1435
|
+
if (performance.now() > deadline) {
|
|
1436
|
+
return found;
|
|
1437
|
+
}
|
|
1438
|
+
const path = [];
|
|
1439
|
+
let reached = null;
|
|
1440
|
+
const shouldStop = (el) => {
|
|
1441
|
+
if (climbed.has(el)) {
|
|
1442
|
+
reached = climbed.get(el) ?? null;
|
|
1443
|
+
return true;
|
|
1444
|
+
}
|
|
1445
|
+
const overlapped = found.find((p) => composedOverlaps(p.element, el));
|
|
1446
|
+
if (overlapped) {
|
|
1447
|
+
reached = composedContains(overlapped.element, el) ? overlapped : null;
|
|
1448
|
+
return true;
|
|
1449
|
+
}
|
|
1450
|
+
path.push(el);
|
|
1451
|
+
return false;
|
|
1452
|
+
};
|
|
1453
|
+
const hit = closestHTMLElement(deepElementFromPoint(x, y));
|
|
1454
|
+
const popup = climbToPopup(hit, MAX_HIT_TEST_CLIMB_DEPTH, toPopup, shouldStop);
|
|
1455
|
+
if (popup) {
|
|
1456
|
+
popup.source = "hitTest";
|
|
1457
|
+
found.push(popup);
|
|
1458
|
+
reached = popup;
|
|
1459
|
+
}
|
|
1460
|
+
for (const el of path) {
|
|
1461
|
+
climbed.set(el, reached);
|
|
1462
|
+
}
|
|
1463
|
+
if (reached) {
|
|
1464
|
+
(reached.hitPoints ??= []).push([x, y]);
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
return found;
|
|
1468
|
+
}
|
|
1469
|
+
function getHitTestPoints(grid) {
|
|
1470
|
+
const { innerWidth: width, innerHeight: height } = window;
|
|
1471
|
+
const rows = [...grid.edgeRows, height / 2, ...grid.edgeRows.map((y) => height - y)].map((y) => Math.round(y));
|
|
1472
|
+
const ys = [...new Set(rows)].filter((y) => y >= 0 && y < height);
|
|
1473
|
+
return ys.flatMap((y) => grid.columns.map((column) => [Math.round(column * width), y]));
|
|
1474
|
+
}
|
|
1475
|
+
var TEXT_ENTRY_SELECTOR = 'textarea, input:not([type]), input[type="text"], input[type="email"], input[type="password"], input[type="search"], input[type="tel"], input[type="number"], input[type="url"]';
|
|
1476
|
+
function deepElementFromPoint(x, y) {
|
|
1477
|
+
let el = document.elementFromPoint(x, y);
|
|
1478
|
+
while (el?.shadowRoot) {
|
|
1479
|
+
const inner = el.shadowRoot.elementFromPoint(x, y);
|
|
1480
|
+
if (!inner || inner === el) {
|
|
1481
|
+
break;
|
|
1482
|
+
}
|
|
1483
|
+
el = inner;
|
|
1484
|
+
}
|
|
1485
|
+
return el;
|
|
1486
|
+
}
|
|
1487
|
+
function closestHTMLElement(el) {
|
|
1488
|
+
while (el && !(el instanceof HTMLElement)) {
|
|
1489
|
+
el = el.parentElement;
|
|
1490
|
+
}
|
|
1491
|
+
return el;
|
|
1492
|
+
}
|
|
1378
1493
|
function toPopupData(el, shadowHosts, text = getElementText(el)) {
|
|
1379
1494
|
if (!text) {
|
|
1380
1495
|
return null;
|
|
1381
1496
|
}
|
|
1382
1497
|
const buttons = getButtonData(el, shadowHosts);
|
|
1383
1498
|
classifyButtons(buttons);
|
|
1384
|
-
return { text, element: el, buttons };
|
|
1499
|
+
return { text, element: el, buttons, regexClassification: classifyPopup(buttons) };
|
|
1385
1500
|
}
|
|
1386
1501
|
function hasPopupButtons(text, buttons) {
|
|
1387
1502
|
return !isOnlyButtonText(text, buttons) && buttons.some((b) => b.regexClassification !== "other");
|
|
@@ -1393,26 +1508,34 @@
|
|
|
1393
1508
|
}
|
|
1394
1509
|
return rest.replace(/\s+/g, "").length < 10;
|
|
1395
1510
|
}
|
|
1511
|
+
function toPopupRoot(el, shadowHosts) {
|
|
1512
|
+
const text = getElementText(el);
|
|
1513
|
+
if (!text || !hasHeuristicPatterns(text)) {
|
|
1514
|
+
return null;
|
|
1515
|
+
}
|
|
1516
|
+
const popup = toPopupData(el, shadowHosts, text);
|
|
1517
|
+
return popup && hasPopupButtons(text, popup.buttons) ? popup : null;
|
|
1518
|
+
}
|
|
1396
1519
|
var MAX_FRAGMENT_EXPANSION_DEPTH = 6;
|
|
1520
|
+
var MAX_HIT_TEST_CLIMB_DEPTH = 8;
|
|
1521
|
+
function climbToPopup(el, maxDepth, toPopup, shouldStop) {
|
|
1522
|
+
for (let depth = 0; el && depth < maxDepth; depth++, el = getComposedParent(el)) {
|
|
1523
|
+
if (shouldStop?.(el) || el === document.body || el === document.documentElement || el.getBoundingClientRect().height > window.innerHeight) {
|
|
1524
|
+
return null;
|
|
1525
|
+
}
|
|
1526
|
+
const popup = toPopup(el);
|
|
1527
|
+
if (popup) {
|
|
1528
|
+
return popup;
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
return null;
|
|
1532
|
+
}
|
|
1397
1533
|
function expandPopupFragment(popup, shadowHosts) {
|
|
1398
1534
|
if (hasHeuristicPatterns(popup.text) && hasPopupButtons(popup.text, popup.buttons)) {
|
|
1399
1535
|
return popup;
|
|
1400
1536
|
}
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
if (el === document.body || el === document.documentElement || el.getBoundingClientRect().height > window.innerHeight) {
|
|
1404
|
-
break;
|
|
1405
|
-
}
|
|
1406
|
-
const text = getElementText(el);
|
|
1407
|
-
if (!text || !hasHeuristicPatterns(text)) {
|
|
1408
|
-
continue;
|
|
1409
|
-
}
|
|
1410
|
-
const root = toPopupData(el, shadowHosts, text);
|
|
1411
|
-
if (root && hasPopupButtons(text, root.buttons)) {
|
|
1412
|
-
return root;
|
|
1413
|
-
}
|
|
1414
|
-
}
|
|
1415
|
-
return popup;
|
|
1537
|
+
const parent = getComposedParent(popup.element);
|
|
1538
|
+
return climbToPopup(parent, MAX_FRAGMENT_EXPANSION_DEPTH, (el) => toPopupRoot(el, shadowHosts)) ?? popup;
|
|
1416
1539
|
}
|
|
1417
1540
|
function getComposedParent(el) {
|
|
1418
1541
|
if (el.parentElement) {
|
|
@@ -1443,6 +1566,9 @@
|
|
|
1443
1566
|
function isRenderedTextElement(el) {
|
|
1444
1567
|
return el instanceof HTMLElement && !["STYLE", "SCRIPT", "TEMPLATE", "NOSCRIPT", "LINK", "SLOT"].includes(el.tagName) && window.getComputedStyle(el).display !== "none";
|
|
1445
1568
|
}
|
|
1569
|
+
function composedOverlaps(a, b) {
|
|
1570
|
+
return composedContains(a, b) || composedContains(b, a);
|
|
1571
|
+
}
|
|
1446
1572
|
function composedContains(container, node) {
|
|
1447
1573
|
if (container.contains(node)) {
|
|
1448
1574
|
return true;
|
|
@@ -1934,7 +2060,11 @@
|
|
|
1934
2060
|
async detectCmp() {
|
|
1935
2061
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
1936
2062
|
this.autoconsent.config.performanceLoggingEnabled && performance.mark("heuristicDetectorStart");
|
|
1937
|
-
this.popups = getActionablePopups(
|
|
2063
|
+
this.popups = getActionablePopups(
|
|
2064
|
+
this.mode,
|
|
2065
|
+
this.autoconsent.config.heuristicPopupSearchTimeout,
|
|
2066
|
+
this.autoconsent.config.enableHeuristicHitTest
|
|
2067
|
+
);
|
|
1938
2068
|
this.autoconsent.config.performanceLoggingEnabled && performance.mark("heuristicDetectorEnd");
|
|
1939
2069
|
this.autoconsent.config.performanceLoggingEnabled && performance.measure("heuristicDetector", "heuristicDetectorStart", "heuristicDetectorEnd");
|
|
1940
2070
|
if (this.popups.length > 0) {
|