blob: 44090a59c66511db4a4e3b49d0b00eca85eb4991 [file] [log] [blame]
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/page_info_model.h"
#include "app/l10n_util.h"
#include "base/i18n/time_formatting.h"
#include "chrome/browser/cert_store.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/ssl/ssl_manager.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/pref_service.h"
#include "grit/generated_resources.h"
#include "net/base/cert_status_flags.h"
#include "net/base/x509_certificate.h"
namespace {
// Returns a name that can be used to represent the issuer. It tries in this
// order CN, O and OU and returns the first non-empty one found.
std::string GetIssuerName(const net::X509Certificate::Principal& issuer) {
if (!issuer.common_name.empty())
return issuer.common_name;
if (!issuer.organization_names.empty())
return issuer.organization_names[0];
if (!issuer.organization_unit_names.empty())
return issuer.organization_unit_names[0];
return std::string();
}
}
PageInfoModel::PageInfoModel(Profile* profile,
const GURL& url,
const NavigationEntry::SSLStatus& ssl,
bool show_history,
PageInfoModelObserver* observer)
: observer_(observer) {
bool state = true;
string16 head_line;
string16 description;
scoped_refptr<net::X509Certificate> cert;
// Identity section.
string16 subject_name(UTF8ToUTF16(url.host()));
bool empty_subject_name = false;
if (subject_name.empty()) {
subject_name.assign(
l10n_util::GetStringUTF16(IDS_PAGE_INFO_SECURITY_TAB_UNKNOWN_PARTY));
empty_subject_name = true;
}
if (ssl.cert_id() &&
CertStore::GetSharedInstance()->RetrieveCert(ssl.cert_id(), &cert) &&
!net::IsCertStatusError(ssl.cert_status())) {
// OK HTTPS page.
if ((ssl.cert_status() & net::CERT_STATUS_IS_EV) != 0) {
DCHECK(!cert->subject().organization_names.empty());
head_line =
l10n_util::GetStringFUTF16(IDS_PAGE_INFO_EV_IDENTITY_TITLE,
UTF8ToUTF16(cert->subject().organization_names[0]),
UTF8ToUTF16(url.host()));
// An EV Cert is required to have a city (localityName) and country but
// state is "if any".
DCHECK(!cert->subject().locality_name.empty());
DCHECK(!cert->subject().country_name.empty());
string16 locality;
if (!cert->subject().state_or_province_name.empty()) {
locality = l10n_util::GetStringFUTF16(
IDS_PAGEINFO_ADDRESS,
UTF8ToUTF16(cert->subject().locality_name),
UTF8ToUTF16(cert->subject().state_or_province_name),
UTF8ToUTF16(cert->subject().country_name));
} else {
locality = l10n_util::GetStringFUTF16(
IDS_PAGEINFO_PARTIAL_ADDRESS,
UTF8ToUTF16(cert->subject().locality_name),
UTF8ToUTF16(cert->subject().country_name));
}
DCHECK(!cert->subject().organization_names.empty());
description.assign(l10n_util::GetStringFUTF16(
IDS_PAGE_INFO_SECURITY_TAB_SECURE_IDENTITY_EV,
UTF8ToUTF16(cert->subject().organization_names[0]),
locality,
UTF8ToUTF16(GetIssuerName(cert->issuer()))));
} else {
// Non EV OK HTTPS.
if (empty_subject_name)
head_line.clear(); // Don't display any title.
else
head_line.assign(subject_name);
string16 issuer_name(UTF8ToUTF16(GetIssuerName(cert->issuer())));
if (issuer_name.empty()) {
issuer_name.assign(l10n_util::GetStringUTF16(
IDS_PAGE_INFO_SECURITY_TAB_UNKNOWN_PARTY));
} else {
description.assign(l10n_util::GetStringFUTF16(
IDS_PAGE_INFO_SECURITY_TAB_SECURE_IDENTITY, issuer_name));
}
}
} else {
// Bad HTTPS.
description.assign(l10n_util::GetStringUTF16(
IDS_PAGE_INFO_SECURITY_TAB_INSECURE_IDENTITY));
state = false;
}
sections_.push_back(SectionInfo(
state,
l10n_util::GetStringUTF16(IDS_PAGE_INFO_SECURITY_TAB_IDENTITY_TITLE),
head_line,
description));
// Connection section.
// We consider anything less than 80 bits encryption to be weak encryption.
// TODO(wtc): Bug 1198735: report mixed/unsafe content for unencrypted and
// weakly encrypted connections.
state = true;
head_line.clear();
description.clear();
if (ssl.security_bits() <= 0) {
state = false;
description.assign(
l10n_util::GetStringFUTF16(
IDS_PAGE_INFO_SECURITY_TAB_NOT_ENCRYPTED_CONNECTION_TEXT,
subject_name));
} else if (ssl.security_bits() < 80) {
state = false;
description.assign(
l10n_util::GetStringFUTF16(
IDS_PAGE_INFO_SECURITY_TAB_WEAK_ENCRYPTION_CONNECTION_TEXT,
subject_name));
} else {
description.assign(
l10n_util::GetStringFUTF16(
IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_CONNECTION_TEXT,
subject_name,
IntToString16(ssl.security_bits())));
if (ssl.has_mixed_content()) {
state = false;
description.assign(
l10n_util::GetStringFUTF16(
IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_SENTENCE_LINK,
description,
l10n_util::GetStringUTF16(
IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_MIXED_CONTENT_WARNING)));
} else if (ssl.has_unsafe_content()) {
state = false;
description.assign(
l10n_util::GetStringFUTF16(
IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_SENTENCE_LINK,
description,
l10n_util::GetStringUTF16(
IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_BAD_HTTPS_WARNING)));
}
}
sections_.push_back(SectionInfo(
state,
l10n_util::GetStringUTF16(IDS_PAGE_INFO_SECURITY_TAB_CONNECTION_TITLE),
head_line,
description));
// Request the number of visits.
HistoryService* history = profile->GetHistoryService(
Profile::EXPLICIT_ACCESS);
if (show_history && history) {
history->GetVisitCountToHost(
url,
&request_consumer_,
NewCallback(this, &PageInfoModel::OnGotVisitCountToHost));
}
}
int PageInfoModel::GetSectionCount() {
return sections_.size();
}
PageInfoModel::SectionInfo PageInfoModel::GetSectionInfo(int index) {
DCHECK(index < static_cast<int>(sections_.size()));
return sections_[index];
}
void PageInfoModel::OnGotVisitCountToHost(HistoryService::Handle handle,
bool found_visits,
int count,
base::Time first_visit) {
if (!found_visits) {
// This indicates an error, such as the page wasn't http/https; do nothing.
return;
}
bool visited_before_today = false;
if (count) {
base::Time today = base::Time::Now().LocalMidnight();
base::Time first_visit_midnight = first_visit.LocalMidnight();
visited_before_today = (first_visit_midnight < today);
}
if (!visited_before_today) {
sections_.push_back(SectionInfo(
false,
l10n_util::GetStringUTF16(
IDS_PAGE_INFO_SECURITY_TAB_PERSONAL_HISTORY_TITLE),
string16(),
l10n_util::GetStringUTF16(
IDS_PAGE_INFO_SECURITY_TAB_FIRST_VISITED_TODAY)));
} else {
sections_.push_back(SectionInfo(
true,
l10n_util::GetStringUTF16(
IDS_PAGE_INFO_SECURITY_TAB_PERSONAL_HISTORY_TITLE),
string16(),
l10n_util::GetStringFUTF16(
IDS_PAGE_INFO_SECURITY_TAB_VISITED_BEFORE_TODAY,
WideToUTF16(base::TimeFormatShortDate(first_visit)))));
}
observer_->ModelChanged();
}
// static
void PageInfoModel::RegisterPrefs(PrefService* prefs) {
prefs->RegisterDictionaryPref(prefs::kPageInfoWindowPlacement);
}