blob: 50b8d427b3f0b5b36e182d10dd2cb6020bb4885c [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/proximity_auth/webui/proximity_auth_webui_handler.h"
#include <algorithm>
#include <memory>
#include <utility>
#include "base/base64url.h"
#include "base/bind.h"
#include "base/i18n/time_formatting.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/default_clock.h"
#include "base/time/default_tick_clock.h"
#include "base/values.h"
#include "components/cryptauth/cryptauth_enrollment_manager.h"
#include "components/cryptauth/proto/cryptauth_api.pb.h"
#include "components/cryptauth/remote_device.h"
#include "components/cryptauth/remote_device_loader.h"
#include "components/cryptauth/secure_context.h"
#include "components/cryptauth/secure_message_delegate.h"
#include "components/prefs/pref_service.h"
#include "components/proximity_auth/logging/logging.h"
#include "components/proximity_auth/messenger.h"
#include "components/proximity_auth/remote_device_life_cycle_impl.h"
#include "components/proximity_auth/remote_status_update.h"
#include "components/proximity_auth/webui/reachable_phone_flow.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_ui.h"
#include "device/bluetooth/bluetooth_uuid.h"
namespace proximity_auth {
namespace {
// Keys in the JSON representation of a log message.
const char kLogMessageTextKey[] = "text";
const char kLogMessageTimeKey[] = "time";
const char kLogMessageFileKey[] = "file";
const char kLogMessageLineKey[] = "line";
const char kLogMessageSeverityKey[] = "severity";
// Keys in the JSON representation of a SyncState object for enrollment or
// device sync.
const char kSyncStateLastSuccessTime[] = "lastSuccessTime";
const char kSyncStateNextRefreshTime[] = "nextRefreshTime";
const char kSyncStateRecoveringFromFailure[] = "recoveringFromFailure";
const char kSyncStateOperationInProgress[] = "operationInProgress";
// Converts |log_message| to a raw dictionary value used as a JSON argument to
// JavaScript functions.
std::unique_ptr<base::DictionaryValue> LogMessageToDictionary(
const LogBuffer::LogMessage& log_message) {
std::unique_ptr<base::DictionaryValue> dictionary(
new base::DictionaryValue());
dictionary->SetString(kLogMessageTextKey, log_message.text);
dictionary->SetString(
kLogMessageTimeKey,
base::TimeFormatTimeOfDayWithMilliseconds(log_message.time));
dictionary->SetString(kLogMessageFileKey, log_message.file);
dictionary->SetInteger(kLogMessageLineKey, log_message.line);
dictionary->SetInteger(kLogMessageSeverityKey,
static_cast<int>(log_message.severity));
return dictionary;
}
// Keys in the JSON representation of an ExternalDeviceInfo proto.
const char kExternalDevicePublicKey[] = "publicKey";
const char kExternalDevicePublicKeyTruncated[] = "publicKeyTruncated";
const char kExternalDeviceFriendlyName[] = "friendlyDeviceName";
const char kExternalDeviceBluetoothAddress[] = "bluetoothAddress";
const char kExternalDeviceUnlockKey[] = "unlockKey";
const char kExternalDeviceMobileHotspot[] = "hasMobileHotspot";
const char kExternalDeviceIsArcPlusPlusEnrollment[] = "isArcPlusPlusEnrollment";
const char kExternalDeviceIsPixelPhone[] = "isPixelPhone";
const char kExternalDeviceConnectionStatus[] = "connectionStatus";
const char kExternalDeviceRemoteState[] = "remoteState";
// The possible values of the |kExternalDeviceConnectionStatus| field.
const char kExternalDeviceConnected[] = "connected";
const char kExternalDeviceDisconnected[] = "disconnected";
const char kExternalDeviceConnecting[] = "connecting";
// Keys in the JSON representation of an IneligibleDevice proto.
const char kIneligibleDeviceReasons[] = "ineligibilityReasons";
// Creates a SyncState JSON object that can be passed to the WebUI.
std::unique_ptr<base::DictionaryValue> CreateSyncStateDictionary(
double last_success_time,
double next_refresh_time,
bool is_recovering_from_failure,
bool is_enrollment_in_progress) {
std::unique_ptr<base::DictionaryValue> sync_state(
new base::DictionaryValue());
sync_state->SetDouble(kSyncStateLastSuccessTime, last_success_time);
sync_state->SetDouble(kSyncStateNextRefreshTime, next_refresh_time);
sync_state->SetBoolean(kSyncStateRecoveringFromFailure,
is_recovering_from_failure);
sync_state->SetBoolean(kSyncStateOperationInProgress,
is_enrollment_in_progress);
return sync_state;
}
} // namespace
ProximityAuthWebUIHandler::ProximityAuthWebUIHandler(
ProximityAuthClient* proximity_auth_client)
: proximity_auth_client_(proximity_auth_client),
web_contents_initialized_(false),
weak_ptr_factory_(this) {
cryptauth_client_factory_ =
proximity_auth_client_->CreateCryptAuthClientFactory();
}
ProximityAuthWebUIHandler::~ProximityAuthWebUIHandler() {
LogBuffer::GetInstance()->RemoveObserver(this);
cryptauth::CryptAuthDeviceManager* device_manager =
proximity_auth_client_->GetCryptAuthDeviceManager();
if (device_manager)
device_manager->RemoveObserver(this);
}
void ProximityAuthWebUIHandler::RegisterMessages() {
web_ui()->RegisterMessageCallback(
"onWebContentsInitialized",
base::BindRepeating(&ProximityAuthWebUIHandler::OnWebContentsInitialized,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
"clearLogBuffer",
base::BindRepeating(&ProximityAuthWebUIHandler::ClearLogBuffer,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
"getLogMessages",
base::BindRepeating(&ProximityAuthWebUIHandler::GetLogMessages,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
"toggleUnlockKey",
base::BindRepeating(&ProximityAuthWebUIHandler::ToggleUnlockKey,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
"findEligibleUnlockDevices",
base::BindRepeating(&ProximityAuthWebUIHandler::FindEligibleUnlockDevices,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
"findReachableDevices",
base::BindRepeating(&ProximityAuthWebUIHandler::FindReachableDevices,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
"getLocalState",
base::BindRepeating(&ProximityAuthWebUIHandler::GetLocalState,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
"forceEnrollment",
base::BindRepeating(&ProximityAuthWebUIHandler::ForceEnrollment,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
"forceDeviceSync",
base::BindRepeating(&ProximityAuthWebUIHandler::ForceDeviceSync,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
"toggleConnection",
base::BindRepeating(&ProximityAuthWebUIHandler::ToggleConnection,
base::Unretained(this)));
}
void ProximityAuthWebUIHandler::OnLogMessageAdded(
const LogBuffer::LogMessage& log_message) {
std::unique_ptr<base::DictionaryValue> dictionary =
LogMessageToDictionary(log_message);
web_ui()->CallJavascriptFunctionUnsafe("LogBufferInterface.onLogMessageAdded",
*dictionary);
}
void ProximityAuthWebUIHandler::OnLogBufferCleared() {
web_ui()->CallJavascriptFunctionUnsafe(
"LogBufferInterface.onLogBufferCleared");
}
void ProximityAuthWebUIHandler::OnEnrollmentStarted() {
web_ui()->CallJavascriptFunctionUnsafe(
"LocalStateInterface.onEnrollmentStateChanged",
*GetEnrollmentStateDictionary());
}
void ProximityAuthWebUIHandler::OnEnrollmentFinished(bool success) {
std::unique_ptr<base::DictionaryValue> enrollment_state =
GetEnrollmentStateDictionary();
PA_LOG(INFO) << "Enrollment attempt completed with success=" << success
<< ":\n" << *enrollment_state;
web_ui()->CallJavascriptFunctionUnsafe(
"LocalStateInterface.onEnrollmentStateChanged", *enrollment_state);
}
void ProximityAuthWebUIHandler::OnSyncStarted() {
web_ui()->CallJavascriptFunctionUnsafe(
"LocalStateInterface.onDeviceSyncStateChanged",
*GetDeviceSyncStateDictionary());
}
void ProximityAuthWebUIHandler::OnSyncFinished(
cryptauth::CryptAuthDeviceManager::SyncResult sync_result,
cryptauth::CryptAuthDeviceManager::DeviceChangeResult
device_change_result) {
std::unique_ptr<base::DictionaryValue> device_sync_state =
GetDeviceSyncStateDictionary();
PA_LOG(INFO) << "Device sync completed with result="
<< static_cast<int>(sync_result) << ":\n" << *device_sync_state;
web_ui()->CallJavascriptFunctionUnsafe(
"LocalStateInterface.onDeviceSyncStateChanged", *device_sync_state);
if (device_change_result ==
cryptauth::CryptAuthDeviceManager::DeviceChangeResult::CHANGED) {
std::unique_ptr<base::ListValue> synced_devices = GetRemoteDevicesList();
PA_LOG(INFO) << "New unlock keys obtained after device sync:\n"
<< *synced_devices;
web_ui()->CallJavascriptFunctionUnsafe(
"LocalStateInterface.onRemoteDevicesChanged", *synced_devices);
}
}
void ProximityAuthWebUIHandler::OnWebContentsInitialized(
const base::ListValue* args) {
if (!web_contents_initialized_) {
cryptauth::CryptAuthEnrollmentManager* enrollment_manager =
proximity_auth_client_->GetCryptAuthEnrollmentManager();
if (enrollment_manager)
enrollment_manager->AddObserver(this);
cryptauth::CryptAuthDeviceManager* device_manager =
proximity_auth_client_->GetCryptAuthDeviceManager();
if (device_manager)
device_manager->AddObserver(this);
LogBuffer::GetInstance()->AddObserver(this);
web_contents_initialized_ = true;
}
}
void ProximityAuthWebUIHandler::GetLogMessages(const base::ListValue* args) {
base::ListValue json_logs;
for (const auto& log : *LogBuffer::GetInstance()->logs()) {
json_logs.Append(LogMessageToDictionary(log));
}
web_ui()->CallJavascriptFunctionUnsafe("LogBufferInterface.onGotLogMessages",
json_logs);
}
void ProximityAuthWebUIHandler::ClearLogBuffer(const base::ListValue* args) {
// The OnLogBufferCleared() observer function will be called after the buffer
// is cleared.
LogBuffer::GetInstance()->Clear();
}
void ProximityAuthWebUIHandler::ToggleUnlockKey(const base::ListValue* args) {
std::string public_key_b64, public_key;
bool make_unlock_key;
if (args->GetSize() != 2 || !args->GetString(0, &public_key_b64) ||
!args->GetBoolean(1, &make_unlock_key) ||
!base::Base64UrlDecode(public_key_b64,
base::Base64UrlDecodePolicy::REQUIRE_PADDING,
&public_key)) {
PA_LOG(ERROR) << "Invalid arguments to toggleUnlockKey";
return;
}
cryptauth::ToggleEasyUnlockRequest request;
request.set_enable(make_unlock_key);
request.set_public_key(public_key);
*(request.mutable_device_classifier()) =
proximity_auth_client_->GetDeviceClassifier();
PA_LOG(INFO) << "Toggling unlock key:\n"
<< " public_key: " << public_key_b64 << "\n"
<< " make_unlock_key: " << make_unlock_key;
cryptauth_client_ = cryptauth_client_factory_->CreateInstance();
cryptauth_client_->ToggleEasyUnlock(
request, base::Bind(&ProximityAuthWebUIHandler::OnEasyUnlockToggled,
weak_ptr_factory_.GetWeakPtr()),
base::Bind(&ProximityAuthWebUIHandler::OnCryptAuthClientError,
weak_ptr_factory_.GetWeakPtr()));
}
void ProximityAuthWebUIHandler::FindEligibleUnlockDevices(
const base::ListValue* args) {
cryptauth_client_ = cryptauth_client_factory_->CreateInstance();
cryptauth::FindEligibleUnlockDevicesRequest request;
*(request.mutable_device_classifier()) =
proximity_auth_client_->GetDeviceClassifier();
cryptauth_client_->FindEligibleUnlockDevices(
request,
base::Bind(&ProximityAuthWebUIHandler::OnFoundEligibleUnlockDevices,
weak_ptr_factory_.GetWeakPtr()),
base::Bind(&ProximityAuthWebUIHandler::OnCryptAuthClientError,
weak_ptr_factory_.GetWeakPtr()));
}
void ProximityAuthWebUIHandler::FindReachableDevices(
const base::ListValue* args) {
if (reachable_phone_flow_) {
PA_LOG(INFO) << "Waiting for existing ReachablePhoneFlow to finish.";
return;
}
reachable_phone_flow_.reset(
new ReachablePhoneFlow(cryptauth_client_factory_.get()));
reachable_phone_flow_->Run(
base::Bind(&ProximityAuthWebUIHandler::OnReachablePhonesFound,
weak_ptr_factory_.GetWeakPtr()));
}
void ProximityAuthWebUIHandler::ForceEnrollment(const base::ListValue* args) {
cryptauth::CryptAuthEnrollmentManager* enrollment_manager =
proximity_auth_client_->GetCryptAuthEnrollmentManager();
if (enrollment_manager) {
enrollment_manager->ForceEnrollmentNow(cryptauth::INVOCATION_REASON_MANUAL);
}
}
void ProximityAuthWebUIHandler::ForceDeviceSync(const base::ListValue* args) {
cryptauth::CryptAuthDeviceManager* device_manager =
proximity_auth_client_->GetCryptAuthDeviceManager();
if (device_manager)
device_manager->ForceSyncNow(cryptauth::INVOCATION_REASON_MANUAL);
}
void ProximityAuthWebUIHandler::ToggleConnection(const base::ListValue* args) {
cryptauth::CryptAuthEnrollmentManager* enrollment_manager =
proximity_auth_client_->GetCryptAuthEnrollmentManager();
cryptauth::CryptAuthDeviceManager* device_manager =
proximity_auth_client_->GetCryptAuthDeviceManager();
if (!enrollment_manager || !device_manager)
return;
std::string b64_public_key;
std::string public_key;
if (!enrollment_manager || !device_manager || !args->GetSize() ||
!args->GetString(0, &b64_public_key) ||
!base::Base64UrlDecode(b64_public_key,
base::Base64UrlDecodePolicy::REQUIRE_PADDING,
&public_key)) {
return;
}
for (const auto& unlock_key : device_manager->GetUnlockKeys()) {
if (unlock_key.public_key() == public_key) {
if (life_cycle_ && selected_remote_device_.public_key == public_key) {
CleanUpRemoteDeviceLifeCycle();
return;
}
// TODO(sacomoto): Pass an instance of ProximityAuthPrefManager. This is
// used to get the address of BLE devices.
remote_device_loader_.reset(new cryptauth::RemoteDeviceLoader(
std::vector<cryptauth::ExternalDeviceInfo>(1, unlock_key),
proximity_auth_client_->GetAccountId(),
enrollment_manager->GetUserPrivateKey(),
proximity_auth_client_->CreateSecureMessageDelegate()));
remote_device_loader_->Load(
true /* should_load_beacon_seeds */,
base::Bind(&ProximityAuthWebUIHandler::OnRemoteDevicesLoaded,
weak_ptr_factory_.GetWeakPtr()));
return;
}
}
PA_LOG(ERROR) << "Unlock key (" << b64_public_key << ") not found";
}
void ProximityAuthWebUIHandler::OnCryptAuthClientError(
const std::string& error_message) {
PA_LOG(WARNING) << "CryptAuth request failed: " << error_message;
base::Value error_string(error_message);
web_ui()->CallJavascriptFunctionUnsafe("CryptAuthInterface.onError",
error_string);
}
void ProximityAuthWebUIHandler::OnEasyUnlockToggled(
const cryptauth::ToggleEasyUnlockResponse& response) {
web_ui()->CallJavascriptFunctionUnsafe(
"CryptAuthInterface.onUnlockKeyToggled");
// TODO(tengs): Update the local state to reflect the toggle.
}
void ProximityAuthWebUIHandler::OnFoundEligibleUnlockDevices(
const cryptauth::FindEligibleUnlockDevicesResponse& response) {
base::ListValue eligible_devices;
for (const auto& external_device : response.eligible_devices()) {
eligible_devices.Append(ExternalDeviceInfoToDictionary(external_device));
}
base::ListValue ineligible_devices;
for (const auto& ineligible_device : response.ineligible_devices()) {
ineligible_devices.Append(IneligibleDeviceToDictionary(ineligible_device));
}
PA_LOG(INFO) << "Found " << eligible_devices.GetSize()
<< " eligible devices and " << ineligible_devices.GetSize()
<< " ineligible devices.";
web_ui()->CallJavascriptFunctionUnsafe(
"CryptAuthInterface.onGotEligibleDevices", eligible_devices,
ineligible_devices);
}
void ProximityAuthWebUIHandler::OnReachablePhonesFound(
const std::vector<cryptauth::ExternalDeviceInfo>& reachable_phones) {
reachable_phone_flow_.reset();
base::ListValue device_list;
for (const auto& external_device : reachable_phones) {
device_list.Append(ExternalDeviceInfoToDictionary(external_device));
}
web_ui()->CallJavascriptFunctionUnsafe(
"CryptAuthInterface.onGotReachableDevices", device_list);
}
void ProximityAuthWebUIHandler::GetLocalState(const base::ListValue* args) {
std::unique_ptr<base::Value> truncated_local_device_id =
GetTruncatedLocalDeviceId();
std::unique_ptr<base::DictionaryValue> enrollment_state =
GetEnrollmentStateDictionary();
std::unique_ptr<base::DictionaryValue> device_sync_state =
GetDeviceSyncStateDictionary();
std::unique_ptr<base::ListValue> synced_devices = GetRemoteDevicesList();
PA_LOG(INFO) << "==== Got Local State ====\n"
<< "Device ID (truncated): " << *truncated_local_device_id
<< "\nEnrollment State: \n"
<< *enrollment_state << "Device Sync State: \n"
<< *device_sync_state << "Unlock Keys: \n"
<< *synced_devices;
web_ui()->CallJavascriptFunctionUnsafe(
"LocalStateInterface.onGotLocalState", *truncated_local_device_id,
*enrollment_state, *device_sync_state, *synced_devices);
}
std::unique_ptr<base::Value>
ProximityAuthWebUIHandler::GetTruncatedLocalDeviceId() {
std::string local_public_key =
proximity_auth_client_->GetLocalDevicePublicKey();
std::string device_id;
base::Base64UrlEncode(local_public_key,
base::Base64UrlEncodePolicy::INCLUDE_PADDING,
&device_id);
return std::make_unique<base::Value>(
cryptauth::RemoteDevice::TruncateDeviceIdForLogs(device_id));
}
std::unique_ptr<base::DictionaryValue>
ProximityAuthWebUIHandler::GetEnrollmentStateDictionary() {
cryptauth::CryptAuthEnrollmentManager* enrollment_manager =
proximity_auth_client_->GetCryptAuthEnrollmentManager();
if (!enrollment_manager)
return std::make_unique<base::DictionaryValue>();
return CreateSyncStateDictionary(
enrollment_manager->GetLastEnrollmentTime().ToJsTime(),
enrollment_manager->GetTimeToNextAttempt().InMillisecondsF(),
enrollment_manager->IsRecoveringFromFailure(),
enrollment_manager->IsEnrollmentInProgress());
}
std::unique_ptr<base::DictionaryValue>
ProximityAuthWebUIHandler::GetDeviceSyncStateDictionary() {
cryptauth::CryptAuthDeviceManager* device_manager =
proximity_auth_client_->GetCryptAuthDeviceManager();
if (!device_manager)
return std::make_unique<base::DictionaryValue>();
return CreateSyncStateDictionary(
device_manager->GetLastSyncTime().ToJsTime(),
device_manager->GetTimeToNextAttempt().InMillisecondsF(),
device_manager->IsRecoveringFromFailure(),
device_manager->IsSyncInProgress());
}
std::unique_ptr<base::ListValue>
ProximityAuthWebUIHandler::GetRemoteDevicesList() {
std::unique_ptr<base::ListValue> unlock_keys(new base::ListValue());
cryptauth::CryptAuthDeviceManager* device_manager =
proximity_auth_client_->GetCryptAuthDeviceManager();
if (!device_manager)
return unlock_keys;
for (const auto& unlock_key : device_manager->GetSyncedDevices()) {
unlock_keys->Append(ExternalDeviceInfoToDictionary(unlock_key));
}
return unlock_keys;
}
void ProximityAuthWebUIHandler::OnRemoteDevicesLoaded(
const std::vector<cryptauth::RemoteDevice>& remote_devices) {
if (remote_devices[0].persistent_symmetric_key.empty()) {
PA_LOG(ERROR) << "Failed to derive PSK.";
return;
}
selected_remote_device_ = remote_devices[0];
life_cycle_.reset(new RemoteDeviceLifeCycleImpl(selected_remote_device_,
proximity_auth_client_));
life_cycle_->AddObserver(this);
life_cycle_->Start();
}
std::unique_ptr<base::DictionaryValue>
ProximityAuthWebUIHandler::ExternalDeviceInfoToDictionary(
const cryptauth::ExternalDeviceInfo& device_info) {
std::string base64_public_key;
base::Base64UrlEncode(device_info.public_key(),
base::Base64UrlEncodePolicy::INCLUDE_PADDING,
&base64_public_key);
// Set the fields in the ExternalDeviceInfo proto.
std::unique_ptr<base::DictionaryValue> dictionary(
new base::DictionaryValue());
dictionary->SetString(kExternalDevicePublicKey, base64_public_key);
dictionary->SetString(
kExternalDevicePublicKeyTruncated,
cryptauth::RemoteDevice::TruncateDeviceIdForLogs(base64_public_key));
dictionary->SetString(kExternalDeviceFriendlyName,
device_info.friendly_device_name());
dictionary->SetString(kExternalDeviceBluetoothAddress,
device_info.bluetooth_address());
dictionary->SetBoolean(kExternalDeviceUnlockKey, device_info.unlock_key());
dictionary->SetBoolean(kExternalDeviceMobileHotspot,
device_info.mobile_hotspot_supported());
dictionary->SetBoolean(kExternalDeviceIsArcPlusPlusEnrollment,
device_info.arc_plus_plus());
dictionary->SetBoolean(kExternalDeviceIsPixelPhone,
device_info.pixel_phone());
dictionary->SetString(kExternalDeviceConnectionStatus,
kExternalDeviceDisconnected);
cryptauth::CryptAuthDeviceManager* device_manager =
proximity_auth_client_->GetCryptAuthDeviceManager();
if (!device_manager)
return dictionary;
// If |device_info| is a known unlock key, then combine the proto data with
// the corresponding local device data (e.g. connection status and remote
// status updates).
std::string public_key = device_info.public_key();
std::vector<cryptauth::ExternalDeviceInfo> unlock_keys =
device_manager->GetUnlockKeys();
auto iterator = std::find_if(
unlock_keys.begin(), unlock_keys.end(),
[&public_key](const cryptauth::ExternalDeviceInfo& unlock_key) {
return unlock_key.public_key() == public_key;
});
if (iterator == unlock_keys.end() ||
selected_remote_device_.public_key != device_info.public_key())
return dictionary;
// Fill in the current Bluetooth connection status.
std::string connection_status = kExternalDeviceDisconnected;
if (life_cycle_ &&
life_cycle_->GetState() ==
RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED) {
connection_status = kExternalDeviceConnected;
} else if (life_cycle_) {
connection_status = kExternalDeviceConnecting;
}
dictionary->SetString(kExternalDeviceConnectionStatus, connection_status);
// Fill the remote status dictionary.
if (last_remote_status_update_) {
std::unique_ptr<base::DictionaryValue> status_dictionary(
new base::DictionaryValue());
status_dictionary->SetInteger("userPresent",
last_remote_status_update_->user_presence);
status_dictionary->SetInteger(
"secureScreenLock",
last_remote_status_update_->secure_screen_lock_state);
status_dictionary->SetInteger(
"trustAgent", last_remote_status_update_->trust_agent_state);
dictionary->Set(kExternalDeviceRemoteState, std::move(status_dictionary));
}
return dictionary;
}
std::unique_ptr<base::DictionaryValue>
ProximityAuthWebUIHandler::IneligibleDeviceToDictionary(
const cryptauth::IneligibleDevice& ineligible_device) {
std::unique_ptr<base::ListValue> ineligibility_reasons(new base::ListValue());
for (const std::string& reason : ineligible_device.reasons()) {
ineligibility_reasons->AppendString(reason);
}
std::unique_ptr<base::DictionaryValue> device_dictionary =
ExternalDeviceInfoToDictionary(ineligible_device.device());
device_dictionary->Set(kIneligibleDeviceReasons,
std::move(ineligibility_reasons));
return device_dictionary;
}
void ProximityAuthWebUIHandler::CleanUpRemoteDeviceLifeCycle() {
PA_LOG(INFO) << "Cleaning up connection to " << selected_remote_device_.name
<< " [" << selected_remote_device_.bluetooth_address << "]";
life_cycle_.reset();
selected_remote_device_ = cryptauth::RemoteDevice();
last_remote_status_update_.reset();
web_ui()->CallJavascriptFunctionUnsafe(
"LocalStateInterface.onRemoteDevicesChanged", *GetRemoteDevicesList());
}
void ProximityAuthWebUIHandler::OnLifeCycleStateChanged(
RemoteDeviceLifeCycle::State old_state,
RemoteDeviceLifeCycle::State new_state) {
// Do not re-attempt to find a connection after the first one fails--just
// abort.
if ((old_state != RemoteDeviceLifeCycle::State::STOPPED &&
new_state == RemoteDeviceLifeCycle::State::FINDING_CONNECTION) ||
new_state == RemoteDeviceLifeCycle::State::AUTHENTICATION_FAILED) {
// Clean up the life cycle asynchronously, because we are currently in the
// call stack of |life_cycle_|.
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::Bind(&ProximityAuthWebUIHandler::CleanUpRemoteDeviceLifeCycle,
weak_ptr_factory_.GetWeakPtr()));
} else if (new_state ==
RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED) {
life_cycle_->GetMessenger()->AddObserver(this);
}
web_ui()->CallJavascriptFunctionUnsafe(
"LocalStateInterface.onRemoteDevicesChanged", *GetRemoteDevicesList());
}
void ProximityAuthWebUIHandler::OnRemoteStatusUpdate(
const RemoteStatusUpdate& status_update) {
PA_LOG(INFO) << "Remote status update:"
<< "\n user_presence: "
<< static_cast<int>(status_update.user_presence)
<< "\n secure_screen_lock_state: "
<< static_cast<int>(status_update.secure_screen_lock_state)
<< "\n trust_agent_state: "
<< static_cast<int>(status_update.trust_agent_state);
last_remote_status_update_.reset(new RemoteStatusUpdate(status_update));
std::unique_ptr<base::ListValue> synced_devices = GetRemoteDevicesList();
web_ui()->CallJavascriptFunctionUnsafe(
"LocalStateInterface.onRemoteDevicesChanged", *synced_devices);
}
} // namespace proximity_auth