fake_hid_impl_for_testing.cc 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  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. #include "device/fido/hid/fake_hid_impl_for_testing.h"
  5. #include <utility>
  6. #include "base/callback_helpers.h"
  7. #include "base/containers/contains.h"
  8. #include "device/fido/fido_parsing_utils.h"
  9. #include "device/fido/hid/fido_hid_discovery.h"
  10. #include "mojo/public/cpp/bindings/pending_associated_remote.h"
  11. #include "mojo/public/cpp/bindings/pending_receiver.h"
  12. #include "services/device/public/cpp/hid/hid_blocklist.h"
  13. #include "services/device/public/mojom/hid.mojom.h"
  14. namespace device {
  15. namespace {
  16. MATCHER_P(IsCtapHidCommand, expected_command, "") {
  17. return arg.size() >= 5 &&
  18. arg[4] == (0x80 | static_cast<uint8_t>(expected_command));
  19. }
  20. } // namespace
  21. MockFidoHidConnection::MockFidoHidConnection(
  22. device::mojom::HidDeviceInfoPtr device,
  23. mojo::PendingReceiver<device::mojom::HidConnection> receiver,
  24. std::array<uint8_t, 4> connection_channel_id)
  25. : receiver_(this, std::move(receiver)),
  26. device_(std::move(device)),
  27. connection_channel_id_(connection_channel_id) {}
  28. MockFidoHidConnection::~MockFidoHidConnection() {}
  29. void MockFidoHidConnection::Read(ReadCallback callback) {
  30. return ReadPtr(&callback);
  31. }
  32. void MockFidoHidConnection::Write(uint8_t report_id,
  33. const std::vector<uint8_t>& buffer,
  34. WriteCallback callback) {
  35. return WritePtr(report_id, buffer, &callback);
  36. }
  37. void MockFidoHidConnection::GetFeatureReport(
  38. uint8_t report_id,
  39. GetFeatureReportCallback callback) {
  40. NOTREACHED();
  41. }
  42. void MockFidoHidConnection::SendFeatureReport(
  43. uint8_t report_id,
  44. const std::vector<uint8_t>& buffer,
  45. SendFeatureReportCallback callback) {
  46. NOTREACHED();
  47. }
  48. void MockFidoHidConnection::SetNonce(base::span<uint8_t const> nonce) {
  49. nonce_ = std::vector<uint8_t>(nonce.begin(), nonce.end());
  50. }
  51. void MockFidoHidConnection::ExpectWriteHidInit() {
  52. ExpectWriteHidInit(testing::Sequence());
  53. }
  54. void MockFidoHidConnection::ExpectWriteHidInit(
  55. const testing::Sequence& sequence) {
  56. EXPECT_CALL(*this, WritePtr(::testing::_,
  57. IsCtapHidCommand(FidoHidDeviceCommand::kInit),
  58. ::testing::_))
  59. .InSequence(sequence)
  60. .WillOnce(::testing::Invoke(
  61. [&](auto&&, const std::vector<uint8_t>& buffer,
  62. device::mojom::HidConnection::WriteCallback* cb) {
  63. ASSERT_EQ(64u, buffer.size());
  64. // First 7 bytes are 4 bytes of channel id, one byte representing
  65. // HID command, 2 bytes for payload length.
  66. SetNonce(base::make_span(buffer).subspan(7, 8));
  67. std::move(*cb).Run(true);
  68. }));
  69. }
  70. void MockFidoHidConnection::ExpectHidWriteWithCommand(
  71. FidoHidDeviceCommand cmd) {
  72. ExpectHidWriteWithCommand(testing::Sequence(), cmd);
  73. }
  74. void MockFidoHidConnection::ExpectHidWriteWithCommand(
  75. const testing::Sequence& sequence,
  76. FidoHidDeviceCommand cmd) {
  77. EXPECT_CALL(*this,
  78. WritePtr(::testing::_, IsCtapHidCommand(cmd), ::testing::_))
  79. .InSequence(sequence)
  80. .WillOnce(::testing::Invoke(
  81. [&](auto&&, const std::vector<uint8_t>& buffer,
  82. device::mojom::HidConnection::WriteCallback* cb) {
  83. std::move(*cb).Run(true);
  84. }));
  85. }
  86. void MockFidoHidConnection::ExpectReadAndReplyWith(
  87. const testing::Sequence& sequence,
  88. std::vector<uint8_t> response) {
  89. EXPECT_CALL(*this, ReadPtr(testing::_))
  90. .InSequence(sequence)
  91. .WillOnce(::testing::Invoke(
  92. [response](device::mojom::HidConnection::ReadCallback* cb) {
  93. std::move(*cb).Run(true, 0, std::move(response));
  94. }));
  95. }
  96. bool FakeFidoHidConnection::mock_connection_error_ = false;
  97. FakeFidoHidConnection::FakeFidoHidConnection(
  98. device::mojom::HidDeviceInfoPtr device)
  99. : device_(std::move(device)) {}
  100. FakeFidoHidConnection::~FakeFidoHidConnection() = default;
  101. void FakeFidoHidConnection::Read(ReadCallback callback) {
  102. std::vector<uint8_t> buffer = {'F', 'a', 'k', 'e', ' ', 'H', 'i', 'd'};
  103. std::move(callback).Run(true, 0, buffer);
  104. }
  105. void FakeFidoHidConnection::Write(uint8_t report_id,
  106. const std::vector<uint8_t>& buffer,
  107. WriteCallback callback) {
  108. if (mock_connection_error_) {
  109. std::move(callback).Run(false);
  110. return;
  111. }
  112. std::move(callback).Run(true);
  113. }
  114. void FakeFidoHidConnection::GetFeatureReport(
  115. uint8_t report_id,
  116. GetFeatureReportCallback callback) {
  117. NOTREACHED();
  118. }
  119. void FakeFidoHidConnection::SendFeatureReport(
  120. uint8_t report_id,
  121. const std::vector<uint8_t>& buffer,
  122. SendFeatureReportCallback callback) {
  123. NOTREACHED();
  124. }
  125. FakeFidoHidManager::FakeFidoHidManager() = default;
  126. FakeFidoHidManager::~FakeFidoHidManager() = default;
  127. void FakeFidoHidManager::AddReceiver(
  128. mojo::PendingReceiver<device::mojom::HidManager> receiver) {
  129. receivers_.Add(this, std::move(receiver));
  130. }
  131. void FakeFidoHidManager::AddFidoHidDevice(std::string guid) {
  132. auto c_info = device::mojom::HidCollectionInfo::New();
  133. c_info->usage = device::mojom::HidUsageAndPage::New(1, 0xf1d0);
  134. c_info->input_reports.push_back(device::mojom::HidReportDescription::New());
  135. auto device = device::mojom::HidDeviceInfo::New();
  136. device->guid = std::move(guid);
  137. device->product_name = "Test Fido Device";
  138. device->serial_number = "123FIDO";
  139. device->bus_type = device::mojom::HidBusType::kHIDBusTypeUSB;
  140. device->collections.push_back(std::move(c_info));
  141. device->max_input_report_size = 64;
  142. device->max_output_report_size = 64;
  143. device->protected_input_report_ids =
  144. HidBlocklist::Get().GetProtectedReportIds(
  145. HidBlocklist::kReportTypeInput, device->vendor_id, device->product_id,
  146. device->collections);
  147. device->protected_output_report_ids =
  148. HidBlocklist::Get().GetProtectedReportIds(
  149. HidBlocklist::kReportTypeOutput, device->vendor_id,
  150. device->product_id, device->collections);
  151. device->protected_feature_report_ids =
  152. HidBlocklist::Get().GetProtectedReportIds(
  153. HidBlocklist::kReportTypeFeature, device->vendor_id,
  154. device->product_id, device->collections);
  155. device->is_excluded_by_blocklist = HidBlocklist::Get().IsVendorProductBlocked(
  156. device->vendor_id, device->product_id);
  157. AddDevice(std::move(device));
  158. }
  159. void FakeFidoHidManager::GetDevicesAndSetClient(
  160. mojo::PendingAssociatedRemote<device::mojom::HidManagerClient> client,
  161. GetDevicesCallback callback) {
  162. GetDevices(std::move(callback));
  163. clients_.Add(std::move(client));
  164. }
  165. void FakeFidoHidManager::GetDevices(GetDevicesCallback callback) {
  166. std::vector<device::mojom::HidDeviceInfoPtr> device_list;
  167. for (auto& map_entry : devices_)
  168. device_list.push_back(map_entry.second->Clone());
  169. std::move(callback).Run(std::move(device_list));
  170. }
  171. void FakeFidoHidManager::Connect(
  172. const std::string& device_guid,
  173. mojo::PendingRemote<mojom::HidConnectionClient> connection_client,
  174. mojo::PendingRemote<mojom::HidConnectionWatcher> watcher,
  175. bool allow_protected_reports,
  176. bool allow_fido_reports,
  177. ConnectCallback callback) {
  178. auto device_it = devices_.find(device_guid);
  179. auto connection_it = connections_.find(device_guid);
  180. if (device_it == devices_.end() || connection_it == connections_.end()) {
  181. std::move(callback).Run(mojo::NullRemote());
  182. return;
  183. }
  184. std::move(callback).Run(std::move(connection_it->second));
  185. }
  186. void FakeFidoHidManager::AddDevice(device::mojom::HidDeviceInfoPtr device) {
  187. DCHECK(!base::Contains(devices_, device->guid));
  188. device::mojom::HidDeviceInfo* device_info = device.get();
  189. for (auto& client : clients_)
  190. client->DeviceAdded(device_info->Clone());
  191. devices_[device->guid] = std::move(device);
  192. }
  193. void FakeFidoHidManager::AddDeviceAndSetConnection(
  194. device::mojom::HidDeviceInfoPtr device,
  195. mojo::PendingRemote<device::mojom::HidConnection> connection) {
  196. connections_[device->guid] = std::move(connection);
  197. AddDevice(std::move(device));
  198. }
  199. void FakeFidoHidManager::RemoveDevice(const std::string device_guid) {
  200. auto it = devices_.find(device_guid);
  201. if (it == devices_.end())
  202. return;
  203. device::mojom::HidDeviceInfo* device_info = it->second.get();
  204. for (auto& client : clients_)
  205. client->DeviceRemoved(device_info->Clone());
  206. devices_.erase(it);
  207. }
  208. void FakeFidoHidManager::ChangeDevice(device::mojom::HidDeviceInfoPtr device) {
  209. DCHECK(base::Contains(devices_, device->guid));
  210. device::mojom::HidDeviceInfo* device_info = device.get();
  211. for (auto& client : clients_)
  212. client->DeviceChanged(device_info->Clone());
  213. devices_[device->guid] = std::move(device);
  214. }
  215. ScopedFakeFidoHidManager::ScopedFakeFidoHidManager() {
  216. FidoHidDiscovery::SetHidManagerBinder(base::BindRepeating(
  217. &FakeFidoHidManager::AddReceiver, base::Unretained(this)));
  218. }
  219. ScopedFakeFidoHidManager::~ScopedFakeFidoHidManager() {
  220. FidoHidDiscovery::SetHidManagerBinder(base::NullCallback());
  221. }
  222. } // namespace device