1 // Copyright 2015 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 #include "content/browser/bluetooth/bluetooth_allowed_devices.h"
6 
7 #include <string>
8 #include <vector>
9 
10 #include "base/logging.h"
11 #include "base/optional.h"
12 #include "base/stl_util.h"
13 #include "base/strings/string_util.h"
14 #include "content/browser/bluetooth/bluetooth_blocklist.h"
15 
16 using device::BluetoothUUID;
17 
18 namespace content {
19 
BluetoothAllowedDevices()20 BluetoothAllowedDevices::BluetoothAllowedDevices() {}
21 BluetoothAllowedDevices::BluetoothAllowedDevices(
22     const BluetoothAllowedDevices& other) = default;
~BluetoothAllowedDevices()23 BluetoothAllowedDevices::~BluetoothAllowedDevices() {}
24 
AddDevice(const std::string & device_address,const blink::mojom::WebBluetoothRequestDeviceOptionsPtr & options)25 const blink::WebBluetoothDeviceId& BluetoothAllowedDevices::AddDevice(
26     const std::string& device_address,
27     const blink::mojom::WebBluetoothRequestDeviceOptionsPtr& options) {
28   auto& device_id = AddDevice(device_address);
29   AddUnionOfServicesTo(options, &device_id_to_services_map_[device_id]);
30   AddManufacturerDataTo(options, &device_id_to_manufacturers_map_[device_id]);
31 
32   // Currently, devices that are added with WebBluetoothRequestDeviceOptionsPtr
33   // |options| come from RequestDevice() and therefore have the ablity to be
34   // connected to.
35   device_id_to_connectable_map_[device_id] = true;
36 
37   return device_id;
38 }
39 
AddDevice(const std::string & device_address)40 const blink::WebBluetoothDeviceId& BluetoothAllowedDevices::AddDevice(
41     const std::string& device_address) {
42   DVLOG(1) << "Adding a device to Map of Allowed Devices.";
43 
44   auto id_iter = device_address_to_id_map_.find(device_address);
45   if (id_iter != device_address_to_id_map_.end()) {
46     DVLOG(1) << "Device already in map of allowed devices.";
47     return device_address_to_id_map_[device_address];
48   }
49   const blink::WebBluetoothDeviceId device_id = GenerateUniqueDeviceId();
50   DVLOG(1) << "Id generated for device: " << device_id;
51 
52   device_address_to_id_map_[device_address] = device_id;
53   device_id_to_address_map_[device_id] = device_address;
54 
55   CHECK(device_id_set_.insert(device_id).second);
56 
57   return device_address_to_id_map_[device_address];
58 }
59 
RemoveDevice(const std::string & device_address)60 void BluetoothAllowedDevices::RemoveDevice(const std::string& device_address) {
61   const blink::WebBluetoothDeviceId* device_id_ptr =
62       GetDeviceId(device_address);
63   DCHECK(device_id_ptr != nullptr);
64 
65   // We make a copy because we are going to remove the original value from its
66   // map.
67   blink::WebBluetoothDeviceId device_id = *device_id_ptr;
68 
69   // 1. Remove from all three maps.
70   CHECK(device_address_to_id_map_.erase(device_address));
71   CHECK(device_id_to_address_map_.erase(device_id));
72   CHECK(device_id_to_services_map_.erase(device_id));
73 
74   // Not all devices are connectable.
75   device_id_to_connectable_map_.erase(device_id);
76 
77   // 2. Remove from set of ids.
78   CHECK(device_id_set_.erase(device_id));
79 }
80 
GetDeviceId(const std::string & device_address)81 const blink::WebBluetoothDeviceId* BluetoothAllowedDevices::GetDeviceId(
82     const std::string& device_address) {
83   auto id_iter = device_address_to_id_map_.find(device_address);
84   if (id_iter == device_address_to_id_map_.end()) {
85     return nullptr;
86   }
87   return &(id_iter->second);
88 }
89 
GetDeviceAddress(const blink::WebBluetoothDeviceId & device_id)90 const std::string& BluetoothAllowedDevices::GetDeviceAddress(
91     const blink::WebBluetoothDeviceId& device_id) {
92   auto id_iter = device_id_to_address_map_.find(device_id);
93   return id_iter == device_id_to_address_map_.end() ? base::EmptyString()
94                                                     : id_iter->second;
95 }
96 
IsAllowedToAccessAtLeastOneService(const blink::WebBluetoothDeviceId & device_id) const97 bool BluetoothAllowedDevices::IsAllowedToAccessAtLeastOneService(
98     const blink::WebBluetoothDeviceId& device_id) const {
99   auto id_iter = device_id_to_services_map_.find(device_id);
100   return id_iter == device_id_to_services_map_.end() ? false
101                                                      : !id_iter->second.empty();
102 }
103 
IsAllowedToAccessService(const blink::WebBluetoothDeviceId & device_id,const BluetoothUUID & service_uuid) const104 bool BluetoothAllowedDevices::IsAllowedToAccessService(
105     const blink::WebBluetoothDeviceId& device_id,
106     const BluetoothUUID& service_uuid) const {
107   if (BluetoothBlocklist::Get().IsExcluded(service_uuid))
108     return false;
109 
110   auto id_iter = device_id_to_services_map_.find(device_id);
111   return id_iter == device_id_to_services_map_.end()
112              ? false
113              : base::Contains(id_iter->second, service_uuid);
114 }
115 
IsAllowedToGATTConnect(const blink::WebBluetoothDeviceId & device_id) const116 bool BluetoothAllowedDevices::IsAllowedToGATTConnect(
117     const blink::WebBluetoothDeviceId& device_id) const {
118   auto id_iter = device_id_to_connectable_map_.find(device_id);
119   if (id_iter == device_id_to_connectable_map_.end())
120     return false;
121   return id_iter->second;
122 }
123 
IsAllowedToAccessManufacturerData(const blink::WebBluetoothDeviceId & device_id,const uint16_t manufacturer_code) const124 bool BluetoothAllowedDevices::IsAllowedToAccessManufacturerData(
125     const blink::WebBluetoothDeviceId& device_id,
126     const uint16_t manufacturer_code) const {
127   auto id_iter = device_id_to_manufacturers_map_.find(device_id);
128   return id_iter == device_id_to_manufacturers_map_.end()
129              ? false
130              : base::Contains(id_iter->second, manufacturer_code);
131 }
132 
GenerateUniqueDeviceId()133 blink::WebBluetoothDeviceId BluetoothAllowedDevices::GenerateUniqueDeviceId() {
134   blink::WebBluetoothDeviceId device_id = blink::WebBluetoothDeviceId::Create();
135   while (base::Contains(device_id_set_, device_id)) {
136     LOG(WARNING) << "Generated repeated id.";
137     device_id = blink::WebBluetoothDeviceId::Create();
138   }
139   return device_id;
140 }
141 
AddUnionOfServicesTo(const blink::mojom::WebBluetoothRequestDeviceOptionsPtr & options,std::unordered_set<BluetoothUUID,device::BluetoothUUIDHash> * unionOfServices)142 void BluetoothAllowedDevices::AddUnionOfServicesTo(
143     const blink::mojom::WebBluetoothRequestDeviceOptionsPtr& options,
144     std::unordered_set<BluetoothUUID, device::BluetoothUUIDHash>*
145         unionOfServices) {
146   if (options->filters) {
147     for (const auto& filter : options->filters.value()) {
148       if (!filter->services)
149         continue;
150 
151       for (const BluetoothUUID& uuid : filter->services.value())
152         unionOfServices->insert(uuid);
153     }
154   }
155 
156   for (const BluetoothUUID& uuid : options->optional_services)
157     unionOfServices->insert(uuid);
158 }
159 
AddManufacturerDataTo(const blink::mojom::WebBluetoothRequestDeviceOptionsPtr & options,base::flat_set<uint16_t> * manufacturer_codes)160 void BluetoothAllowedDevices::AddManufacturerDataTo(
161     const blink::mojom::WebBluetoothRequestDeviceOptionsPtr& options,
162     base::flat_set<uint16_t>* manufacturer_codes) {
163   for (const uint16_t manufacturer_code : options->optional_manufacturer_data)
164     manufacturer_codes->insert(manufacturer_code);
165 }
166 
167 }  // namespace content
168