blob: e8d67c7d777d16c57a612bb1165525438bcc788b [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.
#ifndef DEVICE_FIDO_FIDO_DISCOVERY_H_
#define DEVICE_FIDO_FIDO_DISCOVERY_H_
#include <functional>
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/component_export.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/string_piece.h"
#include "device/fido/cable/cable_discovery_data.h"
#include "device/fido/fido_discovery_base.h"
#include "device/fido/fido_transport_protocol.h"
namespace service_manager {
class Connector;
}
namespace device {
class FidoDevice;
namespace internal {
class ScopedFidoDiscoveryFactory;
}
class COMPONENT_EXPORT(DEVICE_FIDO) FidoDiscovery : public FidoDiscoveryBase {
public:
enum class State {
kIdle,
kStarting,
kRunning,
};
// Factory functions to construct an instance that discovers authenticators on
// the given |transport| protocol. The first variant is for everything except
// for cloud-assisted BLE which is handled by the second variant.
//
// FidoTransportProtocol::kUsbHumanInterfaceDevice requires specifying a valid
// |connector| on Desktop, and is not valid on Android.
static std::unique_ptr<FidoDiscovery> Create(
FidoTransportProtocol transport,
::service_manager::Connector* connector);
static std::unique_ptr<FidoDiscovery> CreateCable(
std::vector<CableDiscoveryData> cable_data);
~FidoDiscovery() override;
bool is_start_requested() const { return state_ != State::kIdle; }
bool is_running() const { return state_ == State::kRunning; }
std::vector<FidoDevice*> GetDevices();
std::vector<const FidoDevice*> GetDevices() const;
// TODO(martinkr): Rename to GetDeviceForTesting.
FidoDevice* GetDevice(base::StringPiece device_id);
const FidoDevice* GetDevice(base::StringPiece device_id) const;
// FidoDiscoveryBase:
void Start() override;
protected:
FidoDiscovery(FidoTransportProtocol transport);
void NotifyDiscoveryStarted(bool success);
void NotifyAuthenticatorAdded(FidoAuthenticator* authenticator);
void NotifyAuthenticatorRemoved(FidoAuthenticator* authenticator);
bool AddDevice(std::unique_ptr<FidoDevice> device);
bool RemoveDevice(base::StringPiece device_id);
// Subclasses should implement this to actually start the discovery when it is
// requested.
//
// The implementation should asynchronously invoke NotifyDiscoveryStarted when
// the discovery is s tarted.
virtual void StartInternal() = 0;
std::map<std::string,
std::pair<std::unique_ptr<FidoAuthenticator>,
std::unique_ptr<FidoDevice>>,
std::less<>>
devices_;
private:
friend class internal::ScopedFidoDiscoveryFactory;
// Factory function can be overridden by tests to construct fakes.
using FactoryFuncPtr = decltype(&Create);
using CableFactoryFuncPtr = decltype(&CreateCable);
static FactoryFuncPtr g_factory_func_;
static CableFactoryFuncPtr g_cable_factory_func_;
State state_ = State::kIdle;
base::WeakPtrFactory<FidoDiscovery> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(FidoDiscovery);
};
namespace internal {
// Base class for a scoped override of FidoDiscovery::Create, used in unit
// tests, layout tests, and when running with the Web Authn Testing API enabled.
//
// While there is a subclass instance in scope, calls to the factory method will
// be hijacked such that the derived class's CreateFidoDiscovery method will be
// invoked instead.
class COMPONENT_EXPORT(DEVICE_FIDO) ScopedFidoDiscoveryFactory {
public:
// There should be at most one instance of any subclass in scope at a time.
ScopedFidoDiscoveryFactory();
virtual ~ScopedFidoDiscoveryFactory();
const std::vector<CableDiscoveryData>& last_cable_data() const {
return last_cable_data_;
}
protected:
void set_last_cable_data(std::vector<CableDiscoveryData> cable_data) {
last_cable_data_ = std::move(cable_data);
}
virtual std::unique_ptr<FidoDiscovery> CreateFidoDiscovery(
FidoTransportProtocol transport,
::service_manager::Connector* connector) = 0;
private:
static std::unique_ptr<FidoDiscovery>
ForwardCreateFidoDiscoveryToCurrentFactory(
FidoTransportProtocol transport,
::service_manager::Connector* connector);
static std::unique_ptr<FidoDiscovery>
ForwardCreateCableDiscoveryToCurrentFactory(
std::vector<CableDiscoveryData> cable_data);
static ScopedFidoDiscoveryFactory* g_current_factory;
FidoDiscovery::FactoryFuncPtr original_factory_func_;
FidoDiscovery::CableFactoryFuncPtr original_cable_factory_func_;
std::vector<CableDiscoveryData> last_cable_data_;
DISALLOW_COPY_AND_ASSIGN(ScopedFidoDiscoveryFactory);
};
} // namespace internal
} // namespace device
#endif // DEVICE_FIDO_FIDO_DISCOVERY_H_