Skip to content

Commit

Permalink
Create new UrlParamClassificationComponentInstaller class.
Browse files Browse the repository at this point in the history
This class will receive classification lists and validate them.
If the list is valid, it will be provided to the
url_param_filter::ClassificationsLoader.

The validation of classification lists occurs in VerifyInstallation, and
the results of this are outputted to a new "Navigation.UrlParamFilter.
ClassificationListValidationResult" histogram.

Change-Id: Ic1cacf585c7dd61992919dd9f9e4f278496d3f11
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3537547
Reviewed-by: Matt Reichhoff <mreichhoff@chromium.org>
Reviewed-by: Joshua Pawlicki <waffles@chromium.org>
Reviewed-by: Ben Kelly <wanderview@chromium.org>
Commit-Queue: Kirubel Aklilu <kaklilu@chromium.org>
Cr-Commit-Position: refs/heads/main@{#987087}
  • Loading branch information
Kirubel Aklilu authored and Chromium LUCI CQ committed Mar 30, 2022
1 parent cf5bdde commit 355b5e4
Show file tree
Hide file tree
Showing 10 changed files with 692 additions and 42 deletions.
2 changes: 2 additions & 0 deletions chrome/browser/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,8 @@ static_library("browser") {
"component_updater/subresource_filter_component_installer.h",
"component_updater/trust_token_key_commitments_component_installer.cc",
"component_updater/trust_token_key_commitments_component_installer.h",
"component_updater/url_param_classification_component_installer.cc",
"component_updater/url_param_classification_component_installer.h",
"consent_auditor/consent_auditor_factory.cc",
"consent_auditor/consent_auditor_factory.h",
"content_index/content_index_metrics.cc",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
// Copyright 2022 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/url_param_classification_component_installer.h"

#include "base/bind.h"
#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/metrics/histogram_functions.h"
#include "base/path_service.h"
#include "base/task/post_task.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/version.h"
#include "chrome/browser/url_param_filter/url_param_classifications_loader.h"
#include "chrome/common/chrome_features.h"
#include "components/component_updater/component_updater_paths.h"
#include "content/public/browser/browser_task_traits.h"
#include "third_party/abseil-cpp/absl/types/optional.h"

using component_updater::ComponentUpdateService;

namespace {

const base::FilePath::CharType kUrlParamClassificationsFileName[] =
FILE_PATH_LITERAL("url_param_classifications.pb");

// The SHA256 of the SubjectPublicKeyInfo used to sign the extension.
// The extension id is: dnhnnofocefcglhjeigmkhcgfoaipbaa
const uint8_t kUrlParamClassificationsPublicKeySHA256[32] = {
0x3d, 0x7d, 0xde, 0x5e, 0x24, 0x52, 0x6b, 0x79, 0x48, 0x6c, 0xa7,
0x26, 0x5e, 0x08, 0xf1, 0x00, 0x82, 0x56, 0x69, 0xb1, 0xca, 0xfc,
0x8a, 0x25, 0x50, 0x06, 0x6b, 0x5f, 0xa1, 0xd5, 0xeb, 0x80};

const char kUrlParamClassificationManifestName[] = "Url Param Classifications";

// Runs on a thread pool.
absl::optional<std::string> LoadFileFromDisk(const base::FilePath& pb_path) {
VLOG(1) << "Reading Url Param Classifications from file: " << pb_path.value();
std::string file_contents;
if (!base::ReadFileToString(pb_path, &file_contents)) {
// The file won't exist on new installations, so this is not always an
// error.
VLOG(1) << "Failed reading from " << pb_path.value();
return absl::nullopt;
}
return file_contents;
}

// Writes a metric denoting the |result| of validating a classification list.
//
// This method is called in VerifyInstallation which returns false (on an error)
// or true (if the whole list is valid), so the metrics will be populated at
// most once per version installed.
void WriteMetrics(
component_updater::UrlParamClassificationComponentInstallerPolicy::
ClassificationListValidationResult result) {
base::UmaHistogramEnumeration(
"Navigation.UrlParamFilter.ClassificationListValidationResult", result);
}

} // namespace

namespace component_updater {

UrlParamClassificationComponentInstallerPolicy::
UrlParamClassificationComponentInstallerPolicy(
component_updater::OnUrlParamClassificationComponentReady
on_component_ready)
: on_component_ready_(on_component_ready) {}

UrlParamClassificationComponentInstallerPolicy::
~UrlParamClassificationComponentInstallerPolicy() = default;

bool UrlParamClassificationComponentInstallerPolicy::
SupportsGroupPolicyEnabledComponentUpdates() const {
return true;
}

bool UrlParamClassificationComponentInstallerPolicy::RequiresNetworkEncryption()
const {
return false;
}

update_client::CrxInstaller::Result
UrlParamClassificationComponentInstallerPolicy::OnCustomInstall(
const base::Value& manifest,
const base::FilePath& install_dir) {
return update_client::CrxInstaller::Result(0); // Nothing custom here.
}

void UrlParamClassificationComponentInstallerPolicy::OnCustomUninstall() {}

base::FilePath UrlParamClassificationComponentInstallerPolicy::GetInstalledPath(
const base::FilePath& base) {
return base.Append(kUrlParamClassificationsFileName);
}

void UrlParamClassificationComponentInstallerPolicy::ComponentReady(
const base::Version& version,
const base::FilePath& install_dir,
base::Value manifest) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
VLOG(1) << "Component ready, version " << version.GetString() << " in "
<< install_dir.value();
if (base::FeatureList::IsEnabled(features::kIncognitoParamFilterEnabled)) {
// 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(&LoadFileFromDisk, GetInstalledPath(install_dir)),
base::BindOnce(
[](OnUrlParamClassificationComponentReady callback,
const absl::optional<std::string>& maybe_file) {
if (maybe_file.has_value())
callback.Run(maybe_file.value());
},
on_component_ready_));
}
}

// Called during startup and installation before ComponentReady().
bool UrlParamClassificationComponentInstallerPolicy::VerifyInstallation(
const base::Value& manifest,
const base::FilePath& install_dir) const {
if (!base::PathExists(GetInstalledPath(install_dir))) {
WriteMetrics(
ClassificationListValidationResult::kMissingClassificationsFile);
return false;
}

std::string file_contents;
if (!base::ReadFileToString(GetInstalledPath(install_dir), &file_contents)) {
WriteMetrics(
ClassificationListValidationResult::kReadingClassificationsFileFailed);
return false;
}

url_param_filter::FilterClassifications classification_list;
if (!classification_list.ParseFromString(file_contents)) {
WriteMetrics(ClassificationListValidationResult::kParsingToProtoFailed);
return false;
}

std::vector<url_param_filter::FilterClassification> source_classifications,
destination_classifications;
for (const url_param_filter::FilterClassification& fc :
classification_list.classifications()) {
if (!fc.has_site()) {
WriteMetrics(
ClassificationListValidationResult::kClassificationMissingSite);
return false;
}

if (!fc.has_site_role()) {
WriteMetrics(
ClassificationListValidationResult::kClassificationMissingSiteRole);
return false;
}

if (fc.site_role() ==
url_param_filter::FilterClassification_SiteRole_SOURCE) {
source_classifications.push_back(fc);
}

if (fc.site_role() ==
url_param_filter::FilterClassification_SiteRole_DESTINATION) {
destination_classifications.push_back(fc);
}
}

WriteMetrics(ClassificationListValidationResult::kSuccessful);
return true;
}

base::FilePath
UrlParamClassificationComponentInstallerPolicy::GetRelativeInstallDir() const {
return base::FilePath(FILE_PATH_LITERAL("UrlParamClassifications"));
}

void UrlParamClassificationComponentInstallerPolicy::GetHash(
std::vector<uint8_t>* hash) const {
hash->assign(std::begin(kUrlParamClassificationsPublicKeySHA256),
std::end(kUrlParamClassificationsPublicKeySHA256));
}

std::string UrlParamClassificationComponentInstallerPolicy::GetName() const {
return kUrlParamClassificationManifestName;
}

update_client::InstallerAttributes
UrlParamClassificationComponentInstallerPolicy::GetInstallerAttributes() const {
return update_client::InstallerAttributes();
}

void RegisterUrlParamClassificationComponent(ComponentUpdateService* cus) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
// Register the component even if feature isn't enabled so that when it is
// enabled in the future, the component is already installed.
VLOG(1) << "Registering Url Param Classifications component.";
auto installer = base::MakeRefCounted<ComponentInstaller>(
std::make_unique<UrlParamClassificationComponentInstallerPolicy>(
base::BindRepeating([](std::string raw_classifications) {
url_param_filter::ClassificationsLoader::GetInstance()
->ReadClassifications(raw_classifications);
})));
installer->Register(cus, base::OnceClosure());
}

} // namespace component_updater
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// Copyright 2022 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_URL_PARAM_CLASSIFICATION_COMPONENT_INSTALLER_H_
#define CHROME_BROWSER_COMPONENT_UPDATER_URL_PARAM_CLASSIFICATION_COMPONENT_INSTALLER_H_

