910e62b5创建于 1月15日历史提交
// Copyright 2022 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/commerce_heuristics_component_installer.h"

#include <stdint.h>

#include <memory>
#include <string>
#include <vector>

#include "base/feature_list.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/functional/callback.h"
#include "base/logging.h"
#include "base/task/thread_pool.h"
#include "components/commerce/core/commerce_heuristics_data.h"
#include "components/component_updater/component_updater_paths.h"
#if !BUILDFLAG(IS_ANDROID)
#include "chrome/browser/new_tab_page/new_tab_page_util.h"
#include "components/search/ntp_features.h"
#else
#include "components/commerce/core/commerce_feature_list.h"
#endif

namespace {

// The SHA256 of the SubjectPublicKeyInfo used to sign the extension.
// The extension id is: cocncanleafgejenidihemfflagifjic
const uint8_t kCommerceHeuristicsPublicKeySHA256[32] = {
    0x2e, 0x2d, 0x20, 0xdb, 0x40, 0x56, 0x49, 0x4d, 0x83, 0x87, 0x4c,
    0x55, 0xb0, 0x68, 0x59, 0x82, 0xb6, 0x0d, 0xad, 0xaf, 0xcd, 0xa8,
    0x49, 0xb8, 0x61, 0x7a, 0x32, 0x38, 0xe0, 0x72, 0x2a, 0x10};

constexpr char kCommerceHeuristicsManifestName[] = "Commerce Heuristics";
constexpr base::FilePath::CharType kCommerceHintHeuristicsFileName[] =
    FILE_PATH_LITERAL("commerce_hint_heuristics.json");
constexpr base::FilePath::CharType kCommerceGlobalHeuristicsFileName[] =
    FILE_PATH_LITERAL("commerce_global_heuristics.json");
constexpr base::FilePath::CharType kCommerceProductIDHeuristicsFileName[] =
    FILE_PATH_LITERAL("commerce_product_id_heuristics.json");
constexpr base::FilePath::CharType kCommerceCartExtractionScriptFileName[] =
    FILE_PATH_LITERAL("cart_product_extraction.js");

base::FilePath GetCommerceHintHeuristicsInstalledPath(
    const base::FilePath& base) {
  return base.Append(kCommerceHintHeuristicsFileName);
}

base::FilePath GetCommerceGlobalHeuristicsInstalledPath(
    const base::FilePath& base) {
  return base.Append(kCommerceGlobalHeuristicsFileName);
}

base::FilePath GetCommerceProductIDHeuristicsInstalledPath(
    const base::FilePath& base) {
  return base.Append(kCommerceProductIDHeuristicsFileName);
}

base::FilePath GetCommerceCartExtractionScriptInstalledPath(
    const base::FilePath& base) {
  return base.Append(kCommerceCartExtractionScriptFileName);
}

void LoadHeuristicFilesFromDisk(const base::Version& version,
                                const base::FilePath& install_dir) {
  if (install_dir.empty()) {
    return;
  }

  const base::FilePath& commerce_hint_file_path =
      GetCommerceHintHeuristicsInstalledPath(install_dir);
  const base::FilePath& commerce_global_file_path =
      GetCommerceGlobalHeuristicsInstalledPath(install_dir);
  const base::FilePath& commerce_product_id_file_path =
      GetCommerceProductIDHeuristicsInstalledPath(install_dir);
  const base::FilePath& cart_extraction_file_path =
      GetCommerceCartExtractionScriptInstalledPath(install_dir);
  if (commerce_global_file_path.empty() || commerce_global_file_path.empty() ||
      commerce_product_id_file_path.empty() ||
      cart_extraction_file_path.empty()) {
    return;
  }

  std::string commerce_hint_json_data;
  std::string commerce_global_json_data;
  std::string commerce_product_id_json_data;
  std::string cart_extraction_script_data;

  if (!base::ReadFileToString(commerce_hint_file_path,
                              &commerce_hint_json_data)) {
    LOG(WARNING) << "Failed reading from " << commerce_hint_file_path.value();
    return;
  }
  if (!base::ReadFileToString(commerce_global_file_path,
                              &commerce_global_json_data)) {
    LOG(WARNING) << "Failed reading from " << commerce_global_file_path.value();
    return;
  }
  if (!base::ReadFileToString(commerce_product_id_file_path,
                              &commerce_product_id_json_data)) {
    LOG(WARNING) << "Failed reading from "
                 << commerce_product_id_file_path.value();
    return;
  }
  if (!base::ReadFileToString(cart_extraction_file_path,
                              &cart_extraction_script_data)) {
    LOG(WARNING) << "Failed reading from " << cart_extraction_file_path.value();
    return;
  }

  if (!commerce_heuristics::CommerceHeuristicsData::GetInstance()
           .PopulateDataFromComponent(std::move(commerce_hint_json_data),
                                      std::move(commerce_global_json_data),
                                      std::move(commerce_product_id_json_data),
                                      std::move(cart_extraction_script_data))) {
    LOG(WARNING) << "Failed populating data.";
    return;
  }
  commerce_heuristics::CommerceHeuristicsData::GetInstance().UpdateVersion(
      version);
}

}  // namespace

namespace component_updater {

bool CommerceHeuristicsInstallerPolicy::
    SupportsGroupPolicyEnabledComponentUpdates() const {
  return false;
}

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

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

void CommerceHeuristicsInstallerPolicy::OnCustomUninstall() {}

void CommerceHeuristicsInstallerPolicy::ComponentReady(
    const base::Version& version,
    const base::FilePath& install_dir,
    base::Value::Dict manifest) {
  VLOG(1) << "Component ready, version " << version.GetString() << " in "
          << install_dir.value();

  base::ThreadPool::PostTask(
      FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
      base::BindOnce(&LoadHeuristicFilesFromDisk, version, install_dir));
}

// Called during startup and installation before ComponentReady().
bool CommerceHeuristicsInstallerPolicy::VerifyInstallation(
    const base::Value::Dict& manifest,
    const base::FilePath& install_dir) const {
  return base::PathExists(
             GetCommerceGlobalHeuristicsInstalledPath(install_dir)) &&
         base::PathExists(GetCommerceHintHeuristicsInstalledPath(install_dir));
}

base::FilePath CommerceHeuristicsInstallerPolicy::GetRelativeInstallDir()
    const {
  return base::FilePath::FromUTF8Unsafe("CommerceHeuristics");
}

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

std::string CommerceHeuristicsInstallerPolicy::GetName() const {
  return kCommerceHeuristicsManifestName;
}

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

void RegisterCommerceHeuristicsComponent(
    component_updater::ComponentUpdateService* cus) {
#if !BUILDFLAG(IS_ANDROID)
  if (IsCartModuleEnabled())
#endif
  {
    VLOG(1) << "Registering Commerce Heuristics component.";
    auto installer = base::MakeRefCounted<ComponentInstaller>(
        std::make_unique<CommerceHeuristicsInstallerPolicy>());
    installer->Register(cus, base::OnceClosure());
  }
}

}  // namespace component_updater