// This file is generated by TypeBuilder_cpp.template.

// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/browser/devtools/protocol/web_authn.h"

#include "content/browser/devtools/protocol/protocol.h"

#include "third_party/inspector_protocol/crdtp/cbor.h"
#include "third_party/inspector_protocol/crdtp/find_by_first.h"
#include "third_party/inspector_protocol/crdtp/span.h"

namespace content {
namespace protocol {
namespace WebAuthn {

using crdtp::DeserializerState;
using crdtp::FallthroughCallback;
using crdtp::ProtocolTypeTraits;

// ------------- Enum values from types.

const char Metainfo::domainName[] = "WebAuthn";
const char Metainfo::commandPrefix[] = "WebAuthn.";
const char Metainfo::version[] = "1.3";





CRDTP_BEGIN_DESERIALIZER(VirtualAuthenticatorOptions)
    CRDTP_DESERIALIZE_FIELD_OPT("automaticPresenceSimulation", m_automaticPresenceSimulation),
    CRDTP_DESERIALIZE_FIELD_OPT("ctap2Version", m_ctap2Version),
    CRDTP_DESERIALIZE_FIELD_OPT("defaultBackupEligibility", m_defaultBackupEligibility),
    CRDTP_DESERIALIZE_FIELD_OPT("defaultBackupState", m_defaultBackupState),
    CRDTP_DESERIALIZE_FIELD_OPT("hasCmtgKey", m_hasCmtgKey),
    CRDTP_DESERIALIZE_FIELD_OPT("hasCredBlob", m_hasCredBlob),
    CRDTP_DESERIALIZE_FIELD_OPT("hasHmacSecret", m_hasHmacSecret),
    CRDTP_DESERIALIZE_FIELD_OPT("hasHmacSecretMc", m_hasHmacSecretMc),
    CRDTP_DESERIALIZE_FIELD_OPT("hasLargeBlob", m_hasLargeBlob),
    CRDTP_DESERIALIZE_FIELD_OPT("hasMinPinLength", m_hasMinPinLength),
    CRDTP_DESERIALIZE_FIELD_OPT("hasPrf", m_hasPrf),
    CRDTP_DESERIALIZE_FIELD_OPT("hasResidentKey", m_hasResidentKey),
    CRDTP_DESERIALIZE_FIELD_OPT("hasUserVerification", m_hasUserVerification),
    CRDTP_DESERIALIZE_FIELD_OPT("isUserVerified", m_isUserVerified),
    CRDTP_DESERIALIZE_FIELD("protocol", m_protocol),
    CRDTP_DESERIALIZE_FIELD("transport", m_transport),
CRDTP_END_DESERIALIZER()

CRDTP_BEGIN_SERIALIZER(VirtualAuthenticatorOptions)
    CRDTP_SERIALIZE_FIELD("protocol", m_protocol);
    CRDTP_SERIALIZE_FIELD("ctap2Version", m_ctap2Version);
    CRDTP_SERIALIZE_FIELD("transport", m_transport);
    CRDTP_SERIALIZE_FIELD("hasResidentKey", m_hasResidentKey);
    CRDTP_SERIALIZE_FIELD("hasUserVerification", m_hasUserVerification);
    CRDTP_SERIALIZE_FIELD("hasLargeBlob", m_hasLargeBlob);
    CRDTP_SERIALIZE_FIELD("hasCredBlob", m_hasCredBlob);
    CRDTP_SERIALIZE_FIELD("hasMinPinLength", m_hasMinPinLength);
    CRDTP_SERIALIZE_FIELD("hasPrf", m_hasPrf);
    CRDTP_SERIALIZE_FIELD("hasHmacSecret", m_hasHmacSecret);
    CRDTP_SERIALIZE_FIELD("hasHmacSecretMc", m_hasHmacSecretMc);
    CRDTP_SERIALIZE_FIELD("hasCmtgKey", m_hasCmtgKey);
    CRDTP_SERIALIZE_FIELD("automaticPresenceSimulation", m_automaticPresenceSimulation);
    CRDTP_SERIALIZE_FIELD("isUserVerified", m_isUserVerified);
    CRDTP_SERIALIZE_FIELD("defaultBackupEligibility", m_defaultBackupEligibility);
    CRDTP_SERIALIZE_FIELD("defaultBackupState", m_defaultBackupState);
CRDTP_END_SERIALIZER();


CRDTP_BEGIN_DESERIALIZER(Credential)
    CRDTP_DESERIALIZE_FIELD_OPT("activeCmtgKeyIndex", m_activeCmtgKeyIndex),
    CRDTP_DESERIALIZE_FIELD_OPT("backupEligibility", m_backupEligibility),
    CRDTP_DESERIALIZE_FIELD_OPT("backupState", m_backupState),
    CRDTP_DESERIALIZE_FIELD_OPT("cmtgKeys", m_cmtgKeys),
    CRDTP_DESERIALIZE_FIELD("credentialId", m_credentialId),
    CRDTP_DESERIALIZE_FIELD_OPT("generateCmtgKeyOnNextOperation", m_generateCmtgKeyOnNextOperation),
    CRDTP_DESERIALIZE_FIELD("isResidentCredential", m_isResidentCredential),
    CRDTP_DESERIALIZE_FIELD_OPT("largeBlob", m_largeBlob),
    CRDTP_DESERIALIZE_FIELD("privateKey", m_privateKey),
    CRDTP_DESERIALIZE_FIELD_OPT("rpId", m_rpId),
    CRDTP_DESERIALIZE_FIELD("signCount", m_signCount),
    CRDTP_DESERIALIZE_FIELD_OPT("userDisplayName", m_userDisplayName),
    CRDTP_DESERIALIZE_FIELD_OPT("userHandle", m_userHandle),
    CRDTP_DESERIALIZE_FIELD_OPT("userName", m_userName),
CRDTP_END_DESERIALIZER()

CRDTP_BEGIN_SERIALIZER(Credential)
    CRDTP_SERIALIZE_FIELD("credentialId", m_credentialId);
    CRDTP_SERIALIZE_FIELD("isResidentCredential", m_isResidentCredential);
    CRDTP_SERIALIZE_FIELD("rpId", m_rpId);
    CRDTP_SERIALIZE_FIELD("privateKey", m_privateKey);
    CRDTP_SERIALIZE_FIELD("userHandle", m_userHandle);
    CRDTP_SERIALIZE_FIELD("signCount", m_signCount);
    CRDTP_SERIALIZE_FIELD("largeBlob", m_largeBlob);
    CRDTP_SERIALIZE_FIELD("backupEligibility", m_backupEligibility);
    CRDTP_SERIALIZE_FIELD("backupState", m_backupState);
    CRDTP_SERIALIZE_FIELD("userName", m_userName);
    CRDTP_SERIALIZE_FIELD("userDisplayName", m_userDisplayName);
    CRDTP_SERIALIZE_FIELD("cmtgKeys", m_cmtgKeys);
    CRDTP_SERIALIZE_FIELD("activeCmtgKeyIndex", m_activeCmtgKeyIndex);
    CRDTP_SERIALIZE_FIELD("generateCmtgKeyOnNextOperation", m_generateCmtgKeyOnNextOperation);
CRDTP_END_SERIALIZER();


// ------------- Enum values from params.


// ------------- Frontend notifications.

void Frontend::CredentialAdded(const String& authenticatorId, std::unique_ptr<protocol::WebAuthn::Credential> credential)
{
    if (!frontend_channel_)
        return;
    crdtp::ObjectSerializer serializer;
    serializer.AddField(crdtp::MakeSpan("authenticatorId"), authenticatorId);
    serializer.AddField(crdtp::MakeSpan("credential"), credential);
    frontend_channel_->SendProtocolNotification(crdtp::CreateNotification("WebAuthn.credentialAdded", serializer.Finish()));
}

void Frontend::CredentialDeleted(const String& authenticatorId, const Binary& credentialId)
{
    if (!frontend_channel_)
        return;
    crdtp::ObjectSerializer serializer;
    serializer.AddField(crdtp::MakeSpan("authenticatorId"), authenticatorId);
    serializer.AddField(crdtp::MakeSpan("credentialId"), credentialId);
    frontend_channel_->SendProtocolNotification(crdtp::CreateNotification("WebAuthn.credentialDeleted", serializer.Finish()));
}

void Frontend::CredentialUpdated(const String& authenticatorId, std::unique_ptr<protocol::WebAuthn::Credential> credential)
{
    if (!frontend_channel_)
        return;
    crdtp::ObjectSerializer serializer;
    serializer.AddField(crdtp::MakeSpan("authenticatorId"), authenticatorId);
    serializer.AddField(crdtp::MakeSpan("credential"), credential);
    frontend_channel_->SendProtocolNotification(crdtp::CreateNotification("WebAuthn.credentialUpdated", serializer.Finish()));
}

void Frontend::CredentialAsserted(const String& authenticatorId, std::unique_ptr<protocol::WebAuthn::Credential> credential)
{
    if (!frontend_channel_)
        return;
    crdtp::ObjectSerializer serializer;
    serializer.AddField(crdtp::MakeSpan("authenticatorId"), authenticatorId);
    serializer.AddField(crdtp::MakeSpan("credential"), credential);
    frontend_channel_->SendProtocolNotification(crdtp::CreateNotification("WebAuthn.credentialAsserted", serializer.Finish()));
}

void Frontend::flush()
{
    frontend_channel_->FlushProtocolNotifications();
}

void Frontend::sendRawNotification(std::unique_ptr<Serializable> notification)
{
    frontend_channel_->SendProtocolNotification(std::move(notification));
}

// --------------------- Dispatcher.

class DomainDispatcherImpl : public protocol::DomainDispatcher {
public:
    DomainDispatcherImpl(FrontendChannel* frontendChannel, Backend* backend)
        : DomainDispatcher(frontendChannel)
        , m_backend(backend) {}
    ~DomainDispatcherImpl() override { }

