Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(385)

Side by Side Diff: chrome/browser/usb/web_usb_permission_store.cc

Issue 1382783002: Store USB device permissions in website settings. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698