blob: 94629af965786f0fab93bbc454d36f2a6db9de12 [file] [log] [blame]
// Copyright 2026 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_DEVTOOLS_PROTOCOL_SMART_CARD_EMULATION_HANDLER_H_
#define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_SMART_CARD_EMULATION_HANDLER_H_
#include <memory>
#include "base/types/expected.h"
#include "content/browser/devtools/devtools_agent_host_impl.h"
#include "content/browser/devtools/protocol/devtools_domain_handler.h"
#include "content/browser/devtools/protocol/smart_card_emulation.h"
#include "content/browser/smart_card/emulation/emulated_smart_card_context_factory.h"
#include "content/browser/smart_card/emulation/smart_card_emulation_manager.h"
#include "content/common/content_export.h"
#include "content/public/browser/web_contents_observer.h"
#include "services/device/public/mojom/smart_card.mojom.h"
namespace content {
class RenderFrameHostImpl;
class WebContents;
namespace protocol {
// This class acts as the "Browser Side" implementation of PC/SC for DevTools.
// It intercepts Mojo calls from the Renderer and translates them into
// DevTools Protocol events.
class CONTENT_EXPORT SmartCardEmulationHandler
: public DevToolsDomainHandler,
public SmartCardEmulation::Backend,
public content::WebContentsObserver,
public SmartCardEmulationManager {
public:
// Requires WebContents to observe navigations.
explicit SmartCardEmulationHandler(content::WebContents* web_contents);
~SmartCardEmulationHandler() override;
// SmartCardEmulation::Backend implementation.
DispatchResponse Enable() override;
DispatchResponse Disable() override;
template <typename CallbackType, typename ResultType>
class PendingRequestImpl {
public:
explicit PendingRequestImpl(CallbackType cb) : callback_(std::move(cb)) {}
PendingRequestImpl(PendingRequestImpl&&) = default;
PendingRequestImpl& operator=(PendingRequestImpl&&) = default;
virtual ~PendingRequestImpl() = default;
void ReportError(device::mojom::SmartCardError error) {
std::move(callback_).Run(ResultType::NewError(error));
}
CallbackType& callback() { return callback_; }
private:
CallbackType callback_;
};
using PendingCreateContext = PendingRequestImpl<
device::mojom::SmartCardContextFactory::CreateContextCallback,
device::mojom::SmartCardCreateContextResult>;
using PendingListReaders =
PendingRequestImpl<device::mojom::SmartCardContext::ListReadersCallback,
device::mojom::SmartCardListReadersResult>;
using PendingGetStatusChange = PendingRequestImpl<
device::mojom::SmartCardContext::GetStatusChangeCallback,
device::mojom::SmartCardStatusChangeResult>;
class PendingConnect : public PendingRequestImpl<
device::mojom::SmartCardContext::ConnectCallback,
device::mojom::SmartCardConnectResult> {
public:
PendingConnect(
device::mojom::SmartCardContext::ConnectCallback callback,
mojo::PendingRemote<device::mojom::SmartCardConnectionWatcher> watcher);
~PendingConnect() override;
PendingConnect(PendingConnect&&);
mojo::PendingRemote<device::mojom::SmartCardConnectionWatcher>
TakeWatcher() {
return std::move(watcher_);
}
private:
mojo::PendingRemote<device::mojom::SmartCardConnectionWatcher> watcher_;
};
// Handles Cancel, Disconnect, SetAttrib, EndTransaction.
using PendingPlainResult = PendingRequestImpl<
base::OnceCallback<void(device::mojom::SmartCardResultPtr)>,
device::mojom::SmartCardResult>;
// Handles Transmit, Control, GetAttrib.
using PendingDataResult = PendingRequestImpl<
base::OnceCallback<void(device::mojom::SmartCardDataResultPtr)>,
device::mojom::SmartCardDataResult>;
using PendingStatus =
PendingRequestImpl<device::mojom::SmartCardConnection::StatusCallback,
device::mojom::SmartCardStatusResult>;
using PendingBeginTransaction = PendingRequestImpl<
device::mojom::SmartCardConnection::BeginTransactionCallback,
device::mojom::SmartCardTransactionResult>;
struct PendingReleaseContext {
void ReportError(device::mojom::SmartCardError error) {}
};
using PendingRequest = std::variant<PendingCreateContext,
PendingListReaders,
PendingGetStatusChange,
PendingConnect,
PendingPlainResult,
PendingDataResult,
PendingStatus,
PendingBeginTransaction,
PendingReleaseContext>;
private:
static std::vector<SmartCardEmulationHandler*> ForAgentHost(
DevToolsAgentHostImpl* host);
// DevToolsDomainHandler implementation.
void Wire(UberDispatcher* dispatcher) override;
void SetRenderer(int process_host_id,
RenderFrameHostImpl* frame_host) override;
// WebContentsObserver implementation.
void ReadyToCommitNavigation(content::NavigationHandle* handle) override;
// Registers the emulated Smart Card factory with the system delegate for
// the given frame.
void UpdateEmulationOverride(content::RenderFrameHost* rfh);
DispatchResponse ReportEstablishContextResult(
const String& in_requestId,
const int in_contextId) override;
DispatchResponse ReportListReadersResult(
const String& in_requestId,
std::unique_ptr<protocol::Array<String>> in_readers) override;
DispatchResponse ReportConnectResult(
const String& in_requestId,
const int in_handle,
std::optional<String> in_activeProtocol) override;
DispatchResponse ReportGetStatusChangeResult(
const String& in_requestId,
std::unique_ptr<
protocol::Array<protocol::SmartCardEmulation::ReaderStateOut>>
in_readerStates) override;
DispatchResponse ReportBeginTransactionResult(const String& in_requestId,
const int in_handle) override;
DispatchResponse ReportDataResult(const String& in_requestId,
const Binary& in_data) override;
DispatchResponse ReportPlainResult(const String& in_requestId) override;
DispatchResponse ReportStatusResult(
const String& in_requestId,
const String& in_readerName,
const String& in_state,
const Binary& in_atr,
std::optional<String> in_protocol) override;
DispatchResponse ReportReleaseContextResult(
const String& in_requestId) override;
DispatchResponse ReportError(const String& in_requestId,
const String& in_resultCode) override;
void OnCreateContext(
device::mojom::SmartCardContextFactory::CreateContextCallback callback)
override;
void OnListReaders(
uint32_t context_id,
device::mojom::SmartCardContext::ListReadersCallback callback) override;
void OnGetStatusChange(
uint32_t context_id,
base::TimeDelta timeout,
std::vector<device::mojom::SmartCardReaderStateInPtr> reader_states,
device::mojom::SmartCardContext::GetStatusChangeCallback callback)
override;
void OnCancel(
uint32_t context_id,
device::mojom::SmartCardContext::CancelCallback callback) override;
void OnConnect(
uint32_t context_id,
const std::string& reader,
device::mojom::SmartCardShareMode share_mode,
device::mojom::SmartCardProtocolsPtr preferred_protocols,
mojo::PendingRemote<device::mojom::SmartCardConnectionWatcher> watcher,
device::mojom::SmartCardContext::ConnectCallback callback) override;
void OnDisconnect(
uint32_t handle,
device::mojom::SmartCardDisposition disposition,
device::mojom::SmartCardConnection::DisconnectCallback callback) override;
void OnControl(
uint32_t handle,
uint32_t control_code,
const std::vector<uint8_t>& data,
device::mojom::SmartCardConnection::ControlCallback callback) override;
void OnGetAttrib(
uint32_t handle,
uint32_t id,
device::mojom::SmartCardConnection::GetAttribCallback callback) override;
void OnTransmit(
uint32_t handle,
device::mojom::SmartCardProtocol protocol,
const std::vector<uint8_t>& data,
device::mojom::SmartCardConnection::TransmitCallback callback) override;
void OnStatus(
uint32_t handle,
device::mojom::SmartCardConnection::StatusCallback callback) override;
void OnSetAttrib(
uint32_t handle,
uint32_t id,
const std::vector<uint8_t>& data,
device::mojom::SmartCardConnection::SetAttribCallback callback) override;
void OnBeginTransaction(
uint32_t handle,
device::mojom::SmartCardConnection::BeginTransactionCallback callback)
override;
void OnEndTransaction(
uint32_t handle,
device::mojom::SmartCardDisposition disposition,
device::mojom::SmartCardTransaction::EndTransactionCallback callback)
override;
void OnReleaseContext(uint32_t context_id) override;
void AddPendingRequest(const std::string& request_id, PendingRequest request);
template <typename T>
base::expected<T, std::string> TakePendingRequest(
const std::string& request_id);
// The Handler needs to store Mojo callbacks for "paused" requests so they can
// be resumed later when the DevTools frontend replies.
std::unordered_map<std::string, PendingRequest> pending_requests_;
bool IsEnabled() const { return !!factory_; }
base::expected<void, std::string> CompleteEstablishContext(
const std::string& request_id,
const uint32_t context_id);
base::expected<void, std::string> CompleteListReaders(
const std::string& request_id,
std::vector<std::string> readers);
base::expected<void, std::string> CompleteConnect(
const std::string& request_id,
const uint32_t handle,
device::mojom::SmartCardProtocol active_protocol);
base::expected<void, std::string> CompleteGetStatusChange(
const std::string& in_requestId,
std::vector<device::mojom::SmartCardReaderStateOutPtr> reader_states);
base::expected<void, std::string> CompleteStatus(
const std::string& request_id,
device::mojom::SmartCardStatusPtr status_data);
base::expected<void, std::string> CompleteDataResult(
const std::string& request_id,
std::vector<uint8_t> response);
base::expected<void, std::string> CompleteBeginTransaction(
const std::string& request_id,
uint32_t handle);
base::expected<void, std::string> CompletePlainResult(
const std::string& request_id);
base::expected<void, std::string> CompleteReleaseContext(
const std::string& request_id);
base::expected<void, std::string> FailRequest(
const std::string& request_id,
device::mojom::SmartCardError error);
// The frontend interface to send events to the DevTools client.
std::unique_ptr<SmartCardEmulation::Frontend> frontend_;
// The Factory that handles the actual Mojo emulation logic.
std::unique_ptr<EmulatedSmartCardContextFactory> factory_;
base::WeakPtrFactory<SmartCardEmulationHandler> weak_ptr_factory_{this};
};
} // namespace protocol
} // namespace content
#endif // CONTENT_BROWSER_DEVTOOLS_PROTOCOL_SMART_CARD_EMULATION_HANDLER_H_