Check USB device path access when prompting users to select a device.
[chromium-blink-merge.git] / chrome / browser / notifications / desktop_notification_service.cc
blob7c91e9d47f55fca425c84794760a65c727683a6a
1 // Copyright (c) 2012 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.
5 #include "chrome/browser/notifications/desktop_notification_service.h"
7 #include "base/bind.h"
8 #include "base/metrics/histogram.h"
9 #include "base/metrics/histogram_macros.h"
10 #include "base/prefs/scoped_user_pref_update.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "chrome/browser/browser_process.h"
13 #include "chrome/browser/notifications/desktop_notification_profile_util.h"
14 #include "chrome/browser/notifications/notification.h"
15 #include "chrome/browser/notifications/notification_object_proxy.h"
16 #include "chrome/browser/notifications/notification_ui_manager.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/ui/browser.h"
19 #include "chrome/common/pref_names.h"
20 #include "components/content_settings/core/common/permission_request_id.h"
21 #include "components/pref_registry/pref_registry_syncable.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "ui/base/webui/web_ui_util.h"
24 #include "ui/message_center/notifier_settings.h"
26 #if defined(ENABLE_EXTENSIONS)
27 #include "chrome/browser/extensions/api/notifications/notifications_api.h"
28 #include "chrome/browser/extensions/extension_service.h"
29 #include "extensions/browser/event_router.h"
30 #include "extensions/browser/extension_registry.h"
31 #include "extensions/browser/extension_system.h"
32 #include "extensions/browser/extension_util.h"
33 #include "extensions/browser/info_map.h"
34 #include "extensions/browser/suggest_permission_util.h"
35 #include "extensions/common/constants.h"
36 #include "extensions/common/extension.h"
37 #include "extensions/common/extension_set.h"
38 #endif
40 using content::BrowserThread;
41 using message_center::NotifierId;
43 // DesktopNotificationService -------------------------------------------------
45 // static
46 void DesktopNotificationService::RegisterProfilePrefs(
47 user_prefs::PrefRegistrySyncable* registry) {
48 registry->RegisterListPref(
49 prefs::kMessageCenterDisabledExtensionIds,
50 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
51 registry->RegisterListPref(
52 prefs::kMessageCenterDisabledSystemComponentIds,
53 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
56 DesktopNotificationService::DesktopNotificationService(Profile* profile)
57 : PermissionContextBase(profile, CONTENT_SETTINGS_TYPE_NOTIFICATIONS),
58 profile_(profile)
59 #if defined(ENABLE_EXTENSIONS)
61 extension_registry_observer_(this)
62 #endif
64 OnStringListPrefChanged(
65 prefs::kMessageCenterDisabledExtensionIds, &disabled_extension_ids_);
66 OnStringListPrefChanged(
67 prefs::kMessageCenterDisabledSystemComponentIds,
68 &disabled_system_component_ids_);
69 disabled_extension_id_pref_.Init(
70 prefs::kMessageCenterDisabledExtensionIds,
71 profile_->GetPrefs(),
72 base::Bind(
73 &DesktopNotificationService::OnStringListPrefChanged,
74 base::Unretained(this),
75 base::Unretained(prefs::kMessageCenterDisabledExtensionIds),
76 base::Unretained(&disabled_extension_ids_)));
77 disabled_system_component_id_pref_.Init(
78 prefs::kMessageCenterDisabledSystemComponentIds,
79 profile_->GetPrefs(),
80 base::Bind(
81 &DesktopNotificationService::OnStringListPrefChanged,
82 base::Unretained(this),
83 base::Unretained(prefs::kMessageCenterDisabledSystemComponentIds),
84 base::Unretained(&disabled_system_component_ids_)));
85 #if defined(ENABLE_EXTENSIONS)
86 extension_registry_observer_.Add(
87 extensions::ExtensionRegistry::Get(profile_));
88 #endif
91 DesktopNotificationService::~DesktopNotificationService() {
94 void DesktopNotificationService::RequestNotificationPermission(
95 content::WebContents* web_contents,
96 const PermissionRequestID& request_id,
97 const GURL& requesting_origin,
98 bool user_gesture,
99 const BrowserPermissionCallback& result_callback) {
100 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
102 #if defined(ENABLE_EXTENSIONS)
103 extensions::InfoMap* extension_info_map =
104 extensions::ExtensionSystem::Get(profile_)->info_map();
105 const extensions::Extension* extension = NULL;
106 if (extension_info_map) {
107 extensions::ExtensionSet extensions;
108 extension_info_map->GetExtensionsWithAPIPermissionForSecurityOrigin(
109 requesting_origin,
110 request_id.render_process_id(),
111 extensions::APIPermission::kNotifications,
112 &extensions);
113 for (extensions::ExtensionSet::const_iterator iter = extensions.begin();
114 iter != extensions.end(); ++iter) {
115 if (IsNotifierEnabled(NotifierId(
116 NotifierId::APPLICATION, (*iter)->id()))) {
117 extension = iter->get();
118 break;
122 if (IsExtensionWithPermissionOrSuggestInConsole(
123 extensions::APIPermission::kNotifications,
124 extension,
125 web_contents->GetRenderViewHost())) {
126 result_callback.Run(CONTENT_SETTING_ALLOW);
127 return;
129 #endif
131 // Track whether the requesting and embedding origins are different when
132 // permission to display Web Notifications is being requested.
133 UMA_HISTOGRAM_BOOLEAN("Notifications.DifferentRequestingEmbeddingOrigins",
134 requesting_origin.GetOrigin() !=
135 web_contents->GetLastCommittedURL().GetOrigin());
137 RequestPermission(web_contents,
138 request_id,
139 requesting_origin,
140 user_gesture,
141 result_callback);
144 bool DesktopNotificationService::IsNotifierEnabled(
145 const NotifierId& notifier_id) const {
146 switch (notifier_id.type) {
147 case NotifierId::APPLICATION:
148 return disabled_extension_ids_.find(notifier_id.id) ==
149 disabled_extension_ids_.end();
150 case NotifierId::WEB_PAGE:
151 return DesktopNotificationProfileUtil::GetContentSetting(
152 profile_, notifier_id.url) == CONTENT_SETTING_ALLOW;
153 case NotifierId::SYSTEM_COMPONENT:
154 #if defined(OS_CHROMEOS)
155 return disabled_system_component_ids_.find(notifier_id.id) ==
156 disabled_system_component_ids_.end();
157 #else
158 // We do not disable system component notifications.
159 return true;
160 #endif
163 NOTREACHED();
164 return false;
167 void DesktopNotificationService::SetNotifierEnabled(
168 const NotifierId& notifier_id,
169 bool enabled) {
170 DCHECK_NE(NotifierId::WEB_PAGE, notifier_id.type);
172 bool add_new_item = false;
173 const char* pref_name = NULL;
174 scoped_ptr<base::StringValue> id;
175 switch (notifier_id.type) {
176 case NotifierId::APPLICATION:
177 pref_name = prefs::kMessageCenterDisabledExtensionIds;
178 add_new_item = !enabled;
179 id.reset(new base::StringValue(notifier_id.id));
180 FirePermissionLevelChangedEvent(notifier_id, enabled);
181 break;
182 case NotifierId::SYSTEM_COMPONENT:
183 #if defined(OS_CHROMEOS)
184 pref_name = prefs::kMessageCenterDisabledSystemComponentIds;
185 add_new_item = !enabled;
186 id.reset(new base::StringValue(notifier_id.id));
187 #else
188 return;
189 #endif
190 break;
191 default:
192 NOTREACHED();
194 DCHECK(pref_name != NULL);
196 ListPrefUpdate update(profile_->GetPrefs(), pref_name);
197 base::ListValue* const list = update.Get();
198 if (add_new_item) {
199 // AppendIfNotPresent will delete |adding_value| when the same value
200 // already exists.
201 list->AppendIfNotPresent(id.release());
202 } else {
203 list->Remove(*id, NULL);
207 void DesktopNotificationService::OnStringListPrefChanged(
208 const char* pref_name, std::set<std::string>* ids_field) {
209 ids_field->clear();
210 // Separate GetPrefs()->GetList() to analyze the crash. See crbug.com/322320
211 const PrefService* pref_service = profile_->GetPrefs();
212 CHECK(pref_service);
213 const base::ListValue* pref_list = pref_service->GetList(pref_name);
214 for (size_t i = 0; i < pref_list->GetSize(); ++i) {
215 std::string element;
216 if (pref_list->GetString(i, &element) && !element.empty())
217 ids_field->insert(element);
218 else
219 LOG(WARNING) << i << "-th element is not a string for " << pref_name;
223 #if defined(ENABLE_EXTENSIONS)
224 void DesktopNotificationService::OnExtensionUninstalled(
225 content::BrowserContext* browser_context,
226 const extensions::Extension* extension,
227 extensions::UninstallReason reason) {
228 NotifierId notifier_id(NotifierId::APPLICATION, extension->id());
229 if (IsNotifierEnabled(notifier_id))
230 return;
232 // The settings for ephemeral apps will be persisted across cache evictions.
233 if (extensions::util::IsEphemeralApp(extension->id(), profile_))
234 return;
236 SetNotifierEnabled(notifier_id, true);
238 #endif
240 // Unlike other permission types, granting a notification for a given origin
241 // will not take into account the |embedder_origin|, it will only be based
242 // on the requesting iframe origin.
243 // TODO(mukai) Consider why notifications behave differently than
244 // other permissions. crbug.com/416894
245 void DesktopNotificationService::UpdateContentSetting(
246 const GURL& requesting_origin,
247 const GURL& embedder_origin,
248 ContentSetting content_setting) {
249 DCHECK(content_setting == CONTENT_SETTING_ALLOW ||
250 content_setting == CONTENT_SETTING_BLOCK);
252 if (content_setting == CONTENT_SETTING_ALLOW) {
253 DesktopNotificationProfileUtil::GrantPermission(
254 profile_, requesting_origin);
255 } else {
256 DesktopNotificationProfileUtil::DenyPermission(profile_, requesting_origin);
260 void DesktopNotificationService::FirePermissionLevelChangedEvent(
261 const NotifierId& notifier_id, bool enabled) {
262 #if defined(ENABLE_EXTENSIONS)
263 DCHECK_EQ(NotifierId::APPLICATION, notifier_id.type);
264 extensions::api::notifications::PermissionLevel permission =
265 enabled ? extensions::api::notifications::PERMISSION_LEVEL_GRANTED
266 : extensions::api::notifications::PERMISSION_LEVEL_DENIED;
267 scoped_ptr<base::ListValue> args(new base::ListValue());
268 args->Append(new base::StringValue(
269 extensions::api::notifications::ToString(permission)));
270 scoped_ptr<extensions::Event> event(new extensions::Event(
271 extensions::api::notifications::OnPermissionLevelChanged::kEventName,
272 args.Pass()));
273 extensions::EventRouter::Get(profile_)
274 ->DispatchEventToExtension(notifier_id.id, event.Pass());
276 // Tell the IO thread that this extension's permission for notifications
277 // has changed.
278 extensions::InfoMap* extension_info_map =
279 extensions::ExtensionSystem::Get(profile_)->info_map();
280 BrowserThread::PostTask(
281 BrowserThread::IO, FROM_HERE,
282 base::Bind(&extensions::InfoMap::SetNotificationsDisabled,
283 extension_info_map, notifier_id.id, !enabled));
284 #endif