Add new certificateProvider extension API.
[chromium-blink-merge.git] / chrome / browser / extensions / api / easy_unlock_private / easy_unlock_private_api.cc
blobc530bd846ba955084f97f69ba12078f2576a35c5
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
3 // found in the LICENSE file.
5 #include "chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.h"
7 #include <vector>
9 #include "base/bind.h"
10 #include "base/command_line.h"
11 #include "base/lazy_instance.h"
12 #include "base/memory/linked_ptr.h"
13 #include "base/numerics/safe_conversions.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/thread_task_runner_handle.h"
16 #include "base/values.h"
17 #include "chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_crypto_delegate.h"
18 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/browser/signin/easy_unlock_screenlock_state_handler.h"
20 #include "chrome/browser/signin/easy_unlock_service.h"
21 #include "chrome/browser/signin/easy_unlock_service_regular.h"
22 #include "chrome/browser/ui/proximity_auth/proximity_auth_error_bubble.h"
23 #include "chrome/common/extensions/api/easy_unlock_private.h"
24 #include "chrome/grit/generated_resources.h"
25 #include "components/proximity_auth/bluetooth_util.h"
26 #include "components/proximity_auth/cryptauth/base64url.h"
27 #include "components/proximity_auth/cryptauth/cryptauth_device_manager.h"
28 #include "components/proximity_auth/cryptauth/cryptauth_enrollment_manager.h"
29 #include "components/proximity_auth/cryptauth/cryptauth_enrollment_utils.h"
30 #include "components/proximity_auth/cryptauth/proto/cryptauth_api.pb.h"
31 #include "components/proximity_auth/cryptauth/secure_message_delegate.h"
32 #include "components/proximity_auth/logging/logging.h"
33 #include "components/proximity_auth/proximity_auth_client.h"
34 #include "components/proximity_auth/screenlock_bridge.h"
35 #include "components/proximity_auth/screenlock_state.h"
36 #include "components/proximity_auth/switches.h"
37 #include "content/public/browser/browser_thread.h"
38 #include "content/public/browser/web_contents.h"
39 #include "extensions/browser/browser_context_keyed_api_factory.h"
40 #include "ui/base/l10n/l10n_util.h"
41 #include "ui/gfx/geometry/rect.h"
42 #include "ui/gfx/range/range.h"
44 #if defined(OS_CHROMEOS)
45 #include "ash/system/chromeos/devicetype_utils.h"
46 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager.h"
47 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager_factory.h"
48 #include "components/user_manager/user.h"
49 #include "components/user_manager/user_manager.h"
50 #endif
52 using proximity_auth::ScreenlockState;
54 namespace extensions {
56 namespace easy_unlock_private = api::easy_unlock_private;
58 namespace {
60 static base::LazyInstance<BrowserContextKeyedAPIFactory<EasyUnlockPrivateAPI> >
61 g_factory = LAZY_INSTANCE_INITIALIZER;
63 // Utility method for getting the API's crypto delegate.
64 EasyUnlockPrivateCryptoDelegate* GetCryptoDelegate(
65 content::BrowserContext* context) {
66 return BrowserContextKeyedAPIFactory<EasyUnlockPrivateAPI>::Get(context)
67 ->GetCryptoDelegate();
70 ScreenlockState ToScreenlockState(easy_unlock_private::State state) {
71 switch (state) {
72 case easy_unlock_private::STATE_NO_BLUETOOTH:
73 return ScreenlockState::NO_BLUETOOTH;
74 case easy_unlock_private::STATE_BLUETOOTH_CONNECTING:
75 return ScreenlockState::BLUETOOTH_CONNECTING;
76 case easy_unlock_private::STATE_NO_PHONE:
77 return ScreenlockState::NO_PHONE;
78 case easy_unlock_private::STATE_PHONE_NOT_AUTHENTICATED:
79 return ScreenlockState::PHONE_NOT_AUTHENTICATED;
80 case easy_unlock_private::STATE_PHONE_LOCKED:
81 return ScreenlockState::PHONE_LOCKED;
82 case easy_unlock_private::STATE_PHONE_UNLOCKABLE:
83 return ScreenlockState::PHONE_NOT_LOCKABLE;
84 case easy_unlock_private::STATE_PHONE_UNSUPPORTED:
85 return ScreenlockState::PHONE_UNSUPPORTED;
86 case easy_unlock_private::STATE_RSSI_TOO_LOW:
87 return ScreenlockState::RSSI_TOO_LOW;
88 case easy_unlock_private::STATE_TX_POWER_TOO_HIGH:
89 return ScreenlockState::TX_POWER_TOO_HIGH;
90 case easy_unlock_private::STATE_PHONE_LOCKED_AND_TX_POWER_TOO_HIGH:
91 return ScreenlockState::PHONE_LOCKED_AND_TX_POWER_TOO_HIGH;
92 case easy_unlock_private::STATE_AUTHENTICATED:
93 return ScreenlockState::AUTHENTICATED;
94 default:
95 return ScreenlockState::INACTIVE;
99 } // namespace
101 // static
102 BrowserContextKeyedAPIFactory<EasyUnlockPrivateAPI>*
103 EasyUnlockPrivateAPI::GetFactoryInstance() {
104 return g_factory.Pointer();
107 EasyUnlockPrivateAPI::EasyUnlockPrivateAPI(content::BrowserContext* context) {
110 EasyUnlockPrivateAPI::~EasyUnlockPrivateAPI() {}
112 EasyUnlockPrivateCryptoDelegate* EasyUnlockPrivateAPI::GetCryptoDelegate() {
113 if (!crypto_delegate_)
114 crypto_delegate_ = EasyUnlockPrivateCryptoDelegate::Create();
115 return crypto_delegate_.get();
118 EasyUnlockPrivateGetStringsFunction::EasyUnlockPrivateGetStringsFunction() {
120 EasyUnlockPrivateGetStringsFunction::~EasyUnlockPrivateGetStringsFunction() {
123 bool EasyUnlockPrivateGetStringsFunction::RunSync() {
124 scoped_ptr<base::DictionaryValue> strings(new base::DictionaryValue);
126 #if defined(OS_CHROMEOS)
127 const base::string16 device_type = ash::GetChromeOSDeviceName();
128 #else
129 // TODO(isherman): Set an appropriate device name for non-ChromeOS devices.
130 const base::string16 device_type = base::ASCIIToUTF16("Chromeschnozzle");
131 #endif // defined(OS_CHROMEOS)
133 #if defined(OS_CHROMEOS)
134 const user_manager::UserManager* manager = user_manager::UserManager::Get();
135 const user_manager::User* user = manager ? manager->GetActiveUser() : NULL;
136 const std::string user_email_utf8 =
137 user ? user->display_email() : std::string();
138 const base::string16 user_email = base::UTF8ToUTF16(user_email_utf8);
139 #else
140 // TODO(isherman): Set an appropriate user display email for non-ChromeOS
141 // platforms.
142 const base::string16 user_email = base::UTF8ToUTF16("superman@example.com");
143 #endif // defined(OS_CHROMEOS)
145 // Common strings.
146 strings->SetString(
147 "learnMoreLinkTitle",
148 l10n_util::GetStringUTF16(IDS_EASY_UNLOCK_LEARN_MORE_LINK_TITLE));
149 strings->SetString("deviceType", device_type);
151 // Setup notification strings.
152 strings->SetString(
153 "setupNotificationTitle",
154 l10n_util::GetStringUTF16(IDS_EASY_UNLOCK_SETUP_NOTIFICATION_TITLE));
155 strings->SetString(
156 "setupNotificationMessage",
157 l10n_util::GetStringFUTF16(IDS_EASY_UNLOCK_SETUP_NOTIFICATION_MESSAGE,
158 device_type));
159 strings->SetString(
160 "setupNotificationButtonTitle",
161 l10n_util::GetStringUTF16(
162 IDS_EASY_UNLOCK_SETUP_NOTIFICATION_BUTTON_TITLE));
164 // Chromebook added to Easy Unlock notification strings.
165 strings->SetString(
166 "chromebookAddedNotificationTitle",
167 l10n_util::GetStringUTF16(
168 IDS_EASY_UNLOCK_CHROMEBOOK_ADDED_NOTIFICATION_TITLE));
169 strings->SetString(
170 "chromebookAddedNotificationMessage",
171 l10n_util::GetStringFUTF16(
172 IDS_EASY_UNLOCK_CHROMEBOOK_ADDED_NOTIFICATION_MESSAGE,
173 device_type));
174 strings->SetString(
175 "chromebookAddedNotificationAboutButton",
176 l10n_util::GetStringUTF16(
177 IDS_EASY_UNLOCK_CHROMEBOOK_ADDED_NOTIFICATION_ABOUT_BUTTON));
179 // Shared "Learn more" button for the pairing changed and pairing change
180 // applied notification.
181 strings->SetString(
182 "phoneChangedNotificationLearnMoreButton",
183 l10n_util::GetStringUTF16(
184 IDS_EASY_UNLOCK_NOTIFICATION_LEARN_MORE_BUTTON));
186 // Pairing changed notification strings.
187 strings->SetString(
188 "phoneChangedNotificationTitle",
189 l10n_util::GetStringUTF16(
190 IDS_EASY_UNLOCK_PAIRING_CHANGED_NOTIFICATION_TITLE));
191 strings->SetString(
192 "phoneChangedNotificationMessage",
193 l10n_util::GetStringFUTF16(
194 IDS_EASY_UNLOCK_PAIRING_CHANGED_NOTIFICATION_MESSAGE,
195 device_type));
196 strings->SetString(
197 "phoneChangedNotificationUpdateButton",
198 l10n_util::GetStringUTF16(
199 IDS_EASY_UNLOCK_PAIRING_CHANGED_NOTIFICATION_UPDATE_BUTTON));
201 // Phone change applied notification strings.
202 strings->SetString(
203 "phoneChangeAppliedNotificationTitle",
204 l10n_util::GetStringUTF16(
205 IDS_EASY_UNLOCK_PAIRING_CHANGE_APPLIED_NOTIFICATION_TITLE));
206 strings->SetString(
207 "phoneChangeAppliedNotificationMessage",
208 l10n_util::GetStringUTF16(
209 IDS_EASY_UNLOCK_PAIRING_CHANGE_APPLIED_NOTIFICATION_MESSAGE));
211 // Setup dialog strings.
212 // Step 1: Intro.
213 strings->SetString(
214 "setupIntroHeaderTitle",
215 l10n_util::GetStringUTF16(IDS_EASY_UNLOCK_SETUP_INTRO_HEADER_TITLE));
216 strings->SetString(
217 "setupIntroHeaderText",
218 l10n_util::GetStringFUTF16(IDS_EASY_UNLOCK_SETUP_INTRO_HEADER_TEXT,
219 device_type,
220 user_email));
221 strings->SetString(
222 "setupIntroFindPhoneButtonLabel",
223 l10n_util::GetStringUTF16(
224 IDS_EASY_UNLOCK_SETUP_INTRO_FIND_PHONE_BUTTON_LABEL));
225 strings->SetString(
226 "setupIntroFindingPhoneButtonLabel",
227 l10n_util::GetStringUTF16(
228 IDS_EASY_UNLOCK_SETUP_INTRO_FINDING_PHONE_BUTTON_LABEL));
229 strings->SetString(
230 "setupIntroRetryFindPhoneButtonLabel",
231 l10n_util::GetStringUTF16(
232 IDS_EASY_UNLOCK_SETUP_INTRO_RETRY_FIND_PHONE_BUTTON_LABEL));
233 strings->SetString(
234 "setupIntroCloseFindPhoneButtonLabel",
235 l10n_util::GetStringUTF16(
236 IDS_EASY_UNLOCK_SETUP_INTRO_CLOSE_FIND_PHONE_BUTTON_LABEL));
237 strings->SetString(
238 "setupIntroHowIsThisSecureLinkText",
239 l10n_util::GetStringUTF16(
240 IDS_EASY_UNLOCK_SETUP_INTRO_HOW_IS_THIS_SECURE_LINK_TEXT));
241 // Step 1.5: Phone found but is not secured with lock screen
242 strings->SetString("setupSecurePhoneHeaderTitle",
243 l10n_util::GetStringUTF16(
244 IDS_EASY_UNLOCK_SETUP_SECURE_PHONE_HEADER_TITLE));
245 strings->SetString(
246 "setupSecurePhoneHeaderText",
247 l10n_util::GetStringFUTF16(IDS_EASY_UNLOCK_SETUP_SECURE_PHONE_HEADER_TEXT,
248 device_type));
249 strings->SetString("setupSecurePhoneButtonLabel",
250 l10n_util::GetStringUTF16(
251 IDS_EASY_UNLOCK_SETUP_SECURE_PHONE_BUTTON_LABEL));
252 strings->SetString("setupSecurePhoneLinkText",
253 l10n_util::GetStringUTF16(
254 IDS_EASY_UNLOCK_SETUP_SECURE_PHONE_LINK_TEXT));
255 // Step 2: Found a viable phone.
256 strings->SetString(
257 "setupFoundPhoneHeaderTitle",
258 l10n_util::GetStringFUTF16(
259 IDS_EASY_UNLOCK_SETUP_FOUND_PHONE_HEADER_TITLE, device_type));
260 strings->SetString(
261 "setupFoundPhoneHeaderText",
262 l10n_util::GetStringFUTF16(
263 IDS_EASY_UNLOCK_SETUP_FOUND_PHONE_HEADER_TEXT, device_type));
264 strings->SetString(
265 "setupFoundPhoneUseThisPhoneButtonLabel",
266 l10n_util::GetStringUTF16(
267 IDS_EASY_UNLOCK_SETUP_FOUND_PHONE_USE_THIS_PHONE_BUTTON_LABEL));
268 strings->SetString("setupFoundPhoneDeviceFormattedButtonLabel",
269 l10n_util::GetStringUTF16(
270 IDS_EASY_UNLOCK_SETUP_FOUND_PHONE_DEVICE_FORMATTED_BUTTON_LABEL));
271 strings->SetString(
272 "setupFoundPhoneSwitchPhoneLinkLabel",
273 l10n_util::GetStringUTF16(
274 IDS_EASY_UNLOCK_SETUP_FOUND_PHONE_SWITCH_PHONE_LINK_LABEL));
275 strings->SetString(
276 "setupPairingPhoneFailedButtonLabel",
277 l10n_util::GetStringUTF16(
278 IDS_EASY_UNLOCK_SETUP_PAIRING_PHONE_FAILED_BUTTON_LABEL));
279 // Step 2.5: Recommend user to set up Android Smart Lock
280 strings->SetString(
281 "setupAndroidSmartLockHeaderTitle",
282 l10n_util::GetStringUTF16(
283 IDS_EASY_UNLOCK_SETUP_ANDROID_SMART_LOCK_HEADER_TITLE));
284 strings->SetString(
285 "setupAndroidSmartLockHeaderText",
286 l10n_util::GetStringFUTF16(
287 IDS_EASY_UNLOCK_SETUP_ANDROID_SMART_LOCK_HEADER_TEXT, device_type));
288 strings->SetString(
289 "setupAndroidSmartLockDoneButtonText",
290 l10n_util::GetStringUTF16(
291 IDS_EASY_UNLOCK_SETUP_ANDROID_SMART_LOCK_DONE_BUTTON_LABEL));
292 strings->SetString(
293 "setupAndroidSmartLockAboutLinkText",
294 l10n_util::GetStringUTF16(
295 IDS_EASY_UNLOCK_SETUP_ANDROID_SMART_LOCK_ABOUT_LINK_TEXT));
296 // Step 3: Setup completed successfully.
297 strings->SetString(
298 "setupCompleteHeaderTitle",
299 l10n_util::GetStringUTF16(
300 IDS_EASY_UNLOCK_SETUP_COMPLETE_HEADER_TITLE));
301 strings->SetString(
302 "setupCompleteHeaderText",
303 l10n_util::GetStringUTF16(
304 IDS_EASY_UNLOCK_SETUP_COMPLETE_HEADER_TEXT));
305 strings->SetString(
306 "setupCompleteTryItOutButtonLabel",
307 l10n_util::GetStringUTF16(
308 IDS_EASY_UNLOCK_SETUP_COMPLETE_TRY_IT_OUT_BUTTON_LABEL));
309 strings->SetString(
310 "setupCompleteSettingsLinkText",
311 l10n_util::GetStringUTF16(
312 IDS_EASY_UNLOCK_SETUP_COMPLETE_SETTINGS_LINK_TEXT));
313 // Step 4: Post lockscreen confirmation.
314 strings->SetString("setupPostLockDismissButtonLabel",
315 l10n_util::GetStringUTF16(
316 IDS_EASY_UNLOCK_SETUP_POST_LOCK_DISMISS_BUTTON_LABEL));
318 // Error strings.
319 strings->SetString(
320 "setupErrorBluetoothUnavailable",
321 l10n_util::GetStringFUTF16(
322 IDS_EASY_UNLOCK_SETUP_ERROR_BLUETOOTH_UNAVAILBLE, device_type));
323 strings->SetString(
324 "setupErrorOffline",
325 l10n_util::GetStringFUTF16(
326 IDS_EASY_UNLOCK_SETUP_ERROR_OFFLINE, device_type));
327 strings->SetString(
328 "setupErrorRemoteSoftwareOutOfDate",
329 l10n_util::GetStringUTF16(
330 IDS_EASY_UNLOCK_SETUP_ERROR_REMOTE_SOFTWARE_OUT_OF_DATE));
331 strings->SetString(
332 "setupErrorRemoteSoftwareOutOfDateGeneric",
333 l10n_util::GetStringUTF16(
334 IDS_EASY_UNLOCK_SETUP_ERROR_REMOTE_SOFTWARE_OUT_OF_DATE_GENERIC));
335 strings->SetString(
336 "setupErrorFindingPhone",
337 l10n_util::GetStringUTF16(IDS_EASY_UNLOCK_SETUP_ERROR_FINDING_PHONE));
338 strings->SetString(
339 "setupErrorSyncPhoneState",
340 l10n_util::GetStringUTF16(
341 IDS_EASY_UNLOCK_SETUP_ERROR_SYNC_PHONE_STATE_FAILED));
342 strings->SetString(
343 "setupErrorConnectingToPhone",
344 l10n_util::GetStringFUTF16(
345 IDS_EASY_UNLOCK_SETUP_ERROR_CONNECTING_TO_PHONE, device_type));
347 SetResult(strings.release());
348 return true;
351 EasyUnlockPrivatePerformECDHKeyAgreementFunction::
352 EasyUnlockPrivatePerformECDHKeyAgreementFunction() {}
354 EasyUnlockPrivatePerformECDHKeyAgreementFunction::
355 ~EasyUnlockPrivatePerformECDHKeyAgreementFunction() {}
357 bool EasyUnlockPrivatePerformECDHKeyAgreementFunction::RunAsync() {
358 scoped_ptr<easy_unlock_private::PerformECDHKeyAgreement::Params> params =
359 easy_unlock_private::PerformECDHKeyAgreement::Params::Create(*args_);
360 EXTENSION_FUNCTION_VALIDATE(params);
362 GetCryptoDelegate(browser_context())->PerformECDHKeyAgreement(
363 *params,
364 base::Bind(&EasyUnlockPrivatePerformECDHKeyAgreementFunction::OnData,
365 this));
366 return true;
369 void EasyUnlockPrivatePerformECDHKeyAgreementFunction::OnData(
370 const std::string& secret_key) {
371 // TODO(tbarzic): Improve error handling.
372 if (!secret_key.empty()) {
373 results_ = easy_unlock_private::PerformECDHKeyAgreement::Results::Create(
374 std::vector<char>(secret_key.begin(), secret_key.end()));
376 SendResponse(true);
379 EasyUnlockPrivateGenerateEcP256KeyPairFunction::
380 EasyUnlockPrivateGenerateEcP256KeyPairFunction() {}
382 EasyUnlockPrivateGenerateEcP256KeyPairFunction::
383 ~EasyUnlockPrivateGenerateEcP256KeyPairFunction() {}
385 bool EasyUnlockPrivateGenerateEcP256KeyPairFunction::RunAsync() {
386 GetCryptoDelegate(browser_context())->GenerateEcP256KeyPair(
387 base::Bind(&EasyUnlockPrivateGenerateEcP256KeyPairFunction::OnData,
388 this));
389 return true;
392 void EasyUnlockPrivateGenerateEcP256KeyPairFunction::OnData(
393 const std::string& private_key,
394 const std::string& public_key) {
395 // TODO(tbarzic): Improve error handling.
396 if (!public_key.empty() && !private_key.empty()) {
397 results_ = easy_unlock_private::GenerateEcP256KeyPair::Results::Create(
398 std::vector<char>(public_key.begin(), public_key.end()),
399 std::vector<char>(private_key.begin(), private_key.end()));
401 SendResponse(true);
404 EasyUnlockPrivateCreateSecureMessageFunction::
405 EasyUnlockPrivateCreateSecureMessageFunction() {}
407 EasyUnlockPrivateCreateSecureMessageFunction::
408 ~EasyUnlockPrivateCreateSecureMessageFunction() {}
410 bool EasyUnlockPrivateCreateSecureMessageFunction::RunAsync() {
411 scoped_ptr<easy_unlock_private::CreateSecureMessage::Params> params =
412 easy_unlock_private::CreateSecureMessage::Params::Create(*args_);
413 EXTENSION_FUNCTION_VALIDATE(params);
415 GetCryptoDelegate(browser_context())->CreateSecureMessage(
416 *params,
417 base::Bind(&EasyUnlockPrivateCreateSecureMessageFunction::OnData,
418 this));
419 return true;
422 void EasyUnlockPrivateCreateSecureMessageFunction::OnData(
423 const std::string& message) {
424 // TODO(tbarzic): Improve error handling.
425 if (!message.empty()) {
426 results_ = easy_unlock_private::CreateSecureMessage::Results::Create(
427 std::vector<char>(message.begin(), message.end()));
429 SendResponse(true);
432 EasyUnlockPrivateUnwrapSecureMessageFunction::
433 EasyUnlockPrivateUnwrapSecureMessageFunction() {}
435 EasyUnlockPrivateUnwrapSecureMessageFunction::
436 ~EasyUnlockPrivateUnwrapSecureMessageFunction() {}
438 bool EasyUnlockPrivateUnwrapSecureMessageFunction::RunAsync() {
439 scoped_ptr<easy_unlock_private::UnwrapSecureMessage::Params> params =
440 easy_unlock_private::UnwrapSecureMessage::Params::Create(*args_);
441 EXTENSION_FUNCTION_VALIDATE(params);
443 GetCryptoDelegate(browser_context())->UnwrapSecureMessage(
444 *params,
445 base::Bind(&EasyUnlockPrivateUnwrapSecureMessageFunction::OnData,
446 this));
447 return true;
450 void EasyUnlockPrivateUnwrapSecureMessageFunction::OnData(
451 const std::string& data) {
452 // TODO(tbarzic): Improve error handling.
453 if (!data.empty()) {
454 results_ = easy_unlock_private::UnwrapSecureMessage::Results::Create(
455 std::vector<char>(data.begin(), data.end()));
457 SendResponse(true);
460 EasyUnlockPrivateSeekBluetoothDeviceByAddressFunction::
461 EasyUnlockPrivateSeekBluetoothDeviceByAddressFunction() {}
463 EasyUnlockPrivateSeekBluetoothDeviceByAddressFunction::
464 ~EasyUnlockPrivateSeekBluetoothDeviceByAddressFunction() {}
466 bool EasyUnlockPrivateSeekBluetoothDeviceByAddressFunction::RunAsync() {
467 scoped_ptr<easy_unlock_private::SeekBluetoothDeviceByAddress::Params> params(
468 easy_unlock_private::SeekBluetoothDeviceByAddress::Params::Create(
469 *args_));
470 EXTENSION_FUNCTION_VALIDATE(params.get());
472 proximity_auth::bluetooth_util::SeekDeviceByAddress(
473 params->device_address,
474 base::Bind(
475 &EasyUnlockPrivateSeekBluetoothDeviceByAddressFunction::OnSeekSuccess,
476 this),
477 base::Bind(
478 &EasyUnlockPrivateSeekBluetoothDeviceByAddressFunction::OnSeekFailure,
479 this),
480 content::BrowserThread::GetBlockingPool()
481 ->GetTaskRunnerWithShutdownBehavior(
482 base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN)
483 .get());
484 return true;
487 void EasyUnlockPrivateSeekBluetoothDeviceByAddressFunction::OnSeekSuccess() {
488 SendResponse(true);
491 void EasyUnlockPrivateSeekBluetoothDeviceByAddressFunction::OnSeekFailure(
492 const std::string& error_message) {
493 SetError(error_message);
494 SendResponse(false);
497 EasyUnlockPrivateConnectToBluetoothServiceInsecurelyFunction::
498 EasyUnlockPrivateConnectToBluetoothServiceInsecurelyFunction() {}
500 EasyUnlockPrivateConnectToBluetoothServiceInsecurelyFunction::
501 ~EasyUnlockPrivateConnectToBluetoothServiceInsecurelyFunction() {}
503 void EasyUnlockPrivateConnectToBluetoothServiceInsecurelyFunction::
504 ConnectToService(device::BluetoothDevice* device,
505 const device::BluetoothUUID& uuid) {
506 device->ConnectToServiceInsecurely(
507 uuid,
508 base::Bind(&EasyUnlockPrivateConnectToBluetoothServiceInsecurelyFunction::
509 OnConnect,
510 this),
511 base::Bind(&EasyUnlockPrivateConnectToBluetoothServiceInsecurelyFunction::
512 OnConnectError,
513 this));
516 EasyUnlockPrivateUpdateScreenlockStateFunction::
517 EasyUnlockPrivateUpdateScreenlockStateFunction() {}
519 EasyUnlockPrivateUpdateScreenlockStateFunction::
520 ~EasyUnlockPrivateUpdateScreenlockStateFunction() {}
522 bool EasyUnlockPrivateUpdateScreenlockStateFunction::RunSync() {
523 scoped_ptr<easy_unlock_private::UpdateScreenlockState::Params> params(
524 easy_unlock_private::UpdateScreenlockState::Params::Create(*args_));
525 EXTENSION_FUNCTION_VALIDATE(params.get());
527 Profile* profile = Profile::FromBrowserContext(browser_context());
528 if (EasyUnlockService::Get(profile)->UpdateScreenlockState(
529 ToScreenlockState(params->state)))
530 return true;
532 SetError("Not allowed");
533 return false;
536 EasyUnlockPrivateSetPermitAccessFunction::
537 EasyUnlockPrivateSetPermitAccessFunction() {
540 EasyUnlockPrivateSetPermitAccessFunction::
541 ~EasyUnlockPrivateSetPermitAccessFunction() {
544 bool EasyUnlockPrivateSetPermitAccessFunction::RunSync() {
545 scoped_ptr<easy_unlock_private::SetPermitAccess::Params> params(
546 easy_unlock_private::SetPermitAccess::Params::Create(*args_));
547 EXTENSION_FUNCTION_VALIDATE(params.get());
549 Profile* profile = Profile::FromBrowserContext(browser_context());
550 EasyUnlockService::Get(profile)
551 ->SetPermitAccess(*params->permit_access.ToValue());
553 return true;
556 EasyUnlockPrivateGetPermitAccessFunction::
557 EasyUnlockPrivateGetPermitAccessFunction() {
560 EasyUnlockPrivateGetPermitAccessFunction::
561 ~EasyUnlockPrivateGetPermitAccessFunction() {
564 bool EasyUnlockPrivateGetPermitAccessFunction::RunSync() {
565 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
566 proximity_auth::switches::kEnableBluetoothLowEnergyDiscovery)) {
567 ReturnPermitAccessForExperiment();
568 return true;
571 Profile* profile = Profile::FromBrowserContext(browser_context());
572 const base::DictionaryValue* permit_value =
573 EasyUnlockService::Get(profile)->GetPermitAccess();
574 if (permit_value) {
575 scoped_ptr<easy_unlock_private::PermitRecord> permit =
576 easy_unlock_private::PermitRecord::FromValue(*permit_value);
577 results_ = easy_unlock_private::GetPermitAccess::Results::Create(*permit);
580 return true;
583 void EasyUnlockPrivateGetPermitAccessFunction::GetKeyPairForExperiment(
584 std::string* user_public_key,
585 std::string* user_private_key) {
586 Profile* profile = Profile::FromBrowserContext(browser_context());
587 proximity_auth::CryptAuthEnrollmentManager* enrollment_manager =
588 EasyUnlockService::Get(profile)
589 ->proximity_auth_client()
590 ->GetCryptAuthEnrollmentManager();
591 proximity_auth::Base64UrlEncode(enrollment_manager->GetUserPublicKey(),
592 user_public_key);
593 proximity_auth::Base64UrlEncode(enrollment_manager->GetUserPrivateKey(),
594 user_private_key);
597 void EasyUnlockPrivateGetPermitAccessFunction::
598 ReturnPermitAccessForExperiment() {
599 // Check that we are inside a user session.
600 Profile* profile = Profile::FromBrowserContext(browser_context());
601 EasyUnlockService* easy_unlock_service = EasyUnlockService::Get(profile);
602 if (easy_unlock_service->GetType() != EasyUnlockService::TYPE_REGULAR) {
603 SetError("This function must be called inside a user session.");
604 SendResponse(true);
605 return;
608 std::string b64_public_key, b64_private_key;
609 GetKeyPairForExperiment(&b64_public_key, &b64_private_key);
611 // Fill in the permit access JSON dictionary.
612 proximity_auth::ProximityAuthClient* client =
613 easy_unlock_service->proximity_auth_client();
614 scoped_ptr<base::DictionaryValue> permit_access(new base::DictionaryValue());
615 permit_access->SetString("permitId",
616 "permit://google.com/" + client->GetAccountId());
617 permit_access->SetString("id", b64_public_key);
618 permit_access->SetString("type", "access");
619 permit_access->SetString("data", b64_private_key);
621 PA_LOG(INFO) << "Returning permit access for "
622 << "chrome.easyUnlockPrivate.getPermitAccess:\n"
623 << " id: " << b64_public_key;
625 scoped_ptr<easy_unlock_private::PermitRecord> result =
626 easy_unlock_private::PermitRecord::FromValue(*permit_access);
627 results_ = easy_unlock_private::GetPermitAccess::Results::Create(*result);
630 EasyUnlockPrivateClearPermitAccessFunction::
631 EasyUnlockPrivateClearPermitAccessFunction() {
634 EasyUnlockPrivateClearPermitAccessFunction::
635 ~EasyUnlockPrivateClearPermitAccessFunction() {
638 bool EasyUnlockPrivateClearPermitAccessFunction::RunSync() {
639 Profile* profile = Profile::FromBrowserContext(browser_context());
640 EasyUnlockService::Get(profile)->ClearPermitAccess();
641 return true;
644 EasyUnlockPrivateSetRemoteDevicesFunction::
645 EasyUnlockPrivateSetRemoteDevicesFunction() {
648 EasyUnlockPrivateSetRemoteDevicesFunction::
649 ~EasyUnlockPrivateSetRemoteDevicesFunction() {
652 bool EasyUnlockPrivateSetRemoteDevicesFunction::RunSync() {
653 scoped_ptr<easy_unlock_private::SetRemoteDevices::Params> params(
654 easy_unlock_private::SetRemoteDevices::Params::Create(*args_));
655 EXTENSION_FUNCTION_VALIDATE(params.get());
657 Profile* profile = Profile::FromBrowserContext(browser_context());
658 base::ListValue devices;
659 for (size_t i = 0; i < params->devices.size(); ++i) {
660 devices.Append(params->devices[i]->ToValue().release());
662 EasyUnlockService::Get(profile)->SetRemoteDevices(devices);
664 return true;
667 EasyUnlockPrivateGetRemoteDevicesFunction::
668 EasyUnlockPrivateGetRemoteDevicesFunction() {
671 EasyUnlockPrivateGetRemoteDevicesFunction::
672 ~EasyUnlockPrivateGetRemoteDevicesFunction() {
675 bool EasyUnlockPrivateGetRemoteDevicesFunction::RunAsync() {
676 // Return the remote devices stored with the native CryptAuthDeviceManager if
677 // we are trying out the BLE experiment.
678 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
679 proximity_auth::switches::kEnableBluetoothLowEnergyDiscovery)) {
680 ReturnDevicesForExperiment();
681 } else {
682 Profile* profile = Profile::FromBrowserContext(browser_context());
683 const base::ListValue* devices =
684 EasyUnlockService::Get(profile)->GetRemoteDevices();
685 SetResult(devices ? devices->DeepCopy() : new base::ListValue());
686 SendResponse(true);
689 return true;
692 std::string EasyUnlockPrivateGetRemoteDevicesFunction::GetUserPrivateKey() {
693 Profile* profile = Profile::FromBrowserContext(browser_context());
694 proximity_auth::ProximityAuthClient* client =
695 EasyUnlockService::Get(profile)->proximity_auth_client();
696 proximity_auth::CryptAuthEnrollmentManager* enrollment_manager =
697 client->GetCryptAuthEnrollmentManager();
698 return enrollment_manager->GetUserPrivateKey();
701 std::vector<cryptauth::ExternalDeviceInfo>
702 EasyUnlockPrivateGetRemoteDevicesFunction::GetUnlockKeys() {
703 Profile* profile = Profile::FromBrowserContext(browser_context());
704 proximity_auth::ProximityAuthClient* client =
705 EasyUnlockService::Get(profile)->proximity_auth_client();
706 proximity_auth::CryptAuthDeviceManager* device_manager =
707 client->GetCryptAuthDeviceManager();
708 return device_manager->unlock_keys();
711 void EasyUnlockPrivateGetRemoteDevicesFunction::ReturnDevicesForExperiment() {
712 // Check that we are inside a user profile.
713 Profile* profile = Profile::FromBrowserContext(browser_context());
714 EasyUnlockService* easy_unlock_service = EasyUnlockService::Get(profile);
715 if (easy_unlock_service->GetType() != EasyUnlockService::TYPE_REGULAR) {
716 SetError("This function must be called inside a user session.");
717 SendResponse(true);
718 return;
721 // Get the synced unlock key data.
722 proximity_auth::ProximityAuthClient* client =
723 easy_unlock_service->proximity_auth_client();
725 permit_id_ = "permit://google.com/easyunlock/v1/" + client->GetAccountId();
726 secure_message_delegate_ = client->CreateSecureMessageDelegate();
727 std::vector<cryptauth::ExternalDeviceInfo> unlock_keys = GetUnlockKeys();
728 expected_devices_count_ = unlock_keys.size();
730 remote_devices_.reset(new base::ListValue());
731 if (expected_devices_count_ == 0) {
732 SetResult(remote_devices_.Pass());
733 SendResponse(true);
734 return;
737 // If there is a BLE unlock key, then don't return anything, so the app does
738 // not try the classic Bluetooth protocol.
739 for (const auto& unlock_key : unlock_keys) {
740 if (unlock_key.bluetooth_address().empty()) {
741 SetResult(remote_devices_.Pass());
742 SendResponse(true);
743 return;
747 // Derive the PSKs for the user's unlock keys.
748 PA_LOG(INFO) << "Deriving PSKs for "
749 << "chrome.easyUnlockPrivate.getRemoteDevices.\n"
750 << "Expecting " << expected_devices_count_ << " devices.";
751 for (const auto& unlock_key : unlock_keys) {
752 secure_message_delegate_->DeriveKey(
753 GetUserPrivateKey(), unlock_key.public_key(),
754 base::Bind(
755 &EasyUnlockPrivateGetRemoteDevicesFunction::OnPSKDerivedForDevice,
756 this, unlock_key));
760 void EasyUnlockPrivateGetRemoteDevicesFunction::OnPSKDerivedForDevice(
761 const cryptauth::ExternalDeviceInfo& device,
762 const std::string& persistent_symmetric_key) {
763 std::string b64_public_key, b64_psk;
764 proximity_auth::Base64UrlEncode(device.public_key(), &b64_public_key);
765 proximity_auth::Base64UrlEncode(persistent_symmetric_key, &b64_psk);
767 // Fill in the JSON dictionary containing a single unlock key's data.
768 scoped_ptr<base::DictionaryValue> device_dictionary(
769 new base::DictionaryValue());
770 device_dictionary->SetString("name", device.friendly_device_name());
771 device_dictionary->SetString("bluetoothAddress", device.bluetooth_address());
772 device_dictionary->SetString("psk", b64_psk);
774 // Fill in the permit license for the unlock key.
775 scoped_ptr<base::DictionaryValue> permit_license(new base::DictionaryValue());
776 permit_license->SetString("permitId", permit_id_);
777 permit_license->SetString("id", b64_public_key);
778 permit_license->SetString("type", "license");
779 permit_license->SetString("data", b64_public_key);
780 device_dictionary->Set("permitRecord", permit_license.Pass());
782 remote_devices_->Append(device_dictionary.Pass());
784 // If all PSKs are derived, then return from the API call.
785 PA_LOG(INFO) << "Derived PSK for " << b64_public_key << ": "
786 << remote_devices_->GetSize() << "/" << expected_devices_count_;
787 if (remote_devices_->GetSize() == expected_devices_count_) {
788 SetResult(remote_devices_.Pass());
789 SendResponse(true);
793 EasyUnlockPrivateGetSignInChallengeFunction::
794 EasyUnlockPrivateGetSignInChallengeFunction() {
797 EasyUnlockPrivateGetSignInChallengeFunction::
798 ~EasyUnlockPrivateGetSignInChallengeFunction() {
801 bool EasyUnlockPrivateGetSignInChallengeFunction::RunAsync() {
802 scoped_ptr<easy_unlock_private::GetSignInChallenge::Params> params(
803 easy_unlock_private::GetSignInChallenge::Params::Create(*args_));
804 EXTENSION_FUNCTION_VALIDATE(params.get());
806 #if defined(OS_CHROMEOS)
807 Profile* profile = Profile::FromBrowserContext(browser_context());
808 const std::string challenge =
809 EasyUnlockService::Get(profile)->GetChallenge();
810 if (!challenge.empty() && !params->nonce.empty()) {
811 EasyUnlockTpmKeyManager* key_manager =
812 EasyUnlockTpmKeyManagerFactory::GetInstance()->Get(profile);
813 if (!key_manager) {
814 SetError("No EasyUnlockTpmKeyManager.");
815 return false;
817 key_manager->SignUsingTpmKey(
818 EasyUnlockService::Get(profile)->GetUserEmail(),
819 std::string(params->nonce.begin(), params->nonce.end()),
820 base::Bind(&EasyUnlockPrivateGetSignInChallengeFunction::OnDone, this,
821 challenge));
822 } else {
823 OnDone(challenge, std::string());
825 return true;
826 #else // if !defined(OS_CHROMEOS)
827 SetError("Sign-in not supported.");
828 return false;
829 #endif // defined(OS_CHROMEOS)
832 void EasyUnlockPrivateGetSignInChallengeFunction::OnDone(
833 const std::string& challenge,
834 const std::string& signed_nonce) {
835 results_ = easy_unlock_private::GetSignInChallenge::Results::Create(
836 std::vector<char>(challenge.begin(), challenge.end()),
837 std::vector<char>(signed_nonce.begin(), signed_nonce.end()));
838 SendResponse(true);
841 EasyUnlockPrivateTrySignInSecretFunction::
842 EasyUnlockPrivateTrySignInSecretFunction() {
845 EasyUnlockPrivateTrySignInSecretFunction::
846 ~EasyUnlockPrivateTrySignInSecretFunction() {
849 bool EasyUnlockPrivateTrySignInSecretFunction::RunSync() {
850 scoped_ptr<easy_unlock_private::TrySignInSecret::Params> params(
851 easy_unlock_private::TrySignInSecret::Params::Create(*args_));
852 EXTENSION_FUNCTION_VALIDATE(params.get());
854 Profile* profile = Profile::FromBrowserContext(browser_context());
855 EasyUnlockService::Get(profile)->FinalizeSignin(std::string(
856 params->sign_in_secret.begin(), params->sign_in_secret.end()));
857 return true;
860 EasyUnlockPrivateGetUserInfoFunction::EasyUnlockPrivateGetUserInfoFunction() {
863 EasyUnlockPrivateGetUserInfoFunction::~EasyUnlockPrivateGetUserInfoFunction() {
866 bool EasyUnlockPrivateGetUserInfoFunction::RunSync() {
867 EasyUnlockService* service =
868 EasyUnlockService::Get(Profile::FromBrowserContext(browser_context()));
869 std::vector<linked_ptr<easy_unlock_private::UserInfo> > users;
870 std::string user_id = service->GetUserEmail();
871 if (!user_id.empty()) {
872 users.push_back(
873 linked_ptr<easy_unlock_private::UserInfo>(
874 new easy_unlock_private::UserInfo()));
875 users[0]->user_id = user_id;
876 users[0]->logged_in = service->GetType() == EasyUnlockService::TYPE_REGULAR;
877 users[0]->data_ready = users[0]->logged_in ||
878 service->GetRemoteDevices() != NULL;
880 EasyUnlockService::UserSettings user_settings =
881 EasyUnlockService::GetUserSettings(user_id);
882 users[0]->require_close_proximity = user_settings.require_close_proximity;
884 users[0]->device_user_id = proximity_auth::CalculateDeviceUserId(
885 EasyUnlockService::GetDeviceId(), user_id);
887 results_ = easy_unlock_private::GetUserInfo::Results::Create(users);
888 return true;
891 EasyUnlockPrivateGetConnectionInfoFunction::
892 EasyUnlockPrivateGetConnectionInfoFunction() {
895 EasyUnlockPrivateGetConnectionInfoFunction::
896 ~EasyUnlockPrivateGetConnectionInfoFunction() {
899 bool EasyUnlockPrivateGetConnectionInfoFunction::DoWork(
900 scoped_refptr<device::BluetoothAdapter> adapter) {
901 scoped_ptr<easy_unlock_private::GetConnectionInfo::Params> params =
902 easy_unlock_private::GetConnectionInfo::Params::Create(*args_);
903 EXTENSION_FUNCTION_VALIDATE(params);
905 device::BluetoothDevice* device = adapter->GetDevice(params->device_address);
907 std::string error;
908 if (!device)
909 error = "Invalid Bluetooth device.";
910 else if (!device->IsConnected())
911 error = "Bluetooth device not connected.";
913 if (!error.empty()) {
914 SetError(error);
915 SendResponse(false);
916 return true;
919 device->GetConnectionInfo(base::Bind(
920 &EasyUnlockPrivateGetConnectionInfoFunction::OnConnectionInfo, this));
921 return false;
924 void EasyUnlockPrivateGetConnectionInfoFunction::OnConnectionInfo(
925 const device::BluetoothDevice::ConnectionInfo& connection_info) {
926 scoped_ptr<base::ListValue> results(new base::ListValue());
927 results->AppendInteger(connection_info.rssi);
928 results->AppendInteger(connection_info.transmit_power);
929 results->AppendInteger(connection_info.max_transmit_power);
930 SetResultList(results.Pass());
931 SendResponse(true);
934 EasyUnlockPrivateShowErrorBubbleFunction::
935 EasyUnlockPrivateShowErrorBubbleFunction() {
938 EasyUnlockPrivateShowErrorBubbleFunction::
939 ~EasyUnlockPrivateShowErrorBubbleFunction() {
942 bool EasyUnlockPrivateShowErrorBubbleFunction::RunSync() {
943 content::WebContents* web_contents = GetAssociatedWebContents();
944 if (!web_contents) {
945 SetError("A foreground app window is required.");
946 return true;
949 scoped_ptr<easy_unlock_private::ShowErrorBubble::Params> params(
950 easy_unlock_private::ShowErrorBubble::Params::Create(*args_));
951 EXTENSION_FUNCTION_VALIDATE(params.get());
953 if (params->link_range.start < 0 ||
954 params->link_range.end < 0 ||
955 base::saturated_cast<size_t>(params->link_range.end) >
956 params->message.size()) {
957 SetError("Invalid link range.");
958 return true;
961 #if defined(TOOLKIT_VIEWS)
962 gfx::Rect anchor_rect(
963 params->anchor_rect.left, params->anchor_rect.top,
964 params->anchor_rect.width, params->anchor_rect.height);
965 anchor_rect +=
966 web_contents->GetContainerBounds().OffsetFromOrigin();
967 ShowProximityAuthErrorBubble(
968 base::UTF8ToUTF16(params->message),
969 gfx::Range(params->link_range.start, params->link_range.end),
970 GURL(params->link_target), anchor_rect, web_contents);
971 #else
972 SetError("Not supported on non-Views platforms.");
973 #endif
974 return true;
977 EasyUnlockPrivateHideErrorBubbleFunction::
978 EasyUnlockPrivateHideErrorBubbleFunction() {
981 EasyUnlockPrivateHideErrorBubbleFunction::
982 ~EasyUnlockPrivateHideErrorBubbleFunction() {
985 bool EasyUnlockPrivateHideErrorBubbleFunction::RunSync() {
986 #if defined(TOOLKIT_VIEWS)
987 HideProximityAuthErrorBubble();
988 #else
989 SetError("Not supported on non-Views platforms.");
990 #endif
991 return true;
994 EasyUnlockPrivateSetAutoPairingResultFunction::
995 EasyUnlockPrivateSetAutoPairingResultFunction() {
998 EasyUnlockPrivateSetAutoPairingResultFunction::
999 ~EasyUnlockPrivateSetAutoPairingResultFunction() {
1002 bool EasyUnlockPrivateSetAutoPairingResultFunction::RunSync() {
1003 scoped_ptr<easy_unlock_private::SetAutoPairingResult::Params> params =
1004 easy_unlock_private::SetAutoPairingResult::Params::Create(*args_);
1005 EXTENSION_FUNCTION_VALIDATE(params);
1007 std::string error_message;
1008 if (params->result.error_message)
1009 error_message = *params->result.error_message;
1011 Profile* profile = Profile::FromBrowserContext(browser_context());
1012 EasyUnlockService::Get(profile)
1013 ->SetAutoPairingResult(params->result.success, error_message);
1015 return true;
1018 } // namespace extensions