From a9e921304c20596213f8f45eed0dcc776ed76f5a Mon Sep 17 00:00:00 2001 From: Anton Lazarev Date: Fri, 17 Jan 2020 16:06:40 -0500 Subject: [PATCH] update tests to reflect new 1p rules --- .../actions/shieldsPanelActions.ts | 5 +- .../background/api/cosmeticFilterAPI.ts | 33 +++--- .../reducers/shieldsPanelReducer.ts | 3 +- .../brave_extension/content_cosmetic.ts | 110 ++++++++++-------- .../browser/ad_block_service_browsertest.cc | 22 ++++ package-lock.json | 48 +++++--- package.json | 1 - test/data/cosmetic_filtering.html | 14 ++- 8 files changed, 140 insertions(+), 96 deletions(-) diff --git a/components/brave_extension/extension/brave_extension/actions/shieldsPanelActions.ts b/components/brave_extension/extension/brave_extension/actions/shieldsPanelActions.ts index d505b48caec9..2d590928b1b2 100644 --- a/components/brave_extension/extension/brave_extension/actions/shieldsPanelActions.ts +++ b/components/brave_extension/extension/brave_extension/actions/shieldsPanelActions.ts @@ -147,12 +147,11 @@ export const generateClassIdStylesheet = (tabId: number, classes: string[], ids: } } -export const cosmeticFilterRuleExceptions = (tabId: number, exceptions: string[], randomizedClassName: string) => { +export const cosmeticFilterRuleExceptions = (tabId: number, exceptions: string[]) => { return { type: types.COSMETIC_FILTER_RULE_EXCEPTIONS, tabId, - exceptions, - randomizedClassName + exceptions } } diff --git a/components/brave_extension/extension/brave_extension/background/api/cosmeticFilterAPI.ts b/components/brave_extension/extension/brave_extension/background/api/cosmeticFilterAPI.ts index 4e393a64c5f1..617673edf833 100644 --- a/components/brave_extension/extension/brave_extension/background/api/cosmeticFilterAPI.ts +++ b/components/brave_extension/extension/brave_extension/background/api/cosmeticFilterAPI.ts @@ -2,16 +2,13 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ -const uuidv4 = require('uuid/v4') - import shieldsPanelActions from '../actions/shieldsPanelActions' -const informTabOfCosmeticRulesToConsider = (tabId: number, hideRules: string[], customStyleRules: any) => { - if (hideRules.length !== 0 || (customStyleRules && customStyleRules !== {})) { +const informTabOfCosmeticRulesToConsider = (tabId: number, hideRules: string[]) => { + if (hideRules.length !== 0) { const message = { type: 'cosmeticFilterConsiderNewRules', - hideRules, - customStyleRules + hideRules } const options = { frameId: 0 @@ -23,7 +20,7 @@ const informTabOfCosmeticRulesToConsider = (tabId: number, hideRules: string[], export const injectClassIdStylesheet = (tabId: number, classes: string[], ids: string[], exceptions: string[]) => { chrome.braveShields.hiddenClassIdSelectors(classes, ids, exceptions, (jsonSelectors) => { const hideSelectors = JSON.parse(jsonSelectors) - informTabOfCosmeticRulesToConsider(tabId, hideSelectors, null) + informTabOfCosmeticRulesToConsider(tabId, hideSelectors) }) } @@ -34,7 +31,17 @@ export const applyAdblockCosmeticFilters = (tabId: number, hostname: string) => return } - informTabOfCosmeticRulesToConsider(tabId, resources.hide_selectors, resources.style_selectors) + informTabOfCosmeticRulesToConsider(tabId, resources.hide_selectors) + + let styledStylesheet = '' + for (const selector in resources.style_selectors) { + styledStylesheet += selector + '{' + resources.style_selectors[selector].join(';') + ';}\n' + } + chrome.tabs.insertCSS(tabId, { + code: styledStylesheet, + cssOrigin: 'user', + runAt: 'document_start' + }) if (resources.injected_script) { chrome.tabs.executeScript(tabId, { @@ -43,15 +50,7 @@ export const applyAdblockCosmeticFilters = (tabId: number, hostname: string) => }) } - const randomizedClassName = 'b' + uuidv4().split('-').slice(0, 2).join('') - - chrome.tabs.insertCSS(tabId, { - code: `.${randomizedClassName} {display: none !important;}`, - cssOrigin: 'user', - runAt: 'document_start' - }) - - shieldsPanelActions.cosmeticFilterRuleExceptions(tabId, resources.exceptions, randomizedClassName) + shieldsPanelActions.cosmeticFilterRuleExceptions(tabId, resources.exceptions) }) } diff --git a/components/brave_extension/extension/brave_extension/background/reducers/shieldsPanelReducer.ts b/components/brave_extension/extension/brave_extension/background/reducers/shieldsPanelReducer.ts index f87e3dd0c1b7..cc078dc0c18f 100644 --- a/components/brave_extension/extension/brave_extension/background/reducers/shieldsPanelReducer.ts +++ b/components/brave_extension/extension/brave_extension/background/reducers/shieldsPanelReducer.ts @@ -368,8 +368,7 @@ export default function shieldsPanelReducer ( } state = shieldsPanelState.saveCosmeticFilterRuleExceptions(state, action.tabId, action.exceptions) chrome.tabs.sendMessage(action.tabId, { - type: 'cosmeticFilterGenericExceptions', - randomizedClassName: action.randomizedClassName + type: 'cosmeticFilteringBackgroundReady' }) break } diff --git a/components/brave_extension/extension/brave_extension/content_cosmetic.ts b/components/brave_extension/extension/brave_extension/content_cosmetic.ts index 4f99ae28b032..230be6655d0a 100644 --- a/components/brave_extension/extension/brave_extension/content_cosmetic.ts +++ b/components/brave_extension/extension/brave_extension/content_cosmetic.ts @@ -16,56 +16,78 @@ const queriedClasses = new Set() let notYetQueriedClasses: string[] = [] let notYetQueriedIds: string[] = [] -let randomizedClassName: string | undefined = undefined +let backgroundReady: boolean = false + +const fetchNewClassIdRules = function () { + // Only let the backend know that we've found new classes and id attributes + // if the back end has told us its ready to go and we have at least one new + // class or id to query for. + if (backgroundReady) { + if (notYetQueriedClasses.length !== 0 || notYetQueriedIds.length !== 0) { + chrome.runtime.sendMessage({ + type: 'hiddenClassIdSelectors', + classes: notYetQueriedClasses, + ids: notYetQueriedIds + }) + notYetQueriedClasses = [] + notYetQueriedIds = [] + } + } else { + setTimeout(fetchNewClassIdRules, 100) + } +} const handleMutations = function (mutations: any[]) { for (const aMutation of mutations) { - if (aMutation.type !== 'attributes') { - continue - } + if (aMutation.type === 'attribute') { + // Since we're filtering for attribute modifications, we can be certain + // that the targets are always HTMLElements, and never TextNode. + const changedElm = aMutation.target + switch (aMutation.attributeName) { + case 'class': + for (const aClassName of changedElm.classList.values()) { + if (queriedClasses.has(aClassName) === false) { + notYetQueriedClasses.push(aClassName) + queriedClasses.add(aClassName) + } + } + break - // Since we're filtering for attribute modifications, we can be certain - // that the targets are always HTMLElements, and never TextNode. - const changedElm = aMutation.target - switch (aMutation.attributeName) { - case 'class': - for (const aClassName of changedElm.classList.values()) { - if (queriedClasses.has(aClassName) === false) { - notYetQueriedClasses.push(aClassName) - queriedClasses.add(aClassName) + case 'id': + const mutatedId = changedElm.id + if (queriedIds.has(mutatedId) === false) { + notYetQueriedIds.push(mutatedId) + queriedIds.add(mutatedId) } + break + } + } else if (aMutation.addedNodes.length > 0) { + for (const element of aMutation.addedNodes) { + const id = element.id + if (id && !queriedIds.has(id)) { + notYetQueriedIds.push(id) + queriedIds.add(id) } - break - - case 'id': - const mutatedId = changedElm.id - if (queriedIds.has(mutatedId) === false) { - notYetQueriedIds.push(mutatedId) - queriedIds.add(mutatedId) + const classList: any = element.classList + if (classList) { + for (const className of classList.values()) { + if (className && !queriedClasses.has(className)) { + notYetQueriedClasses.push(className) + queriedClasses.add(className) + } + } } - break + } } } - // Only let the backend know that we've found new classes and id attributes - // if (1) the back end has told us its ready to go - // (e.g. randomizedClassName has been set) and we have at least one - // new class or id to query for. - if (randomizedClassName !== undefined && - (notYetQueriedClasses.length !== 0 || notYetQueriedIds.length !== 0)) { - chrome.runtime.sendMessage({ - type: 'hiddenClassIdSelectors', - classes: notYetQueriedClasses, - ids: notYetQueriedIds - }) - notYetQueriedClasses = [] - notYetQueriedIds = [] - } + fetchNewClassIdRules() } const cosmeticObserver = new MutationObserver(handleMutations) let observerConfig = { subtree: true, + childList: true, attributeFilter: ['id', 'class'] } cosmeticObserver.observe(document.documentElement, observerConfig) @@ -210,18 +232,6 @@ const isSubTreeFirstParty = (elm: Element, possibleQueryResult?: IsFirstPartyQue ) } -const hideSubtree = (elm: HTMLElement) => { - if (elm.classList) { - if (randomizedClassName) { - elm.classList.add(randomizedClassName) - } else { - console.error('Random class name was not initialized yet') - } - } else if (elm.parentNode) { - (elm.parentNode as HTMLElement).removeChild(elm) - } -} - const hideSelectors = (selectors: string[]) => { if (selectors.length === 0) { return @@ -304,9 +314,8 @@ const pumpCosmeticFilterQueues = () => { chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => { const action = typeof msg === 'string' ? msg : msg.type switch (action) { - case 'cosmeticFilterGenericExceptions': { - randomizedClassName = msg.randomizedClassName - sendResponse(null) + case 'cosmeticFilteringBackgroundReady': { + backgroundReady = true break } @@ -320,6 +329,7 @@ chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => { firstRunQueue.add(aHideRule) } pumpCosmeticFilterQueues() + break } } }) diff --git a/components/brave_shields/browser/ad_block_service_browsertest.cc b/components/brave_shields/browser/ad_block_service_browsertest.cc index d794ad7f28c6..0fef0d64591d 100644 --- a/components/brave_shields/browser/ad_block_service_browsertest.cc +++ b/components/brave_shields/browser/ad_block_service_browsertest.cc @@ -872,6 +872,28 @@ IN_PROC_BROWSER_TEST_F(CosmeticFilteringEnabledTest, CosmeticFilteringSimple) { EXPECT_TRUE(as_expected); } +// Test cosmetic filtering ignores content determined to be 1st party +IN_PROC_BROWSER_TEST_F(CosmeticFilteringEnabledTest, + CosmeticFilteringProtect1p) { + UpdateAdBlockInstanceWithRules("b.com##.fpsponsored\n"); + + WaitForBraveExtensionShieldsDataReady(); + + GURL tab_url = embedded_test_server()->GetURL("b.com", + "/cosmetic_filtering.html"); + ui_test_utils::NavigateToURL(browser(), tab_url); + + content::WebContents* contents = + browser()->tab_strip_model()->GetActiveWebContents(); + + bool as_expected = false; + ASSERT_TRUE(ExecuteScriptAndExtractBool( + contents, + "checkSelector('.fpsponsored', 'display', 'block')", + &as_expected)); + EXPECT_TRUE(as_expected); +} + // Test cosmetic filtering on elements added dynamically IN_PROC_BROWSER_TEST_F(CosmeticFilteringEnabledTest, CosmeticFilteringDynamic) { UpdateAdBlockInstanceWithRules("##.blockme"); diff --git a/package-lock.json b/package-lock.json index 20691e921209..ad5a96ac82fc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1929,9 +1929,9 @@ "integrity": "sha512-hRJD2ahnnpLgsj6KWMYSrmXkM3rm2Dl1qkx6IOFD5FnuNPXJIG5L0dhgKXCYTRMGzU4n0wImQ/xfmRc4POUFlg==" }, "@types/yargs": { - "version": "13.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.4.tgz", - "integrity": "sha512-Ke1WmBbIkVM8bpvsNEcGgQM70XcEh/nbpxQhW7FhrsbCsXSY9BmLB1+LHtD7r9zrsOcFlLiF+a/UeJsdfw3C5A==", + "version": "13.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.5.tgz", + "integrity": "sha512-CF/+sxTO7FOwbIRL4wMv0ZYLCRfMid2HQpzDRyViH7kSpfoAFiMdGqKIxb1PxWfjtQXQhnQuD33lvRHNwr809Q==", "requires": { "@types/yargs-parser": "*" } @@ -4811,9 +4811,9 @@ "dev": true }, "@types/yargs-parser": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-13.1.0.tgz", - "integrity": "sha512-gCubfBUZ6KxzoibJ+SCUc/57Ms1jz5NjHe4+dI2krNmU5zCPAphyLJYyTOg06ueIyfj+SaCUqmzun7ImlxDcKg==" + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-15.0.0.tgz", + "integrity": "sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==" }, "@webassemblyjs/ast": { "version": "1.8.3", @@ -10686,6 +10686,7 @@ "version": "4.5.3", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.3.tgz", "integrity": "sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==", + "dev": true, "requires": { "neo-async": "^2.6.0", "optimist": "^0.6.1", @@ -10696,7 +10697,8 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true } } }, @@ -10912,6 +10914,11 @@ "integrity": "sha1-DfKTUfByEWNRXfueVUPl9u7VFi8=", "dev": true }, + "html-escaper": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.0.tgz", + "integrity": "sha512-a4u9BeERWGu/S8JiWEAQcdrg9v4QArtP9keViQjGMdff20fBdd8waotXaNmODqBe6uZ3Nafi7K/ho4gCQHV3Ig==" + }, "html-minifier": { "version": "3.5.21", "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.21.tgz", @@ -13389,7 +13396,8 @@ "neo-async": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.0.tgz", - "integrity": "sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA==" + "integrity": "sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA==", + "dev": true }, "netmask": { "version": "1.0.6", @@ -13833,6 +13841,7 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true, "requires": { "minimist": "~0.0.1", "wordwrap": "~0.0.2" @@ -13841,7 +13850,8 @@ "minimist": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", - "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=" + "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", + "dev": true } } }, @@ -14179,9 +14189,9 @@ "integrity": "sha512-hRJD2ahnnpLgsj6KWMYSrmXkM3rm2Dl1qkx6IOFD5FnuNPXJIG5L0dhgKXCYTRMGzU4n0wImQ/xfmRc4POUFlg==" }, "@types/yargs": { - "version": "13.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.4.tgz", - "integrity": "sha512-Ke1WmBbIkVM8bpvsNEcGgQM70XcEh/nbpxQhW7FhrsbCsXSY9BmLB1+LHtD7r9zrsOcFlLiF+a/UeJsdfw3C5A==", + "version": "13.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.5.tgz", + "integrity": "sha512-CF/+sxTO7FOwbIRL4wMv0ZYLCRfMid2HQpzDRyViH7kSpfoAFiMdGqKIxb1PxWfjtQXQhnQuD33lvRHNwr809Q==", "requires": { "@types/yargs-parser": "*" } @@ -14268,11 +14278,11 @@ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" }, "istanbul-reports": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.6.tgz", - "integrity": "sha512-SKi4rnMyLBKe0Jy2uUdx28h8oG7ph2PPuQPvIAh31d+Ci+lSiEu4C+h3oBPuJ9+mPKhOyW0M8gY4U5NM1WLeXA==", + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.7.tgz", + "integrity": "sha512-uu1F/L1o5Y6LzPVSVZXNOoD/KXpJue9aeLRd0sM9uMXfZvzomB0WxVamWb5ue8kA2vVWEmW7EG+A5n3f1kqHKg==", "requires": { - "handlebars": "^4.1.2" + "html-escaper": "^2.0.0" } }, "jest": { @@ -18560,6 +18570,7 @@ "version": "3.6.9", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.9.tgz", "integrity": "sha512-pcnnhaoG6RtrvHJ1dFncAe8Od6Nuy30oaJ82ts6//sGSXOP5UjBMEthiProjXmMNHOfd93sqlkztifFMcb+4yw==", + "dev": true, "optional": true, "requires": { "commander": "~2.20.3", @@ -18570,12 +18581,14 @@ "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, "optional": true }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, "optional": true } } @@ -19449,7 +19462,8 @@ "wordwrap": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true }, "worker-farm": { "version": "1.7.0", diff --git a/package.json b/package.json index 3273f3d940c7..7a6a16f8d9d1 100644 --- a/package.json +++ b/package.json @@ -345,7 +345,6 @@ "redux-thunk": "^2.3.0", "throttleit": "^1.0.0", "unique-selector": "^0.4.1", - "uuid": "^3.3.2", "webext-redux": "^2.1.4", "webtorrent": "^0.107.16" } diff --git a/test/data/cosmetic_filtering.html b/test/data/cosmetic_filtering.html index e1c8fb940536..ea7aa32bbb4a 100644 --- a/test/data/cosmetic_filtering.html +++ b/test/data/cosmetic_filtering.html @@ -5,7 +5,8 @@ function addElementsDynamically() { let root = document.documentElement; for (let i = 0; i < 10; i++) { - const e = document.createElement('div') + const e = document.createElement('img') + e.src = 'https://example.com/logo.png' e.className = 'blockme' root.appendChild(e); } @@ -25,17 +26,18 @@ return style[property] === expected; }) window.domAutomationController.send(result) - }, 1500) + }, 3000) } -
+
+
-
+
-
-
+
+