blob: abe4a58513cc170467d0f082dc546e1b284c4083 [file] [log] [blame]
// Copyright (c) 2011 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/ssl/ssl_blocking_page.h"
#include "base/i18n/rtl.h"
#include "base/metrics/histogram.h"
#include "base/string_piece.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/dom_operation_notification_details.h"
#include "chrome/browser/ssl/ssl_error_info.h"
#include "chrome/browser/tab_contents/tab_util.h"
#include "chrome/common/jstemplate_builder.h"
#include "content/browser/cert_store.h"
#include "content/browser/renderer_host/render_process_host.h"
#include "content/browser/renderer_host/render_view_host.h"
#include "content/browser/ssl/ssl_cert_error_handler.h"
#include "content/browser/tab_contents/navigation_controller.h"
#include "content/browser/tab_contents/navigation_entry.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_types.h"
#include "grit/browser_resources.h"
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
namespace {
enum SSLBlockingPageEvent {
SHOW,
PROCEED,
DONT_PROCEED,
UNUSED_ENUM,
};
void RecordSSLBlockingPageStats(SSLBlockingPageEvent event) {
UMA_HISTOGRAM_ENUMERATION("interstial.ssl", event, UNUSED_ENUM);
}
} // namespace
// Note that we always create a navigation entry with SSL errors.
// No error happening loading a sub-resource triggers an interstitial so far.
SSLBlockingPage::SSLBlockingPage(
SSLCertErrorHandler* handler,
bool overridable,
const base::Callback<void(SSLCertErrorHandler*, bool)>& callback)
: ChromeInterstitialPage(
tab_util::GetTabContentsByID(
handler->render_process_host_id(), handler->tab_contents_id()),
true,
handler->request_url()),
handler_(handler),
callback_(callback),
overridable_(overridable) {
RecordSSLBlockingPageStats(SHOW);
}
SSLBlockingPage::~SSLBlockingPage() {
if (!callback_.is_null()) {
// The page is closed without the user having chosen what to do, default to
// deny.
NotifyDenyCertificate();
}
}
std::string SSLBlockingPage::GetHTMLContents() {
// Let's build the html error page.
DictionaryValue strings;
SSLErrorInfo error_info = SSLErrorInfo::CreateError(
SSLErrorInfo::NetErrorToErrorType(handler_->cert_error()),
handler_->ssl_info().cert, handler_->request_url());
strings.SetString("headLine", error_info.title());
strings.SetString("description", error_info.details());
strings.SetString("moreInfoTitle",
l10n_util::GetStringUTF16(IDS_CERT_ERROR_EXTRA_INFO_TITLE));
SetExtraInfo(&strings, error_info.extra_information());
int resource_id;
if (overridable_) {
resource_id = IDR_SSL_ROAD_BLOCK_HTML;
strings.SetString("title",
l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_TITLE));
strings.SetString("proceed",
l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_PROCEED));
strings.SetString("exit",
l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_EXIT));
} else {
resource_id = IDR_SSL_ERROR_HTML;
strings.SetString("title",
l10n_util::GetStringUTF16(IDS_SSL_ERROR_PAGE_TITLE));
strings.SetString("back",
l10n_util::GetStringUTF16(IDS_SSL_ERROR_PAGE_BACK));
}
strings.SetString("textdirection", base::i18n::IsRTL() ? "rtl" : "ltr");
base::StringPiece html(
ResourceBundle::GetSharedInstance().GetRawDataResource(resource_id));
return jstemplate_builder::GetI18nTemplateHtml(html, &strings);
}
void SSLBlockingPage::UpdateEntry(NavigationEntry* entry) {
const net::SSLInfo& ssl_info = handler_->ssl_info();
int cert_id = CertStore::GetInstance()->StoreCert(
ssl_info.cert, tab()->render_view_host()->process()->id());
entry->ssl().set_security_style(SECURITY_STYLE_AUTHENTICATION_BROKEN);
entry->ssl().set_cert_id(cert_id);
entry->ssl().set_cert_status(ssl_info.cert_status);
entry->ssl().set_security_bits(ssl_info.security_bits);
content::NotificationService::current()->Notify(
content::NOTIFICATION_SSL_VISIBLE_STATE_CHANGED,
content::Source<NavigationController>(&tab()->controller()),
content::NotificationService::NoDetails());
}
void SSLBlockingPage::CommandReceived(const std::string& command) {
if (command == "1") {
Proceed();
} else {
DontProceed();
}
}
void SSLBlockingPage::Proceed() {
RecordSSLBlockingPageStats(PROCEED);
// Accepting the certificate resumes the loading of the page.
NotifyAllowCertificate();
// This call hides and deletes the interstitial.
InterstitialPage::Proceed();
}
void SSLBlockingPage::DontProceed() {
RecordSSLBlockingPageStats(DONT_PROCEED);
NotifyDenyCertificate();
InterstitialPage::DontProceed();
}
void SSLBlockingPage::NotifyDenyCertificate() {
// It's possible that callback_ may not exist if the user clicks "Proceed"
// followed by pressing the back button before the interstitial is hidden.
// In that case the certificate will still be treated as allowed.
if (callback_.is_null())
return;
callback_.Run(handler_, false);
callback_.Reset();
}
void SSLBlockingPage::NotifyAllowCertificate() {
DCHECK(!callback_.is_null());
callback_.Run(handler_, true);
callback_.Reset();
}
// static
void SSLBlockingPage::SetExtraInfo(
DictionaryValue* strings,
const std::vector<string16>& extra_info) {
DCHECK(extra_info.size() < 5); // We allow 5 paragraphs max.
const char* keys[5] = {
"moreInfo1", "moreInfo2", "moreInfo3", "moreInfo4", "moreInfo5"
};
int i;
for (i = 0; i < static_cast<int>(extra_info.size()); i++) {
strings->SetString(keys[i], extra_info[i]);
}
for (; i < 5; i++) {
strings->SetString(keys[i], "");
}
}