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 |