OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/chromeos/platform_keys/platform_keys_service.h" | 5 #include "chrome/browser/chromeos/platform_keys/platform_keys_service.h" |
6 | 6 |
7 #include "base/base64.h" | 7 #include "base/base64.h" |
8 #include "base/callback.h" | 8 #include "base/callback.h" |
9 #include "base/callback_helpers.h" | |
9 #include "base/values.h" | 10 #include "base/values.h" |
10 #include "chrome/browser/chromeos/platform_keys/platform_keys.h" | 11 #include "chrome/browser/chromeos/platform_keys/platform_keys.h" |
11 #include "content/public/browser/browser_thread.h" | 12 #include "content/public/browser/browser_thread.h" |
12 #include "extensions/browser/state_store.h" | 13 #include "extensions/browser/state_store.h" |
13 #include "net/cert/x509_certificate.h" | 14 #include "net/cert/x509_certificate.h" |
14 | 15 |
15 using content::BrowserThread; | 16 using content::BrowserThread; |
16 | 17 |
17 namespace chromeos { | 18 namespace chromeos { |
18 | 19 |
19 namespace { | 20 namespace { |
20 | 21 |
21 const char kErrorKeyNotAllowedForSigning[] = | 22 const char kErrorKeyNotAllowedForSigning[] = |
22 "This key is not allowed for signing. Either it was used for signing " | 23 "This key is not allowed for signing. Either it was used for signing " |
23 "before or it was not correctly generated."; | 24 "before or it was not correctly generated."; |
24 const char kStateStorePlatformKeys[] = "PlatformKeys"; | 25 const char kStateStorePlatformKeys[] = "PlatformKeys"; |
25 | 26 |
26 scoped_ptr<base::StringValue> GetPublicKeyValue( | 27 scoped_ptr<base::StringValue> GetPublicKeyValue( |
27 const std::string& public_key_spki_der) { | 28 const std::string& public_key_spki_der) { |
28 std::string public_key_spki_der_b64; | 29 std::string public_key_spki_der_b64; |
29 base::Base64Encode(public_key_spki_der, &public_key_spki_der_b64); | 30 base::Base64Encode(public_key_spki_der, &public_key_spki_der_b64); |
30 return make_scoped_ptr(new base::StringValue(public_key_spki_der_b64)); | 31 return make_scoped_ptr(new base::StringValue(public_key_spki_der_b64)); |
31 } | 32 } |
32 | 33 |
33 void RunGenerateKeyCallback( | |
34 const PlatformKeysService::GenerateKeyCallback& callback, | |
35 const std::string& public_key_spki_der) { | |
36 callback.Run(public_key_spki_der, std::string() /* no error */); | |
37 } | |
38 | |
39 // Callback used by |PlatformKeysService::Sign|. | |
40 // Is called with the old validity of |public_key_spki_der| (or false if an | |
41 // error occurred during reading the StateStore). If allowed, starts the actual | |
42 // signing operation which will call back |callback|. If not allowed, calls | |
43 // |callback| with an error. | |
44 void CheckValidityAndSign(const std::string& token_id, | |
45 scoped_ptr<platform_keys::SignRSAParams> params, | |
46 const PlatformKeysService::SignCallback& callback, | |
47 content::BrowserContext* browser_context, | |
48 bool key_is_valid) { | |
49 if (!key_is_valid) { | |
50 callback.Run(std::string() /* no signature */, | |
51 kErrorKeyNotAllowedForSigning); | |
52 return; | |
53 } | |
54 platform_keys::subtle::SignRSA(token_id, params.Pass(), callback, | |
55 browser_context); | |
56 } | |
57 | |
58 } // namespace | 34 } // namespace |
59 | 35 |
36 class PlatformKeysService::Task { | |
37 public: | |
38 Task() {} | |
39 virtual ~Task() {} | |
40 virtual void Start() = 0; | |
41 virtual bool IsDone() = 0; | |
42 | |
43 private: | |
44 DISALLOW_ASSIGN(Task); | |
45 }; | |
46 | |
47 class PlatformKeysService::PermissionUpdateTask : public Task { | |
48 public: | |
49 enum class Step { | |
50 READ_PLATFORM_KEYS, | |
51 WRITE_UPDATE_AND_CALLBACK, | |
52 DONE, | |
53 }; | |
54 | |
55 // Creates a task that reads the current permission for an extension to access | |
56 // a certain key. Afterwards it updates and persists the permission to the new | |
57 // value |new_permission_value|. |callback| will be run after the permission | |
58 // was persisted. The old permission value is then accessible through | |
59 // old_permission_value(). | |
60 PermissionUpdateTask(const bool new_permission_value, | |
61 const std::string& public_key_spki_der, | |
62 const std::string& extension_id, | |
63 base::Callback<void(Task*)> callback, | |
64 PlatformKeysService* service) | |
65 : new_permission_value_(new_permission_value), | |
66 public_key_spki_der_(public_key_spki_der), | |
67 extension_id_(extension_id), | |
68 callback_(callback), | |
69 service_(service), | |
70 weak_factory_(this) {} | |
71 | |
72 ~PermissionUpdateTask() override {} | |
73 | |
74 void Start() override { | |
75 CHECK(next_step_ == Step::READ_PLATFORM_KEYS); | |
76 DoStep(); | |
77 } | |
78 | |
79 bool IsDone() override { return next_step_ == Step::DONE; } | |
80 | |
81 // The original permission value before setting the new value | |
82 // |new_permission_value|. | |
83 bool old_permission_value() { return old_permission_value_; } | |
84 | |
85 private: | |
86 void DoStep() { | |
87 switch (next_step_) { | |
88 case Step::READ_PLATFORM_KEYS: | |
89 next_step_ = Step::WRITE_UPDATE_AND_CALLBACK; | |
90 ReadPlatformKeys(); | |
91 return; | |
92 case Step::WRITE_UPDATE_AND_CALLBACK: | |
93 next_step_ = Step::DONE; | |
94 WriteUpdate(); | |
95 if (!callback_.is_null()) { | |
96 // Make a local copy of the callback to run as it might be deleted | |
97 // during the Run(). | |
98 base::ResetAndReturn(&callback_).Run(this); | |
99 // |this| might be invalid now. | |
100 } | |
101 return; | |
102 case Step::DONE: | |
103 NOTREACHED(); | |
104 return; | |
105 } | |
106 } | |
107 | |
108 // Reads the PlatformKeys value from the extension's state store and calls | |
109 // back to GotPlatformKeys(). | |
110 void ReadPlatformKeys() { | |
111 service_->GetPlatformKeysOfExtension( | |
112 extension_id_, base::Bind(&PermissionUpdateTask::GotPlatformKeys, | |
113 weak_factory_.GetWeakPtr())); | |
114 } | |
115 | |
116 void GotPlatformKeys(scoped_ptr<base::ListValue> platform_keys) { | |
117 platform_keys_ = platform_keys.Pass(); | |
118 DoStep(); | |
119 } | |
120 | |
121 // Returns whether the extension has permission to use the key for signing | |
122 // according to the PlatformKeys value read from the extensions state store. | |
123 // Invalidates the key if it was found to be valid. | |
124 void WriteUpdate() { | |
125 scoped_ptr<base::StringValue> key_value( | |
126 GetPublicKeyValue(public_key_spki_der_)); | |
127 | |
128 base::ListValue::const_iterator it = platform_keys_->Find(*key_value); | |
129 old_permission_value_ = it != platform_keys_->end(); | |
130 if (old_permission_value_ == new_permission_value_) | |
131 return; | |
132 | |
133 if (new_permission_value_) | |
134 platform_keys_->Append(key_value.release()); | |
135 else | |
136 platform_keys_->Remove(*key_value, nullptr); | |
137 | |
138 service_->SetPlatformKeysOfExtension(extension_id_, platform_keys_.Pass()); | |
139 } | |
140 | |
141 Step next_step_ = Step::READ_PLATFORM_KEYS; | |
142 scoped_ptr<base::ListValue> platform_keys_; | |
143 bool old_permission_value_ = false; | |
144 | |
145 const bool new_permission_value_; | |
146 const std::string public_key_spki_der_; | |
147 const std::string extension_id_; | |
148 base::Callback<void(Task*)> callback_; | |
149 PlatformKeysService* const service_; | |
150 base::WeakPtrFactory<PermissionUpdateTask> weak_factory_; | |
151 | |
152 DISALLOW_COPY_AND_ASSIGN(PermissionUpdateTask); | |
153 }; | |
154 | |
155 class PlatformKeysService::SignTask : public Task { | |
156 public: | |
157 enum class Step { | |
158 UPDATE_PERMISSION, | |
159 SIGN_OR_ABORT, | |
160 DONE, | |
161 }; | |
162 | |
163 // This Task will check the permissions of the extension with |extension_id| | |
164 // for the key identified by |public_key_spki_der|, then updates the | |
165 // permission to prevent any future signing operation of that extension using | |
166 // that same key. If the permission check was positive, it will actually sign | |
167 // |data| with the key and pass the signature to |callback|. | |
168 // If an error occurs, an error message is passed to |callback| instead. | |
169 SignTask(const std::string& token_id, | |
170 scoped_ptr<platform_keys::SignRSAParams> params, | |
171 const std::string& extension_id, | |
172 const SignCallback& callback, | |
173 PlatformKeysService* service) | |
174 : token_id_(token_id), | |
175 params_(params.Pass()), | |
176 extension_id_(extension_id), | |
177 callback_(callback), | |
178 service_(service), | |
179 weak_factory_(this) {} | |
180 ~SignTask() override {} | |
181 | |
182 void Start() override { | |
183 CHECK(next_step_ == Step::UPDATE_PERMISSION); | |
184 DoStep(); | |
185 } | |
186 bool IsDone() override { return next_step_ == Step::DONE; } | |
187 | |
188 private: | |
189 void DoStep() { | |
190 switch (next_step_) { | |
191 case Step::UPDATE_PERMISSION: | |
192 next_step_ = Step::SIGN_OR_ABORT; | |
193 UpdatePermission(); | |
194 return; | |
195 case Step::SIGN_OR_ABORT: | |
196 next_step_ = Step::DONE; | |
197 if (!service_->permission_check_enabled_ || | |
198 permission_update_->old_permission_value()) { | |
199 Sign(); | |
200 } else { | |
201 callback_.Run(std::string() /* no signature */, | |
202 kErrorKeyNotAllowedForSigning); | |
203 DoStep(); | |
204 } | |
205 return; | |
206 case Step::DONE: | |
207 service_->TaskFinished(this); | |
208 // |this| might be invalid now. | |
209 return; | |
210 } | |
211 } | |
212 | |
213 // Reads the current permission of the extension with |extension_id_| for key | |
214 // |params_->public_key| and updates the permission to disable further | |
215 // signing operations with that key. | |
216 void UpdatePermission() { | |
217 permission_update_.reset(new PermissionUpdateTask( | |
218 false /* new permission value */, params_->public_key(), extension_id_, | |
219 base::Bind(&SignTask::DidUpdatePermission, weak_factory_.GetWeakPtr()), | |
220 service_)); | |
221 permission_update_->Start(); | |
222 } | |
223 | |
224 void DidUpdatePermission(Task* /* task */) { DoStep(); } | |
225 | |
226 // Starts the actual signing operation and afterwards passes the signature (or | |
227 // error) to |callback_|. | |
228 void Sign() { | |
229 platform_keys::subtle::SignRSA( | |
230 token_id_, params_.Pass(), | |
231 base::Bind(&SignTask::DidSign, weak_factory_.GetWeakPtr()), | |
232 service_->browser_context_); | |
233 } | |
234 | |
235 void DidSign(const std::string& signature, const std::string& error_message) { | |
236 callback_.Run(signature, error_message); | |
237 DoStep(); | |
238 } | |
239 | |
240 Step next_step_ = Step::UPDATE_PERMISSION; | |
241 scoped_ptr<base::ListValue> platform_keys_; | |
242 scoped_ptr<PermissionUpdateTask> permission_update_; | |
243 | |
244 const std::string token_id_; | |
245 scoped_ptr<platform_keys::SignRSAParams> params_; | |
246 const std::string extension_id_; | |
247 const SignCallback callback_; | |
248 PlatformKeysService* const service_; | |
249 base::WeakPtrFactory<SignTask> weak_factory_; | |
250 | |
251 DISALLOW_COPY_AND_ASSIGN(SignTask); | |
252 }; | |
253 | |
60 PlatformKeysService::PlatformKeysService( | 254 PlatformKeysService::PlatformKeysService( |
61 content::BrowserContext* browser_context, | 255 content::BrowserContext* browser_context, |
62 extensions::StateStore* state_store) | 256 extensions::StateStore* state_store) |
63 : browser_context_(browser_context), | 257 : browser_context_(browser_context), |
64 state_store_(state_store), | 258 state_store_(state_store), |
65 weak_factory_(this) { | 259 weak_factory_(this) { |
66 DCHECK(state_store); | 260 DCHECK(state_store); |
67 } | 261 } |
68 | 262 |
69 PlatformKeysService::~PlatformKeysService() { | 263 PlatformKeysService::~PlatformKeysService() { |
70 } | 264 } |
71 | 265 |
72 void PlatformKeysService::DisablePermissionCheckForTesting() { | 266 void PlatformKeysService::DisablePermissionCheckForTesting() { |
73 permission_check_enabled_ = false; | 267 permission_check_enabled_ = false; |
74 } | 268 } |
75 | 269 |
76 void PlatformKeysService::GenerateRSAKey(const std::string& token_id, | 270 void PlatformKeysService::GenerateRSAKey(const std::string& token_id, |
77 unsigned int modulus_length, | 271 unsigned int modulus_length, |
78 const std::string& extension_id, | 272 const std::string& extension_id, |
79 const GenerateKeyCallback& callback) { | 273 const GenerateKeyCallback& callback) { |
80 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 274 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
81 | 275 |
82 platform_keys::subtle::GenerateRSAKey( | 276 platform_keys::subtle::GenerateRSAKey( |
83 token_id, | 277 token_id, modulus_length, |
84 modulus_length, | 278 base::Bind(&PlatformKeysService::GeneratedKey, weak_factory_.GetWeakPtr(), |
85 base::Bind(&PlatformKeysService::GenerateRSAKeyCallback, | 279 extension_id, callback), |
86 weak_factory_.GetWeakPtr(), | |
87 extension_id, | |
88 callback), | |
89 browser_context_); | 280 browser_context_); |
90 } | 281 } |
91 | 282 |
92 void PlatformKeysService::SignRSA( | 283 void PlatformKeysService::SignRSA( |
93 const std::string& token_id, | 284 const std::string& token_id, |
94 scoped_ptr<platform_keys::SignRSAParams> params, | 285 scoped_ptr<platform_keys::SignRSAParams> params, |
95 const std::string& extension_id, | 286 const std::string& extension_id, |
96 const SignCallback& callback) { | 287 const SignCallback& callback) { |
97 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 288 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
98 ReadValidityAndInvalidateKey( | 289 StartOrQueueTask(make_scoped_ptr( |
99 extension_id, params->public_key(), | 290 new SignTask(token_id, params.Pass(), extension_id, callback, this))); |
100 base::Bind(&CheckValidityAndSign, token_id, base::Passed(¶ms), | |
101 callback, browser_context_)); | |
102 } | 291 } |
103 | 292 |
104 void PlatformKeysService::SelectClientCertificates( | 293 void PlatformKeysService::SelectClientCertificates( |
105 const platform_keys::ClientCertificateRequest& request, | 294 const platform_keys::ClientCertificateRequest& request, |
106 const std::string& extension_id, | 295 const std::string& extension_id, |
107 const SelectCertificatesCallback& callback) { | 296 const SelectCertificatesCallback& callback) { |
108 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 297 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
109 | 298 |
110 platform_keys::subtle::SelectClientCertificates( | 299 platform_keys::subtle::SelectClientCertificates( |
111 request, | 300 request, |
112 base::Bind(&PlatformKeysService::SelectClientCertificatesCallback, | 301 base::Bind(&PlatformKeysService::SelectClientCertificatesCallback, |
113 weak_factory_.GetWeakPtr(), extension_id, callback), | 302 weak_factory_.GetWeakPtr(), extension_id, callback), |
114 browser_context_); | 303 browser_context_); |
115 } | 304 } |
116 | 305 |
117 void PlatformKeysService::RegisterPublicKey( | 306 void PlatformKeysService::StartOrQueueTask(scoped_ptr<Task> task) { |
118 const std::string& extension_id, | 307 tasks_.push(make_linked_ptr(task.release())); |
119 const std::string& public_key_spki_der, | 308 if (tasks_.size() == 1) |
120 const base::Closure& callback) { | 309 tasks_.front()->Start(); |
121 GetPlatformKeysOfExtension( | |
122 extension_id, | |
123 base::Bind(&PlatformKeysService::RegisterPublicKeyGotPlatformKeys, | |
124 weak_factory_.GetWeakPtr(), | |
125 extension_id, | |
126 public_key_spki_der, | |
127 callback)); | |
128 } | 310 } |
129 | 311 |
130 void PlatformKeysService::ReadValidityAndInvalidateKey( | 312 void PlatformKeysService::TaskFinished(Task* task) { |
131 const std::string& extension_id, | 313 DCHECK(!tasks_.empty()); |
132 const std::string& public_key_spki_der, | 314 DCHECK(task == tasks_.front().get()); |
133 const base::Callback<void(bool)>& callback) { | 315 // Remove all finished tasks from the queue (should be at most one). |
134 GetPlatformKeysOfExtension(extension_id, | 316 while (!tasks_.empty() && tasks_.front()->IsDone()) |
135 base::Bind(&PlatformKeysService::InvalidateKey, | 317 tasks_.pop(); |
136 weak_factory_.GetWeakPtr(), | 318 |
137 extension_id, | 319 // Now either the queue is empty or the next task is not finished yet and it |
138 public_key_spki_der, | 320 // can be started. |
139 callback)); | 321 if (!tasks_.empty()) |
322 tasks_.front()->Start(); | |
140 } | 323 } |
141 | 324 |
142 void PlatformKeysService::GetPlatformKeysOfExtension( | 325 void PlatformKeysService::GetPlatformKeysOfExtension( |
143 const std::string& extension_id, | 326 const std::string& extension_id, |
144 const GetPlatformKeysCallback& callback) { | 327 const GetPlatformKeysCallback& callback) { |
145 state_store_->GetExtensionValue( | 328 state_store_->GetExtensionValue( |
146 extension_id, kStateStorePlatformKeys, | 329 extension_id, kStateStorePlatformKeys, |
147 base::Bind(&PlatformKeysService::GotPlatformKeysOfExtension, | 330 base::Bind(&PlatformKeysService::GotPlatformKeysOfExtension, |
148 weak_factory_.GetWeakPtr(), extension_id, callback)); | 331 weak_factory_.GetWeakPtr(), extension_id, callback)); |
149 } | 332 } |
150 | 333 |
151 void PlatformKeysService::SetPlatformKeysOfExtension( | 334 void PlatformKeysService::SetPlatformKeysOfExtension( |
152 const std::string& extension_id, | 335 const std::string& extension_id, |
153 scoped_ptr<base::ListValue> platform_keys) { | 336 scoped_ptr<base::ListValue> platform_keys) { |
154 state_store_->SetExtensionValue(extension_id, kStateStorePlatformKeys, | 337 state_store_->SetExtensionValue(extension_id, kStateStorePlatformKeys, |
155 platform_keys.Pass()); | 338 platform_keys.Pass()); |
156 } | 339 } |
157 | 340 |
158 void PlatformKeysService::GenerateRSAKeyCallback( | 341 void PlatformKeysService::GeneratedKey(const std::string& extension_id, |
159 const std::string& extension_id, | 342 const GenerateKeyCallback& callback, |
160 const GenerateKeyCallback& callback, | 343 const std::string& public_key_spki_der, |
161 const std::string& public_key_spki_der, | 344 const std::string& error_message) { |
162 const std::string& error_message) { | |
163 if (!error_message.empty()) { | 345 if (!error_message.empty()) { |
164 callback.Run(std::string() /* no public key */, error_message); | 346 callback.Run(std::string() /* no public key */, error_message); |
165 return; | 347 return; |
166 } | 348 } |
167 base::Closure wrapped_callback( | 349 |
168 base::Bind(&RunGenerateKeyCallback, callback, public_key_spki_der)); | 350 StartOrQueueTask(make_scoped_ptr(new PermissionUpdateTask( |
169 RegisterPublicKey(extension_id, public_key_spki_der, wrapped_callback); | 351 true /* new permission value */, public_key_spki_der, extension_id, |
352 base::Bind(&PlatformKeysService::DidRegisterGeneratedKey, | |
353 base::Unretained(this), callback, public_key_spki_der), | |
354 this))); | |
355 } | |
356 | |
357 void PlatformKeysService::DidRegisterGeneratedKey( | |
kaliamoorthi
2015/02/09 16:02:10
nit: How about RegisteredGeneratedKey? I see other
pneubeck (no reviews)
2015/02/15 09:25:57
Done.
| |
358 const GenerateKeyCallback& callback, | |
359 const std::string& public_key_spki_der, | |
360 Task* task) { | |
361 callback.Run(public_key_spki_der, std::string() /* no error */); | |
362 TaskFinished(task); | |
170 } | 363 } |
171 | 364 |
172 void PlatformKeysService::SelectClientCertificatesCallback( | 365 void PlatformKeysService::SelectClientCertificatesCallback( |
173 const std::string& extension_id, | 366 const std::string& extension_id, |
174 const SelectCertificatesCallback& callback, | 367 const SelectCertificatesCallback& callback, |
175 scoped_ptr<net::CertificateList> matches, | 368 scoped_ptr<net::CertificateList> matches, |
176 const std::string& error_message) { | 369 const std::string& error_message) { |
177 if (permission_check_enabled_) | 370 if (permission_check_enabled_) |
178 matches->clear(); | 371 matches->clear(); |
179 | 372 |
180 // TODO(pneubeck): Remove all certs that the extension doesn't have access to. | 373 // TODO(pneubeck): Remove all certs that the extension doesn't have access to. |
181 callback.Run(matches.Pass(), error_message); | 374 callback.Run(matches.Pass(), error_message); |
182 } | 375 } |
183 | 376 |
184 void PlatformKeysService::RegisterPublicKeyGotPlatformKeys( | |
185 const std::string& extension_id, | |
186 const std::string& public_key_spki_der, | |
187 const base::Closure& callback, | |
188 scoped_ptr<base::ListValue> platform_keys) { | |
189 scoped_ptr<base::StringValue> key_value( | |
190 GetPublicKeyValue(public_key_spki_der)); | |
191 | |
192 DCHECK(platform_keys->end() == platform_keys->Find(*key_value)) | |
193 << "Keys are assumed to be generated and not to be registered multiple " | |
194 "times."; | |
195 platform_keys->Append(key_value.release()); | |
196 SetPlatformKeysOfExtension(extension_id, platform_keys.Pass()); | |
197 callback.Run(); | |
198 } | |
199 | |
200 void PlatformKeysService::InvalidateKey( | |
201 const std::string& extension_id, | |
202 const std::string& public_key_spki_der, | |
203 const base::Callback<void(bool)>& callback, | |
204 scoped_ptr<base::ListValue> platform_keys) { | |
205 scoped_ptr<base::StringValue> key_value( | |
206 GetPublicKeyValue(public_key_spki_der)); | |
207 | |
208 size_t index = 0; | |
209 // If the key is found in |platform_keys|, it's valid for the extension to use | |
210 // it for signing. | |
211 bool key_was_valid = platform_keys->Remove(*key_value, &index); | |
212 | |
213 if (key_was_valid) { | |
214 // Persist that the key is now invalid. | |
215 SetPlatformKeysOfExtension(extension_id, platform_keys.Pass()); | |
216 } | |
217 | |
218 if (permission_check_enabled_) { | |
219 // If permission checks are enabled, pass back the key permission (before | |
220 // it was removed above). | |
221 callback.Run(key_was_valid); | |
222 } else { | |
223 // Otherwise just allow signing with the key (which is enabled for testing | |
224 // only). | |
225 callback.Run(true); | |
226 } | |
227 } | |
228 | |
229 void PlatformKeysService::GotPlatformKeysOfExtension( | 377 void PlatformKeysService::GotPlatformKeysOfExtension( |
230 const std::string& extension_id, | 378 const std::string& extension_id, |
231 const GetPlatformKeysCallback& callback, | 379 const GetPlatformKeysCallback& callback, |
232 scoped_ptr<base::Value> value) { | 380 scoped_ptr<base::Value> value) { |
233 if (!value) | 381 if (!value) |
234 value.reset(new base::ListValue); | 382 value.reset(new base::ListValue); |
235 | 383 |
236 base::ListValue* keys = NULL; | 384 base::ListValue* keys = NULL; |
237 if (!value->GetAsList(&keys)) { | 385 if (!value->GetAsList(&keys)) { |
238 LOG(ERROR) << "Found a value of wrong type."; | 386 LOG(ERROR) << "Found a value of wrong type."; |
239 | 387 |
240 keys = new base::ListValue; | 388 keys = new base::ListValue; |
241 value.reset(keys); | 389 value.reset(keys); |
242 } | 390 } |
243 | 391 |
244 ignore_result(value.release()); | 392 ignore_result(value.release()); |
245 callback.Run(make_scoped_ptr(keys)); | 393 callback.Run(make_scoped_ptr(keys)); |
246 } | 394 } |
247 | 395 |
248 } // namespace chromeos | 396 } // namespace chromeos |
OLD | NEW |