blob: e7ff22f4c3601eaac2e6bde98880930107aae41d [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/smart_card/fake_smart_card_device_service.h"
#include "base/containers/map_util.h"
namespace {
using device::mojom::SmartCardConnectResult;
using device::mojom::SmartCardContext;
using device::mojom::SmartCardCreateContextResult;
using device::mojom::SmartCardCreateContextResultPtr;
using device::mojom::SmartCardError;
using device::mojom::SmartCardListReadersResult;
using device::mojom::SmartCardReaderStateFlags;
using device::mojom::SmartCardReaderStateIn;
using device::mojom::SmartCardReaderStateInPtr;
using device::mojom::SmartCardReaderStateOut;
using device::mojom::SmartCardReaderStateOutPtr;
using device::mojom::SmartCardResult;
using device::mojom::SmartCardStatusChangeResult;
using device::mojom::SmartCardSuccess;
constexpr char kFooReader[] = "Foo Reader";
constexpr char kAcmeReader[] = "Acme Reader";
bool StateHasChanged(const SmartCardReaderStateOut& state_out,
const SmartCardReaderStateIn& state_in) {
// Try the easy cases first:
if (state_in.current_state->unaware) {
return true;
}
if (state_in.current_count != state_out.event_count) {
return true;
}
// And only then go for a full diff:
const SmartCardReaderStateFlags& flags_in = *state_in.current_state;
const SmartCardReaderStateFlags& flags_out = *state_out.event_state;
// clang-format off
return flags_in.unknown != flags_out.unknown ||
flags_in.unavailable != flags_out.unavailable ||
flags_in.empty != flags_out.empty ||
flags_in.present != flags_out.present ||
flags_in.exclusive != flags_out.exclusive ||
flags_in.inuse != flags_out.inuse ||
flags_in.mute != flags_out.mute ||
flags_in.unpowered != flags_out.unpowered;
// clang-format on
}
} // anonymous namespace
struct FakeSmartCardDeviceService::ReaderState {
bool unknown;
bool unavailable;
bool empty;
bool present;
bool exclusive;
bool inuse;
bool mute;
bool unpowered;
uint16_t event_count;
};
struct FakeSmartCardDeviceService::PendingStatusChange {
PendingStatusChange(std::vector<SmartCardReaderStateInPtr> reader_states,
SmartCardContext::GetStatusChangeCallback callback)
: reader_states(std::move(reader_states)),
callback(std::move(callback)) {}
~PendingStatusChange() = default;
std::vector<SmartCardReaderStateInPtr> reader_states;
SmartCardContext::GetStatusChangeCallback callback;
};
FakeSmartCardDeviceService::FakeSmartCardDeviceService() {
readers_[kFooReader] = {.empty = true};
readers_[kAcmeReader] = {.present = true};
}
FakeSmartCardDeviceService::~FakeSmartCardDeviceService() = default;
mojo::PendingRemote<device::mojom::SmartCardContextFactory>
FakeSmartCardDeviceService::GetSmartCardContextFactory() {
mojo::PendingRemote<device::mojom::SmartCardContextFactory> pending_remote;
context_factory_receivers_.Add(
this, pending_remote.InitWithNewPipeAndPassReceiver());
return pending_remote;
}
void FakeSmartCardDeviceService::CreateContext(CreateContextCallback callback) {
mojo::PendingRemote<SmartCardContext> context_remote;
context_receivers_.Add(this, context_remote.InitWithNewPipeAndPassReceiver());
std::move(callback).Run(
SmartCardCreateContextResult::NewContext(std::move(context_remote)));
}
void FakeSmartCardDeviceService::ListReaders(ListReadersCallback callback) {
std::vector<std::string> names;
for (const auto& [name, state] : readers_) {
names.push_back(name);
}
std::move(callback).Run(SmartCardListReadersResult::NewReaders(names));
}
void FakeSmartCardDeviceService::GetStatusChange(
base::TimeDelta timeout,
std::vector<device::mojom::SmartCardReaderStateInPtr> reader_states,
GetStatusChangeCallback callback) {
pending_status_changes_.push_back(std::make_unique<PendingStatusChange>(
std::move(reader_states), std::move(callback)));
TryResolvePendingStatusChanges();
}
void FakeSmartCardDeviceService::Cancel(CancelCallback callback) {
auto pending_list = std::move(pending_status_changes_);
for (auto& pending_change : pending_list) {
std::move(pending_change->callback)
.Run(SmartCardStatusChangeResult::NewError(SmartCardError::kCancelled));
}
std::move(callback).Run(SmartCardResult::NewSuccess(SmartCardSuccess::kOk));
}
void FakeSmartCardDeviceService::Connect(
const std::string& reader,
device::mojom::SmartCardShareMode share_mode,
device::mojom::SmartCardProtocolsPtr preferred_protocols,
mojo::PendingRemote<device::mojom::SmartCardConnectionWatcher>
connection_watcher,
ConnectCallback callback) {
std::move(callback).Run(
SmartCardConnectResult::NewError(SmartCardError::kUnresponsiveCard));
}
void FakeSmartCardDeviceService::TryResolvePendingStatusChanges() {
std::erase_if(pending_status_changes_,
[this](std::unique_ptr<PendingStatusChange>& p) {
return TryResolve(*p);
});
}
bool FakeSmartCardDeviceService::TryResolve(
PendingStatusChange& pending_status_change) {
std::vector<device::mojom::SmartCardReaderStateOutPtr> states_out;
bool state_changed = false;
for (const SmartCardReaderStateInPtr& state_in :
pending_status_change.reader_states) {
if (state_in->current_state->ignore) {
continue;
}
const ReaderState* reader_state =
base::FindOrNull(readers_, state_in->reader);
auto state_out = SmartCardReaderStateOut::New();
if (reader_state) {
FillStateOut(*state_out, *state_in, *reader_state);
state_changed = state_out->event_state->changed;
} else {
// Inform that this reader is unknown.
auto flags = SmartCardReaderStateFlags::New();
flags->unknown = true;
state_out->reader = state_in->reader;
state_out->event_state = std::move(flags);
state_changed = true;
}
states_out.push_back(std::move(state_out));
}
if (state_changed) {
// We only finish an outstanding GetStatusChange() request if the current
// state of the readers is different from any of requests input states.
std::move(pending_status_change.callback)
.Run(SmartCardStatusChangeResult::NewReaderStates(
std::move(states_out)));
return true;
}
return false;
}
// static
void FakeSmartCardDeviceService::FillStateOut(
SmartCardReaderStateOut& state_out,
const SmartCardReaderStateIn& state_in,
const ReaderState& reader_state) {
state_out.reader = state_in.reader;
state_out.event_state = SmartCardReaderStateFlags::New();
state_out.event_state->unknown = reader_state.unknown;
state_out.event_state->unavailable = reader_state.unavailable;
state_out.event_state->empty = reader_state.empty;
state_out.event_state->present = reader_state.present;
state_out.event_state->exclusive = reader_state.exclusive;
state_out.event_state->inuse = reader_state.inuse;
state_out.event_state->mute = reader_state.mute;
state_out.event_state->unpowered = reader_state.unpowered;
state_out.event_count = reader_state.event_count;
state_out.event_state->changed = StateHasChanged(state_out, state_in);
}