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/ui/webui/options/content_settings_handler.h"
11 #include "base/bind.h"
12 #include "base/bind_helpers.h"
13 #include "base/command_line.h"
14 #include "base/prefs/pref_service.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/values.h"
18 #include "chrome/browser/browser_process.h"
19 #include "chrome/browser/chrome_notification_types.h"
20 #include "chrome/browser/custom_handlers/protocol_handler_registry.h"
21 #include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h"
22 #include "chrome/browser/extensions/extension_special_storage_policy.h"
23 #include "chrome/browser/notifications/desktop_notification_profile_util.h"
24 #include "chrome/browser/profiles/profile.h"
25 #include "chrome/browser/ui/browser_list.h"
26 #include "chrome/common/chrome_switches.h"
27 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
28 #include "chrome/common/pref_names.h"
29 #include "chrome/common/url_constants.h"
30 #include "chrome/grit/generated_resources.h"
31 #include "chrome/grit/locale_settings.h"
32 #include "components/content_settings/core/browser/content_settings_details.h"
33 #include "components/content_settings/core/browser/content_settings_utils.h"
34 #include "components/content_settings/core/browser/host_content_settings_map.h"
35 #include "components/content_settings/core/common/content_settings.h"
36 #include "components/content_settings/core/common/content_settings_pattern.h"
37 #include "components/google/core/browser/google_util.h"
38 #include "components/user_prefs/user_prefs.h"
39 #include "content/public/browser/notification_service.h"
40 #include "content/public/browser/notification_source.h"
41 #include "content/public/browser/notification_types.h"
42 #include "content/public/browser/user_metrics.h"
43 #include "content/public/browser/web_contents.h"
44 #include "content/public/browser/web_ui.h"
45 #include "content/public/common/content_switches.h"
46 #include "content/public/common/page_zoom.h"
47 #include "content/public/common/url_constants.h"
48 #include "extensions/browser/extension_registry.h"
49 #include "extensions/common/extension_set.h"
50 #include "extensions/common/permissions/api_permission.h"
51 #include "extensions/common/permissions/permissions_data.h"
52 #include "ui/base/l10n/l10n_util.h"
54 #if defined(OS_CHROMEOS)
55 #include "components/user_manager/user_manager.h"
58 using base::UserMetricsAction;
59 using content_settings::ContentSettingToString;
60 using content_settings::ContentSettingFromString;
61 using extensions::APIPermission;
65 struct ContentSettingsTypeNameEntry {
66 ContentSettingsType type;
70 // Maps from a secondary pattern to a setting.
71 typedef std::map<ContentSettingsPattern, ContentSetting>
73 // Maps from a primary pattern/source pair to a OnePatternSettings. All the
74 // mappings in OnePatternSettings share the given primary pattern and source.
75 typedef std::map<std::pair<ContentSettingsPattern, std::string>,
79 // The AppFilter is used in AddExceptionsGrantedByHostedApps() to choose
80 // extensions which should have their extent displayed.
81 typedef bool (*AppFilter)(const extensions::Extension& app,
82 content::BrowserContext* profile);
84 const char kExceptionsLearnMoreUrl[] =
85 "https://support.google.com/chrome/?p=settings_manage_exceptions";
87 const char* kSetting = "setting";
88 const char* kOrigin = "origin";
89 const char* kSource = "source";
90 const char* kAppName = "appName";
91 const char* kAppId = "appId";
92 const char* kEmbeddingOrigin = "embeddingOrigin";
93 const char* kPreferencesSource = "preference";
94 const char* kVideoSetting = "video";
95 const char* kZoom = "zoom";
97 const ContentSettingsTypeNameEntry kContentSettingsTypeGroupNames[] = {
98 {CONTENT_SETTINGS_TYPE_COOKIES, "cookies"},
99 {CONTENT_SETTINGS_TYPE_IMAGES, "images"},
100 {CONTENT_SETTINGS_TYPE_JAVASCRIPT, "javascript"},
101 {CONTENT_SETTINGS_TYPE_PLUGINS, "plugins"},
102 {CONTENT_SETTINGS_TYPE_POPUPS, "popups"},
103 {CONTENT_SETTINGS_TYPE_GEOLOCATION, "location"},
104 {CONTENT_SETTINGS_TYPE_NOTIFICATIONS, "notifications"},
105 {CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE, "auto-select-certificate"},
106 {CONTENT_SETTINGS_TYPE_FULLSCREEN, "fullscreen"},
107 {CONTENT_SETTINGS_TYPE_MOUSELOCK, "mouselock"},
108 {CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS, "register-protocol-handler"},
109 {CONTENT_SETTINGS_TYPE_MEDIASTREAM, "media-stream"},
110 {CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, "media-stream-mic"},
111 {CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, "media-stream-camera"},
112 {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, "ppapi-broker"},
113 {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, "multiple-automatic-downloads"},
114 {CONTENT_SETTINGS_TYPE_MIDI_SYSEX, "midi-sysex"},
115 {CONTENT_SETTINGS_TYPE_PUSH_MESSAGING, "push-messaging"},
116 {CONTENT_SETTINGS_TYPE_SSL_CERT_DECISIONS, "ssl-cert-decisions"},
117 #if defined(OS_CHROMEOS)
118 {CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER, "protectedContent"},
122 // A pseudo content type. We use it to display data like a content setting even
123 // though it is not a real content setting.
124 const char* kZoomContentType = "zoomlevels";
126 content::BrowserContext* GetBrowserContext(content::WebUI* web_ui) {
127 return web_ui->GetWebContents()->GetBrowserContext();
130 ContentSettingsType ContentSettingsTypeFromGroupName(const std::string& name) {
131 for (size_t i = 0; i < arraysize(kContentSettingsTypeGroupNames); ++i) {
132 if (name == kContentSettingsTypeGroupNames[i].name)
133 return kContentSettingsTypeGroupNames[i].type;
136 NOTREACHED() << name << " is not a recognized content settings type.";
137 return CONTENT_SETTINGS_TYPE_DEFAULT;
140 // Create a DictionaryValue* that will act as a data source for a single row
141 // in a HostContentSettingsMap-controlled exceptions table (e.g., cookies).
142 // Ownership of the pointer is passed to the caller.
143 base::DictionaryValue* GetExceptionForPage(
144 const ContentSettingsPattern& pattern,
145 const ContentSettingsPattern& secondary_pattern,
146 const ContentSetting& setting,
147 const std::string& provider_name) {
148 base::DictionaryValue* exception = new base::DictionaryValue();
149 exception->SetString(kOrigin, pattern.ToString());
150 exception->SetString(kEmbeddingOrigin,
151 secondary_pattern == ContentSettingsPattern::Wildcard() ?
153 secondary_pattern.ToString());
154 exception->SetString(kSetting, ContentSettingToString(setting));
155 exception->SetString(kSource, provider_name);
159 // Create a DictionaryValue* that will act as a data source for a single row
160 // in the Geolocation exceptions table. Ownership of the pointer is passed to
162 base::DictionaryValue* GetGeolocationExceptionForPage(
163 const ContentSettingsPattern& origin,
164 const ContentSettingsPattern& embedding_origin,
165 ContentSetting setting) {
166 base::DictionaryValue* exception = new base::DictionaryValue();
167 exception->SetString(kSetting, ContentSettingToString(setting));
168 exception->SetString(kOrigin, origin.ToString());
169 exception->SetString(kEmbeddingOrigin, embedding_origin.ToString());
173 // Create a DictionaryValue* that will act as a data source for a single row
174 // in the desktop notifications exceptions table. Ownership of the pointer is
175 // passed to the caller.
176 base::DictionaryValue* GetNotificationExceptionForPage(
177 const ContentSettingsPattern& primary_pattern,
178 const ContentSettingsPattern& secondary_pattern,
179 ContentSetting setting,
180 const std::string& provider_name) {
181 std::string embedding_origin;
182 if (secondary_pattern != ContentSettingsPattern::Wildcard())
183 embedding_origin = secondary_pattern.ToString();
185 base::DictionaryValue* exception = new base::DictionaryValue();
186 exception->SetString(kSetting, ContentSettingToString(setting));
187 exception->SetString(kOrigin, primary_pattern.ToString());
188 exception->SetString(kEmbeddingOrigin, embedding_origin);
189 exception->SetString(kSource, provider_name);
193 // Returns true whenever the |extension| is hosted and has |permission|.
194 // Must have the AppFilter signature.
195 template <APIPermission::ID permission>
196 bool HostedAppHasPermission(const extensions::Extension& extension,
197 content::BrowserContext* /* context */) {
198 return extension.is_hosted_app() &&
199 extension.permissions_data()->HasAPIPermission(permission);
202 // Add an "Allow"-entry to the list of |exceptions| for a |url_pattern| from
203 // the web extent of a hosted |app|.
204 void AddExceptionForHostedApp(const std::string& url_pattern,
205 const extensions::Extension& app, base::ListValue* exceptions) {
206 base::DictionaryValue* exception = new base::DictionaryValue();
207 exception->SetString(kSetting, ContentSettingToString(CONTENT_SETTING_ALLOW));
208 exception->SetString(kOrigin, url_pattern);
209 exception->SetString(kEmbeddingOrigin, url_pattern);
210 exception->SetString(kSource, "HostedApp");
211 exception->SetString(kAppName, app.name());
212 exception->SetString(kAppId, app.id());
213 exceptions->Append(exception);
216 // Asks the |profile| for hosted apps which have the |permission| set, and
217 // adds their web extent and launch URL to the |exceptions| list.
218 void AddExceptionsGrantedByHostedApps(content::BrowserContext* context,
219 AppFilter app_filter,
220 base::ListValue* exceptions) {
221 const extensions::ExtensionSet& extensions =
222 extensions::ExtensionRegistry::Get(context)->enabled_extensions();
223 for (extensions::ExtensionSet::const_iterator extension = extensions.begin();
224 extension != extensions.end(); ++extension) {
225 if (!app_filter(*extension->get(), context))
228 extensions::URLPatternSet web_extent = (*extension)->web_extent();
229 // Add patterns from web extent.
230 for (extensions::URLPatternSet::const_iterator pattern = web_extent.begin();
231 pattern != web_extent.end(); ++pattern) {
232 std::string url_pattern = pattern->GetAsString();
233 AddExceptionForHostedApp(url_pattern, *extension->get(), exceptions);
235 // Retrieve the launch URL.
237 extensions::AppLaunchInfo::GetLaunchWebURL(extension->get());
238 // Skip adding the launch URL if it is part of the web extent.
239 if (web_extent.MatchesURL(launch_url))
241 AddExceptionForHostedApp(launch_url.spec(), *extension->get(), exceptions);
245 // Sort ZoomLevelChanges by host and scheme
246 // (a.com < http://a.com < https://a.com < b.com).
247 bool HostZoomSort(const content::HostZoomMap::ZoomLevelChange& a,
248 const content::HostZoomMap::ZoomLevelChange& b) {
249 return a.host == b.host ? a.scheme < b.scheme : a.host < b.host;
256 ContentSettingsHandler::MediaSettingsInfo::MediaSettingsInfo()
257 : flash_default_setting(CONTENT_SETTING_DEFAULT),
258 flash_settings_initialized(false),
259 last_flash_refresh_request_id(0),
260 show_flash_default_link(false),
261 show_flash_exceptions_link(false),
262 default_setting(CONTENT_SETTING_DEFAULT),
263 policy_disable_audio(false),
264 policy_disable_video(false),
265 default_setting_initialized(false),
266 exceptions_initialized(false) {
269 ContentSettingsHandler::MediaSettingsInfo::~MediaSettingsInfo() {
272 ContentSettingsHandler::ContentSettingsHandler() : observer_(this) {
275 ContentSettingsHandler::~ContentSettingsHandler() {
278 void ContentSettingsHandler::GetLocalizedValues(
279 base::DictionaryValue* localized_strings) {
280 DCHECK(localized_strings);
282 // TODO(dhnishi): Standardize to lowerCamelCase.
283 static OptionsStringResource resources[] = {
284 { "allowException", IDS_EXCEPTIONS_ALLOW_BUTTON },
285 { "blockException", IDS_EXCEPTIONS_BLOCK_BUTTON },
286 { "sessionException", IDS_EXCEPTIONS_SESSION_ONLY_BUTTON },
287 { "askException", IDS_EXCEPTIONS_ASK_BUTTON },
288 { "otr_exceptions_explanation", IDS_EXCEPTIONS_OTR_LABEL },
289 { "addNewExceptionInstructions", IDS_EXCEPTIONS_ADD_NEW_INSTRUCTIONS },
290 { "manageExceptions", IDS_EXCEPTIONS_MANAGE },
291 { "manage_handlers", IDS_HANDLERS_MANAGE },
292 { "exceptionPatternHeader", IDS_EXCEPTIONS_PATTERN_HEADER },
293 { "exceptionBehaviorHeader", IDS_EXCEPTIONS_ACTION_HEADER },
294 { "exceptionZoomHeader", IDS_EXCEPTIONS_ZOOM_HEADER },
295 { "embeddedOnHost", IDS_EXCEPTIONS_GEOLOCATION_EMBEDDED_ON_HOST },
297 { "cookiesTabLabel", IDS_COOKIES_TAB_LABEL },
298 { "cookies_header", IDS_COOKIES_HEADER },
299 { "cookiesAllow", IDS_COOKIES_ALLOW_RADIO },
300 { "cookiesBlock", IDS_COOKIES_BLOCK_RADIO },
301 { "cookies_session_only", IDS_COOKIES_SESSION_ONLY_RADIO },
302 { "cookies_block_3rd_party", IDS_COOKIES_BLOCK_3RDPARTY_CHKBOX },
303 { "cookies_clear_when_close", IDS_COOKIES_CLEAR_WHEN_CLOSE_CHKBOX },
304 { "cookies_lso_clear_when_close", IDS_COOKIES_LSO_CLEAR_WHEN_CLOSE_CHKBOX },
305 { "cookies_show_cookies", IDS_COOKIES_SHOW_COOKIES_BUTTON },
306 { "flash_storage_settings", IDS_FLASH_STORAGE_SETTINGS },
307 { "flash_storage_url", IDS_FLASH_STORAGE_URL },
308 #if defined(ENABLE_GOOGLE_NOW)
309 { "googleGeolocationAccessEnable",
310 IDS_GEOLOCATION_GOOGLE_ACCESS_ENABLE_CHKBOX },
313 { "imagesTabLabel", IDS_IMAGES_TAB_LABEL },
314 { "images_header", IDS_IMAGES_HEADER },
315 { "imagesAllow", IDS_IMAGES_LOAD_RADIO },
316 { "imagesBlock", IDS_IMAGES_NOLOAD_RADIO },
317 // JavaScript filter.
318 { "javascriptTabLabel", IDS_JAVASCRIPT_TAB_LABEL },
319 { "javascript_header", IDS_JAVASCRIPT_HEADER },
320 { "javascriptAllow", IDS_JS_ALLOW_RADIO },
321 { "javascriptBlock", IDS_JS_DONOTALLOW_RADIO },
323 { "pluginsTabLabel", IDS_PLUGIN_TAB_LABEL },
324 { "plugins_header", IDS_PLUGIN_HEADER },
325 { "pluginsAsk", IDS_PLUGIN_ASK_RADIO },
326 { "pluginsAllow", IDS_PLUGIN_LOAD_RADIO },
327 { "pluginsBlock", IDS_PLUGIN_ASK_MENU_RADIO },
328 { "disableIndividualPlugins", IDS_PLUGIN_SELECTIVE_DISABLE },
330 { "popupsTabLabel", IDS_POPUP_TAB_LABEL },
331 { "popups_header", IDS_POPUP_HEADER },
332 { "popupsAllow", IDS_POPUP_ALLOW_RADIO },
333 { "popupsBlock", IDS_POPUP_BLOCK_RADIO },
335 { "locationTabLabel", IDS_GEOLOCATION_TAB_LABEL },
336 { "location_header", IDS_GEOLOCATION_HEADER },
337 { "locationAllow", IDS_GEOLOCATION_ALLOW_RADIO },
338 { "locationAsk", IDS_GEOLOCATION_ASK_RADIO },
339 { "locationBlock", IDS_GEOLOCATION_BLOCK_RADIO },
340 { "set_by", IDS_GEOLOCATION_SET_BY_HOVER },
341 // Notifications filter.
342 { "notificationsTabLabel", IDS_NOTIFICATIONS_TAB_LABEL },
343 { "notifications_header", IDS_NOTIFICATIONS_HEADER },
344 { "notificationsAllow", IDS_NOTIFICATIONS_ALLOW_RADIO },
345 { "notificationsAsk", IDS_NOTIFICATIONS_ASK_RADIO },
346 { "notificationsBlock", IDS_NOTIFICATIONS_BLOCK_RADIO },
347 // Fullscreen filter.
348 { "fullscreenTabLabel", IDS_FULLSCREEN_TAB_LABEL },
349 { "fullscreen_header", IDS_FULLSCREEN_HEADER },
350 // Mouse Lock filter.
351 { "mouselockTabLabel", IDS_MOUSE_LOCK_TAB_LABEL },
352 { "mouselock_header", IDS_MOUSE_LOCK_HEADER },
353 { "mouselockAllow", IDS_MOUSE_LOCK_ALLOW_RADIO },
354 { "mouselockAsk", IDS_MOUSE_LOCK_ASK_RADIO },
355 { "mouselockBlock", IDS_MOUSE_LOCK_BLOCK_RADIO },
356 #if defined(OS_CHROMEOS) || defined(OS_WIN)
357 // Protected Content filter
358 { "protectedContentTabLabel", IDS_PROTECTED_CONTENT_TAB_LABEL },
359 { "protectedContentInfo", IDS_PROTECTED_CONTENT_INFO },
360 { "protectedContentEnable", IDS_PROTECTED_CONTENT_ENABLE },
361 { "protectedContent_header", IDS_PROTECTED_CONTENT_HEADER },
362 #endif // defined(OS_CHROMEOS) || defined(OS_WIN)
363 // Media stream capture device filter.
364 { "mediaStreamTabLabel", IDS_MEDIA_STREAM_TAB_LABEL },
365 { "media-stream_header", IDS_MEDIA_STREAM_HEADER },
366 { "mediaStreamAsk", IDS_MEDIA_STREAM_ASK_RADIO },
367 { "mediaStreamBlock", IDS_MEDIA_STREAM_BLOCK_RADIO },
368 { "mediaStreamAudioAsk", IDS_MEDIA_STREAM_ASK_AUDIO_ONLY_RADIO },
369 { "mediaStreamAudioBlock", IDS_MEDIA_STREAM_BLOCK_AUDIO_ONLY_RADIO },
370 { "mediaStreamVideoAsk", IDS_MEDIA_STREAM_ASK_VIDEO_ONLY_RADIO },
371 { "mediaStreamVideoBlock", IDS_MEDIA_STREAM_BLOCK_VIDEO_ONLY_RADIO },
372 { "mediaStreamBubbleAudio", IDS_MEDIA_STREAM_AUDIO_MANAGED },
373 { "mediaStreamBubbleVideo", IDS_MEDIA_STREAM_VIDEO_MANAGED },
374 { "mediaAudioExceptionHeader", IDS_MEDIA_AUDIO_EXCEPTION_HEADER },
375 { "mediaVideoExceptionHeader", IDS_MEDIA_VIDEO_EXCEPTION_HEADER },
376 { "mediaPepperFlashDefaultDivergedLabel",
377 IDS_MEDIA_PEPPER_FLASH_DEFAULT_DIVERGED_LABEL },
378 { "mediaPepperFlashExceptionsDivergedLabel",
379 IDS_MEDIA_PEPPER_FLASH_EXCEPTIONS_DIVERGED_LABEL },
380 { "mediaPepperFlashChangeLink", IDS_MEDIA_PEPPER_FLASH_CHANGE_LINK },
381 { "mediaPepperFlashGlobalPrivacyURL", IDS_FLASH_GLOBAL_PRIVACY_URL },
382 { "mediaPepperFlashWebsitePrivacyURL", IDS_FLASH_WEBSITE_PRIVACY_URL },
383 // PPAPI broker filter.
384 { "ppapi-broker_header", IDS_PPAPI_BROKER_HEADER },
385 { "ppapiBrokerTabLabel", IDS_PPAPI_BROKER_TAB_LABEL },
386 { "ppapiBrokerAllow", IDS_PPAPI_BROKER_ALLOW_RADIO },
387 { "ppapiBrokerAsk", IDS_PPAPI_BROKER_ASK_RADIO },
388 { "ppapiBrokerBlock", IDS_PPAPI_BROKER_BLOCK_RADIO },
389 // Multiple automatic downloads
390 { "multipleAutomaticDownloadsTabLabel",
391 IDS_AUTOMATIC_DOWNLOADS_TAB_LABEL },
392 { "multiple-automatic-downloads_header",
393 IDS_AUTOMATIC_DOWNLOADS_TAB_LABEL },
394 { "multipleAutomaticDownloadsAllow",
395 IDS_AUTOMATIC_DOWNLOADS_ALLOW_RADIO },
396 { "multipleAutomaticDownloadsAsk",
397 IDS_AUTOMATIC_DOWNLOADS_ASK_RADIO },
398 { "multipleAutomaticDownloadsBlock",
399 IDS_AUTOMATIC_DOWNLOADS_BLOCK_RADIO },
400 // MIDI system exclusive messages
401 { "midi-sysex_header", IDS_MIDI_SYSEX_TAB_LABEL },
402 { "midiSysExAllow", IDS_MIDI_SYSEX_ALLOW_RADIO },
403 { "midiSysExAsk", IDS_MIDI_SYSEX_ASK_RADIO },
404 { "midiSysExBlock", IDS_MIDI_SYSEX_BLOCK_RADIO },
405 // Push messaging strings
406 { "push-messaging_header", IDS_PUSH_MESSAGES_TAB_LABEL },
407 { "pushMessagingAllow", IDS_PUSH_MESSSAGING_ALLOW_RADIO },
408 { "pushMessagingAsk", IDS_PUSH_MESSSAGING_ASK_RADIO },
409 { "pushMessagingBlock", IDS_PUSH_MESSSAGING_BLOCK_RADIO },
410 { "zoomlevels_header", IDS_ZOOMLEVELS_HEADER_AND_TAB_LABEL },
411 { "zoomLevelsManage", IDS_ZOOMLEVELS_MANAGE_BUTTON },
414 RegisterStrings(localized_strings, resources, arraysize(resources));
415 RegisterTitle(localized_strings, "contentSettingsPage",
416 IDS_CONTENT_SETTINGS_TITLE);
418 // Register titles for each of the individual settings whose exception
419 // dialogs will be processed by |ContentSettingsHandler|.
420 RegisterTitle(localized_strings, "cookies",
421 IDS_COOKIES_TAB_LABEL);
422 RegisterTitle(localized_strings, "images",
423 IDS_IMAGES_TAB_LABEL);
424 RegisterTitle(localized_strings, "javascript",
425 IDS_JAVASCRIPT_TAB_LABEL);
426 RegisterTitle(localized_strings, "plugins",
427 IDS_PLUGIN_TAB_LABEL);
428 RegisterTitle(localized_strings, "popups",
429 IDS_POPUP_TAB_LABEL);
430 RegisterTitle(localized_strings, "location",
431 IDS_GEOLOCATION_TAB_LABEL);
432 RegisterTitle(localized_strings, "notifications",
433 IDS_NOTIFICATIONS_TAB_LABEL);
434 RegisterTitle(localized_strings, "fullscreen",
435 IDS_FULLSCREEN_TAB_LABEL);
436 RegisterTitle(localized_strings, "mouselock",
437 IDS_MOUSE_LOCK_TAB_LABEL);
438 #if defined(OS_CHROMEOS)
439 RegisterTitle(localized_strings, "protectedContent",
440 IDS_PROTECTED_CONTENT_TAB_LABEL);
442 RegisterTitle(localized_strings, "media-stream",
443 IDS_MEDIA_STREAM_TAB_LABEL);
444 RegisterTitle(localized_strings, "ppapi-broker",
445 IDS_PPAPI_BROKER_TAB_LABEL);
446 RegisterTitle(localized_strings, "multiple-automatic-downloads",
447 IDS_AUTOMATIC_DOWNLOADS_TAB_LABEL);
448 RegisterTitle(localized_strings, "midi-sysex",
449 IDS_MIDI_SYSEX_TAB_LABEL);
450 RegisterTitle(localized_strings, "zoomlevels",
451 IDS_ZOOMLEVELS_HEADER_AND_TAB_LABEL);
453 localized_strings->SetString("exceptionsLearnMoreUrl",
454 kExceptionsLearnMoreUrl);
457 void ContentSettingsHandler::InitializeHandler() {
458 notification_registrar_.Add(
459 this, chrome::NOTIFICATION_PROFILE_CREATED,
460 content::NotificationService::AllSources());
461 notification_registrar_.Add(
462 this, chrome::NOTIFICATION_PROFILE_DESTROYED,
463 content::NotificationService::AllSources());
465 notification_registrar_.Add(
466 this, chrome::NOTIFICATION_DESKTOP_NOTIFICATION_SETTINGS_CHANGED,
467 content::NotificationService::AllSources());
468 content::BrowserContext* context = GetBrowserContext(web_ui());
469 notification_registrar_.Add(
470 this, chrome::NOTIFICATION_PROTOCOL_HANDLER_REGISTRY_CHANGED,
471 content::Source<content::BrowserContext>(context));
473 PrefService* prefs = user_prefs::UserPrefs::Get(context);
474 pref_change_registrar_.Init(prefs);
475 pref_change_registrar_.Add(
476 prefs::kPepperFlashSettingsEnabled,
477 base::Bind(&ContentSettingsHandler::OnPepperFlashPrefChanged,
478 base::Unretained(this)));
479 pref_change_registrar_.Add(
480 prefs::kAudioCaptureAllowed,
481 base::Bind(&ContentSettingsHandler::UpdateMediaSettingsView,
482 base::Unretained(this)));
483 pref_change_registrar_.Add(
484 prefs::kVideoCaptureAllowed,
485 base::Bind(&ContentSettingsHandler::UpdateMediaSettingsView,
486 base::Unretained(this)));
487 pref_change_registrar_.Add(
490 &ContentSettingsHandler::UpdateProtectedContentExceptionsButton,
491 base::Unretained(this)));
493 content::HostZoomMap* host_zoom_map =
494 content::HostZoomMap::GetDefaultForBrowserContext(context);
495 host_zoom_map_subscription_ =
496 host_zoom_map->AddZoomLevelChangedCallback(
497 base::Bind(&ContentSettingsHandler::OnZoomLevelChanged,
498 base::Unretained(this)));
500 flash_settings_manager_.reset(new PepperFlashSettingsManager(this, context));
502 Profile* profile = Profile::FromWebUI(web_ui());
503 observer_.Add(profile->GetHostContentSettingsMap());
504 if (profile->HasOffTheRecordProfile()) {
505 auto map = profile->GetOffTheRecordProfile()->GetHostContentSettingsMap();
506 if (!observer_.IsObserving(map))
511 void ContentSettingsHandler::InitializePage() {
512 media_settings_ = MediaSettingsInfo();
513 RefreshFlashMediaSettings();
515 UpdateHandlersEnabledRadios();
516 UpdateAllExceptionsViewsFromModel();
517 UpdateProtectedContentExceptionsButton();
520 void ContentSettingsHandler::OnContentSettingChanged(
521 const ContentSettingsPattern& primary_pattern,
522 const ContentSettingsPattern& secondary_pattern,
523 ContentSettingsType content_type,
524 std::string resource_identifier) {
525 const ContentSettingsDetails details(
526 primary_pattern, secondary_pattern, content_type, resource_identifier);
527 // TODO(estade): we pretend update_all() is always true.
528 if (details.update_all_types())
529 UpdateAllExceptionsViewsFromModel();
531 UpdateExceptionsViewFromModel(details.type());
534 void ContentSettingsHandler::Observe(
536 const content::NotificationSource& source,
537 const content::NotificationDetails& details) {
539 case chrome::NOTIFICATION_PROFILE_DESTROYED: {
540 Profile* profile = content::Source<Profile>(source).ptr();
541 if (profile->IsOffTheRecord() &&
542 observer_.IsObserving(profile->GetHostContentSettingsMap())) {
543 web_ui()->CallJavascriptFunction(
544 "ContentSettingsExceptionsArea.OTRProfileDestroyed");
545 observer_.Remove(profile->GetHostContentSettingsMap());
550 case chrome::NOTIFICATION_PROFILE_CREATED: {
551 Profile* profile = content::Source<Profile>(source).ptr();
552 if (profile->IsOffTheRecord()) {
553 UpdateAllOTRExceptionsViewsFromModel();
554 observer_.Add(profile->GetHostContentSettingsMap());
559 case chrome::NOTIFICATION_DESKTOP_NOTIFICATION_SETTINGS_CHANGED: {
560 UpdateNotificationExceptionsView();
564 case chrome::NOTIFICATION_PROTOCOL_HANDLER_REGISTRY_CHANGED: {
565 UpdateHandlersEnabledRadios();
571 void ContentSettingsHandler::OnGetPermissionSettingsCompleted(
574 PP_Flash_BrowserOperations_Permission default_permission,
575 const ppapi::FlashSiteSettings& sites) {
576 if (success && request_id == media_settings_.last_flash_refresh_request_id) {
577 media_settings_.flash_settings_initialized = true;
578 media_settings_.flash_default_setting =
579 PepperFlashContentSettingsUtils::FlashPermissionToContentSetting(
581 PepperFlashContentSettingsUtils::FlashSiteSettingsToMediaExceptions(
582 sites, &media_settings_.flash_exceptions);
583 PepperFlashContentSettingsUtils::SortMediaExceptions(
584 &media_settings_.flash_exceptions);
586 UpdateFlashMediaLinksVisibility();
590 void ContentSettingsHandler::UpdateSettingDefaultFromModel(
591 ContentSettingsType type) {
592 base::DictionaryValue filter_settings;
593 std::string provider_id;
594 filter_settings.SetString(ContentSettingsTypeToGroupName(type) + ".value",
595 GetSettingDefaultFromModel(type, &provider_id));
596 filter_settings.SetString(
597 ContentSettingsTypeToGroupName(type) + ".managedBy", provider_id);
599 web_ui()->CallJavascriptFunction(
600 "ContentSettings.setContentFilterSettingsValue", filter_settings);
603 void ContentSettingsHandler::UpdateMediaSettingsView() {
604 PrefService* prefs = user_prefs::UserPrefs::Get(GetBrowserContext(web_ui()));
605 bool audio_disabled = !prefs->GetBoolean(prefs::kAudioCaptureAllowed) &&
606 prefs->IsManagedPreference(prefs::kAudioCaptureAllowed);
607 bool video_disabled = !prefs->GetBoolean(prefs::kVideoCaptureAllowed) &&
608 prefs->IsManagedPreference(prefs::kVideoCaptureAllowed);
610 media_settings_.policy_disable_audio = audio_disabled;
611 media_settings_.policy_disable_video = video_disabled;
612 media_settings_.default_setting =
613 GetContentSettingsMap()->GetDefaultContentSetting(
614 CONTENT_SETTINGS_TYPE_MEDIASTREAM, NULL);
615 media_settings_.default_setting_initialized = true;
616 UpdateFlashMediaLinksVisibility();
618 base::DictionaryValue media_ui_settings;
619 media_ui_settings.SetBoolean("cameraDisabled", video_disabled);
620 media_ui_settings.SetBoolean("micDisabled", audio_disabled);
622 // In case only video is enabled change the text appropriately.
623 if (audio_disabled && !video_disabled) {
624 media_ui_settings.SetString("askText", "mediaStreamVideoAsk");
625 media_ui_settings.SetString("blockText", "mediaStreamVideoBlock");
626 media_ui_settings.SetBoolean("showBubble", true);
627 media_ui_settings.SetString("bubbleText", "mediaStreamBubbleAudio");
629 web_ui()->CallJavascriptFunction("ContentSettings.updateMediaUI",
634 // In case only audio is enabled change the text appropriately.
635 if (video_disabled && !audio_disabled) {
636 base::DictionaryValue media_ui_settings;
637 media_ui_settings.SetString("askText", "mediaStreamAudioAsk");
638 media_ui_settings.SetString("blockText", "mediaStreamAudioBlock");
639 media_ui_settings.SetBoolean("showBubble", true);
640 media_ui_settings.SetString("bubbleText", "mediaStreamBubbleVideo");
642 web_ui()->CallJavascriptFunction("ContentSettings.updateMediaUI",
647 if (audio_disabled && video_disabled) {
648 // Fake policy controlled default because the user can not change anything
649 // until both audio and video are blocked.
650 base::DictionaryValue filter_settings;
651 std::string group_name =
652 ContentSettingsTypeToGroupName(CONTENT_SETTINGS_TYPE_MEDIASTREAM);
653 filter_settings.SetString(group_name + ".value",
654 ContentSettingToString(CONTENT_SETTING_BLOCK));
655 filter_settings.SetString(group_name + ".managedBy", "policy");
656 web_ui()->CallJavascriptFunction(
657 "ContentSettings.setContentFilterSettingsValue", filter_settings);
660 media_ui_settings.SetString("askText", "mediaStreamAsk");
661 media_ui_settings.SetString("blockText", "mediaStreamBlock");
662 media_ui_settings.SetBoolean("showBubble", false);
663 media_ui_settings.SetString("bubbleText", std::string());
665 web_ui()->CallJavascriptFunction("ContentSettings.updateMediaUI",
669 std::string ContentSettingsHandler::GetSettingDefaultFromModel(
670 ContentSettingsType type, std::string* provider_id) {
671 Profile* profile = Profile::FromWebUI(web_ui());
672 ContentSetting default_setting;
674 profile->GetHostContentSettingsMap()->GetDefaultContentSetting(
677 return ContentSettingToString(default_setting);
680 void ContentSettingsHandler::UpdateHandlersEnabledRadios() {
681 base::FundamentalValue handlers_enabled(
682 GetProtocolHandlerRegistry()->enabled());
684 web_ui()->CallJavascriptFunction(
685 "ContentSettings.updateHandlersEnabledRadios",
689 void ContentSettingsHandler::UpdateAllExceptionsViewsFromModel() {
690 for (int type = CONTENT_SETTINGS_TYPE_DEFAULT + 1;
691 type < CONTENT_SETTINGS_NUM_TYPES; ++type) {
692 UpdateExceptionsViewFromModel(static_cast<ContentSettingsType>(type));
694 // Zoom levels are not actually a content type so we need to handle them
696 UpdateZoomLevelsExceptionsView();
699 void ContentSettingsHandler::UpdateAllOTRExceptionsViewsFromModel() {
700 for (int type = CONTENT_SETTINGS_TYPE_DEFAULT + 1;
701 type < CONTENT_SETTINGS_NUM_TYPES; ++type) {
702 UpdateOTRExceptionsViewFromModel(static_cast<ContentSettingsType>(type));
706 void ContentSettingsHandler::UpdateExceptionsViewFromModel(
707 ContentSettingsType type) {
709 case CONTENT_SETTINGS_TYPE_GEOLOCATION:
710 UpdateGeolocationExceptionsView();
712 case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
713 UpdateNotificationExceptionsView();
715 case CONTENT_SETTINGS_TYPE_MEDIASTREAM:
716 UpdateMediaSettingsView();
718 case CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC:
719 case CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA:
720 UpdateMediaExceptionsView();
722 case CONTENT_SETTINGS_TYPE_MIXEDSCRIPT:
723 // We don't yet support exceptions for mixed scripting.
725 case CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE:
726 // The content settings type CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE
727 // is supposed to be set by policy only. Hence there is no user facing UI
728 // for this content type and we skip it here.
730 case CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS:
731 // The RPH settings are retrieved separately.
733 case CONTENT_SETTINGS_TYPE_MIDI_SYSEX:
734 UpdateMIDISysExExceptionsView();
736 case CONTENT_SETTINGS_TYPE_SSL_CERT_DECISIONS:
737 // The content settings type CONTENT_SETTINGS_TYPE_SSL_CERT_DECISIONS is
738 // supposed to be set by flags and field trials only, thus there is no
739 // user facing UI for this content type and we skip it here.
742 case CONTENT_SETTINGS_TYPE_METRO_SWITCH_TO_DESKTOP:
746 UpdateExceptionsViewFromHostContentSettingsMap(type);
751 void ContentSettingsHandler::UpdateOTRExceptionsViewFromModel(
752 ContentSettingsType type) {
754 case CONTENT_SETTINGS_TYPE_GEOLOCATION:
755 case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
756 case CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE:
757 case CONTENT_SETTINGS_TYPE_MIXEDSCRIPT:
759 case CONTENT_SETTINGS_TYPE_METRO_SWITCH_TO_DESKTOP:
761 case CONTENT_SETTINGS_TYPE_MEDIASTREAM:
762 case CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC:
763 case CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA:
764 case CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS:
765 case CONTENT_SETTINGS_TYPE_MIDI_SYSEX:
766 case CONTENT_SETTINGS_TYPE_SSL_CERT_DECISIONS:
769 UpdateExceptionsViewFromOTRHostContentSettingsMap(type);
774 // TODO(estade): merge with GetExceptionsFromHostContentSettingsMap.
775 void ContentSettingsHandler::UpdateGeolocationExceptionsView() {
776 Profile* profile = Profile::FromWebUI(web_ui());
777 HostContentSettingsMap* map = profile->GetHostContentSettingsMap();
779 ContentSettingsForOneType all_settings;
780 map->GetSettingsForOneType(
781 CONTENT_SETTINGS_TYPE_GEOLOCATION,
785 // Group geolocation settings by primary_pattern.
786 AllPatternsSettings all_patterns_settings;
787 for (ContentSettingsForOneType::iterator i = all_settings.begin();
788 i != all_settings.end(); ++i) {
789 // Don't add default settings.
790 if (i->primary_pattern == ContentSettingsPattern::Wildcard() &&
791 i->secondary_pattern == ContentSettingsPattern::Wildcard() &&
792 i->source != kPreferencesSource) {
795 all_patterns_settings[std::make_pair(i->primary_pattern, i->source)]
796 [i->secondary_pattern] = i->setting;
799 base::ListValue exceptions;
800 AddExceptionsGrantedByHostedApps(
802 HostedAppHasPermission<APIPermission::kGeolocation>,
805 for (AllPatternsSettings::iterator i = all_patterns_settings.begin();
806 i != all_patterns_settings.end(); ++i) {
807 const ContentSettingsPattern& primary_pattern = i->first.first;
808 const OnePatternSettings& one_settings = i->second;
810 OnePatternSettings::const_iterator parent =
811 one_settings.find(primary_pattern);
813 // Add the "parent" entry for the non-embedded setting.
814 ContentSetting parent_setting =
815 parent == one_settings.end() ? CONTENT_SETTING_DEFAULT : parent->second;
816 exceptions.Append(GetGeolocationExceptionForPage(primary_pattern,
820 // Add the "children" for any embedded settings.
821 for (OnePatternSettings::const_iterator j = one_settings.begin();
822 j != one_settings.end();
824 // Skip the non-embedded setting which we already added above.
828 exceptions.Append(GetGeolocationExceptionForPage(
829 primary_pattern, j->first, j->second));
833 base::StringValue type_string(
834 ContentSettingsTypeToGroupName(CONTENT_SETTINGS_TYPE_GEOLOCATION));
835 web_ui()->CallJavascriptFunction("ContentSettings.setExceptions",
836 type_string, exceptions);
838 // This is mainly here to keep this function ideologically parallel to
839 // UpdateExceptionsViewFromHostContentSettingsMap().
840 UpdateSettingDefaultFromModel(CONTENT_SETTINGS_TYPE_GEOLOCATION);
843 void ContentSettingsHandler::UpdateNotificationExceptionsView() {
844 Profile* profile = Profile::FromWebUI(web_ui());
845 ContentSettingsForOneType settings;
846 DesktopNotificationProfileUtil::GetNotificationsSettings(profile, &settings);
848 base::ListValue exceptions;
849 AddExceptionsGrantedByHostedApps(
851 HostedAppHasPermission<APIPermission::kNotifications>,
854 for (ContentSettingsForOneType::const_iterator i =
858 // Don't add default settings.
859 if (i->primary_pattern == ContentSettingsPattern::Wildcard() &&
860 i->secondary_pattern == ContentSettingsPattern::Wildcard() &&
861 i->source != kPreferencesSource) {
866 GetNotificationExceptionForPage(i->primary_pattern,
867 i->secondary_pattern,
872 base::StringValue type_string(
873 ContentSettingsTypeToGroupName(CONTENT_SETTINGS_TYPE_NOTIFICATIONS));
874 web_ui()->CallJavascriptFunction("ContentSettings.setExceptions",
875 type_string, exceptions);
877 // This is mainly here to keep this function ideologically parallel to
878 // UpdateExceptionsViewFromHostContentSettingsMap().
879 UpdateSettingDefaultFromModel(CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
882 void ContentSettingsHandler::UpdateMediaExceptionsView() {
883 base::ListValue media_exceptions;
884 GetExceptionsFromHostContentSettingsMap(
885 GetContentSettingsMap(),
886 CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
889 base::ListValue video_exceptions;
890 GetExceptionsFromHostContentSettingsMap(
891 GetContentSettingsMap(),
892 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA,
895 // Merge the |video_exceptions| list to |media_exceptions| list.
896 std::map<std::string, base::DictionaryValue*> entries_map;
897 for (base::ListValue::const_iterator media_entry(media_exceptions.begin());
898 media_entry != media_exceptions.end(); ++media_entry) {
899 base::DictionaryValue* media_dict = NULL;
900 if (!(*media_entry)->GetAsDictionary(&media_dict))
903 media_dict->SetString(kVideoSetting,
904 ContentSettingToString(CONTENT_SETTING_ASK));
906 std::string media_origin;
907 media_dict->GetString(kOrigin, &media_origin);
908 entries_map[media_origin] = media_dict;
911 for (base::ListValue::iterator video_entry = video_exceptions.begin();
912 video_entry != video_exceptions.end(); ++video_entry) {
913 base::DictionaryValue* video_dict = NULL;
914 if (!(*video_entry)->GetAsDictionary(&video_dict))
917 std::string video_origin;
918 std::string video_setting;
919 video_dict->GetString(kOrigin, &video_origin);
920 video_dict->GetString(kSetting, &video_setting);
922 std::map<std::string, base::DictionaryValue*>::iterator iter =
923 entries_map.find(video_origin);
924 if (iter == entries_map.end()) {
925 base::DictionaryValue* exception = new base::DictionaryValue();
926 exception->SetString(kOrigin, video_origin);
927 exception->SetString(kSetting,
928 ContentSettingToString(CONTENT_SETTING_ASK));
929 exception->SetString(kVideoSetting, video_setting);
930 exception->SetString(kSource, kPreferencesSource);
932 // Append the new entry to the list and map.
933 media_exceptions.Append(exception);
934 entries_map[video_origin] = exception;
936 // Modify the existing entry.
937 iter->second->SetString(kVideoSetting, video_setting);
941 media_settings_.exceptions.clear();
942 for (base::ListValue::const_iterator media_entry = media_exceptions.begin();
943 media_entry != media_exceptions.end(); ++media_entry) {
944 base::DictionaryValue* media_dict = NULL;
945 bool result = (*media_entry)->GetAsDictionary(&media_dict);
949 std::string audio_setting;
950 std::string video_setting;
951 media_dict->GetString(kOrigin, &origin);
952 media_dict->GetString(kSetting, &audio_setting);
953 media_dict->GetString(kVideoSetting, &video_setting);
954 media_settings_.exceptions.push_back(MediaException(
955 ContentSettingsPattern::FromString(origin),
956 ContentSettingFromString(audio_setting),
957 ContentSettingFromString(video_setting)));
959 PepperFlashContentSettingsUtils::SortMediaExceptions(
960 &media_settings_.exceptions);
961 media_settings_.exceptions_initialized = true;
962 UpdateFlashMediaLinksVisibility();
964 base::StringValue type_string(
965 ContentSettingsTypeToGroupName(CONTENT_SETTINGS_TYPE_MEDIASTREAM));
966 web_ui()->CallJavascriptFunction("ContentSettings.setExceptions",
967 type_string, media_exceptions);
969 UpdateSettingDefaultFromModel(CONTENT_SETTINGS_TYPE_MEDIASTREAM);
972 void ContentSettingsHandler::UpdateMIDISysExExceptionsView() {
973 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableWebMIDI)) {
974 web_ui()->CallJavascriptFunction(
975 "ContentSettings.showExperimentalWebMIDISettings",
976 base::FundamentalValue(true));
979 UpdateSettingDefaultFromModel(CONTENT_SETTINGS_TYPE_MIDI_SYSEX);
980 UpdateExceptionsViewFromHostContentSettingsMap(
981 CONTENT_SETTINGS_TYPE_MIDI_SYSEX);
984 void ContentSettingsHandler::UpdateZoomLevelsExceptionsView() {
985 base::ListValue zoom_levels_exceptions;
987 content::HostZoomMap* host_zoom_map =
988 content::HostZoomMap::GetDefaultForBrowserContext(
989 GetBrowserContext(web_ui()));
990 content::HostZoomMap::ZoomLevelVector zoom_levels(
991 host_zoom_map->GetAllZoomLevels());
992 std::sort(zoom_levels.begin(), zoom_levels.end(), HostZoomSort);
994 for (content::HostZoomMap::ZoomLevelVector::const_iterator i =
996 i != zoom_levels.end();
998 scoped_ptr<base::DictionaryValue> exception(new base::DictionaryValue);
1000 case content::HostZoomMap::ZOOM_CHANGED_FOR_HOST: {
1001 exception->SetString(kOrigin, i->host);
1002 std::string host = i->host;
1003 if (host == content::kUnreachableWebDataURL) {
1005 l10n_util::GetStringUTF8(IDS_ZOOMLEVELS_CHROME_ERROR_PAGES_LABEL);
1007 exception->SetString(kOrigin, host);
1009 case content::HostZoomMap::ZOOM_CHANGED_FOR_SCHEME_AND_HOST:
1010 // These are not stored in preferences and get cleared on next browser
1011 // start. Therefore, we don't care for them.
1013 case content::HostZoomMap::ZOOM_CHANGED_TEMPORARY_ZOOM:
1016 exception->SetString(kSetting,
1017 ContentSettingToString(CONTENT_SETTING_DEFAULT));
1019 // Calculate the zoom percent from the factor. Round up to the nearest whole
1021 int zoom_percent = static_cast<int>(
1022 content::ZoomLevelToZoomFactor(i->zoom_level) * 100 + 0.5);
1023 exception->SetString(
1025 l10n_util::GetStringFUTF16(IDS_ZOOM_PERCENT,
1026 base::IntToString16(zoom_percent)));
1027 exception->SetString(kSource, kPreferencesSource);
1028 // Append the new entry to the list and map.
1029 zoom_levels_exceptions.Append(exception.release());
1032 base::StringValue type_string(kZoomContentType);
1033 web_ui()->CallJavascriptFunction("ContentSettings.setExceptions",
1034 type_string, zoom_levels_exceptions);
1037 void ContentSettingsHandler::UpdateExceptionsViewFromHostContentSettingsMap(
1038 ContentSettingsType type) {
1039 base::ListValue exceptions;
1040 GetExceptionsFromHostContentSettingsMap(
1041 GetContentSettingsMap(), type, &exceptions);
1042 base::StringValue type_string(ContentSettingsTypeToGroupName(type));
1043 web_ui()->CallJavascriptFunction("ContentSettings.setExceptions", type_string,
1046 UpdateExceptionsViewFromOTRHostContentSettingsMap(type);
1048 // TODO(koz): The default for fullscreen is always 'ask'.
1049 // http://crbug.com/104683
1050 if (type == CONTENT_SETTINGS_TYPE_FULLSCREEN)
1053 #if defined(OS_CHROMEOS)
1054 // Also the default for protected contents is managed in another place.
1055 if (type == CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER)
1059 // The default may also have changed (we won't get a separate notification).
1060 // If it hasn't changed, this call will be harmless.
1061 UpdateSettingDefaultFromModel(type);
1064 void ContentSettingsHandler::UpdateExceptionsViewFromOTRHostContentSettingsMap(
1065 ContentSettingsType type) {
1066 const HostContentSettingsMap* otr_settings_map = GetOTRContentSettingsMap();
1067 if (!otr_settings_map)
1069 base::ListValue exceptions;
1070 GetExceptionsFromHostContentSettingsMap(otr_settings_map, type, &exceptions);
1071 base::StringValue type_string(ContentSettingsTypeToGroupName(type));
1072 web_ui()->CallJavascriptFunction("ContentSettings.setOTRExceptions",
1073 type_string, exceptions);
1076 void ContentSettingsHandler::GetExceptionsFromHostContentSettingsMap(
1077 const HostContentSettingsMap* map,
1078 ContentSettingsType type,
1079 base::ListValue* exceptions) {
1080 ContentSettingsForOneType entries;
1081 map->GetSettingsForOneType(type, std::string(), &entries);
1082 // Group settings by primary_pattern.
1083 AllPatternsSettings all_patterns_settings;
1084 for (ContentSettingsForOneType::iterator i = entries.begin();
1085 i != entries.end(); ++i) {
1086 // Don't add default settings.
1087 if (i->primary_pattern == ContentSettingsPattern::Wildcard() &&
1088 i->secondary_pattern == ContentSettingsPattern::Wildcard() &&
1089 i->source != kPreferencesSource) {
1093 // Off-the-record HostContentSettingsMap contains incognito content settings
1094 // as well as normal content settings. Here, we use the incongnito settings
1096 if (map->is_off_the_record() && !i->incognito)
1099 all_patterns_settings[std::make_pair(i->primary_pattern, i->source)]
1100 [i->secondary_pattern] = i->setting;
1103 // Keep the exceptions sorted by provider so they will be displayed in
1104 // precedence order.
1105 std::vector<std::vector<base::Value*> > all_provider_exceptions;
1106 all_provider_exceptions.resize(HostContentSettingsMap::NUM_PROVIDER_TYPES);
1108 for (AllPatternsSettings::iterator i = all_patterns_settings.begin();
1109 i != all_patterns_settings.end();
1111 const ContentSettingsPattern& primary_pattern = i->first.first;
1112 const OnePatternSettings& one_settings = i->second;
1114 // The "parent" entry either has an identical primary and secondary pattern,
1115 // or has a wildcard secondary. The two cases are indistinguishable in the
1117 OnePatternSettings::const_iterator parent =
1118 one_settings.find(primary_pattern);
1119 if (parent == one_settings.end())
1120 parent = one_settings.find(ContentSettingsPattern::Wildcard());
1122 const std::string& source = i->first.second;
1123 std::vector<base::Value*>* this_provider_exceptions =
1124 &all_provider_exceptions.at(
1125 HostContentSettingsMap::GetProviderTypeFromSource(source));
1127 // Add the "parent" entry for the non-embedded setting.
1128 ContentSetting parent_setting =
1129 parent == one_settings.end() ? CONTENT_SETTING_DEFAULT : parent->second;
1130 const ContentSettingsPattern& secondary_pattern =
1131 parent == one_settings.end() ? primary_pattern : parent->first;
1132 this_provider_exceptions->push_back(GetExceptionForPage(primary_pattern,
1137 // Add the "children" for any embedded settings.
1138 for (OnePatternSettings::const_iterator j = one_settings.begin();
1139 j != one_settings.end(); ++j) {
1140 // Skip the non-embedded setting which we already added above.
1144 ContentSetting content_setting = j->second;
1145 this_provider_exceptions->push_back(GetExceptionForPage(
1153 for (size_t i = 0; i < all_provider_exceptions.size(); ++i) {
1154 for (size_t j = 0; j < all_provider_exceptions[i].size(); ++j) {
1155 exceptions->Append(all_provider_exceptions[i][j]);
1160 void ContentSettingsHandler::RemoveMediaException(const base::ListValue* args) {
1162 bool rv = args->GetString(1, &mode);
1165 std::string pattern;
1166 rv = args->GetString(2, &pattern);
1169 HostContentSettingsMap* settings_map =
1170 mode == "normal" ? GetContentSettingsMap() :
1171 GetOTRContentSettingsMap();
1173 settings_map->SetWebsiteSetting(ContentSettingsPattern::FromString(pattern),
1174 ContentSettingsPattern::Wildcard(),
1175 CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
1178 settings_map->SetWebsiteSetting(ContentSettingsPattern::FromString(pattern),
1179 ContentSettingsPattern::Wildcard(),
1180 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA,
1186 void ContentSettingsHandler::RemoveExceptionFromHostContentSettingsMap(
1187 const base::ListValue* args,
1188 ContentSettingsType type) {
1190 bool rv = args->GetString(1, &mode);
1193 std::string pattern;
1194 rv = args->GetString(2, &pattern);
1197 // The fourth argument to this handler is optional.
1198 std::string secondary_pattern;
1199 if (args->GetSize() >= 4U) {
1200 rv = args->GetString(3, &secondary_pattern);
1204 HostContentSettingsMap* settings_map =
1205 mode == "normal" ? GetContentSettingsMap() :
1206 GetOTRContentSettingsMap();
1208 settings_map->SetWebsiteSetting(
1209 ContentSettingsPattern::FromString(pattern),
1210 secondary_pattern.empty() ?
1211 ContentSettingsPattern::Wildcard() :
1212 ContentSettingsPattern::FromString(secondary_pattern),
1219 void ContentSettingsHandler::RemoveZoomLevelException(
1220 const base::ListValue* args) {
1222 bool rv = args->GetString(1, &mode);
1225 std::string pattern;
1226 rv = args->GetString(2, &pattern);
1230 l10n_util::GetStringUTF8(IDS_ZOOMLEVELS_CHROME_ERROR_PAGES_LABEL)) {
1231 pattern = content::kUnreachableWebDataURL;
1234 content::HostZoomMap* host_zoom_map =
1235 content::HostZoomMap::GetDefaultForBrowserContext(
1236 GetBrowserContext(web_ui()));
1237 double default_level = host_zoom_map->GetDefaultZoomLevel();
1238 host_zoom_map->SetZoomLevelForHost(pattern, default_level);
1241 void ContentSettingsHandler::RegisterMessages() {
1242 web_ui()->RegisterMessageCallback("setContentFilter",
1243 base::Bind(&ContentSettingsHandler::SetContentFilter,
1244 base::Unretained(this)));
1245 web_ui()->RegisterMessageCallback("removeException",
1246 base::Bind(&ContentSettingsHandler::RemoveException,
1247 base::Unretained(this)));
1248 web_ui()->RegisterMessageCallback("setException",
1249 base::Bind(&ContentSettingsHandler::SetException,
1250 base::Unretained(this)));
1251 web_ui()->RegisterMessageCallback("checkExceptionPatternValidity",
1252 base::Bind(&ContentSettingsHandler::CheckExceptionPatternValidity,
1253 base::Unretained(this)));
1256 void ContentSettingsHandler::SetContentFilter(const base::ListValue* args) {
1257 DCHECK_EQ(2U, args->GetSize());
1258 std::string group, setting;
1259 if (!(args->GetString(0, &group) &&
1260 args->GetString(1, &setting))) {
1265 ContentSetting default_setting = ContentSettingFromString(setting);
1266 ContentSettingsType content_type = ContentSettingsTypeFromGroupName(group);
1267 Profile* profile = Profile::FromWebUI(web_ui());
1269 #if defined(OS_CHROMEOS)
1270 // ChromeOS special case : in Guest mode settings are opened in Incognito
1271 // mode, so we need original profile to actually modify settings.
1272 if (user_manager::UserManager::Get()->IsLoggedInAsGuest())
1273 profile = profile->GetOriginalProfile();
1277 HostContentSettingsMap* map = profile->GetHostContentSettingsMap();
1278 map->SetDefaultContentSetting(content_type, default_setting);
1280 switch (content_type) {
1281 case CONTENT_SETTINGS_TYPE_COOKIES:
1282 content::RecordAction(
1283 UserMetricsAction("Options_DefaultCookieSettingChanged"));
1285 case CONTENT_SETTINGS_TYPE_IMAGES:
1286 content::RecordAction(
1287 UserMetricsAction("Options_DefaultImagesSettingChanged"));
1289 case CONTENT_SETTINGS_TYPE_JAVASCRIPT:
1290 content::RecordAction(
1291 UserMetricsAction("Options_DefaultJavaScriptSettingChanged"));
1293 case CONTENT_SETTINGS_TYPE_PLUGINS:
1294 content::RecordAction(
1295 UserMetricsAction("Options_DefaultPluginsSettingChanged"));
1297 case CONTENT_SETTINGS_TYPE_POPUPS:
1298 content::RecordAction(
1299 UserMetricsAction("Options_DefaultPopupsSettingChanged"));
1301 case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
1302 content::RecordAction(
1303 UserMetricsAction("Options_DefaultNotificationsSettingChanged"));
1305 case CONTENT_SETTINGS_TYPE_GEOLOCATION:
1306 content::RecordAction(
1307 UserMetricsAction("Options_DefaultGeolocationSettingChanged"));
1309 case CONTENT_SETTINGS_TYPE_MOUSELOCK:
1310 content::RecordAction(
1311 UserMetricsAction("Options_DefaultMouseLockSettingChanged"));
1313 case CONTENT_SETTINGS_TYPE_MEDIASTREAM:
1314 content::RecordAction(
1315 UserMetricsAction("Options_DefaultMediaStreamMicSettingChanged"));
1317 case CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS:
1318 content::RecordAction(
1319 UserMetricsAction("Options_DefaultMultipleAutomaticDLSettingChange"));
1321 case CONTENT_SETTINGS_TYPE_MIDI_SYSEX:
1322 content::RecordAction(
1323 UserMetricsAction("Options_DefaultMIDISysExSettingChanged"));
1325 case CONTENT_SETTINGS_TYPE_PUSH_MESSAGING:
1326 content::RecordAction(
1327 UserMetricsAction("Options_DefaultPushMessagingSettingChanged"));
1334 void ContentSettingsHandler::RemoveException(const base::ListValue* args) {
1335 std::string type_string;
1336 CHECK(args->GetString(0, &type_string));
1338 // Zoom levels are no actual content type so we need to handle them
1339 // separately. They would not be recognized by
1340 // ContentSettingsTypeFromGroupName.
1341 if (type_string == kZoomContentType) {
1342 RemoveZoomLevelException(args);
1346 ContentSettingsType type = ContentSettingsTypeFromGroupName(type_string);
1347 if (type == CONTENT_SETTINGS_TYPE_MEDIASTREAM)
1348 RemoveMediaException(args);
1350 RemoveExceptionFromHostContentSettingsMap(args, type);
1353 void ContentSettingsHandler::SetException(const base::ListValue* args) {
1354 std::string type_string;
1355 CHECK(args->GetString(0, &type_string));
1357 CHECK(args->GetString(1, &mode));
1358 std::string pattern;
1359 CHECK(args->GetString(2, &pattern));
1360 std::string setting;
1361 CHECK(args->GetString(3, &setting));
1363 ContentSettingsType type = ContentSettingsTypeFromGroupName(type_string);
1364 if (type == CONTENT_SETTINGS_TYPE_GEOLOCATION ||
1365 type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS ||
1366 type == CONTENT_SETTINGS_TYPE_MEDIASTREAM ||
1367 type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC ||
1368 type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA) {
1371 HostContentSettingsMap* settings_map =
1372 mode == "normal" ? GetContentSettingsMap() :
1373 GetOTRContentSettingsMap();
1375 // The settings map could be null if the mode was OTR but the OTR profile
1376 // got destroyed before we received this message.
1379 settings_map->SetContentSetting(ContentSettingsPattern::FromString(pattern),
1380 ContentSettingsPattern::Wildcard(),
1383 ContentSettingFromString(setting));
1387 void ContentSettingsHandler::CheckExceptionPatternValidity(
1388 const base::ListValue* args) {
1389 std::string type_string;
1390 CHECK(args->GetString(0, &type_string));
1391 std::string mode_string;
1392 CHECK(args->GetString(1, &mode_string));
1393 std::string pattern_string;
1394 CHECK(args->GetString(2, &pattern_string));
1396 ContentSettingsPattern pattern =
1397 ContentSettingsPattern::FromString(pattern_string);
1399 web_ui()->CallJavascriptFunction(
1400 "ContentSettings.patternValidityCheckComplete",
1401 base::StringValue(type_string),
1402 base::StringValue(mode_string),
1403 base::StringValue(pattern_string),
1404 base::FundamentalValue(pattern.IsValid()));
1408 std::string ContentSettingsHandler::ContentSettingsTypeToGroupName(
1409 ContentSettingsType type) {
1410 for (size_t i = 0; i < arraysize(kContentSettingsTypeGroupNames); ++i) {
1411 if (type == kContentSettingsTypeGroupNames[i].type)
1412 return kContentSettingsTypeGroupNames[i].name;
1416 return std::string();
1419 HostContentSettingsMap* ContentSettingsHandler::GetContentSettingsMap() {
1420 return Profile::FromWebUI(web_ui())->GetHostContentSettingsMap();
1423 ProtocolHandlerRegistry* ContentSettingsHandler::GetProtocolHandlerRegistry() {
1424 return ProtocolHandlerRegistryFactory::GetForBrowserContext(
1425 GetBrowserContext(web_ui()));
1428 HostContentSettingsMap*
1429 ContentSettingsHandler::GetOTRContentSettingsMap() {
1430 Profile* profile = Profile::FromWebUI(web_ui());
1431 if (profile->HasOffTheRecordProfile())
1432 return profile->GetOffTheRecordProfile()->GetHostContentSettingsMap();
1436 void ContentSettingsHandler::RefreshFlashMediaSettings() {
1437 media_settings_.flash_settings_initialized = false;
1439 media_settings_.last_flash_refresh_request_id =
1440 flash_settings_manager_->GetPermissionSettings(
1441 PP_FLASH_BROWSEROPERATIONS_SETTINGTYPE_CAMERAMIC);
1444 void ContentSettingsHandler::OnPepperFlashPrefChanged() {
1445 ShowFlashMediaLink(DEFAULT_SETTING, false);
1446 ShowFlashMediaLink(EXCEPTIONS, false);
1448 PrefService* prefs = user_prefs::UserPrefs::Get(GetBrowserContext(web_ui()));
1449 if (prefs->GetBoolean(prefs::kPepperFlashSettingsEnabled))
1450 RefreshFlashMediaSettings();
1452 media_settings_.flash_settings_initialized = false;
1455 void ContentSettingsHandler::OnZoomLevelChanged(
1456 const content::HostZoomMap::ZoomLevelChange& change) {
1457 UpdateZoomLevelsExceptionsView();
1460 void ContentSettingsHandler::ShowFlashMediaLink(LinkType link_type, bool show) {
1461 bool& show_link = link_type == DEFAULT_SETTING ?
1462 media_settings_.show_flash_default_link :
1463 media_settings_.show_flash_exceptions_link;
1464 if (show_link != show) {
1465 web_ui()->CallJavascriptFunction(
1466 link_type == DEFAULT_SETTING ?
1467 "ContentSettings.showMediaPepperFlashDefaultLink" :
1468 "ContentSettings.showMediaPepperFlashExceptionsLink",
1469 base::FundamentalValue(show));
1474 void ContentSettingsHandler::UpdateFlashMediaLinksVisibility() {
1475 if (!media_settings_.flash_settings_initialized ||
1476 !media_settings_.default_setting_initialized ||
1477 !media_settings_.exceptions_initialized) {
1481 // Flash won't send us notifications when its settings get changed, which
1482 // means the Flash settings in |media_settings_| may be out-dated, especially
1483 // after we show links to change Flash settings.
1484 // In order to avoid confusion, we won't hide the links once they are showed.
1485 // One exception is that we will hide them when Pepper Flash is disabled
1486 // (handled in OnPepperFlashPrefChanged()).
1487 if (media_settings_.show_flash_default_link &&
1488 media_settings_.show_flash_exceptions_link) {
1492 if (!media_settings_.show_flash_default_link) {
1493 // If both audio and video capture are disabled by policy, the link
1494 // shouldn't be showed. Flash conforms to the policy in this case because
1495 // it cannot open those devices. We don't have to look at the Flash
1497 if (!(media_settings_.policy_disable_audio &&
1498 media_settings_.policy_disable_video) &&
1499 media_settings_.flash_default_setting !=
1500 media_settings_.default_setting) {
1501 ShowFlashMediaLink(DEFAULT_SETTING, true);
1504 if (!media_settings_.show_flash_exceptions_link) {
1505 // If audio or video capture is disabled by policy, we skip comparison of
1506 // exceptions for audio or video capture, respectively.
1507 if (!PepperFlashContentSettingsUtils::AreMediaExceptionsEqual(
1508 media_settings_.default_setting,
1509 media_settings_.exceptions,
1510 media_settings_.flash_default_setting,
1511 media_settings_.flash_exceptions,
1512 media_settings_.policy_disable_audio,
1513 media_settings_.policy_disable_video)) {
1514 ShowFlashMediaLink(EXCEPTIONS, true);
1519 void ContentSettingsHandler::UpdateProtectedContentExceptionsButton() {
1520 #if defined(OS_CHROMEOS)
1521 // Guests cannot modify exceptions. UIAccountTweaks will disabled the button.
1522 if (user_manager::UserManager::Get()->IsLoggedInAsGuest())
1526 // Exceptions apply only when the feature is enabled.
1527 PrefService* prefs = user_prefs::UserPrefs::Get(GetBrowserContext(web_ui()));
1528 bool enable_exceptions = prefs->GetBoolean(prefs::kEnableDRM);
1529 web_ui()->CallJavascriptFunction(
1530 "ContentSettings.enableProtectedContentExceptions",
1531 base::FundamentalValue(enable_exceptions));
1534 } // namespace options