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. 4 5#include "chrome/browser/ui/webui/options/content_settings_handler.h" 6 7#include <algorithm> 8#include <map> 9#include <vector> 10 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/content_settings/content_settings_utils.h" 21#include "chrome/browser/content_settings/host_content_settings_map.h" 22#include "chrome/browser/custom_handlers/protocol_handler_registry.h" 23#include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h" 24#include "chrome/browser/extensions/extension_special_storage_policy.h" 25#include "chrome/browser/notifications/desktop_notification_profile_util.h" 26#include "chrome/browser/profiles/profile.h" 27#include "chrome/browser/ui/browser_list.h" 28#include "chrome/common/chrome_switches.h" 29#include "chrome/common/extensions/manifest_handlers/app_launch_info.h" 30#include "chrome/common/pref_names.h" 31#include "chrome/common/url_constants.h" 32#include "chrome/grit/generated_resources.h" 33#include "chrome/grit/locale_settings.h" 34#include "components/content_settings/core/browser/content_settings_details.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 "extensions/browser/extension_registry.h" 48#include "extensions/common/extension_set.h" 49#include "extensions/common/permissions/api_permission.h" 50#include "extensions/common/permissions/permissions_data.h" 51#include "ui/base/l10n/l10n_util.h" 52 53#if defined(OS_CHROMEOS) 54#include "components/user_manager/user_manager.h" 55#endif 56 57using base::UserMetricsAction; 58using content_settings::ContentSettingToString; 59using content_settings::ContentSettingFromString; 60using extensions::APIPermission; 61 62namespace { 63 64struct ContentSettingsTypeNameEntry { 65 ContentSettingsType type; 66 const char* name; 67}; 68 69// Maps from a secondary pattern to a setting. 70typedef std::map<ContentSettingsPattern, ContentSetting> 71 OnePatternSettings; 72// Maps from a primary pattern/source pair to a OnePatternSettings. All the 73// mappings in OnePatternSettings share the given primary pattern and source. 74typedef std::map<std::pair<ContentSettingsPattern, std::string>, 75 OnePatternSettings> 76 AllPatternsSettings; 77 78// The AppFilter is used in AddExceptionsGrantedByHostedApps() to choose 79// extensions which should have their extent displayed. 80typedef bool (*AppFilter)(const extensions::Extension& app, 81 content::BrowserContext* profile); 82 83const char kExceptionsLearnMoreUrl[] = 84 "https://support.google.com/chrome/?p=settings_manage_exceptions"; 85 86const char* kSetting = "setting"; 87const char* kOrigin = "origin"; 88const char* kSource = "source"; 89const char* kAppName = "appName"; 90const char* kAppId = "appId"; 91const char* kEmbeddingOrigin = "embeddingOrigin"; 92const char* kPreferencesSource = "preference"; 93const char* kVideoSetting = "video"; 94const char* kZoom = "zoom"; 95 96const ContentSettingsTypeNameEntry kContentSettingsTypeGroupNames[] = { 97 {CONTENT_SETTINGS_TYPE_COOKIES, "cookies"}, 98 {CONTENT_SETTINGS_TYPE_IMAGES, "images"}, 99 {CONTENT_SETTINGS_TYPE_JAVASCRIPT, "javascript"}, 100 {CONTENT_SETTINGS_TYPE_PLUGINS, "plugins"}, 101 {CONTENT_SETTINGS_TYPE_POPUPS, "popups"}, 102 {CONTENT_SETTINGS_TYPE_GEOLOCATION, "location"}, 103 {CONTENT_SETTINGS_TYPE_NOTIFICATIONS, "notifications"}, 104 {CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE, "auto-select-certificate"}, 105 {CONTENT_SETTINGS_TYPE_FULLSCREEN, "fullscreen"}, 106 {CONTENT_SETTINGS_TYPE_MOUSELOCK, "mouselock"}, 107 {CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS, "register-protocol-handler"}, 108 {CONTENT_SETTINGS_TYPE_MEDIASTREAM, "media-stream"}, 109 {CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, "media-stream-mic"}, 110 {CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, "media-stream-camera"}, 111 {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, "ppapi-broker"}, 112 {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, "multiple-automatic-downloads"}, 113 {CONTENT_SETTINGS_TYPE_MIDI_SYSEX, "midi-sysex"}, 114 {CONTENT_SETTINGS_TYPE_PUSH_MESSAGING, "push-messaging"}, 115 {CONTENT_SETTINGS_TYPE_SSL_CERT_DECISIONS, "ssl-cert-decisions"}, 116#if defined(OS_CHROMEOS) 117 {CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER, "protectedContent"}, 118#endif 119}; 120 121// A pseudo content type. We use it to display data like a content setting even 122// though it is not a real content setting. 123const char* kZoomContentType = "zoomlevels"; 124 125content::BrowserContext* GetBrowserContext(content::WebUI* web_ui) { 126 return web_ui->GetWebContents()->GetBrowserContext(); 127} 128 129ContentSettingsType ContentSettingsTypeFromGroupName(const std::string& name) { 130 for (size_t i = 0; i < arraysize(kContentSettingsTypeGroupNames); ++i) { 131 if (name == kContentSettingsTypeGroupNames[i].name) 132 return kContentSettingsTypeGroupNames[i].type; 133 } 134 135 NOTREACHED() << name << " is not a recognized content settings type."; 136 return CONTENT_SETTINGS_TYPE_DEFAULT; 137} 138 139// Create a DictionaryValue* that will act as a data source for a single row 140// in a HostContentSettingsMap-controlled exceptions table (e.g., cookies). 141// Ownership of the pointer is passed to the caller. 142base::DictionaryValue* GetExceptionForPage( 143 const ContentSettingsPattern& pattern, 144 const ContentSettingsPattern& secondary_pattern, 145 const ContentSetting& setting, 146 const std::string& provider_name) { 147 base::DictionaryValue* exception = new base::DictionaryValue(); 148 exception->SetString(kOrigin, pattern.ToString()); 149 exception->SetString(kEmbeddingOrigin, 150 secondary_pattern == ContentSettingsPattern::Wildcard() ? 151 std::string() : 152 secondary_pattern.ToString()); 153 exception->SetString(kSetting, ContentSettingToString(setting)); 154 exception->SetString(kSource, provider_name); 155 return exception; 156} 157 158// Create a DictionaryValue* that will act as a data source for a single row 159// in the Geolocation exceptions table. Ownership of the pointer is passed to 160// the caller. 161base::DictionaryValue* GetGeolocationExceptionForPage( 162 const ContentSettingsPattern& origin, 163 const ContentSettingsPattern& embedding_origin, 164 ContentSetting setting) { 165 base::DictionaryValue* exception = new base::DictionaryValue(); 166 exception->SetString(kSetting, ContentSettingToString(setting)); 167 exception->SetString(kOrigin, origin.ToString()); 168 exception->SetString(kEmbeddingOrigin, embedding_origin.ToString()); 169 return exception; 170} 171 172// Create a DictionaryValue* that will act as a data source for a single row 173// in the desktop notifications exceptions table. Ownership of the pointer is 174// passed to the caller. 175base::DictionaryValue* GetNotificationExceptionForPage( 176 const ContentSettingsPattern& primary_pattern, 177 const ContentSettingsPattern& secondary_pattern, 178 ContentSetting setting, 179 const std::string& provider_name) { 180 std::string embedding_origin; 181 if (secondary_pattern != ContentSettingsPattern::Wildcard()) 182 embedding_origin = secondary_pattern.ToString(); 183 184 base::DictionaryValue* exception = new base::DictionaryValue(); 185 exception->SetString(kSetting, ContentSettingToString(setting)); 186 exception->SetString(kOrigin, primary_pattern.ToString()); 187 exception->SetString(kEmbeddingOrigin, embedding_origin); 188 exception->SetString(kSource, provider_name); 189 return exception; 190} 191 192// Returns true whenever the |extension| is hosted and has |permission|. 193// Must have the AppFilter signature. 194template <APIPermission::ID permission> 195bool HostedAppHasPermission(const extensions::Extension& extension, 196 content::BrowserContext* /* context */) { 197 return extension.is_hosted_app() && 198 extension.permissions_data()->HasAPIPermission(permission); 199} 200 201// Add an "Allow"-entry to the list of |exceptions| for a |url_pattern| from 202// the web extent of a hosted |app|. 203void AddExceptionForHostedApp(const std::string& url_pattern, 204 const extensions::Extension& app, base::ListValue* exceptions) { 205 base::DictionaryValue* exception = new base::DictionaryValue(); 206 exception->SetString(kSetting, ContentSettingToString(CONTENT_SETTING_ALLOW)); 207 exception->SetString(kOrigin, url_pattern); 208 exception->SetString(kEmbeddingOrigin, url_pattern); 209 exception->SetString(kSource, "HostedApp"); 210 exception->SetString(kAppName, app.name()); 211 exception->SetString(kAppId, app.id()); 212 exceptions->Append(exception); 213} 214 215// Asks the |profile| for hosted apps which have the |permission| set, and 216// adds their web extent and launch URL to the |exceptions| list. 217void AddExceptionsGrantedByHostedApps(content::BrowserContext* context, 218 AppFilter app_filter, 219 base::ListValue* exceptions) { 220 const extensions::ExtensionSet& extensions = 221 extensions::ExtensionRegistry::Get(context)->enabled_extensions(); 222 for (extensions::ExtensionSet::const_iterator extension = extensions.begin(); 223 extension != extensions.end(); ++extension) { 224 if (!app_filter(*extension->get(), context)) 225 continue; 226 227 extensions::URLPatternSet web_extent = (*extension)->web_extent(); 228 // Add patterns from web extent. 229 for (extensions::URLPatternSet::const_iterator pattern = web_extent.begin(); 230 pattern != web_extent.end(); ++pattern) { 231 std::string url_pattern = pattern->GetAsString(); 232 AddExceptionForHostedApp(url_pattern, *extension->get(), exceptions); 233 } 234 // Retrieve the launch URL. 235 GURL launch_url = 236 extensions::AppLaunchInfo::GetLaunchWebURL(extension->get()); 237 // Skip adding the launch URL if it is part of the web extent. 238 if (web_extent.MatchesURL(launch_url)) 239 continue; 240 AddExceptionForHostedApp(launch_url.spec(), *extension->get(), exceptions); 241 } 242} 243 244// Sort ZoomLevelChanges by host and scheme 245// (a.com < http://a.com < https://a.com < b.com). 246bool HostZoomSort(const content::HostZoomMap::ZoomLevelChange& a, 247 const content::HostZoomMap::ZoomLevelChange& b) { 248 return a.host == b.host ? a.scheme < b.scheme : a.host < b.host; 249} 250 251} // namespace 252 253namespace options { 254 255ContentSettingsHandler::MediaSettingsInfo::MediaSettingsInfo() 256 : flash_default_setting(CONTENT_SETTING_DEFAULT), 257 flash_settings_initialized(false), 258 last_flash_refresh_request_id(0), 259 show_flash_default_link(false), 260 show_flash_exceptions_link(false), 261 default_setting(CONTENT_SETTING_DEFAULT), 262 policy_disable_audio(false), 263 policy_disable_video(false), 264 default_setting_initialized(false), 265 exceptions_initialized(false) { 266} 267 268ContentSettingsHandler::MediaSettingsInfo::~MediaSettingsInfo() { 269} 270 271ContentSettingsHandler::ContentSettingsHandler() : observer_(this) { 272} 273 274ContentSettingsHandler::~ContentSettingsHandler() { 275} 276 277void ContentSettingsHandler::GetLocalizedValues( 278 base::DictionaryValue* localized_strings) { 279 DCHECK(localized_strings); 280 281 // TODO(dhnishi): Standardize to lowerCamelCase. 282 static OptionsStringResource resources[] = { 283 { "allowException", IDS_EXCEPTIONS_ALLOW_BUTTON }, 284 { "blockException", IDS_EXCEPTIONS_BLOCK_BUTTON }, 285 { "sessionException", IDS_EXCEPTIONS_SESSION_ONLY_BUTTON }, 286 { "askException", IDS_EXCEPTIONS_ASK_BUTTON }, 287 { "otr_exceptions_explanation", IDS_EXCEPTIONS_OTR_LABEL }, 288 { "addNewExceptionInstructions", IDS_EXCEPTIONS_ADD_NEW_INSTRUCTIONS }, 289 { "manageExceptions", IDS_EXCEPTIONS_MANAGE }, 290 { "manage_handlers", IDS_HANDLERS_MANAGE }, 291 { "exceptionPatternHeader", IDS_EXCEPTIONS_PATTERN_HEADER }, 292 { "exceptionBehaviorHeader", IDS_EXCEPTIONS_ACTION_HEADER }, 293 { "exceptionZoomHeader", IDS_EXCEPTIONS_ZOOM_HEADER }, 294 { "embeddedOnHost", IDS_EXCEPTIONS_GEOLOCATION_EMBEDDED_ON_HOST }, 295 // Cookies filter. 296 { "cookiesTabLabel", IDS_COOKIES_TAB_LABEL }, 297 { "cookies_header", IDS_COOKIES_HEADER }, 298 { "cookiesAllow", IDS_COOKIES_ALLOW_RADIO }, 299 { "cookiesBlock", IDS_COOKIES_BLOCK_RADIO }, 300 { "cookies_session_only", IDS_COOKIES_SESSION_ONLY_RADIO }, 301 { "cookies_block_3rd_party", IDS_COOKIES_BLOCK_3RDPARTY_CHKBOX }, 302 { "cookies_clear_when_close", IDS_COOKIES_CLEAR_WHEN_CLOSE_CHKBOX }, 303 { "cookies_lso_clear_when_close", IDS_COOKIES_LSO_CLEAR_WHEN_CLOSE_CHKBOX }, 304 { "cookies_show_cookies", IDS_COOKIES_SHOW_COOKIES_BUTTON }, 305 { "flash_storage_settings", IDS_FLASH_STORAGE_SETTINGS }, 306 { "flash_storage_url", IDS_FLASH_STORAGE_URL }, 307#if defined(ENABLE_GOOGLE_NOW) 308 { "googleGeolocationAccessEnable", 309 IDS_GEOLOCATION_GOOGLE_ACCESS_ENABLE_CHKBOX }, 310#endif 311 // Image filter. 312 { "imagesTabLabel", IDS_IMAGES_TAB_LABEL }, 313 { "images_header", IDS_IMAGES_HEADER }, 314 { "imagesAllow", IDS_IMAGES_LOAD_RADIO }, 315 { "imagesBlock", IDS_IMAGES_NOLOAD_RADIO }, 316 // JavaScript filter. 317 { "javascriptTabLabel", IDS_JAVASCRIPT_TAB_LABEL }, 318 { "javascript_header", IDS_JAVASCRIPT_HEADER }, 319 { "javascriptAllow", IDS_JS_ALLOW_RADIO }, 320 { "javascriptBlock", IDS_JS_DONOTALLOW_RADIO }, 321 // Plug-ins filter. 322 { "pluginsTabLabel", IDS_PLUGIN_TAB_LABEL }, 323 { "plugins_header", IDS_PLUGIN_HEADER }, 324 { "pluginsAsk", IDS_PLUGIN_ASK_RADIO }, 325 { "pluginsAllow", IDS_PLUGIN_LOAD_RADIO }, 326 { "pluginsBlock", IDS_PLUGIN_NOLOAD_RADIO }, 327 { "disableIndividualPlugins", IDS_PLUGIN_SELECTIVE_DISABLE }, 328 // Pop-ups filter. 329 { "popupsTabLabel", IDS_POPUP_TAB_LABEL }, 330 { "popups_header", IDS_POPUP_HEADER }, 331 { "popupsAllow", IDS_POPUP_ALLOW_RADIO }, 332 { "popupsBlock", IDS_POPUP_BLOCK_RADIO }, 333 // Location filter. 334 { "locationTabLabel", IDS_GEOLOCATION_TAB_LABEL }, 335 { "location_header", IDS_GEOLOCATION_HEADER }, 336 { "locationAllow", IDS_GEOLOCATION_ALLOW_RADIO }, 337 { "locationAsk", IDS_GEOLOCATION_ASK_RADIO }, 338 { "locationBlock", IDS_GEOLOCATION_BLOCK_RADIO }, 339 { "set_by", IDS_GEOLOCATION_SET_BY_HOVER }, 340 // Notifications filter. 341 { "notificationsTabLabel", IDS_NOTIFICATIONS_TAB_LABEL }, 342 { "notifications_header", IDS_NOTIFICATIONS_HEADER }, 343 { "notificationsAllow", IDS_NOTIFICATIONS_ALLOW_RADIO }, 344 { "notificationsAsk", IDS_NOTIFICATIONS_ASK_RADIO }, 345 { "notificationsBlock", IDS_NOTIFICATIONS_BLOCK_RADIO }, 346 // Fullscreen filter. 347 { "fullscreenTabLabel", IDS_FULLSCREEN_TAB_LABEL }, 348 { "fullscreen_header", IDS_FULLSCREEN_HEADER }, 349 // Mouse Lock filter. 350 { "mouselockTabLabel", IDS_MOUSE_LOCK_TAB_LABEL }, 351 { "mouselock_header", IDS_MOUSE_LOCK_HEADER }, 352 { "mouselockAllow", IDS_MOUSE_LOCK_ALLOW_RADIO }, 353 { "mouselockAsk", IDS_MOUSE_LOCK_ASK_RADIO }, 354 { "mouselockBlock", IDS_MOUSE_LOCK_BLOCK_RADIO }, 355#if defined(OS_CHROMEOS) || defined(OS_WIN) 356 // Protected Content filter 357 { "protectedContentTabLabel", IDS_PROTECTED_CONTENT_TAB_LABEL }, 358 { "protectedContentInfo", IDS_PROTECTED_CONTENT_INFO }, 359 { "protectedContentEnable", IDS_PROTECTED_CONTENT_ENABLE }, 360 { "protectedContent_header", IDS_PROTECTED_CONTENT_HEADER }, 361#endif // defined(OS_CHROMEOS) || defined(OS_WIN) 362 // Media stream capture device filter. 363 { "mediaStreamTabLabel", IDS_MEDIA_STREAM_TAB_LABEL }, 364 { "media-stream_header", IDS_MEDIA_STREAM_HEADER }, 365 { "mediaStreamAsk", IDS_MEDIA_STREAM_ASK_RADIO }, 366 { "mediaStreamBlock", IDS_MEDIA_STREAM_BLOCK_RADIO }, 367 { "mediaStreamAudioAsk", IDS_MEDIA_STREAM_ASK_AUDIO_ONLY_RADIO }, 368 { "mediaStreamAudioBlock", IDS_MEDIA_STREAM_BLOCK_AUDIO_ONLY_RADIO }, 369 { "mediaStreamVideoAsk", IDS_MEDIA_STREAM_ASK_VIDEO_ONLY_RADIO }, 370 { "mediaStreamVideoBlock", IDS_MEDIA_STREAM_BLOCK_VIDEO_ONLY_RADIO }, 371 { "mediaStreamBubbleAudio", IDS_MEDIA_STREAM_AUDIO_MANAGED }, 372 { "mediaStreamBubbleVideo", IDS_MEDIA_STREAM_VIDEO_MANAGED }, 373 { "mediaAudioExceptionHeader", IDS_MEDIA_AUDIO_EXCEPTION_HEADER }, 374 { "mediaVideoExceptionHeader", IDS_MEDIA_VIDEO_EXCEPTION_HEADER }, 375 { "mediaPepperFlashDefaultDivergedLabel", 376 IDS_MEDIA_PEPPER_FLASH_DEFAULT_DIVERGED_LABEL }, 377 { "mediaPepperFlashExceptionsDivergedLabel", 378 IDS_MEDIA_PEPPER_FLASH_EXCEPTIONS_DIVERGED_LABEL }, 379 { "mediaPepperFlashChangeLink", IDS_MEDIA_PEPPER_FLASH_CHANGE_LINK }, 380 { "mediaPepperFlashGlobalPrivacyURL", IDS_FLASH_GLOBAL_PRIVACY_URL }, 381 { "mediaPepperFlashWebsitePrivacyURL", IDS_FLASH_WEBSITE_PRIVACY_URL }, 382 // PPAPI broker filter. 383 { "ppapi-broker_header", IDS_PPAPI_BROKER_HEADER }, 384 { "ppapiBrokerTabLabel", IDS_PPAPI_BROKER_TAB_LABEL }, 385 { "ppapiBrokerAllow", IDS_PPAPI_BROKER_ALLOW_RADIO }, 386 { "ppapiBrokerAsk", IDS_PPAPI_BROKER_ASK_RADIO }, 387 { "ppapiBrokerBlock", IDS_PPAPI_BROKER_BLOCK_RADIO }, 388 // Multiple automatic downloads 389 { "multipleAutomaticDownloadsTabLabel", 390 IDS_AUTOMATIC_DOWNLOADS_TAB_LABEL }, 391 { "multipleAutomaticDownloadsAllow", 392 IDS_AUTOMATIC_DOWNLOADS_ALLOW_RADIO }, 393 { "multipleAutomaticDownloadsAsk", 394 IDS_AUTOMATIC_DOWNLOADS_ASK_RADIO }, 395 { "multipleAutomaticDownloadsBlock", 396 IDS_AUTOMATIC_DOWNLOADS_BLOCK_RADIO }, 397 // MIDI system exclusive messages 398 { "midi-sysex_header", IDS_MIDI_SYSEX_TAB_LABEL }, 399 { "midiSysExAllow", IDS_MIDI_SYSEX_ALLOW_RADIO }, 400 { "midiSysExAsk", IDS_MIDI_SYSEX_ASK_RADIO }, 401 { "midiSysExBlock", IDS_MIDI_SYSEX_BLOCK_RADIO }, 402 // Push messaging strings 403 { "push-messaging_header", IDS_PUSH_MESSAGES_TAB_LABEL }, 404 { "pushMessagingAllow", IDS_PUSH_MESSSAGING_ALLOW_RADIO }, 405 { "pushMessagingAsk", IDS_PUSH_MESSSAGING_ASK_RADIO }, 406 { "pushMessagingBlock", IDS_PUSH_MESSSAGING_BLOCK_RADIO }, 407 { "zoomlevels_header", IDS_ZOOMLEVELS_HEADER_AND_TAB_LABEL }, 408 { "zoomLevelsManage", IDS_ZOOMLEVELS_MANAGE_BUTTON }, 409 }; 410 411 RegisterStrings(localized_strings, resources, arraysize(resources)); 412 RegisterTitle(localized_strings, "contentSettingsPage", 413 IDS_CONTENT_SETTINGS_TITLE); 414 415 // Register titles for each of the individual settings whose exception 416 // dialogs will be processed by |ContentSettingsHandler|. 417 RegisterTitle(localized_strings, "cookies", 418 IDS_COOKIES_TAB_LABEL); 419 RegisterTitle(localized_strings, "images", 420 IDS_IMAGES_TAB_LABEL); 421 RegisterTitle(localized_strings, "javascript", 422 IDS_JAVASCRIPT_TAB_LABEL); 423 RegisterTitle(localized_strings, "plugins", 424 IDS_PLUGIN_TAB_LABEL); 425 RegisterTitle(localized_strings, "popups", 426 IDS_POPUP_TAB_LABEL); 427 RegisterTitle(localized_strings, "location", 428 IDS_GEOLOCATION_TAB_LABEL); 429 RegisterTitle(localized_strings, "notifications", 430 IDS_NOTIFICATIONS_TAB_LABEL); 431 RegisterTitle(localized_strings, "fullscreen", 432 IDS_FULLSCREEN_TAB_LABEL); 433 RegisterTitle(localized_strings, "mouselock", 434 IDS_MOUSE_LOCK_TAB_LABEL); 435#if defined(OS_CHROMEOS) 436 RegisterTitle(localized_strings, "protectedContent", 437 IDS_PROTECTED_CONTENT_TAB_LABEL); 438#endif 439 RegisterTitle(localized_strings, "media-stream", 440 IDS_MEDIA_STREAM_TAB_LABEL); 441 RegisterTitle(localized_strings, "ppapi-broker", 442 IDS_PPAPI_BROKER_TAB_LABEL); 443 RegisterTitle(localized_strings, "multiple-automatic-downloads", 444 IDS_AUTOMATIC_DOWNLOADS_TAB_LABEL); 445 RegisterTitle(localized_strings, "midi-sysex", 446 IDS_MIDI_SYSEX_TAB_LABEL); 447 RegisterTitle(localized_strings, "zoomlevels", 448 IDS_ZOOMLEVELS_HEADER_AND_TAB_LABEL); 449 450 localized_strings->SetString("exceptionsLearnMoreUrl", 451 kExceptionsLearnMoreUrl); 452} 453 454void ContentSettingsHandler::InitializeHandler() { 455 notification_registrar_.Add( 456 this, chrome::NOTIFICATION_PROFILE_CREATED, 457 content::NotificationService::AllSources()); 458 notification_registrar_.Add( 459 this, chrome::NOTIFICATION_PROFILE_DESTROYED, 460 content::NotificationService::AllSources()); 461 462 notification_registrar_.Add( 463 this, chrome::NOTIFICATION_DESKTOP_NOTIFICATION_SETTINGS_CHANGED, 464 content::NotificationService::AllSources()); 465 content::BrowserContext* context = GetBrowserContext(web_ui()); 466 notification_registrar_.Add( 467 this, chrome::NOTIFICATION_PROTOCOL_HANDLER_REGISTRY_CHANGED, 468 content::Source<content::BrowserContext>(context)); 469 470 PrefService* prefs = user_prefs::UserPrefs::Get(context); 471 pref_change_registrar_.Init(prefs); 472 pref_change_registrar_.Add( 473 prefs::kPepperFlashSettingsEnabled, 474 base::Bind(&ContentSettingsHandler::OnPepperFlashPrefChanged, 475 base::Unretained(this))); 476 pref_change_registrar_.Add( 477 prefs::kAudioCaptureAllowed, 478 base::Bind(&ContentSettingsHandler::UpdateMediaSettingsView, 479 base::Unretained(this))); 480 pref_change_registrar_.Add( 481 prefs::kVideoCaptureAllowed, 482 base::Bind(&ContentSettingsHandler::UpdateMediaSettingsView, 483 base::Unretained(this))); 484 pref_change_registrar_.Add( 485 prefs::kEnableDRM, 486 base::Bind( 487 &ContentSettingsHandler::UpdateProtectedContentExceptionsButton, 488 base::Unretained(this))); 489 490 content::HostZoomMap* host_zoom_map = 491 content::HostZoomMap::GetDefaultForBrowserContext(context); 492 host_zoom_map_subscription_ = 493 host_zoom_map->AddZoomLevelChangedCallback( 494 base::Bind(&ContentSettingsHandler::OnZoomLevelChanged, 495 base::Unretained(this))); 496 497 flash_settings_manager_.reset(new PepperFlashSettingsManager(this, context)); 498 499 Profile* profile = Profile::FromWebUI(web_ui()); 500 observer_.Add(profile->GetHostContentSettingsMap()); 501 if (profile->HasOffTheRecordProfile()) { 502 auto map = profile->GetOffTheRecordProfile()->GetHostContentSettingsMap(); 503 if (!observer_.IsObserving(map)) 504 observer_.Add(map); 505 } 506} 507 508void ContentSettingsHandler::InitializePage() { 509 media_settings_ = MediaSettingsInfo(); 510 RefreshFlashMediaSettings(); 511 512 UpdateHandlersEnabledRadios(); 513 UpdateAllExceptionsViewsFromModel(); 514 UpdateProtectedContentExceptionsButton(); 515} 516 517void ContentSettingsHandler::OnContentSettingChanged( 518 const ContentSettingsPattern& primary_pattern, 519 const ContentSettingsPattern& secondary_pattern, 520 ContentSettingsType content_type, 521 std::string resource_identifier) { 522 const ContentSettingsDetails details( 523 primary_pattern, secondary_pattern, content_type, resource_identifier); 524 // TODO(estade): we pretend update_all() is always true. 525 if (details.update_all_types()) 526 UpdateAllExceptionsViewsFromModel(); 527 else 528 UpdateExceptionsViewFromModel(details.type()); 529} 530 531void ContentSettingsHandler::Observe( 532 int type, 533 const content::NotificationSource& source, 534 const content::NotificationDetails& details) { 535 switch (type) { 536 case chrome::NOTIFICATION_PROFILE_DESTROYED: { 537 Profile* profile = content::Source<Profile>(source).ptr(); 538 if (profile->IsOffTheRecord() && 539 observer_.IsObserving(profile->GetHostContentSettingsMap())) { 540 web_ui()->CallJavascriptFunction( 541 "ContentSettingsExceptionsArea.OTRProfileDestroyed"); 542 observer_.Remove(profile->GetHostContentSettingsMap()); 543 } 544 break; 545 } 546 547 case chrome::NOTIFICATION_PROFILE_CREATED: { 548 Profile* profile = content::Source<Profile>(source).ptr(); 549 if (profile->IsOffTheRecord()) { 550 UpdateAllOTRExceptionsViewsFromModel(); 551 observer_.Add(profile->GetHostContentSettingsMap()); 552 } 553 break; 554 } 555 556 case chrome::NOTIFICATION_DESKTOP_NOTIFICATION_SETTINGS_CHANGED: { 557 UpdateNotificationExceptionsView(); 558 break; 559 } 560 561 case chrome::NOTIFICATION_PROTOCOL_HANDLER_REGISTRY_CHANGED: { 562 UpdateHandlersEnabledRadios(); 563 break; 564 } 565 } 566} 567 568void ContentSettingsHandler::OnGetPermissionSettingsCompleted( 569 uint32 request_id, 570 bool success, 571 PP_Flash_BrowserOperations_Permission default_permission, 572 const ppapi::FlashSiteSettings& sites) { 573 if (success && request_id == media_settings_.last_flash_refresh_request_id) { 574 media_settings_.flash_settings_initialized = true; 575 media_settings_.flash_default_setting = 576 PepperFlashContentSettingsUtils::FlashPermissionToContentSetting( 577 default_permission); 578 PepperFlashContentSettingsUtils::FlashSiteSettingsToMediaExceptions( 579 sites, &media_settings_.flash_exceptions); 580 PepperFlashContentSettingsUtils::SortMediaExceptions( 581 &media_settings_.flash_exceptions); 582 583 UpdateFlashMediaLinksVisibility(); 584 } 585} 586 587void ContentSettingsHandler::UpdateSettingDefaultFromModel( 588 ContentSettingsType type) { 589 base::DictionaryValue filter_settings; 590 std::string provider_id; 591 filter_settings.SetString(ContentSettingsTypeToGroupName(type) + ".value", 592 GetSettingDefaultFromModel(type, &provider_id)); 593 filter_settings.SetString( 594 ContentSettingsTypeToGroupName(type) + ".managedBy", provider_id); 595 596 web_ui()->CallJavascriptFunction( 597 "ContentSettings.setContentFilterSettingsValue", filter_settings); 598} 599 600void ContentSettingsHandler::UpdateMediaSettingsView() { 601 PrefService* prefs = user_prefs::UserPrefs::Get(GetBrowserContext(web_ui())); 602 bool audio_disabled = !prefs->GetBoolean(prefs::kAudioCaptureAllowed) && 603 prefs->IsManagedPreference(prefs::kAudioCaptureAllowed); 604 bool video_disabled = !prefs->GetBoolean(prefs::kVideoCaptureAllowed) && 605 prefs->IsManagedPreference(prefs::kVideoCaptureAllowed); 606 607 media_settings_.policy_disable_audio = audio_disabled; 608 media_settings_.policy_disable_video = video_disabled; 609 media_settings_.default_setting = 610 GetContentSettingsMap()->GetDefaultContentSetting( 611 CONTENT_SETTINGS_TYPE_MEDIASTREAM, NULL); 612 media_settings_.default_setting_initialized = true; 613 UpdateFlashMediaLinksVisibility(); 614 615 base::DictionaryValue media_ui_settings; 616 media_ui_settings.SetBoolean("cameraDisabled", video_disabled); 617 media_ui_settings.SetBoolean("micDisabled", audio_disabled); 618 619 // In case only video is enabled change the text appropriately. 620 if (audio_disabled && !video_disabled) { 621 media_ui_settings.SetString("askText", "mediaStreamVideoAsk"); 622 media_ui_settings.SetString("blockText", "mediaStreamVideoBlock"); 623 media_ui_settings.SetBoolean("showBubble", true); 624 media_ui_settings.SetString("bubbleText", "mediaStreamBubbleAudio"); 625 626 web_ui()->CallJavascriptFunction("ContentSettings.updateMediaUI", 627 media_ui_settings); 628 return; 629 } 630 631 // In case only audio is enabled change the text appropriately. 632 if (video_disabled && !audio_disabled) { 633 base::DictionaryValue media_ui_settings; 634 media_ui_settings.SetString("askText", "mediaStreamAudioAsk"); 635 media_ui_settings.SetString("blockText", "mediaStreamAudioBlock"); 636 media_ui_settings.SetBoolean("showBubble", true); 637 media_ui_settings.SetString("bubbleText", "mediaStreamBubbleVideo"); 638 639 web_ui()->CallJavascriptFunction("ContentSettings.updateMediaUI", 640 media_ui_settings); 641 return; 642 } 643 644 if (audio_disabled && video_disabled) { 645 // Fake policy controlled default because the user can not change anything 646 // until both audio and video are blocked. 647 base::DictionaryValue filter_settings; 648 std::string group_name = 649 ContentSettingsTypeToGroupName(CONTENT_SETTINGS_TYPE_MEDIASTREAM); 650 filter_settings.SetString(group_name + ".value", 651 ContentSettingToString(CONTENT_SETTING_BLOCK)); 652 filter_settings.SetString(group_name + ".managedBy", "policy"); 653 web_ui()->CallJavascriptFunction( 654 "ContentSettings.setContentFilterSettingsValue", filter_settings); 655 } 656 657 media_ui_settings.SetString("askText", "mediaStreamAsk"); 658 media_ui_settings.SetString("blockText", "mediaStreamBlock"); 659 media_ui_settings.SetBoolean("showBubble", false); 660 media_ui_settings.SetString("bubbleText", std::string()); 661 662 web_ui()->CallJavascriptFunction("ContentSettings.updateMediaUI", 663 media_ui_settings); 664} 665 666std::string ContentSettingsHandler::GetSettingDefaultFromModel( 667 ContentSettingsType type, std::string* provider_id) { 668 Profile* profile = Profile::FromWebUI(web_ui()); 669 ContentSetting default_setting; 670 default_setting = 671 profile->GetHostContentSettingsMap()->GetDefaultContentSetting( 672 type, provider_id); 673 674 return ContentSettingToString(default_setting); 675} 676 677void ContentSettingsHandler::UpdateHandlersEnabledRadios() { 678 base::FundamentalValue handlers_enabled( 679 GetProtocolHandlerRegistry()->enabled()); 680 681 web_ui()->CallJavascriptFunction( 682 "ContentSettings.updateHandlersEnabledRadios", 683 handlers_enabled); 684} 685 686void ContentSettingsHandler::UpdateAllExceptionsViewsFromModel() { 687 for (int type = CONTENT_SETTINGS_TYPE_DEFAULT + 1; 688 type < CONTENT_SETTINGS_NUM_TYPES; ++type) { 689 UpdateExceptionsViewFromModel(static_cast<ContentSettingsType>(type)); 690 } 691 // Zoom levels are not actually a content type so we need to handle them 692 // separately. 693 UpdateZoomLevelsExceptionsView(); 694} 695 696void ContentSettingsHandler::UpdateAllOTRExceptionsViewsFromModel() { 697 for (int type = CONTENT_SETTINGS_TYPE_DEFAULT + 1; 698 type < CONTENT_SETTINGS_NUM_TYPES; ++type) { 699 UpdateOTRExceptionsViewFromModel(static_cast<ContentSettingsType>(type)); 700 } 701} 702 703void ContentSettingsHandler::UpdateExceptionsViewFromModel( 704 ContentSettingsType type) { 705 switch (type) { 706 case CONTENT_SETTINGS_TYPE_GEOLOCATION: 707 UpdateGeolocationExceptionsView(); 708 break; 709 case CONTENT_SETTINGS_TYPE_NOTIFICATIONS: 710 UpdateNotificationExceptionsView(); 711 break; 712 case CONTENT_SETTINGS_TYPE_MEDIASTREAM: 713 UpdateMediaSettingsView(); 714 break; 715 case CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC: 716 case CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA: 717 UpdateMediaExceptionsView(); 718 break; 719 case CONTENT_SETTINGS_TYPE_MIXEDSCRIPT: 720 // We don't yet support exceptions for mixed scripting. 721 break; 722 case CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE: 723 // The content settings type CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE 724 // is supposed to be set by policy only. Hence there is no user facing UI 725 // for this content type and we skip it here. 726 break; 727 case CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS: 728 // The RPH settings are retrieved separately. 729 break; 730 case CONTENT_SETTINGS_TYPE_MIDI_SYSEX: 731 UpdateMIDISysExExceptionsView(); 732 break; 733 case CONTENT_SETTINGS_TYPE_SSL_CERT_DECISIONS: 734 // The content settings type CONTENT_SETTINGS_TYPE_SSL_CERT_DECISIONS is 735 // supposed to be set by flags and field trials only, thus there is no 736 // user facing UI for this content type and we skip it here. 737 break; 738#if defined(OS_WIN) 739 case CONTENT_SETTINGS_TYPE_METRO_SWITCH_TO_DESKTOP: 740 break; 741#endif 742 default: 743 UpdateExceptionsViewFromHostContentSettingsMap(type); 744 break; 745 } 746} 747 748void ContentSettingsHandler::UpdateOTRExceptionsViewFromModel( 749 ContentSettingsType type) { 750 switch (type) { 751 case CONTENT_SETTINGS_TYPE_GEOLOCATION: 752 case CONTENT_SETTINGS_TYPE_NOTIFICATIONS: 753 case CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE: 754 case CONTENT_SETTINGS_TYPE_MIXEDSCRIPT: 755#if defined(OS_WIN) 756 case CONTENT_SETTINGS_TYPE_METRO_SWITCH_TO_DESKTOP: 757#endif 758 case CONTENT_SETTINGS_TYPE_MEDIASTREAM: 759 case CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC: 760 case CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA: 761 case CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS: 762 case CONTENT_SETTINGS_TYPE_MIDI_SYSEX: 763 case CONTENT_SETTINGS_TYPE_SSL_CERT_DECISIONS: 764 break; 765 default: 766 UpdateExceptionsViewFromOTRHostContentSettingsMap(type); 767 break; 768 } 769} 770 771// TODO(estade): merge with GetExceptionsFromHostContentSettingsMap. 772void ContentSettingsHandler::UpdateGeolocationExceptionsView() { 773 Profile* profile = Profile::FromWebUI(web_ui()); 774 HostContentSettingsMap* map = profile->GetHostContentSettingsMap(); 775 776 ContentSettingsForOneType all_settings; 777 map->GetSettingsForOneType( 778 CONTENT_SETTINGS_TYPE_GEOLOCATION, 779 std::string(), 780 &all_settings); 781 782 // Group geolocation settings by primary_pattern. 783 AllPatternsSettings all_patterns_settings; 784 for (ContentSettingsForOneType::iterator i = all_settings.begin(); 785 i != all_settings.end(); ++i) { 786 // Don't add default settings. 787 if (i->primary_pattern == ContentSettingsPattern::Wildcard() && 788 i->secondary_pattern == ContentSettingsPattern::Wildcard() && 789 i->source != kPreferencesSource) { 790 continue; 791 } 792 all_patterns_settings[std::make_pair(i->primary_pattern, i->source)] 793 [i->secondary_pattern] = i->setting; 794 } 795 796 base::ListValue exceptions; 797 AddExceptionsGrantedByHostedApps( 798 profile, 799 HostedAppHasPermission<APIPermission::kGeolocation>, 800 &exceptions); 801 802 for (AllPatternsSettings::iterator i = all_patterns_settings.begin(); 803 i != all_patterns_settings.end(); ++i) { 804 const ContentSettingsPattern& primary_pattern = i->first.first; 805 const OnePatternSettings& one_settings = i->second; 806 807 OnePatternSettings::const_iterator parent = 808 one_settings.find(primary_pattern); 809 810 // Add the "parent" entry for the non-embedded setting. 811 ContentSetting parent_setting = 812 parent == one_settings.end() ? CONTENT_SETTING_DEFAULT : parent->second; 813 exceptions.Append(GetGeolocationExceptionForPage(primary_pattern, 814 primary_pattern, 815 parent_setting)); 816 817 // Add the "children" for any embedded settings. 818 for (OnePatternSettings::const_iterator j = one_settings.begin(); 819 j != one_settings.end(); 820 ++j) { 821 // Skip the non-embedded setting which we already added above. 822 if (j == parent) 823 continue; 824 825 exceptions.Append(GetGeolocationExceptionForPage( 826 primary_pattern, j->first, j->second)); 827 } 828 } 829 830 base::StringValue type_string( 831 ContentSettingsTypeToGroupName(CONTENT_SETTINGS_TYPE_GEOLOCATION)); 832 web_ui()->CallJavascriptFunction("ContentSettings.setExceptions", 833 type_string, exceptions); 834 835 // This is mainly here to keep this function ideologically parallel to 836 // UpdateExceptionsViewFromHostContentSettingsMap(). 837 UpdateSettingDefaultFromModel(CONTENT_SETTINGS_TYPE_GEOLOCATION); 838} 839 840void ContentSettingsHandler::UpdateNotificationExceptionsView() { 841 Profile* profile = Profile::FromWebUI(web_ui()); 842 ContentSettingsForOneType settings; 843 DesktopNotificationProfileUtil::GetNotificationsSettings(profile, &settings); 844 845 base::ListValue exceptions; 846 AddExceptionsGrantedByHostedApps( 847 profile, 848 HostedAppHasPermission<APIPermission::kNotifications>, 849 &exceptions); 850 851 for (ContentSettingsForOneType::const_iterator i = 852 settings.begin(); 853 i != settings.end(); 854 ++i) { 855 // Don't add default settings. 856 if (i->primary_pattern == ContentSettingsPattern::Wildcard() && 857 i->secondary_pattern == ContentSettingsPattern::Wildcard() && 858 i->source != kPreferencesSource) { 859 continue; 860 } 861 862 exceptions.Append( 863 GetNotificationExceptionForPage(i->primary_pattern, 864 i->secondary_pattern, 865 i->setting, 866 i->source)); 867 } 868 869 base::StringValue type_string( 870 ContentSettingsTypeToGroupName(CONTENT_SETTINGS_TYPE_NOTIFICATIONS)); 871 web_ui()->CallJavascriptFunction("ContentSettings.setExceptions", 872 type_string, exceptions); 873 874 // This is mainly here to keep this function ideologically parallel to 875 // UpdateExceptionsViewFromHostContentSettingsMap(). 876 UpdateSettingDefaultFromModel(CONTENT_SETTINGS_TYPE_NOTIFICATIONS); 877} 878 879void ContentSettingsHandler::UpdateMediaExceptionsView() { 880 base::ListValue media_exceptions; 881 GetExceptionsFromHostContentSettingsMap( 882 GetContentSettingsMap(), 883 CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, 884 &media_exceptions); 885 886 base::ListValue video_exceptions; 887 GetExceptionsFromHostContentSettingsMap( 888 GetContentSettingsMap(), 889 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, 890 &video_exceptions); 891 892 // Merge the |video_exceptions| list to |media_exceptions| list. 893 std::map<std::string, base::DictionaryValue*> entries_map; 894 for (base::ListValue::const_iterator media_entry(media_exceptions.begin()); 895 media_entry != media_exceptions.end(); ++media_entry) { 896 base::DictionaryValue* media_dict = NULL; 897 if (!(*media_entry)->GetAsDictionary(&media_dict)) 898 NOTREACHED(); 899 900 media_dict->SetString(kVideoSetting, 901 ContentSettingToString(CONTENT_SETTING_ASK)); 902 903 std::string media_origin; 904 media_dict->GetString(kOrigin, &media_origin); 905 entries_map[media_origin] = media_dict; 906 } 907 908 for (base::ListValue::iterator video_entry = video_exceptions.begin(); 909 video_entry != video_exceptions.end(); ++video_entry) { 910 base::DictionaryValue* video_dict = NULL; 911 if (!(*video_entry)->GetAsDictionary(&video_dict)) 912 NOTREACHED(); 913 914 std::string video_origin; 915 std::string video_setting; 916 video_dict->GetString(kOrigin, &video_origin); 917 video_dict->GetString(kSetting, &video_setting); 918 919 std::map<std::string, base::DictionaryValue*>::iterator iter = 920 entries_map.find(video_origin); 921 if (iter == entries_map.end()) { 922 base::DictionaryValue* exception = new base::DictionaryValue(); 923 exception->SetString(kOrigin, video_origin); 924 exception->SetString(kSetting, 925 ContentSettingToString(CONTENT_SETTING_ASK)); 926 exception->SetString(kVideoSetting, video_setting); 927 exception->SetString(kSource, kPreferencesSource); 928 929 // Append the new entry to the list and map. 930 media_exceptions.Append(exception); 931 entries_map[video_origin] = exception; 932 } else { 933 // Modify the existing entry. 934 iter->second->SetString(kVideoSetting, video_setting); 935 } 936 } 937 938 media_settings_.exceptions.clear(); 939 for (base::ListValue::const_iterator media_entry = media_exceptions.begin(); 940 media_entry != media_exceptions.end(); ++media_entry) { 941 base::DictionaryValue* media_dict = NULL; 942 bool result = (*media_entry)->GetAsDictionary(&media_dict); 943 DCHECK(result); 944 945 std::string origin; 946 std::string audio_setting; 947 std::string video_setting; 948 media_dict->GetString(kOrigin, &origin); 949 media_dict->GetString(kSetting, &audio_setting); 950 media_dict->GetString(kVideoSetting, &video_setting); 951 media_settings_.exceptions.push_back(MediaException( 952 ContentSettingsPattern::FromString(origin), 953 ContentSettingFromString(audio_setting), 954 ContentSettingFromString(video_setting))); 955 } 956 PepperFlashContentSettingsUtils::SortMediaExceptions( 957 &media_settings_.exceptions); 958 media_settings_.exceptions_initialized = true; 959 UpdateFlashMediaLinksVisibility(); 960 961 base::StringValue type_string( 962 ContentSettingsTypeToGroupName(CONTENT_SETTINGS_TYPE_MEDIASTREAM)); 963 web_ui()->CallJavascriptFunction("ContentSettings.setExceptions", 964 type_string, media_exceptions); 965 966 UpdateSettingDefaultFromModel(CONTENT_SETTINGS_TYPE_MEDIASTREAM); 967} 968 969void ContentSettingsHandler::UpdateMIDISysExExceptionsView() { 970 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableWebMIDI)) { 971 web_ui()->CallJavascriptFunction( 972 "ContentSettings.showExperimentalWebMIDISettings", 973 base::FundamentalValue(true)); 974 } 975 976 UpdateSettingDefaultFromModel(CONTENT_SETTINGS_TYPE_MIDI_SYSEX); 977 UpdateExceptionsViewFromHostContentSettingsMap( 978 CONTENT_SETTINGS_TYPE_MIDI_SYSEX); 979} 980 981void ContentSettingsHandler::UpdateZoomLevelsExceptionsView() { 982 base::ListValue zoom_levels_exceptions; 983 984 content::HostZoomMap* host_zoom_map = 985 content::HostZoomMap::GetDefaultForBrowserContext( 986 GetBrowserContext(web_ui())); 987 content::HostZoomMap::ZoomLevelVector zoom_levels( 988 host_zoom_map->GetAllZoomLevels()); 989 std::sort(zoom_levels.begin(), zoom_levels.end(), HostZoomSort); 990 991 for (content::HostZoomMap::ZoomLevelVector::const_iterator i = 992 zoom_levels.begin(); 993 i != zoom_levels.end(); 994 ++i) { 995 scoped_ptr<base::DictionaryValue> exception(new base::DictionaryValue); 996 switch (i->mode) { 997 case content::HostZoomMap::ZOOM_CHANGED_FOR_HOST: 998 exception->SetString(kOrigin, i->host); 999 break; 1000 case content::HostZoomMap::ZOOM_CHANGED_FOR_SCHEME_AND_HOST: 1001 // These are not stored in preferences and get cleared on next browser 1002 // start. Therefore, we don't care for them. 1003 break; 1004 case content::HostZoomMap::ZOOM_CHANGED_TEMPORARY_ZOOM: 1005 NOTREACHED(); 1006 } 1007 exception->SetString(kSetting, 1008 ContentSettingToString(CONTENT_SETTING_DEFAULT)); 1009 1010 // Calculate the zoom percent from the factor. Round up to the nearest whole 1011 // number. 1012 int zoom_percent = static_cast<int>( 1013 content::ZoomLevelToZoomFactor(i->zoom_level) * 100 + 0.5); 1014 exception->SetString( 1015 kZoom, 1016 l10n_util::GetStringFUTF16(IDS_ZOOM_PERCENT, 1017 base::IntToString16(zoom_percent))); 1018 exception->SetString(kSource, kPreferencesSource); 1019 // Append the new entry to the list and map. 1020 zoom_levels_exceptions.Append(exception.release()); 1021 } 1022 1023 base::StringValue type_string(kZoomContentType); 1024 web_ui()->CallJavascriptFunction("ContentSettings.setExceptions", 1025 type_string, zoom_levels_exceptions); 1026} 1027 1028void ContentSettingsHandler::UpdateExceptionsViewFromHostContentSettingsMap( 1029 ContentSettingsType type) { 1030 base::ListValue exceptions; 1031 GetExceptionsFromHostContentSettingsMap( 1032 GetContentSettingsMap(), type, &exceptions); 1033 base::StringValue type_string(ContentSettingsTypeToGroupName(type)); 1034 web_ui()->CallJavascriptFunction("ContentSettings.setExceptions", type_string, 1035 exceptions); 1036 1037 UpdateExceptionsViewFromOTRHostContentSettingsMap(type); 1038 1039 // TODO(koz): The default for fullscreen is always 'ask'. 1040 // http://crbug.com/104683 1041 if (type == CONTENT_SETTINGS_TYPE_FULLSCREEN) 1042 return; 1043 1044#if defined(OS_CHROMEOS) 1045 // Also the default for protected contents is managed in another place. 1046 if (type == CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER) 1047 return; 1048#endif 1049 1050 // The default may also have changed (we won't get a separate notification). 1051 // If it hasn't changed, this call will be harmless. 1052 UpdateSettingDefaultFromModel(type); 1053} 1054 1055void ContentSettingsHandler::UpdateExceptionsViewFromOTRHostContentSettingsMap( 1056 ContentSettingsType type) { 1057 const HostContentSettingsMap* otr_settings_map = GetOTRContentSettingsMap(); 1058 if (!otr_settings_map) 1059 return; 1060 base::ListValue exceptions; 1061 GetExceptionsFromHostContentSettingsMap(otr_settings_map, type, &exceptions); 1062 base::StringValue type_string(ContentSettingsTypeToGroupName(type)); 1063 web_ui()->CallJavascriptFunction("ContentSettings.setOTRExceptions", 1064 type_string, exceptions); 1065} 1066 1067void ContentSettingsHandler::GetExceptionsFromHostContentSettingsMap( 1068 const HostContentSettingsMap* map, 1069 ContentSettingsType type, 1070 base::ListValue* exceptions) { 1071 ContentSettingsForOneType entries; 1072 map->GetSettingsForOneType(type, std::string(), &entries); 1073 // Group settings by primary_pattern. 1074 AllPatternsSettings all_patterns_settings; 1075 for (ContentSettingsForOneType::iterator i = entries.begin(); 1076 i != entries.end(); ++i) { 1077 // Don't add default settings. 1078 if (i->primary_pattern == ContentSettingsPattern::Wildcard() && 1079 i->secondary_pattern == ContentSettingsPattern::Wildcard() && 1080 i->source != kPreferencesSource) { 1081 continue; 1082 } 1083 1084 // Off-the-record HostContentSettingsMap contains incognito content settings 1085 // as well as normal content settings. Here, we use the incongnito settings 1086 // only. 1087 if (map->is_off_the_record() && !i->incognito) 1088 continue; 1089 1090 all_patterns_settings[std::make_pair(i->primary_pattern, i->source)] 1091 [i->secondary_pattern] = i->setting; 1092 } 1093 1094 // Keep the exceptions sorted by provider so they will be displayed in 1095 // precedence order. 1096 std::vector<std::vector<base::Value*> > all_provider_exceptions; 1097 all_provider_exceptions.resize(HostContentSettingsMap::NUM_PROVIDER_TYPES); 1098 1099 for (AllPatternsSettings::iterator i = all_patterns_settings.begin(); 1100 i != all_patterns_settings.end(); 1101 ++i) { 1102 const ContentSettingsPattern& primary_pattern = i->first.first; 1103 const OnePatternSettings& one_settings = i->second; 1104 1105 // The "parent" entry either has an identical primary and secondary pattern, 1106 // or has a wildcard secondary. The two cases are indistinguishable in the 1107 // UI. 1108 OnePatternSettings::const_iterator parent = 1109 one_settings.find(primary_pattern); 1110 if (parent == one_settings.end()) 1111 parent = one_settings.find(ContentSettingsPattern::Wildcard()); 1112 1113 const std::string& source = i->first.second; 1114 std::vector<base::Value*>* this_provider_exceptions = 1115 &all_provider_exceptions.at( 1116 HostContentSettingsMap::GetProviderTypeFromSource(source)); 1117 1118 // Add the "parent" entry for the non-embedded setting. 1119 ContentSetting parent_setting = 1120 parent == one_settings.end() ? CONTENT_SETTING_DEFAULT : parent->second; 1121 const ContentSettingsPattern& secondary_pattern = 1122 parent == one_settings.end() ? primary_pattern : parent->first; 1123 this_provider_exceptions->push_back(GetExceptionForPage(primary_pattern, 1124 secondary_pattern, 1125 parent_setting, 1126 source)); 1127 1128 // Add the "children" for any embedded settings. 1129 for (OnePatternSettings::const_iterator j = one_settings.begin(); 1130 j != one_settings.end(); ++j) { 1131 // Skip the non-embedded setting which we already added above. 1132 if (j == parent) 1133 continue; 1134 1135 ContentSetting content_setting = j->second; 1136 this_provider_exceptions->push_back(GetExceptionForPage( 1137 primary_pattern, 1138 j->first, 1139 content_setting, 1140 source)); 1141 } 1142 } 1143 1144 for (size_t i = 0; i < all_provider_exceptions.size(); ++i) { 1145 for (size_t j = 0; j < all_provider_exceptions[i].size(); ++j) { 1146 exceptions->Append(all_provider_exceptions[i][j]); 1147 } 1148 } 1149} 1150 1151void ContentSettingsHandler::RemoveMediaException(const base::ListValue* args) { 1152 std::string mode; 1153 bool rv = args->GetString(1, &mode); 1154 DCHECK(rv); 1155 1156 std::string pattern; 1157 rv = args->GetString(2, &pattern); 1158 DCHECK(rv); 1159 1160 HostContentSettingsMap* settings_map = 1161 mode == "normal" ? GetContentSettingsMap() : 1162 GetOTRContentSettingsMap(); 1163 if (settings_map) { 1164 settings_map->SetWebsiteSetting(ContentSettingsPattern::FromString(pattern), 1165 ContentSettingsPattern::Wildcard(), 1166 CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, 1167 std::string(), 1168 NULL); 1169 settings_map->SetWebsiteSetting(ContentSettingsPattern::FromString(pattern), 1170 ContentSettingsPattern::Wildcard(), 1171 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, 1172 std::string(), 1173 NULL); 1174 } 1175} 1176 1177void ContentSettingsHandler::RemoveExceptionFromHostContentSettingsMap( 1178 const base::ListValue* args, 1179 ContentSettingsType type) { 1180 std::string mode; 1181 bool rv = args->GetString(1, &mode); 1182 DCHECK(rv); 1183 1184 std::string pattern; 1185 rv = args->GetString(2, &pattern); 1186 DCHECK(rv); 1187 1188 // The fourth argument to this handler is optional. 1189 std::string secondary_pattern; 1190 if (args->GetSize() >= 4U) { 1191 rv = args->GetString(3, &secondary_pattern); 1192 DCHECK(rv); 1193 } 1194 1195 HostContentSettingsMap* settings_map = 1196 mode == "normal" ? GetContentSettingsMap() : 1197 GetOTRContentSettingsMap(); 1198 if (settings_map) { 1199 settings_map->SetWebsiteSetting( 1200 ContentSettingsPattern::FromString(pattern), 1201 secondary_pattern.empty() ? 1202 ContentSettingsPattern::Wildcard() : 1203 ContentSettingsPattern::FromString(secondary_pattern), 1204 type, 1205 std::string(), 1206 NULL); 1207 } 1208} 1209 1210void ContentSettingsHandler::RemoveZoomLevelException( 1211 const base::ListValue* args) { 1212 std::string mode; 1213 bool rv = args->GetString(1, &mode); 1214 DCHECK(rv); 1215 1216 std::string pattern; 1217 rv = args->GetString(2, &pattern); 1218 DCHECK(rv); 1219 1220 content::HostZoomMap* host_zoom_map = 1221 content::HostZoomMap::GetDefaultForBrowserContext( 1222 GetBrowserContext(web_ui())); 1223 double default_level = host_zoom_map->GetDefaultZoomLevel(); 1224 host_zoom_map->SetZoomLevelForHost(pattern, default_level); 1225} 1226 1227void ContentSettingsHandler::RegisterMessages() { 1228 web_ui()->RegisterMessageCallback("setContentFilter", 1229 base::Bind(&ContentSettingsHandler::SetContentFilter, 1230 base::Unretained(this))); 1231 web_ui()->RegisterMessageCallback("removeException", 1232 base::Bind(&ContentSettingsHandler::RemoveException, 1233 base::Unretained(this))); 1234 web_ui()->RegisterMessageCallback("setException", 1235 base::Bind(&ContentSettingsHandler::SetException, 1236 base::Unretained(this))); 1237 web_ui()->RegisterMessageCallback("checkExceptionPatternValidity", 1238 base::Bind(&ContentSettingsHandler::CheckExceptionPatternValidity, 1239 base::Unretained(this))); 1240} 1241 1242void ContentSettingsHandler::SetContentFilter(const base::ListValue* args) { 1243 DCHECK_EQ(2U, args->GetSize()); 1244 std::string group, setting; 1245 if (!(args->GetString(0, &group) && 1246 args->GetString(1, &setting))) { 1247 NOTREACHED(); 1248 return; 1249 } 1250 1251 ContentSetting default_setting = ContentSettingFromString(setting); 1252 ContentSettingsType content_type = ContentSettingsTypeFromGroupName(group); 1253 Profile* profile = Profile::FromWebUI(web_ui()); 1254 1255#if defined(OS_CHROMEOS) 1256 // ChromeOS special case : in Guest mode settings are opened in Incognito 1257 // mode, so we need original profile to actually modify settings. 1258 if (user_manager::UserManager::Get()->IsLoggedInAsGuest()) 1259 profile = profile->GetOriginalProfile(); 1260#endif 1261 1262 1263 HostContentSettingsMap* map = profile->GetHostContentSettingsMap(); 1264 map->SetDefaultContentSetting(content_type, default_setting); 1265 1266 switch (content_type) { 1267 case CONTENT_SETTINGS_TYPE_COOKIES: 1268 content::RecordAction( 1269 UserMetricsAction("Options_DefaultCookieSettingChanged")); 1270 break; 1271 case CONTENT_SETTINGS_TYPE_IMAGES: 1272 content::RecordAction( 1273 UserMetricsAction("Options_DefaultImagesSettingChanged")); 1274 break; 1275 case CONTENT_SETTINGS_TYPE_JAVASCRIPT: 1276 content::RecordAction( 1277 UserMetricsAction("Options_DefaultJavaScriptSettingChanged")); 1278 break; 1279 case CONTENT_SETTINGS_TYPE_PLUGINS: 1280 content::RecordAction( 1281 UserMetricsAction("Options_DefaultPluginsSettingChanged")); 1282 break; 1283 case CONTENT_SETTINGS_TYPE_POPUPS: 1284 content::RecordAction( 1285 UserMetricsAction("Options_DefaultPopupsSettingChanged")); 1286 break; 1287 case CONTENT_SETTINGS_TYPE_NOTIFICATIONS: 1288 content::RecordAction( 1289 UserMetricsAction("Options_DefaultNotificationsSettingChanged")); 1290 break; 1291 case CONTENT_SETTINGS_TYPE_GEOLOCATION: 1292 content::RecordAction( 1293 UserMetricsAction("Options_DefaultGeolocationSettingChanged")); 1294 break; 1295 case CONTENT_SETTINGS_TYPE_MOUSELOCK: 1296 content::RecordAction( 1297 UserMetricsAction("Options_DefaultMouseLockSettingChanged")); 1298 break; 1299 case CONTENT_SETTINGS_TYPE_MEDIASTREAM: 1300 content::RecordAction( 1301 UserMetricsAction("Options_DefaultMediaStreamMicSettingChanged")); 1302 break; 1303 case CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS: 1304 content::RecordAction( 1305 UserMetricsAction("Options_DefaultMultipleAutomaticDLSettingChange")); 1306 break; 1307 case CONTENT_SETTINGS_TYPE_MIDI_SYSEX: 1308 content::RecordAction( 1309 UserMetricsAction("Options_DefaultMIDISysExSettingChanged")); 1310 break; 1311 case CONTENT_SETTINGS_TYPE_PUSH_MESSAGING: 1312 content::RecordAction( 1313 UserMetricsAction("Options_DefaultPushMessagingSettingChanged")); 1314 break; 1315 default: 1316 break; 1317 } 1318} 1319 1320void ContentSettingsHandler::RemoveException(const base::ListValue* args) { 1321 std::string type_string; 1322 CHECK(args->GetString(0, &type_string)); 1323 1324 // Zoom levels are no actual content type so we need to handle them 1325 // separately. They would not be recognized by 1326 // ContentSettingsTypeFromGroupName. 1327 if (type_string == kZoomContentType) { 1328 RemoveZoomLevelException(args); 1329 return; 1330 } 1331 1332 ContentSettingsType type = ContentSettingsTypeFromGroupName(type_string); 1333 if (type == CONTENT_SETTINGS_TYPE_MEDIASTREAM) 1334 RemoveMediaException(args); 1335 else 1336 RemoveExceptionFromHostContentSettingsMap(args, type); 1337} 1338 1339void ContentSettingsHandler::SetException(const base::ListValue* args) { 1340 std::string type_string; 1341 CHECK(args->GetString(0, &type_string)); 1342 std::string mode; 1343 CHECK(args->GetString(1, &mode)); 1344 std::string pattern; 1345 CHECK(args->GetString(2, &pattern)); 1346 std::string setting; 1347 CHECK(args->GetString(3, &setting)); 1348 1349 ContentSettingsType type = ContentSettingsTypeFromGroupName(type_string); 1350 if (type == CONTENT_SETTINGS_TYPE_GEOLOCATION || 1351 type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS || 1352 type == CONTENT_SETTINGS_TYPE_MEDIASTREAM || 1353 type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC || 1354 type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA) { 1355 NOTREACHED(); 1356 } else { 1357 HostContentSettingsMap* settings_map = 1358 mode == "normal" ? GetContentSettingsMap() : 1359 GetOTRContentSettingsMap(); 1360 1361 // The settings map could be null if the mode was OTR but the OTR profile 1362 // got destroyed before we received this message. 1363 if (!settings_map) 1364 return; 1365 settings_map->SetContentSetting(ContentSettingsPattern::FromString(pattern), 1366 ContentSettingsPattern::Wildcard(), 1367 type, 1368 std::string(), 1369 ContentSettingFromString(setting)); 1370 } 1371} 1372 1373void ContentSettingsHandler::CheckExceptionPatternValidity( 1374 const base::ListValue* args) { 1375 std::string type_string; 1376 CHECK(args->GetString(0, &type_string)); 1377 std::string mode_string; 1378 CHECK(args->GetString(1, &mode_string)); 1379 std::string pattern_string; 1380 CHECK(args->GetString(2, &pattern_string)); 1381 1382 ContentSettingsPattern pattern = 1383 ContentSettingsPattern::FromString(pattern_string); 1384 1385 web_ui()->CallJavascriptFunction( 1386 "ContentSettings.patternValidityCheckComplete", 1387 base::StringValue(type_string), 1388 base::StringValue(mode_string), 1389 base::StringValue(pattern_string), 1390 base::FundamentalValue(pattern.IsValid())); 1391} 1392 1393// static 1394std::string ContentSettingsHandler::ContentSettingsTypeToGroupName( 1395 ContentSettingsType type) { 1396 for (size_t i = 0; i < arraysize(kContentSettingsTypeGroupNames); ++i) { 1397 if (type == kContentSettingsTypeGroupNames[i].type) 1398 return kContentSettingsTypeGroupNames[i].name; 1399 } 1400 1401 NOTREACHED(); 1402 return std::string(); 1403} 1404 1405HostContentSettingsMap* ContentSettingsHandler::GetContentSettingsMap() { 1406 return Profile::FromWebUI(web_ui())->GetHostContentSettingsMap(); 1407} 1408 1409ProtocolHandlerRegistry* ContentSettingsHandler::GetProtocolHandlerRegistry() { 1410 return ProtocolHandlerRegistryFactory::GetForBrowserContext( 1411 GetBrowserContext(web_ui())); 1412} 1413 1414HostContentSettingsMap* 1415 ContentSettingsHandler::GetOTRContentSettingsMap() { 1416 Profile* profile = Profile::FromWebUI(web_ui()); 1417 if (profile->HasOffTheRecordProfile()) 1418 return profile->GetOffTheRecordProfile()->GetHostContentSettingsMap(); 1419 return NULL; 1420} 1421 1422void ContentSettingsHandler::RefreshFlashMediaSettings() { 1423 media_settings_.flash_settings_initialized = false; 1424 1425 media_settings_.last_flash_refresh_request_id = 1426 flash_settings_manager_->GetPermissionSettings( 1427 PP_FLASH_BROWSEROPERATIONS_SETTINGTYPE_CAMERAMIC); 1428} 1429 1430void ContentSettingsHandler::OnPepperFlashPrefChanged() { 1431 ShowFlashMediaLink(DEFAULT_SETTING, false); 1432 ShowFlashMediaLink(EXCEPTIONS, false); 1433 1434 PrefService* prefs = user_prefs::UserPrefs::Get(GetBrowserContext(web_ui())); 1435 if (prefs->GetBoolean(prefs::kPepperFlashSettingsEnabled)) 1436 RefreshFlashMediaSettings(); 1437 else 1438 media_settings_.flash_settings_initialized = false; 1439} 1440 1441void ContentSettingsHandler::OnZoomLevelChanged( 1442 const content::HostZoomMap::ZoomLevelChange& change) { 1443 UpdateZoomLevelsExceptionsView(); 1444} 1445 1446void ContentSettingsHandler::ShowFlashMediaLink(LinkType link_type, bool show) { 1447 bool& show_link = link_type == DEFAULT_SETTING ? 1448 media_settings_.show_flash_default_link : 1449 media_settings_.show_flash_exceptions_link; 1450 if (show_link != show) { 1451 web_ui()->CallJavascriptFunction( 1452 link_type == DEFAULT_SETTING ? 1453 "ContentSettings.showMediaPepperFlashDefaultLink" : 1454 "ContentSettings.showMediaPepperFlashExceptionsLink", 1455 base::FundamentalValue(show)); 1456 show_link = show; 1457 } 1458} 1459 1460void ContentSettingsHandler::UpdateFlashMediaLinksVisibility() { 1461 if (!media_settings_.flash_settings_initialized || 1462 !media_settings_.default_setting_initialized || 1463 !media_settings_.exceptions_initialized) { 1464 return; 1465 } 1466 1467 // Flash won't send us notifications when its settings get changed, which 1468 // means the Flash settings in |media_settings_| may be out-dated, especially 1469 // after we show links to change Flash settings. 1470 // In order to avoid confusion, we won't hide the links once they are showed. 1471 // One exception is that we will hide them when Pepper Flash is disabled 1472 // (handled in OnPepperFlashPrefChanged()). 1473 if (media_settings_.show_flash_default_link && 1474 media_settings_.show_flash_exceptions_link) { 1475 return; 1476 } 1477 1478 if (!media_settings_.show_flash_default_link) { 1479 // If both audio and video capture are disabled by policy, the link 1480 // shouldn't be showed. Flash conforms to the policy in this case because 1481 // it cannot open those devices. We don't have to look at the Flash 1482 // settings. 1483 if (!(media_settings_.policy_disable_audio && 1484 media_settings_.policy_disable_video) && 1485 media_settings_.flash_default_setting != 1486 media_settings_.default_setting) { 1487 ShowFlashMediaLink(DEFAULT_SETTING, true); 1488 } 1489 } 1490 if (!media_settings_.show_flash_exceptions_link) { 1491 // If audio or video capture is disabled by policy, we skip comparison of 1492 // exceptions for audio or video capture, respectively. 1493 if (!PepperFlashContentSettingsUtils::AreMediaExceptionsEqual( 1494 media_settings_.default_setting, 1495 media_settings_.exceptions, 1496 media_settings_.flash_default_setting, 1497 media_settings_.flash_exceptions, 1498 media_settings_.policy_disable_audio, 1499 media_settings_.policy_disable_video)) { 1500 ShowFlashMediaLink(EXCEPTIONS, true); 1501 } 1502 } 1503} 1504 1505void ContentSettingsHandler::UpdateProtectedContentExceptionsButton() { 1506#if defined(OS_CHROMEOS) 1507 // Guests cannot modify exceptions. UIAccountTweaks will disabled the button. 1508 if (user_manager::UserManager::Get()->IsLoggedInAsGuest()) 1509 return; 1510#endif 1511 1512 // Exceptions apply only when the feature is enabled. 1513 PrefService* prefs = user_prefs::UserPrefs::Get(GetBrowserContext(web_ui())); 1514 bool enable_exceptions = prefs->GetBoolean(prefs::kEnableDRM); 1515 web_ui()->CallJavascriptFunction( 1516 "ContentSettings.enableProtectedContentExceptions", 1517 base::FundamentalValue(enable_exceptions)); 1518} 1519 1520} // namespace options 1521