chromium/chrome/browser/smart_card/smart_card_reader_tracker.h

// 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_