1 // Copyright 2017 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 "device/fido/fido_device_discovery.h"
6 
7 #include <utility>
8 
9 #include "base/bind.h"
10 #include "base/threading/sequenced_task_runner_handle.h"
11 #include "device/fido/fido_authenticator.h"
12 #include "device/fido/fido_device.h"
13 #include "device/fido/fido_device_authenticator.h"
14 
15 namespace device {
16 
17 FidoDeviceDiscovery::Observer::~Observer() = default;
18 
FidoDeviceDiscovery(FidoTransportProtocol transport)19 FidoDeviceDiscovery::FidoDeviceDiscovery(FidoTransportProtocol transport)
20     : FidoDiscoveryBase(transport) {}
21 
22 FidoDeviceDiscovery::~FidoDeviceDiscovery() = default;
23 
Start()24 void FidoDeviceDiscovery::Start() {
25   DCHECK_EQ(state_, State::kIdle);
26   state_ = State::kStarting;
27 
28   // To ensure that that NotifyStarted() is never invoked synchronously,
29   // post task asynchronously.
30   base::SequencedTaskRunnerHandle::Get()->PostTask(
31       FROM_HERE, base::BindOnce(&FidoDeviceDiscovery::StartInternal,
32                                 weak_factory_.GetWeakPtr()));
33 }
34 
NotifyDiscoveryStarted(bool success)35 void FidoDeviceDiscovery::NotifyDiscoveryStarted(bool success) {
36   if (state_ == State::kStopped)
37     return;
38 
39   DCHECK(state_ == State::kStarting);
40   if (success)
41     state_ = State::kRunning;
42   if (!observer())
43     return;
44 
45   std::vector<FidoAuthenticator*> authenticators;
46   authenticators.reserve(authenticators_.size());
47   for (const auto& authenticator : authenticators_)
48     authenticators.push_back(authenticator.second.get());
49   observer()->DiscoveryStarted(this, success, std::move(authenticators));
50 }
51 
NotifyAuthenticatorAdded(FidoAuthenticator * authenticator)52 void FidoDeviceDiscovery::NotifyAuthenticatorAdded(
53     FidoAuthenticator* authenticator) {
54   DCHECK_NE(state_, State::kIdle);
55   if (!observer() || state_ != State::kRunning)
56     return;
57   observer()->AuthenticatorAdded(this, authenticator);
58 }
59 
NotifyAuthenticatorRemoved(FidoAuthenticator * authenticator)60 void FidoDeviceDiscovery::NotifyAuthenticatorRemoved(
61     FidoAuthenticator* authenticator) {
62   DCHECK_NE(state_, State::kIdle);
63   if (!observer() || state_ != State::kRunning)
64     return;
65   observer()->AuthenticatorRemoved(this, authenticator);
66 }
67 
68 std::vector<FidoDeviceAuthenticator*>
GetAuthenticatorsForTesting()69 FidoDeviceDiscovery::GetAuthenticatorsForTesting() {
70   std::vector<FidoDeviceAuthenticator*> authenticators;
71   authenticators.reserve(authenticators_.size());
72   for (const auto& authenticator : authenticators_)
73     authenticators.push_back(authenticator.second.get());
74   return authenticators;
75 }
76 
77 std::vector<const FidoDeviceAuthenticator*>
GetAuthenticatorsForTesting() const78 FidoDeviceDiscovery::GetAuthenticatorsForTesting() const {
79   std::vector<const FidoDeviceAuthenticator*> authenticators;
80   authenticators.reserve(authenticators_.size());
81   for (const auto& authenticator : authenticators_)
82     authenticators.push_back(authenticator.second.get());
83   return authenticators;
84 }
85 
GetAuthenticatorForTesting(base::StringPiece authenticator_id)86 FidoDeviceAuthenticator* FidoDeviceDiscovery::GetAuthenticatorForTesting(
87     base::StringPiece authenticator_id) {
88   return GetAuthenticator(authenticator_id);
89 }
90 
GetAuthenticator(base::StringPiece authenticator_id)91 FidoDeviceAuthenticator* FidoDeviceDiscovery::GetAuthenticator(
92     base::StringPiece authenticator_id) {
93   auto found = authenticators_.find(authenticator_id);
94   return found != authenticators_.end() ? found->second.get() : nullptr;
95 }
96 
AddDevice(std::unique_ptr<FidoDevice> device)97 bool FidoDeviceDiscovery::AddDevice(std::unique_ptr<FidoDevice> device) {
98   if (state_ == State::kStopped)
99     return false;
100 
101   auto authenticator =
102       std::make_unique<FidoDeviceAuthenticator>(std::move(device));
103   const auto result =
104       authenticators_.emplace(authenticator->GetId(), std::move(authenticator));
105   if (!result.second) {
106     return false;  // Duplicate device id.
107   }
108 
109   NotifyAuthenticatorAdded(result.first->second.get());
110   return true;
111 }
112 
RemoveDevice(base::StringPiece device_id)113 bool FidoDeviceDiscovery::RemoveDevice(base::StringPiece device_id) {
114   if (state_ == State::kStopped)
115     return false;
116 
117   auto found = authenticators_.find(device_id);
118   if (found == authenticators_.end())
119     return false;
120 
121   auto authenticator = std::move(found->second);
122   authenticators_.erase(found);
123   NotifyAuthenticatorRemoved(authenticator.get());
124   return true;
125 }
126 
MaybeStop()127 bool FidoDeviceDiscovery::MaybeStop() {
128   state_ = State::kStopped;
129   return true;
130 }
131 
132 }  // namespace device
133