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") {
"component_updater/component_updater_utils.h",
"component_updater/crl_set_component_installer.cc",
"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.h",
"component_updater/games_component_installer.cc",
......@@ -1170,6 +1172,8 @@ jumbo_static_library("browser") {
"permissions/adaptive_notification_permission_ui_selector.h",
"permissions/chooser_context_base.cc",
"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.h",
"permissions/permission_context_base.cc",
......@@ -1941,6 +1945,7 @@ jumbo_static_library("browser") {
":buildflags",
":expired_flags_list",
":ntp_background_proto",
":permissions_proto",
":resource_prefetch_predictor_proto",
"//base:i18n",
"//base/allocator:buildflags",
......@@ -5336,6 +5341,12 @@ proto_library("resource_prefetch_predictor_proto") {
]
}
proto_library("permissions_proto") {
sources = [
"permissions/crowd_deny.proto",
]
}
grit("resources") {
source = "browser_resources.grd"
......
......@@ -57,6 +57,7 @@
#include "chrome/browser/chrome_browser_field_trials.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/crowd_deny_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/mei_preload_component_installer.h"
......@@ -553,6 +554,7 @@ void RegisterComponentsForUpdate(bool is_off_the_record_profile,
#endif
RegisterSafetyTipsComponent(cus, path);
RegisterCrowdDenyComponent(cus, path);
#if BUILDFLAG(GOOGLE_CHROME_BRANDING) && defined(OS_ANDROID)
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_
This diff is collapsed.
......@@ -3166,6 +3166,7 @@ test("unit_tests") {
"../browser/permissions/chooser_context_base_mock_permission_observer.cc",
"../browser/permissions/chooser_context_base_mock_permission_observer.h",
"../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/permission_context_base_feature_policy_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