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 AddDevice(std::move(device)); | |
77 } | |
78 | |
79 void U2fRequest::OnDeviceRemoved(scoped_refptr<HidDeviceInfo> device_info) { | |
80 // Ignore non-U2F devices | |
81 if (!filter_.Matches(device_info)) | |
82 return; | |
83 | |
84 auto device = base::MakeUnique<U2fHidDevice>(device_info); | |
85 | |
86 // Check if the active device was removed | |
87 if (current_device_ && current_device_->GetId() == device->GetId()) { | |
88 current_device_ = nullptr; | |
89 state_ = State::IDLE; | |
90 Transition(); | |
91 return; | |
92 } | |
93 | |
94 // Remove the device if it exists in either device list | |
95 devices_.remove_if([&device](const std::unique_ptr<U2fDevice>& this_device) { | |
96 return this_device->GetId() == device->GetId(); | |
97 }); | |
98 attempted_devices_.remove_if( | |
99 [&device](const std::unique_ptr<U2fDevice>& this_device) { | |
100 return this_device->GetId() == device->GetId(); | |
101 }); | |
102 } | |
103 | |
104 void U2fRequest::IterateDevice() { | |
105 // Move active device to attempted device list | |
106 if (current_device_) | |
107 attempted_devices_.push_back(std::move(current_device_)); | |
108 | |
109 // If there is an additional device on device list, make it active. | |
110 // Otherwise, if all devices have been tried, move attempted devices back to | |
111 // the main device list. | |
112 if (devices_.size() > 0) { | |
113 current_device_ = std::move(devices_.front()); | |
114 devices_.pop_front(); | |
115 } else if (attempted_devices_.size() > 0) { | |
116 devices_ = std::move(attempted_devices_); | |
117 // After trying every device, wait 200ms before trying again | |
118 delay_callback_.Reset( | |
119 base::Bind(&U2fRequest::OnWaitComplete, weak_factory_.GetWeakPtr())); | |
120 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | |
121 FROM_HERE, delay_callback_.callback(), | |
122 base::TimeDelta::FromMilliseconds(200)); | |
123 } | |
124 } | |
125 | |
126 void U2fRequest::OnWaitComplete() { | |
127 state_ = State::IDLE; | |
128 Transition(); | |
129 } | |
130 | |
131 void U2fRequest::AddDevice(std::unique_ptr<U2fDevice> device) { | |
132 devices_.push_back(std::move(device)); | |
133 | |
134 // Start the state machine if this is the only device | |
135 if (state_ == State::OFF) { | |
136 state_ = State::IDLE; | |
137 delay_callback_.Cancel(); | |
138 Transition(); | |
139 } | |
140 } | |
141 | |
142 void U2fRequest::AddDeviceForTesting(std::unique_ptr<U2fDevice> device) { | |
143 AddDevice(std::move(device)); | |
144 } | |
145 | |
146 U2fRequest::~U2fRequest() {} | |
147 | |
148 } // namespace device | |
OLD | NEW |