From 611881dba06c0a8cef2fdca805c736873e462fc8 Mon Sep 17 00:00:00 2001 From: Anton Lazarev Date: Thu, 20 Feb 2020 16:08:33 -0500 Subject: [PATCH] support merging regional and custom hostname cosmetic adblock resources --- browser/extensions/api/brave_shields_api.cc | 21 +++ .../ad_block_regional_service_manager.cc | 25 ++++ .../ad_block_regional_service_manager.h | 5 + .../browser/ad_block_service_helper.cc | 56 ++++++++ .../browser/ad_block_service_helper.h | 3 + .../browser/cosmetic_merge_unittest.cc | 132 ++++++++++++++++++ test/BUILD.gn | 1 + 7 files changed, 243 insertions(+) create mode 100644 components/brave_shields/browser/cosmetic_merge_unittest.cc diff --git a/browser/extensions/api/brave_shields_api.cc b/browser/extensions/api/brave_shields_api.cc index 4d2b6cfcf78a..fd76dd679f8d 100644 --- a/browser/extensions/api/brave_shields_api.cc +++ b/browser/extensions/api/brave_shields_api.cc @@ -15,7 +15,11 @@ #include "brave/browser/webcompat_reporter/webcompat_reporter_dialog.h" #include "brave/common/extensions/api/brave_shields.h" #include "brave/common/extensions/extension_constants.h" +#include "brave/components/brave_shields/browser/ad_block_base_service.h" +#include "brave/components/brave_shields/browser/ad_block_custom_filters_service.h" +#include "brave/components/brave_shields/browser/ad_block_regional_service_manager.h" #include "brave/components/brave_shields/browser/ad_block_service.h" +#include "brave/components/brave_shields/browser/ad_block_service_helper.h" #include "brave/components/brave_shields/browser/brave_shields_p3a.h" #include "brave/components/brave_shields/browser/brave_shields_util.h" #include "brave/components/brave_shields/browser/brave_shields_web_contents_observer.h" @@ -59,6 +63,23 @@ BraveShieldsHostnameCosmeticResourcesFunction::Run() { return RespondNow(Error( "Hostname-specific cosmetic resources could not be returned")); } + + base::Optional regional_resources = g_brave_browser_process-> + ad_block_regional_service_manager()-> + HostnameCosmeticResources(params->hostname); + + if (regional_resources && regional_resources->is_dict()) { + ::brave_shields::MergeResourcesInto(&*resources, &*regional_resources); + } + + base::Optional custom_resources = g_brave_browser_process-> + ad_block_custom_filters_service()-> + HostnameCosmeticResources(params->hostname); + + if (custom_resources && custom_resources->is_dict()) { + ::brave_shields::MergeResourcesInto(&*resources, &*custom_resources); + } + auto result_list = std::make_unique(); result_list->GetList().push_back(std::move(*resources)); diff --git a/components/brave_shields/browser/ad_block_regional_service_manager.cc b/components/brave_shields/browser/ad_block_regional_service_manager.cc index 689df46b54b3..31d1be6051c7 100644 --- a/components/brave_shields/browser/ad_block_regional_service_manager.cc +++ b/components/brave_shields/browser/ad_block_regional_service_manager.cc @@ -191,6 +191,31 @@ void AdBlockRegionalServiceManager::EnableFilterList(const std::string& uuid, base::Unretained(this), uuid, enabled)); } +base::Optional +AdBlockRegionalServiceManager::HostnameCosmeticResources( + const std::string& hostname) { + auto it = this->regional_services_.begin(); + if (it == this->regional_services_.end()) { + return base::Optional(); + } + base::Optional first_value = + it->second->HostnameCosmeticResources(hostname); + + for ( ; it != this->regional_services_.end(); it++) { + base::Optional next_value = + it->second->HostnameCosmeticResources(hostname); + if (first_value) { + if (next_value) { + MergeResourcesInto(&*first_value, &*next_value); + } + } else { + first_value = std::move(next_value); + } + } + + return first_value; +} + // static bool AdBlockRegionalServiceManager::IsSupportedLocale( const std::string& locale) { diff --git a/components/brave_shields/browser/ad_block_regional_service_manager.h b/components/brave_shields/browser/ad_block_regional_service_manager.h index c60f2e22a17f..0fd22650bf5c 100644 --- a/components/brave_shields/browser/ad_block_regional_service_manager.h +++ b/components/brave_shields/browser/ad_block_regional_service_manager.h @@ -12,7 +12,9 @@ #include "base/macros.h" #include "base/memory/scoped_refptr.h" +#include "base/optional.h" #include "base/synchronization/lock.h" +#include "base/values.h" #include "brave/components/brave_component_updater/browser/brave_component.h" #include "content/public/common/resource_type.h" #include "url/gurl.h" @@ -52,6 +54,9 @@ class AdBlockRegionalServiceManager { void AddResources(const std::string& resources); void EnableFilterList(const std::string& uuid, bool enabled); + base::Optional HostnameCosmeticResources( + const std::string& hostname); + private: friend class ::AdBlockServiceTest; bool Init(); diff --git a/components/brave_shields/browser/ad_block_service_helper.cc b/components/brave_shields/browser/ad_block_service_helper.cc index 6a89e9f46f52..f51cece837a7 100644 --- a/components/brave_shields/browser/ad_block_service_helper.cc +++ b/components/brave_shields/browser/ad_block_service_helper.cc @@ -6,8 +6,10 @@ #include "brave/components/brave_shields/browser/ad_block_service_helper.h" #include +#include #include "base/strings/string_util.h" +#include "base/values.h" using adblock::FilterList; @@ -44,4 +46,58 @@ std::vector::const_iterator FindAdBlockFilterListByLocale( }); } +// Merges the contents of the second HostnameCosmeticResources Value into the +// first one provided. +void MergeResourcesInto(base::Value* into, base::Value* from) { + base::Value* resources_hide_selectors = into->FindKey("hide_selectors"); + base::Value* from_resources_hide_selectors = + from->FindKey("hide_selectors"); + if (resources_hide_selectors && from_resources_hide_selectors) { + for (auto i = from_resources_hide_selectors->GetList().begin(); + i < from_resources_hide_selectors->GetList().end(); + i++) { + resources_hide_selectors->Append(std::move(*i)); + } + } + + base::Value* resources_style_selectors = into->FindKey("style_selectors"); + base::Value* from_resources_style_selectors = + from->FindKey("style_selectors"); + if (resources_style_selectors && from_resources_style_selectors) { + for (auto i : from_resources_style_selectors->DictItems()) { + base::Value* resources_entry = + resources_style_selectors->FindKey(i.first); + if (resources_entry) { + for (auto j = i.second.GetList().begin(); + j < i.second.GetList().end(); + j++) { + resources_entry->Append(std::move(*j)); + } + } else { + resources_style_selectors->SetPath(i.first, std::move(i.second)); + } + } + } + + base::Value* resources_exceptions = into->FindKey("exceptions"); + base::Value* from_resources_exceptions = from->FindKey("exceptions"); + if (resources_exceptions && from_resources_exceptions) { + for (auto i = from_resources_exceptions->GetList().begin(); + i < from_resources_exceptions->GetList().end(); + i++) { + resources_exceptions->Append(std::move(*i)); + } + } + + base::Value* resources_injected_script = into->FindKey("injected_script"); + base::Value* from_resources_injected_script = + from->FindKey("injected_script"); + if (resources_injected_script && from_resources_injected_script) { + *resources_injected_script = base::Value( + resources_injected_script->GetString() + + '\n' + + from_resources_injected_script->GetString()); + } +} + } // namespace brave_shields diff --git a/components/brave_shields/browser/ad_block_service_helper.h b/components/brave_shields/browser/ad_block_service_helper.h index 906bdcdbbb86..e7471d547528 100644 --- a/components/brave_shields/browser/ad_block_service_helper.h +++ b/components/brave_shields/browser/ad_block_service_helper.h @@ -9,6 +9,7 @@ #include #include +#include "base/values.h" #include "brave/vendor/adblock_rust_ffi/src/wrapper.hpp" namespace brave_shields { @@ -20,6 +21,8 @@ std::vector::const_iterator FindAdBlockFilterListByLocale( const std::vector& region_lists, const std::string& locale); +void MergeResourcesInto(base::Value* into, base::Value* from); + } // namespace brave_shields #endif // BRAVE_COMPONENTS_BRAVE_SHIELDS_BROWSER_AD_BLOCK_SERVICE_HELPER_H_ diff --git a/components/brave_shields/browser/cosmetic_merge_unittest.cc b/components/brave_shields/browser/cosmetic_merge_unittest.cc new file mode 100644 index 000000000000..82dcec44b294 --- /dev/null +++ b/components/brave_shields/browser/cosmetic_merge_unittest.cc @@ -0,0 +1,132 @@ +/* Copyright (c) 2020 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * 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/. */ + +#include "base/json/json_reader.h" +#include "brave/components/brave_shields/browser/ad_block_service_helper.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace brave_shields { + +using ::testing::_; + +class CosmeticResourceMergeTest : public testing::Test { + public: + CosmeticResourceMergeTest() {} + ~CosmeticResourceMergeTest() override {} + + void CompareMergeFromStrings( + const std::string& a, + const std::string& b, + const std::string& expected) { + base::Optional a_val = base::JSONReader::Read(a); + ASSERT_TRUE(a_val); + + base::Optional b_val = base::JSONReader::Read(b); + ASSERT_TRUE(b_val); + + const base::Optional expected_val = + base::JSONReader::Read(expected); + ASSERT_TRUE(expected_val); + + MergeResourcesInto(&*a_val, &*b_val); + + ASSERT_EQ(*a_val, *expected_val); + } + + protected: + void SetUp() override {} + + void TearDown() override {} +}; + +const char EMPTY_RESOURCES[] = "{" + "\"hide_selectors\": [], " + "\"style_selectors\": {}, " + "\"exceptions\": [], " + "\"injected_script\": \"\"" +"}"; + +const char NONEMPTY_RESOURCES[] = "{" + "\"hide_selectors\": [\"a\", \"b\"], " + "\"style_selectors\": {\"c\": \"color: #fff\", \"d\": \"color: #000\"}, " + "\"exceptions\": [\"e\", \"f\"], " + "\"injected_script\": \"console.log('g')\"" +"}"; + +TEST_F(CosmeticResourceMergeTest, MergeTwoEmptyResources) { + const std::string a = EMPTY_RESOURCES; + const std::string b = EMPTY_RESOURCES; + + // Same as EMPTY_RESOURCES, but with an additional newline in the + // injected_script + const std::string expected = "{" + "\"hide_selectors\": [], " + "\"style_selectors\": {}, " + "\"exceptions\": [], " + "\"injected_script\": \"\n\"" + "}"; + + CompareMergeFromStrings(a, b, expected); +} + +TEST_F(CosmeticResourceMergeTest, MergeEmptyIntoNonEmpty) { + const std::string a = NONEMPTY_RESOURCES; + const std::string b = EMPTY_RESOURCES; + + // Same as a, but with an additional newline at the end of the + // injected_script + const std::string expected = "{" + "\"hide_selectors\": [\"a\", \"b\"], " + "\"style_selectors\": {\"c\": \"color: #fff\", \"d\": \"color: #000\"}, " + "\"exceptions\": [\"e\", \"f\"], " + "\"injected_script\": \"console.log('g')\n\"" + "}"; + + CompareMergeFromStrings(a, b, expected); +} + +TEST_F(CosmeticResourceMergeTest, MergeNonEmptyIntoEmpty) { + const std::string a = EMPTY_RESOURCES; + const std::string b = NONEMPTY_RESOURCES; + + // Same as b, but with an additional newline at the beginning of the + // injected_script + const std::string expected = "{" + "\"hide_selectors\": [\"a\", \"b\"]," + "\"style_selectors\": {\"c\": \"color: #fff\", \"d\": \"color: #000\"}, " + "\"exceptions\": [\"e\", \"f\"], " + "\"injected_script\": \"\nconsole.log('g')\"" + "}"; + + CompareMergeFromStrings(a, b, expected); +} + +TEST_F(CosmeticResourceMergeTest, MergeNonEmptyIntoNonEmpty) { + const std::string a = NONEMPTY_RESOURCES; + const std::string b = "{" + "\"hide_selectors\": [\"h\", \"i\"], " + "\"style_selectors\": {\"j\": \"color: #eee\", \"k\": \"color: #111\"}, " + "\"exceptions\": [\"l\", \"m\"], " + "\"injected_script\": \"console.log('n')\"" + "}"; + + const std::string expected = "{" + "\"hide_selectors\": [\"a\", \"b\", \"h\", \"i\"], " + "\"style_selectors\": {" + "\"c\": \"color: #fff\", " + "\"d\": \"color: #000\", " + "\"j\": \"color: #eee\", " + "\"k\": \"color: #111\"" + "}, " + "\"exceptions\": [\"e\", \"f\", \"l\", \"m\"], " + "\"injected_script\": \"console.log('g')\nconsole.log('n')\"" + "}"; + + CompareMergeFromStrings(a, b, expected); +} + + +} // namespace brave_shields diff --git a/test/BUILD.gn b/test/BUILD.gn index 75bf06fdc0a8..eb20e38eeb11 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -95,6 +95,7 @@ test("brave_unit_tests") { "//brave/components/assist_ranker/ranker_model_loader_impl_unittest.cc", "//brave/components/brave_shields/browser/ad_block_regional_service_unittest.cc", "//brave/components/brave_shields/browser/adblock_stub_response_unittest.cc", + "//brave/components/brave_shields/browser/cosmetic_merge_unittest.cc", "//brave/components/brave_shields/browser/https_everywhere_recently_used_cache_unittest.cpp", "//brave/components/ntp_sponsored_images/browser/view_counter_model_unittest.cc", "//brave/components/ntp_sponsored_images/browser/view_counter_service_unittest.cc",