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 <string>
8#include <vector>
9
10#include "base/bind.h"
11#include "base/bind_helpers.h"
12#include "base/command_line.h"
13#include "base/i18n/time_formatting.h"
14#include "base/metrics/histogram.h"
15#include "base/strings/string_number_conversions.h"
16#include "base/strings/utf_string_conversions.h"
17#include "base/values.h"
18#include "chrome/browser/browsing_data/browsing_data_cookie_helper.h"
19#include "chrome/browser/browsing_data/browsing_data_database_helper.h"
20#include "chrome/browser/browsing_data/browsing_data_file_system_helper.h"
21#include "chrome/browser/browsing_data/browsing_data_indexed_db_helper.h"
22#include "chrome/browser/browsing_data/browsing_data_local_storage_helper.h"
23#include "chrome/browser/browsing_data/browsing_data_server_bound_cert_helper.h"
24#include "chrome/browser/content_settings/content_settings_utils.h"
25#include "chrome/browser/content_settings/host_content_settings_map.h"
26#include "chrome/browser/content_settings/local_shared_objects_container.h"
27#include "chrome/browser/history/history_service_factory.h"
28#include "chrome/browser/profiles/profile.h"
29#include "chrome/browser/ssl/ssl_error_info.h"
30#include "chrome/browser/ui/website_settings/website_settings_infobar_delegate.h"
31#include "chrome/browser/ui/website_settings/website_settings_ui.h"
32#include "chrome/common/content_settings_pattern.h"
33#include "content/public/browser/browser_thread.h"
34#include "content/public/browser/cert_store.h"
35#include "content/public/browser/user_metrics.h"
36#include "content/public/common/content_switches.h"
37#include "content/public/common/signed_certificate_timestamp_id_and_status.h"
38#include "content/public/common/ssl_status.h"
39#include "content/public/common/url_constants.h"
40#include "grit/chromium_strings.h"
41#include "grit/generated_resources.h"
42#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
43#include "net/cert/cert_status_flags.h"
44#include "net/cert/x509_certificate.h"
45#include "net/ssl/ssl_cipher_suite_names.h"
46#include "net/ssl/ssl_connection_status_flags.h"
47#include "ui/base/l10n/l10n_util.h"
48#include "ui/base/resource/resource_bundle.h"
49
50#if defined(OS_CHROMEOS)
51#include "chrome/browser/chromeos/policy/policy_cert_service.h"
52#include "chrome/browser/chromeos/policy/policy_cert_service_factory.h"
53#endif
54
55using content::BrowserThread;
56
57namespace {
58
59// The list of content settings types to display on the Website Settings UI.
60ContentSettingsType kPermissionType[] = {
61  CONTENT_SETTINGS_TYPE_IMAGES,
62  CONTENT_SETTINGS_TYPE_JAVASCRIPT,
63  CONTENT_SETTINGS_TYPE_PLUGINS,
64  CONTENT_SETTINGS_TYPE_POPUPS,
65  CONTENT_SETTINGS_TYPE_GEOLOCATION,
66  CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
67  CONTENT_SETTINGS_TYPE_FULLSCREEN,
68  CONTENT_SETTINGS_TYPE_MOUSELOCK,
69  CONTENT_SETTINGS_TYPE_MEDIASTREAM,
70  CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS,
71  CONTENT_SETTINGS_TYPE_MIDI_SYSEX,
72};
73
74bool CertificateTransparencyStatusMatch(
75    const content::SignedCertificateTimestampIDStatusList& scts,
76    net::ct::SCTVerifyStatus status) {
77  for (content::SignedCertificateTimestampIDStatusList::const_iterator it =
78           scts.begin();
79       it != scts.end();
80       ++it) {
81    if (it->status == status)
82      return true;
83  }
84
85  return false;
86}
87
88int GetSiteIdentityDetailsMessageByCTInfo(
89    const content::SignedCertificateTimestampIDStatusList& scts,
90    bool is_ev) {
91  // No SCTs - no CT information.
92  if (scts.empty())
93    return (is_ev ? IDS_PAGE_INFO_SECURITY_TAB_SECURE_IDENTITY_EV_NO_CT
94                  : IDS_PAGE_INFO_SECURITY_TAB_SECURE_IDENTITY_NO_CT);
95
96  if (CertificateTransparencyStatusMatch(scts, net::ct::SCT_STATUS_OK))
97    return (is_ev ? IDS_PAGE_INFO_SECURITY_TAB_SECURE_IDENTITY_EV_CT_VERIFIED
98                  : IDS_PAGE_INFO_SECURITY_TAB_SECURE_IDENTITY_CT_VERIFIED);
99
100  if (CertificateTransparencyStatusMatch(scts, net::ct::SCT_STATUS_INVALID))
101    return (is_ev ? IDS_PAGE_INFO_SECURITY_TAB_SECURE_IDENTITY_EV_CT_INVALID
102                  : IDS_PAGE_INFO_SECURITY_TAB_SECURE_IDENTITY_CT_INVALID);
103
104  // status is SCT_STATUS_LOG_UNKNOWN
105  return (is_ev ? IDS_PAGE_INFO_SECURITY_TAB_SECURE_IDENTITY_EV_CT_UNVERIFIED
106                : IDS_PAGE_INFO_SECURITY_TAB_SECURE_IDENTITY_CT_UNVERIFIED);
107}
108
109// This function will return SITE_IDENTITY_STATUS_CERT or
110// SITE_IDENTITY_STATUS_EV_CERT depending on |is_ev| unless there are SCTs
111// which failed verification, in which case it will return
112// SITE_IDENTITY_STATUS_ERROR.
113WebsiteSettings::SiteIdentityStatus GetSiteIdentityStatusByCTInfo(
114    const content::SignedCertificateTimestampIDStatusList& scts,
115    bool is_ev) {
116  if (CertificateTransparencyStatusMatch(scts, net::ct::SCT_STATUS_INVALID))
117    return WebsiteSettings::SITE_IDENTITY_STATUS_ERROR;
118
119  return is_ev ? WebsiteSettings::SITE_IDENTITY_STATUS_EV_CERT
120               : WebsiteSettings::SITE_IDENTITY_STATUS_CERT;
121}
122
123}  // namespace
124
125WebsiteSettings::WebsiteSettings(
126    WebsiteSettingsUI* ui,
127    Profile* profile,
128    TabSpecificContentSettings* tab_specific_content_settings,
129    InfoBarService* infobar_service,
130    const GURL& url,
131    const content::SSLStatus& ssl,
132    content::CertStore* cert_store)
133    : TabSpecificContentSettings::SiteDataObserver(
134          tab_specific_content_settings),
135      ui_(ui),
136      infobar_service_(infobar_service),
137      show_info_bar_(false),
138      site_url_(url),
139      site_identity_status_(SITE_IDENTITY_STATUS_UNKNOWN),
140      cert_id_(0),
141      site_connection_status_(SITE_CONNECTION_STATUS_UNKNOWN),
142      cert_store_(cert_store),
143      content_settings_(profile->GetHostContentSettingsMap()) {
144  Init(profile, url, ssl);
145
146  HistoryService* history_service = HistoryServiceFactory::GetForProfile(
147      profile, Profile::EXPLICIT_ACCESS);
148  if (history_service) {
149    history_service->GetVisibleVisitCountToHost(
150        site_url_,
151        &visit_count_request_consumer_,
152        base::Bind(&WebsiteSettings::OnGotVisitCountToHost,
153                   base::Unretained(this)));
154  }
155
156  PresentSitePermissions();
157  PresentSiteData();
158  PresentSiteIdentity();
159  PresentHistoryInfo(base::Time());
160
161  // Every time the Website Settings UI is opened a |WebsiteSettings| object is
162  // created. So this counts how ofter the Website Settings UI is opened.
163  content::RecordAction(content::UserMetricsAction("WebsiteSettings_Opened"));
164}
165
166WebsiteSettings::~WebsiteSettings() {
167}
168
169void WebsiteSettings::OnSitePermissionChanged(ContentSettingsType type,
170                                              ContentSetting setting) {
171  // Count how often a permission for a specific content type is changed using
172  // the Website Settings UI.
173  UMA_HISTOGRAM_COUNTS("WebsiteSettings.PermissionChanged", type);
174
175  ContentSettingsPattern primary_pattern;
176  ContentSettingsPattern secondary_pattern;
177  switch (type) {
178    case CONTENT_SETTINGS_TYPE_GEOLOCATION:
179    case CONTENT_SETTINGS_TYPE_MIDI_SYSEX:
180      // TODO(markusheintz): The rule we create here should also change the
181      // location permission for iframed content.
182      primary_pattern = ContentSettingsPattern::FromURLNoWildcard(site_url_);
183      secondary_pattern = ContentSettingsPattern::FromURLNoWildcard(site_url_);
184      break;
185    case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
186      primary_pattern = ContentSettingsPattern::FromURLNoWildcard(site_url_);
187      secondary_pattern = ContentSettingsPattern::Wildcard();
188      break;
189    case CONTENT_SETTINGS_TYPE_IMAGES:
190    case CONTENT_SETTINGS_TYPE_JAVASCRIPT:
191    case CONTENT_SETTINGS_TYPE_PLUGINS:
192    case CONTENT_SETTINGS_TYPE_POPUPS:
193    case CONTENT_SETTINGS_TYPE_FULLSCREEN:
194    case CONTENT_SETTINGS_TYPE_MOUSELOCK:
195    case CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS:
196      primary_pattern = ContentSettingsPattern::FromURL(site_url_);
197      secondary_pattern = ContentSettingsPattern::Wildcard();
198      break;
199    case CONTENT_SETTINGS_TYPE_MEDIASTREAM: {
200      // We need to use the same same patterns as other places like infobar code
201      // to override the existing rule instead of creating the new one.
202      primary_pattern = ContentSettingsPattern::FromURLNoWildcard(site_url_);
203      secondary_pattern = ContentSettingsPattern::Wildcard();
204      // Set permission for both microphone and camera.
205      content_settings_->SetContentSetting(
206          primary_pattern,
207          secondary_pattern,
208          CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
209          std::string(),
210          setting);
211
212      content_settings_->SetContentSetting(
213          primary_pattern,
214          secondary_pattern,
215          CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA,
216          std::string(),
217          setting);
218      break;
219    }
220    default:
221      NOTREACHED() << "ContentSettingsType " << type << "is not supported.";
222      break;
223  }
224
225  if (type != CONTENT_SETTINGS_TYPE_MEDIASTREAM) {
226    // Permission settings are specified via rules. There exists always at least
227    // one rule for the default setting. Get the rule that currently defines
228    // the permission for the given permission |type|. Then test whether the
229    // existing rule is more specific than the rule we are about to create. If
230    // the existing rule is more specific, than change the existing rule instead
231    // of creating a new rule that would be hidden behind the existing rule.
232    // This is not a concern for CONTENT_SETTINGS_TYPE_MEDIASTREAM since users
233    // can not create media settings exceptions by hand.
234    content_settings::SettingInfo info;
235    scoped_ptr<Value> v(content_settings_->GetWebsiteSetting(
236        site_url_, site_url_, type, std::string(), &info));
237    DCHECK(info.source == content_settings::SETTING_SOURCE_USER);
238    ContentSettingsPattern::Relation r1 =
239        info.primary_pattern.Compare(primary_pattern);
240    DCHECK(r1 != ContentSettingsPattern::DISJOINT_ORDER_POST &&
241           r1 != ContentSettingsPattern::DISJOINT_ORDER_PRE);
242    if (r1 == ContentSettingsPattern::PREDECESSOR) {
243      primary_pattern = info.primary_pattern;
244    } else if (r1 == ContentSettingsPattern::IDENTITY) {
245      ContentSettingsPattern::Relation r2 =
246          info.secondary_pattern.Compare(secondary_pattern);
247      DCHECK(r2 != ContentSettingsPattern::DISJOINT_ORDER_POST &&
248             r2 != ContentSettingsPattern::DISJOINT_ORDER_PRE);
249      if (r2 == ContentSettingsPattern::PREDECESSOR)
250        secondary_pattern = info.secondary_pattern;
251    }
252
253    Value* value = NULL;
254    if (setting != CONTENT_SETTING_DEFAULT)
255      value = Value::CreateIntegerValue(setting);
256    content_settings_->SetWebsiteSetting(
257        primary_pattern, secondary_pattern, type, std::string(), value);
258  }
259
260  show_info_bar_ = true;
261
262// TODO(markusheintz): This is a temporary hack to fix issue:
263// http://crbug.com/144203.
264#if defined(OS_MACOSX)
265  // Refresh the UI to reflect the new setting.
266  PresentSitePermissions();
267#endif
268}
269
270void WebsiteSettings::OnGotVisitCountToHost(HistoryService::Handle handle,
271                                            bool found_visits,
272                                            int visit_count,
273                                            base::Time first_visit) {
274  if (!found_visits) {
275    // This indicates an error, such as the page's URL scheme wasn't
276    // http/https.
277    first_visit = base::Time();
278  } else if (visit_count == 0) {
279    first_visit = base::Time::Now();
280  }
281  PresentHistoryInfo(first_visit);
282}
283
284void WebsiteSettings::OnSiteDataAccessed() {
285  PresentSiteData();
286}
287
288void WebsiteSettings::OnUIClosing() {
289  if (show_info_bar_)
290    WebsiteSettingsInfoBarDelegate::Create(infobar_service_);
291}
292
293void WebsiteSettings::Init(Profile* profile,
294                           const GURL& url,
295                           const content::SSLStatus& ssl) {
296  if (url.SchemeIs(chrome::kChromeUIScheme)) {
297    site_identity_status_ = SITE_IDENTITY_STATUS_INTERNAL_PAGE;
298    site_identity_details_ =
299        l10n_util::GetStringUTF16(IDS_PAGE_INFO_INTERNAL_PAGE);
300    site_connection_status_ = SITE_CONNECTION_STATUS_INTERNAL_PAGE;
301    return;
302  }
303
304  scoped_refptr<net::X509Certificate> cert;
305
306  // Identity section.
307  base::string16 subject_name(UTF8ToUTF16(url.host()));
308  if (subject_name.empty()) {
309    subject_name.assign(
310        l10n_util::GetStringUTF16(IDS_PAGE_INFO_SECURITY_TAB_UNKNOWN_PARTY));
311  }
312
313  cert_id_ = ssl.cert_id;
314
315  if (ssl.cert_id &&
316      cert_store_->RetrieveCert(ssl.cert_id, &cert) &&
317      (!net::IsCertStatusError(ssl.cert_status) ||
318       net::IsCertStatusMinorError(ssl.cert_status))) {
319    // There are no major errors. Check for minor errors.
320#if defined(OS_CHROMEOS)
321    policy::PolicyCertService* service =
322        policy::PolicyCertServiceFactory::GetForProfile(profile);
323    const bool used_policy_certs = service && service->UsedPolicyCertificates();
324#else
325    const bool used_policy_certs = false;
326#endif
327    if (used_policy_certs) {
328      site_identity_status_ = SITE_IDENTITY_STATUS_ADMIN_PROVIDED_CERT;
329      site_identity_details_ = l10n_util::GetStringFUTF16(
330          IDS_CERT_POLICY_PROVIDED_CERT_MESSAGE, UTF8ToUTF16(url.host()));
331    } else if (net::IsCertStatusMinorError(ssl.cert_status)) {
332      site_identity_status_ = SITE_IDENTITY_STATUS_CERT_REVOCATION_UNKNOWN;
333      base::string16 issuer_name(UTF8ToUTF16(cert->issuer().GetDisplayName()));
334      if (issuer_name.empty()) {
335        issuer_name.assign(l10n_util::GetStringUTF16(
336            IDS_PAGE_INFO_SECURITY_TAB_UNKNOWN_PARTY));
337      }
338
339      site_identity_details_.assign(l10n_util::GetStringFUTF16(
340          GetSiteIdentityDetailsMessageByCTInfo(
341              ssl.signed_certificate_timestamp_ids, false /* not EV */),
342          issuer_name));
343
344      site_identity_details_ += ASCIIToUTF16("\n\n");
345      if (ssl.cert_status & net::CERT_STATUS_UNABLE_TO_CHECK_REVOCATION) {
346        site_identity_details_ += l10n_util::GetStringUTF16(
347            IDS_PAGE_INFO_SECURITY_TAB_UNABLE_TO_CHECK_REVOCATION);
348      } else if (ssl.cert_status & net::CERT_STATUS_NO_REVOCATION_MECHANISM) {
349        site_identity_details_ += l10n_util::GetStringUTF16(
350            IDS_PAGE_INFO_SECURITY_TAB_NO_REVOCATION_MECHANISM);
351      } else {
352        NOTREACHED() << "Need to specify string for this warning";
353      }
354    } else if (ssl.cert_status & net::CERT_STATUS_IS_EV) {
355      // EV HTTPS page.
356      site_identity_status_ = GetSiteIdentityStatusByCTInfo(
357          ssl.signed_certificate_timestamp_ids, true);
358      DCHECK(!cert->subject().organization_names.empty());
359      organization_name_ = UTF8ToUTF16(cert->subject().organization_names[0]);
360      // An EV Cert is required to have a city (localityName) and country but
361      // state is "if any".
362      DCHECK(!cert->subject().locality_name.empty());
363      DCHECK(!cert->subject().country_name.empty());
364      base::string16 locality;
365      if (!cert->subject().state_or_province_name.empty()) {
366        locality = l10n_util::GetStringFUTF16(
367            IDS_PAGEINFO_ADDRESS,
368            UTF8ToUTF16(cert->subject().locality_name),
369            UTF8ToUTF16(cert->subject().state_or_province_name),
370            UTF8ToUTF16(cert->subject().country_name));
371      } else {
372        locality = l10n_util::GetStringFUTF16(
373            IDS_PAGEINFO_PARTIAL_ADDRESS,
374            UTF8ToUTF16(cert->subject().locality_name),
375            UTF8ToUTF16(cert->subject().country_name));
376      }
377      DCHECK(!cert->subject().organization_names.empty());
378      site_identity_details_.assign(l10n_util::GetStringFUTF16(
379          GetSiteIdentityDetailsMessageByCTInfo(
380              ssl.signed_certificate_timestamp_ids, true /* is EV */),
381          UTF8ToUTF16(cert->subject().organization_names[0]),
382          locality,
383          UTF8ToUTF16(cert->issuer().GetDisplayName())));
384    } else {
385      // Non-EV OK HTTPS page.
386      site_identity_status_ = GetSiteIdentityStatusByCTInfo(
387          ssl.signed_certificate_timestamp_ids, false);
388      base::string16 issuer_name(UTF8ToUTF16(cert->issuer().GetDisplayName()));
389      if (issuer_name.empty()) {
390        issuer_name.assign(l10n_util::GetStringUTF16(
391            IDS_PAGE_INFO_SECURITY_TAB_UNKNOWN_PARTY));
392      }
393
394      site_identity_details_.assign(l10n_util::GetStringFUTF16(
395          GetSiteIdentityDetailsMessageByCTInfo(
396              ssl.signed_certificate_timestamp_ids, false /* not EV */),
397          issuer_name));
398    }
399  } else {
400    // HTTP or HTTPS with errors (not warnings).
401    site_identity_details_.assign(l10n_util::GetStringUTF16(
402        IDS_PAGE_INFO_SECURITY_TAB_INSECURE_IDENTITY));
403    if (ssl.security_style == content::SECURITY_STYLE_UNAUTHENTICATED)
404      site_identity_status_ = SITE_IDENTITY_STATUS_NO_CERT;
405    else
406      site_identity_status_ = SITE_IDENTITY_STATUS_ERROR;
407
408    const base::string16 bullet = UTF8ToUTF16("\n • ");
409    std::vector<SSLErrorInfo> errors;
410    SSLErrorInfo::GetErrorsForCertStatus(ssl.cert_id, ssl.cert_status,
411                                         url, &errors);
412    for (size_t i = 0; i < errors.size(); ++i) {
413      site_identity_details_ += bullet;
414      site_identity_details_ += errors[i].short_description();
415    }
416
417    if (ssl.cert_status & net::CERT_STATUS_NON_UNIQUE_NAME) {
418      site_identity_details_ += ASCIIToUTF16("\n\n");
419      site_identity_details_ += l10n_util::GetStringUTF16(
420          IDS_PAGE_INFO_SECURITY_TAB_NON_UNIQUE_NAME);
421    }
422  }
423
424  // Site Connection
425  // We consider anything less than 80 bits encryption to be weak encryption.
426  // TODO(wtc): Bug 1198735: report mixed/unsafe content for unencrypted and
427  // weakly encrypted connections.
428  site_connection_status_ = SITE_CONNECTION_STATUS_UNKNOWN;
429
430  if (!ssl.cert_id) {
431    // Not HTTPS.
432    DCHECK_EQ(ssl.security_style, content::SECURITY_STYLE_UNAUTHENTICATED);
433    if (ssl.security_style == content::SECURITY_STYLE_UNAUTHENTICATED)
434      site_connection_status_ = SITE_CONNECTION_STATUS_UNENCRYPTED;
435    else
436      site_connection_status_ = SITE_CONNECTION_STATUS_ENCRYPTED_ERROR;
437
438    site_connection_details_.assign(l10n_util::GetStringFUTF16(
439        IDS_PAGE_INFO_SECURITY_TAB_NOT_ENCRYPTED_CONNECTION_TEXT,
440        subject_name));
441  } else if (ssl.security_bits < 0) {
442    // Security strength is unknown.  Say nothing.
443    site_connection_status_ = SITE_CONNECTION_STATUS_ENCRYPTED_ERROR;
444  } else if (ssl.security_bits == 0) {
445    DCHECK_NE(ssl.security_style, content::SECURITY_STYLE_UNAUTHENTICATED);
446    site_connection_status_ = SITE_CONNECTION_STATUS_ENCRYPTED_ERROR;
447    site_connection_details_.assign(l10n_util::GetStringFUTF16(
448        IDS_PAGE_INFO_SECURITY_TAB_NOT_ENCRYPTED_CONNECTION_TEXT,
449        subject_name));
450  } else if (ssl.security_bits < 80) {
451    site_connection_status_ = SITE_CONNECTION_STATUS_ENCRYPTED_ERROR;
452    site_connection_details_.assign(l10n_util::GetStringFUTF16(
453        IDS_PAGE_INFO_SECURITY_TAB_WEAK_ENCRYPTION_CONNECTION_TEXT,
454        subject_name));
455  } else {
456    site_connection_status_ = SITE_CONNECTION_STATUS_ENCRYPTED;
457    site_connection_details_.assign(l10n_util::GetStringFUTF16(
458        IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_CONNECTION_TEXT,
459        subject_name,
460        base::IntToString16(ssl.security_bits)));
461    if (ssl.content_status) {
462      bool ran_insecure_content =
463          !!(ssl.content_status & content::SSLStatus::RAN_INSECURE_CONTENT);
464      site_connection_status_ = ran_insecure_content ?
465          SITE_CONNECTION_STATUS_ENCRYPTED_ERROR
466          : SITE_CONNECTION_STATUS_MIXED_CONTENT;
467      site_connection_details_.assign(l10n_util::GetStringFUTF16(
468          IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_SENTENCE_LINK,
469          site_connection_details_,
470          l10n_util::GetStringUTF16(ran_insecure_content ?
471              IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_INSECURE_CONTENT_ERROR :
472              IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_INSECURE_CONTENT_WARNING)));
473    }
474  }
475
476  uint16 cipher_suite =
477      net::SSLConnectionStatusToCipherSuite(ssl.connection_status);
478  if (ssl.security_bits > 0 && cipher_suite) {
479    int ssl_version =
480        net::SSLConnectionStatusToVersion(ssl.connection_status);
481    const char* ssl_version_str;
482    net::SSLVersionToString(&ssl_version_str, ssl_version);
483    site_connection_details_ += ASCIIToUTF16("\n\n");
484    site_connection_details_ += l10n_util::GetStringFUTF16(
485        IDS_PAGE_INFO_SECURITY_TAB_SSL_VERSION,
486        ASCIIToUTF16(ssl_version_str));
487
488    bool did_fallback = (ssl.connection_status &
489                         net::SSL_CONNECTION_VERSION_FALLBACK) != 0;
490    bool no_renegotiation =
491        (ssl.connection_status &
492        net::SSL_CONNECTION_NO_RENEGOTIATION_EXTENSION) != 0;
493    const char *key_exchange, *cipher, *mac;
494    bool is_aead;
495    net::SSLCipherSuiteToStrings(
496        &key_exchange, &cipher, &mac, &is_aead, cipher_suite);
497
498    site_connection_details_ += ASCIIToUTF16("\n\n");
499    if (is_aead) {
500      site_connection_details_ += l10n_util::GetStringFUTF16(
501          IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTION_DETAILS_AEAD,
502          ASCIIToUTF16(cipher), ASCIIToUTF16(key_exchange));
503    } else {
504      site_connection_details_ += l10n_util::GetStringFUTF16(
505          IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTION_DETAILS,
506          ASCIIToUTF16(cipher), ASCIIToUTF16(mac), ASCIIToUTF16(key_exchange));
507    }
508
509    if (did_fallback) {
510      // For now, only SSLv3 fallback will trigger a warning icon.
511      if (site_connection_status_ < SITE_CONNECTION_STATUS_MIXED_CONTENT)
512        site_connection_status_ = SITE_CONNECTION_STATUS_MIXED_CONTENT;
513      site_connection_details_ += ASCIIToUTF16("\n\n");
514      site_connection_details_ += l10n_util::GetStringUTF16(
515          IDS_PAGE_INFO_SECURITY_TAB_FALLBACK_MESSAGE);
516    }
517    if (no_renegotiation) {
518      site_connection_details_ += ASCIIToUTF16("\n\n");
519      site_connection_details_ += l10n_util::GetStringUTF16(
520          IDS_PAGE_INFO_SECURITY_TAB_RENEGOTIATION_MESSAGE);
521    }
522  }
523
524  // By default select the permissions tab that displays all the site
525  // permissions. In case of a connection error or an issue with the
526  // certificate presented by the website, select the connection tab to draw
527  // the user's attention to the issue. If the site does not provide a
528  // certificate because it was loaded over an unencrypted connection, don't
529  // select the connection tab.
530  WebsiteSettingsUI::TabId tab_id = WebsiteSettingsUI::TAB_ID_PERMISSIONS;
531  if (site_connection_status_ == SITE_CONNECTION_STATUS_ENCRYPTED_ERROR ||
532      site_connection_status_ == SITE_CONNECTION_STATUS_MIXED_CONTENT ||
533      site_identity_status_ == SITE_IDENTITY_STATUS_ERROR ||
534      site_identity_status_ == SITE_IDENTITY_STATUS_CERT_REVOCATION_UNKNOWN ||
535      site_identity_status_ == SITE_IDENTITY_STATUS_ADMIN_PROVIDED_CERT)
536    tab_id = WebsiteSettingsUI::TAB_ID_CONNECTION;
537  ui_->SetSelectedTab(tab_id);
538}
539
540void WebsiteSettings::PresentSitePermissions() {
541  PermissionInfoList permission_info_list;
542
543  WebsiteSettingsUI::PermissionInfo permission_info;
544  for (size_t i = 0; i < arraysize(kPermissionType); ++i) {
545    permission_info.type = kPermissionType[i];
546    if (permission_info.type == CONTENT_SETTINGS_TYPE_MIDI_SYSEX) {
547      const CommandLine* command_line = CommandLine::ForCurrentProcess();
548      if (!command_line->HasSwitch(switches::kEnableWebMIDI))
549        continue;
550    }
551
552    content_settings::SettingInfo info;
553    if (permission_info.type == CONTENT_SETTINGS_TYPE_MEDIASTREAM) {
554      scoped_ptr<base::Value> mic_value(content_settings_->GetWebsiteSetting(
555          site_url_,
556          site_url_,
557          CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
558          std::string(),
559          &info));
560      ContentSetting mic_setting =
561          content_settings::ValueToContentSetting(mic_value.get());
562
563      scoped_ptr<base::Value> camera_value(content_settings_->GetWebsiteSetting(
564          site_url_,
565          site_url_,
566          CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA,
567          std::string(),
568          &info));
569      ContentSetting camera_setting =
570          content_settings::ValueToContentSetting(camera_value.get());
571
572      if (mic_setting != camera_setting || mic_setting == CONTENT_SETTING_ASK)
573        permission_info.setting = CONTENT_SETTING_DEFAULT;
574      else
575        permission_info.setting = mic_setting;
576    } else {
577      scoped_ptr<Value> value(content_settings_->GetWebsiteSetting(
578          site_url_, site_url_, permission_info.type, std::string(), &info));
579      DCHECK(value.get());
580      if (value->GetType() == Value::TYPE_INTEGER) {
581        permission_info.setting =
582            content_settings::ValueToContentSetting(value.get());
583      } else {
584        NOTREACHED();
585      }
586    }
587
588    permission_info.source = info.source;
589
590    if (info.primary_pattern == ContentSettingsPattern::Wildcard() &&
591        info.secondary_pattern == ContentSettingsPattern::Wildcard() &&
592        permission_info.type != CONTENT_SETTINGS_TYPE_MEDIASTREAM) {
593      permission_info.default_setting = permission_info.setting;
594      permission_info.setting = CONTENT_SETTING_DEFAULT;
595    } else {
596      permission_info.default_setting =
597          content_settings_->GetDefaultContentSetting(permission_info.type,
598                                                      NULL);
599    }
600    permission_info_list.push_back(permission_info);
601  }
602
603  ui_->SetPermissionInfo(permission_info_list);
604}
605
606void WebsiteSettings::PresentSiteData() {
607  CookieInfoList cookie_info_list;
608  const LocalSharedObjectsContainer& allowed_objects =
609      tab_specific_content_settings()->allowed_local_shared_objects();
610  const LocalSharedObjectsContainer& blocked_objects =
611      tab_specific_content_settings()->blocked_local_shared_objects();
612
613  // Add first party cookie and site data counts.
614  WebsiteSettingsUI::CookieInfo cookie_info;
615  std::string cookie_source =
616      net::registry_controlled_domains::GetDomainAndRegistry(
617          site_url_,
618          net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
619  if (cookie_source.empty())
620    cookie_source = site_url_.host();
621  cookie_info.cookie_source = cookie_source;
622  cookie_info.allowed = allowed_objects.GetObjectCountForDomain(site_url_);
623  cookie_info.blocked = blocked_objects.GetObjectCountForDomain(site_url_);
624  cookie_info_list.push_back(cookie_info);
625
626  // Add third party cookie counts.
627  cookie_info.cookie_source = l10n_util::GetStringUTF8(
628     IDS_WEBSITE_SETTINGS_THIRD_PARTY_SITE_DATA);
629  cookie_info.allowed = allowed_objects.GetObjectCount() - cookie_info.allowed;
630  cookie_info.blocked = blocked_objects.GetObjectCount() - cookie_info.blocked;
631  cookie_info_list.push_back(cookie_info);
632
633  ui_->SetCookieInfo(cookie_info_list);
634}
635
636void WebsiteSettings::PresentSiteIdentity() {
637  // After initialization the status about the site's connection
638  // and it's identity must be available.
639  DCHECK_NE(site_identity_status_, SITE_IDENTITY_STATUS_UNKNOWN);
640  DCHECK_NE(site_connection_status_, SITE_CONNECTION_STATUS_UNKNOWN);
641  WebsiteSettingsUI::IdentityInfo info;
642  if (site_identity_status_ == SITE_IDENTITY_STATUS_EV_CERT)
643    info.site_identity = UTF16ToUTF8(organization_name());
644  else
645    info.site_identity = site_url_.host();
646
647  info.connection_status = site_connection_status_;
648  info.connection_status_description =
649      UTF16ToUTF8(site_connection_details_);
650  info.identity_status = site_identity_status_;
651  info.identity_status_description =
652      UTF16ToUTF8(site_identity_details_);
653  info.cert_id = cert_id_;
654  ui_->SetIdentityInfo(info);
655}
656
657void WebsiteSettings::PresentHistoryInfo(base::Time first_visit) {
658  if (first_visit == base::Time()) {
659    ui_->SetFirstVisit(base::string16());
660    return;
661  }
662
663  bool visited_before_today = false;
664  base::Time today = base::Time::Now().LocalMidnight();
665  base::Time first_visit_midnight = first_visit.LocalMidnight();
666  visited_before_today = (first_visit_midnight < today);
667
668  base::string16 first_visit_text;
669  if (visited_before_today) {
670    first_visit_text = l10n_util::GetStringFUTF16(
671        IDS_PAGE_INFO_SECURITY_TAB_VISITED_BEFORE_TODAY,
672        base::TimeFormatShortDate(first_visit));
673  } else {
674    first_visit_text = l10n_util::GetStringUTF16(
675        IDS_PAGE_INFO_SECURITY_TAB_FIRST_VISITED_TODAY);
676
677  }
678  ui_->SetFirstVisit(first_visit_text);
679}
680