1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef CHROME_BROWSER_HID_HID_CHOOSER_CONTEXT_H_
6 #define CHROME_BROWSER_HID_HID_CHOOSER_CONTEXT_H_
7 
8 #include <map>
9 #include <memory>
10 #include <set>
11 #include <string>
12 #include <utility>
13 #include <vector>
14 
15 #include "base/memory/weak_ptr.h"
16 #include "base/observer_list.h"
17 #include "base/unguessable_token.h"
18 #include "components/permissions/chooser_context_base.h"
19 #include "mojo/public/cpp/bindings/associated_receiver.h"
20 #include "mojo/public/cpp/bindings/pending_remote.h"
21 #include "mojo/public/cpp/bindings/remote.h"
22 #include "services/device/public/mojom/hid.mojom.h"
23 #include "url/origin.h"
24 
25 class Profile;
26 
27 namespace base {
28 class Value;
29 }
30 
31 // Manages the internal state and connection to the device service for the
32 // Human Interface Device (HID) chooser UI.
33 class HidChooserContext : public permissions::ChooserContextBase,
34                           public device::mojom::HidManagerClient {
35  public:
36   // This observer can be used to be notified when HID devices are connected or
37   // disconnected.
38   class DeviceObserver : public base::CheckedObserver {
39    public:
40     virtual void OnDeviceAdded(const device::mojom::HidDeviceInfo&);
41     virtual void OnDeviceRemoved(const device::mojom::HidDeviceInfo&);
42     virtual void OnHidManagerConnectionError();
43 
44     // Called when the HidChooserContext is shutting down. Observers must remove
45     // themselves before returning.
46     virtual void OnHidChooserContextShutdown() = 0;
47   };
48 
49   explicit HidChooserContext(Profile* profile);
50   HidChooserContext(const HidChooserContext&) = delete;
51   HidChooserContext& operator=(const HidChooserContext&) = delete;
52   ~HidChooserContext() override;
53 
54   // Returns a human-readable string identifier for |device|.
55   static base::string16 DisplayNameFromDeviceInfo(
56       const device::mojom::HidDeviceInfo& device);
57 
58   // permissions::ChooserContextBase implementation:
59   bool IsValidObject(const base::Value& object) override;
60   // In addition these methods from ChooserContextBase are overridden in order
61   // to expose ephemeral devices through the public interface.
62   std::vector<std::unique_ptr<Object>> GetGrantedObjects(
63       const url::Origin& requesting_origin,
64       const url::Origin& embedding_origin) override;
65   std::vector<std::unique_ptr<Object>> GetAllGrantedObjects() override;
66   void RevokeObjectPermission(const url::Origin& requesting_origin,
67                               const url::Origin& embedding_origin,
68                               const base::Value& object) override;
69   base::string16 GetObjectDisplayName(const base::Value& object) override;
70 
71   // HID-specific interface for granting and checking permissions.
72   void GrantDevicePermission(const url::Origin& requesting_origin,
73                              const url::Origin& embedding_origin,
74                              const device::mojom::HidDeviceInfo& device);
75   bool HasDevicePermission(const url::Origin& requesting_origin,
76                            const url::Origin& embedding_origin,
77                            const device::mojom::HidDeviceInfo& device);
78 
79   // For ScopedObserver.
80   void AddDeviceObserver(DeviceObserver* observer);
81   void RemoveDeviceObserver(DeviceObserver* observer);
82 
83   // Forward HidManager::GetDevices.
84   void GetDevices(device::mojom::HidManager::GetDevicesCallback callback);
85 
86   // Only call this if you're sure |devices_| has been initialized before-hand.
87   // The returned raw pointer is owned by |devices_| and will be destroyed when
88   // the device is removed.
89   const device::mojom::HidDeviceInfo* GetDeviceInfo(const std::string& guid);
90 
91   device::mojom::HidManager* GetHidManager();
92 
93   // Sets |manager| as the HidManager and registers this context as a
94   // HidManagerClient. Calls |callback| with the set of enumerated devices once
95   // the client is registered and the initial enumeration is complete.
96   void SetHidManagerForTesting(
97       mojo::PendingRemote<device::mojom::HidManager> manager,
98       device::mojom::HidManager::GetDevicesCallback callback);
99 
100   base::WeakPtr<HidChooserContext> AsWeakPtr();
101 
102  private:
103   // device::mojom::HidManagerClient implementation:
104   void DeviceAdded(device::mojom::HidDeviceInfoPtr device_info) override;
105   void DeviceRemoved(device::mojom::HidDeviceInfoPtr device_info) override;
106 
107   void EnsureHidManagerConnection();
108   void SetUpHidManagerConnection(
109       mojo::PendingRemote<device::mojom::HidManager> manager);
110   void InitDeviceList(std::vector<device::mojom::HidDeviceInfoPtr> devices);
111   void OnHidManagerConnectionError();
112 
113   const bool is_incognito_;
114   bool is_initialized_ = false;
115   base::queue<device::mojom::HidManager::GetDevicesCallback>
116       pending_get_devices_requests_;
117 
118   // Tracks the set of devices to which an origin (potentially embedded in
119   // another origin) has access to. Key is (requesting_origin,
120   // embedding_origin).
121   std::map<std::pair<url::Origin, url::Origin>, std::set<std::string>>
122       ephemeral_devices_;
123 
124   // Map from device GUID to device info.
125   std::map<std::string, device::mojom::HidDeviceInfoPtr> devices_;
126 
127   mojo::Remote<device::mojom::HidManager> hid_manager_;
128   mojo::AssociatedReceiver<device::mojom::HidManagerClient> client_receiver_{
129       this};
130   base::ObserverList<DeviceObserver> device_observer_list_;
131 
132   base::WeakPtrFactory<HidChooserContext> weak_factory_{this};
133 };
134 
135 #endif  // CHROME_BROWSER_HID_HID_CHOOSER_CONTEXT_H_
136