Commit ce7f30a4 authored by Balazs Engedy's avatar Balazs Engedy Committed by Commit Bot

Add Crowd Deny component.

This CL implements CrowdDenyComponentInstaller, defines the Protobuf
definition of the payload, and adds some plumbing to read the payload
from the disk and store it in the CrowdDenyPreloadData singleton.

Bug: 1028642
Change-Id: Ie0f296784d83b398f4e9732ed85072b9e71f5772
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1937174Reviewed-by: default avatarVasilii Sukhanov <vasilii@chromium.org>
Reviewed-by: default avatarAndy Paicu <andypaicu@chromium.org>
Reviewed-by: default avatarJoshua Pawlicki <waffles@chromium.org>
Commit-Queue: Balazs Engedy <engedy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#720250}
parent be7551a8
...@@ -312,6 +312,8 @@ jumbo_static_library("browser") { ...@@ -312,6 +312,8 @@ jumbo_static_library("browser") {
"component_updater/component_updater_utils.h", "component_updater/component_updater_utils.h",
"component_updater/crl_set_component_installer.cc", "component_updater/crl_set_component_installer.cc",
"component_updater/crl_set_component_installer.h", "component_updater/crl_set_component_installer.h",
"component_updater/crowd_deny_component_installer.cc",
"component_updater/crowd_deny_component_installer.h",
"component_updater/file_type_policies_component_installer.cc", "component_updater/file_type_policies_component_installer.cc",
"component_updater/file_type_policies_component_installer.h", "component_updater/file_type_policies_component_installer.h",
"component_updater/games_component_installer.cc", "component_updater/games_component_installer.cc",
...@@ -1170,6 +1172,8 @@ jumbo_static_library("browser") { ...@@ -1170,6 +1172,8 @@ jumbo_static_library("browser") {
"permissions/adaptive_notification_permission_ui_selector.h", "permissions/adaptive_notification_permission_ui_selector.h",
"permissions/chooser_context_base.cc", "permissions/chooser_context_base.cc",
"permissions/chooser_context_base.h", "permissions/chooser_context_base.h",
"permissions/crowd_deny_preload_data.cc",
"permissions/crowd_deny_preload_data.h",
"permissions/crowd_deny_safe_browsing_request.cc", "permissions/crowd_deny_safe_browsing_request.cc",
"permissions/crowd_deny_safe_browsing_request.h", "permissions/crowd_deny_safe_browsing_request.h",
"permissions/permission_context_base.cc", "permissions/permission_context_base.cc",
...@@ -1941,6 +1945,7 @@ jumbo_static_library("browser") { ...@@ -1941,6 +1945,7 @@ jumbo_static_library("browser") {
":buildflags", ":buildflags",
":expired_flags_list", ":expired_flags_list",
":ntp_background_proto", ":ntp_background_proto",
":permissions_proto",
":resource_prefetch_predictor_proto", ":resource_prefetch_predictor_proto",
"//base:i18n", "//base:i18n",
"//base/allocator:buildflags", "//base/allocator:buildflags",
...@@ -5336,6 +5341,12 @@ proto_library("resource_prefetch_predictor_proto") { ...@@ -5336,6 +5341,12 @@ proto_library("resource_prefetch_predictor_proto") {
] ]
} }
proto_library("permissions_proto") {
sources = [
"permissions/crowd_deny.proto",
]
}
grit("resources") { grit("resources") {
source = "browser_resources.grd" source = "browser_resources.grd"
......
...@@ -57,6 +57,7 @@ ...@@ -57,6 +57,7 @@
#include "chrome/browser/chrome_browser_field_trials.h" #include "chrome/browser/chrome_browser_field_trials.h"
#include "chrome/browser/chrome_browser_main_extra_parts.h" #include "chrome/browser/chrome_browser_main_extra_parts.h"
#include "chrome/browser/component_updater/crl_set_component_installer.h" #include "chrome/browser/component_updater/crl_set_component_installer.h"
#include "chrome/browser/component_updater/crowd_deny_component_installer.h"
#include "chrome/browser/component_updater/file_type_policies_component_installer.h" #include "chrome/browser/component_updater/file_type_policies_component_installer.h"
#include "chrome/browser/component_updater/games_component_installer.h" #include "chrome/browser/component_updater/games_component_installer.h"
#include "chrome/browser/component_updater/mei_preload_component_installer.h" #include "chrome/browser/component_updater/mei_preload_component_installer.h"
...@@ -553,6 +554,7 @@ void RegisterComponentsForUpdate(bool is_off_the_record_profile, ...@@ -553,6 +554,7 @@ void RegisterComponentsForUpdate(bool is_off_the_record_profile,
#endif #endif
RegisterSafetyTipsComponent(cus, path); RegisterSafetyTipsComponent(cus, path);
RegisterCrowdDenyComponent(cus, path);
#if BUILDFLAG(GOOGLE_CHROME_BRANDING) && defined(OS_ANDROID) #if BUILDFLAG(GOOGLE_CHROME_BRANDING) && defined(OS_ANDROID)
component_updater::RegisterGamesComponent(cus, profile_prefs); component_updater::RegisterGamesComponent(cus, profile_prefs);
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/component_updater/crowd_deny_component_installer.h"
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/callback.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/values.h"
#include "chrome/browser/permissions/crowd_deny_preload_data.h"
namespace {
// The SHA-256 hash of the public key (in X.509 format, DER-encoded) used to
// sign the extension. The extension id is: ggkkehgbnfjpeggfpleeakpidbkibbmn.
constexpr uint8_t kCrowdDenyPublicKeySHA256[32] = {
0x66, 0xaa, 0x47, 0x61, 0xd5, 0x9f, 0x46, 0x65, 0xfb, 0x44, 0x0a,
0xf8, 0x31, 0xa8, 0x11, 0xcd, 0x5e, 0xea, 0x32, 0xe0, 0x29, 0x8b,
0x0c, 0x3a, 0xb4, 0xc9, 0x5e, 0x9c, 0xa4, 0x2a, 0x6d, 0x90};
constexpr char kCrowdDenyHumanReadableName[] = "Crowd Deny";
constexpr char kCrowdDenyManifestPreloadDataFormatKey[] = "preload_data_format";
constexpr int kCrowdDenyManifestPreloadDataCurrentFormat = 1;
constexpr base::FilePath::CharType kCrowdDenyPreloadDataFilename[] =
FILE_PATH_LITERAL("Preload Data");
base::FilePath GetPreloadDataFilePath(const base::FilePath& install_dir) {
return install_dir.Append(kCrowdDenyPreloadDataFilename);
}
} // namespace
namespace component_updater {
bool CrowdDenyComponentInstallerPolicy::
SupportsGroupPolicyEnabledComponentUpdates() const {
return false;
}
bool CrowdDenyComponentInstallerPolicy::VerifyInstallation(
const base::DictionaryValue& manifest,
const base::FilePath& install_dir) const {
// Just check that the file is there, detailed verification of the contents is
// delegated to code in //chrome/browser/permissions.
return base::PathExists(GetPreloadDataFilePath(install_dir));
}
bool CrowdDenyComponentInstallerPolicy::RequiresNetworkEncryption() const {
return true;
}
update_client::CrxInstaller::Result
CrowdDenyComponentInstallerPolicy::OnCustomInstall(
const base::DictionaryValue& manifest,
const base::FilePath& install_dir) {
// Nothing custom here.
return update_client::CrxInstaller::Result(0);
}
void CrowdDenyComponentInstallerPolicy::OnCustomUninstall() {
// Nothing custom here.
}
void CrowdDenyComponentInstallerPolicy::ComponentReady(
const base::Version& version,
const base::FilePath& install_dir,
std::unique_ptr<base::DictionaryValue> manifest) {
DVLOG(1) << "Crowd Deny component ready, version " << version.GetString()
<< " in " << install_dir.value();
int format = 0;
if (!manifest->GetInteger(kCrowdDenyManifestPreloadDataFormatKey, &format) ||
format != kCrowdDenyManifestPreloadDataCurrentFormat) {
DVLOG(1) << "Crowd Deny component bailing out. Future data version: "
<< format;
return;
}
CrowdDenyPreloadData::GetInstance()->LoadFromDisk(
GetPreloadDataFilePath(install_dir));
}
base::FilePath CrowdDenyComponentInstallerPolicy::GetRelativeInstallDir()
const {
return base::FilePath(FILE_PATH_LITERAL("Crowd Deny"));
}
void CrowdDenyComponentInstallerPolicy::GetHash(
std::vector<uint8_t>* hash) const {
hash->assign(
kCrowdDenyPublicKeySHA256,
kCrowdDenyPublicKeySHA256 + base::size(kCrowdDenyPublicKeySHA256));
}
std::string CrowdDenyComponentInstallerPolicy::GetName() const {
return kCrowdDenyHumanReadableName;
}
std::vector<std::string> CrowdDenyComponentInstallerPolicy::GetMimeTypes()
const {
// Not a plugin.
return std::vector<std::string>();
}
update_client::InstallerAttributes
CrowdDenyComponentInstallerPolicy::GetInstallerAttributes() const {
// No special update rules.
return update_client::InstallerAttributes();
}
void RegisterCrowdDenyComponent(ComponentUpdateService* cus,
const base::FilePath& user_data_dir) {
auto installer = base::MakeRefCounted<ComponentInstaller>(
std::make_unique<CrowdDenyComponentInstallerPolicy>());
installer->Register(cus, base::OnceClosure());
}
} // namespace component_updater
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_COMPONENT_UPDATER_CROWD_DENY_COMPONENT_INSTALLER_H_
#define CHROME_BROWSER_COMPONENT_UPDATER_CROWD_DENY_COMPONENT_INSTALLER_H_
#include "base/macros.h"
#include "components/component_updater/component_installer.h"
namespace base {
class FilePath;
} // namespace base
namespace component_updater {
class ComponentUpdateService;
class CrowdDenyComponentInstallerPolicy : public ComponentInstallerPolicy {
public:
CrowdDenyComponentInstallerPolicy() {}
~CrowdDenyComponentInstallerPolicy() override {}
private:
static base::FilePath GetInstalledPath(const base::FilePath& base);
// ComponentInstallerPolicy:
bool SupportsGroupPolicyEnabledComponentUpdates() const override;
bool VerifyInstallation(const base::DictionaryValue& manifest,
const base::FilePath& install_dir) const override;
bool RequiresNetworkEncryption() const override;
update_client::CrxInstaller::Result OnCustomInstall(
const base::DictionaryValue& manifest,
const base::FilePath& install_dir) override;
void OnCustomUninstall() override;
void ComponentReady(const base::Version& version,
const base::FilePath& install_dir,
std::unique_ptr<base::DictionaryValue> manifest) override;
base::FilePath GetRelativeInstallDir() const override;
void GetHash(std::vector<uint8_t>* hash) const override;
std::string GetName() const override;
std::vector<std::string> GetMimeTypes() const override;
update_client::InstallerAttributes GetInstallerAttributes() const override;
DISALLOW_COPY_AND_ASSIGN(CrowdDenyComponentInstallerPolicy);
};
// Call once during startup to make the component update service aware of the
// Crowd Deny component.
void RegisterCrowdDenyComponent(ComponentUpdateService* cus,
const base::FilePath& user_data_dir);
} // namespace component_updater
#endif // CHROME_BROWSER_COMPONENT_UPDATER_CROWD_DENY_COMPONENT_INSTALLER_H_
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
syntax = "proto2";
option optimize_for = LITE_RUNTIME;
package chrome_browser_crowd_deny;
// Information, about a specific site, relevant for making permission decisions.
message SiteReputation {
// The domain of the site this records describes.
optional string domain = 1;
// The quality of the experience users have with notifications on a site.
enum NotificationUserExperienceQuality {
UNKNOWN = 0;
ACCEPTABLE = 1;
UNSOLICITED_PROMPTS = 2;
}
// The quality of the experience users have with notifications on this site.
optional NotificationUserExperienceQuality notification_ux_quality = 2;
}
// Information, about popular sites, relevant for making permission decisions.
//
// The preloaded list contains reputation data for popular sites, and is
// distributed to Chrome clients ahead of time through the component updater as
// part of the `crowd_deny_crx` component extension. The CRX package contains a
// single file with a single instance of this message in the binary wire format.
message PreloadData {
// Site reputation information for popular sites. Unsorted.
repeated SiteReputation site_reputations = 1;
}
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/permissions/crowd_deny_preload_data.h"
#include <utility>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/files/file_util.h"
#include "base/location.h"
#include "base/no_destructor.h"
#include "base/sequenced_task_runner.h"
#include "base/task/post_task.h"
#include "base/task_runner_util.h"
#include "url/gurl.h"
#include "url/origin.h"
#include "url/url_constants.h"
namespace {
using DomainToReputationMap = CrowdDenyPreloadData::DomainToReputationMap;
// Attempts to load the preload data from |proto_path|, parse it as a serialized
// chrome_browser_crowd_deny::PreloadData message, and index it by domain.
// Returns an empty map is anything goes wrong.
DomainToReputationMap LoadAndParseAndIndexPreloadDataFromDisk(
const base::FilePath& proto_path) {
std::string binary_proto;
if (!base::ReadFileToString(proto_path, &binary_proto))
return {};
CrowdDenyPreloadData::PreloadData preload_data;
if (!preload_data.ParseFromString(binary_proto))
return {};
std::vector<DomainToReputationMap::value_type> domain_reputation_pairs;
domain_reputation_pairs.reserve(preload_data.site_reputations_size());
for (const auto& site_reputation : preload_data.site_reputations()) {
domain_reputation_pairs.emplace_back(site_reputation.domain(),
site_reputation);
}
return DomainToReputationMap(std::move(domain_reputation_pairs));
}
} // namespace
CrowdDenyPreloadData::CrowdDenyPreloadData() {
loading_task_runner_ = base::CreateSequencedTaskRunner(
{base::ThreadPool(), base::MayBlock(), base::TaskPriority::USER_VISIBLE});
}
CrowdDenyPreloadData::~CrowdDenyPreloadData() = default;
// static
CrowdDenyPreloadData* CrowdDenyPreloadData::GetInstance() {
static base::NoDestructor<CrowdDenyPreloadData> instance;
return instance.get();
}
const CrowdDenyPreloadData::SiteReputation*
CrowdDenyPreloadData::GetReputationDataForSite(
const url::Origin& origin) const {
if (origin.scheme() != url::kHttpsScheme)
return nullptr;
// For now, do not allow subdomain matches.
const auto it = domain_to_reputation_map_.find(origin.host());
if (it == domain_to_reputation_map_.end())
return nullptr;
return &it->second;
}
void CrowdDenyPreloadData::LoadFromDisk(const base::FilePath& proto_path) {
// On failure, LoadAndParseAndIndexPreloadDataFromDisk will return an empty
// map. Replace the in-memory state with that regardless, so that the stale
// old data will no longer be used.
base::PostTaskAndReplyWithResult(
loading_task_runner_.get(), FROM_HERE,
base::BindOnce(&LoadAndParseAndIndexPreloadDataFromDisk, proto_path),
base::BindOnce(&CrowdDenyPreloadData::set_site_reputations,
base::Unretained(this)));
}
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_PERMISSIONS_CROWD_DENY_PRELOAD_DATA_H_
#define CHROME_BROWSER_PERMISSIONS_CROWD_DENY_PRELOAD_DATA_H_
#include <memory>
#include <utility>
#include "base/containers/flat_map.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "chrome/browser/permissions/crowd_deny.pb.h"
namespace base {
class SequencedTaskRunner;
}
namespace url {
class Origin;
}
namespace base {
class FilePath;
}
// Stores information relevant for making permission decision on popular sites.
//
// The preloaded list contains reputation data for popular sites, and is
// distributed to Chrome clients ahead of time through the component updater.
// The purpose is to reduce the frequency of on-demand pings to Safe Browsing.
class CrowdDenyPreloadData {
public:
using SiteReputation = chrome_browser_crowd_deny::SiteReputation;
using DomainToReputationMap = base::flat_map<std::string, SiteReputation>;
using PreloadData = chrome_browser_crowd_deny::PreloadData;
CrowdDenyPreloadData();
~CrowdDenyPreloadData();
static CrowdDenyPreloadData* GetInstance();
// Returns preloaded site reputation data for |origin| if available, or
// nullptr otherwise.
//
// Because there is no way to establish the identity of insecure origins,
// reputation data is only ever provided if |origin| has HTTPS scheme. The
// port of |origin| is ignored.
const SiteReputation* GetReputationDataForSite(
const url::Origin& origin) const;
// Parses a single instance of chrome_browser_crowd_deny::PreloadData message
// in binary wire format from the file at |preload_data_path|.
void LoadFromDisk(const base::FilePath& preload_data_path);
private:
void set_site_reputations(DomainToReputationMap map) {
domain_to_reputation_map_ = std::move(map);
}
DomainToReputationMap domain_to_reputation_map_;
scoped_refptr<base::SequencedTaskRunner> loading_task_runner_;
DISALLOW_COPY_AND_ASSIGN(CrowdDenyPreloadData);
};
#endif // CHROME_BROWSER_PERMISSIONS_CROWD_DENY_PRELOAD_DATA_H_
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/permissions/crowd_deny_preload_data.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/string_piece.h"
#include "base/test/task_environment.h"
#include "chrome/browser/permissions/crowd_deny.pb.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
#include "url/origin.h"
namespace {
constexpr char kTestDomainAlpha[] = "alpha.com";
constexpr char kTestDomainBeta[] = "beta.com";
constexpr char kTestDomainGamma[] = "gamma.com";
constexpr char kTestDomainDelta[] = "delta.com";
constexpr char kTestDomainEpsilon[] = "epsilon.com";
constexpr char kTestOriginAlpha[] = "https://alpha.com";
constexpr char kTestOriginBeta[] = "https://beta.com";
constexpr char kTestOriginGamma[] = "https://gamma.com";
constexpr char kTestOriginDelta[] = "https://delta.com";
constexpr char kTestOriginEpsilon[] = "https://epsilon.com";
constexpr const char* kAllTestingOrigins[] = {
kTestOriginAlpha, kTestOriginBeta, kTestOriginGamma, kTestOriginDelta,
kTestOriginEpsilon};
} // namespace
class CrowdDenyPreloadDataTest : public testing::Test {
public:
using SiteReputation = chrome_browser_crowd_deny::SiteReputation;
CrowdDenyPreloadDataTest() {}
~CrowdDenyPreloadDataTest() override = default;
protected:
void SetUp() override { ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir()); }
base::test::TaskEnvironment* task_environment() { return &task_environment_; }
base::FilePath GetPathInTempDir(
base::FilePath::StringPieceType filename) const {
return scoped_temp_dir_.GetPath().Append(filename);
}
void SerializeTestRawData(base::StringPiece raw_data, base::FilePath path) {
const int bytes_to_write = base::checked_cast<int>(raw_data.size());
ASSERT_EQ(bytes_to_write,
base::WriteFile(path, raw_data.data(), bytes_to_write));
}
void SerializeTestPreloadData(
chrome_browser_crowd_deny::PreloadData preload_data,
base::FilePath path) {
std::string binary_preload_data;
ASSERT_TRUE(preload_data.SerializeToString(&binary_preload_data));
ASSERT_NO_FATAL_FAILURE(SerializeTestRawData(binary_preload_data, path));
}
void LoadTestDataAndWait(base::FilePath path) {
CrowdDenyPreloadData::GetInstance()->LoadFromDisk(path);
task_environment()->RunUntilIdle();
}
void SerializeAndLoadTestData(
chrome_browser_crowd_deny::PreloadData test_data) {
const base::FilePath temp_path =
GetPathInTempDir(FILE_PATH_LITERAL("Preload Data"));
ASSERT_NO_FATAL_FAILURE(
SerializeTestPreloadData(std::move(test_data), temp_path));
LoadTestDataAndWait(temp_path);
}
void SerializeAndLoadCannedTestData() {
chrome_browser_crowd_deny::PreloadData test_data;
auto* alpha_site_reputation = test_data.add_site_reputations();
alpha_site_reputation->set_domain(kTestDomainAlpha);
alpha_site_reputation->set_notification_ux_quality(SiteReputation::UNKNOWN);
auto* beta_site_reputation = test_data.add_site_reputations();
beta_site_reputation->set_domain(kTestDomainBeta);
beta_site_reputation->set_notification_ux_quality(
SiteReputation::ACCEPTABLE);
auto* gamma_site_reputation = test_data.add_site_reputations();
gamma_site_reputation->set_domain(kTestDomainGamma);
gamma_site_reputation->set_notification_ux_quality(
SiteReputation::UNSOLICITED_PROMPTS);
auto* delta_site_reputation = test_data.add_site_reputations();
delta_site_reputation->set_domain(kTestDomainDelta);
// No |notification_ux_quality| field.
ASSERT_NO_FATAL_FAILURE(SerializeAndLoadTestData(std::move(test_data)));
}
void ExpectEmptyPreloadData() {
for (const char* origin_string : kAllTestingOrigins) {
SCOPED_TRACE(origin_string);
EXPECT_FALSE(
CrowdDenyPreloadData::GetInstance()->GetReputationDataForSite(
url::Origin::Create(GURL(origin_string))));
}
}
private:
base::test::TaskEnvironment task_environment_;
base::ScopedTempDir scoped_temp_dir_;
DISALLOW_COPY_AND_ASSIGN(CrowdDenyPreloadDataTest);
};
TEST_F(CrowdDenyPreloadDataTest, NoData) {
ExpectEmptyPreloadData();
}
TEST_F(CrowdDenyPreloadDataTest, MissingFile) {
LoadTestDataAndWait(GetPathInTempDir(FILE_PATH_LITERAL("NonExistentFile")));
ExpectEmptyPreloadData();
}
TEST_F(CrowdDenyPreloadDataTest, EmptyData) {
const base::FilePath empty_file_path =
GetPathInTempDir(FILE_PATH_LITERAL("EmptyFile"));
SerializeTestRawData(base::StringPiece(), empty_file_path);
LoadTestDataAndWait(empty_file_path);
ExpectEmptyPreloadData();
}
TEST_F(CrowdDenyPreloadDataTest, BadData) {
const base::FilePath bad_data_path =
GetPathInTempDir(FILE_PATH_LITERAL("BadFile"));
SerializeTestRawData("This is not a proto.", bad_data_path);
LoadTestDataAndWait(bad_data_path);
ExpectEmptyPreloadData();
}
TEST_F(CrowdDenyPreloadDataTest, NotificationUserExperienceQuality) {
ASSERT_NO_FATAL_FAILURE(SerializeAndLoadCannedTestData());
const auto* data =
CrowdDenyPreloadData::GetInstance()->GetReputationDataForSite(
url::Origin::Create(GURL(kTestOriginAlpha)));
ASSERT_TRUE(data);
EXPECT_EQ(kTestDomainAlpha, data->domain());
EXPECT_EQ(SiteReputation::UNKNOWN, data->notification_ux_quality());
data = CrowdDenyPreloadData::GetInstance()->GetReputationDataForSite(
url::Origin::Create(GURL(kTestOriginBeta)));
ASSERT_TRUE(data);
EXPECT_EQ(kTestDomainBeta, data->domain());
EXPECT_EQ(SiteReputation::ACCEPTABLE, data->notification_ux_quality());
data = CrowdDenyPreloadData::GetInstance()->GetReputationDataForSite(
url::Origin::Create(GURL(kTestOriginGamma)));
ASSERT_TRUE(data);
EXPECT_EQ(kTestDomainGamma, data->domain());
EXPECT_EQ(SiteReputation::UNSOLICITED_PROMPTS,
data->notification_ux_quality());
data = CrowdDenyPreloadData::GetInstance()->GetReputationDataForSite(
url::Origin::Create(GURL(kTestOriginDelta)));
ASSERT_TRUE(data);
EXPECT_EQ(kTestDomainDelta, data->domain());
EXPECT_EQ(SiteReputation::UNKNOWN, data->notification_ux_quality());
data = CrowdDenyPreloadData::GetInstance()->GetReputationDataForSite(
url::Origin::Create(GURL(kTestOriginEpsilon)));
EXPECT_FALSE(data);
}
TEST_F(CrowdDenyPreloadDataTest, GetReputationReturnsNullForNonHttpsOrigins) {
const char* kNonHttpsOrigins[] = {
"http://alpha.com",
"wss://alpha.com",
"ftp://alpha.com",
"file:///alpha.com",
};
ASSERT_NO_FATAL_FAILURE(SerializeAndLoadCannedTestData());
EXPECT_TRUE(CrowdDenyPreloadData::GetInstance()->GetReputationDataForSite(
url::Origin::Create(GURL(kTestOriginAlpha))));
for (const char* non_https_origin : kNonHttpsOrigins) {
SCOPED_TRACE(non_https_origin);
EXPECT_FALSE(CrowdDenyPreloadData::GetInstance()->GetReputationDataForSite(
url::Origin::Create(GURL(non_https_origin))));
}
}
TEST_F(CrowdDenyPreloadDataTest, GetReputationIgnoresPort) {
ASSERT_NO_FATAL_FAILURE(SerializeAndLoadCannedTestData());
EXPECT_TRUE(CrowdDenyPreloadData::GetInstance()->GetReputationDataForSite(
url::Origin::Create(GURL("https://alpha.com:443"))));
EXPECT_TRUE(CrowdDenyPreloadData::GetInstance()->GetReputationDataForSite(
url::Origin::Create(GURL("https://alpha.com:1234"))));
}
TEST_F(CrowdDenyPreloadDataTest, Update) {
ASSERT_NO_FATAL_FAILURE(SerializeAndLoadCannedTestData());
// Prepare and load an updated payload version, which updates the entry for
// `delta.com`, adds an entry for `epsilon.com`, and removes all others.
chrome_browser_crowd_deny::PreloadData test_data_v2;
auto* delta_site_reputation = test_data_v2.add_site_reputations();
delta_site_reputation->set_domain(kTestDomainDelta);
delta_site_reputation->set_notification_ux_quality(
SiteReputation::UNSOLICITED_PROMPTS);
auto* epsilon_site_reputation = test_data_v2.add_site_reputations();
epsilon_site_reputation->set_domain(kTestDomainEpsilon);
epsilon_site_reputation->set_notification_ux_quality(
SiteReputation::ACCEPTABLE);
ASSERT_NO_FATAL_FAILURE(SerializeAndLoadTestData(std::move(test_data_v2)));
// Check that the updated preload data is visible.
EXPECT_FALSE(CrowdDenyPreloadData::GetInstance()->GetReputationDataForSite(
url::Origin::Create(GURL(kTestOriginAlpha))));
EXPECT_FALSE(CrowdDenyPreloadData::GetInstance()->GetReputationDataForSite(
url::Origin::Create(GURL(kTestOriginBeta))));
EXPECT_FALSE(CrowdDenyPreloadData::GetInstance()->GetReputationDataForSite(
url::Origin::Create(GURL(kTestOriginGamma))));
const auto* data =
CrowdDenyPreloadData::GetInstance()->GetReputationDataForSite(
url::Origin::Create(GURL(kTestOriginDelta)));
ASSERT_TRUE(data);
EXPECT_EQ(kTestDomainDelta, data->domain());
EXPECT_EQ(SiteReputation::UNSOLICITED_PROMPTS,
data->notification_ux_quality());
data = CrowdDenyPreloadData::GetInstance()->GetReputationDataForSite(
url::Origin::Create(GURL(kTestOriginEpsilon)));
ASSERT_TRUE(data);
EXPECT_EQ(kTestDomainEpsilon, data->domain());
EXPECT_EQ(SiteReputation::ACCEPTABLE, data->notification_ux_quality());
}
TEST_F(CrowdDenyPreloadDataTest, UpdateToMissingFileWipesInMemoryState) {
ASSERT_NO_FATAL_FAILURE(SerializeAndLoadCannedTestData());
LoadTestDataAndWait(GetPathInTempDir(FILE_PATH_LITERAL("NonExistentFile")));
ExpectEmptyPreloadData();
}
TEST_F(CrowdDenyPreloadDataTest, UpdateToEmptyFileWipesInMemoryState) {
ASSERT_NO_FATAL_FAILURE(SerializeAndLoadCannedTestData());
const base::FilePath empty_file_path =
GetPathInTempDir(FILE_PATH_LITERAL("EmptyFile"));
SerializeTestRawData(base::StringPiece(), empty_file_path);
LoadTestDataAndWait(empty_file_path);
ExpectEmptyPreloadData();
}
TEST_F(CrowdDenyPreloadDataTest, UpdateToBadFileWipesInMemoryState) {
ASSERT_NO_FATAL_FAILURE(SerializeAndLoadCannedTestData());
const base::FilePath bad_data_path =
GetPathInTempDir(FILE_PATH_LITERAL("BadFile"));
SerializeTestRawData("This is not a proto.", bad_data_path);
LoadTestDataAndWait(bad_data_path);
ExpectEmptyPreloadData();
}
// During start-up congestion, it is possible that a new version of the
// component becomes available while the old version is pending being loaded.
// Ensure that when things settle down, the last version loaded will prevail,
// and nothing explodes on the way.
TEST_F(CrowdDenyPreloadDataTest, LastOneSurvivesFromUpdatesInQuickSuccession) {
ASSERT_NO_FATAL_FAILURE(SerializeAndLoadCannedTestData());
// Prepare and load two updated versions, each twice, in a quick success.
chrome_browser_crowd_deny::PreloadData test_data_v2;
auto* delta_site_reputation = test_data_v2.add_site_reputations();
delta_site_reputation->set_domain(kTestDomainDelta);
chrome_browser_crowd_deny::PreloadData test_data_v3;
auto* epsilon_site_reputation = test_data_v3.add_site_reputations();
epsilon_site_reputation->set_domain(kTestDomainEpsilon);
epsilon_site_reputation->set_notification_ux_quality(
SiteReputation::ACCEPTABLE);
const base::FilePath data_path_v2 =
GetPathInTempDir(FILE_PATH_LITERAL("DataV2"));
const base::FilePath data_path_v3 =
GetPathInTempDir(FILE_PATH_LITERAL("DataV3"));
SerializeTestPreloadData(std::move(test_data_v2), data_path_v2);
SerializeTestPreloadData(std::move(test_data_v3), data_path_v3);
// Trigger three loads without pumping the message loop.
//
// TODO(crbug.com/1028642): Think about making this test stronger. Even if the
// ordering were random, given the generous retry policy in continuous build,
// the test would still pass most of the time.
CrowdDenyPreloadData::GetInstance()->LoadFromDisk(data_path_v2);
CrowdDenyPreloadData::GetInstance()->LoadFromDisk(data_path_v3);
task_environment()->RunUntilIdle();
// Expect the new version to have become visible.
const auto* data =
CrowdDenyPreloadData::GetInstance()->GetReputationDataForSite(
url::Origin::Create(GURL(kTestOriginEpsilon)));
ASSERT_TRUE(data);
EXPECT_EQ(kTestDomainEpsilon, data->domain());
EXPECT_EQ(SiteReputation::ACCEPTABLE, data->notification_ux_quality());
EXPECT_FALSE(CrowdDenyPreloadData::GetInstance()->GetReputationDataForSite(
url::Origin::Create(GURL(kTestOriginDelta))));
}
...@@ -3166,6 +3166,7 @@ test("unit_tests") { ...@@ -3166,6 +3166,7 @@ test("unit_tests") {
"../browser/permissions/chooser_context_base_mock_permission_observer.cc", "../browser/permissions/chooser_context_base_mock_permission_observer.cc",
"../browser/permissions/chooser_context_base_mock_permission_observer.h", "../browser/permissions/chooser_context_base_mock_permission_observer.h",
"../browser/permissions/chooser_context_base_unittest.cc", "../browser/permissions/chooser_context_base_unittest.cc",
"../browser/permissions/crowd_deny_preload_data_unittest.cc",
"../browser/permissions/crowd_deny_safe_browsing_request_unittest.cc", "../browser/permissions/crowd_deny_safe_browsing_request_unittest.cc",
"../browser/permissions/permission_context_base_feature_policy_unittest.cc", "../browser/permissions/permission_context_base_feature_policy_unittest.cc",
"../browser/permissions/permission_context_base_unittest.cc", "../browser/permissions/permission_context_base_unittest.cc",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment