chromium/chromeos/dbus/permission_broker/fake_permission_broker_client.h

// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROMEOS_DBUS_PERMISSION_BROKER_FAKE_PERMISSION_BROKER_CLIENT_H_
#define CHROMEOS_DBUS_PERMISSION_BROKER_FAKE_PERMISSION_BROKER_CLIENT_H_

#include <stdint.h>

#include <map>
#include <set>
#include <string>
#include <utility>

#include "base/compiler_specific.h"
#include "base/files/file_descriptor_watcher_posix.h"
#include "base/files/scoped_file.h"
#include "chromeos/dbus/permission_broker/permission_broker_client.h"

namespace chromeos {

class COMPONENT_EXPORT(PERMISSION_BROKER) FakePermissionBrokerClient
    : public PermissionBrokerClient {
 public:
  class Delegate {
   public:
    virtual ~Delegate() = default;

    virtual void OnTcpPortReleased(uint16_t port,
                                   const std::string& interface) {}
    virtual void OnUdpPortReleased(uint16_t port,
                                   const std::string& interface) {}
  };

  FakePermissionBrokerClient();

  FakePermissionBrokerClient(const FakePermissionBrokerClient&) = delete;
  FakePermissionBrokerClient& operator=(const FakePermissionBrokerClient&) =
      delete;

  ~FakePermissionBrokerClient() override;

  // Checks that a fake instance was initialized and returns it.
  static FakePermissionBrokerClient* Get();

  void CheckPathAccess(const std::string& path,
                       ResultCallback callback) override;
  void OpenPath(const std::string& path,
                OpenPathCallback callback,
                ErrorCallback error_callback) override;
  void ClaimDevicePath(const std::string& path,
                       uint32_t allowed_interfaces_mask,
                       int lifeline_fd,
                       OpenPathCallback callback,
                       ErrorCallback error_callback) override;
  void OpenPathAndRegisterClient(const std::string& path,
                                 uint32_t allowed_interfaces_mask,
                                 int lifeline_fd,
                                 OpenPathAndRegisterClientCallback callback,
                                 ErrorCallback error_callback) override;
  void DetachInterface(const std::string& client_id,
                       uint8_t iface_num,
                       ResultCallback callback) override;
  void ReattachInterface(const std::string& client_id,
                         uint8_t iface_num,
                         ResultCallback callback) override;
  void RequestTcpPortAccess(uint16_t port,
                            const std::string& interface,
                            int lifeline_fd,
                            ResultCallback callback) override;
  void RequestUdpPortAccess(uint16_t port,
                            const std::string& interface,
                            int lifeline_fd,
                            ResultCallback callback) override;
  void ReleaseTcpPort(uint16_t port,
                      const std::string& interface,
                      ResultCallback callback) override;
  void ReleaseUdpPort(uint16_t port,
                      const std::string& interface,
                      ResultCallback callback) override;
  void RequestTcpPortForward(uint16_t in_port,
                             const std::string& in_interface,
                             const std::string& dst_ip,
                             uint16_t dst_port,
                             int lifeline_fd,
                             ResultCallback callback) override;
  void RequestUdpPortForward(uint16_t in_port,
                             const std::string& in_interface,
                             const std::string& dst_ip,
                             uint16_t dst_port,
                             int lifeline_fd,
                             ResultCallback callback) override;
  void ReleaseTcpPortForward(uint16_t in_port,
                             const std::string& in_interface,
                             ResultCallback callback) override;
  void ReleaseUdpPortForward(uint16_t in_port,
                             const std::string& in_interface,
                             ResultCallback callback) override;

  // Add a rule to have RequestTcpPortAccess fail.
  void AddTcpDenyRule(uint16_t port, const std::string& interface);

  // Unconditionally fail all RequestTcpPortAccess calls.
  void SetTcpDenyAll();

  // Add a rule to have RequestUdpPortAccess fail.
  void AddUdpDenyRule(uint16_t port, const std::string& interface);

  // Unconditionally fail all RequestUdpPortAccess calls.
  void SetUdpDenyAll();

  // Returns true if TCP port has a hole.
  bool HasTcpHole(uint16_t port, const std::string& interface);

  // Returns true if UDP port has a hole.
  bool HasUdpHole(uint16_t port, const std::string& interface);

  // Returns true if TCP port is being forwarded.
  bool HasTcpPortForward(uint16_t port, const std::string& interface);

  // Returns true if UDP port is being forwarded.
  bool HasUdpPortForward(uint16_t port, const std::string& interface);

  void AttachDelegate(Delegate* delegate);

 private:
  using RuleSet =
      std::set<std::pair<uint16_t /* port */, std::string /* interface */>>;

  struct UsbInterfaces {
    UsbInterfaces(
        const std::string& path,
        base::ScopedFD lifeline_fd,
        std::unique_ptr<base::FileDescriptorWatcher::Controller> controller);
    ~UsbInterfaces();
    UsbInterfaces(UsbInterfaces&&);
    UsbInterfaces& operator=(UsbInterfaces&&);

    UsbInterfaces(const UsbInterfaces&) = delete;
    UsbInterfaces& operator=(const UsbInterfaces&) = delete;

    std::string path;

    // NOTE: The ordering of these fields is important: `controller` must be
    // destroyed before `lifetime_fd` is closed.
    base::ScopedFD lifeline_fd;
    std::unique_ptr<base::FileDescriptorWatcher::Controller> controller;
  };

  bool RequestPortImpl(uint16_t port,
                       const std::string& interface,
                       const RuleSet& deny_rule_set,
                       RuleSet* hole_set);

  void HandleClosedClient(const std::string& client_id) {
    clients_.erase(client_id);
  }

  RuleSet tcp_hole_set_;
  RuleSet udp_hole_set_;

  RuleSet tcp_forwarding_set_;
  RuleSet udp_forwarding_set_;

  RuleSet tcp_deny_rule_set_;
  RuleSet udp_deny_rule_set_;

  bool tcp_deny_all_ = false;
  bool udp_deny_all_ = false;

  std::map<std::string, UsbInterfaces> clients_;

  raw_ptr<Delegate, DanglingUntriaged> delegate_ = nullptr;

  base::WeakPtrFactory<FakePermissionBrokerClient> weak_factory_{this};
};

}  // namespace chromeos

#endif  // CHROMEOS_DBUS_PERMISSION_BROKER_FAKE_PERMISSION_BROKER_CLIENT_H_