1// Copyright (c) 2011 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/ssl/ssl_blocking_page.h"
6
7#include "base/i18n/rtl.h"
8#include "base/metrics/histogram.h"
9#include "base/string_piece.h"
10#include "base/utf_string_conversions.h"
11#include "base/values.h"
12#include "chrome/browser/dom_operation_notification_details.h"
13#include "chrome/browser/ssl/ssl_cert_error_handler.h"
14#include "chrome/browser/ssl/ssl_error_info.h"
15#include "chrome/common/jstemplate_builder.h"
16#include "content/browser/cert_store.h"
17#include "content/browser/renderer_host/render_process_host.h"
18#include "content/browser/renderer_host/render_view_host.h"
19#include "content/browser/tab_contents/navigation_controller.h"
20#include "content/browser/tab_contents/navigation_entry.h"
21#include "content/browser/tab_contents/tab_contents.h"
22#include "content/common/notification_service.h"
23#include "grit/browser_resources.h"
24#include "grit/generated_resources.h"
25#include "ui/base/l10n/l10n_util.h"
26#include "ui/base/resource/resource_bundle.h"
27
28namespace {
29
30enum SSLBlockingPageEvent {
31  SHOW,
32  PROCEED,
33  DONT_PROCEED,
34  UNUSED_ENUM,
35};
36
37void RecordSSLBlockingPageStats(SSLBlockingPageEvent event) {
38  UMA_HISTOGRAM_ENUMERATION("interstial.ssl", event, UNUSED_ENUM);
39}
40
41}  // namespace
42
43// Note that we always create a navigation entry with SSL errors.
44// No error happening loading a sub-resource triggers an interstitial so far.
45SSLBlockingPage::SSLBlockingPage(SSLCertErrorHandler* handler,
46                                 Delegate* delegate,
47                                 ErrorLevel error_level)
48    : InterstitialPage(handler->GetTabContents(), true, handler->request_url()),
49      handler_(handler),
50      delegate_(delegate),
51      delegate_has_been_notified_(false),
52      error_level_(error_level) {
53  RecordSSLBlockingPageStats(SHOW);
54}
55
56SSLBlockingPage::~SSLBlockingPage() {
57  if (!delegate_has_been_notified_) {
58    // The page is closed without the user having chosen what to do, default to
59    // deny.
60    NotifyDenyCertificate();
61  }
62}
63
64std::string SSLBlockingPage::GetHTMLContents() {
65  // Let's build the html error page.
66  DictionaryValue strings;
67  SSLErrorInfo error_info = delegate_->GetSSLErrorInfo(handler_);
68  strings.SetString("headLine", error_info.title());
69  strings.SetString("description", error_info.details());
70
71  strings.SetString("moreInfoTitle",
72                    l10n_util::GetStringUTF16(IDS_CERT_ERROR_EXTRA_INFO_TITLE));
73  SetExtraInfo(&strings, error_info.extra_information());
74
75  int resource_id;
76  if (error_level_ == ERROR_OVERRIDABLE) {
77    resource_id = IDR_SSL_ROAD_BLOCK_HTML;
78    strings.SetString("title",
79                      l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_TITLE));
80    strings.SetString("proceed",
81                      l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_PROCEED));
82    strings.SetString("exit",
83                      l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_EXIT));
84  } else {
85    DCHECK_EQ(error_level_, ERROR_FATAL);
86    resource_id = IDR_SSL_ERROR_HTML;
87    strings.SetString("title",
88                      l10n_util::GetStringUTF16(IDS_SSL_ERROR_PAGE_TITLE));
89    strings.SetString("back",
90                      l10n_util::GetStringUTF16(IDS_SSL_ERROR_PAGE_BACK));
91  }
92
93  strings.SetString("textdirection", base::i18n::IsRTL() ? "rtl" : "ltr");
94
95  base::StringPiece html(
96      ResourceBundle::GetSharedInstance().GetRawDataResource(resource_id));
97
98  return jstemplate_builder::GetI18nTemplateHtml(html, &strings);
99}
100
101void SSLBlockingPage::UpdateEntry(NavigationEntry* entry) {
102  const net::SSLInfo& ssl_info = handler_->ssl_info();
103  int cert_id = CertStore::GetInstance()->StoreCert(
104      ssl_info.cert, tab()->render_view_host()->process()->id());
105
106  entry->ssl().set_security_style(SECURITY_STYLE_AUTHENTICATION_BROKEN);
107  entry->ssl().set_cert_id(cert_id);
108  entry->ssl().set_cert_status(ssl_info.cert_status);
109  entry->ssl().set_security_bits(ssl_info.security_bits);
110  NotificationService::current()->Notify(
111      NotificationType::SSL_VISIBLE_STATE_CHANGED,
112      Source<NavigationController>(&tab()->controller()),
113      NotificationService::NoDetails());
114}
115
116void SSLBlockingPage::CommandReceived(const std::string& command) {
117  if (command == "1") {
118    Proceed();
119  } else {
120    DontProceed();
121  }
122}
123
124void SSLBlockingPage::Proceed() {
125  RecordSSLBlockingPageStats(PROCEED);
126
127  // Accepting the certificate resumes the loading of the page.
128  NotifyAllowCertificate();
129
130  // This call hides and deletes the interstitial.
131  InterstitialPage::Proceed();
132}
133
134void SSLBlockingPage::DontProceed() {
135  RecordSSLBlockingPageStats(DONT_PROCEED);
136
137  NotifyDenyCertificate();
138  InterstitialPage::DontProceed();
139}
140
141void SSLBlockingPage::NotifyDenyCertificate() {
142  DCHECK(!delegate_has_been_notified_);
143
144  delegate_->OnDenyCertificate(handler_);
145  delegate_has_been_notified_ = true;
146}
147
148void SSLBlockingPage::NotifyAllowCertificate() {
149  DCHECK(!delegate_has_been_notified_);
150
151  delegate_->OnAllowCertificate(handler_);
152  delegate_has_been_notified_ = true;
153}
154
155// static
156void SSLBlockingPage::SetExtraInfo(
157    DictionaryValue* strings,
158    const std::vector<string16>& extra_info) {
159  DCHECK(extra_info.size() < 5);  // We allow 5 paragraphs max.
160  const char* keys[5] = {
161      "moreInfo1", "moreInfo2", "moreInfo3", "moreInfo4", "moreInfo5"
162  };
163  int i;
164  for (i = 0; i < static_cast<int>(extra_info.size()); i++) {
165    strings->SetString(keys[i], extra_info[i]);
166  }
167  for (; i < 5; i++) {
168    strings->SetString(keys[i], "");
169  }
170}
171