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 "google_apis/api_key_cache.h"

#include <stddef.h>

#include <algorithm>
#include <memory>
#include <string>

#include "base/command_line.h"
#include "base/environment.h"
#include "base/feature_list.h"
#include "base/features.h"
#include "base/logging.h"
#include "base/metrics/field_trial_params.h"
#include "base/metrics/histogram_functions.h"
#include "base/strings/stringize_macros.h"
#include "build/branding_buildflags.h"
#include "build/build_config.h"
#include "google_apis/buildflags.h"
#include "google_apis/default_api_keys.h"
#include "google_apis/gaia/gaia_config.h"
#include "google_apis/gaia/gaia_switches.h"

#if BUILDFLAG(IS_APPLE)
#include "google_apis/google_api_keys_mac.h"
#endif

namespace google_apis {

namespace {

// Gets a value for a key.  In priority order, this will be the value
// provided via:
// 1. Command-line switch
// 2. Config file
// 3. Environment variable
// 4. On macOS and iOS, the value passed in Info.plist
// 5. Baked into the build.
// |command_line_switch| may be NULL. Official Google Chrome builds will not
// use the value provided by an environment variable.
static std::string CalculateKeyValue(
    const char* baked_in_value,
    base::cstring_view environment_variable_name,
    const char* command_line_switch,
    const std::string& default_if_unset,
    base::Environment* environment,
    base::CommandLine* command_line,
    GaiaConfig* gaia_config,
    bool allow_override_via_environment,
    bool allow_unset_values) {
  std::string key_value = baked_in_value;
  std::string temp;
#if BUILDFLAG(IS_APPLE)
  // macOS and iOS can also override the API key with a value from the
  // Info.plist.
  temp = GetAPIKeyFromInfoPlist(environment_variable_name);
  if (!temp.empty()) {
    key_value = temp;
    VLOG(1) << "Overriding API key " << environment_variable_name
            << " with value from Info.plist.";
  }
#endif

  if (allow_override_via_environment) {
    // Don't allow using the environment to override API keys for official
    // Google Chrome builds. There have been reports of mangled environments
    // affecting users (crbug.com/710575).
    if (auto maybe_key_value = environment->GetVar(environment_variable_name);
        maybe_key_value.has_value()) {
      key_value = *maybe_key_value;
      VLOG(1) << "Overriding API key " << environment_variable_name
              << " with value " << key_value << " from environment variable.";
    }
  }

  if (gaia_config &&
      gaia_config->GetAPIKeyIfExists(environment_variable_name, &temp)) {
    key_value = temp;
    VLOG(1) << "Overriding API key " << environment_variable_name
            << " with value " << key_value << " from gaia config.";
  }

  if (command_line_switch && command_line->HasSwitch(command_line_switch)) {
    key_value = command_line->GetSwitchValueASCII(command_line_switch);
    VLOG(1) << "Overriding API key " << environment_variable_name
            << " with value " << key_value << " from command-line switch.";
  }

  if (key_value == DefaultApiKeys::kUnsetApiToken) {
    // No key should be unset in an official build except the
    // GOOGLE_DEFAULT_* keys. The default keys don't trigger this
    // check as their "unset" value is not DefaultApiKeys::kUnsetApiToken.
    CHECK(allow_unset_values);
    if (default_if_unset.size() > 0) {
      VLOG(1) << "Using default value \"" << default_if_unset
              << "\" for API key " << environment_variable_name;
      key_value = default_if_unset;
    }
  }

  // This should remain a debug-only log.
  DVLOG(1) << "API key " << environment_variable_name << "=" << key_value;

  return key_value;
}
}  // namespace

ApiKeyCache::ApiKeyCache(const DefaultApiKeys& default_api_keys) {
  std::unique_ptr<base::Environment> environment(base::Environment::Create());
  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
  GaiaConfig* gaia_config = GaiaConfig::GetInstance();

  api_key_ = CalculateKeyValue(
      default_api_keys.google_api_key, STRINGIZE_NO_EXPANSION(GOOGLE_API_KEY),
      nullptr, std::string(), environment.get(), command_line, gaia_config,
      default_api_keys.allow_override_via_environment,
      default_api_keys.allow_unset_values);

// A special non-stable key is at the moment defined only for Android Chrome.
#if BUILDFLAG(IS_ANDROID)
  api_key_non_stable_ = CalculateKeyValue(
      default_api_keys.google_api_key_android_non_stable,
      STRINGIZE_NO_EXPANSION(GOOGLE_API_KEY_ANDROID_NON_STABLE), nullptr,
      std::string(), environment.get(), command_line, gaia_config,
      default_api_keys.allow_override_via_environment,
      default_api_keys.allow_unset_values);
#else
  api_key_non_stable_ = api_key_;
#endif

  api_key_remoting_ = CalculateKeyValue(
      default_api_keys.google_api_key_remoting,
      STRINGIZE_NO_EXPANSION(GOOGLE_API_KEY_REMOTING), nullptr, std::string(),
      environment.get(), command_line, gaia_config,
      default_api_keys.allow_override_via_environment,
      default_api_keys.allow_unset_values);

  api_key_soda_ = CalculateKeyValue(
      default_api_keys.google_api_key_soda,
      STRINGIZE_NO_EXPANSION(GOOGLE_API_KEY_SODA), nullptr, std::string(),
      environment.get(), command_line, gaia_config,
      default_api_keys.allow_override_via_environment,
      default_api_keys.allow_unset_values);
#if !BUILDFLAG(IS_ANDROID)
  api_key_hats_ = CalculateKeyValue(
      default_api_keys.google_api_key_hats,
      STRINGIZE_NO_EXPANSION(GOOGLE_API_KEY_HATS), nullptr, std::string(),
      environment.get(), command_line, gaia_config,
      default_api_keys.allow_override_via_environment,
      default_api_keys.allow_unset_values);
#endif

#if BUILDFLAG(IS_CHROMEOS)
  api_key_sharing_ = CalculateKeyValue(
      default_api_keys.google_api_key_sharing,
      STRINGIZE_NO_EXPANSION(GOOGLE_API_KEY_SHARING), nullptr, std::string(),
      environment.get(), command_line, gaia_config,
      default_api_keys.allow_override_via_environment,
      default_api_keys.allow_unset_values);

  api_key_read_aloud_ = CalculateKeyValue(
      default_api_keys.google_api_key_read_aloud,
      STRINGIZE_NO_EXPANSION(GOOGLE_API_KEY_READ_ALOUD), nullptr, std::string(),
      environment.get(), command_line, gaia_config,
      default_api_keys.allow_override_via_environment,
      default_api_keys.allow_unset_values);

  api_key_fresnel_ = CalculateKeyValue(
      default_api_keys.google_api_key_fresnel,
      STRINGIZE_NO_EXPANSION(GOOGLE_API_KEY_FRESNEL), nullptr, std::string(),
      environment.get(), command_line, gaia_config,
      default_api_keys.allow_override_via_environment,
      default_api_keys.allow_unset_values);

  api_key_boca_ = CalculateKeyValue(
      default_api_keys.google_api_key_boca,
      STRINGIZE_NO_EXPANSION(GOOGLE_API_KEY_BOCA), nullptr, std::string(),
      environment.get(), command_line, gaia_config,
      default_api_keys.allow_override_via_environment,
      default_api_keys.allow_unset_values);

  api_key_cros_system_geo_ = CalculateKeyValue(
      default_api_keys.google_api_key_cros_system_geo_,
      STRINGIZE_NO_EXPANSION(GOOGLE_API_KEY_CROS_SYSTEM_GEO), nullptr,
      std::string(), environment.get(), command_line, gaia_config,
      default_api_keys.allow_override_via_environment,
      default_api_keys.allow_unset_values);

  api_key_cros_chrome_geo_ = CalculateKeyValue(
      default_api_keys.google_api_key_cros_chrome_geo_,
      STRINGIZE_NO_EXPANSION(GOOGLE_API_KEY_CROS_CHROME_GEO), nullptr,
      std::string(), environment.get(), command_line, gaia_config,
      default_api_keys.allow_override_via_environment,
      default_api_keys.allow_unset_values);

#endif

  metrics_key_ = CalculateKeyValue(
      default_api_keys.google_metrics_signing_key,
      STRINGIZE_NO_EXPANSION(GOOGLE_METRICS_SIGNING_KEY), nullptr,
      std::string(), environment.get(), command_line, gaia_config,
      default_api_keys.allow_override_via_environment,
      default_api_keys.allow_unset_values);

  std::string default_client_id = CalculateKeyValue(
      default_api_keys.google_default_client_id,
      STRINGIZE_NO_EXPANSION(GOOGLE_DEFAULT_CLIENT_ID), nullptr, std::string(),
      environment.get(), command_line, gaia_config,
      default_api_keys.allow_override_via_environment,
      default_api_keys.allow_unset_values);
  std::string default_client_secret = CalculateKeyValue(
      default_api_keys.google_default_client_secret,
      STRINGIZE_NO_EXPANSION(GOOGLE_DEFAULT_CLIENT_SECRET), nullptr,
      std::string(), environment.get(), command_line, gaia_config,
      default_api_keys.allow_override_via_environment,
      default_api_keys.allow_unset_values);

  // We currently only allow overriding the baked-in values for the
  // default OAuth2 client ID and secret using a command-line
  // argument and gaia config, since that is useful to enable testing against
  // staging servers, and since that was what was possible and
  // likely practiced by the QA team before this implementation was
  // written.
  client_ids_[CLIENT_MAIN] =
      CalculateKeyValue(default_api_keys.google_client_id_main,
                        STRINGIZE_NO_EXPANSION(GOOGLE_CLIENT_ID_MAIN),
                        ::switches::kOAuth2ClientID, default_client_id,
                        environment.get(), command_line, gaia_config,
                        default_api_keys.allow_override_via_environment,
                        default_api_keys.allow_unset_values);
  client_secrets_[CLIENT_MAIN] =
      CalculateKeyValue(default_api_keys.google_client_secret_main,
                        STRINGIZE_NO_EXPANSION(GOOGLE_CLIENT_SECRET_MAIN),
                        ::switches::kOAuth2ClientSecret, default_client_secret,
                        environment.get(), command_line, gaia_config,
                        default_api_keys.allow_override_via_environment,
                        default_api_keys.allow_unset_values);

  client_ids_[CLIENT_REMOTING] = CalculateKeyValue(
      default_api_keys.google_client_id_remoting,
      STRINGIZE_NO_EXPANSION(GOOGLE_CLIENT_ID_REMOTING), nullptr,
      default_client_id, environment.get(), command_line, gaia_config,
      default_api_keys.allow_override_via_environment,
      default_api_keys.allow_unset_values);
  client_secrets_[CLIENT_REMOTING] = CalculateKeyValue(
      default_api_keys.google_client_secret_remoting,
      STRINGIZE_NO_EXPANSION(GOOGLE_CLIENT_SECRET_REMOTING), nullptr,
      default_client_secret, environment.get(), command_line, gaia_config,
      default_api_keys.allow_override_via_environment,
      default_api_keys.allow_unset_values);

  client_ids_[CLIENT_REMOTING_HOST] = CalculateKeyValue(
      default_api_keys.google_client_id_remoting_host,
      STRINGIZE_NO_EXPANSION(GOOGLE_CLIENT_ID_REMOTING_HOST), nullptr,
      default_client_id, environment.get(), command_line, gaia_config,
      default_api_keys.allow_override_via_environment,
      default_api_keys.allow_unset_values);
  client_secrets_[CLIENT_REMOTING_HOST] = CalculateKeyValue(
      default_api_keys.google_client_secret_remoting_host,
      STRINGIZE_NO_EXPANSION(GOOGLE_CLIENT_SECRET_REMOTING_HOST), nullptr,
      default_client_secret, environment.get(), command_line, gaia_config,
      default_api_keys.allow_override_via_environment,
      default_api_keys.allow_unset_values);
}

ApiKeyCache::~ApiKeyCache() = default;

const std::string& ApiKeyCache::GetClientID(OAuth2Client client) const {
  DCHECK_LT(client, CLIENT_NUM_ITEMS);
  return client_ids_[client];
}

const std::string& ApiKeyCache::GetClientSecret(OAuth2Client client) const {
  DCHECK_LT(client, CLIENT_NUM_ITEMS);
  return client_secrets_[client];
}

#if BUILDFLAG(SUPPORT_EXTERNAL_GOOGLE_API_KEY)
void ApiKeyCache::SetClientID(OAuth2Client client,
                              const std::string& client_id) {
  client_ids_[client] = client_id;
}

void ApiKeyCache::SetClientSecret(OAuth2Client client,
                                  const std::string& client_secret) {
  client_secrets_[client] = client_secret;
}
#endif  // BUILDFLAG(SUPPORT_EXTERNAL_GOOGLE_API_KEY)

bool ApiKeyCache::HasAPIKeyConfigured() const {
  return api_key_ != DefaultApiKeys::kUnsetApiToken;
}

bool ApiKeyCache::HasOAuthClientConfigured() const {
  auto is_unset = [](const std::string& value) {
    return value == DefaultApiKeys::kUnsetApiToken;
  };
  return std::ranges::none_of(client_ids_, is_unset) &&
         std::ranges::none_of(client_secrets_, is_unset);
}

}  // namespace google_apis