easy_unlock_private_api.cc revision 03b57e008b61dfcb1fbad3aea950ae0e001748b0
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. 4 5#include "chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.h" 6 7#include "base/bind.h" 8#include "base/lazy_instance.h" 9#include "base/strings/utf_string_conversions.h" 10#include "base/values.h" 11#include "chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_bluetooth_util.h" 12#include "chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_crypto_delegate.h" 13#include "chrome/browser/profiles/profile.h" 14#include "chrome/browser/signin/easy_unlock_screenlock_state_handler.h" 15#include "chrome/browser/signin/easy_unlock_service.h" 16#include "chrome/common/extensions/api/easy_unlock_private.h" 17#include "chrome/grit/generated_resources.h" 18#include "extensions/browser/browser_context_keyed_api_factory.h" 19#include "ui/base/l10n/l10n_util.h" 20 21#if defined(OS_CHROMEOS) 22#include "chrome/browser/chromeos/chromeos_utils.h" 23#endif 24 25namespace extensions { 26namespace api { 27 28namespace { 29 30static base::LazyInstance<BrowserContextKeyedAPIFactory<EasyUnlockPrivateAPI> > 31 g_factory = LAZY_INSTANCE_INITIALIZER; 32 33// Utility method for getting the API's crypto delegate. 34EasyUnlockPrivateCryptoDelegate* GetCryptoDelegate( 35 content::BrowserContext* context) { 36 return BrowserContextKeyedAPIFactory<EasyUnlockPrivateAPI>::Get(context) 37 ->crypto_delegate(); 38} 39 40EasyUnlockScreenlockStateHandler* GetScreenlockStateHandler( 41 content::BrowserContext* context) { 42 return EasyUnlockService::Get(Profile::FromBrowserContext(context)) 43 ->GetScreenlockStateHandler(); 44} 45 46EasyUnlockScreenlockStateHandler::State ToScreenlockStateHandlerState( 47 easy_unlock_private::State state) { 48 switch (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; 67 default: 68 return EasyUnlockScreenlockStateHandler::STATE_INACTIVE; 69 } 70} 71 72} // namespace 73 74// static 75BrowserContextKeyedAPIFactory<EasyUnlockPrivateAPI>* 76 EasyUnlockPrivateAPI::GetFactoryInstance() { 77 return g_factory.Pointer(); 78} 79 80EasyUnlockPrivateAPI::EasyUnlockPrivateAPI(content::BrowserContext* context) 81 : crypto_delegate_(EasyUnlockPrivateCryptoDelegate::Create()) { 82} 83 84EasyUnlockPrivateAPI::~EasyUnlockPrivateAPI() {} 85 86EasyUnlockPrivateGetStringsFunction::EasyUnlockPrivateGetStringsFunction() { 87} 88EasyUnlockPrivateGetStringsFunction::~EasyUnlockPrivateGetStringsFunction() { 89} 90 91bool EasyUnlockPrivateGetStringsFunction::RunSync() { 92 scoped_ptr<base::DictionaryValue> strings(new base::DictionaryValue); 93 94#if defined(OS_CHROMEOS) 95 const base::string16 device_type = chromeos::GetChromeDeviceType(); 96#else 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) 100 101 // Common strings. 102 strings->SetString( 103 "learnMoreLinkTitle", 104 l10n_util::GetStringUTF16(IDS_EASY_UNLOCK_LEARN_MORE_LINK_TITLE)); 105 106 // Setup notification strings. 107 strings->SetString( 108 "setupNotificationTitle", 109 l10n_util::GetStringFUTF16(IDS_EASY_UNLOCK_SETUP_NOTIFICATION_TITLE, 110 device_type)); 111 strings->SetString( 112 "setupNotificationMessage", 113 l10n_util::GetStringFUTF16(IDS_EASY_UNLOCK_SETUP_NOTIFICATION_MESSAGE, 114 device_type)); 115 strings->SetString( 116 "setupNotificationButtonTitle", 117 l10n_util::GetStringUTF16( 118 IDS_EASY_UNLOCK_SETUP_NOTIFICATION_BUTTON_TITLE)); 119 120 // Success notification strings. 121 strings->SetString( 122 "successNotificationTitle", 123 l10n_util::GetStringUTF16(IDS_EASY_UNLOCK_SUCCESS_NOTIFICATION_TITLE)); 124 strings->SetString( 125 "successNotificationMessage", 126 l10n_util::GetStringFUTF16(IDS_EASY_UNLOCK_SUCCESS_NOTIFICATION_MESSAGE, 127 device_type)); 128 129 // Chromebook added to Easy Unlock notification strings. 130 strings->SetString( 131 "chromebookAddedNotificationTitle", 132 l10n_util::GetStringUTF16( 133 IDS_EASY_UNLOCK_CHROMEBOOK_ADDED_NOTIFICATION_TITLE)); 134 strings->SetString( 135 "chromebookAddedNotificationMessage", 136 l10n_util::GetStringFUTF16( 137 IDS_EASY_UNLOCK_CHROMEBOOK_ADDED_NOTIFICATION_MESSAGE, 138 device_type)); 139 140 // Setup dialog strings. 141 // Step 1: Intro. 142 strings->SetString( 143 "setupIntroHeaderTitle", 144 l10n_util::GetStringFUTF16( 145 IDS_EASY_UNLOCK_SETUP_INTRO_HEADER_TITLE, device_type)); 146 strings->SetString( 147 "setupIntroHeaderText", 148 l10n_util::GetStringFUTF16( 149 IDS_EASY_UNLOCK_SETUP_INTRO_HEADER_TEXT, device_type)); 150 strings->SetString( 151 "setupIntroHeaderFootnote", 152 l10n_util::GetStringUTF16( 153 IDS_EASY_UNLOCK_SETUP_INTRO_HEADER_FOOTNOTE)); 154 strings->SetString( 155 "setupIntroFindPhoneButtonLabel", 156 l10n_util::GetStringUTF16( 157 IDS_EASY_UNLOCK_SETUP_INTRO_FIND_PHONE_BUTTON_LABEL)); 158 strings->SetString( 159 "setupIntroFindingPhoneButtonLabel", 160 l10n_util::GetStringUTF16( 161 IDS_EASY_UNLOCK_SETUP_INTRO_FINDING_PHONE_BUTTON_LABEL)); 162 strings->SetString( 163 "setupIntroRetryFindPhoneButtonLabel", 164 l10n_util::GetStringUTF16( 165 IDS_EASY_UNLOCK_SETUP_INTRO_RETRY_FIND_PHONE_BUTTON_LABEL)); 166 strings->SetString( 167 "setupIntroHowIsThisSecureLinkText", 168 l10n_util::GetStringUTF16( 169 IDS_EASY_UNLOCK_SETUP_INTRO_HOW_IS_THIS_SECURE_LINK_TEXT)); 170 // Step 2: Found a viable phone. 171 strings->SetString( 172 "setupFoundPhoneHeaderTitle", 173 l10n_util::GetStringFUTF16( 174 IDS_EASY_UNLOCK_SETUP_FOUND_PHONE_HEADER_TITLE, device_type)); 175 strings->SetString( 176 "setupFoundPhoneHeaderText", 177 l10n_util::GetStringFUTF16( 178 IDS_EASY_UNLOCK_SETUP_FOUND_PHONE_HEADER_TEXT, device_type)); 179 strings->SetString( 180 "setupFoundPhoneUseThisPhoneButtonLabel", 181 l10n_util::GetStringUTF16( 182 IDS_EASY_UNLOCK_SETUP_FOUND_PHONE_USE_THIS_PHONE_BUTTON_LABEL)); 183 strings->SetString( 184 "setupPairingPhoneFailedButtonLabel", 185 l10n_util::GetStringUTF16( 186 IDS_EASY_UNLOCK_SETUP_PAIRING_PHONE_FAILED_BUTTON_LABEL)); 187 // Step 3: Setup completed successfully. 188 strings->SetString( 189 "setupCompleteHeaderTitle", 190 l10n_util::GetStringUTF16( 191 IDS_EASY_UNLOCK_SETUP_COMPLETE_HEADER_TITLE)); 192 strings->SetString( 193 "setupCompleteHeaderText", 194 l10n_util::GetStringUTF16( 195 IDS_EASY_UNLOCK_SETUP_COMPLETE_HEADER_TEXT)); 196 strings->SetString( 197 "setupCompleteTryItOutButtonLabel", 198 l10n_util::GetStringUTF16( 199 IDS_EASY_UNLOCK_SETUP_COMPLETE_TRY_IT_OUT_BUTTON_LABEL)); 200 strings->SetString( 201 "setupCompleteSettingsLinkText", 202 l10n_util::GetStringUTF16( 203 IDS_EASY_UNLOCK_SETUP_COMPLETE_SETTINGS_LINK_TEXT)); 204 205 // Error strings. 206 strings->SetString( 207 "setupErrorBluetoothUnavailable", 208 l10n_util::GetStringFUTF16( 209 IDS_EASY_UNLOCK_SETUP_ERROR_BLUETOOTH_UNAVAILBLE, device_type)); 210 strings->SetString( 211 "setupErrorOffline", 212 l10n_util::GetStringFUTF16( 213 IDS_EASY_UNLOCK_SETUP_ERROR_OFFLINE, device_type)); 214 strings->SetString( 215 "setupErrorFindingPhone", 216 l10n_util::GetStringUTF16(IDS_EASY_UNLOCK_SETUP_ERROR_FINDING_PHONE)); 217 strings->SetString( 218 "setupErrorBluetoothConnectionFailed", 219 l10n_util::GetStringFUTF16( 220 IDS_EASY_UNLOCK_SETUP_ERROR_BLUETOOTH_CONNECTION_FAILED, 221 device_type)); 222 strings->SetString( 223 "setupErrorConnectionToPhoneTimeout", 224 l10n_util::GetStringFUTF16( 225 IDS_EASY_UNLOCK_SETUP_ERROR_CONNECT_TO_PHONE_TIMEOUT, 226 device_type)); 227 strings->SetString( 228 "setupErrorSyncPhoneState", 229 l10n_util::GetStringUTF16( 230 IDS_EASY_UNLOCK_SETUP_ERROR_SYNC_PHONE_STATE_FAILED)); 231 strings->SetString( 232 "setupErrorConnectingToPhone", 233 l10n_util::GetStringFUTF16( 234 IDS_EASY_UNLOCK_SETUP_ERROR_CONNECTING_TO_PHONE, device_type)); 235 236 // TODO(isherman): Remove these strings once the app has been updated. 237 strings->SetString( 238 "notificationTitle", 239 l10n_util::GetStringFUTF16(IDS_EASY_UNLOCK_SETUP_NOTIFICATION_TITLE, 240 device_type)); 241 strings->SetString( 242 "notificationMessage", 243 l10n_util::GetStringFUTF16(IDS_EASY_UNLOCK_SETUP_NOTIFICATION_MESSAGE, 244 device_type)); 245 strings->SetString( 246 "notificationButtonTitle", 247 l10n_util::GetStringUTF16( 248 IDS_EASY_UNLOCK_SETUP_NOTIFICATION_BUTTON_TITLE)); 249 250 SetResult(strings.release()); 251 return true; 252} 253 254EasyUnlockPrivatePerformECDHKeyAgreementFunction:: 255EasyUnlockPrivatePerformECDHKeyAgreementFunction() {} 256 257EasyUnlockPrivatePerformECDHKeyAgreementFunction:: 258~EasyUnlockPrivatePerformECDHKeyAgreementFunction() {} 259 260bool EasyUnlockPrivatePerformECDHKeyAgreementFunction::RunAsync() { 261 scoped_ptr<easy_unlock_private::PerformECDHKeyAgreement::Params> params = 262 easy_unlock_private::PerformECDHKeyAgreement::Params::Create(*args_); 263 EXTENSION_FUNCTION_VALIDATE(params); 264 265 GetCryptoDelegate(browser_context())->PerformECDHKeyAgreement( 266 params->private_key, 267 params->public_key, 268 base::Bind(&EasyUnlockPrivatePerformECDHKeyAgreementFunction::OnData, 269 this)); 270 return true; 271} 272 273void EasyUnlockPrivatePerformECDHKeyAgreementFunction::OnData( 274 const std::string& secret_key) { 275 // TODO(tbarzic): Improve error handling. 276 if (!secret_key.empty()) { 277 results_ = easy_unlock_private::PerformECDHKeyAgreement::Results::Create( 278 secret_key); 279 } 280 SendResponse(true); 281} 282 283EasyUnlockPrivateGenerateEcP256KeyPairFunction:: 284EasyUnlockPrivateGenerateEcP256KeyPairFunction() {} 285 286EasyUnlockPrivateGenerateEcP256KeyPairFunction:: 287~EasyUnlockPrivateGenerateEcP256KeyPairFunction() {} 288 289bool EasyUnlockPrivateGenerateEcP256KeyPairFunction::RunAsync() { 290 GetCryptoDelegate(browser_context())->GenerateEcP256KeyPair( 291 base::Bind(&EasyUnlockPrivateGenerateEcP256KeyPairFunction::OnData, 292 this)); 293 return true; 294} 295 296void EasyUnlockPrivateGenerateEcP256KeyPairFunction::OnData( 297 const std::string& private_key, 298 const std::string& public_key) { 299 // TODO(tbarzic): Improve error handling. 300 if (!public_key.empty() && !private_key.empty()) { 301 results_ = easy_unlock_private::GenerateEcP256KeyPair::Results::Create( 302 public_key, private_key); 303 } 304 SendResponse(true); 305} 306 307EasyUnlockPrivateCreateSecureMessageFunction:: 308EasyUnlockPrivateCreateSecureMessageFunction() {} 309 310EasyUnlockPrivateCreateSecureMessageFunction:: 311~EasyUnlockPrivateCreateSecureMessageFunction() {} 312 313bool EasyUnlockPrivateCreateSecureMessageFunction::RunAsync() { 314 scoped_ptr<easy_unlock_private::CreateSecureMessage::Params> params = 315 easy_unlock_private::CreateSecureMessage::Params::Create(*args_); 316 EXTENSION_FUNCTION_VALIDATE(params); 317 318 GetCryptoDelegate(browser_context())->CreateSecureMessage( 319 params->payload, 320 params->key, 321 params->options.associated_data ? 322 *params->options.associated_data : std::string(), 323 params->options.public_metadata ? 324 *params->options.public_metadata : std::string(), 325 params->options.verification_key_id ? 326 *params->options.verification_key_id : std::string(), 327 params->options.encrypt_type, 328 params->options.sign_type, 329 base::Bind(&EasyUnlockPrivateCreateSecureMessageFunction::OnData, 330 this)); 331 return true; 332} 333 334void EasyUnlockPrivateCreateSecureMessageFunction::OnData( 335 const std::string& message) { 336 // TODO(tbarzic): Improve error handling. 337 if (!message.empty()) { 338 results_ = easy_unlock_private::CreateSecureMessage::Results::Create( 339 message); 340 } 341 SendResponse(true); 342} 343 344EasyUnlockPrivateUnwrapSecureMessageFunction:: 345EasyUnlockPrivateUnwrapSecureMessageFunction() {} 346 347EasyUnlockPrivateUnwrapSecureMessageFunction:: 348~EasyUnlockPrivateUnwrapSecureMessageFunction() {} 349 350bool EasyUnlockPrivateUnwrapSecureMessageFunction::RunAsync() { 351 scoped_ptr<easy_unlock_private::UnwrapSecureMessage::Params> params = 352 easy_unlock_private::UnwrapSecureMessage::Params::Create(*args_); 353 EXTENSION_FUNCTION_VALIDATE(params); 354 355 GetCryptoDelegate(browser_context())->UnwrapSecureMessage( 356 params->secure_message, 357 params->key, 358 params->options.associated_data ? 359 *params->options.associated_data : std::string(), 360 params->options.encrypt_type, 361 params->options.sign_type, 362 base::Bind(&EasyUnlockPrivateUnwrapSecureMessageFunction::OnData, 363 this)); 364 return true; 365} 366 367void EasyUnlockPrivateUnwrapSecureMessageFunction::OnData( 368 const std::string& data) { 369 // TODO(tbarzic): Improve error handling. 370 if (!data.empty()) 371 results_ = easy_unlock_private::UnwrapSecureMessage::Results::Create(data); 372 SendResponse(true); 373} 374 375EasyUnlockPrivateSeekBluetoothDeviceByAddressFunction:: 376 EasyUnlockPrivateSeekBluetoothDeviceByAddressFunction() {} 377 378EasyUnlockPrivateSeekBluetoothDeviceByAddressFunction:: 379 ~EasyUnlockPrivateSeekBluetoothDeviceByAddressFunction() {} 380 381bool EasyUnlockPrivateSeekBluetoothDeviceByAddressFunction::RunAsync() { 382 scoped_ptr<easy_unlock_private::SeekBluetoothDeviceByAddress::Params> params( 383 easy_unlock_private::SeekBluetoothDeviceByAddress::Params::Create( 384 *args_)); 385 EXTENSION_FUNCTION_VALIDATE(params.get()); 386 387 easy_unlock::SeekBluetoothDeviceByAddress( 388 params->device_address, 389 base::Bind( 390 &EasyUnlockPrivateSeekBluetoothDeviceByAddressFunction:: 391 OnSeekCompleted, 392 this)); 393 return true; 394} 395 396void EasyUnlockPrivateSeekBluetoothDeviceByAddressFunction::OnSeekCompleted( 397 const easy_unlock::SeekDeviceResult& seek_result) { 398 if (seek_result.success) { 399 SendResponse(true); 400 } else { 401 SetError(seek_result.error_message); 402 SendResponse(false); 403 } 404} 405 406EasyUnlockPrivateConnectToBluetoothServiceInsecurelyFunction:: 407 EasyUnlockPrivateConnectToBluetoothServiceInsecurelyFunction() {} 408 409EasyUnlockPrivateConnectToBluetoothServiceInsecurelyFunction:: 410 ~EasyUnlockPrivateConnectToBluetoothServiceInsecurelyFunction() {} 411 412void EasyUnlockPrivateConnectToBluetoothServiceInsecurelyFunction:: 413 ConnectToService(device::BluetoothDevice* device, 414 const device::BluetoothUUID& uuid) { 415 easy_unlock::ConnectToBluetoothServiceInsecurely( 416 device, 417 uuid, 418 base::Bind(&EasyUnlockPrivateConnectToBluetoothServiceInsecurelyFunction:: 419 OnConnect, 420 this), 421 base::Bind(&EasyUnlockPrivateConnectToBluetoothServiceInsecurelyFunction:: 422 OnConnectError, 423 this)); 424} 425 426EasyUnlockPrivateUpdateScreenlockStateFunction:: 427 EasyUnlockPrivateUpdateScreenlockStateFunction() {} 428 429EasyUnlockPrivateUpdateScreenlockStateFunction:: 430 ~EasyUnlockPrivateUpdateScreenlockStateFunction() {} 431 432bool EasyUnlockPrivateUpdateScreenlockStateFunction::RunSync() { 433 scoped_ptr<easy_unlock_private::UpdateScreenlockState::Params> params( 434 easy_unlock_private::UpdateScreenlockState::Params::Create(*args_)); 435 EXTENSION_FUNCTION_VALIDATE(params.get()); 436 437 EasyUnlockScreenlockStateHandler* screenlock_state_handler = 438 GetScreenlockStateHandler(browser_context()); 439 if (screenlock_state_handler) { 440 screenlock_state_handler->ChangeState( 441 ToScreenlockStateHandlerState(params->state)); 442 return true; 443 } 444 445 SetError("Not allowed"); 446 return false; 447} 448 449EasyUnlockPrivateSetPermitAccessFunction:: 450 EasyUnlockPrivateSetPermitAccessFunction() { 451} 452 453EasyUnlockPrivateSetPermitAccessFunction:: 454 ~EasyUnlockPrivateSetPermitAccessFunction() { 455} 456 457bool EasyUnlockPrivateSetPermitAccessFunction::RunSync() { 458 scoped_ptr<easy_unlock_private::SetPermitAccess::Params> params( 459 easy_unlock_private::SetPermitAccess::Params::Create(*args_)); 460 EXTENSION_FUNCTION_VALIDATE(params.get()); 461 462 Profile* profile = Profile::FromBrowserContext(browser_context()); 463 EasyUnlockService::Get(profile) 464 ->SetPermitAccess(*params->permit_access.ToValue()); 465 466 return true; 467} 468 469EasyUnlockPrivateGetPermitAccessFunction:: 470 EasyUnlockPrivateGetPermitAccessFunction() { 471} 472 473EasyUnlockPrivateGetPermitAccessFunction:: 474 ~EasyUnlockPrivateGetPermitAccessFunction() { 475} 476 477bool EasyUnlockPrivateGetPermitAccessFunction::RunSync() { 478 Profile* profile = Profile::FromBrowserContext(browser_context()); 479 const base::DictionaryValue* permit_value = 480 EasyUnlockService::Get(profile)->GetPermitAccess(); 481 if (permit_value) { 482 scoped_ptr<easy_unlock_private::PermitRecord> permit = 483 easy_unlock_private::PermitRecord::FromValue(*permit_value); 484 results_ = easy_unlock_private::GetPermitAccess::Results::Create(*permit); 485 } 486 487 return true; 488} 489 490EasyUnlockPrivateClearPermitAccessFunction:: 491 EasyUnlockPrivateClearPermitAccessFunction() { 492} 493 494EasyUnlockPrivateClearPermitAccessFunction:: 495 ~EasyUnlockPrivateClearPermitAccessFunction() { 496} 497 498bool EasyUnlockPrivateClearPermitAccessFunction::RunSync() { 499 Profile* profile = Profile::FromBrowserContext(browser_context()); 500 EasyUnlockService::Get(profile)->ClearPermitAccess(); 501 return true; 502} 503 504EasyUnlockPrivateSetRemoteDevicesFunction:: 505 EasyUnlockPrivateSetRemoteDevicesFunction() { 506} 507 508EasyUnlockPrivateSetRemoteDevicesFunction:: 509 ~EasyUnlockPrivateSetRemoteDevicesFunction() { 510} 511 512bool EasyUnlockPrivateSetRemoteDevicesFunction::RunSync() { 513 scoped_ptr<easy_unlock_private::SetRemoteDevices::Params> params( 514 easy_unlock_private::SetRemoteDevices::Params::Create(*args_)); 515 EXTENSION_FUNCTION_VALIDATE(params.get()); 516 517 Profile* profile = Profile::FromBrowserContext(browser_context()); 518 if (params->devices.empty()) { 519 EasyUnlockService::Get(profile)->ClearRemoteDevices(); 520 } else { 521 base::ListValue devices; 522 for (size_t i = 0; i < params->devices.size(); ++i) { 523 devices.Append(params->devices[i]->ToValue().release()); 524 } 525 EasyUnlockService::Get(profile)->SetRemoteDevices(devices); 526 } 527 528 return true; 529} 530 531EasyUnlockPrivateGetRemoteDevicesFunction:: 532 EasyUnlockPrivateGetRemoteDevicesFunction() { 533} 534 535EasyUnlockPrivateGetRemoteDevicesFunction:: 536 ~EasyUnlockPrivateGetRemoteDevicesFunction() { 537} 538 539bool EasyUnlockPrivateGetRemoteDevicesFunction::RunSync() { 540 Profile* profile = Profile::FromBrowserContext(browser_context()); 541 const base::ListValue* devices = 542 EasyUnlockService::Get(profile)->GetRemoteDevices(); 543 SetResult(devices ? devices->DeepCopy() : new base::ListValue()); 544 return true; 545} 546 547} // namespace api 548} // namespace extensions 549