Add ComponentInstaller for FirstPartySets component.
This component will receive a JSON object that encodes the First-Party sets that are to be preloaded as part of the MVP of the First-Party Sets prototype (https://github.com/privacycg/first-party-sets). This will allow sites to declare themselves as the same first-party; this information will be used to allow certain embedded contexts access to their own first-party state. Note: I've added the base::Feature enabling this functionality to //services/network/public/cpp as both the //chrome client and (in future cls) the Network Service implementation will need to use this Feature to gate their behavior. Change-Id: I20f2378fcee624169f6b57d6837998c92f7f0033 Bug: 1124904 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2392797 Commit-Queue: Chris Fredrickson <cfredric@google.com> Reviewed-by: Colin Blundell <blundell@chromium.org> Reviewed-by: Sorin Jianu <sorin@chromium.org> Reviewed-by: Steven Bingler <bingler@chromium.org> Cr-Commit-Position: refs/heads/master@{#805795}
This commit is contained in:
@ -300,6 +300,8 @@ static_library("browser") {
|
||||
"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/first_party_sets_component_installer.cc",
|
||||
"component_updater/first_party_sets_component_installer.h",
|
||||
"component_updater/floc_blocklist_component_installer.cc",
|
||||
"component_updater/floc_blocklist_component_installer.h",
|
||||
"component_updater/games_component_installer.cc",
|
||||
|
@ -0,0 +1,162 @@
|
||||
// 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
|
@ -0,0 +1,71 @@
|
||||
// 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.
|
||||
|
||||
#ifndef CHROME_BROWSER_COMPONENT_UPDATER_FIRST_PARTY_SETS_COMPONENT_INSTALLER_H_
|
||||
#define CHROME_BROWSER_COMPONENT_UPDATER_FIRST_PARTY_SETS_COMPONENT_INSTALLER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/callback.h"
|
||||
#include "base/values.h"
|
||||
#include "components/component_updater/component_installer.h"
|
||||
|
||||
namespace base {
|
||||
class FilePath;
|
||||
} // namespace base
|
||||
|
||||
namespace component_updater {
|
||||
|
||||
class ComponentUpdateService;
|
||||
|
||||
class FirstPartySetsComponentInstallerPolicy : public ComponentInstallerPolicy {
|
||||
public:
|
||||
// |on_sets_ready| will be called on the UI thread when the sets are ready. It
|
||||
// is exposed here for testing.
|
||||
explicit FirstPartySetsComponentInstallerPolicy(
|
||||
base::RepeatingCallback<void(const std::string&)> on_sets_ready);
|
||||
~FirstPartySetsComponentInstallerPolicy() override;
|
||||
|
||||
FirstPartySetsComponentInstallerPolicy(
|
||||
const FirstPartySetsComponentInstallerPolicy&) = delete;
|
||||
FirstPartySetsComponentInstallerPolicy operator=(
|
||||
const FirstPartySetsComponentInstallerPolicy&) = delete;
|
||||
|
||||
private:
|
||||
FRIEND_TEST_ALL_PREFIXES(FirstPartySetsComponentInstallerTest, LoadsSets);
|
||||
|
||||
// The following methods override ComponentInstallerPolicy.
|
||||
bool SupportsGroupPolicyEnabledComponentUpdates() const override;
|
||||
bool RequiresNetworkEncryption() const override;
|
||||
update_client::CrxInstaller::Result OnCustomInstall(
|
||||
const base::DictionaryValue& manifest,
|
||||
const base::FilePath& install_dir) override;
|
||||
void OnCustomUninstall() override;
|
||||
bool VerifyInstallation(const base::DictionaryValue& manifest,
|
||||
const base::FilePath& install_dir) const 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;
|
||||
update_client::InstallerAttributes GetInstallerAttributes() const override;
|
||||
std::vector<std::string> GetMimeTypes() const override;
|
||||
|
||||
static base::FilePath GetInstalledPath(const base::FilePath& base);
|
||||
|
||||
base::RepeatingCallback<void(const std::string&)> on_sets_ready_;
|
||||
};
|
||||
|
||||
// Call once during startup to make the component update service aware of
|
||||
// the First-Party Sets component.
|
||||
void RegisterFirstPartySetsComponent(ComponentUpdateService* cus);
|
||||
|
||||
} // namespace component_updater
|
||||
|
||||
#endif // CHROME_BROWSER_COMPONENT_UPDATER_FIRST_PARTY_SETS_COMPONENT_INSTALLER_H_
|
@ -0,0 +1,77 @@
|
||||
// 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/files/file_util.h"
|
||||
#include "base/files/scoped_temp_dir.h"
|
||||
#include "base/run_loop.h"
|
||||
#include "base/sequence_checker.h"
|
||||
#include "base/test/bind_test_util.h"
|
||||
#include "base/test/scoped_feature_list.h"
|
||||
#include "base/test/task_environment.h"
|
||||
#include "base/threading/thread_task_runner_handle.h"
|
||||
#include "base/version.h"
|
||||
#include "chrome/common/pref_names.h"
|
||||
#include "chrome/test/base/testing_browser_process.h"
|
||||
#include "components/component_updater/mock_component_updater_service.h"
|
||||
#include "services/network/public/cpp/features.h"
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
namespace component_updater {
|
||||
|
||||
namespace {
|
||||
using ::testing::_;
|
||||
} // namespace
|
||||
|
||||
class FirstPartySetsComponentInstallerTest : public ::testing::Test {
|
||||
public:
|
||||
FirstPartySetsComponentInstallerTest() {
|
||||
CHECK(component_install_dir_.CreateUniqueTempDir());
|
||||
}
|
||||
|
||||
protected:
|
||||
base::test::TaskEnvironment env_;
|
||||
|
||||
base::ScopedTempDir component_install_dir_;
|
||||
};
|
||||
|
||||
TEST_F(FirstPartySetsComponentInstallerTest, FeatureDisabled) {
|
||||
base::test::ScopedFeatureList scoped_list;
|
||||
scoped_list.InitAndDisableFeature(network::features::kFirstPartySets);
|
||||
auto service =
|
||||
std::make_unique<component_updater::MockComponentUpdateService>();
|
||||
EXPECT_CALL(*service, RegisterComponent(_)).Times(0);
|
||||
RegisterFirstPartySetsComponent(service.get());
|
||||
|
||||
env_.RunUntilIdle();
|
||||
}
|
||||
|
||||
TEST_F(FirstPartySetsComponentInstallerTest, LoadsSets) {
|
||||
base::test::ScopedFeatureList scoped_list;
|
||||
scoped_list.InitAndEnableFeature(network::features::kFirstPartySets);
|
||||
|
||||
SEQUENCE_CHECKER(sequence_checker);
|
||||
const std::string expectation = "some first party sets";
|
||||
base::RunLoop run_loop;
|
||||
auto policy = std::make_unique<FirstPartySetsComponentInstallerPolicy>(
|
||||
base::BindLambdaForTesting([&](const std::string& got) {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker);
|
||||
EXPECT_EQ(got, expectation);
|
||||
run_loop.Quit();
|
||||
}));
|
||||
|
||||
ASSERT_TRUE(
|
||||
base::WriteFile(FirstPartySetsComponentInstallerPolicy::GetInstalledPath(
|
||||
component_install_dir_.GetPath()),
|
||||
expectation));
|
||||
|
||||
policy->ComponentReady(base::Version(), component_install_dir_.GetPath(),
|
||||
std::make_unique<base::DictionaryValue>());
|
||||
|
||||
run_loop.Run();
|
||||
}
|
||||
|
||||
} // namespace component_updater
|
@ -13,6 +13,7 @@
|
||||
#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/first_party_sets_component_installer.h"
|
||||
#include "chrome/browser/component_updater/floc_blocklist_component_installer.h"
|
||||
#include "chrome/browser/component_updater/games_component_installer.h"
|
||||
#include "chrome/browser/component_updater/mei_preload_component_installer.h"
|
||||
@ -126,6 +127,7 @@ void RegisterComponentsForUpdate(bool is_off_the_record_profile,
|
||||
cus, g_browser_process->GetApplicationLocale());
|
||||
RegisterOptimizationHintsComponent(cus, is_off_the_record_profile);
|
||||
RegisterTrustTokenKeyCommitmentsComponentIfTrustTokensEnabled(cus);
|
||||
RegisterFirstPartySetsComponent(cus);
|
||||
|
||||
base::FilePath path;
|
||||
if (base::PathService::Get(chrome::DIR_USER_DATA, &path)) {
|
||||
|
@ -3259,6 +3259,7 @@ test("unit_tests") {
|
||||
"../browser/component_updater/autofill_states_component_installer_unittest.cc",
|
||||
"../browser/component_updater/chrome_component_updater_configurator_unittest.cc",
|
||||
"../browser/component_updater/crl_set_component_installer_unittest.cc",
|
||||
"../browser/component_updater/first_party_sets_component_installer_unittest.cc",
|
||||
"../browser/component_updater/floc_blocklist_component_installer_unittest.cc",
|
||||
"../browser/component_updater/games_component_installer_unittest.cc",
|
||||
"../browser/component_updater/optimization_hints_component_installer_unittest.cc",
|
||||
|
@ -251,5 +251,9 @@ const base::Feature kSCTAuditing{"SCTAuditing",
|
||||
constexpr base::FeatureParam<double> kSCTAuditingSamplingRate{
|
||||
&kSCTAuditing, "sampling_rate", 0.0};
|
||||
|
||||
// Enables usage of First Party Sets to determine cookie availability.
|
||||
constexpr base::Feature kFirstPartySets{"FirstPartySets",
|
||||
base::FEATURE_DISABLED_BY_DEFAULT};
|
||||
|
||||
} // namespace features
|
||||
} // namespace network
|
||||
|
@ -102,6 +102,9 @@ extern const base::Feature kSCTAuditing;
|
||||
COMPONENT_EXPORT(NETWORK_CPP)
|
||||
extern const base::FeatureParam<double> kSCTAuditingSamplingRate;
|
||||
|
||||
COMPONENT_EXPORT(NETWORK_CPP)
|
||||
extern const base::Feature kFirstPartySets;
|
||||
|
||||
} // namespace features
|
||||
} // namespace network
|
||||
|
||||
|
Reference in New Issue
Block a user