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