| OLD | NEW |
| (Empty) |
| 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/website_settings/website_settings.h" | |
| 6 | |
| 7 #include <stddef.h> | |
| 8 #include <stdint.h> | |
| 9 | |
| 10 #include <string> | |
| 11 #include <vector> | |
| 12 | |
| 13 #include "base/command_line.h" | |
| 14 #include "base/i18n/time_formatting.h" | |
| 15 #include "base/macros.h" | |
| 16 #include "base/memory/ptr_util.h" | |
| 17 #include "base/metrics/field_trial.h" | |
| 18 #include "base/metrics/histogram_macros.h" | |
| 19 #include "base/strings/string_number_conversions.h" | |
| 20 #include "base/strings/utf_string_conversions.h" | |
| 21 #include "base/values.h" | |
| 22 #include "build/build_config.h" | |
| 23 #include "chrome/browser/browser_process.h" | |
| 24 #include "chrome/browser/browsing_data/browsing_data_channel_id_helper.h" | |
| 25 #include "chrome/browser/browsing_data/browsing_data_cookie_helper.h" | |
| 26 #include "chrome/browser/browsing_data/browsing_data_database_helper.h" | |
| 27 #include "chrome/browser/browsing_data/browsing_data_file_system_helper.h" | |
| 28 #include "chrome/browser/browsing_data/browsing_data_indexed_db_helper.h" | |
| 29 #include "chrome/browser/browsing_data/browsing_data_local_storage_helper.h" | |
| 30 #include "chrome/browser/content_settings/host_content_settings_map_factory.h" | |
| 31 #include "chrome/browser/content_settings/local_shared_objects_container.h" | |
| 32 #include "chrome/browser/history/history_service_factory.h" | |
| 33 #include "chrome/browser/infobars/infobar_service.h" | |
| 34 #include "chrome/browser/permissions/chooser_context_base.h" | |
| 35 #include "chrome/browser/permissions/permission_manager.h" | |
| 36 #include "chrome/browser/permissions/permission_result.h" | |
| 37 #include "chrome/browser/permissions/permission_uma_util.h" | |
| 38 #include "chrome/browser/permissions/permission_util.h" | |
| 39 #include "chrome/browser/profiles/profile.h" | |
| 40 #include "chrome/browser/ssl/chrome_ssl_host_state_delegate.h" | |
| 41 #include "chrome/browser/ssl/chrome_ssl_host_state_delegate_factory.h" | |
| 42 #include "chrome/browser/ui/website_settings/website_settings_ui.h" | |
| 43 #include "chrome/browser/usb/usb_chooser_context.h" | |
| 44 #include "chrome/browser/usb/usb_chooser_context_factory.h" | |
| 45 #include "chrome/common/chrome_switches.h" | |
| 46 #include "chrome/common/url_constants.h" | |
| 47 #include "chrome/grit/chromium_strings.h" | |
| 48 #include "chrome/grit/generated_resources.h" | |
| 49 #include "chrome/grit/theme_resources.h" | |
| 50 #include "components/content_settings/core/browser/content_settings_utils.h" | |
| 51 #include "components/content_settings/core/browser/host_content_settings_map.h" | |
| 52 #include "components/content_settings/core/common/content_settings.h" | |
| 53 #include "components/content_settings/core/common/content_settings_pattern.h" | |
| 54 #include "components/rappor/public/rappor_utils.h" | |
| 55 #include "components/rappor/rappor_service_impl.h" | |
| 56 #include "components/ssl_errors/error_info.h" | |
| 57 #include "components/strings/grit/components_chromium_strings.h" | |
| 58 #include "components/strings/grit/components_strings.h" | |
| 59 #include "components/url_formatter/elide_url.h" | |
| 60 #include "content/public/browser/browser_thread.h" | |
| 61 #include "content/public/browser/user_metrics.h" | |
| 62 #include "content/public/common/content_switches.h" | |
| 63 #include "content/public/common/url_constants.h" | |
| 64 #include "net/cert/cert_status_flags.h" | |
| 65 #include "net/cert/x509_certificate.h" | |
| 66 #include "net/ssl/ssl_cipher_suite_names.h" | |
| 67 #include "net/ssl/ssl_connection_status_flags.h" | |
| 68 #include "third_party/boringssl/src/include/openssl/ssl.h" | |
| 69 #include "ui/base/l10n/l10n_util.h" | |
| 70 | |
| 71 #if defined(OS_CHROMEOS) | |
| 72 #include "chrome/browser/chromeos/policy/policy_cert_service.h" | |
| 73 #include "chrome/browser/chromeos/policy/policy_cert_service_factory.h" | |
| 74 #endif | |
| 75 | |
| 76 #if !defined(OS_ANDROID) | |
| 77 #include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h" | |
| 78 #include "chrome/browser/ui/website_settings/website_settings_infobar_delegate.h
" | |
| 79 #endif | |
| 80 | |
| 81 using base::ASCIIToUTF16; | |
| 82 using base::UTF8ToUTF16; | |
| 83 using base::UTF16ToUTF8; | |
| 84 using content::BrowserThread; | |
| 85 | |
| 86 namespace { | |
| 87 | |
| 88 // Events for UMA. Do not reorder or change! | |
| 89 enum SSLCertificateDecisionsDidRevoke { | |
| 90 USER_CERT_DECISIONS_NOT_REVOKED = 0, | |
| 91 USER_CERT_DECISIONS_REVOKED, | |
| 92 END_OF_SSL_CERTIFICATE_DECISIONS_DID_REVOKE_ENUM | |
| 93 }; | |
| 94 | |
| 95 // The list of content settings types to display on the Website Settings UI. THE | |
| 96 // ORDER OF THESE ITEMS IS IMPORTANT. To propose changing it, email | |
| 97 // security-dev@chromium.org. | |
| 98 ContentSettingsType kPermissionType[] = { | |
| 99 CONTENT_SETTINGS_TYPE_GEOLOCATION, | |
| 100 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, | |
| 101 CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, | |
| 102 CONTENT_SETTINGS_TYPE_NOTIFICATIONS, | |
| 103 CONTENT_SETTINGS_TYPE_JAVASCRIPT, | |
| 104 #if !defined(OS_ANDROID) | |
| 105 CONTENT_SETTINGS_TYPE_PLUGINS, | |
| 106 CONTENT_SETTINGS_TYPE_IMAGES, | |
| 107 #endif | |
| 108 CONTENT_SETTINGS_TYPE_POPUPS, | |
| 109 CONTENT_SETTINGS_TYPE_BACKGROUND_SYNC, | |
| 110 CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, | |
| 111 CONTENT_SETTINGS_TYPE_AUTOPLAY, | |
| 112 CONTENT_SETTINGS_TYPE_MIDI_SYSEX, | |
| 113 }; | |
| 114 | |
| 115 // Determines whether to show permission |type| in the Website Settings UI. Only | |
| 116 // applies to permissions listed in |kPermissionType|. | |
| 117 bool ShouldShowPermission(ContentSettingsType type) { | |
| 118 #if !defined(OS_ANDROID) | |
| 119 // Autoplay is Android-only at the moment. | |
| 120 if (type == CONTENT_SETTINGS_TYPE_AUTOPLAY) | |
| 121 return false; | |
| 122 #endif | |
| 123 | |
| 124 return true; | |
| 125 } | |
| 126 | |
| 127 void CheckContentStatus(security_state::ContentStatus content_status, | |
| 128 bool* displayed, | |
| 129 bool* ran) { | |
| 130 switch (content_status) { | |
| 131 case security_state::CONTENT_STATUS_DISPLAYED: | |
| 132 *displayed = true; | |
| 133 break; | |
| 134 case security_state::CONTENT_STATUS_RAN: | |
| 135 *ran = true; | |
| 136 break; | |
| 137 case security_state::CONTENT_STATUS_DISPLAYED_AND_RAN: | |
| 138 *displayed = true; | |
| 139 *ran = true; | |
| 140 break; | |
| 141 case security_state::CONTENT_STATUS_UNKNOWN: | |
| 142 case security_state::CONTENT_STATUS_NONE: | |
| 143 break; | |
| 144 } | |
| 145 } | |
| 146 | |
| 147 void CheckForInsecureContent( | |
| 148 const security_state::SecurityInfo& security_info, | |
| 149 bool* displayed, | |
| 150 bool* ran) { | |
| 151 CheckContentStatus(security_info.mixed_content_status, displayed, ran); | |
| 152 // Only consider subresources with certificate errors if the main | |
| 153 // resource was loaded over HTTPS without major certificate errors. If | |
| 154 // the main resource had a certificate error, then it would not be | |
| 155 // that useful (and would potentially be confusing) to warn about | |
| 156 // subesources that had certificate errors too. | |
| 157 if (net::IsCertStatusError(security_info.cert_status) && | |
| 158 !net::IsCertStatusMinorError(security_info.cert_status)) { | |
| 159 return; | |
| 160 } | |
| 161 CheckContentStatus(security_info.content_with_cert_errors_status, displayed, | |
| 162 ran); | |
| 163 } | |
| 164 | |
| 165 void GetSiteIdentityByMaliciousContentStatus( | |
| 166 security_state::MaliciousContentStatus malicious_content_status, | |
| 167 WebsiteSettings::SiteIdentityStatus* status, | |
| 168 base::string16* details) { | |
| 169 switch (malicious_content_status) { | |
| 170 case security_state::MALICIOUS_CONTENT_STATUS_NONE: | |
| 171 NOTREACHED(); | |
| 172 break; | |
| 173 case security_state::MALICIOUS_CONTENT_STATUS_MALWARE: | |
| 174 *status = WebsiteSettings::SITE_IDENTITY_STATUS_MALWARE; | |
| 175 *details = | |
| 176 l10n_util::GetStringUTF16(IDS_PAGEINFO_MALWARE_DETAILS); | |
| 177 break; | |
| 178 case security_state::MALICIOUS_CONTENT_STATUS_SOCIAL_ENGINEERING: | |
| 179 *status = WebsiteSettings::SITE_IDENTITY_STATUS_SOCIAL_ENGINEERING; | |
| 180 *details = l10n_util::GetStringUTF16( | |
| 181 IDS_PAGEINFO_SOCIAL_ENGINEERING_DETAILS); | |
| 182 break; | |
| 183 case security_state::MALICIOUS_CONTENT_STATUS_UNWANTED_SOFTWARE: | |
| 184 *status = WebsiteSettings::SITE_IDENTITY_STATUS_UNWANTED_SOFTWARE; | |
| 185 *details = l10n_util::GetStringUTF16( | |
| 186 IDS_PAGEINFO_UNWANTED_SOFTWARE_DETAILS); | |
| 187 break; | |
| 188 } | |
| 189 } | |
| 190 | |
| 191 base::string16 GetSimpleSiteName(const GURL& url) { | |
| 192 return url_formatter::FormatUrlForSecurityDisplay( | |
| 193 url, url_formatter::SchemeDisplay::OMIT_HTTP_AND_HTTPS); | |
| 194 } | |
| 195 | |
| 196 ChooserContextBase* GetUsbChooserContext(Profile* profile) { | |
| 197 return UsbChooserContextFactory::GetForProfile(profile); | |
| 198 } | |
| 199 | |
| 200 // The list of chooser types that need to display entries in the Website | |
| 201 // Settings UI. THE ORDER OF THESE ITEMS IS IMPORTANT. To propose changing it, | |
| 202 // email security-dev@chromium.org. | |
| 203 WebsiteSettings::ChooserUIInfo kChooserUIInfo[] = { | |
| 204 {CONTENT_SETTINGS_TYPE_USB_CHOOSER_DATA, &GetUsbChooserContext, | |
| 205 IDR_BLOCKED_USB, IDR_ALLOWED_USB, IDS_WEBSITE_SETTINGS_USB_DEVICE_LABEL, | |
| 206 IDS_WEBSITE_SETTINGS_DELETE_USB_DEVICE, "name"}, | |
| 207 }; | |
| 208 | |
| 209 } // namespace | |
| 210 | |
| 211 WebsiteSettings::WebsiteSettings( | |
| 212 WebsiteSettingsUI* ui, | |
| 213 Profile* profile, | |
| 214 TabSpecificContentSettings* tab_specific_content_settings, | |
| 215 content::WebContents* web_contents, | |
| 216 const GURL& url, | |
| 217 const security_state::SecurityInfo& security_info) | |
| 218 : TabSpecificContentSettings::SiteDataObserver( | |
| 219 tab_specific_content_settings), | |
| 220 content::WebContentsObserver(web_contents), | |
| 221 ui_(ui), | |
| 222 show_info_bar_(false), | |
| 223 site_url_(url), | |
| 224 site_identity_status_(SITE_IDENTITY_STATUS_UNKNOWN), | |
| 225 site_connection_status_(SITE_CONNECTION_STATUS_UNKNOWN), | |
| 226 show_ssl_decision_revoke_button_(false), | |
| 227 content_settings_(HostContentSettingsMapFactory::GetForProfile(profile)), | |
| 228 chrome_ssl_host_state_delegate_( | |
| 229 ChromeSSLHostStateDelegateFactory::GetForProfile(profile)), | |
| 230 did_revoke_user_ssl_decisions_(false), | |
| 231 profile_(profile), | |
| 232 security_level_(security_state::NONE) { | |
| 233 Init(url, security_info); | |
| 234 | |
| 235 PresentSitePermissions(); | |
| 236 PresentSiteData(); | |
| 237 PresentSiteIdentity(); | |
| 238 | |
| 239 // Every time the Website Settings UI is opened a |WebsiteSettings| object is | |
| 240 // created. So this counts how ofter the Website Settings UI is opened. | |
| 241 RecordWebsiteSettingsAction(WEBSITE_SETTINGS_OPENED); | |
| 242 } | |
| 243 | |
| 244 WebsiteSettings::~WebsiteSettings() { | |
| 245 } | |
| 246 | |
| 247 void WebsiteSettings::RecordWebsiteSettingsAction( | |
| 248 WebsiteSettingsAction action) { | |
| 249 UMA_HISTOGRAM_ENUMERATION("WebsiteSettings.Action", | |
| 250 action, | |
| 251 WEBSITE_SETTINGS_COUNT); | |
| 252 | |
| 253 std::string histogram_name; | |
| 254 | |
| 255 if (site_url_.SchemeIsCryptographic()) { | |
| 256 if (security_level_ == security_state::SECURE || | |
| 257 security_level_ == security_state::EV_SECURE) { | |
| 258 UMA_HISTOGRAM_ENUMERATION("Security.PageInfo.Action.HttpsUrl.Valid", | |
| 259 action, WEBSITE_SETTINGS_COUNT); | |
| 260 } else if (security_level_ == security_state::NONE) { | |
| 261 UMA_HISTOGRAM_ENUMERATION("Security.PageInfo.Action.HttpsUrl.Downgraded", | |
| 262 action, WEBSITE_SETTINGS_COUNT); | |
| 263 } else if (security_level_ == security_state::DANGEROUS) { | |
| 264 UMA_HISTOGRAM_ENUMERATION("Security.PageInfo.Action.HttpsUrl.Dangerous", | |
| 265 action, WEBSITE_SETTINGS_COUNT); | |
| 266 } | |
| 267 return; | |
| 268 } | |
| 269 | |
| 270 if (security_level_ == security_state::HTTP_SHOW_WARNING) { | |
| 271 UMA_HISTOGRAM_ENUMERATION("Security.PageInfo.Action.HttpUrl.Warning", | |
| 272 action, WEBSITE_SETTINGS_COUNT); | |
| 273 } else if (security_level_ == security_state::DANGEROUS) { | |
| 274 UMA_HISTOGRAM_ENUMERATION("Security.PageInfo.Action.HttpUrl.Dangerous", | |
| 275 action, WEBSITE_SETTINGS_COUNT); | |
| 276 } else { | |
| 277 UMA_HISTOGRAM_ENUMERATION("Security.PageInfo.Action.HttpUrl.Neutral", | |
| 278 action, WEBSITE_SETTINGS_COUNT); | |
| 279 } | |
| 280 } | |
| 281 | |
| 282 void WebsiteSettings::OnSitePermissionChanged(ContentSettingsType type, | |
| 283 ContentSetting setting) { | |
| 284 // Count how often a permission for a specific content type is changed using | |
| 285 // the Website Settings UI. | |
| 286 size_t num_values; | |
| 287 int histogram_value = ContentSettingTypeToHistogramValue(type, &num_values); | |
| 288 UMA_HISTOGRAM_ENUMERATION("WebsiteSettings.OriginInfo.PermissionChanged", | |
| 289 histogram_value, num_values); | |
| 290 | |
| 291 if (setting == ContentSetting::CONTENT_SETTING_ALLOW) { | |
| 292 UMA_HISTOGRAM_ENUMERATION( | |
| 293 "WebsiteSettings.OriginInfo.PermissionChanged.Allowed", histogram_value, | |
| 294 num_values); | |
| 295 | |
| 296 if (type == CONTENT_SETTINGS_TYPE_PLUGINS) { | |
| 297 rappor::SampleDomainAndRegistryFromGURL( | |
| 298 g_browser_process->rappor_service(), | |
| 299 "ContentSettings.Plugins.AddedAllowException", site_url_); | |
| 300 } | |
| 301 } else if (setting == ContentSetting::CONTENT_SETTING_BLOCK) { | |
| 302 UMA_HISTOGRAM_ENUMERATION( | |
| 303 "WebsiteSettings.OriginInfo.PermissionChanged.Blocked", histogram_value, | |
| 304 num_values); | |
| 305 } | |
| 306 | |
| 307 // This is technically redundant given the histogram above, but putting the | |
| 308 // total count of permission changes in another histogram makes it easier to | |
| 309 // compare it against other kinds of actions in WebsiteSettings[PopupView]. | |
| 310 RecordWebsiteSettingsAction(WEBSITE_SETTINGS_CHANGED_PERMISSION); | |
| 311 | |
| 312 PermissionUtil::ScopedRevocationReporter scoped_revocation_reporter( | |
| 313 this->profile_, this->site_url_, this->site_url_, type, | |
| 314 PermissionSourceUI::OIB); | |
| 315 | |
| 316 content_settings_->SetNarrowestContentSetting(site_url_, site_url_, type, | |
| 317 setting); | |
| 318 | |
| 319 show_info_bar_ = true; | |
| 320 | |
| 321 // Refresh the UI to reflect the new setting. | |
| 322 PresentSitePermissions(); | |
| 323 } | |
| 324 | |
| 325 void WebsiteSettings::OnSiteChosenObjectDeleted( | |
| 326 const ChooserUIInfo& ui_info, | |
| 327 const base::DictionaryValue& object) { | |
| 328 // TODO(reillyg): Create metrics for revocations. crbug.com/556845 | |
| 329 ChooserContextBase* context = ui_info.get_context(profile_); | |
| 330 const GURL origin = site_url_.GetOrigin(); | |
| 331 context->RevokeObjectPermission(origin, origin, object); | |
| 332 | |
| 333 show_info_bar_ = true; | |
| 334 | |
| 335 // Refresh the UI to reflect the changed settings. | |
| 336 PresentSitePermissions(); | |
| 337 } | |
| 338 | |
| 339 void WebsiteSettings::OnSiteDataAccessed() { | |
| 340 PresentSiteData(); | |
| 341 } | |
| 342 | |
| 343 void WebsiteSettings::OnUIClosing() { | |
| 344 #if defined(OS_ANDROID) | |
| 345 NOTREACHED(); | |
| 346 #else | |
| 347 if (show_info_bar_ && web_contents() && !web_contents()->IsBeingDestroyed()) { | |
| 348 InfoBarService* infobar_service = | |
| 349 InfoBarService::FromWebContents(web_contents()); | |
| 350 if (infobar_service) | |
| 351 WebsiteSettingsInfoBarDelegate::Create(infobar_service); | |
| 352 } | |
| 353 | |
| 354 SSLCertificateDecisionsDidRevoke user_decision = | |
| 355 did_revoke_user_ssl_decisions_ ? USER_CERT_DECISIONS_REVOKED | |
| 356 : USER_CERT_DECISIONS_NOT_REVOKED; | |
| 357 | |
| 358 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.did_user_revoke_decisions", | |
| 359 user_decision, | |
| 360 END_OF_SSL_CERTIFICATE_DECISIONS_DID_REVOKE_ENUM); | |
| 361 #endif | |
| 362 } | |
| 363 | |
| 364 void WebsiteSettings::OnRevokeSSLErrorBypassButtonPressed() { | |
| 365 DCHECK(chrome_ssl_host_state_delegate_); | |
| 366 chrome_ssl_host_state_delegate_->RevokeUserAllowExceptionsHard( | |
| 367 site_url().host()); | |
| 368 did_revoke_user_ssl_decisions_ = true; | |
| 369 } | |
| 370 | |
| 371 void WebsiteSettings::Init(const GURL& url, | |
| 372 const security_state::SecurityInfo& security_info) { | |
| 373 #if !defined(OS_ANDROID) && !defined(OS_IOS) | |
| 374 // On desktop, internal URLs aren't handled by this class. Instead, a | |
| 375 // custom and simpler popup is shown. | |
| 376 DCHECK(!url.SchemeIs(content::kChromeUIScheme) && | |
| 377 !url.SchemeIs(content::kChromeDevToolsScheme) && | |
| 378 !url.SchemeIs(content::kViewSourceScheme) && | |
| 379 !url.SchemeIs(content_settings::kExtensionScheme)); | |
| 380 #endif | |
| 381 | |
| 382 bool isChromeUINativeScheme = false; | |
| 383 #if defined(OS_ANDROID) | |
| 384 isChromeUINativeScheme = url.SchemeIs(chrome::kChromeUINativeScheme); | |
| 385 #endif | |
| 386 | |
| 387 security_level_ = security_info.security_level; | |
| 388 | |
| 389 if (url.SchemeIs(url::kAboutScheme)) { | |
| 390 // All about: URLs except about:blank are redirected. | |
| 391 DCHECK_EQ(url::kAboutBlankURL, url.spec()); | |
| 392 site_identity_status_ = SITE_IDENTITY_STATUS_NO_CERT; | |
| 393 site_identity_details_ = | |
| 394 l10n_util::GetStringUTF16(IDS_PAGE_INFO_SECURITY_TAB_INSECURE_IDENTITY); | |
| 395 site_connection_status_ = SITE_CONNECTION_STATUS_UNENCRYPTED; | |
| 396 site_connection_details_ = l10n_util::GetStringFUTF16( | |
| 397 IDS_PAGE_INFO_SECURITY_TAB_NOT_ENCRYPTED_CONNECTION_TEXT, | |
| 398 UTF8ToUTF16(url.spec())); | |
| 399 return; | |
| 400 } | |
| 401 | |
| 402 if (url.SchemeIs(content::kChromeUIScheme) || isChromeUINativeScheme) { | |
| 403 site_identity_status_ = SITE_IDENTITY_STATUS_INTERNAL_PAGE; | |
| 404 site_identity_details_ = | |
| 405 l10n_util::GetStringUTF16(IDS_PAGE_INFO_INTERNAL_PAGE); | |
| 406 site_connection_status_ = SITE_CONNECTION_STATUS_INTERNAL_PAGE; | |
| 407 return; | |
| 408 } | |
| 409 | |
| 410 // Identity section. | |
| 411 certificate_ = security_info.certificate; | |
| 412 | |
| 413 if (security_info.malicious_content_status != | |
| 414 security_state::MALICIOUS_CONTENT_STATUS_NONE) { | |
| 415 // The site has been flagged by Safe Browsing as dangerous. | |
| 416 GetSiteIdentityByMaliciousContentStatus( | |
| 417 security_info.malicious_content_status, &site_identity_status_, | |
| 418 &site_identity_details_); | |
| 419 } else if (certificate_ && | |
| 420 (!net::IsCertStatusError(security_info.cert_status) || | |
| 421 net::IsCertStatusMinorError(security_info.cert_status))) { | |
| 422 // HTTPS with no or minor errors. | |
| 423 if (security_info.security_level == | |
| 424 security_state::SECURE_WITH_POLICY_INSTALLED_CERT) { | |
| 425 site_identity_status_ = SITE_IDENTITY_STATUS_ADMIN_PROVIDED_CERT; | |
| 426 site_identity_details_ = l10n_util::GetStringFUTF16( | |
| 427 IDS_CERT_POLICY_PROVIDED_CERT_MESSAGE, UTF8ToUTF16(url.host())); | |
| 428 } else if (net::IsCertStatusMinorError(security_info.cert_status)) { | |
| 429 site_identity_status_ = SITE_IDENTITY_STATUS_CERT_REVOCATION_UNKNOWN; | |
| 430 base::string16 issuer_name( | |
| 431 UTF8ToUTF16(certificate_->issuer().GetDisplayName())); | |
| 432 if (issuer_name.empty()) { | |
| 433 issuer_name.assign(l10n_util::GetStringUTF16( | |
| 434 IDS_PAGE_INFO_SECURITY_TAB_UNKNOWN_PARTY)); | |
| 435 } | |
| 436 | |
| 437 site_identity_details_.assign(l10n_util::GetStringFUTF16( | |
| 438 IDS_PAGE_INFO_SECURITY_TAB_SECURE_IDENTITY_VERIFIED, issuer_name)); | |
| 439 | |
| 440 site_identity_details_ += ASCIIToUTF16("\n\n"); | |
| 441 if (security_info.cert_status & | |
| 442 net::CERT_STATUS_UNABLE_TO_CHECK_REVOCATION) { | |
| 443 site_identity_details_ += l10n_util::GetStringUTF16( | |
| 444 IDS_PAGE_INFO_SECURITY_TAB_UNABLE_TO_CHECK_REVOCATION); | |
| 445 } else if (security_info.cert_status & | |
| 446 net::CERT_STATUS_NO_REVOCATION_MECHANISM) { | |
| 447 site_identity_details_ += l10n_util::GetStringUTF16( | |
| 448 IDS_PAGE_INFO_SECURITY_TAB_NO_REVOCATION_MECHANISM); | |
| 449 } else { | |
| 450 NOTREACHED() << "Need to specify string for this warning"; | |
| 451 } | |
| 452 } else { | |
| 453 // No major or minor errors. | |
| 454 if (security_info.cert_status & net::CERT_STATUS_IS_EV) { | |
| 455 // EV HTTPS page. | |
| 456 site_identity_status_ = SITE_IDENTITY_STATUS_EV_CERT; | |
| 457 DCHECK(!certificate_->subject().organization_names.empty()); | |
| 458 organization_name_ = | |
| 459 UTF8ToUTF16(certificate_->subject().organization_names[0]); | |
| 460 // An EV Cert is required to have a city (localityName) and country but | |
| 461 // state is "if any". | |
| 462 DCHECK(!certificate_->subject().locality_name.empty()); | |
| 463 DCHECK(!certificate_->subject().country_name.empty()); | |
| 464 base::string16 locality; | |
| 465 if (!certificate_->subject().state_or_province_name.empty()) { | |
| 466 locality = l10n_util::GetStringFUTF16( | |
| 467 IDS_PAGEINFO_ADDRESS, | |
| 468 UTF8ToUTF16(certificate_->subject().locality_name), | |
| 469 UTF8ToUTF16(certificate_->subject().state_or_province_name), | |
| 470 UTF8ToUTF16(certificate_->subject().country_name)); | |
| 471 } else { | |
| 472 locality = l10n_util::GetStringFUTF16( | |
| 473 IDS_PAGEINFO_PARTIAL_ADDRESS, | |
| 474 UTF8ToUTF16(certificate_->subject().locality_name), | |
| 475 UTF8ToUTF16(certificate_->subject().country_name)); | |
| 476 } | |
| 477 DCHECK(!certificate_->subject().organization_names.empty()); | |
| 478 site_identity_details_.assign(l10n_util::GetStringFUTF16( | |
| 479 IDS_PAGE_INFO_SECURITY_TAB_SECURE_IDENTITY_EV_VERIFIED, | |
| 480 UTF8ToUTF16(certificate_->subject().organization_names[0]), | |
| 481 locality, UTF8ToUTF16(certificate_->issuer().GetDisplayName()))); | |
| 482 } else { | |
| 483 // Non-EV OK HTTPS page. | |
| 484 site_identity_status_ = SITE_IDENTITY_STATUS_CERT; | |
| 485 base::string16 issuer_name( | |
| 486 UTF8ToUTF16(certificate_->issuer().GetDisplayName())); | |
| 487 if (issuer_name.empty()) { | |
| 488 issuer_name.assign(l10n_util::GetStringUTF16( | |
| 489 IDS_PAGE_INFO_SECURITY_TAB_UNKNOWN_PARTY)); | |
| 490 } | |
| 491 | |
| 492 site_identity_details_.assign(l10n_util::GetStringFUTF16( | |
| 493 IDS_PAGE_INFO_SECURITY_TAB_SECURE_IDENTITY_VERIFIED, issuer_name)); | |
| 494 } | |
| 495 if (security_info.sha1_in_chain) { | |
| 496 site_identity_status_ = | |
| 497 SITE_IDENTITY_STATUS_DEPRECATED_SIGNATURE_ALGORITHM; | |
| 498 site_identity_details_ += | |
| 499 UTF8ToUTF16("\n\n") + | |
| 500 l10n_util::GetStringUTF16( | |
| 501 IDS_PAGE_INFO_SECURITY_TAB_DEPRECATED_SIGNATURE_ALGORITHM); | |
| 502 } | |
| 503 } | |
| 504 } else { | |
| 505 // HTTP or HTTPS with errors (not warnings). | |
| 506 site_identity_details_.assign(l10n_util::GetStringUTF16( | |
| 507 IDS_PAGE_INFO_SECURITY_TAB_INSECURE_IDENTITY)); | |
| 508 if (!security_info.scheme_is_cryptographic || !security_info.certificate) | |
| 509 site_identity_status_ = SITE_IDENTITY_STATUS_NO_CERT; | |
| 510 else | |
| 511 site_identity_status_ = SITE_IDENTITY_STATUS_ERROR; | |
| 512 | |
| 513 const base::string16 bullet = UTF8ToUTF16("\n • "); | |
| 514 std::vector<ssl_errors::ErrorInfo> errors; | |
| 515 ssl_errors::ErrorInfo::GetErrorsForCertStatus( | |
| 516 certificate_, security_info.cert_status, url, &errors); | |
| 517 for (size_t i = 0; i < errors.size(); ++i) { | |
| 518 site_identity_details_ += bullet; | |
| 519 site_identity_details_ += errors[i].short_description(); | |
| 520 } | |
| 521 | |
| 522 if (security_info.cert_status & net::CERT_STATUS_NON_UNIQUE_NAME) { | |
| 523 site_identity_details_ += ASCIIToUTF16("\n\n"); | |
| 524 site_identity_details_ += l10n_util::GetStringUTF16( | |
| 525 IDS_PAGE_INFO_SECURITY_TAB_NON_UNIQUE_NAME); | |
| 526 } | |
| 527 } | |
| 528 | |
| 529 // Site Connection | |
| 530 // We consider anything less than 80 bits encryption to be weak encryption. | |
| 531 // TODO(wtc): Bug 1198735: report mixed/unsafe content for unencrypted and | |
| 532 // weakly encrypted connections. | |
| 533 site_connection_status_ = SITE_CONNECTION_STATUS_UNKNOWN; | |
| 534 | |
| 535 base::string16 subject_name(GetSimpleSiteName(url)); | |
| 536 if (subject_name.empty()) { | |
| 537 subject_name.assign( | |
| 538 l10n_util::GetStringUTF16(IDS_PAGE_INFO_SECURITY_TAB_UNKNOWN_PARTY)); | |
| 539 } | |
| 540 | |
| 541 if (!security_info.certificate || !security_info.scheme_is_cryptographic) { | |
| 542 // Page is still loading (so SSL status is not yet available) or | |
| 543 // loaded over HTTP or loaded over HTTPS with no cert. | |
| 544 site_connection_status_ = SITE_CONNECTION_STATUS_UNENCRYPTED; | |
| 545 | |
| 546 site_connection_details_.assign(l10n_util::GetStringFUTF16( | |
| 547 IDS_PAGE_INFO_SECURITY_TAB_NOT_ENCRYPTED_CONNECTION_TEXT, | |
| 548 subject_name)); | |
| 549 } else if (security_info.security_bits < 0) { | |
| 550 // Security strength is unknown. Say nothing. | |
| 551 site_connection_status_ = SITE_CONNECTION_STATUS_ENCRYPTED_ERROR; | |
| 552 } else if (security_info.security_bits == 0) { | |
| 553 DCHECK_NE(security_info.security_level, security_state::NONE); | |
| 554 site_connection_status_ = SITE_CONNECTION_STATUS_ENCRYPTED_ERROR; | |
| 555 site_connection_details_.assign(l10n_util::GetStringFUTF16( | |
| 556 IDS_PAGE_INFO_SECURITY_TAB_NOT_ENCRYPTED_CONNECTION_TEXT, | |
| 557 subject_name)); | |
| 558 } else { | |
| 559 site_connection_status_ = SITE_CONNECTION_STATUS_ENCRYPTED; | |
| 560 | |
| 561 if (security_info.obsolete_ssl_status == net::OBSOLETE_SSL_NONE) { | |
| 562 site_connection_details_.assign(l10n_util::GetStringFUTF16( | |
| 563 IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_CONNECTION_TEXT, | |
| 564 subject_name)); | |
| 565 } else { | |
| 566 site_connection_details_.assign(l10n_util::GetStringFUTF16( | |
| 567 IDS_PAGE_INFO_SECURITY_TAB_WEAK_ENCRYPTION_CONNECTION_TEXT, | |
| 568 subject_name)); | |
| 569 } | |
| 570 | |
| 571 bool ran_insecure_content = false; | |
| 572 bool displayed_insecure_content = false; | |
| 573 CheckForInsecureContent(security_info, &displayed_insecure_content, | |
| 574 &ran_insecure_content); | |
| 575 if (ran_insecure_content || displayed_insecure_content) { | |
| 576 site_connection_status_ = | |
| 577 ran_insecure_content | |
| 578 ? SITE_CONNECTION_STATUS_INSECURE_ACTIVE_SUBRESOURCE | |
| 579 : SITE_CONNECTION_STATUS_INSECURE_PASSIVE_SUBRESOURCE; | |
| 580 site_connection_details_.assign(l10n_util::GetStringFUTF16( | |
| 581 IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_SENTENCE_LINK, | |
| 582 site_connection_details_, | |
| 583 l10n_util::GetStringUTF16( | |
| 584 ran_insecure_content | |
| 585 ? IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_INSECURE_CONTENT_ERROR | |
| 586 : IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_INSECURE_CONTENT_WARNIN
G))); | |
| 587 } | |
| 588 } | |
| 589 | |
| 590 uint16_t cipher_suite = | |
| 591 net::SSLConnectionStatusToCipherSuite(security_info.connection_status); | |
| 592 if (security_info.security_bits > 0 && cipher_suite) { | |
| 593 int ssl_version = | |
| 594 net::SSLConnectionStatusToVersion(security_info.connection_status); | |
| 595 const char* ssl_version_str; | |
| 596 net::SSLVersionToString(&ssl_version_str, ssl_version); | |
| 597 site_connection_details_ += ASCIIToUTF16("\n\n"); | |
| 598 site_connection_details_ += l10n_util::GetStringFUTF16( | |
| 599 IDS_PAGE_INFO_SECURITY_TAB_SSL_VERSION, | |
| 600 ASCIIToUTF16(ssl_version_str)); | |
| 601 | |
| 602 const char *key_exchange, *cipher, *mac; | |
| 603 bool is_aead, is_tls13; | |
| 604 net::SSLCipherSuiteToStrings(&key_exchange, &cipher, &mac, &is_aead, | |
| 605 &is_tls13, cipher_suite); | |
| 606 | |
| 607 site_connection_details_ += ASCIIToUTF16("\n\n"); | |
| 608 if (is_aead) { | |
| 609 if (is_tls13) { | |
| 610 // For TLS 1.3 ciphers, report the group (historically, curve) as the | |
| 611 // key exchange. | |
| 612 key_exchange = SSL_get_curve_name(security_info.key_exchange_group); | |
| 613 if (!key_exchange) { | |
| 614 NOTREACHED(); | |
| 615 key_exchange = ""; | |
| 616 } | |
| 617 } | |
| 618 site_connection_details_ += l10n_util::GetStringFUTF16( | |
| 619 IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTION_DETAILS_AEAD, | |
| 620 ASCIIToUTF16(cipher), ASCIIToUTF16(key_exchange)); | |
| 621 } else { | |
| 622 site_connection_details_ += l10n_util::GetStringFUTF16( | |
| 623 IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTION_DETAILS, | |
| 624 ASCIIToUTF16(cipher), ASCIIToUTF16(mac), ASCIIToUTF16(key_exchange)); | |
| 625 } | |
| 626 | |
| 627 if (ssl_version == net::SSL_CONNECTION_VERSION_SSL3 && | |
| 628 site_connection_status_ < | |
| 629 SITE_CONNECTION_STATUS_INSECURE_PASSIVE_SUBRESOURCE) { | |
| 630 site_connection_status_ = SITE_CONNECTION_STATUS_ENCRYPTED_ERROR; | |
| 631 } | |
| 632 } | |
| 633 | |
| 634 // Check if a user decision has been made to allow or deny certificates with | |
| 635 // errors on this site. | |
| 636 ChromeSSLHostStateDelegate* delegate = | |
| 637 ChromeSSLHostStateDelegateFactory::GetForProfile(profile_); | |
| 638 DCHECK(delegate); | |
| 639 // Only show an SSL decision revoke button if the user has chosen to bypass | |
| 640 // SSL host errors for this host in the past. | |
| 641 show_ssl_decision_revoke_button_ = delegate->HasAllowException(url.host()); | |
| 642 } | |
| 643 | |
| 644 void WebsiteSettings::PresentSitePermissions() { | |
| 645 PermissionInfoList permission_info_list; | |
| 646 ChosenObjectInfoList chosen_object_info_list; | |
| 647 | |
| 648 WebsiteSettingsUI::PermissionInfo permission_info; | |
| 649 for (size_t i = 0; i < arraysize(kPermissionType); ++i) { | |
| 650 permission_info.type = kPermissionType[i]; | |
| 651 | |
| 652 if (!ShouldShowPermission(permission_info.type)) | |
| 653 continue; | |
| 654 | |
| 655 content_settings::SettingInfo info; | |
| 656 std::unique_ptr<base::Value> value = content_settings_->GetWebsiteSetting( | |
| 657 site_url_, site_url_, permission_info.type, std::string(), &info); | |
| 658 DCHECK(value.get()); | |
| 659 if (value->GetType() == base::Value::Type::INTEGER) { | |
| 660 permission_info.setting = | |
| 661 content_settings::ValueToContentSetting(value.get()); | |
| 662 } else { | |
| 663 NOTREACHED(); | |
| 664 } | |
| 665 | |
| 666 permission_info.source = info.source; | |
| 667 permission_info.is_incognito = profile_->IsOffTheRecord(); | |
| 668 | |
| 669 if (info.primary_pattern == ContentSettingsPattern::Wildcard() && | |
| 670 info.secondary_pattern == ContentSettingsPattern::Wildcard()) { | |
| 671 permission_info.default_setting = permission_info.setting; | |
| 672 permission_info.setting = CONTENT_SETTING_DEFAULT; | |
| 673 } else { | |
| 674 permission_info.default_setting = | |
| 675 content_settings_->GetDefaultContentSetting(permission_info.type, | |
| 676 NULL); | |
| 677 } | |
| 678 | |
| 679 // For permissions that are still prompting the user and haven't been | |
| 680 // explicitly set by another source, check its embargo status. | |
| 681 if (PermissionUtil::IsPermission(permission_info.type) && | |
| 682 permission_info.setting == CONTENT_SETTING_DEFAULT && | |
| 683 permission_info.source == | |
| 684 content_settings::SettingSource::SETTING_SOURCE_USER) { | |
| 685 // TODO(raymes): Use GetPermissionStatus() to retrieve information | |
| 686 // about *all* permissions once it has default behaviour implemented for | |
| 687 // ContentSettingTypes that aren't permissions. | |
| 688 PermissionResult permission_result = | |
| 689 PermissionManager::Get(profile_)->GetPermissionStatus( | |
| 690 permission_info.type, site_url_, site_url_); | |
| 691 | |
| 692 // If under embargo, update |permission_info| to reflect that. | |
| 693 if (permission_result.content_setting == CONTENT_SETTING_BLOCK && | |
| 694 (permission_result.source == | |
| 695 PermissionStatusSource::MULTIPLE_DISMISSALS || | |
| 696 permission_result.source == | |
| 697 PermissionStatusSource::SAFE_BROWSING_BLACKLIST)) | |
| 698 permission_info.setting = permission_result.content_setting; | |
| 699 } | |
| 700 | |
| 701 permission_info_list.push_back(permission_info); | |
| 702 } | |
| 703 | |
| 704 for (const ChooserUIInfo& ui_info : kChooserUIInfo) { | |
| 705 ChooserContextBase* context = ui_info.get_context(profile_); | |
| 706 const GURL origin = site_url_.GetOrigin(); | |
| 707 auto chosen_objects = context->GetGrantedObjects(origin, origin); | |
| 708 for (std::unique_ptr<base::DictionaryValue>& object : chosen_objects) { | |
| 709 chosen_object_info_list.push_back( | |
| 710 base::MakeUnique<WebsiteSettingsUI::ChosenObjectInfo>( | |
| 711 ui_info, std::move(object))); | |
| 712 } | |
| 713 } | |
| 714 | |
| 715 ui_->SetPermissionInfo(permission_info_list, | |
| 716 std::move(chosen_object_info_list)); | |
| 717 } | |
| 718 | |
| 719 void WebsiteSettings::PresentSiteData() { | |
| 720 CookieInfoList cookie_info_list; | |
| 721 const LocalSharedObjectsContainer& allowed_objects = | |
| 722 tab_specific_content_settings()->allowed_local_shared_objects(); | |
| 723 const LocalSharedObjectsContainer& blocked_objects = | |
| 724 tab_specific_content_settings()->blocked_local_shared_objects(); | |
| 725 | |
| 726 // Add first party cookie and site data counts. | |
| 727 WebsiteSettingsUI::CookieInfo cookie_info; | |
| 728 cookie_info.allowed = allowed_objects.GetObjectCountForDomain(site_url_); | |
| 729 cookie_info.blocked = blocked_objects.GetObjectCountForDomain(site_url_); | |
| 730 cookie_info.is_first_party = true; | |
| 731 cookie_info_list.push_back(cookie_info); | |
| 732 | |
| 733 // Add third party cookie counts. | |
| 734 cookie_info.allowed = allowed_objects.GetObjectCount() - cookie_info.allowed; | |
| 735 cookie_info.blocked = blocked_objects.GetObjectCount() - cookie_info.blocked; | |
| 736 cookie_info.is_first_party = false; | |
| 737 cookie_info_list.push_back(cookie_info); | |
| 738 | |
| 739 ui_->SetCookieInfo(cookie_info_list); | |
| 740 } | |
| 741 | |
| 742 void WebsiteSettings::PresentSiteIdentity() { | |
| 743 // After initialization the status about the site's connection and its | |
| 744 // identity must be available. | |
| 745 DCHECK_NE(site_identity_status_, SITE_IDENTITY_STATUS_UNKNOWN); | |
| 746 DCHECK_NE(site_connection_status_, SITE_CONNECTION_STATUS_UNKNOWN); | |
| 747 WebsiteSettingsUI::IdentityInfo info; | |
| 748 if (site_identity_status_ == SITE_IDENTITY_STATUS_EV_CERT) | |
| 749 info.site_identity = UTF16ToUTF8(organization_name()); | |
| 750 else | |
| 751 info.site_identity = UTF16ToUTF8(GetSimpleSiteName(site_url_)); | |
| 752 | |
| 753 info.connection_status = site_connection_status_; | |
| 754 info.connection_status_description = | |
| 755 UTF16ToUTF8(site_connection_details_); | |
| 756 info.identity_status = site_identity_status_; | |
| 757 info.identity_status_description = | |
| 758 UTF16ToUTF8(site_identity_details_); | |
| 759 info.certificate = certificate_; | |
| 760 info.show_ssl_decision_revoke_button = show_ssl_decision_revoke_button_; | |
| 761 ui_->SetIdentityInfo(info); | |
| 762 } | |
| OLD | NEW |