blob: 4af19379519627782fd0d4559c8646824db9dfb0 [file] [log] [blame]
// Copyright 2020 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/first_party_sets_component_installer.h"
#include "base/bind.h"
#include "base/feature_list.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/optional.h"
#include "base/path_service.h"
#include "base/stl_util.h"
#include "base/task/post_task.h"
#include "base/task/thread_pool.h"
#include "base/version.h"
#include "components/component_updater/component_updater_paths.h"
#include "services/network/public/cpp/features.h"
using component_updater::ComponentUpdateService;
namespace {
constexpr base::FilePath::CharType kFirstPartySetsSetsFileName[] =
FILE_PATH_LITERAL("sets.json");
// The SHA256 of the SubjectPublicKeyInfo used to sign the extension.
// The extension id is: gonpemdgkjcecdgbnaabipppbmgfggbe
constexpr uint8_t kFirstPartySetsPublicKeySHA256[32] = {
0x6e, 0xdf, 0x4c, 0x36, 0xa9, 0x24, 0x23, 0x61, 0xd0, 0x01, 0x8f,
0xff, 0x1c, 0x65, 0x66, 0x14, 0xa8, 0x46, 0x37, 0xe6, 0xeb, 0x80,
0x8b, 0x8f, 0xb0, 0xb6, 0x18, 0xa7, 0xcd, 0x3d, 0xbb, 0xfb};
constexpr char kFirstPartySetsManifestName[] = "First-Party Sets";
constexpr base::FilePath::CharType kFirstPartySetsRelativeInstallDir[] =
FILE_PATH_LITERAL("FirstPartySetsPreloaded");
// Reads the sets as raw JSON from their storage file, returning the raw sets on
// success and nullopt on failure.
base::Optional<std::string> LoadSetsFromDisk(const base::FilePath& pb_path) {
if (pb_path.empty())
return base::nullopt;
VLOG(1) << "Reading First-Party Sets from file: " << pb_path.value();
std::string result;
if (!base::ReadFileToString(pb_path, &result)) {
// The file won't exist on new installations, so this is not always an
// error.
VLOG(1) << "Failed reading from " << pb_path.value();
return base::nullopt;
}
return result;
}
} // namespace
namespace component_updater {
FirstPartySetsComponentInstallerPolicy::FirstPartySetsComponentInstallerPolicy(
base::RepeatingCallback<void(const std::string&)> on_sets_ready)
: on_sets_ready_(std::move(on_sets_ready)) {}
FirstPartySetsComponentInstallerPolicy::
~FirstPartySetsComponentInstallerPolicy() = default;
bool FirstPartySetsComponentInstallerPolicy::
SupportsGroupPolicyEnabledComponentUpdates() const {
// False since this is a data, non-binary component.
return false;
}
bool FirstPartySetsComponentInstallerPolicy::RequiresNetworkEncryption() const {
// Update checks and pings associated with this component do not require
// confidentiality, since the component is identical for all users.
return false;
}
update_client::CrxInstaller::Result
FirstPartySetsComponentInstallerPolicy::OnCustomInstall(
const base::DictionaryValue& manifest,
const base::FilePath& install_dir) {
return update_client::CrxInstaller::Result(0); // Nothing custom here.
}
void FirstPartySetsComponentInstallerPolicy::OnCustomUninstall() {}
base::FilePath FirstPartySetsComponentInstallerPolicy::GetInstalledPath(
const base::FilePath& base) {
return base.Append(kFirstPartySetsSetsFileName);
}
void FirstPartySetsComponentInstallerPolicy::ComponentReady(
const base::Version& version,
const base::FilePath& install_dir,
std::unique_ptr<base::DictionaryValue> manifest) {
VLOG(1) << "First-Party Sets Component ready, version " << version.GetString()
<< " in " << install_dir.value();
base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
base::BindOnce(&LoadSetsFromDisk, GetInstalledPath(install_dir)),
base::BindOnce(
[](base::RepeatingCallback<void(const std::string&)> on_sets_ready,
base::Optional<std::string> raw_sets) {
if (raw_sets.has_value())
on_sets_ready.Run(*raw_sets);
},
on_sets_ready_));
}
// Called during startup and installation before ComponentReady().
bool FirstPartySetsComponentInstallerPolicy::VerifyInstallation(
const base::DictionaryValue& manifest,
const base::FilePath& install_dir) const {
// No need to actually validate the sets here, since we'll do the validation
// in the Network Service.
return base::PathExists(GetInstalledPath(install_dir));
}
base::FilePath FirstPartySetsComponentInstallerPolicy::GetRelativeInstallDir()
const {
return base::FilePath(kFirstPartySetsRelativeInstallDir);
}
void FirstPartySetsComponentInstallerPolicy::GetHash(
std::vector<uint8_t>* hash) const {
hash->assign(kFirstPartySetsPublicKeySHA256,
kFirstPartySetsPublicKeySHA256 +
base::size(kFirstPartySetsPublicKeySHA256));
}
std::string FirstPartySetsComponentInstallerPolicy::GetName() const {
return kFirstPartySetsManifestName;
}
update_client::InstallerAttributes
FirstPartySetsComponentInstallerPolicy::GetInstallerAttributes() const {
return update_client::InstallerAttributes();
}
std::vector<std::string> FirstPartySetsComponentInstallerPolicy::GetMimeTypes()
const {
return {};
}
void RegisterFirstPartySetsComponent(ComponentUpdateService* cus) {
if (!base::FeatureList::IsEnabled(network::features::kFirstPartySets))
return;
VLOG(1) << "Registering First-Party Sets component.";
auto installer = base::MakeRefCounted<ComponentInstaller>(
std::make_unique<FirstPartySetsComponentInstallerPolicy>(
/*on_sets_ready=*/base::BindRepeating(
[](const std ::string& raw_sets) {
// TODO(cfredric): forward to NetworkService here.
VLOG(1) << "Received Sets: \"" << raw_sets << "\"";
})));
installer->Register(cus, base::OnceClosure());
}
} // namespace component_updater