| // 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 <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/fido_transport_protocol.h" |
| |
| namespace service_manager { |
| class Connector; |
| } |
| |
| namespace device { |
| |
| class FidoDevice; |
| |
| namespace internal { |
| class ScopedFidoDiscoveryFactory; |
| } |
| |
| class COMPONENT_EXPORT(DEVICE_FIDO) FidoDiscovery { |
| public: |
| enum class State { |
| kIdle, |
| kStarting, |
| kRunning, |
| }; |
| |
| class COMPONENT_EXPORT(DEVICE_FIDO) Observer { |
| public: |
| virtual ~Observer(); |
| |
| // It is guaranteed that this is never invoked synchronously from Start(). |
| virtual void DiscoveryStarted(FidoDiscovery* discovery, bool success) = 0; |
| |
| // It is guaranteed that DeviceAdded/DeviceRemoved() will not be invoked |
| // before the client of FidoDiscovery calls FidoDiscovery::Start(). However, |
| // for devices already known to the system at that point, DeviceAdded() |
| // might already be called to reported already known devices. |
| // |
| // The supplied FidoDevice instance is guaranteed to have its protocol |
| // version initialized. I.e., FidoDiscovery calls |
| // FidoDevice::DiscoverSupportedProtocolAndDeviceInfo() before notifying |
| // the Observer. |
| virtual void DeviceAdded(FidoDiscovery* discovery, FidoDevice* device) = 0; |
| virtual void DeviceRemoved(FidoDiscovery* discovery, |
| FidoDevice* device) = 0; |
| }; |
| |
| // Factory function to construct an instance that discovers authenticators on |
| // the given |transport| protocol. |
| // |
| // 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); |
| |
| virtual ~FidoDiscovery(); |
| |
| Observer* observer() const { return observer_; } |
| void set_observer(Observer* observer) { |
| DCHECK(!observer_ || !observer) << "Only one observer is supported."; |
| observer_ = observer; |
| } |
| |
| FidoTransportProtocol transport() const { return transport_; } |
| bool is_start_requested() const { return state_ != State::kIdle; } |
| bool is_running() const { return state_ == State::kRunning; } |
| |
| void Start(); |
| |
| std::vector<FidoDevice*> GetDevices(); |
| std::vector<const FidoDevice*> GetDevices() const; |
| |
| FidoDevice* GetDevice(base::StringPiece device_id); |
| const FidoDevice* GetDevice(base::StringPiece device_id) const; |
| |
| protected: |
| FidoDiscovery(FidoTransportProtocol transport); |
| |
| void NotifyDiscoveryStarted(bool success); |
| void NotifyDeviceAdded(FidoDevice* device); |
| void NotifyDeviceRemoved(FidoDevice* device); |
| |
| 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::unique_ptr<FidoDevice>, std::less<>> devices_; |
| Observer* observer_ = nullptr; |
| |
| private: |
| friend class internal::ScopedFidoDiscoveryFactory; |
| |
| // Factory function can be overridden by tests to construct fakes. |
| using FactoryFuncPtr = decltype(&Create); |
| static FactoryFuncPtr g_factory_func_; |
| |
| const FidoTransportProtocol transport_; |
| 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(); |
| |
| protected: |
| 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 ScopedFidoDiscoveryFactory* g_current_factory; |
| FidoDiscovery::FactoryFuncPtr original_factory_func_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ScopedFidoDiscoveryFactory); |
| }; |
| |
| } // namespace internal |
| } // namespace device |
| |
| #endif // DEVICE_FIDO_FIDO_DISCOVERY_H_ |