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"
10 #include "base/lazy_instance.h"
11 #include "base/memory/linked_ptr.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/values.h"
14 #include "chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_crypto_delegate.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/signin/easy_unlock_screenlock_state_handler.h"
17 #include "chrome/browser/signin/easy_unlock_service.h"
18 #include "chrome/common/extensions/api/easy_unlock_private.h"
19 #include "chrome/grit/generated_resources.h"
20 #include "components/proximity_auth/bluetooth_util.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "extensions/browser/browser_context_keyed_api_factory.h"
23 #include "ui/base/l10n/l10n_util.h"
25 #if defined(OS_CHROMEOS)
26 #include "chrome/browser/chromeos/chromeos_utils.h"
27 #include "components/user_manager/user.h"
28 #include "components/user_manager/user_manager.h"
31 namespace extensions {
36 static base::LazyInstance<BrowserContextKeyedAPIFactory<EasyUnlockPrivateAPI> >
37 g_factory = LAZY_INSTANCE_INITIALIZER;
39 // Utility method for getting the API's crypto delegate.
40 EasyUnlockPrivateCryptoDelegate* GetCryptoDelegate(
41 content::BrowserContext* context) {
42 return BrowserContextKeyedAPIFactory<EasyUnlockPrivateAPI>::Get(context)
46 EasyUnlockScreenlockStateHandler::State ToScreenlockStateHandlerState(
47 easy_unlock_private::State state) {
49 case easy_unlock_private::STATE_NO_BLUETOOTH:
50 return EasyUnlockScreenlockStateHandler::STATE_NO_BLUETOOTH;
51 case easy_unlock_private::STATE_BLUETOOTH_CONNECTING:
52 return EasyUnlockScreenlockStateHandler::STATE_BLUETOOTH_CONNECTING;
53 case easy_unlock_private::STATE_NO_PHONE:
54 return EasyUnlockScreenlockStateHandler::STATE_NO_PHONE;
55 case easy_unlock_private::STATE_PHONE_NOT_AUTHENTICATED:
56 return EasyUnlockScreenlockStateHandler::STATE_PHONE_NOT_AUTHENTICATED;
57 case easy_unlock_private::STATE_PHONE_LOCKED:
58 return EasyUnlockScreenlockStateHandler::STATE_PHONE_LOCKED;
59 case easy_unlock_private::STATE_PHONE_UNLOCKABLE:
60 return EasyUnlockScreenlockStateHandler::STATE_PHONE_UNLOCKABLE;
61 case easy_unlock_private::STATE_PHONE_NOT_NEARBY:
62 return EasyUnlockScreenlockStateHandler::STATE_PHONE_NOT_NEARBY;
63 case easy_unlock_private::STATE_PHONE_UNSUPPORTED:
64 return EasyUnlockScreenlockStateHandler::STATE_PHONE_UNSUPPORTED;
65 case easy_unlock_private::STATE_AUTHENTICATED:
66 return EasyUnlockScreenlockStateHandler::STATE_AUTHENTICATED;
68 return EasyUnlockScreenlockStateHandler::STATE_INACTIVE;
75 BrowserContextKeyedAPIFactory<EasyUnlockPrivateAPI>*
76 EasyUnlockPrivateAPI::GetFactoryInstance() {
77 return g_factory.Pointer();
80 EasyUnlockPrivateAPI::EasyUnlockPrivateAPI(content::BrowserContext* context)
81 : crypto_delegate_(EasyUnlockPrivateCryptoDelegate::Create()) {
84 EasyUnlockPrivateAPI::~EasyUnlockPrivateAPI() {}
86 EasyUnlockPrivateGetStringsFunction::EasyUnlockPrivateGetStringsFunction() {
88 EasyUnlockPrivateGetStringsFunction::~EasyUnlockPrivateGetStringsFunction() {
91 bool EasyUnlockPrivateGetStringsFunction::RunSync() {
92 scoped_ptr<base::DictionaryValue> strings(new base::DictionaryValue);
94 #if defined(OS_CHROMEOS)
95 const base::string16 device_type = chromeos::GetChromeDeviceType();
97 // TODO(isherman): Set an appropriate device name for non-ChromeOS devices.
98 const base::string16 device_type = base::ASCIIToUTF16("Chromeschnozzle");
99 #endif // defined(OS_CHROMEOS)
101 #if defined(OS_CHROMEOS)
102 const user_manager::UserManager* manager = user_manager::UserManager::Get();
103 const user_manager::User* user = manager ? manager->GetActiveUser() : NULL;
104 const std::string user_email_utf8 =
105 user ? user->display_email() : std::string();
106 const base::string16 user_email = base::UTF8ToUTF16(user_email_utf8);
108 // TODO(isherman): Set an appropriate user display email for non-ChromeOS
110 const base::string16 user_email = base::UTF8ToUTF16("superman@example.com");
111 #endif // defined(OS_CHROMEOS)
115 "learnMoreLinkTitle",
116 l10n_util::GetStringUTF16(IDS_EASY_UNLOCK_LEARN_MORE_LINK_TITLE));
118 // Setup notification strings.
120 "setupNotificationTitle",
121 l10n_util::GetStringFUTF16(IDS_EASY_UNLOCK_SETUP_NOTIFICATION_TITLE,
124 "setupNotificationMessage",
125 l10n_util::GetStringFUTF16(IDS_EASY_UNLOCK_SETUP_NOTIFICATION_MESSAGE,
128 "setupNotificationButtonTitle",
129 l10n_util::GetStringUTF16(
130 IDS_EASY_UNLOCK_SETUP_NOTIFICATION_BUTTON_TITLE));
132 // Success notification strings.
134 "successNotificationTitle",
135 l10n_util::GetStringUTF16(IDS_EASY_UNLOCK_SUCCESS_NOTIFICATION_TITLE));
137 "successNotificationMessage",
138 l10n_util::GetStringFUTF16(IDS_EASY_UNLOCK_SUCCESS_NOTIFICATION_MESSAGE,
141 // Chromebook added to Easy Unlock notification strings.
143 "chromebookAddedNotificationTitle",
144 l10n_util::GetStringUTF16(
145 IDS_EASY_UNLOCK_CHROMEBOOK_ADDED_NOTIFICATION_TITLE));
147 "chromebookAddedNotificationMessage",
148 l10n_util::GetStringFUTF16(
149 IDS_EASY_UNLOCK_CHROMEBOOK_ADDED_NOTIFICATION_MESSAGE,
152 // Setup dialog strings.
155 "setupIntroHeaderTitle",
156 l10n_util::GetStringFUTF16(
157 IDS_EASY_UNLOCK_SETUP_INTRO_HEADER_TITLE, device_type));
159 "setupIntroHeaderText",
160 l10n_util::GetStringFUTF16(IDS_EASY_UNLOCK_SETUP_INTRO_HEADER_TEXT,
164 "setupIntroFindPhoneButtonLabel",
165 l10n_util::GetStringUTF16(
166 IDS_EASY_UNLOCK_SETUP_INTRO_FIND_PHONE_BUTTON_LABEL));
168 "setupIntroFindingPhoneButtonLabel",
169 l10n_util::GetStringUTF16(
170 IDS_EASY_UNLOCK_SETUP_INTRO_FINDING_PHONE_BUTTON_LABEL));
172 "setupIntroRetryFindPhoneButtonLabel",
173 l10n_util::GetStringUTF16(
174 IDS_EASY_UNLOCK_SETUP_INTRO_RETRY_FIND_PHONE_BUTTON_LABEL));
176 "setupIntroHowIsThisSecureLinkText",
177 l10n_util::GetStringUTF16(
178 IDS_EASY_UNLOCK_SETUP_INTRO_HOW_IS_THIS_SECURE_LINK_TEXT));
179 // Step 2: Found a viable phone.
181 "setupFoundPhoneHeaderTitle",
182 l10n_util::GetStringFUTF16(
183 IDS_EASY_UNLOCK_SETUP_FOUND_PHONE_HEADER_TITLE, device_type));
185 "setupFoundPhoneHeaderText",
186 l10n_util::GetStringFUTF16(
187 IDS_EASY_UNLOCK_SETUP_FOUND_PHONE_HEADER_TEXT, device_type));
189 "setupFoundPhoneUseThisPhoneButtonLabel",
190 l10n_util::GetStringUTF16(
191 IDS_EASY_UNLOCK_SETUP_FOUND_PHONE_USE_THIS_PHONE_BUTTON_LABEL));
193 "setupPairingPhoneFailedButtonLabel",
194 l10n_util::GetStringUTF16(
195 IDS_EASY_UNLOCK_SETUP_PAIRING_PHONE_FAILED_BUTTON_LABEL));
196 // Step 3: Setup completed successfully.
198 "setupCompleteHeaderTitle",
199 l10n_util::GetStringUTF16(
200 IDS_EASY_UNLOCK_SETUP_COMPLETE_HEADER_TITLE));
202 "setupCompleteHeaderText",
203 l10n_util::GetStringUTF16(
204 IDS_EASY_UNLOCK_SETUP_COMPLETE_HEADER_TEXT));
206 "setupCompleteTryItOutButtonLabel",
207 l10n_util::GetStringUTF16(
208 IDS_EASY_UNLOCK_SETUP_COMPLETE_TRY_IT_OUT_BUTTON_LABEL));
210 "setupCompleteSettingsLinkText",
211 l10n_util::GetStringUTF16(
212 IDS_EASY_UNLOCK_SETUP_COMPLETE_SETTINGS_LINK_TEXT));
216 "setupErrorBluetoothUnavailable",
217 l10n_util::GetStringFUTF16(
218 IDS_EASY_UNLOCK_SETUP_ERROR_BLUETOOTH_UNAVAILBLE, device_type));
221 l10n_util::GetStringFUTF16(
222 IDS_EASY_UNLOCK_SETUP_ERROR_OFFLINE, device_type));
224 "setupErrorFindingPhone",
225 l10n_util::GetStringUTF16(IDS_EASY_UNLOCK_SETUP_ERROR_FINDING_PHONE));
227 "setupErrorBluetoothConnectionFailed",
228 l10n_util::GetStringFUTF16(
229 IDS_EASY_UNLOCK_SETUP_ERROR_BLUETOOTH_CONNECTION_FAILED,
232 "setupErrorConnectionToPhoneTimeout",
233 l10n_util::GetStringFUTF16(
234 IDS_EASY_UNLOCK_SETUP_ERROR_CONNECT_TO_PHONE_TIMEOUT,
237 "setupErrorSyncPhoneState",
238 l10n_util::GetStringUTF16(
239 IDS_EASY_UNLOCK_SETUP_ERROR_SYNC_PHONE_STATE_FAILED));
241 "setupErrorConnectingToPhone",
242 l10n_util::GetStringFUTF16(
243 IDS_EASY_UNLOCK_SETUP_ERROR_CONNECTING_TO_PHONE, device_type));
245 // TODO(isherman): Remove this string once the app has been updated.
246 strings->SetString("setupIntroHeaderFootnote", base::string16());
248 SetResult(strings.release());
252 EasyUnlockPrivatePerformECDHKeyAgreementFunction::
253 EasyUnlockPrivatePerformECDHKeyAgreementFunction() {}
255 EasyUnlockPrivatePerformECDHKeyAgreementFunction::
256 ~EasyUnlockPrivatePerformECDHKeyAgreementFunction() {}
258 bool EasyUnlockPrivatePerformECDHKeyAgreementFunction::RunAsync() {
259 scoped_ptr<easy_unlock_private::PerformECDHKeyAgreement::Params> params =
260 easy_unlock_private::PerformECDHKeyAgreement::Params::Create(*args_);
261 EXTENSION_FUNCTION_VALIDATE(params);
263 GetCryptoDelegate(browser_context())->PerformECDHKeyAgreement(
265 base::Bind(&EasyUnlockPrivatePerformECDHKeyAgreementFunction::OnData,
270 void EasyUnlockPrivatePerformECDHKeyAgreementFunction::OnData(
271 const std::string& secret_key) {
272 // TODO(tbarzic): Improve error handling.
273 if (!secret_key.empty()) {
274 results_ = easy_unlock_private::PerformECDHKeyAgreement::Results::Create(
280 EasyUnlockPrivateGenerateEcP256KeyPairFunction::
281 EasyUnlockPrivateGenerateEcP256KeyPairFunction() {}
283 EasyUnlockPrivateGenerateEcP256KeyPairFunction::
284 ~EasyUnlockPrivateGenerateEcP256KeyPairFunction() {}
286 bool EasyUnlockPrivateGenerateEcP256KeyPairFunction::RunAsync() {
287 GetCryptoDelegate(browser_context())->GenerateEcP256KeyPair(
288 base::Bind(&EasyUnlockPrivateGenerateEcP256KeyPairFunction::OnData,
293 void EasyUnlockPrivateGenerateEcP256KeyPairFunction::OnData(
294 const std::string& private_key,
295 const std::string& public_key) {
296 // TODO(tbarzic): Improve error handling.
297 if (!public_key.empty() && !private_key.empty()) {
298 results_ = easy_unlock_private::GenerateEcP256KeyPair::Results::Create(
299 public_key, private_key);
304 EasyUnlockPrivateCreateSecureMessageFunction::
305 EasyUnlockPrivateCreateSecureMessageFunction() {}
307 EasyUnlockPrivateCreateSecureMessageFunction::
308 ~EasyUnlockPrivateCreateSecureMessageFunction() {}
310 bool EasyUnlockPrivateCreateSecureMessageFunction::RunAsync() {
311 scoped_ptr<easy_unlock_private::CreateSecureMessage::Params> params =
312 easy_unlock_private::CreateSecureMessage::Params::Create(*args_);
313 EXTENSION_FUNCTION_VALIDATE(params);
315 GetCryptoDelegate(browser_context())->CreateSecureMessage(
317 base::Bind(&EasyUnlockPrivateCreateSecureMessageFunction::OnData,
322 void EasyUnlockPrivateCreateSecureMessageFunction::OnData(
323 const std::string& message) {
324 // TODO(tbarzic): Improve error handling.
325 if (!message.empty()) {
326 results_ = easy_unlock_private::CreateSecureMessage::Results::Create(
332 EasyUnlockPrivateUnwrapSecureMessageFunction::
333 EasyUnlockPrivateUnwrapSecureMessageFunction() {}
335 EasyUnlockPrivateUnwrapSecureMessageFunction::
336 ~EasyUnlockPrivateUnwrapSecureMessageFunction() {}
338 bool EasyUnlockPrivateUnwrapSecureMessageFunction::RunAsync() {
339 scoped_ptr<easy_unlock_private::UnwrapSecureMessage::Params> params =
340 easy_unlock_private::UnwrapSecureMessage::Params::Create(*args_);
341 EXTENSION_FUNCTION_VALIDATE(params);
343 GetCryptoDelegate(browser_context())->UnwrapSecureMessage(
345 base::Bind(&EasyUnlockPrivateUnwrapSecureMessageFunction::OnData,
350 void EasyUnlockPrivateUnwrapSecureMessageFunction::OnData(
351 const std::string& data) {
352 // TODO(tbarzic): Improve error handling.
354 results_ = easy_unlock_private::UnwrapSecureMessage::Results::Create(data);
358 EasyUnlockPrivateSeekBluetoothDeviceByAddressFunction::
359 EasyUnlockPrivateSeekBluetoothDeviceByAddressFunction() {}
361 EasyUnlockPrivateSeekBluetoothDeviceByAddressFunction::
362 ~EasyUnlockPrivateSeekBluetoothDeviceByAddressFunction() {}
364 bool EasyUnlockPrivateSeekBluetoothDeviceByAddressFunction::RunAsync() {
365 scoped_ptr<easy_unlock_private::SeekBluetoothDeviceByAddress::Params> params(
366 easy_unlock_private::SeekBluetoothDeviceByAddress::Params::Create(
368 EXTENSION_FUNCTION_VALIDATE(params.get());
370 proximity_auth::bluetooth_util::SeekDeviceByAddress(
371 params->device_address,
373 &EasyUnlockPrivateSeekBluetoothDeviceByAddressFunction::OnSeekSuccess,
376 &EasyUnlockPrivateSeekBluetoothDeviceByAddressFunction::OnSeekFailure,
378 content::BrowserThread::GetBlockingPool());
382 void EasyUnlockPrivateSeekBluetoothDeviceByAddressFunction::OnSeekSuccess() {
386 void EasyUnlockPrivateSeekBluetoothDeviceByAddressFunction::OnSeekFailure(
387 const std::string& error_message) {
388 SetError(error_message);
392 EasyUnlockPrivateConnectToBluetoothServiceInsecurelyFunction::
393 EasyUnlockPrivateConnectToBluetoothServiceInsecurelyFunction() {}
395 EasyUnlockPrivateConnectToBluetoothServiceInsecurelyFunction::
396 ~EasyUnlockPrivateConnectToBluetoothServiceInsecurelyFunction() {}
398 void EasyUnlockPrivateConnectToBluetoothServiceInsecurelyFunction::
399 ConnectToService(device::BluetoothDevice* device,
400 const device::BluetoothUUID& uuid) {
401 proximity_auth::bluetooth_util::ConnectToServiceInsecurely(
404 base::Bind(&EasyUnlockPrivateConnectToBluetoothServiceInsecurelyFunction::
407 base::Bind(&EasyUnlockPrivateConnectToBluetoothServiceInsecurelyFunction::
412 EasyUnlockPrivateUpdateScreenlockStateFunction::
413 EasyUnlockPrivateUpdateScreenlockStateFunction() {}
415 EasyUnlockPrivateUpdateScreenlockStateFunction::
416 ~EasyUnlockPrivateUpdateScreenlockStateFunction() {}
418 bool EasyUnlockPrivateUpdateScreenlockStateFunction::RunSync() {
419 scoped_ptr<easy_unlock_private::UpdateScreenlockState::Params> params(
420 easy_unlock_private::UpdateScreenlockState::Params::Create(*args_));
421 EXTENSION_FUNCTION_VALIDATE(params.get());
423 Profile* profile = Profile::FromBrowserContext(browser_context());
424 if (EasyUnlockService::Get(profile)->UpdateScreenlockState(
425 ToScreenlockStateHandlerState(params->state)))
428 SetError("Not allowed");
432 EasyUnlockPrivateSetPermitAccessFunction::
433 EasyUnlockPrivateSetPermitAccessFunction() {
436 EasyUnlockPrivateSetPermitAccessFunction::
437 ~EasyUnlockPrivateSetPermitAccessFunction() {
440 bool EasyUnlockPrivateSetPermitAccessFunction::RunSync() {
441 scoped_ptr<easy_unlock_private::SetPermitAccess::Params> params(
442 easy_unlock_private::SetPermitAccess::Params::Create(*args_));
443 EXTENSION_FUNCTION_VALIDATE(params.get());
445 Profile* profile = Profile::FromBrowserContext(browser_context());
446 EasyUnlockService::Get(profile)
447 ->SetPermitAccess(*params->permit_access.ToValue());
452 EasyUnlockPrivateGetPermitAccessFunction::
453 EasyUnlockPrivateGetPermitAccessFunction() {
456 EasyUnlockPrivateGetPermitAccessFunction::
457 ~EasyUnlockPrivateGetPermitAccessFunction() {
460 bool EasyUnlockPrivateGetPermitAccessFunction::RunSync() {
461 Profile* profile = Profile::FromBrowserContext(browser_context());
462 const base::DictionaryValue* permit_value =
463 EasyUnlockService::Get(profile)->GetPermitAccess();
465 scoped_ptr<easy_unlock_private::PermitRecord> permit =
466 easy_unlock_private::PermitRecord::FromValue(*permit_value);
467 results_ = easy_unlock_private::GetPermitAccess::Results::Create(*permit);
473 EasyUnlockPrivateClearPermitAccessFunction::
474 EasyUnlockPrivateClearPermitAccessFunction() {
477 EasyUnlockPrivateClearPermitAccessFunction::
478 ~EasyUnlockPrivateClearPermitAccessFunction() {
481 bool EasyUnlockPrivateClearPermitAccessFunction::RunSync() {
482 Profile* profile = Profile::FromBrowserContext(browser_context());
483 EasyUnlockService::Get(profile)->ClearPermitAccess();
487 EasyUnlockPrivateSetRemoteDevicesFunction::
488 EasyUnlockPrivateSetRemoteDevicesFunction() {
491 EasyUnlockPrivateSetRemoteDevicesFunction::
492 ~EasyUnlockPrivateSetRemoteDevicesFunction() {
495 bool EasyUnlockPrivateSetRemoteDevicesFunction::RunSync() {
496 scoped_ptr<easy_unlock_private::SetRemoteDevices::Params> params(
497 easy_unlock_private::SetRemoteDevices::Params::Create(*args_));
498 EXTENSION_FUNCTION_VALIDATE(params.get());
500 Profile* profile = Profile::FromBrowserContext(browser_context());
501 if (params->devices.empty()) {
502 EasyUnlockService::Get(profile)->ClearRemoteDevices();
504 base::ListValue devices;
505 for (size_t i = 0; i < params->devices.size(); ++i) {
506 devices.Append(params->devices[i]->ToValue().release());
508 EasyUnlockService::Get(profile)->SetRemoteDevices(devices);
514 EasyUnlockPrivateGetRemoteDevicesFunction::
515 EasyUnlockPrivateGetRemoteDevicesFunction() {
518 EasyUnlockPrivateGetRemoteDevicesFunction::
519 ~EasyUnlockPrivateGetRemoteDevicesFunction() {
522 bool EasyUnlockPrivateGetRemoteDevicesFunction::RunSync() {
523 Profile* profile = Profile::FromBrowserContext(browser_context());
524 const base::ListValue* devices =
525 EasyUnlockService::Get(profile)->GetRemoteDevices();
526 SetResult(devices ? devices->DeepCopy() : new base::ListValue());
530 EasyUnlockPrivateGetSignInChallengeFunction::
531 EasyUnlockPrivateGetSignInChallengeFunction() {
534 EasyUnlockPrivateGetSignInChallengeFunction::
535 ~EasyUnlockPrivateGetSignInChallengeFunction() {
538 bool EasyUnlockPrivateGetSignInChallengeFunction::RunSync() {
539 Profile* profile = Profile::FromBrowserContext(browser_context());
540 const std::string challenge =
541 EasyUnlockService::Get(profile)->GetChallenge();
542 if (!challenge.empty()) {
544 easy_unlock_private::GetSignInChallenge::Results::Create(challenge);
549 EasyUnlockPrivateTrySignInSecretFunction::
550 EasyUnlockPrivateTrySignInSecretFunction() {
553 EasyUnlockPrivateTrySignInSecretFunction::
554 ~EasyUnlockPrivateTrySignInSecretFunction() {
557 bool EasyUnlockPrivateTrySignInSecretFunction::RunSync() {
558 scoped_ptr<easy_unlock_private::TrySignInSecret::Params> params(
559 easy_unlock_private::TrySignInSecret::Params::Create(*args_));
560 EXTENSION_FUNCTION_VALIDATE(params.get());
562 Profile* profile = Profile::FromBrowserContext(browser_context());
563 EasyUnlockService::Get(profile)->FinalizeSignin(params->sign_in_secret);
567 EasyUnlockPrivateGetUserInfoFunction::EasyUnlockPrivateGetUserInfoFunction() {
570 EasyUnlockPrivateGetUserInfoFunction::~EasyUnlockPrivateGetUserInfoFunction() {
573 bool EasyUnlockPrivateGetUserInfoFunction::RunSync() {
574 EasyUnlockService* service =
575 EasyUnlockService::Get(Profile::FromBrowserContext(browser_context()));
576 std::vector<linked_ptr<easy_unlock_private::UserInfo> > users;
577 std::string user_id = service->GetUserEmail();
578 if (!user_id.empty()) {
580 linked_ptr<easy_unlock_private::UserInfo>(
581 new easy_unlock_private::UserInfo()));
582 users[0]->user_id = user_id;
583 users[0]->logged_in = service->GetType() == EasyUnlockService::TYPE_REGULAR;
584 users[0]->data_ready = users[0]->logged_in ||
585 service->GetRemoteDevices() != NULL;
587 results_ = easy_unlock_private::GetUserInfo::Results::Create(users);
592 } // namespace extensions