blob: 661497d40098963b433ae9801e29d613372c1013 [file] [log] [blame]
// Copyright 2018 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/services/multidevice_setup/multidevice_setup_impl.h"
#include "base/memory/ptr_util.h"
#include "base/no_destructor.h"
#include "base/time/default_clock.h"
#include "chromeos/components/proximity_auth/logging/logging.h"
#include "chromeos/services/multidevice_setup/account_status_change_delegate_notifier_impl.h"
#include "chromeos/services/multidevice_setup/eligible_host_devices_provider_impl.h"
#include "chromeos/services/multidevice_setup/host_backend_delegate_impl.h"
#include "chromeos/services/multidevice_setup/host_status_provider_impl.h"
#include "chromeos/services/multidevice_setup/host_verifier_impl.h"
#include "chromeos/services/multidevice_setup/setup_flow_completion_recorder_impl.h"
namespace chromeos {
namespace multidevice_setup {
// static
MultiDeviceSetupImpl::Factory* MultiDeviceSetupImpl::Factory::test_factory_ =
nullptr;
// static
MultiDeviceSetupImpl::Factory* MultiDeviceSetupImpl::Factory::Get() {
if (test_factory_)
return test_factory_;
static base::NoDestructor<Factory> factory;
return factory.get();
}
// static
void MultiDeviceSetupImpl::Factory::SetFactoryForTesting(
Factory* test_factory) {
test_factory_ = test_factory;
}
MultiDeviceSetupImpl::Factory::~Factory() = default;
std::unique_ptr<mojom::MultiDeviceSetup>
MultiDeviceSetupImpl::Factory::BuildInstance(
PrefService* pref_service,
device_sync::DeviceSyncClient* device_sync_client,
secure_channel::SecureChannelClient* secure_channel_client) {
return base::WrapUnique(new MultiDeviceSetupImpl(
pref_service, device_sync_client, secure_channel_client));
}
MultiDeviceSetupImpl::MultiDeviceSetupImpl(
PrefService* pref_service,
device_sync::DeviceSyncClient* device_sync_client,
secure_channel::SecureChannelClient* secure_channel_client)
: eligible_host_devices_provider_(
EligibleHostDevicesProviderImpl::Factory::Get()->BuildInstance(
device_sync_client)),
host_backend_delegate_(
HostBackendDelegateImpl::Factory::Get()->BuildInstance(
eligible_host_devices_provider_.get(),
pref_service,
device_sync_client)),
host_verifier_(HostVerifierImpl::Factory::Get()->BuildInstance(
host_backend_delegate_.get(),
device_sync_client,
pref_service)),
host_status_provider_(
HostStatusProviderImpl::Factory::Get()->BuildInstance(
eligible_host_devices_provider_.get(),
host_backend_delegate_.get(),
host_verifier_.get(),
device_sync_client)),
setup_flow_completion_recorder_(
SetupFlowCompletionRecorderImpl::Factory::Get()->BuildInstance(
pref_service,
base::DefaultClock::GetInstance())),
delegate_notifier_(
AccountStatusChangeDelegateNotifierImpl::Factory::Get()
->BuildInstance(device_sync_client,
pref_service,
setup_flow_completion_recorder_.get(),
base::DefaultClock::GetInstance())) {
host_status_provider_->AddObserver(this);
}
MultiDeviceSetupImpl::~MultiDeviceSetupImpl() {
host_status_provider_->RemoveObserver(this);
}
void MultiDeviceSetupImpl::SetAccountStatusChangeDelegate(
mojom::AccountStatusChangeDelegatePtr delegate) {
delegate_notifier_->SetAccountStatusChangeDelegatePtr(std::move(delegate));
}
void MultiDeviceSetupImpl::AddHostStatusObserver(
mojom::HostStatusObserverPtr observer) {
host_status_observers_.AddPtr(std::move(observer));
}
void MultiDeviceSetupImpl::GetEligibleHostDevices(
GetEligibleHostDevicesCallback callback) {
std::vector<cryptauth::RemoteDevice> eligible_remote_devices;
for (const auto& remote_device_ref :
eligible_host_devices_provider_->GetEligibleHostDevices()) {
eligible_remote_devices.push_back(remote_device_ref.GetRemoteDevice());
}
std::move(callback).Run(eligible_remote_devices);
}
void MultiDeviceSetupImpl::SetHostDevice(const std::string& host_public_key,
SetHostDeviceCallback callback) {
cryptauth::RemoteDeviceRefList eligible_devices =
eligible_host_devices_provider_->GetEligibleHostDevices();
auto it =
std::find_if(eligible_devices.begin(), eligible_devices.end(),
[&host_public_key](const auto& eligible_device) {
return eligible_device.public_key() == host_public_key;
});
if (it == eligible_devices.end()) {
std::move(callback).Run(false /* success */);
return;
}
host_backend_delegate_->AttemptToSetMultiDeviceHostOnBackend(*it);
std::move(callback).Run(true /* success */);
}
void MultiDeviceSetupImpl::RemoveHostDevice() {
host_backend_delegate_->AttemptToSetMultiDeviceHostOnBackend(
base::nullopt /* host_device */);
}
void MultiDeviceSetupImpl::GetHostStatus(GetHostStatusCallback callback) {
HostStatusProvider::HostStatusWithDevice host_status_with_device =
host_status_provider_->GetHostWithStatus();
// The Mojo API requires a raw cryptauth::RemoteDevice instead of a
// cryptauth::RemoteDeviceRef.
base::Optional<cryptauth::RemoteDevice> device_for_callback;
if (host_status_with_device.host_device()) {
device_for_callback =
host_status_with_device.host_device()->GetRemoteDevice();
}
std::move(callback).Run(host_status_with_device.host_status(),
device_for_callback);
}
void MultiDeviceSetupImpl::RetrySetHostNow(RetrySetHostNowCallback callback) {
HostStatusProvider::HostStatusWithDevice host_status_with_device =
host_status_provider_->GetHostWithStatus();
if (host_status_with_device.host_status() ==
mojom::HostStatus::kHostSetLocallyButWaitingForBackendConfirmation) {
host_backend_delegate_->AttemptToSetMultiDeviceHostOnBackend(
*host_backend_delegate_->GetPendingHostRequest());
std::move(callback).Run(true /* success */);
return;
}
if (host_status_with_device.host_status() ==
mojom::HostStatus::kHostSetButNotYetVerified) {
host_verifier_->AttemptVerificationNow();
std::move(callback).Run(true /* success */);
return;
}
// RetrySetHostNow() was called when there was nothing to retry.
std::move(callback).Run(false /* success */);
}
void MultiDeviceSetupImpl::TriggerEventForDebugging(
mojom::EventTypeForDebugging type,
TriggerEventForDebuggingCallback callback) {
if (!delegate_notifier_->delegate_ptr_) {
PA_LOG(ERROR) << "MultiDeviceSetupImpl::TriggerEventForDebugging(): No "
<< "delgate has been set; cannot proceed.";
std::move(callback).Run(false /* success */);
return;
}
PA_LOG(INFO) << "MultiDeviceSetupImpl::TriggerEventForDebugging(" << type
<< ") called.";
mojom::AccountStatusChangeDelegate* delegate =
delegate_notifier_->delegate_ptr_.get();
switch (type) {
case mojom::EventTypeForDebugging::kNewUserPotentialHostExists:
delegate->OnPotentialHostExistsForNewUser();
break;
case mojom::EventTypeForDebugging::kExistingUserConnectedHostSwitched:
delegate->OnConnectedHostSwitchedForExistingUser();
break;
case mojom::EventTypeForDebugging::kExistingUserNewChromebookAdded:
delegate->OnNewChromebookAddedForExistingUser();
break;
default:
NOTREACHED();
}
std::move(callback).Run(true /* success */);
}
void MultiDeviceSetupImpl::OnHostStatusChange(
const HostStatusProvider::HostStatusWithDevice& host_status_with_device) {
mojom::HostStatus status_for_callback = host_status_with_device.host_status();
// The Mojo API requires a raw cryptauth::RemoteDevice instead of a
// cryptauth::RemoteDeviceRef.
base::Optional<cryptauth::RemoteDevice> device_for_callback;
if (host_status_with_device.host_device()) {
device_for_callback =
host_status_with_device.host_device()->GetRemoteDevice();
}
host_status_observers_.ForAllPtrs(
[&status_for_callback,
&device_for_callback](mojom::HostStatusObserver* observer) {
observer->OnHostStatusChanged(status_for_callback, device_for_callback);
});
}
void MultiDeviceSetupImpl::FlushForTesting() {
host_status_observers_.FlushForTesting();
}
} // namespace multidevice_setup
} // namespace chromeos