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 U2fRequest::~U2fRequest() {} |
| 150 |
| 151 } // namespace device |
OLD | NEW |