| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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 "components/proximity_auth/webui/proximity_auth_webui_handler.h" | 5 #include "components/proximity_auth/webui/proximity_auth_webui_handler.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/i18n/time_formatting.h" | 10 #include "base/i18n/time_formatting.h" |
| 11 #include "base/prefs/pref_service.h" | 11 #include "base/prefs/pref_service.h" |
| 12 #include "base/thread_task_runner_handle.h" | 12 #include "base/thread_task_runner_handle.h" |
| 13 #include "base/time/default_clock.h" | 13 #include "base/time/default_clock.h" |
| 14 #include "base/time/default_tick_clock.h" | 14 #include "base/time/default_tick_clock.h" |
| 15 #include "base/values.h" | 15 #include "base/values.h" |
| 16 #include "components/proximity_auth/ble/bluetooth_low_energy_connection_finder.h
" | |
| 17 #include "components/proximity_auth/ble/bluetooth_low_energy_device_whitelist.h" | |
| 18 #include "components/proximity_auth/ble/pref_names.h" | 16 #include "components/proximity_auth/ble/pref_names.h" |
| 19 #include "components/proximity_auth/bluetooth_connection_finder.h" | 17 #include "components/proximity_auth/bluetooth_connection_finder.h" |
| 20 #include "components/proximity_auth/bluetooth_throttler_impl.h" | |
| 21 #include "components/proximity_auth/cryptauth/base64url.h" | 18 #include "components/proximity_auth/cryptauth/base64url.h" |
| 22 #include "components/proximity_auth/cryptauth/cryptauth_enrollment_manager.h" | 19 #include "components/proximity_auth/cryptauth/cryptauth_enrollment_manager.h" |
| 23 #include "components/proximity_auth/cryptauth/proto/cryptauth_api.pb.h" | 20 #include "components/proximity_auth/cryptauth/proto/cryptauth_api.pb.h" |
| 24 #include "components/proximity_auth/cryptauth/secure_message_delegate.h" | 21 #include "components/proximity_auth/cryptauth/secure_message_delegate.h" |
| 25 #include "components/proximity_auth/device_to_device_authenticator.h" | |
| 26 #include "components/proximity_auth/logging/logging.h" | 22 #include "components/proximity_auth/logging/logging.h" |
| 27 #include "components/proximity_auth/messenger_impl.h" | 23 #include "components/proximity_auth/messenger.h" |
| 24 #include "components/proximity_auth/remote_device_life_cycle_impl.h" |
| 28 #include "components/proximity_auth/remote_status_update.h" | 25 #include "components/proximity_auth/remote_status_update.h" |
| 29 #include "components/proximity_auth/secure_context.h" | 26 #include "components/proximity_auth/secure_context.h" |
| 30 #include "components/proximity_auth/webui/reachable_phone_flow.h" | 27 #include "components/proximity_auth/webui/reachable_phone_flow.h" |
| 31 #include "content/public/browser/browser_thread.h" | 28 #include "content/public/browser/browser_thread.h" |
| 32 #include "content/public/browser/web_ui.h" | 29 #include "content/public/browser/web_ui.h" |
| 33 #include "device/bluetooth/bluetooth_uuid.h" | 30 #include "device/bluetooth/bluetooth_uuid.h" |
| 34 | 31 |
| 35 namespace proximity_auth { | 32 namespace proximity_auth { |
| 36 | 33 |
| 37 namespace { | 34 namespace { |
| 38 | 35 |
| 39 // The UUID of the Smart Lock classic Bluetooth service. | |
| 40 const char kClassicBluetoothServiceUUID[] = | |
| 41 "704EE561-3782-405A-A14B-2D47A2DDCDDF"; | |
| 42 | |
| 43 // The UUID of the Bluetooth Low Energy service. | |
| 44 const char kBLESmartLockServiceUUID[] = "b3b7e28e-a000-3e17-bd86-6e97b9e28c11"; | |
| 45 | |
| 46 // Keys in the JSON representation of a log message. | 36 // Keys in the JSON representation of a log message. |
| 47 const char kLogMessageTextKey[] = "text"; | 37 const char kLogMessageTextKey[] = "text"; |
| 48 const char kLogMessageTimeKey[] = "time"; | 38 const char kLogMessageTimeKey[] = "time"; |
| 49 const char kLogMessageFileKey[] = "file"; | 39 const char kLogMessageFileKey[] = "file"; |
| 50 const char kLogMessageLineKey[] = "line"; | 40 const char kLogMessageLineKey[] = "line"; |
| 51 const char kLogMessageSeverityKey[] = "severity"; | 41 const char kLogMessageSeverityKey[] = "severity"; |
| 52 | 42 |
| 53 // Keys in the JSON representation of a SyncState object for enrollment or | 43 // Keys in the JSON representation of a SyncState object for enrollment or |
| 54 // device sync. | 44 // device sync. |
| 55 const char kSyncStateLastSuccessTime[] = "lastSuccessTime"; | 45 const char kSyncStateLastSuccessTime[] = "lastSuccessTime"; |
| (...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 333 return; | 323 return; |
| 334 | 324 |
| 335 std::string b64_public_key; | 325 std::string b64_public_key; |
| 336 std::string public_key; | 326 std::string public_key; |
| 337 if (!enrollment_manager || !device_manager || !args->GetSize() || | 327 if (!enrollment_manager || !device_manager || !args->GetSize() || |
| 338 !args->GetString(0, &b64_public_key) || | 328 !args->GetString(0, &b64_public_key) || |
| 339 !Base64UrlDecode(b64_public_key, &public_key)) { | 329 !Base64UrlDecode(b64_public_key, &public_key)) { |
| 340 return; | 330 return; |
| 341 } | 331 } |
| 342 | 332 |
| 343 Connection* connection = GetConnection(); | |
| 344 for (const auto& unlock_key : device_manager->unlock_keys()) { | 333 for (const auto& unlock_key : device_manager->unlock_keys()) { |
| 345 if (unlock_key.public_key() == public_key) { | 334 if (unlock_key.public_key() == public_key) { |
| 346 // Check if there is an existing connection to disconnect from first. | 335 if (life_cycle_ && selected_remote_device_.public_key == public_key) { |
| 347 if (connection && connection->IsConnected() && | 336 CleanUpRemoteDeviceLifeCycle(); |
| 348 selected_remote_device_.public_key == public_key) { | |
| 349 PA_LOG(INFO) << "Disconnecting from " | |
| 350 << unlock_key.friendly_device_name() << "[" | |
| 351 << unlock_key.bluetooth_address() << "]"; | |
| 352 connection->Disconnect(); | |
| 353 return; | 337 return; |
| 354 } | 338 } |
| 355 | 339 |
| 356 // Derive the PSK before connecting to the device. | 340 // Derive the PSK before connecting to the device. |
| 357 PA_LOG(INFO) << "Deriving PSK before connecting to " | 341 PA_LOG(INFO) << "Deriving PSK before connecting to " |
| 358 << unlock_key.friendly_device_name(); | 342 << unlock_key.friendly_device_name(); |
| 359 secure_message_delegate_ = | 343 secure_message_delegate_ = |
| 360 proximity_auth_client_->CreateSecureMessageDelegate(); | 344 proximity_auth_client_->CreateSecureMessageDelegate(); |
| 361 secure_message_delegate_->DeriveKey( | 345 secure_message_delegate_->DeriveKey( |
| 362 enrollment_manager->GetUserPrivateKey(), unlock_key.public_key(), | 346 enrollment_manager->GetUserPrivateKey(), unlock_key.public_key(), |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 464 if (!device_manager) | 448 if (!device_manager) |
| 465 return unlock_keys; | 449 return unlock_keys; |
| 466 | 450 |
| 467 for (const auto& unlock_key : device_manager->unlock_keys()) { | 451 for (const auto& unlock_key : device_manager->unlock_keys()) { |
| 468 unlock_keys->Append(ExternalDeviceInfoToDictionary(unlock_key)); | 452 unlock_keys->Append(ExternalDeviceInfoToDictionary(unlock_key)); |
| 469 } | 453 } |
| 470 | 454 |
| 471 return unlock_keys; | 455 return unlock_keys; |
| 472 } | 456 } |
| 473 | 457 |
| 474 Connection* ProximityAuthWebUIHandler::GetConnection() { | |
| 475 Connection* connection = connection_.get(); | |
| 476 if (messenger_) { | |
| 477 DCHECK(!connection); | |
| 478 connection = messenger_->connection(); | |
| 479 } | |
| 480 return connection; | |
| 481 } | |
| 482 | |
| 483 void ProximityAuthWebUIHandler::OnPSKDerived( | 458 void ProximityAuthWebUIHandler::OnPSKDerived( |
| 484 const cryptauth::ExternalDeviceInfo& unlock_key, | 459 const cryptauth::ExternalDeviceInfo& unlock_key, |
| 485 const std::string& persistent_symmetric_key) { | 460 const std::string& persistent_symmetric_key) { |
| 486 if (persistent_symmetric_key.empty()) { | 461 if (persistent_symmetric_key.empty()) { |
| 487 PA_LOG(ERROR) << "Failed to derive PSK."; | 462 PA_LOG(ERROR) << "Failed to derive PSK."; |
| 488 return; | 463 return; |
| 489 } | 464 } |
| 490 | 465 |
| 491 selected_remote_device_ = | 466 selected_remote_device_ = |
| 492 RemoteDevice(unlock_key.friendly_device_name(), unlock_key.public_key(), | 467 RemoteDevice(unlock_key.friendly_device_name(), unlock_key.public_key(), |
| 493 unlock_key.bluetooth_address(), persistent_symmetric_key); | 468 unlock_key.bluetooth_address(), persistent_symmetric_key); |
| 494 | 469 |
| 495 // TODO(tengs): We distinguish whether the unlock key uses classic Bluetooth | 470 life_cycle_.reset(new RemoteDeviceLifeCycleImpl(selected_remote_device_, |
| 496 // or BLE based on the presence of the |bluetooth_address| field. However, we | 471 proximity_auth_client_)); |
| 497 // should ideally have a separate field specifying the protocol. | 472 life_cycle_->AddObserver(this); |
| 498 if (selected_remote_device_.bluetooth_address.empty()) | 473 life_cycle_->Start(); |
| 499 FindBluetoothLowEnergyConnection(selected_remote_device_); | |
| 500 else | |
| 501 FindBluetoothClassicConnection(selected_remote_device_); | |
| 502 } | |
| 503 | |
| 504 void ProximityAuthWebUIHandler::FindBluetoothClassicConnection( | |
| 505 const RemoteDevice& remote_device) { | |
| 506 PA_LOG(INFO) << "Finding classic Bluetooth device " << remote_device.name | |
| 507 << " [" << remote_device.bluetooth_address << "]."; | |
| 508 | |
| 509 // TODO(tengs): Set a timeout to stop the connection finder eventually. | |
| 510 connection_finder_.reset(new BluetoothConnectionFinder( | |
| 511 remote_device, device::BluetoothUUID(kClassicBluetoothServiceUUID), | |
| 512 base::TimeDelta::FromSeconds(3))); | |
| 513 connection_finder_->Find( | |
| 514 base::Bind(&ProximityAuthWebUIHandler::OnConnectionFound, | |
| 515 weak_ptr_factory_.GetWeakPtr())); | |
| 516 | |
| 517 web_ui()->CallJavascriptFunction("LocalStateInterface.onUnlockKeysChanged", | |
| 518 *GetUnlockKeysList()); | |
| 519 } | |
| 520 | |
| 521 void ProximityAuthWebUIHandler::FindBluetoothLowEnergyConnection( | |
| 522 const RemoteDevice& remote_device) { | |
| 523 PrefService* pref_service = proximity_auth_client_->GetPrefService(); | |
| 524 if (!pref_service->FindPreference( | |
| 525 prefs::kBluetoothLowEnergyDeviceWhitelist)) { | |
| 526 PA_LOG(ERROR) << "Please enable the BLE experiment in chrome://flags."; | |
| 527 return; | |
| 528 } | |
| 529 | |
| 530 PA_LOG(INFO) << "Finding Bluetooth Low Energy device " << remote_device.name; | |
| 531 if (!bluetooth_throttler_) { | |
| 532 bluetooth_throttler_.reset(new BluetoothThrottlerImpl( | |
| 533 make_scoped_ptr(new base::DefaultTickClock()))); | |
| 534 } | |
| 535 | |
| 536 ble_device_whitelist_.reset(new BluetoothLowEnergyDeviceWhitelist( | |
| 537 proximity_auth_client_->GetPrefService())); | |
| 538 | |
| 539 // TODO(tengs): Set a timeout to stop the connection finder eventually. | |
| 540 connection_finder_.reset(new BluetoothLowEnergyConnectionFinder( | |
| 541 remote_device, kBLESmartLockServiceUUID, | |
| 542 BluetoothLowEnergyConnectionFinder::FIND_ANY_DEVICE, | |
| 543 ble_device_whitelist_.get(), bluetooth_throttler_.get(), 3)); | |
| 544 connection_finder_->Find( | |
| 545 base::Bind(&ProximityAuthWebUIHandler::OnConnectionFound, | |
| 546 weak_ptr_factory_.GetWeakPtr())); | |
| 547 | |
| 548 web_ui()->CallJavascriptFunction("LocalStateInterface.onUnlockKeysChanged", | |
| 549 *GetUnlockKeysList()); | |
| 550 } | |
| 551 | |
| 552 void ProximityAuthWebUIHandler::OnAuthenticationResult( | |
| 553 Authenticator::Result result, | |
| 554 scoped_ptr<SecureContext> secure_context) { | |
| 555 secure_context_ = secure_context.Pass(); | |
| 556 | |
| 557 // Create the MessengerImpl asynchronously. |messenger_| registers itself as | |
| 558 // an observer of |connection_|, so creating it synchronously would trigger | |
| 559 // |OnSendComplete()| as an observer call for |messenger_|. | |
| 560 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
| 561 FROM_HERE, | |
| 562 base::Bind(&ProximityAuthWebUIHandler::CreateStatusUpdateMessenger, | |
| 563 weak_ptr_factory_.GetWeakPtr())); | |
| 564 } | |
| 565 | |
| 566 void ProximityAuthWebUIHandler::OnConnectionFound( | |
| 567 scoped_ptr<Connection> connection) { | |
| 568 DCHECK(connection->IsConnected()); | |
| 569 connection_ = connection.Pass(); | |
| 570 connection_->AddObserver(this); | |
| 571 | |
| 572 web_ui()->CallJavascriptFunction("LocalStateInterface.onUnlockKeysChanged", | |
| 573 *GetUnlockKeysList()); | |
| 574 | |
| 575 // TODO(tengs): Create an authenticator for BLE connections. | |
| 576 if (selected_remote_device_.bluetooth_address.empty()) | |
| 577 return; | |
| 578 | |
| 579 authenticator_.reset(new DeviceToDeviceAuthenticator( | |
| 580 connection_.get(), proximity_auth_client_->GetAccountId(), | |
| 581 proximity_auth_client_->CreateSecureMessageDelegate())); | |
| 582 authenticator_->Authenticate( | |
| 583 base::Bind(&ProximityAuthWebUIHandler::OnAuthenticationResult, | |
| 584 weak_ptr_factory_.GetWeakPtr())); | |
| 585 } | |
| 586 | |
| 587 void ProximityAuthWebUIHandler::CreateStatusUpdateMessenger() { | |
| 588 messenger_.reset( | |
| 589 new MessengerImpl(connection_.Pass(), secure_context_.Pass())); | |
| 590 messenger_->AddObserver(this); | |
| 591 } | 474 } |
| 592 | 475 |
| 593 scoped_ptr<base::DictionaryValue> | 476 scoped_ptr<base::DictionaryValue> |
| 594 ProximityAuthWebUIHandler::ExternalDeviceInfoToDictionary( | 477 ProximityAuthWebUIHandler::ExternalDeviceInfoToDictionary( |
| 595 const cryptauth::ExternalDeviceInfo& device_info) { | 478 const cryptauth::ExternalDeviceInfo& device_info) { |
| 596 std::string base64_public_key; | 479 std::string base64_public_key; |
| 597 Base64UrlEncode(device_info.public_key(), &base64_public_key); | 480 Base64UrlEncode(device_info.public_key(), &base64_public_key); |
| 598 | 481 |
| 599 // Set the fields in the ExternalDeviceInfo proto. | 482 // Set the fields in the ExternalDeviceInfo proto. |
| 600 scoped_ptr<base::DictionaryValue> dictionary(new base::DictionaryValue()); | 483 scoped_ptr<base::DictionaryValue> dictionary(new base::DictionaryValue()); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 622 [&public_key](const cryptauth::ExternalDeviceInfo& unlock_key) { | 505 [&public_key](const cryptauth::ExternalDeviceInfo& unlock_key) { |
| 623 return unlock_key.public_key() == public_key; | 506 return unlock_key.public_key() == public_key; |
| 624 }); | 507 }); |
| 625 | 508 |
| 626 if (iterator == device_manager->unlock_keys().end() || | 509 if (iterator == device_manager->unlock_keys().end() || |
| 627 selected_remote_device_.public_key != device_info.public_key()) | 510 selected_remote_device_.public_key != device_info.public_key()) |
| 628 return dictionary; | 511 return dictionary; |
| 629 | 512 |
| 630 // Fill in the current Bluetooth connection status. | 513 // Fill in the current Bluetooth connection status. |
| 631 std::string connection_status = kExternalDeviceDisconnected; | 514 std::string connection_status = kExternalDeviceDisconnected; |
| 632 Connection* connection = GetConnection(); | 515 if (life_cycle_ && |
| 633 if (connection && connection->IsConnected()) { | 516 life_cycle_->GetState() == |
| 517 RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED) { |
| 634 connection_status = kExternalDeviceConnected; | 518 connection_status = kExternalDeviceConnected; |
| 635 } else if (connection_finder_) { | 519 } else if (life_cycle_) { |
| 636 connection_status = kExternalDeviceConnecting; | 520 connection_status = kExternalDeviceConnecting; |
| 637 } | 521 } |
| 638 dictionary->SetString(kExternalDeviceConnectionStatus, connection_status); | 522 dictionary->SetString(kExternalDeviceConnectionStatus, connection_status); |
| 639 | 523 |
| 640 // Fill the remote status dictionary. | 524 // Fill the remote status dictionary. |
| 641 if (last_remote_status_update_) { | 525 if (last_remote_status_update_) { |
| 642 scoped_ptr<base::DictionaryValue> status_dictionary( | 526 scoped_ptr<base::DictionaryValue> status_dictionary( |
| 643 new base::DictionaryValue()); | 527 new base::DictionaryValue()); |
| 644 status_dictionary->SetInteger("userPresent", | 528 status_dictionary->SetInteger("userPresent", |
| 645 last_remote_status_update_->user_presence); | 529 last_remote_status_update_->user_presence); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 662 ineligibility_reasons->AppendString(reason); | 546 ineligibility_reasons->AppendString(reason); |
| 663 } | 547 } |
| 664 | 548 |
| 665 scoped_ptr<base::DictionaryValue> device_dictionary = | 549 scoped_ptr<base::DictionaryValue> device_dictionary = |
| 666 ExternalDeviceInfoToDictionary(ineligible_device.device()); | 550 ExternalDeviceInfoToDictionary(ineligible_device.device()); |
| 667 device_dictionary->Set(kIneligibleDeviceReasons, | 551 device_dictionary->Set(kIneligibleDeviceReasons, |
| 668 ineligibility_reasons.Pass()); | 552 ineligibility_reasons.Pass()); |
| 669 return device_dictionary; | 553 return device_dictionary; |
| 670 } | 554 } |
| 671 | 555 |
| 672 void ProximityAuthWebUIHandler::OnConnectionStatusChanged( | 556 void ProximityAuthWebUIHandler::CleanUpRemoteDeviceLifeCycle() { |
| 673 Connection* connection, | 557 PA_LOG(INFO) << "Cleaning up connection to " << selected_remote_device_.name |
| 674 Connection::Status old_status, | 558 << " [" << selected_remote_device_.bluetooth_address << "]"; |
| 675 Connection::Status new_status) { | 559 life_cycle_.reset(); |
| 676 PA_LOG(INFO) << "Connection status changed from " << old_status << " to " | 560 selected_remote_device_ = RemoteDevice(); |
| 677 << new_status; | 561 last_remote_status_update_.reset(); |
| 562 web_ui()->CallJavascriptFunction("LocalStateInterface.onUnlockKeysChanged", |
| 563 *GetUnlockKeysList()); |
| 564 } |
| 678 | 565 |
| 679 if (new_status == Connection::DISCONNECTED) { | 566 void ProximityAuthWebUIHandler::OnLifeCycleStateChanged( |
| 680 last_remote_status_update_.reset(); | 567 RemoteDeviceLifeCycle::State old_state, |
| 681 selected_remote_device_ = RemoteDevice(); | 568 RemoteDeviceLifeCycle::State new_state) { |
| 682 connection_finder_.reset(); | 569 // Do not re-attempt to find a connection after the first one fails--just |
| 570 // abort. |
| 571 if ((old_state != RemoteDeviceLifeCycle::State::STOPPED && |
| 572 new_state == RemoteDeviceLifeCycle::State::FINDING_CONNECTION) || |
| 573 new_state == RemoteDeviceLifeCycle::State::AUTHENTICATION_FAILED) { |
| 574 // Clean up the life cycle asynchronously, because we are currently in the |
| 575 // call stack of |life_cycle_|. |
| 576 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 577 FROM_HERE, |
| 578 base::Bind(&ProximityAuthWebUIHandler::CleanUpRemoteDeviceLifeCycle, |
| 579 weak_ptr_factory_.GetWeakPtr())); |
| 580 } else if (new_state == |
| 581 RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED) { |
| 582 life_cycle_->GetMessenger()->AddObserver(this); |
| 683 } | 583 } |
| 684 | 584 |
| 685 scoped_ptr<base::ListValue> unlock_keys = GetUnlockKeysList(); | |
| 686 web_ui()->CallJavascriptFunction("LocalStateInterface.onUnlockKeysChanged", | 585 web_ui()->CallJavascriptFunction("LocalStateInterface.onUnlockKeysChanged", |
| 687 *unlock_keys); | 586 *GetUnlockKeysList()); |
| 688 } | |
| 689 | |
| 690 void ProximityAuthWebUIHandler::OnMessageReceived(const Connection& connection, | |
| 691 const WireMessage& message) { | |
| 692 std::string address = connection.remote_device().bluetooth_address; | |
| 693 PA_LOG(INFO) << "Message received from " << address; | |
| 694 } | 587 } |
| 695 | 588 |
| 696 void ProximityAuthWebUIHandler::OnRemoteStatusUpdate( | 589 void ProximityAuthWebUIHandler::OnRemoteStatusUpdate( |
| 697 const RemoteStatusUpdate& status_update) { | 590 const RemoteStatusUpdate& status_update) { |
| 698 PA_LOG(INFO) << "Remote status update:" | 591 PA_LOG(INFO) << "Remote status update:" |
| 699 << "\n user_presence: " | 592 << "\n user_presence: " |
| 700 << static_cast<int>(status_update.user_presence) | 593 << static_cast<int>(status_update.user_presence) |
| 701 << "\n secure_screen_lock_state: " | 594 << "\n secure_screen_lock_state: " |
| 702 << static_cast<int>(status_update.secure_screen_lock_state) | 595 << static_cast<int>(status_update.secure_screen_lock_state) |
| 703 << "\n trust_agent_state: " | 596 << "\n trust_agent_state: " |
| 704 << static_cast<int>(status_update.trust_agent_state); | 597 << static_cast<int>(status_update.trust_agent_state); |
| 705 | 598 |
| 706 last_remote_status_update_.reset(new RemoteStatusUpdate(status_update)); | 599 last_remote_status_update_.reset(new RemoteStatusUpdate(status_update)); |
| 707 scoped_ptr<base::ListValue> unlock_keys = GetUnlockKeysList(); | 600 scoped_ptr<base::ListValue> unlock_keys = GetUnlockKeysList(); |
| 708 web_ui()->CallJavascriptFunction("LocalStateInterface.onUnlockKeysChanged", | 601 web_ui()->CallJavascriptFunction("LocalStateInterface.onUnlockKeysChanged", |
| 709 *unlock_keys); | 602 *unlock_keys); |
| 710 } | 603 } |
| 711 | 604 |
| 712 } // namespace proximity_auth | 605 } // namespace proximity_auth |
| OLD | NEW |