blob: 7170324c560599f1aa8217d1f5c59c23557c3da6 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "device/fido/hid/fake_hid_impl_for_testing.h"
#include <utility>
#include "device/fido/fido_parsing_utils.h"
#include "services/device/public/mojom/constants.mojom.h"
#include "services/device/public/mojom/hid.mojom.h"
#include "services/service_manager/public/cpp/connector.h"
#include "services/service_manager/public/mojom/connector.mojom.h"
namespace device {
namespace {
MATCHER_P(IsCtapHidCommand, expected_command, "") {
return arg.size() >= 5 &&
arg[4] == (0x80 | static_cast<uint8_t>(expected_command));
}
} // namespace
MockHidConnection::MockHidConnection(
device::mojom::HidDeviceInfoPtr device,
device::mojom::HidConnectionRequest request,
std::vector<uint8_t> connection_channel_id)
: binding_(this, std::move(request)),
device_(std::move(device)),
connection_channel_id_(connection_channel_id) {}
MockHidConnection::~MockHidConnection() {}
void MockHidConnection::Read(ReadCallback callback) {
return ReadPtr(&callback);
}
void MockHidConnection::Write(uint8_t report_id,
const std::vector<uint8_t>& buffer,
WriteCallback callback) {
return WritePtr(report_id, buffer, &callback);
}
void MockHidConnection::GetFeatureReport(uint8_t report_id,
GetFeatureReportCallback callback) {
NOTREACHED();
}
void MockHidConnection::SendFeatureReport(uint8_t report_id,
const std::vector<uint8_t>& buffer,
SendFeatureReportCallback callback) {
NOTREACHED();
}
void MockHidConnection::SetNonce(base::span<uint8_t const> nonce) {
nonce_ = std::vector<uint8_t>(nonce.begin(), nonce.end());
}
void MockHidConnection::ExpectWriteHidInit() {
EXPECT_CALL(*this, WritePtr(::testing::_,
IsCtapHidCommand(FidoHidDeviceCommand::kInit),
::testing::_))
.WillOnce(::testing::Invoke(
[&](auto&&, const std::vector<uint8_t>& buffer,
device::mojom::HidConnection::WriteCallback* cb) {
ASSERT_EQ(64u, buffer.size());
// First 7 bytes are 4 bytes of channel id, one byte representing
// HID command, 2 bytes for payload length.
SetNonce(base::make_span(buffer).subspan(7, 8));
std::move(*cb).Run(true);
}));
}
void MockHidConnection::ExpectHidWriteWithCommand(FidoHidDeviceCommand cmd) {
EXPECT_CALL(*this,
WritePtr(::testing::_, IsCtapHidCommand(cmd), ::testing::_))
.WillOnce(::testing::Invoke(
[&](auto&&, const std::vector<uint8_t>& buffer,
device::mojom::HidConnection::WriteCallback* cb) {
std::move(*cb).Run(true);
}));
}
bool FakeHidConnection::mock_connection_error_ = false;
FakeHidConnection::FakeHidConnection(device::mojom::HidDeviceInfoPtr device)
: device_(std::move(device)) {}
FakeHidConnection::~FakeHidConnection() = default;
void FakeHidConnection::Read(ReadCallback callback) {
std::vector<uint8_t> buffer = {'F', 'a', 'k', 'e', ' ', 'H', 'i', 'd'};
std::move(callback).Run(true, 0, buffer);
}
void FakeHidConnection::Write(uint8_t report_id,
const std::vector<uint8_t>& buffer,
WriteCallback callback) {
if (mock_connection_error_) {
std::move(callback).Run(false);
return;
}
std::move(callback).Run(true);
}
void FakeHidConnection::GetFeatureReport(uint8_t report_id,
GetFeatureReportCallback callback) {
NOTREACHED();
}
void FakeHidConnection::SendFeatureReport(uint8_t report_id,
const std::vector<uint8_t>& buffer,
SendFeatureReportCallback callback) {
NOTREACHED();
}
FakeHidManager::FakeHidManager() = default;
FakeHidManager::~FakeHidManager() = default;
void FakeHidManager::AddBinding(mojo::ScopedMessagePipeHandle handle) {
bindings_.AddBinding(this,
device::mojom::HidManagerRequest(std::move(handle)));
}
void FakeHidManager::AddBinding2(device::mojom::HidManagerRequest request) {
bindings_.AddBinding(this, std::move(request));
}
void FakeHidManager::AddFidoHidDevice(std::string guid) {
auto c_info = device::mojom::HidCollectionInfo::New();
c_info->usage = device::mojom::HidUsageAndPage::New(1, 0xf1d0);
auto device = device::mojom::HidDeviceInfo::New();
device->guid = std::move(guid);
device->product_name = "Test Fido Device";
device->serial_number = "123FIDO";
device->bus_type = device::mojom::HidBusType::kHIDBusTypeUSB;
device->collections.push_back(std::move(c_info));
device->max_input_report_size = 64;
device->max_output_report_size = 64;
AddDevice(std::move(device));
}
void FakeHidManager::GetDevicesAndSetClient(
device::mojom::HidManagerClientAssociatedPtrInfo client,
GetDevicesCallback callback) {
GetDevices(std::move(callback));
device::mojom::HidManagerClientAssociatedPtr client_ptr;
client_ptr.Bind(std::move(client));
clients_.AddPtr(std::move(client_ptr));
}
void FakeHidManager::GetDevices(GetDevicesCallback callback) {
std::vector<device::mojom::HidDeviceInfoPtr> device_list;
for (auto& map_entry : devices_)
device_list.push_back(map_entry.second->Clone());
std::move(callback).Run(std::move(device_list));
}
void FakeHidManager::Connect(const std::string& device_guid,
ConnectCallback callback) {
auto device_it = devices_.find(device_guid);
auto connection_it = connections_.find(device_guid);
if (device_it == devices_.end() || connection_it == connections_.end()) {
std::move(callback).Run(nullptr);
return;
}
std::move(callback).Run(std::move(connection_it->second));
}
void FakeHidManager::AddDevice(device::mojom::HidDeviceInfoPtr device) {
device::mojom::HidDeviceInfo* device_info = device.get();
clients_.ForAllPtrs([device_info](device::mojom::HidManagerClient* client) {
client->DeviceAdded(device_info->Clone());
});
devices_[device->guid] = std::move(device);
}
void FakeHidManager::AddDeviceAndSetConnection(
device::mojom::HidDeviceInfoPtr device,
device::mojom::HidConnectionPtr connection) {
connections_[device->guid] = std::move(connection);
AddDevice(std::move(device));
}
void FakeHidManager::RemoveDevice(const std::string device_guid) {
auto it = devices_.find(device_guid);
if (it == devices_.end())
return;
device::mojom::HidDeviceInfo* device_info = it->second.get();
clients_.ForAllPtrs([device_info](device::mojom::HidManagerClient* client) {
client->DeviceRemoved(device_info->Clone());
});
devices_.erase(it);
}
ScopedFakeHidManager::ScopedFakeHidManager() {
service_manager::mojom::ConnectorRequest request;
connector_ = service_manager::Connector::Create(&request);
connector_->OverrideBinderForTesting(
service_manager::ServiceFilter::ByName(device::mojom::kServiceName),
device::mojom::HidManager::Name_,
base::BindRepeating(&FakeHidManager::AddBinding, base::Unretained(this)));
}
ScopedFakeHidManager::~ScopedFakeHidManager() = default;
} // namespace device