OLD | NEW |
---|---|
(Empty) | |
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 "base/memory/singleton.h" | |
6 #include "base/stl_util.h" | |
7 #include "base/values.h" | |
8 #include "chrome/browser/content_settings/host_content_settings_map_factory.h" | |
9 #include "chrome/browser/profiles/incognito_helpers.h" | |
10 #include "chrome/browser/profiles/profile.h" | |
11 #include "chrome/browser/usb/web_usb_permission_store.h" | |
12 #include "components/content_settings/core/browser/host_content_settings_map.h" | |
13 #include "components/content_settings/core/common/content_settings_pattern.h" | |
14 #include "components/keyed_service/content/browser_context_dependency_manager.h" | |
15 #include "components/keyed_service/content/browser_context_keyed_service_factory .h" | |
16 #include "device/core/device_client.h" | |
17 #include "device/usb/usb_device.h" | |
18 | |
19 using content::BrowserContext; | |
20 using device::UsbDevice; | |
21 | |
22 namespace { | |
23 | |
24 const char* const kDeviceListKey = "devices"; | |
25 const char* const kDeviceNameKey = "name"; | |
26 const char* const kVendorIdKey = "vendor-id"; | |
27 const char* const kProductIdKey = "product-id"; | |
28 const char* const kSerialNumberKey = "serial-number"; | |
29 | |
30 class WebUSBPermissionStoreFactory : public BrowserContextKeyedServiceFactory { | |
31 public: | |
32 static WebUSBPermissionStore* GetForBrowserContext(BrowserContext* context) { | |
33 return static_cast<WebUSBPermissionStore*>( | |
34 GetInstance()->GetServiceForBrowserContext(context, true)); | |
35 } | |
36 | |
37 static WebUSBPermissionStoreFactory* GetInstance() { | |
Bernhard Bauer
2015/10/01 08:31:25
You will need to add a (visible from outside) meth
| |
38 return base::Singleton<WebUSBPermissionStoreFactory>::get(); | |
39 } | |
40 | |
41 private: | |
42 friend struct base::DefaultSingletonTraits<WebUSBPermissionStoreFactory>; | |
43 | |
44 WebUSBPermissionStoreFactory() | |
45 : BrowserContextKeyedServiceFactory( | |
46 "WebUSBPermissionStore", | |
47 BrowserContextDependencyManager::GetInstance()) {} | |
48 ~WebUSBPermissionStoreFactory() override {} | |
49 | |
50 BrowserContext* GetBrowserContextToUse( | |
51 BrowserContext* context) const override { | |
52 return chrome::GetBrowserContextOwnInstanceInIncognito(context); | |
53 } | |
54 | |
55 KeyedService* BuildServiceInstanceFor( | |
56 BrowserContext* context) const override { | |
57 return new WebUSBPermissionStore(context); | |
58 } | |
Bernhard Bauer
2015/10/01 08:31:25
DISALLOW_COPY_AND_ASSIGN
| |
59 }; | |
60 | |
61 bool CanStorePersistentEntry(const scoped_refptr<UsbDevice>& device) { | |
62 return !device->serial_number().empty(); | |
63 } | |
64 | |
65 class USBDeviceEntry { | |
66 public: | |
67 static scoped_ptr<USBDeviceEntry> FindForDevice( | |
68 const base::DictionaryValue& value, | |
69 scoped_refptr<UsbDevice> device) { | |
70 const base::ListValue* device_list; | |
71 if (!value.GetList(kDeviceListKey, &device_list)) | |
72 return nullptr; | |
73 | |
74 scoped_ptr<USBDeviceEntry> entry(new USBDeviceEntry()); | |
75 for (size_t i = 0; i < device_list->GetSize(); ++i) { | |
76 const base::DictionaryValue* device_dict; | |
77 if (!device_list->GetDictionary(i, &device_dict)) | |
78 continue; | |
79 | |
80 if (!device_dict->GetString(kDeviceNameKey, &entry->device_name_) || | |
81 !device_dict->GetInteger(kVendorIdKey, &entry->vendor_id_) || | |
82 !device_dict->GetInteger(kProductIdKey, &entry->product_id_) || | |
83 !device_dict->GetString(kSerialNumberKey, &entry->serial_number_)) | |
84 continue; | |
85 | |
86 if (entry->device_name_.empty()) | |
87 continue; | |
88 | |
89 if (entry->vendor_id_ != device->vendor_id() || | |
90 entry->product_id_ != device->product_id() || | |
91 entry->serial_number_ != device->serial_number()) | |
92 continue; | |
93 | |
94 entry->found_in_list_ = true; | |
95 entry->list_index_ = i; | |
96 return entry.Pass(); | |
97 } | |
98 return nullptr; | |
99 } | |
100 | |
101 USBDeviceEntry() {} | |
102 | |
103 explicit USBDeviceEntry(scoped_refptr<UsbDevice> device) { | |
Ken Rockot(use gerrit already)
2015/10/01 01:26:32
nit: const scoped_refptr<UsbDevice>& here and else
| |
104 device_name_ = device->product_string(); | |
105 vendor_id_ = device->vendor_id(); | |
106 product_id_ = device->product_id(); | |
107 serial_number_ = device->serial_number(); | |
108 } | |
109 | |
110 ~USBDeviceEntry() {} | |
111 | |
112 void AddToDeviceList(base::DictionaryValue* value) { | |
113 DCHECK(!found_in_list_); | |
114 scoped_ptr<base::DictionaryValue> device_dict(new base::DictionaryValue()); | |
115 device_dict->SetString(kDeviceNameKey, device_name_); | |
116 device_dict->SetInteger(kVendorIdKey, vendor_id_); | |
117 device_dict->SetInteger(kProductIdKey, product_id_); | |
118 device_dict->SetString(kSerialNumberKey, serial_number_); | |
119 | |
120 base::ListValue* device_list; | |
121 if (!value->GetList(kDeviceListKey, &device_list)) { | |
122 device_list = new base::ListValue(); | |
123 value->Set(kDeviceListKey, device_list); | |
124 } | |
125 | |
126 device_list->Append(device_dict.Pass()); | |
127 } | |
128 | |
129 void RemoveFromDeviceList(base::DictionaryValue* value) { | |
130 DCHECK(found_in_list_); | |
131 base::ListValue* device_list; | |
Bernhard Bauer
2015/10/01 08:31:25
Initialize to nullptr? Otherwise you might derefer
| |
132 if (!value->GetList(kDeviceListKey, &device_list)) | |
133 NOTREACHED(); | |
Bernhard Bauer
2015/10/01 08:31:25
Instead of `if (...) NOTREACHED()`, store a succes
| |
134 | |
135 bool removed = device_list->Remove(list_index_, nullptr); | |
136 DCHECK(removed); | |
137 } | |
138 | |
139 private: | |
140 base::string16 device_name_; | |
141 int vendor_id_; | |
142 int product_id_; | |
143 base::string16 serial_number_; | |
144 bool found_in_list_ = false; | |
145 size_t list_index_; | |
Bernhard Bauer
2015/10/01 08:31:25
DISALLOW_COPY_AND_ASSIGN
| |
146 }; | |
147 | |
148 scoped_ptr<base::DictionaryValue> GetDictionaryForOrigin( | |
149 HostContentSettingsMap* settings, | |
150 const GURL& origin_url) { | |
151 if (!settings) | |
152 return nullptr; | |
153 | |
154 scoped_ptr<base::DictionaryValue> value = | |
155 base::DictionaryValue::From(settings->GetWebsiteSetting( | |
156 origin_url, origin_url, CONTENT_SETTINGS_TYPE_USB, std::string(), | |
157 nullptr)); | |
158 if (!value) { | |
Bernhard Bauer
2015/10/01 08:31:25
Nit: Braces are optional for single-line bodies, a
| |
159 return make_scoped_ptr(new base::DictionaryValue()); | |
160 } | |
161 | |
162 return value.Pass(); | |
163 } | |
164 | |
165 void SetDictionaryForOrigin(HostContentSettingsMap* settings, | |
166 const GURL& origin_url, | |
167 scoped_ptr<base::Value> value) { | |
168 if (!settings) | |
169 return; | |
170 | |
171 ContentSettingsPattern pattern( | |
172 ContentSettingsPattern::FromURLNoWildcard(origin_url)); | |
173 if (!pattern.IsValid()) | |
174 return; | |
175 | |
176 settings->SetWebsiteSetting(pattern, ContentSettingsPattern::Wildcard(), | |
177 CONTENT_SETTINGS_TYPE_USB, std::string(), | |
178 value.release()); | |
179 } | |
180 | |
181 } // namespace | |
182 | |
183 // static | |
184 WebUSBPermissionStore* WebUSBPermissionStore::Get(BrowserContext* context) { | |
185 return WebUSBPermissionStoreFactory::GetForBrowserContext(context); | |
186 } | |
187 | |
188 WebUSBPermissionStore::WebUSBPermissionStore(BrowserContext* context) | |
189 : observer_(this) { | |
190 usb_service_ = device::DeviceClient::Get()->GetUsbService(); | |
191 if (usb_service_) | |
192 observer_.Add(usb_service_); | |
193 Profile* profile = Profile::FromBrowserContext(context); | |
194 host_content_settings_map_ = | |
195 HostContentSettingsMapFactory::GetForProfile(profile); | |
196 } | |
197 | |
198 WebUSBPermissionStore::~WebUSBPermissionStore() {} | |
199 | |
200 void WebUSBPermissionStore::GrantDevicePermission(const GURL& origin, | |
201 const std::string& guid) { | |
202 DCHECK_EQ(origin, origin.GetOrigin()); | |
203 scoped_refptr<UsbDevice> device = usb_service_->GetDevice(guid); | |
204 if (!device) | |
205 return; | |
206 | |
207 if (CanStorePersistentEntry(device)) { | |
208 USBDeviceEntry entry(device); | |
209 scoped_ptr<base::DictionaryValue> value = | |
210 GetDictionaryForOrigin(host_content_settings_map_, origin); | |
211 entry.AddToDeviceList(value.get()); | |
212 SetDictionaryForOrigin(host_content_settings_map_, origin, value.Pass()); | |
213 } else { | |
214 ephemeral_devices_[origin].insert(guid); | |
215 } | |
216 } | |
217 | |
218 void WebUSBPermissionStore::RevokeDevicePermission(const GURL& origin, | |
219 const std::string& guid) { | |
220 DCHECK_EQ(origin, origin.GetOrigin()); | |
221 auto it = ephemeral_devices_.find(origin); | |
222 if (it != ephemeral_devices_.end()) { | |
223 it->second.erase(guid); | |
224 if (it->second.empty()) | |
225 ephemeral_devices_.erase(it); | |
226 } | |
227 | |
228 scoped_refptr<UsbDevice> device = usb_service_->GetDevice(guid); | |
229 if (!device) | |
230 return; | |
231 | |
232 scoped_ptr<base::DictionaryValue> value = | |
233 GetDictionaryForOrigin(host_content_settings_map_, origin); | |
234 scoped_ptr<USBDeviceEntry> entry = | |
235 USBDeviceEntry::FindForDevice(*value, device); | |
236 if (entry) { | |
237 entry->RemoveFromDeviceList(value.get()); | |
238 SetDictionaryForOrigin(host_content_settings_map_, origin, value.Pass()); | |
239 } | |
240 } | |
241 | |
242 bool WebUSBPermissionStore::HasDevicePermission(const GURL& origin, | |
243 const std::string& guid) { | |
244 DCHECK_EQ(origin, origin.GetOrigin()); | |
245 auto it = ephemeral_devices_.find(origin); | |
246 if (it != ephemeral_devices_.end()) | |
247 return ContainsValue(it->second, guid); | |
248 | |
249 scoped_refptr<UsbDevice> device = usb_service_->GetDevice(guid); | |
250 if (!device) | |
251 return false; | |
252 | |
253 scoped_ptr<base::DictionaryValue> value = | |
254 GetDictionaryForOrigin(host_content_settings_map_, origin); | |
255 return USBDeviceEntry::FindForDevice(*value, device); | |
256 } | |
257 | |
258 void WebUSBPermissionStore::OnDeviceRemoved(scoped_refptr<UsbDevice> device) { | |
259 for (auto& map_entry : ephemeral_devices_) | |
260 map_entry.second.erase(device->guid()); | |
261 } | |
OLD | NEW |