// Copyright 2018 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. #ifndef DEVICE_FIDO_FIDO_REQUEST_HANDLER_H_ #define DEVICE_FIDO_FIDO_REQUEST_HANDLER_H_ #include "device/fido/fido_request_handler_base.h" #include #include "base/callback.h" #include "base/containers/flat_set.h" #include "base/macros.h" #include "base/optional.h" #include "device/fido/fido_constants.h" #include "device/fido/fido_device.h" #include "device/fido/fido_transport_protocol.h" namespace device { // Handles receiving response form potentially multiple connected authenticators // and relaying response to the relying party. template class FidoRequestHandler : public FidoRequestHandlerBase { public: using CompletionCallback = base::OnceCallback response_data)>; FidoRequestHandler(service_manager::Connector* connector, const base::flat_set& transports, CompletionCallback completion_callback) : FidoRequestHandlerBase(connector, transports), completion_callback_(std::move(completion_callback)) {} ~FidoRequestHandler() override { if (!is_complete()) CancelOngoingTasks(); } bool is_complete() const { return completion_callback_.is_null(); } protected: // Converts device response code received from CTAP1/CTAP2 device into // FidoReturnCode and passes response data to webauth::mojom::Authenticator. void OnDeviceResponse(FidoDevice* device, CtapDeviceResponseCode device_response_code, base::Optional response_data) { if (is_complete()) { DVLOG(2) << "Response from authenticator received after request is complete."; return; } const auto return_code = ConvertDeviceResponseCodeToFidoReturnCode( device_response_code, response_data.has_value()); if (!return_code) { ongoing_tasks().erase(device->GetId()); return; } // Once response has been passed to the relying party, cancel all other on // going requests. CancelOngoingTasks(device->GetId()); std::move(completion_callback_).Run(*return_code, std::move(response_data)); } private: static base::Optional ConvertDeviceResponseCodeToFidoReturnCode( CtapDeviceResponseCode device_response_code, bool response_has_value) { switch (device_response_code) { case CtapDeviceResponseCode::kSuccess: return response_has_value ? FidoReturnCode::kSuccess : FidoReturnCode::kAuthenticatorResponseInvalid; // These errors are only returned after the user interacted with the // device. case CtapDeviceResponseCode::kCtap2ErrCredentialExcluded: return FidoReturnCode::kUserConsentButCredentialExcluded; case CtapDeviceResponseCode::kCtap2ErrNoCredentials: return FidoReturnCode::kUserConsentButCredentialNotRecognized; default: return base::nullopt; } } CompletionCallback completion_callback_; DISALLOW_COPY_AND_ASSIGN(FidoRequestHandler); }; } // namespace device #endif // DEVICE_FIDO_FIDO_REQUEST_HANDLER_H_