OLD | NEW |
---|---|
(Empty) | |
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 "u2f_request.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/memory/ptr_util.h" | |
9 #include "base/threading/thread_task_runner_handle.h" | |
10 #include "device/base/device_client.h" | |
11 #include "u2f_hid_device.h" | |
12 | |
13 namespace device { | |
14 | |
15 U2fRequest::U2fRequest(const ResponseCallback& cb) | |
16 : state_(State::INIT), | |
17 cb_(cb), | |
18 hid_service_observer_(this), | |
19 weak_factory_(this) { | |
20 filter_.SetUsagePage(0xf1d0); | |
21 } | |
22 | |
23 void U2fRequest::Transition() { | |
24 switch (state_) { | |
25 case State::IDLE: | |
26 IterateDevice(); | |
27 if (!current_device_) { | |
28 // No devices available | |
29 state_ = State::OFF; | |
30 break; | |
31 } | |
32 state_ = State::WINK; | |
33 current_device_->TryWink( | |
34 base::Bind(&U2fRequest::Transition, weak_factory_.GetWeakPtr())); | |
35 break; | |
36 case State::WINK: | |
37 state_ = State::BUSY; | |
38 TryDevice(); | |
39 default: | |
40 break; | |
41 } | |
42 } | |
43 | |
44 void U2fRequest::Start() { | |
45 if (state_ == State::INIT) { | |
46 state_ = State::BUSY; | |
47 Enumerate(); | |
48 } | |
49 } | |
50 | |
51 void U2fRequest::Enumerate() { | |
52 HidService* hid_service = DeviceClient::Get()->GetHidService(); | |
53 DCHECK(hid_service); | |
54 hid_service_observer_.Add(hid_service); | |
55 hid_service->GetDevices( | |
56 base::Bind(&U2fRequest::OnEnumerate, weak_factory_.GetWeakPtr())); | |
57 } | |
58 | |
59 void U2fRequest::OnEnumerate( | |
60 const std::vector<scoped_refptr<HidDeviceInfo>>& devices) { | |
61 for (auto device_info : devices) { | |
62 if (filter_.Matches(device_info)) | |
63 devices_.push_back(base::MakeUnique<U2fHidDevice>(device_info)); | |
64 } | |
65 | |
66 state_ = State::IDLE; | |
67 Transition(); | |
68 } | |
69 | |
70 void U2fRequest::OnDeviceAdded(scoped_refptr<HidDeviceInfo> device_info) { | |
71 // Ignore non-U2F devices | |
72 if (!filter_.Matches(device_info)) | |
73 return; | |
74 | |
75 auto device = base::MakeUnique<U2fHidDevice>(device_info); | |
76 devices_.push_back(std::move(device)); | |
77 | |
78 // Start the state machine if this is the only device | |
79 if (state_ == State::OFF) { | |
80 state_ = State::IDLE; | |
81 delay_callback_.Cancel(); | |
82 Transition(); | |
83 } | |
84 } | |
85 | |
86 void U2fRequest::OnDeviceRemoved(scoped_refptr<HidDeviceInfo> device_info) { | |
87 // Ignore non-U2F devices | |
88 if (!filter_.Matches(device_info)) | |
89 return; | |
90 | |
91 auto device = base::MakeUnique<U2fHidDevice>(device_info); | |
92 | |
93 // Check if the active device was removed | |
94 if (current_device_ && current_device_->GetId() == device->GetId()) { | |
95 current_device_ = nullptr; | |
96 state_ = State::IDLE; | |
97 Transition(); | |
98 return; | |
99 } | |
100 | |
101 // Remove the device if it exists in the devices list | |
102 for (auto it = devices_.begin(); it != devices_.end();) { | |
103 if ((*it)->GetId() == device->GetId()) { | |
104 it = devices_.erase(it); | |
105 return; | |
106 } else { | |
107 ++it; | |
108 } | |
109 } | |
110 | |
111 // Remove the device if it exists in the attempted devices list | |
112 for (auto it = attempted_devices_.begin(); it != attempted_devices_.end();) { | |
113 if ((*it)->GetId() == device->GetId()) { | |
114 it = attempted_devices_.erase(it); | |
115 return; | |
116 } else { | |
117 ++it; | |
118 } | |
119 } | |
120 } | |
121 | |
122 void U2fRequest::IterateDevice() { | |
123 // Move active device to attempted device list | |
124 if (current_device_) | |
125 attempted_devices_.push_back(std::move(current_device_)); | |
126 | |
127 // If there is an additional device on device list, make it active. | |
128 // Otherwise, if all devices have been tried, move attempted devices back to | |
129 // the main device list. | |
130 if (devices_.size() > 0) { | |
131 current_device_ = std::move(devices_.front()); | |
132 devices_.pop_front(); | |
133 } else if (attempted_devices_.size() > 0) { | |
134 devices_ = std::move(attempted_devices_); | |
135 // After trying every device, wait 200ms before trying again | |
136 delay_callback_.Reset( | |
137 base::Bind(&U2fRequest::OnWaitComplete, weak_factory_.GetWeakPtr())); | |
138 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | |
139 FROM_HERE, delay_callback_.callback(), | |
140 base::TimeDelta::FromMilliseconds(200)); | |
141 } | |
142 } | |
143 | |
144 void U2fRequest::OnWaitComplete() { | |
145 state_ = State::IDLE; | |
146 Transition(); | |
147 } | |
148 | |
149 void U2fRequest::AddDeviceForTesting(std::unique_ptr<U2fDevice> device) { | |
150 devices_.push_back(std::move(device)); | |
151 | |
152 // Start the state machine if this is the only device | |
153 if (state_ == State::OFF) { | |
154 state_ = State::IDLE; | |
155 delay_callback_.Cancel(); | |
156 Transition(); | |
157 } | |
Reilly Grant (use Gerrit)
2017/04/21 20:10:01
I recommend pulling this out into an AddDevice() f
Casey Piper
2017/04/21 22:55:16
Done.
| |
158 } | |
159 | |
160 U2fRequest::~U2fRequest() {} | |
161 | |
162 } // namespace device | |
OLD | NEW |