// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_SMART_CARD_SMART_CARD_READER_TRACKER_H_
#define CHROME_BROWSER_SMART_CARD_SMART_CARD_READER_TRACKER_H_
#include <optional>
#include "base/observer_list.h"
#include "components/keyed_service/core/keyed_service.h"
#include "services/device/public/mojom/smart_card.mojom.h"
// Keeps track of the current list of readers and their states.
// Notifies about changes via an observer pattern.
class SmartCardReaderTracker : public KeyedService {
public:
struct ReaderInfo {
ReaderInfo();
ReaderInfo(ReaderInfo&& other);
ReaderInfo(const ReaderInfo&);
~ReaderInfo();
ReaderInfo& operator=(const ReaderInfo& other);
bool operator==(const ReaderInfo& b) const;
std::string name;
// A subset of device::mojom::SmartCardReaderStateFlags
bool unavailable = false;
bool empty = false;
bool present = false;
bool exclusive = false;
bool inuse = false;
bool mute = false;
bool unpowered = false;
// Number of card insertion and removal events that happened in this reader.
// Will always be zero if not supported by the platform.
uint16_t event_count = 0;
std::vector<uint8_t> answer_to_reset;
};
// Observer class for changes to smart card readers.
//
// Note that there's no OnReaderAdded() for two reasons:
// 1 - The browser code does not need it.
// 2 - The underlying PC/SC feature needed to implement this is not present
// in all platforms (it's missing on MacOS).
class Observer : public base::CheckedObserver {
public:
// Called when a smart card reader is removed from the system.
virtual void OnReaderRemoved(const std::string& reader_name) {}
// Called when the attributes (state and/or atr) of a smart card reader
// changes.
virtual void OnReaderChanged(const ReaderInfo& reader_info) {}
// Called when a error preventing the monitoring of reader changes occurs.
// Can be retried with a new `Start` call.
virtual void OnError(device::mojom::SmartCardError error) {}
};
class ObserverList {
public:
ObserverList();
ObserverList(const ObserverList&) = delete;
ObserverList& operator=(const ObserverList&) = delete;
~ObserverList();
bool empty() const { return observers_.empty(); }
void AddObserverIfMissing(Observer* observer);
void RemoveObserver(Observer* observer);
void NotifyReaderChanged(const ReaderInfo& reader_info);
void NotifyReaderRemoved(const std::string& reader_name);
void NotifyError(device::mojom::SmartCardError error);
private:
base::ObserverList<Observer> observers_;
};
// The parameter is a list of readers currently available.
//
// If a PC/SC error occurred, there will be no list. Ie, the optional will
// have no value.
//
// If the list is empty, tracking will also have stopped as there are no
// readers to track.
using StartCallback =
base::OnceCallback<void(std::optional<std::vector<ReaderInfo>>)>;
SmartCardReaderTracker() = default;
~SmartCardReaderTracker() override = default;
// Returns the list of currently available smart card readers and (re)starts
// tracking them for changes or removals.
//
// It will stop tracking once there are no more observers, upon the first
// error encountered or if there are no readers in the system.
virtual void Start(Observer* observer, StartCallback) = 0;
// Removes an observer and stops tracking smart card reader
// changes/additions/removals if there are no other observers left
virtual void Stop(Observer* observer) = 0;
};
#endif // CHROME_BROWSER_SMART_CARD_SMART_CARD_READER_TRACKER_H_