blob: 2ee3cb5860137a93442c829d26a4fce9fdf894e9 [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// 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/tpcd_metadata_component_installer.h"
#include "base/feature_list.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "base/logging.h"
#include "base/metrics/histogram_functions.h"
#include "base/path_service.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/version.h"
#include "components/component_updater/component_updater_service.h"
#include "components/content_settings/core/common/content_settings_pattern.h"
#include "components/tpcd/metadata/parser.h"
#include "content/public/browser/browser_thread.h"
#include "net/base/features.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
using component_updater::ComponentUpdateService;
namespace {
// This is similar to the display name at http://omaharelease/1915488/settings
// and
// http://google3/java/com/google/installer/releasemanager/Automation.java;l=1161;rcl=553816031
const char kTpcdMetadataManifestName[] =
"Third-Party Cookie Deprecation Metadata";
// The SHA256 of the SubjectPublicKeyInfo used to sign the extension.
// The extension id is: jflhchccmppkfebkiaminageehmchikm
const uint8_t kTpcdMetadataPublicKeySHA256[32] = {
0x95, 0xb7, 0x27, 0x22, 0xcf, 0xfa, 0x54, 0x1a, 0x80, 0xc8, 0xd0,
0x64, 0x47, 0xc2, 0x78, 0xac, 0x61, 0x26, 0x43, 0xbf, 0x3a, 0x51,
0x2e, 0xa6, 0xce, 0x00, 0x25, 0x7b, 0x6c, 0xc4, 0x4e, 0x39};
const base::FilePath::CharType kComponentFileName[] =
FILE_PATH_LITERAL("metadata.pb");
const base::FilePath::CharType kRelInstallDirName[] =
FILE_PATH_LITERAL("TpcdMetadata");
// Runs on a thread pool.
absl::optional<std::string> ReadComponentFromDisk(
const base::FilePath& file_path) {
VLOG(1) << "Reading TPCD Metadata from file: " << file_path.value();
std::string contents;
if (!base::ReadFileToString(file_path, &contents)) {
VLOG(1) << "Failed reading from " << file_path.value();
return absl::nullopt;
}
return contents;
}
const base::FilePath GetComponentPath(const base::FilePath& install_dir) {
return install_dir.Append(kComponentFileName);
}
} // namespace
namespace component_updater {
TpcdMetadataComponentInstaller::TpcdMetadataComponentInstaller(
OnTpcdMetadataComponentReadyCallback on_component_ready_callback)
: on_component_ready_callback_(on_component_ready_callback) {}
TpcdMetadataComponentInstaller::~TpcdMetadataComponentInstaller() = default;
// Start of ComponentInstallerPolicy overrides impl:
bool TpcdMetadataComponentInstaller::
SupportsGroupPolicyEnabledComponentUpdates() const {
return true;
}
bool TpcdMetadataComponentInstaller::RequiresNetworkEncryption() const {
return false;
}
update_client::CrxInstaller::Result
TpcdMetadataComponentInstaller::OnCustomInstall(
const base::Value::Dict& manifest,
const base::FilePath& install_dir) {
return update_client::CrxInstaller::Result(0); // Nothing custom here.
}
void TpcdMetadataComponentInstaller::OnCustomUninstall() {}
void TpcdMetadataComponentInstaller::ComponentReady(
const base::Version& version,
const base::FilePath& install_dir,
base::Value::Dict manifest) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
VLOG(1) << "TPCD Metadata Component ready, version " << version.GetString()
<< " in " << install_dir.value();
if (base::FeatureList::IsEnabled(net::features::kTpcdMetadataGrants)) {
// Given `BEST_EFFORT` since we don't need to be USER_BLOCKING.
base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
base::BindOnce(&ReadComponentFromDisk, GetComponentPath(install_dir)),
base::BindOnce(
[](OnTpcdMetadataComponentReadyCallback on_component_ready_callback,
const absl::optional<std::string>& maybe_contents) {
if (maybe_contents.has_value()) {
on_component_ready_callback.Run(maybe_contents.value());
}
},
on_component_ready_callback_));
}
}
void WriteMetrics(TpcdMetadataInstallationResult result) {
base::UmaHistogramEnumeration(
"Navigation.TpcdMitigations.MetadataInstallationResult", result);
}
// Called during startup and installation before ComponentReady().
bool TpcdMetadataComponentInstaller::VerifyInstallation(
const base::Value::Dict& manifest,
const base::FilePath& install_dir) const {
if (!base::PathExists(GetComponentPath(install_dir))) {
WriteMetrics(TpcdMetadataInstallationResult::kMissingMetadataFile);
return false;
}
std::string contents;
if (!base::ReadFileToString(GetComponentPath(install_dir), &contents)) {
WriteMetrics(TpcdMetadataInstallationResult::kReadingMetadataFileFailed);
return false;
}
tpcd::metadata::Metadata metadata;
if (!metadata.ParseFromString(contents)) {
WriteMetrics(TpcdMetadataInstallationResult::kParsingToProtoFailed);
return false;
}
for (const auto& me : metadata.metadata_entries()) {
if (!me.has_primary_pattern_spec() ||
!ContentSettingsPattern::FromString(me.primary_pattern_spec())
.IsValid()) {
WriteMetrics(TpcdMetadataInstallationResult::kErroneousSpec);
return false;
}
if (!me.has_secondary_pattern_spec() ||
!ContentSettingsPattern::FromString(me.secondary_pattern_spec())
.IsValid()) {
WriteMetrics(TpcdMetadataInstallationResult::kErroneousSpec);
return false;
}
}
WriteMetrics(TpcdMetadataInstallationResult::kSuccessful);
return true;
}
base::FilePath TpcdMetadataComponentInstaller::GetRelativeInstallDir() const {
return base::FilePath(kRelInstallDirName);
}
void TpcdMetadataComponentInstaller::GetHash(std::vector<uint8_t>* hash) const {
hash->assign(std::begin(kTpcdMetadataPublicKeySHA256),
std::end(kTpcdMetadataPublicKeySHA256));
}
std::string TpcdMetadataComponentInstaller::GetName() const {
return kTpcdMetadataManifestName;
}
update_client::InstallerAttributes
TpcdMetadataComponentInstaller::GetInstallerAttributes() const {
return update_client::InstallerAttributes();
}
// End of ComponentInstallerPolicy overrides impl.
void RegisterTpcdMetadataComponent(ComponentUpdateService* cus) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
VLOG(1) << "Third Party Cookie Deprecation Metadata component.";
auto installer = base::MakeRefCounted<ComponentInstaller>(
std::make_unique<TpcdMetadataComponentInstaller>(
base::BindRepeating([](std::string raw_metadata) {
tpcd::metadata::Parser::GetInstance()->ParseMetadata(raw_metadata);
})));
installer->Register(cus, base::OnceClosure());
}
} // namespace component_updater