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