910e62b5创建于 1月15日历史提交
// Copyright 2024 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/extensions/api/proxy/proxy_pref_transformer.h"

#include <optional>
#include <string>

#include "base/logging.h"
#include "base/notreached.h"
#include "base/values.h"
#include "chrome/browser/extensions/api/proxy/proxy_api_constants.h"
#include "chrome/browser/extensions/api/proxy/proxy_api_helpers.h"
#include "components/proxy_config/proxy_config_dictionary.h"
#include "components/proxy_config/proxy_prefs.h"
#include "extensions/buildflags/buildflags.h"

static_assert(BUILDFLAG(ENABLE_EXTENSIONS_CORE));

namespace extensions {

ProxyPrefTransformer::ProxyPrefTransformer() = default;

ProxyPrefTransformer::~ProxyPrefTransformer() = default;

std::optional<base::Value> ProxyPrefTransformer::ExtensionToBrowserPref(
    const base::Value& extension_pref,
    std::string& error,
    bool& bad_message) {
  // When ExtensionToBrowserPref is called, the format of |extension_pref|
  // has been verified already by the extension API to match the schema
  // defined in the extension API JSON.
  CHECK(extension_pref.is_dict());
  const base::Value::Dict& config = extension_pref.GetDict();
  // Extract the various pieces of information passed to
  // chrome.proxy.settings.set(). Several of these strings will
  // remain blank no respective values have been passed to set().
  // If a values has been passed to set but could not be parsed, we bail
  // out and return null.
  ProxyPrefs::ProxyMode mode_enum;
  bool pac_mandatory;
  std::string pac_url;
  std::string pac_data;
  std::string proxy_rules_string;
  std::string bypass_list;
  if (!proxy_api_helpers::GetProxyModeFromExtensionPref(config, &mode_enum,
                                                        &error, &bad_message) ||
      !proxy_api_helpers::GetPacMandatoryFromExtensionPref(
          config, &pac_mandatory, &error, &bad_message) ||
      !proxy_api_helpers::GetPacUrlFromExtensionPref(config, &pac_url, &error,
                                                     &bad_message) ||
      !proxy_api_helpers::GetPacDataFromExtensionPref(config, &pac_data, &error,
                                                      &bad_message) ||
      !proxy_api_helpers::GetProxyRulesStringFromExtensionPref(
          config, &proxy_rules_string, &error, &bad_message) ||
      !proxy_api_helpers::GetBypassListFromExtensionPref(
          config, &bypass_list, &error, &bad_message)) {
    return std::nullopt;
  }

  std::optional<base::Value::Dict> result =
      proxy_api_helpers::CreateProxyConfigDict(
          mode_enum, pac_mandatory, pac_url, pac_data, proxy_rules_string,
          bypass_list, &error);

  if (!result) {
    return std::nullopt;
  }

  return base::Value(std::move(*result));
}

std::optional<base::Value> ProxyPrefTransformer::BrowserToExtensionPref(
    const base::Value& browser_pref,
    bool is_incognito_profile) {
  CHECK(browser_pref.is_dict());

  // This is a dictionary wrapper that exposes the proxy configuration stored in
  // the browser preferences.
  ProxyConfigDictionary config(browser_pref.GetDict().Clone());

  ProxyPrefs::ProxyMode mode;
  if (!config.GetMode(&mode)) {
    LOG(ERROR) << "Cannot determine proxy mode.";
    return std::nullopt;
  }

  // Build a new ProxyConfig instance as defined in the extension API.
  base::Value::Dict extension_pref;

  extension_pref.Set(proxy_api_constants::kProxyConfigMode,
                     ProxyPrefs::ProxyModeToString(mode));

  switch (mode) {
    case ProxyPrefs::MODE_DIRECT:
    case ProxyPrefs::MODE_AUTO_DETECT:
    case ProxyPrefs::MODE_SYSTEM:
      // These modes have no further parameters.
      break;
    case ProxyPrefs::MODE_PAC_SCRIPT: {
      // A PAC URL either point to a PAC script or contain a base64 encoded
      // PAC script. In either case we build a PacScript dictionary as defined
      // in the extension API.
      std::optional<base::Value::Dict> pac_dict =
          proxy_api_helpers::CreatePacScriptDict(config);
      if (!pac_dict) {
        return std::nullopt;
      }
      extension_pref.Set(proxy_api_constants::kProxyConfigPacScript,
                         std::move(*pac_dict));
      break;
    }
    case ProxyPrefs::MODE_FIXED_SERVERS: {
      // Build ProxyRules dictionary according to the extension API.
      std::optional<base::Value::Dict> proxy_rules_dict =
          proxy_api_helpers::CreateProxyRulesDict(config);
      if (!proxy_rules_dict) {
        return std::nullopt;
      }
      extension_pref.Set(proxy_api_constants::kProxyConfigRules,
                         std::move(*proxy_rules_dict));
      break;
    }
    case ProxyPrefs::kModeCount:
      NOTREACHED();
  }
  return base::Value(std::move(extension_pref));
}

}  // namespace extensions