Remove common consent overlays
This commit is contained in:
106
src/archiver.mjs
106
src/archiver.mjs
@@ -22,6 +22,68 @@ const VIEWPORT = {
|
|||||||
height: 768
|
height: 768
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const COMMON_ANNOYANCE_SELECTORS = [
|
||||||
|
"[id^=\"sp_message_container_\"]",
|
||||||
|
"iframe[id^=\"sp_message_iframe_\"]",
|
||||||
|
"iframe[title*=\"consent\" i]",
|
||||||
|
"iframe[title*=\"privacy manager\" i]",
|
||||||
|
"#onetrust-consent-sdk",
|
||||||
|
"#onetrust-banner-sdk",
|
||||||
|
"#didomi-host",
|
||||||
|
"#qc-cmp2-container",
|
||||||
|
".qc-cmp2-container",
|
||||||
|
"#CybotCookiebotDialog",
|
||||||
|
".iubenda-cs-container",
|
||||||
|
"#cmpwrapper",
|
||||||
|
"[id^=\"cmpbox\"]",
|
||||||
|
".fc-consent-root",
|
||||||
|
".fc-dialog-container",
|
||||||
|
"[aria-modal=\"true\"][id*=\"consent\" i]",
|
||||||
|
"[aria-modal=\"true\"][id*=\"cookie\" i]",
|
||||||
|
"[role=\"dialog\"][aria-label*=\"cookie\" i]",
|
||||||
|
"[role=\"dialog\"][aria-label*=\"consent\" i]",
|
||||||
|
"[id*=\"cookie-banner\" i]",
|
||||||
|
"[class*=\"cookie-banner\" i]",
|
||||||
|
"[id*=\"cookie-consent\" i]",
|
||||||
|
"[class*=\"cookie-consent\" i]",
|
||||||
|
"[id*=\"cookie-notice\" i]",
|
||||||
|
"[class*=\"cookie-notice\" i]",
|
||||||
|
"[id*=\"cookie-popup\" i]",
|
||||||
|
"[class*=\"cookie-popup\" i]",
|
||||||
|
"[id*=\"adblock\" i]",
|
||||||
|
"[class*=\"adblock\" i]",
|
||||||
|
"[id*=\"ad-block\" i]",
|
||||||
|
"[class*=\"ad-block\" i]"
|
||||||
|
];
|
||||||
|
|
||||||
|
const COMMON_ANNOYANCE_ROOT_CLASSES = [
|
||||||
|
"sp-message-open",
|
||||||
|
"didomi-popup-open",
|
||||||
|
"qc-cmp-ui-showing",
|
||||||
|
"ot-sdk-show-settings",
|
||||||
|
"iubenda-cs-visible"
|
||||||
|
];
|
||||||
|
|
||||||
|
const COMMON_ANNOYANCE_CSS = `
|
||||||
|
${COMMON_ANNOYANCE_SELECTORS.join(",\n")} {
|
||||||
|
display: none !important;
|
||||||
|
visibility: hidden !important;
|
||||||
|
pointer-events: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html.sp-message-open,
|
||||||
|
body.sp-message-open,
|
||||||
|
html.didomi-popup-open,
|
||||||
|
body.didomi-popup-open,
|
||||||
|
html.qc-cmp-ui-showing,
|
||||||
|
body.qc-cmp-ui-showing,
|
||||||
|
html.iubenda-cs-visible,
|
||||||
|
body.iubenda-cs-visible {
|
||||||
|
overflow: auto !important;
|
||||||
|
position: static !important;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
export { DEFAULT_USER_AGENT, defaultArchivePath };
|
export { DEFAULT_USER_AGENT, defaultArchivePath };
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -1176,9 +1238,10 @@ async function setupRequestBlocking(page, sourceHostname) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function injectCosmeticFilters(page, hostname) {
|
async function injectCosmeticFilters(page, hostname) {
|
||||||
if (!privacyFiltersAvailable || filterRules.cosmeticRules.length === 0) return;
|
const lines = [COMMON_ANNOYANCE_CSS];
|
||||||
|
if (privacyFiltersAvailable && filterRules.cosmeticRules.length > 0) {
|
||||||
const lines = getCosmeticCssForHostname(filterRules, hostname);
|
lines.push(...getCosmeticCssForHostname(filterRules, hostname));
|
||||||
|
}
|
||||||
if (lines.length > 0) {
|
if (lines.length > 0) {
|
||||||
try {
|
try {
|
||||||
await page.addStyleTag({ content: lines.join("\n") });
|
await page.addStyleTag({ content: lines.join("\n") });
|
||||||
@@ -1188,6 +1251,42 @@ async function injectCosmeticFilters(page, hostname) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function removeCommonAnnoyances(page) {
|
||||||
|
try {
|
||||||
|
await page.evaluate(({ selectors, rootClasses }) => {
|
||||||
|
for (const selector of selectors) {
|
||||||
|
try {
|
||||||
|
document.querySelectorAll(selector).forEach((element) => element.remove());
|
||||||
|
} catch {
|
||||||
|
// Ignore selectors unsupported by the current browser.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const root of [document.documentElement, document.body].filter(Boolean)) {
|
||||||
|
root.classList.remove(...rootClasses);
|
||||||
|
root.removeAttribute("data-previous-scroll-y");
|
||||||
|
|
||||||
|
const overflow = root.style.overflow || "";
|
||||||
|
const position = root.style.position || "";
|
||||||
|
if (/hidden|clip/i.test(overflow)) {
|
||||||
|
root.style.removeProperty("overflow");
|
||||||
|
}
|
||||||
|
if (/fixed/i.test(position)) {
|
||||||
|
root.style.removeProperty("position");
|
||||||
|
root.style.removeProperty("top");
|
||||||
|
root.style.removeProperty("left");
|
||||||
|
root.style.removeProperty("right");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
selectors: COMMON_ANNOYANCE_SELECTORS,
|
||||||
|
rootClasses: COMMON_ANNOYANCE_ROOT_CLASSES
|
||||||
|
});
|
||||||
|
} catch {
|
||||||
|
// Ignore cleanup failures; the archive is still useful.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const GM_MOCK = `
|
const GM_MOCK = `
|
||||||
if (typeof GM === "undefined") {
|
if (typeof GM === "undefined") {
|
||||||
window.GM = {
|
window.GM = {
|
||||||
@@ -1320,6 +1419,7 @@ export async function renderPage(sourceUrl, options = {}) {
|
|||||||
await page.waitForTimeout(userscriptDelay);
|
await page.waitForTimeout(userscriptDelay);
|
||||||
|
|
||||||
await waitForNetworkIdle(page);
|
await waitForNetworkIdle(page);
|
||||||
|
await removeCommonAnnoyances(page);
|
||||||
await snapshotLoadedResourceUrls(page);
|
await snapshotLoadedResourceUrls(page);
|
||||||
await snapshotRuntimeStyles(page);
|
await snapshotRuntimeStyles(page);
|
||||||
|
|
||||||
|
|||||||
@@ -78,6 +78,28 @@ test("applies cosmetic filters with domain exceptions and skips unsupported proc
|
|||||||
assert.match(getCosmeticCssForHostname(rules, "foo.com").join("\n"), /\.adguard/);
|
assert.match(getCosmeticCssForHostname(rules, "foo.com").join("\n"), /\.adguard/);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("renderPage removes common cookie consent overlays before snapshot", async () => {
|
||||||
|
const html = `<!doctype html>
|
||||||
|
<html class="js sp-message-open" style="overflow: hidden;">
|
||||||
|
<body class="didomi-popup-open" style="overflow: hidden;">
|
||||||
|
<main>Article text</main>
|
||||||
|
<div id="sp_message_container_123" role="dialog" aria-modal="true">
|
||||||
|
<iframe id="sp_message_iframe_123" title="SP Consent Message" srcdoc="<p>Cookies on FT Sites</p>"></iframe>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>`;
|
||||||
|
|
||||||
|
const rendered = await renderPage(`data:text/html,${encodeURIComponent(html)}`, {
|
||||||
|
userscriptDelay: 0
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.match(rendered, /Article text/);
|
||||||
|
assert.doesNotMatch(rendered, /sp_message_container_123/);
|
||||||
|
assert.doesNotMatch(rendered, /sp_message_iframe_123/);
|
||||||
|
assert.doesNotMatch(rendered, /<html[^>]*class="[^"]*sp-message-open/i);
|
||||||
|
assert.doesNotMatch(rendered, /<body[^>]*class="[^"]*didomi-popup-open/i);
|
||||||
|
});
|
||||||
|
|
||||||
test("renderPage serializes CSSOM-inserted style rules", async () => {
|
test("renderPage serializes CSSOM-inserted style rules", async () => {
|
||||||
const html = `<!doctype html>
|
const html = `<!doctype html>
|
||||||
<html>
|
<html>
|
||||||
|
|||||||
Reference in New Issue
Block a user