chromium/chrome/browser/component_updater/third_party_module_list_component_installer_win.cc

// Copyright 2017 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/third_party_module_list_component_installer_win.h"

#include <iterator>
#include <utility>

#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/not_fatal_until.h"
#include "base/ranges/algorithm.h"
#include "base/values.h"
#include "base/version.h"
#include "chrome/browser/win/conflicts/module_blocklist_cache_util.h"
#include "chrome/browser/win/conflicts/module_database.h"
#include "chrome/browser/win/conflicts/third_party_conflicts_manager.h"

namespace component_updater {

namespace {

// The relative path of the expected module list file inside of an installation
// of this component.
constexpr base::FilePath::CharType kRelativeModuleListPath[] =
    FILE_PATH_LITERAL("module_list_proto");

constexpr char kComponentId[] = "ehgidpndbllacpjalkiimkbadgjfnnmc";

base::Version GetComponentVersion(
    const ComponentUpdateService* component_update_service) {
  DCHECK(component_update_service);

  auto components = component_update_service->GetComponents();
  auto iter = base::ranges::find(components, kComponentId, &ComponentInfo::id);
  CHECK(iter != components.end(), base::NotFatalUntil::M130);

  return iter->version;
}

void OnModuleListComponentReady(const base::FilePath& module_list_path) {
  DCHECK(ModuleDatabase::GetTaskRunner()->RunsTasksInCurrentSequence());

  ThirdPartyConflictsManager* manager =
      ModuleDatabase::GetInstance()->third_party_conflicts_manager();
  if (!manager) {
    return;
  }

  manager->LoadModuleList(module_list_path);
}

void OnModuleListComponentRegistered(const base::Version& component_version) {
  DCHECK(ModuleDatabase::GetTaskRunner()->RunsTasksInCurrentSequence());

  // Notify the ThirdPartyConflictsManager.
  ThirdPartyConflictsManager* manager =
      ModuleDatabase::GetInstance()->third_party_conflicts_manager();
  if (!manager) {
    return;
  }

  manager->OnModuleListComponentRegistered(kComponentId, component_version);
}

}  // namespace

// The SHA256 of the SubjectPublicKeyInfo used to sign the component.
constexpr uint8_t kThirdPartyModuleListPublicKeySHA256[32] = {
    0x47, 0x68, 0x3f, 0xd3, 0x1b, 0xb0, 0x2f, 0x90, 0xba, 0x88, 0xca,
    0x10, 0x36, 0x95, 0xdd, 0xc2, 0x29, 0xd1, 0x4f, 0x38, 0xf2, 0x9d,
    0x6c, 0x9c, 0x68, 0x6c, 0xa2, 0xa4, 0xa2, 0x8e, 0xa5, 0x5c};

// The name of the component. This is used in the chrome://components page.
constexpr char kThirdPartyModuleListName[] = "Third Party Module List";

ThirdPartyModuleListComponentInstallerPolicy::
    ThirdPartyModuleListComponentInstallerPolicy() = default;

ThirdPartyModuleListComponentInstallerPolicy::
    ~ThirdPartyModuleListComponentInstallerPolicy() = default;

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

bool ThirdPartyModuleListComponentInstallerPolicy::RequiresNetworkEncryption()
    const {
  // Public data is delivered via this component, no need for encryption.
  return false;
}

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

void ThirdPartyModuleListComponentInstallerPolicy::OnCustomUninstall() {}

// NOTE: This is always called on the main UI thread. It is called once every
// startup to notify of an already installed component, and may be called
// repeatedly after that every time a new component is ready.
void ThirdPartyModuleListComponentInstallerPolicy::ComponentReady(
    const base::Version& version,
    const base::FilePath& install_dir,
    base::Value::Dict manifest) {
  // Forward the notification to the ThirdPartyConflictsManager on the
  // ModuleDatabase task runner. The manager is responsible for the work of
  // actually loading the module list, etc, on background threads.
  ModuleDatabase::GetTaskRunner()->PostTask(
      FROM_HERE, base::BindOnce(&OnModuleListComponentReady,
                                GetModuleListPath(install_dir)));
}

bool ThirdPartyModuleListComponentInstallerPolicy::VerifyInstallation(
    const base::Value::Dict& manifest,
    const base::FilePath& install_dir) const {
  // This is called during startup and installation before ComponentReady().
  // The component is considered valid if the expected file exists in the
  // installation.
  return base::PathExists(GetModuleListPath(install_dir));
}

base::FilePath
ThirdPartyModuleListComponentInstallerPolicy::GetRelativeInstallDir() const {
  return base::FilePath(kModuleListComponentRelativePath);
}

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

std::string ThirdPartyModuleListComponentInstallerPolicy::GetName() const {
  return kThirdPartyModuleListName;
}

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

// static
base::FilePath ThirdPartyModuleListComponentInstallerPolicy::GetModuleListPath(
    const base::FilePath& install_dir) {
  return install_dir.Append(kRelativeModuleListPath);
}

void RegisterThirdPartyModuleListComponent(
    ComponentUpdateService* component_update_service) {
  DVLOG(1) << "Registering Third Party Module List component.";

  auto installer = base::MakeRefCounted<ComponentInstaller>(
      std::make_unique<ThirdPartyModuleListComponentInstallerPolicy>());
  installer->Register(
      component_update_service,
      base::BindOnce(
          [](ComponentUpdateService* component_update_service) {
            ModuleDatabase::GetTaskRunner()->PostTask(
                FROM_HERE,
                base::BindOnce(&OnModuleListComponentRegistered,
                               GetComponentVersion(component_update_service)));
          },
          component_update_service));
}

}  // namespace component_updater