// Copyright (c) 2012 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 "google_apis/google_api_keys.h" // If you add more includes to this list, you also need to add them to // google_api_keys_unittest.cc and google_api_keys_mac_unittest.mm. #include #include #include #include "base/command_line.h" #include "base/environment.h" #include "base/lazy_instance.h" #include "base/logging.h" #include "base/strings/stringize_macros.h" #include "build/branding_buildflags.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 #if defined(USE_OFFICIAL_GOOGLE_API_KEYS) #include "google_apis/internal/google_chrome_api_keys.h" #include "google_apis/internal/metrics_signing_key.h" #endif // Used to indicate an unset key/id/secret. This works better with // various unit tests than leaving the token empty. #define DUMMY_API_TOKEN "dummytoken" #if !defined(GOOGLE_API_KEY) #define GOOGLE_API_KEY DUMMY_API_TOKEN #endif #if !defined(GOOGLE_METRICS_SIGNING_KEY) #define GOOGLE_METRICS_SIGNING_KEY DUMMY_API_TOKEN #endif #if !defined(GOOGLE_CLIENT_ID_MAIN) #define GOOGLE_CLIENT_ID_MAIN DUMMY_API_TOKEN #endif #if !defined(GOOGLE_CLIENT_SECRET_MAIN) #define GOOGLE_CLIENT_SECRET_MAIN DUMMY_API_TOKEN #endif #if !defined(GOOGLE_CLIENT_ID_REMOTING) #define GOOGLE_CLIENT_ID_REMOTING DUMMY_API_TOKEN #endif #if !defined(GOOGLE_CLIENT_SECRET_REMOTING) #define GOOGLE_CLIENT_SECRET_REMOTING DUMMY_API_TOKEN #endif #if !defined(GOOGLE_CLIENT_ID_REMOTING_HOST) #define GOOGLE_CLIENT_ID_REMOTING_HOST DUMMY_API_TOKEN #endif #if !defined(GOOGLE_CLIENT_SECRET_REMOTING_HOST) #define GOOGLE_CLIENT_SECRET_REMOTING_HOST DUMMY_API_TOKEN #endif #if !defined(GOOGLE_API_KEY_ANDROID_NON_STABLE) #define GOOGLE_API_KEY_ANDROID_NON_STABLE DUMMY_API_TOKEN #endif #if !defined(GOOGLE_API_KEY_REMOTING) #define GOOGLE_API_KEY_REMOTING DUMMY_API_TOKEN #endif // API key for SharingService. #if !defined(GOOGLE_API_KEY_SHARING) #define GOOGLE_API_KEY_SHARING DUMMY_API_TOKEN #endif // API key for the Speech On-Device API (SODA). #if !defined(GOOGLE_API_KEY_SODA) #define GOOGLE_API_KEY_SODA DUMMY_API_TOKEN #endif // API key for the ReadAloud API. #if !defined(GOOGLE_API_KEY_READ_ALOUD) #define GOOGLE_API_KEY_READ_ALOUD DUMMY_API_TOKEN #endif // API key for the Fresnel API. #if !defined(GOOGLE_API_KEY_FRESNEL) #define GOOGLE_API_KEY_FRESNEL DUMMY_API_TOKEN #endif // These are used as shortcuts for developers and users providing // OAuth credentials via preprocessor defines or environment // variables. If set, they will be used to replace any of the client // IDs and secrets above that have not been set (and only those; they // will not override already-set values). #if !defined(GOOGLE_DEFAULT_CLIENT_ID) #define GOOGLE_DEFAULT_CLIENT_ID "" #endif #if !defined(GOOGLE_DEFAULT_CLIENT_SECRET) #define GOOGLE_DEFAULT_CLIENT_SECRET "" #endif namespace google_apis { const char kAPIKeysDevelopersHowToURL[] = "https://www.chromium.org/developers/how-tos/api-keys"; // This is used as a lazy instance to determine keys once and cache them. class APIKeyCache { public: APIKeyCache() { std::unique_ptr environment(base::Environment::Create()); base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); GaiaConfig* gaia_config = GaiaConfig::GetInstance(); api_key_ = CalculateKeyValue( GOOGLE_API_KEY, STRINGIZE_NO_EXPANSION(GOOGLE_API_KEY), nullptr, std::string(), environment.get(), command_line, gaia_config); // A special non-stable key is at the moment defined only for Android Chrome. #if BUILDFLAG(IS_ANDROID) api_key_non_stable_ = CalculateKeyValue( GOOGLE_API_KEY_ANDROID_NON_STABLE, STRINGIZE_NO_EXPANSION(GOOGLE_API_KEY_ANDROID_NON_STABLE), nullptr, std::string(), environment.get(), command_line, gaia_config); #else api_key_non_stable_ = api_key_; #endif api_key_remoting_ = CalculateKeyValue( GOOGLE_API_KEY_REMOTING, STRINGIZE_NO_EXPANSION(GOOGLE_API_KEY_REMOTING), nullptr, std::string(), environment.get(), command_line, gaia_config); api_key_sharing_ = CalculateKeyValue( GOOGLE_API_KEY_SHARING, STRINGIZE_NO_EXPANSION(GOOGLE_API_KEY_SHARING), nullptr, std::string(), environment.get(), command_line, gaia_config); api_key_soda_ = CalculateKeyValue( GOOGLE_API_KEY_SODA, STRINGIZE_NO_EXPANSION(GOOGLE_API_KEY_SODA), nullptr, std::string(), environment.get(), command_line, gaia_config); api_key_read_aloud_ = CalculateKeyValue( GOOGLE_API_KEY_READ_ALOUD, STRINGIZE_NO_EXPANSION(GOOGLE_API_KEY_READ_ALOUD), nullptr, std::string(), environment.get(), command_line, gaia_config); api_key_fresnel_ = CalculateKeyValue( GOOGLE_API_KEY_FRESNEL, STRINGIZE_NO_EXPANSION(GOOGLE_API_KEY_FRESNEL), nullptr, std::string(), environment.get(), command_line, gaia_config); metrics_key_ = CalculateKeyValue( GOOGLE_METRICS_SIGNING_KEY, STRINGIZE_NO_EXPANSION(GOOGLE_METRICS_SIGNING_KEY), nullptr, std::string(), environment.get(), command_line, gaia_config); std::string default_client_id = CalculateKeyValue( GOOGLE_DEFAULT_CLIENT_ID, STRINGIZE_NO_EXPANSION(GOOGLE_DEFAULT_CLIENT_ID), nullptr, std::string(), environment.get(), command_line, gaia_config); std::string default_client_secret = CalculateKeyValue( GOOGLE_DEFAULT_CLIENT_SECRET, STRINGIZE_NO_EXPANSION(GOOGLE_DEFAULT_CLIENT_SECRET), nullptr, std::string(), environment.get(), command_line, gaia_config); // 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( GOOGLE_CLIENT_ID_MAIN, STRINGIZE_NO_EXPANSION(GOOGLE_CLIENT_ID_MAIN), ::switches::kOAuth2ClientID, default_client_id, environment.get(), command_line, gaia_config); client_secrets_[CLIENT_MAIN] = CalculateKeyValue( GOOGLE_CLIENT_SECRET_MAIN, STRINGIZE_NO_EXPANSION(GOOGLE_CLIENT_SECRET_MAIN), ::switches::kOAuth2ClientSecret, default_client_secret, environment.get(), command_line, gaia_config); client_ids_[CLIENT_REMOTING] = CalculateKeyValue( GOOGLE_CLIENT_ID_REMOTING, STRINGIZE_NO_EXPANSION(GOOGLE_CLIENT_ID_REMOTING), nullptr, default_client_id, environment.get(), command_line, gaia_config); client_secrets_[CLIENT_REMOTING] = CalculateKeyValue( GOOGLE_CLIENT_SECRET_REMOTING, STRINGIZE_NO_EXPANSION(GOOGLE_CLIENT_SECRET_REMOTING), nullptr, default_client_secret, environment.get(), command_line, gaia_config); client_ids_[CLIENT_REMOTING_HOST] = CalculateKeyValue( GOOGLE_CLIENT_ID_REMOTING_HOST, STRINGIZE_NO_EXPANSION(GOOGLE_CLIENT_ID_REMOTING_HOST), nullptr, default_client_id, environment.get(), command_line, gaia_config); client_secrets_[CLIENT_REMOTING_HOST] = CalculateKeyValue( GOOGLE_CLIENT_SECRET_REMOTING_HOST, STRINGIZE_NO_EXPANSION(GOOGLE_CLIENT_SECRET_REMOTING_HOST), nullptr, default_client_secret, environment.get(), command_line, gaia_config); } std::string api_key() const { return api_key_; } #if BUILDFLAG(IS_IOS) || BUILDFLAG(IS_FUCHSIA) void set_api_key(const std::string& api_key) { api_key_ = api_key; } #endif std::string api_key_non_stable() const { return api_key_non_stable_; } std::string api_key_remoting() const { return api_key_remoting_; } std::string api_key_sharing() const { return api_key_sharing_; } std::string api_key_soda() const { return api_key_soda_; } std::string api_key_read_aloud() const { return api_key_read_aloud_; } std::string api_key_fresnel() const { return api_key_fresnel_; } std::string metrics_key() const { return metrics_key_; } std::string GetClientID(OAuth2Client client) const { DCHECK_LT(client, CLIENT_NUM_ITEMS); return client_ids_[client]; } #if BUILDFLAG(IS_IOS) void SetClientID(OAuth2Client client, const std::string& client_id) { client_ids_[client] = client_id; } #endif std::string GetClientSecret(OAuth2Client client) const { DCHECK_LT(client, CLIENT_NUM_ITEMS); return client_secrets_[client]; } #if BUILDFLAG(IS_IOS) void SetClientSecret(OAuth2Client client, const std::string& client_secret) { client_secrets_[client] = client_secret; } #endif std::string GetSpdyProxyAuthValue() { #if defined(SPDY_PROXY_AUTH_VALUE) return SPDY_PROXY_AUTH_VALUE; #else return std::string(); #endif } private: // 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. 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, const char* environment_variable_name, const char* command_line_switch, const std::string& default_if_unset, base::Environment* environment, base::CommandLine* command_line, GaiaConfig* gaia_config) { 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 = ::google_apis::GetAPIKeyFromInfoPlist(environment_variable_name); if (!temp.empty()) { key_value = temp; VLOG(1) << "Overriding API key " << environment_variable_name << " with value " << key_value << " from Info.plist."; } #endif #if !BUILDFLAG(GOOGLE_CHROME_BRANDING) // 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 (environment->GetVar(environment_variable_name, &temp)) { key_value = temp; VLOG(1) << "Overriding API key " << environment_variable_name << " with value " << key_value << " from environment variable."; } #endif 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 == DUMMY_API_TOKEN) { #if BUILDFLAG(GOOGLE_CHROME_BRANDING) && !BUILDFLAG(IS_FUCHSIA) // 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 DUMMY_API_TOKEN. // Exclude Fuchsia to match BUILD.gn. // TODO(crbug.com/1171510): Update Fuchsia exclusion when bug is fixed. CHECK(false); #endif 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; } std::string api_key_; std::string api_key_non_stable_; std::string api_key_remoting_; std::string api_key_sharing_; std::string api_key_soda_; std::string api_key_read_aloud_; std::string api_key_fresnel_; std::string metrics_key_; std::string client_ids_[CLIENT_NUM_ITEMS]; std::string client_secrets_[CLIENT_NUM_ITEMS]; }; static base::LazyInstance::DestructorAtExit g_api_key_cache = LAZY_INSTANCE_INITIALIZER; bool HasAPIKeyConfigured() { return GetAPIKey() != DUMMY_API_TOKEN; } std::string GetAPIKey() { return g_api_key_cache.Get().api_key(); } std::string GetNonStableAPIKey() { return g_api_key_cache.Get().api_key_non_stable(); } std::string GetRemotingAPIKey() { return g_api_key_cache.Get().api_key_remoting(); } std::string GetSharingAPIKey() { return g_api_key_cache.Get().api_key_sharing(); } std::string GetSodaAPIKey() { return g_api_key_cache.Get().api_key_soda(); } std::string GetReadAloudAPIKey() { return g_api_key_cache.Get().api_key_read_aloud(); } std::string GetFresnelAPIKey() { return g_api_key_cache.Get().api_key_fresnel(); } #if BUILDFLAG(IS_IOS) || BUILDFLAG(IS_FUCHSIA) void SetAPIKey(const std::string& api_key) { g_api_key_cache.Get().set_api_key(api_key); } #endif std::string GetMetricsKey() { return g_api_key_cache.Get().metrics_key(); } bool HasOAuthClientConfigured() { for (size_t client_id = 0; client_id < CLIENT_NUM_ITEMS; ++client_id) { OAuth2Client client = static_cast(client_id); if (GetOAuth2ClientID(client) == DUMMY_API_TOKEN || GetOAuth2ClientSecret(client) == DUMMY_API_TOKEN) { return false; } } return true; } std::string GetOAuth2ClientID(OAuth2Client client) { return g_api_key_cache.Get().GetClientID(client); } std::string GetOAuth2ClientSecret(OAuth2Client client) { return g_api_key_cache.Get().GetClientSecret(client); } #if BUILDFLAG(IS_IOS) void SetOAuth2ClientID(OAuth2Client client, const std::string& client_id) { g_api_key_cache.Get().SetClientID(client, client_id); } void SetOAuth2ClientSecret(OAuth2Client client, const std::string& client_secret) { g_api_key_cache.Get().SetClientSecret(client, client_secret); } #endif std::string GetSpdyProxyAuthValue() { return g_api_key_cache.Get().GetSpdyProxyAuthValue(); } bool IsGoogleChromeAPIKeyUsed() { #if defined(USE_OFFICIAL_GOOGLE_API_KEYS) return true; #else return false; #endif } } // namespace google_apis