    using CallHandler = void (DomainDispatcherImpl::*)(crdtp::Dispatchable& dispatchable);

    bool Dispatch(crdtp::span<uint8_t> command_name, crdtp::Dispatchable& dispatchable) override;

    void enable(crdtp::Dispatchable& dispatchable);
    void disable(crdtp::Dispatchable& dispatchable);
    void addVirtualAuthenticator(crdtp::Dispatchable& dispatchable);
    void setResponseOverrideBits(crdtp::Dispatchable& dispatchable);
    void removeVirtualAuthenticator(crdtp::Dispatchable& dispatchable);
    void addCredential(crdtp::Dispatchable& dispatchable);
    void getCredential(crdtp::Dispatchable& dispatchable);
    void getCredentials(crdtp::Dispatchable& dispatchable);
    void removeCredential(crdtp::Dispatchable& dispatchable);
    void clearCredentials(crdtp::Dispatchable& dispatchable);
    void setUserVerified(crdtp::Dispatchable& dispatchable);
    void setAutomaticPresenceSimulation(crdtp::Dispatchable& dispatchable);
    void setCredentialProperties(crdtp::Dispatchable& dispatchable);
 protected:
    Backend* m_backend;
};

namespace {
// This helper method with a static map of command methods (instance methods
// of DomainDispatcherImpl declared just above) by their name is used immediately below,
// in the DomainDispatcherImpl::Dispatch method.
DomainDispatcherImpl::CallHandler CommandByName(crdtp::span<uint8_t> command_name) {
  static auto* commands = [](){
    auto* commands = new std::vector<std::pair<crdtp::span<uint8_t>,
                              DomainDispatcherImpl::CallHandler>>{
    {
          crdtp::SpanFrom("addCredential"),
          &DomainDispatcherImpl::addCredential
    },
    {
          crdtp::SpanFrom("addVirtualAuthenticator"),
          &DomainDispatcherImpl::addVirtualAuthenticator
    },
    {
          crdtp::SpanFrom("clearCredentials"),
          &DomainDispatcherImpl::clearCredentials
    },
    {
          crdtp::SpanFrom("disable"),
          &DomainDispatcherImpl::disable
    },
    {
          crdtp::SpanFrom("enable"),
          &DomainDispatcherImpl::enable
    },
    {
          crdtp::SpanFrom("getCredential"),
          &DomainDispatcherImpl::getCredential
    },
    {
          crdtp::SpanFrom("getCredentials"),
          &DomainDispatcherImpl::getCredentials
    },
    {
          crdtp::SpanFrom("removeCredential"),
          &DomainDispatcherImpl::removeCredential
    },
    {
          crdtp::SpanFrom("removeVirtualAuthenticator"),
          &DomainDispatcherImpl::removeVirtualAuthenticator
    },
    {
          crdtp::SpanFrom("setAutomaticPresenceSimulation"),
          &DomainDispatcherImpl::setAutomaticPresenceSimulation
    },
    {
          crdtp::SpanFrom("setCredentialProperties"),
          &DomainDispatcherImpl::setCredentialProperties
    },
    {
          crdtp::SpanFrom("setResponseOverrideBits"),
          &DomainDispatcherImpl::setResponseOverrideBits
    },
    {
          crdtp::SpanFrom("setUserVerified"),
          &DomainDispatcherImpl::setUserVerified
    },
    };
    return commands;
  }();
  return crdtp::FindByFirst<DomainDispatcherImpl::CallHandler>(*commands, command_name, nullptr);
}
}  // namespace

bool DomainDispatcherImpl::Dispatch(crdtp::span<uint8_t> command_name, crdtp::Dispatchable& dispatchable) {
  CallHandler handler = CommandByName(command_name);
  if (!handler) return false;

  (this->*handler)(dispatchable);
  return true;
}


namespace {

struct enableParams : public crdtp::DeserializableProtocolObject<enableParams> {
    std::optional<bool> enableUI;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(enableParams)
    CRDTP_DESERIALIZE_FIELD_OPT("enableUI", enableUI),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::enable(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    enableParams params;
    if (!enableParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->Enable(std::move(params.enableUI));
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
    if (weak->get())
        weak->get()->sendResponse(dispatchable.CallId(), response);
    return;
}

namespace {


}  // namespace

void DomainDispatcherImpl::disable(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->Disable();
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
    if (weak->get())
        weak->get()->sendResponse(dispatchable.CallId(), response);
    return;
}

namespace {

struct addVirtualAuthenticatorParams : public crdtp::DeserializableProtocolObject<addVirtualAuthenticatorParams> {
    std::unique_ptr<protocol::WebAuthn::VirtualAuthenticatorOptions> options;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(addVirtualAuthenticatorParams)
    CRDTP_DESERIALIZE_FIELD("options", options),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::addVirtualAuthenticator(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    addVirtualAuthenticatorParams params;
    if (!addVirtualAuthenticatorParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }
    // Declare output parameters.
    String out_authenticatorId;

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->AddVirtualAuthenticator(std::move(params.options), &out_authenticatorId);
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
      if (weak->get()) {
        std::unique_ptr<crdtp::Serializable> result;
        if (response.IsSuccess()) {
          crdtp::ObjectSerializer serializer;
          serializer.AddField(crdtp::MakeSpan("authenticatorId"), out_authenticatorId);
          result = serializer.Finish();
        } else {
          result = Serializable::From({});
        }
        weak->get()->sendResponse(dispatchable.CallId(), response, std::move(result));
      }
    return;
}

namespace {

struct setResponseOverrideBitsParams : public crdtp::DeserializableProtocolObject<setResponseOverrideBitsParams> {
    String authenticatorId;
    std::optional<bool> isBogusSignature;
    std::optional<bool> isBadUV;
    std::optional<bool> isBadUP;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(setResponseOverrideBitsParams)
    CRDTP_DESERIALIZE_FIELD("authenticatorId", authenticatorId),
    CRDTP_DESERIALIZE_FIELD_OPT("isBadUP", isBadUP),
    CRDTP_DESERIALIZE_FIELD_OPT("isBadUV", isBadUV),
    CRDTP_DESERIALIZE_FIELD_OPT("isBogusSignature", isBogusSignature),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::setResponseOverrideBits(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    setResponseOverrideBitsParams params;
    if (!setResponseOverrideBitsParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->SetResponseOverrideBits(params.authenticatorId, std::move(params.isBogusSignature), std::move(params.isBadUV), std::move(params.isBadUP));
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
    if (weak->get())
        weak->get()->sendResponse(dispatchable.CallId(), response);
    return;
}

namespace {

struct removeVirtualAuthenticatorParams : public crdtp::DeserializableProtocolObject<removeVirtualAuthenticatorParams> {
    String authenticatorId;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(removeVirtualAuthenticatorParams)
    CRDTP_DESERIALIZE_FIELD("authenticatorId", authenticatorId),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::removeVirtualAuthenticator(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    removeVirtualAuthenticatorParams params;
    if (!removeVirtualAuthenticatorParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->RemoveVirtualAuthenticator(params.authenticatorId);
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
    if (weak->get())
        weak->get()->sendResponse(dispatchable.CallId(), response);
    return;
}

class AddCredentialCallbackImpl : public Backend::AddCredentialCallback, public DomainDispatcher::Callback {
public:
    AddCredentialCallbackImpl(std::unique_ptr<DomainDispatcher::WeakPtr> backendImpl, crdtp::Dispatchable& dispatchable)
        : DomainDispatcher::Callback(std::move(backendImpl), dispatchable, crdtp::SpanFrom("WebAuthn.addCredential")) { }

    void sendSuccess() override
    {
        crdtp::ObjectSerializer serializer;
        sendIfActive(serializer.Finish(), DispatchResponse::Success());
    }

    void fallThrough() override
    {
        fallThroughIfActive();
    }

    void sendFailure(const DispatchResponse& response) override
    {
        DCHECK(response.IsError());
        sendIfActive(nullptr, response);
    }
};

namespace {

struct addCredentialParams : public crdtp::DeserializableProtocolObject<addCredentialParams> {
    String authenticatorId;
    std::unique_ptr<protocol::WebAuthn::Credential> credential;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(addCredentialParams)
    CRDTP_DESERIALIZE_FIELD("authenticatorId", authenticatorId),
    CRDTP_DESERIALIZE_FIELD("credential", credential),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::addCredential(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    addCredentialParams params;
    if (!addCredentialParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }

    m_backend->AddCredential(params.authenticatorId, std::move(params.credential), std::make_unique<AddCredentialCallbackImpl>(weakPtr(), dispatchable));
}

class GetCredentialCallbackImpl : public Backend::GetCredentialCallback, public DomainDispatcher::Callback {
public:
    GetCredentialCallbackImpl(std::unique_ptr<DomainDispatcher::WeakPtr> backendImpl, crdtp::Dispatchable& dispatchable)
        : DomainDispatcher::Callback(std::move(backendImpl), dispatchable, crdtp::SpanFrom("WebAuthn.getCredential")) { }

    void sendSuccess(std::unique_ptr<protocol::WebAuthn::Credential> credential) override
    {
        crdtp::ObjectSerializer serializer;
        serializer.AddField(crdtp::MakeSpan("credential"), credential);
        sendIfActive(serializer.Finish(), DispatchResponse::Success());
    }

    void fallThrough() override
    {
        fallThroughIfActive();
    }

    void sendFailure(const DispatchResponse& response) override
    {
        DCHECK(response.IsError());
        sendIfActive(nullptr, response);
    }
};

namespace {

struct getCredentialParams : public crdtp::DeserializableProtocolObject<getCredentialParams> {
    String authenticatorId;
    Binary credentialId;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(getCredentialParams)
    CRDTP_DESERIALIZE_FIELD("authenticatorId", authenticatorId),
    CRDTP_DESERIALIZE_FIELD("credentialId", credentialId),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::getCredential(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    getCredentialParams params;
    if (!getCredentialParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }

    m_backend->GetCredential(params.authenticatorId, params.credentialId, std::make_unique<GetCredentialCallbackImpl>(weakPtr(), dispatchable));
}

class GetCredentialsCallbackImpl : public Backend::GetCredentialsCallback, public DomainDispatcher::Callback {
public:
    GetCredentialsCallbackImpl(std::unique_ptr<DomainDispatcher::WeakPtr> backendImpl, crdtp::Dispatchable& dispatchable)
        : DomainDispatcher::Callback(std::move(backendImpl), dispatchable, crdtp::SpanFrom("WebAuthn.getCredentials")) { }

    void sendSuccess(std::unique_ptr<protocol::Array<protocol::WebAuthn::Credential>> credentials) override
    {
        crdtp::ObjectSerializer serializer;
        serializer.AddField(crdtp::MakeSpan("credentials"), credentials);
        sendIfActive(serializer.Finish(), DispatchResponse::Success());
    }

    void fallThrough() override
    {
        fallThroughIfActive();
    }

    void sendFailure(const DispatchResponse& response) override
    {
        DCHECK(response.IsError());
        sendIfActive(nullptr, response);
    }
};

namespace {

struct getCredentialsParams : public crdtp::DeserializableProtocolObject<getCredentialsParams> {
    String authenticatorId;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(getCredentialsParams)
    CRDTP_DESERIALIZE_FIELD("authenticatorId", authenticatorId),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::getCredentials(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    getCredentialsParams params;
    if (!getCredentialsParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }

    m_backend->GetCredentials(params.authenticatorId, std::make_unique<GetCredentialsCallbackImpl>(weakPtr(), dispatchable));
}

namespace {

struct removeCredentialParams : public crdtp::DeserializableProtocolObject<removeCredentialParams> {
    String authenticatorId;
    Binary credentialId;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(removeCredentialParams)
    CRDTP_DESERIALIZE_FIELD("authenticatorId", authenticatorId),
    CRDTP_DESERIALIZE_FIELD("credentialId", credentialId),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::removeCredential(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    removeCredentialParams params;
    if (!removeCredentialParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->RemoveCredential(params.authenticatorId, params.credentialId);
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
    if (weak->get())
        weak->get()->sendResponse(dispatchable.CallId(), response);
    return;
}

namespace {

struct clearCredentialsParams : public crdtp::DeserializableProtocolObject<clearCredentialsParams> {
    String authenticatorId;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(clearCredentialsParams)
    CRDTP_DESERIALIZE_FIELD("authenticatorId", authenticatorId),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::clearCredentials(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    clearCredentialsParams params;
    if (!clearCredentialsParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->ClearCredentials(params.authenticatorId);
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
    if (weak->get())
        weak->get()->sendResponse(dispatchable.CallId(), response);
    return;
}

namespace {

struct setUserVerifiedParams : public crdtp::DeserializableProtocolObject<setUserVerifiedParams> {
    String authenticatorId;
    bool isUserVerified;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(setUserVerifiedParams)
    CRDTP_DESERIALIZE_FIELD("authenticatorId", authenticatorId),
    CRDTP_DESERIALIZE_FIELD("isUserVerified", isUserVerified),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::setUserVerified(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    setUserVerifiedParams params;
    if (!setUserVerifiedParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->SetUserVerified(params.authenticatorId, params.isUserVerified);
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
    if (weak->get())
        weak->get()->sendResponse(dispatchable.CallId(), response);
    return;
}

namespace {

struct setAutomaticPresenceSimulationParams : public crdtp::DeserializableProtocolObject<setAutomaticPresenceSimulationParams> {
    String authenticatorId;
    bool enabled;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(setAutomaticPresenceSimulationParams)
    CRDTP_DESERIALIZE_FIELD("authenticatorId", authenticatorId),
    CRDTP_DESERIALIZE_FIELD("enabled", enabled),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::setAutomaticPresenceSimulation(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    setAutomaticPresenceSimulationParams params;
    if (!setAutomaticPresenceSimulationParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->SetAutomaticPresenceSimulation(params.authenticatorId, params.enabled);
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
    if (weak->get())
        weak->get()->sendResponse(dispatchable.CallId(), response);
    return;
}

namespace {

struct setCredentialPropertiesParams : public crdtp::DeserializableProtocolObject<setCredentialPropertiesParams> {
    String authenticatorId;
    Binary credentialId;
    std::optional<bool> backupEligibility;
    std::optional<bool> backupState;
    std::optional<int> activeCmtgKeyIndex;
    std::optional<bool> generateCmtgKeyOnNextOperation;
    std::optional<int> signCount;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(setCredentialPropertiesParams)
    CRDTP_DESERIALIZE_FIELD_OPT("activeCmtgKeyIndex", activeCmtgKeyIndex),
    CRDTP_DESERIALIZE_FIELD("authenticatorId", authenticatorId),
    CRDTP_DESERIALIZE_FIELD_OPT("backupEligibility", backupEligibility),
    CRDTP_DESERIALIZE_FIELD_OPT("backupState", backupState),
    CRDTP_DESERIALIZE_FIELD("credentialId", credentialId),
    CRDTP_DESERIALIZE_FIELD_OPT("generateCmtgKeyOnNextOperation", generateCmtgKeyOnNextOperation),
    CRDTP_DESERIALIZE_FIELD_OPT("signCount", signCount),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::setCredentialProperties(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    setCredentialPropertiesParams params;
    if (!setCredentialPropertiesParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->SetCredentialProperties(params.authenticatorId, params.credentialId, std::move(params.backupEligibility), std::move(params.backupState), std::move(params.activeCmtgKeyIndex), std::move(params.generateCmtgKeyOnNextOperation), std::move(params.signCount));
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
    if (weak->get())
        weak->get()->sendResponse(dispatchable.CallId(), response);
    return;
}

namespace {
// This helper method (with a static map of redirects) is used from Dispatcher::wire
// immediately below.
const std::vector<std::pair<crdtp::span<uint8_t>, crdtp::span<uint8_t>>>& SortedRedirects() {
  static auto* redirects = [](){
    auto* redirects = new std::vector<std::pair<crdtp::span<uint8_t>, crdtp::span<uint8_t>>>{
    };
    return redirects;
  }();
  return *redirects;
}
}  // namespace

// static
void Dispatcher::wire(UberDispatcher* uber, Backend* backend)
{
    auto dispatcher = std::make_unique<DomainDispatcherImpl>(uber->channel(), backend);
    uber->WireBackend(crdtp::SpanFrom("WebAuthn"), SortedRedirects(), std::move(dispatcher));
}

} // WebAuthn
} // namespace content
} // namespace protocol
