• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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 
6 #include "chrome/browser/content_settings/content_settings_notification_provider.h"
7 
8 #include "base/string_util.h"
9 #include "chrome/browser/notifications/desktop_notification_service_factory.h"
10 #include "chrome/browser/notifications/notification.h"
11 #include "chrome/browser/notifications/notifications_prefs_cache.h"
12 #include "chrome/browser/notifications/notification_ui_manager.h"
13 #include "chrome/browser/prefs/pref_service.h"
14 #include "chrome/browser/prefs/scoped_user_pref_update.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/common/content_settings_types.h"
17 #include "chrome/common/pref_names.h"
18 #include "chrome/common/url_constants.h"
19 #include "content/common/notification_service.h"
20 #include "content/common/notification_type.h"
21 #include "googleurl/src/gurl.h"
22 
23 namespace {
24 
25 const ContentSetting kDefaultSetting = CONTENT_SETTING_ASK;
26 
27 }  // namespace
28 
29 namespace content_settings {
30 
31 // ////////////////////////////////////////////////////////////////////////////
32 // NotificationProvider
33 //
34 
35 // static
RegisterUserPrefs(PrefService * user_prefs)36 void NotificationProvider::RegisterUserPrefs(PrefService* user_prefs) {
37   if (!user_prefs->FindPreference(prefs::kDesktopNotificationAllowedOrigins))
38     user_prefs->RegisterListPref(prefs::kDesktopNotificationAllowedOrigins);
39   if (!user_prefs->FindPreference(prefs::kDesktopNotificationDeniedOrigins))
40     user_prefs->RegisterListPref(prefs::kDesktopNotificationDeniedOrigins);
41 }
42 
43 // TODO(markusheintz): Re-factoring in progress. Do not move or touch the
44 // following two static methods as you might cause trouble. Thanks!
45 
46 // static
ToContentSettingsPattern(const GURL & origin)47 ContentSettingsPattern NotificationProvider::ToContentSettingsPattern(
48     const GURL& origin) {
49   // Fix empty GURLs.
50   if (origin.spec().empty()) {
51     std::string pattern_spec(chrome::kFileScheme);
52     pattern_spec += chrome::kStandardSchemeSeparator;
53     return ContentSettingsPattern(pattern_spec);
54   }
55   return ContentSettingsPattern::FromURLNoWildcard(origin);
56 }
57 
58 // static
ToGURL(const ContentSettingsPattern & pattern)59 GURL NotificationProvider::ToGURL(const ContentSettingsPattern& pattern) {
60   std::string pattern_spec(pattern.AsString());
61 
62   if (pattern_spec.empty() ||
63       StartsWithASCII(pattern_spec,
64                       std::string(ContentSettingsPattern::kDomainWildcard),
65                       true)) {
66     NOTREACHED();
67   }
68 
69   std::string url_spec("");
70   if (StartsWithASCII(pattern_spec, std::string(chrome::kFileScheme), false)) {
71     url_spec += pattern_spec;
72   } else if (!pattern.scheme().empty()) {
73     url_spec += pattern.scheme();
74     url_spec += chrome::kStandardSchemeSeparator;
75     url_spec += pattern_spec;
76   }
77 
78   return GURL(url_spec);
79 }
80 
NotificationProvider(Profile * profile)81 NotificationProvider::NotificationProvider(
82     Profile* profile)
83     : profile_(profile) {
84   prefs_registrar_.Init(profile_->GetPrefs());
85   StartObserving();
86 }
87 
~NotificationProvider()88 NotificationProvider::~NotificationProvider() {
89   StopObserving();
90 }
91 
ContentSettingsTypeIsManaged(ContentSettingsType content_type)92 bool NotificationProvider::ContentSettingsTypeIsManaged(
93       ContentSettingsType content_type) {
94   return false;
95 }
96 
GetContentSetting(const GURL & requesting_url,const GURL & embedding_url,ContentSettingsType content_type,const ResourceIdentifier & resource_identifier) const97 ContentSetting NotificationProvider::GetContentSetting(
98       const GURL& requesting_url,
99       const GURL& embedding_url,
100       ContentSettingsType content_type,
101       const ResourceIdentifier& resource_identifier) const {
102   if (content_type != CONTENT_SETTINGS_TYPE_NOTIFICATIONS)
103     return CONTENT_SETTING_DEFAULT;
104 
105   return GetContentSetting(requesting_url);
106 }
107 
SetContentSetting(const ContentSettingsPattern & requesting_url_pattern,const ContentSettingsPattern & embedding_url_pattern,ContentSettingsType content_type,const ResourceIdentifier & resource_identifier,ContentSetting content_setting)108 void NotificationProvider::SetContentSetting(
109       const ContentSettingsPattern& requesting_url_pattern,
110       const ContentSettingsPattern& embedding_url_pattern,
111       ContentSettingsType content_type,
112       const ResourceIdentifier& resource_identifier,
113       ContentSetting content_setting) {
114   if (content_type != CONTENT_SETTINGS_TYPE_NOTIFICATIONS)
115     return;
116 
117   GURL origin = ToGURL(requesting_url_pattern);
118   if (CONTENT_SETTING_ALLOW == content_setting) {
119     GrantPermission(origin);
120   } else if (CONTENT_SETTING_BLOCK == content_setting) {
121     DenyPermission(origin);
122   } else if (CONTENT_SETTING_DEFAULT == content_setting) {
123     ContentSetting current_setting = GetContentSetting(origin);
124     if (CONTENT_SETTING_ALLOW == current_setting) {
125       ResetAllowedOrigin(origin);
126     } else if (CONTENT_SETTING_BLOCK == current_setting) {
127       ResetBlockedOrigin(origin);
128     } else {
129       NOTREACHED();
130     }
131   } else {
132       NOTREACHED();
133   }
134 }
135 
GetAllContentSettingsRules(ContentSettingsType content_type,const ResourceIdentifier & resource_identifier,Rules * content_setting_rules) const136 void NotificationProvider::GetAllContentSettingsRules(
137       ContentSettingsType content_type,
138       const ResourceIdentifier& resource_identifier,
139       Rules* content_setting_rules) const {
140   if (content_type != CONTENT_SETTINGS_TYPE_NOTIFICATIONS)
141     return;
142 
143   std::vector<GURL> allowed_origins = GetAllowedOrigins();
144   std::vector<GURL> denied_origins = GetBlockedOrigins();
145 
146   for (std::vector<GURL>::iterator url = allowed_origins.begin();
147        url != allowed_origins.end();
148        ++url) {
149     ContentSettingsPattern pattern =
150         ContentSettingsPattern::FromURLNoWildcard(*url);
151     content_setting_rules->push_back(Rule(
152         pattern,
153         pattern,
154         CONTENT_SETTING_ALLOW));
155   }
156   for (std::vector<GURL>::iterator url = denied_origins.begin();
157        url != denied_origins.end();
158        ++url) {
159     ContentSettingsPattern pattern =
160         ContentSettingsPattern::FromURLNoWildcard(*url);
161     content_setting_rules->push_back(Rule(
162         pattern,
163         pattern,
164         CONTENT_SETTING_BLOCK));
165   }
166 }
167 
ClearAllContentSettingsRules(ContentSettingsType content_type)168 void NotificationProvider::ClearAllContentSettingsRules(
169       ContentSettingsType content_type) {
170   if (content_type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS)
171     ResetAllOrigins();
172 }
173 
ResetToDefaults()174 void NotificationProvider::ResetToDefaults() {
175   ResetAllOrigins();
176 }
177 
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)178 void NotificationProvider::Observe(NotificationType type,
179                                    const NotificationSource& source,
180                                    const NotificationDetails& details) {
181   if (NotificationType::PREF_CHANGED == type) {
182     const std::string& name = *Details<std::string>(details).ptr();
183     OnPrefsChanged(name);
184   } else if (NotificationType::PROFILE_DESTROYED == type) {
185     StopObserving();
186   }
187 }
188 
189 /////////////////////////////////////////////////////////////////////
190 // Private
191 //
192 
StartObserving()193 void NotificationProvider::StartObserving() {
194   if (!profile_->IsOffTheRecord()) {
195     prefs_registrar_.Add(prefs::kDesktopNotificationDefaultContentSetting,
196                          this);
197     prefs_registrar_.Add(prefs::kDesktopNotificationAllowedOrigins, this);
198     prefs_registrar_.Add(prefs::kDesktopNotificationDeniedOrigins, this);
199 
200     notification_registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
201                                 NotificationService::AllSources());
202   }
203 
204   notification_registrar_.Add(this, NotificationType::PROFILE_DESTROYED,
205                               Source<Profile>(profile_));
206 }
207 
StopObserving()208 void NotificationProvider::StopObserving() {
209   if (!profile_->IsOffTheRecord()) {
210     prefs_registrar_.RemoveAll();
211   }
212   notification_registrar_.RemoveAll();
213 }
214 
OnPrefsChanged(const std::string & pref_name)215 void NotificationProvider::OnPrefsChanged(const std::string& pref_name) {
216   if (pref_name == prefs::kDesktopNotificationAllowedOrigins) {
217     NotifySettingsChange();
218   } else if (pref_name == prefs::kDesktopNotificationDeniedOrigins) {
219     NotifySettingsChange();
220   }
221 }
222 
NotifySettingsChange()223 void NotificationProvider::NotifySettingsChange() {
224   // TODO(markusheintz): Re-factoring work in progress: Replace the
225   // DESKTOP_NOTIFICATION_SETTINGS_CHANGED with a CONTENT_SETTINGS_CHANGED
226   // notification, and use the HostContentSettingsMap as source once this
227   // content settings provider in integrated in the HostContentSetttingsMap.
228   NotificationService::current()->Notify(
229       NotificationType::DESKTOP_NOTIFICATION_SETTINGS_CHANGED,
230       Source<DesktopNotificationService>(
231           DesktopNotificationServiceFactory::GetForProfile(profile_)),
232       NotificationService::NoDetails());
233 }
234 
GetAllowedOrigins() const235 std::vector<GURL> NotificationProvider::GetAllowedOrigins() const {
236   std::vector<GURL> allowed_origins;
237   PrefService* prefs = profile_->GetPrefs();
238   const ListValue* allowed_sites =
239       prefs->GetList(prefs::kDesktopNotificationAllowedOrigins);
240   if (allowed_sites) {
241     // TODO(markusheintz): Remove dependency to PrefsCache
242     NotificationsPrefsCache::ListValueToGurlVector(*allowed_sites,
243                                                    &allowed_origins);
244   }
245   return allowed_origins;
246 }
247 
GetBlockedOrigins() const248 std::vector<GURL> NotificationProvider::GetBlockedOrigins() const {
249   std::vector<GURL> denied_origins;
250   PrefService* prefs = profile_->GetPrefs();
251   const ListValue* denied_sites =
252       prefs->GetList(prefs::kDesktopNotificationDeniedOrigins);
253   if (denied_sites) {
254      // TODO(markusheintz): Remove dependency to PrefsCache
255     NotificationsPrefsCache::ListValueToGurlVector(*denied_sites,
256                                                    &denied_origins);
257   }
258   return denied_origins;
259 }
260 
GrantPermission(const GURL & origin)261 void NotificationProvider::GrantPermission(const GURL& origin) {
262   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
263   PersistPermissionChange(origin, true);
264   NotifySettingsChange();
265 }
266 
DenyPermission(const GURL & origin)267 void NotificationProvider::DenyPermission(const GURL& origin) {
268   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
269   PersistPermissionChange(origin, false);
270   NotifySettingsChange();
271 }
272 
PersistPermissionChange(const GURL & origin,bool is_allowed)273 void NotificationProvider::PersistPermissionChange(
274     const GURL& origin, bool is_allowed) {
275   // Don't persist changes when incognito.
276   if (profile_->IsOffTheRecord())
277     return;
278   PrefService* prefs = profile_->GetPrefs();
279 
280   // |Observe()| updates the whole permission set in the cache, but only a
281   // single origin has changed. Hence, callers of this method manually
282   // schedule a task to update the prefs cache, and the prefs observer is
283   // disabled while the update runs.
284   StopObserving();
285 
286   bool allowed_changed = false;
287   bool denied_changed = false;
288 
289   {
290     ListPrefUpdate update_allowed_sites(
291         prefs, prefs::kDesktopNotificationAllowedOrigins);
292     ListPrefUpdate update_denied_sites(
293         prefs, prefs::kDesktopNotificationDeniedOrigins);
294     ListValue* allowed_sites = update_allowed_sites.Get();
295     ListValue* denied_sites = update_denied_sites.Get();
296     // |value| is passed to the preferences list, or deleted.
297     StringValue* value = new StringValue(origin.spec());
298 
299     // Remove from one list and add to the other.
300     if (is_allowed) {
301       // Remove from the denied list.
302       if (denied_sites->Remove(*value) != -1)
303         denied_changed = true;
304 
305       // Add to the allowed list.
306       if (allowed_sites->AppendIfNotPresent(value))
307         allowed_changed = true;
308     } else {
309       // Remove from the allowed list.
310       if (allowed_sites->Remove(*value) != -1)
311         allowed_changed = true;
312 
313       // Add to the denied list.
314       if (denied_sites->AppendIfNotPresent(value))
315         denied_changed = true;
316     }
317   }
318 
319   // Persist the pref if anthing changed, but only send updates for the
320   // list that changed.
321   if (allowed_changed || denied_changed)
322     prefs->ScheduleSavePersistentPrefs();
323   StartObserving();
324 }
325 
GetContentSetting(const GURL & origin) const326 ContentSetting NotificationProvider::GetContentSetting(
327     const GURL& origin) const {
328   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
329 
330   if (profile_->IsOffTheRecord())
331     return kDefaultSetting;
332 
333   std::vector<GURL> allowed_origins(GetAllowedOrigins());
334   if (std::find(allowed_origins.begin(), allowed_origins.end(), origin) !=
335       allowed_origins.end())
336     return CONTENT_SETTING_ALLOW;
337 
338   std::vector<GURL> denied_origins(GetBlockedOrigins());
339   if (std::find(denied_origins.begin(), denied_origins.end(), origin) !=
340       denied_origins.end())
341     return CONTENT_SETTING_BLOCK;
342 
343   return CONTENT_SETTING_DEFAULT;
344 }
345 
ResetAllowedOrigin(const GURL & origin)346 void NotificationProvider::ResetAllowedOrigin(const GURL& origin) {
347   if (profile_->IsOffTheRecord())
348     return;
349 
350   // Since this isn't called often, let the normal observer behavior update the
351   // cache in this case.
352   PrefService* prefs = profile_->GetPrefs();
353   {
354     ListPrefUpdate update(prefs, prefs::kDesktopNotificationAllowedOrigins);
355     ListValue* allowed_sites = update.Get();
356     StringValue value(origin.spec());
357     int removed_index = allowed_sites->Remove(value);
358     DCHECK_NE(-1, removed_index) << origin << " was not allowed";
359   }
360   prefs->ScheduleSavePersistentPrefs();
361 }
362 
ResetBlockedOrigin(const GURL & origin)363 void NotificationProvider::ResetBlockedOrigin(const GURL& origin) {
364   if (profile_->IsOffTheRecord())
365     return;
366 
367   // Since this isn't called often, let the normal observer behavior update the
368   // cache in this case.
369   PrefService* prefs = profile_->GetPrefs();
370   {
371     ListPrefUpdate update(prefs, prefs::kDesktopNotificationDeniedOrigins);
372     ListValue* denied_sites = update.Get();
373     StringValue value(origin.spec());
374     int removed_index = denied_sites->Remove(value);
375     DCHECK_NE(-1, removed_index) << origin << " was not blocked";
376   }
377   prefs->ScheduleSavePersistentPrefs();
378 }
379 
ResetAllOrigins()380 void NotificationProvider::ResetAllOrigins() {
381   PrefService* prefs = profile_->GetPrefs();
382   prefs->ClearPref(prefs::kDesktopNotificationAllowedOrigins);
383   prefs->ClearPref(prefs::kDesktopNotificationDeniedOrigins);
384 }
385 
386 }  // namespace content_settings
387