blob: 94f6812ab7494f0534857b92a5a6b6fefca4d83e [file] [log] [blame]
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "google_apis/google_api_keys.h"
6
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00007// If you add more includes to this list, you also need to add them to
8// google_api_keys_unittest.cc.
Torne (Richard Coles)58218062012-11-14 11:43:16 +00009#include "base/command_line.h"
10#include "base/environment.h"
11#include "base/lazy_instance.h"
12#include "base/logging.h"
13#include "base/memory/scoped_ptr.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000014#include "base/strings/stringize_macros.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000015
16#if defined(GOOGLE_CHROME_BUILD) || defined(USE_OFFICIAL_GOOGLE_API_KEYS)
17#include "google_apis/internal/google_chrome_api_keys.h"
18#endif
19
Torne (Richard Coles)58218062012-11-14 11:43:16 +000020// Used to indicate an unset key/id/secret. This works better with
21// various unit tests than leaving the token empty.
22#define DUMMY_API_TOKEN "dummytoken"
23
24#if !defined(GOOGLE_API_KEY)
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000025#define GOOGLE_API_KEY DUMMY_API_TOKEN
Torne (Richard Coles)58218062012-11-14 11:43:16 +000026#endif
27
28#if !defined(GOOGLE_CLIENT_ID_MAIN)
29#define GOOGLE_CLIENT_ID_MAIN DUMMY_API_TOKEN
30#endif
31
32#if !defined(GOOGLE_CLIENT_SECRET_MAIN)
33#define GOOGLE_CLIENT_SECRET_MAIN DUMMY_API_TOKEN
34#endif
35
36#if !defined(GOOGLE_CLIENT_ID_CLOUD_PRINT)
37#define GOOGLE_CLIENT_ID_CLOUD_PRINT DUMMY_API_TOKEN
38#endif
39
40#if !defined(GOOGLE_CLIENT_SECRET_CLOUD_PRINT)
41#define GOOGLE_CLIENT_SECRET_CLOUD_PRINT DUMMY_API_TOKEN
42#endif
43
44#if !defined(GOOGLE_CLIENT_ID_REMOTING)
45#define GOOGLE_CLIENT_ID_REMOTING DUMMY_API_TOKEN
46#endif
47
48#if !defined(GOOGLE_CLIENT_SECRET_REMOTING)
49#define GOOGLE_CLIENT_SECRET_REMOTING DUMMY_API_TOKEN
50#endif
51
Torne (Richard Coles)3551c9c2013-08-23 16:39:15 +010052#if !defined(GOOGLE_CLIENT_ID_REMOTING_HOST)
53#define GOOGLE_CLIENT_ID_REMOTING_HOST DUMMY_API_TOKEN
54#endif
55
56#if !defined(GOOGLE_CLIENT_SECRET_REMOTING_HOST)
57#define GOOGLE_CLIENT_SECRET_REMOTING_HOST DUMMY_API_TOKEN
58#endif
59
Torne (Richard Coles)58218062012-11-14 11:43:16 +000060// These are used as shortcuts for developers and users providing
61// OAuth credentials via preprocessor defines or environment
62// variables. If set, they will be used to replace any of the client
63// IDs and secrets above that have not been set (and only those; they
64// will not override already-set values).
Torne (Richard Coles)58218062012-11-14 11:43:16 +000065#if !defined(GOOGLE_DEFAULT_CLIENT_ID)
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000066#define GOOGLE_DEFAULT_CLIENT_ID ""
Torne (Richard Coles)58218062012-11-14 11:43:16 +000067#endif
68#if !defined(GOOGLE_DEFAULT_CLIENT_SECRET)
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000069#define GOOGLE_DEFAULT_CLIENT_SECRET ""
Torne (Richard Coles)58218062012-11-14 11:43:16 +000070#endif
71
72namespace switches {
73
74// Specifies custom OAuth2 client id for testing purposes.
75const char kOAuth2ClientID[] = "oauth2-client-id";
76
77// Specifies custom OAuth2 client secret for testing purposes.
78const char kOAuth2ClientSecret[] = "oauth2-client-secret";
79
80} // namespace switches
81
82namespace google_apis {
83
84// This is used as a lazy instance to determine keys once and cache them.
85class APIKeyCache {
86 public:
87 APIKeyCache() {
88 scoped_ptr<base::Environment> environment(base::Environment::Create());
89 CommandLine* command_line = CommandLine::ForCurrentProcess();
90
91 api_key_ = CalculateKeyValue(GOOGLE_API_KEY,
92 STRINGIZE_NO_EXPANSION(GOOGLE_API_KEY),
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010093 NULL,
94 std::string(),
Torne (Richard Coles)58218062012-11-14 11:43:16 +000095 environment.get(),
96 command_line);
97
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010098 std::string default_client_id =
99 CalculateKeyValue(GOOGLE_DEFAULT_CLIENT_ID,
100 STRINGIZE_NO_EXPANSION(GOOGLE_DEFAULT_CLIENT_ID),
101 NULL,
102 std::string(),
103 environment.get(),
104 command_line);
105 std::string default_client_secret =
106 CalculateKeyValue(GOOGLE_DEFAULT_CLIENT_SECRET,
107 STRINGIZE_NO_EXPANSION(GOOGLE_DEFAULT_CLIENT_SECRET),
108 NULL,
109 std::string(),
110 environment.get(),
111 command_line);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000112
113 // We currently only allow overriding the baked-in values for the
114 // default OAuth2 client ID and secret using a command-line
115 // argument, since that is useful to enable testing against
116 // staging servers, and since that was what was possible and
117 // likely practiced by the QA team before this implementation was
118 // written.
119 client_ids_[CLIENT_MAIN] = CalculateKeyValue(
120 GOOGLE_CLIENT_ID_MAIN,
121 STRINGIZE_NO_EXPANSION(GOOGLE_CLIENT_ID_MAIN),
122 switches::kOAuth2ClientID,
123 default_client_id,
124 environment.get(),
125 command_line);
126 client_secrets_[CLIENT_MAIN] = CalculateKeyValue(
127 GOOGLE_CLIENT_SECRET_MAIN,
128 STRINGIZE_NO_EXPANSION(GOOGLE_CLIENT_SECRET_MAIN),
129 switches::kOAuth2ClientSecret,
130 default_client_secret,
131 environment.get(),
132 command_line);
133
134 client_ids_[CLIENT_CLOUD_PRINT] = CalculateKeyValue(
135 GOOGLE_CLIENT_ID_CLOUD_PRINT,
136 STRINGIZE_NO_EXPANSION(GOOGLE_CLIENT_ID_CLOUD_PRINT),
137 NULL,
138 default_client_id,
139 environment.get(),
140 command_line);
141 client_secrets_[CLIENT_CLOUD_PRINT] = CalculateKeyValue(
142 GOOGLE_CLIENT_SECRET_CLOUD_PRINT,
143 STRINGIZE_NO_EXPANSION(GOOGLE_CLIENT_SECRET_CLOUD_PRINT),
144 NULL,
145 default_client_secret,
146 environment.get(),
147 command_line);
148
149 client_ids_[CLIENT_REMOTING] = CalculateKeyValue(
150 GOOGLE_CLIENT_ID_REMOTING,
151 STRINGIZE_NO_EXPANSION(GOOGLE_CLIENT_ID_REMOTING),
152 NULL,
153 default_client_id,
154 environment.get(),
155 command_line);
156 client_secrets_[CLIENT_REMOTING] = CalculateKeyValue(
157 GOOGLE_CLIENT_SECRET_REMOTING,
158 STRINGIZE_NO_EXPANSION(GOOGLE_CLIENT_SECRET_REMOTING),
159 NULL,
160 default_client_secret,
161 environment.get(),
162 command_line);
Torne (Richard Coles)3551c9c2013-08-23 16:39:15 +0100163
164 client_ids_[CLIENT_REMOTING_HOST] = CalculateKeyValue(
165 GOOGLE_CLIENT_ID_REMOTING_HOST,
166 STRINGIZE_NO_EXPANSION(GOOGLE_CLIENT_ID_REMOTING_HOST),
167 NULL,
168 default_client_id,
169 environment.get(),
170 command_line);
171 client_secrets_[CLIENT_REMOTING_HOST] = CalculateKeyValue(
172 GOOGLE_CLIENT_SECRET_REMOTING_HOST,
173 STRINGIZE_NO_EXPANSION(GOOGLE_CLIENT_SECRET_REMOTING_HOST),
174 NULL,
175 default_client_secret,
176 environment.get(),
177 command_line);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000178 }
179
180 std::string api_key() const { return api_key_; }
181
182 std::string GetClientID(OAuth2Client client) const {
183 DCHECK_LT(client, CLIENT_NUM_ITEMS);
184 return client_ids_[client];
185 }
186
187 std::string GetClientSecret(OAuth2Client client) const {
188 DCHECK_LT(client, CLIENT_NUM_ITEMS);
189 return client_secrets_[client];
190 }
191
192 private:
193 // Gets a value for a key. In priority order, this will be the value
194 // provided via a command-line switch, the value provided via an
195 // environment variable, or finally a value baked into the build.
196 // |command_line_switch| may be NULL.
197 static std::string CalculateKeyValue(const char* baked_in_value,
198 const char* environment_variable_name,
199 const char* command_line_switch,
200 const std::string& default_if_unset,
201 base::Environment* environment,
202 CommandLine* command_line) {
203 std::string key_value = baked_in_value;
204 std::string temp;
205 if (environment->GetVar(environment_variable_name, &temp)) {
206 key_value = temp;
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000207 VLOG(1) << "Overriding API key " << environment_variable_name
208 << " with value " << key_value << " from environment variable.";
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000209 }
210
211 if (command_line_switch && command_line->HasSwitch(command_line_switch)) {
212 key_value = command_line->GetSwitchValueASCII(command_line_switch);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000213 VLOG(1) << "Overriding API key " << environment_variable_name
214 << " with value " << key_value << " from command-line switch.";
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000215 }
216
217 if (key_value == DUMMY_API_TOKEN) {
218#if defined(GOOGLE_CHROME_BUILD)
219 // No key should be unset in an official build except the
220 // GOOGLE_DEFAULT_* keys. The default keys don't trigger this
221 // check as their "unset" value is not DUMMY_API_TOKEN.
222 CHECK(false);
223#endif
224 if (default_if_unset.size() > 0) {
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000225 VLOG(1) << "Using default value \"" << default_if_unset
226 << "\" for API key " << environment_variable_name;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000227 key_value = default_if_unset;
228 }
229 }
230
231 // This should remain a debug-only log.
232 DVLOG(1) << "API key " << environment_variable_name << "=" << key_value;
233
234 return key_value;
235 }
236
237 std::string api_key_;
238 std::string client_ids_[CLIENT_NUM_ITEMS];
239 std::string client_secrets_[CLIENT_NUM_ITEMS];
240};
241
242static base::LazyInstance<APIKeyCache> g_api_key_cache =
243 LAZY_INSTANCE_INITIALIZER;
244
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100245bool HasKeysConfigured() {
246 if (GetAPIKey() == DUMMY_API_TOKEN)
247 return false;
248
249 for (size_t client_id = 0; client_id < CLIENT_NUM_ITEMS; ++client_id) {
250 OAuth2Client client = static_cast<OAuth2Client>(client_id);
251 if (GetOAuth2ClientID(client) == DUMMY_API_TOKEN ||
252 GetOAuth2ClientSecret(client) == DUMMY_API_TOKEN) {
253 return false;
254 }
255 }
256
257 return true;
258}
259
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000260std::string GetAPIKey() {
261 return g_api_key_cache.Get().api_key();
262}
263
264std::string GetOAuth2ClientID(OAuth2Client client) {
265 return g_api_key_cache.Get().GetClientID(client);
266}
267
268std::string GetOAuth2ClientSecret(OAuth2Client client) {
269 return g_api_key_cache.Get().GetClientSecret(client);
270}
271
272} // namespace google_apis