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