blob: d20707fc6dbde579d5afe04090cdcd80337362bc [file] [log] [blame]
// Copyright 2014 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 "chromeos/components/proximity_auth/proximity_auth_system.h"
#include "chromeos/components/multidevice/logging/logging.h"
#include "chromeos/components/proximity_auth/proximity_auth_client.h"
#include "chromeos/components/proximity_auth/remote_device_life_cycle_impl.h"
#include "chromeos/components/proximity_auth/unlock_manager_impl.h"
#include "chromeos/services/secure_channel/public/cpp/client/secure_channel_client.h"
namespace proximity_auth {
ProximityAuthSystem::ProximityAuthSystem(
ScreenlockType screenlock_type,
ProximityAuthClient* proximity_auth_client,
chromeos::secure_channel::SecureChannelClient* secure_channel_client)
: secure_channel_client_(secure_channel_client),
unlock_manager_(
std::make_unique<UnlockManagerImpl>(screenlock_type,
proximity_auth_client)),
suspended_(false),
started_(false) {}
ProximityAuthSystem::ProximityAuthSystem(
chromeos::secure_channel::SecureChannelClient* secure_channel_client,
std::unique_ptr<UnlockManager> unlock_manager)
: secure_channel_client_(secure_channel_client),
unlock_manager_(std::move(unlock_manager)),
suspended_(false),
started_(false) {}
ProximityAuthSystem::~ProximityAuthSystem() {
ScreenlockBridge::Get()->RemoveObserver(this);
unlock_manager_->SetRemoteDeviceLifeCycle(nullptr);
}
void ProximityAuthSystem::Start() {
if (started_)
return;
started_ = true;
ScreenlockBridge::Get()->AddObserver(this);
const AccountId& focused_account_id =
ScreenlockBridge::Get()->focused_account_id();
if (focused_account_id.is_valid())
OnFocusedUserChanged(focused_account_id);
}
void ProximityAuthSystem::Stop() {
if (!started_)
return;
started_ = false;
ScreenlockBridge::Get()->RemoveObserver(this);
OnFocusedUserChanged(EmptyAccountId());
}
void ProximityAuthSystem::SetRemoteDevicesForUser(
const AccountId& account_id,
const chromeos::multidevice::RemoteDeviceRefList& remote_devices,
base::Optional<chromeos::multidevice::RemoteDeviceRef> local_device) {
PA_LOG(VERBOSE) << "Setting devices for user " << account_id.Serialize()
<< ". Remote device count: " << remote_devices.size()
<< ", Local device: ["
<< (local_device.has_value() ? "present" : "absent") << "].";
remote_devices_map_[account_id] = remote_devices;
local_device_map_.emplace(account_id, *local_device);
if (started_) {
const AccountId& focused_account_id =
ScreenlockBridge::Get()->focused_account_id();
if (focused_account_id.is_valid())
OnFocusedUserChanged(focused_account_id);
}
}
chromeos::multidevice::RemoteDeviceRefList
ProximityAuthSystem::GetRemoteDevicesForUser(
const AccountId& account_id) const {
if (remote_devices_map_.find(account_id) == remote_devices_map_.end())
return chromeos::multidevice::RemoteDeviceRefList();
return remote_devices_map_.at(account_id);
}
void ProximityAuthSystem::OnAuthAttempted() {
unlock_manager_->OnAuthAttempted(mojom::AuthType::USER_CLICK);
}
void ProximityAuthSystem::OnSuspend() {
PA_LOG(INFO) << "Preparing for device suspension.";
DCHECK(!suspended_);
suspended_ = true;
unlock_manager_->SetRemoteDeviceLifeCycle(nullptr);
remote_device_life_cycle_.reset();
}
void ProximityAuthSystem::OnSuspendDone() {
PA_LOG(INFO) << "Device resumed from suspension.";
DCHECK(suspended_);
suspended_ = false;
if (!ScreenlockBridge::Get()->IsLocked()) {
PA_LOG(INFO) << "Suspend done, but no lock screen.";
} else if (!started_) {
PA_LOG(INFO) << "Suspend done, but not system started.";
} else {
OnFocusedUserChanged(ScreenlockBridge::Get()->focused_account_id());
}
}
void ProximityAuthSystem::CancelConnectionAttempt() {
unlock_manager_->CancelConnectionAttempt();
}
std::unique_ptr<RemoteDeviceLifeCycle>
ProximityAuthSystem::CreateRemoteDeviceLifeCycle(
chromeos::multidevice::RemoteDeviceRef remote_device,
base::Optional<chromeos::multidevice::RemoteDeviceRef> local_device) {
return std::make_unique<RemoteDeviceLifeCycleImpl>(
remote_device, local_device, secure_channel_client_);
}
void ProximityAuthSystem::OnScreenDidLock(
ScreenlockBridge::LockHandler::ScreenType screen_type) {
const AccountId& focused_account_id =
ScreenlockBridge::Get()->focused_account_id();
if (focused_account_id.is_valid())
OnFocusedUserChanged(focused_account_id);
}
void ProximityAuthSystem::OnScreenDidUnlock(
ScreenlockBridge::LockHandler::ScreenType screen_type) {
unlock_manager_->SetRemoteDeviceLifeCycle(nullptr);
remote_device_life_cycle_.reset();
}
void ProximityAuthSystem::OnFocusedUserChanged(const AccountId& account_id) {
// Update the current RemoteDeviceLifeCycle to the focused user.
if (remote_device_life_cycle_) {
if (remote_device_life_cycle_->GetRemoteDevice().user_email() !=
account_id.GetUserEmail()) {
PA_LOG(INFO) << "Focused user changed, destroying life cycle for "
<< account_id.Serialize() << ".";
unlock_manager_->SetRemoteDeviceLifeCycle(nullptr);
remote_device_life_cycle_.reset();
} else {
PA_LOG(INFO) << "Refocused on a user who is already focused.";
return;
}
}
if (remote_devices_map_.find(account_id) == remote_devices_map_.end() ||
remote_devices_map_[account_id].size() == 0) {
PA_LOG(INFO) << "User " << account_id.Serialize()
<< " does not have a Smart Lock host device.";
return;
}
if (local_device_map_.find(account_id) == local_device_map_.end()) {
PA_LOG(INFO) << "User " << account_id.Serialize()
<< " does not have a local device.";
return;
}
// TODO(tengs): We currently assume each user has only one RemoteDevice, so we
// can simply take the first item in the list.
chromeos::multidevice::RemoteDeviceRef remote_device =
remote_devices_map_[account_id][0];
base::Optional<chromeos::multidevice::RemoteDeviceRef> local_device;
local_device = local_device_map_.at(account_id);
if (!suspended_) {
PA_LOG(INFO) << "Creating RemoteDeviceLifeCycle for focused user: "
<< account_id.Serialize();
remote_device_life_cycle_ =
CreateRemoteDeviceLifeCycle(remote_device, local_device);
// UnlockManager listens for Bluetooth power change events, and is therefore
// responsible for starting RemoteDeviceLifeCycle when Bluetooth becomes
// powered.
unlock_manager_->SetRemoteDeviceLifeCycle(remote_device_life_cycle_.get());
}
}
} // namespace proximity_auth