#include "base/callback.h"
#include "base/files/file_path.h"
#include "base/values.h"
#include "components/component_updater/component_installer.h"

namespace component_updater {

class ComponentUpdateService;

using OnUrlParamClassificationComponentReady =
base::RepeatingCallback<void(std::string)>;

class UrlParamClassificationComponentInstallerPolicy
: public ComponentInstallerPolicy {
public:
// The result of reading and validating the UrlParamFilterClassification list
// from Component Updater.
//
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class ClassificationListValidationResult {
// No invalid classifications were found in the list.
kSuccessful = 0,
// The file wasn't present.
kMissingClassificationsFile = 1,
// Reading from the classifications file failed.
kReadingClassificationsFileFailed = 2,
// The raw classifications string was unabled to be parsed into the proto.
kParsingToProtoFailed = 3,
// Classification was ignored due to missing required site name.
kClassificationMissingSite = 4,
// Classification was ignored due to missing required site role.
kClassificationMissingSiteRole = 5,
kMaxValue = kClassificationMissingSiteRole,
};

explicit UrlParamClassificationComponentInstallerPolicy(
OnUrlParamClassificationComponentReady on_component_ready);
~UrlParamClassificationComponentInstallerPolicy() override;

UrlParamClassificationComponentInstallerPolicy(
const UrlParamClassificationComponentInstallerPolicy&) = delete;
UrlParamClassificationComponentInstallerPolicy& operator=(
const UrlParamClassificationComponentInstallerPolicy&) = delete;

private:
FRIEND_TEST_ALL_PREFIXES(UrlParamClassificationComponentInstallerTest,
VerifyAttributes);

// The following methods override ComponentInstallerPolicy.
bool SupportsGroupPolicyEnabledComponentUpdates() const override;
bool RequiresNetworkEncryption() const override;
update_client::CrxInstaller::Result OnCustomInstall(
const base::Value& manifest,
const base::FilePath& install_dir) override;
void OnCustomUninstall() override;
bool VerifyInstallation(const base::Value& manifest,
const base::FilePath& install_dir) const override;
void ComponentReady(const base::Version& version,
const base::FilePath& install_dir,
base::Value 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;

static base::FilePath GetInstalledPath(const base::FilePath& base);
void MaybeFireCallback(
const absl::optional<std::string>& maybe_classifications);

OnUrlParamClassificationComponentReady on_component_ready_;
};

// Call once during startup to make the component update service aware of
// the Url Param Classification component.
void RegisterUrlParamClassificationComponent(ComponentUpdateService* cus);

} // namespace component_updater

#endif // CHROME_BROWSER_COMPONENT_UPDATER_URL_PARAM_CLASSIFICATION_COMPONENT_INSTALLER_H_

0 comments on commit 355b5e4

Please sign in to comment.