ssl_blocking_page.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
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/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/profiles/profile.h"
13#include "chrome/browser/renderer_preferences_util.h"
14#include "chrome/browser/ssl/ssl_error_info.h"
15#include "chrome/common/jstemplate_builder.h"
16#include "content/public/browser/cert_store.h"
17#include "content/public/browser/interstitial_page.h"
18#include "content/public/browser/navigation_controller.h"
19#include "content/public/browser/navigation_entry.h"
20#include "content/public/browser/notification_service.h"
21#include "content/public/browser/notification_types.h"
22#include "content/public/browser/render_process_host.h"
23#include "content/public/browser/render_view_host.h"
24#include "content/public/browser/web_contents.h"
25#include "content/public/common/ssl_status.h"
26#include "grit/browser_resources.h"
27#include "grit/generated_resources.h"
28#include "ui/base/l10n/l10n_util.h"
29#include "ui/base/resource/resource_bundle.h"
30
31using content::InterstitialPage;
32using content::NavigationController;
33using content::NavigationEntry;
34
35namespace {
36
37enum SSLBlockingPageEvent {
38  SHOW,
39  PROCEED,
40  DONT_PROCEED,
41  UNUSED_ENUM,
42};
43
44void RecordSSLBlockingPageStats(SSLBlockingPageEvent event) {
45  UMA_HISTOGRAM_ENUMERATION("interstial.ssl", event, UNUSED_ENUM);
46}
47
48}  // namespace
49
50// Note that we always create a navigation entry with SSL errors.
51// No error happening loading a sub-resource triggers an interstitial so far.
52SSLBlockingPage::SSLBlockingPage(
53    content::WebContents* web_contents,
54    int cert_error,
55    const net::SSLInfo& ssl_info,
56    const GURL& request_url,
57    bool overridable,
58    bool strict_enforcement,
59    const base::Callback<void(bool)>& callback)
60    : callback_(callback),
61      web_contents_(web_contents),
62      cert_error_(cert_error),
63      ssl_info_(ssl_info),
64      request_url_(request_url),
65      overridable_(overridable),
66      strict_enforcement_(strict_enforcement) {
67  RecordSSLBlockingPageStats(SHOW);
68  interstitial_page_ = InterstitialPage::Create(
69      web_contents_, true, request_url, this);
70  interstitial_page_->Show();
71}
72
73SSLBlockingPage::~SSLBlockingPage() {
74  if (!callback_.is_null()) {
75    // The page is closed without the user having chosen what to do, default to
76    // deny.
77    NotifyDenyCertificate();
78  }
79}
80
81std::string SSLBlockingPage::GetHTMLContents() {
82  // Let's build the html error page.
83  DictionaryValue strings;
84  SSLErrorInfo error_info = SSLErrorInfo::CreateError(
85      SSLErrorInfo::NetErrorToErrorType(cert_error_), ssl_info_.cert,
86      request_url_);
87
88  strings.SetString("headLine", error_info.title());
89  strings.SetString("description", error_info.details());
90
91  strings.SetString("moreInfoTitle",
92                    l10n_util::GetStringUTF16(IDS_CERT_ERROR_EXTRA_INFO_TITLE));
93  SetExtraInfo(&strings, error_info.extra_information());
94
95  int resource_id;
96  if (overridable_ && !strict_enforcement_) {
97    resource_id = IDR_SSL_ROAD_BLOCK_HTML;
98    strings.SetString("title",
99                      l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_TITLE));
100    strings.SetString("proceed",
101                      l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_PROCEED));
102    strings.SetString("exit",
103                      l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_EXIT));
104    strings.SetString("shouldNotProceed",
105                      l10n_util::GetStringUTF16(
106                          IDS_SSL_BLOCKING_PAGE_SHOULD_NOT_PROCEED));
107  } else {
108    resource_id = IDR_SSL_ERROR_HTML;
109    strings.SetString("title",
110                      l10n_util::GetStringUTF16(IDS_SSL_ERROR_PAGE_TITLE));
111    strings.SetString("back",
112                      l10n_util::GetStringUTF16(IDS_SSL_ERROR_PAGE_BACK));
113    if (strict_enforcement_) {
114      strings.SetString("cannotProceed",
115                        l10n_util::GetStringUTF16(
116                            IDS_SSL_ERROR_PAGE_CANNOT_PROCEED));
117    }
118  }
119
120  strings.SetString("textdirection", base::i18n::IsRTL() ? "rtl" : "ltr");
121
122  base::StringPiece html(
123      ResourceBundle::GetSharedInstance().GetRawDataResource(
124          resource_id));
125
126  return jstemplate_builder::GetI18nTemplateHtml(html, &strings);
127}
128
129void SSLBlockingPage::OverrideEntry(NavigationEntry* entry) {
130  int cert_id = content::CertStore::GetInstance()->StoreCert(
131      ssl_info_.cert, web_contents_->GetRenderProcessHost()->GetID());
132
133  entry->GetSSL().security_style =
134      content::SECURITY_STYLE_AUTHENTICATION_BROKEN;
135  entry->GetSSL().cert_id = cert_id;
136  entry->GetSSL().cert_status = ssl_info_.cert_status;
137  entry->GetSSL().security_bits = ssl_info_.security_bits;
138  content::NotificationService::current()->Notify(
139      content::NOTIFICATION_SSL_VISIBLE_STATE_CHANGED,
140      content::Source<NavigationController>(&web_contents_->GetController()),
141      content::NotificationService::NoDetails());
142}
143
144void SSLBlockingPage::CommandReceived(const std::string& command) {
145  if (command == "1") {
146    interstitial_page_->Proceed();
147  } else {
148    interstitial_page_->DontProceed();
149  }
150}
151
152void SSLBlockingPage::OverrideRendererPrefs(
153      content::RendererPreferences* prefs) {
154  Profile* profile = Profile::FromBrowserContext(
155      web_contents_->GetBrowserContext());
156  renderer_preferences_util::UpdateFromSystemSettings(prefs, profile);
157}
158
159void SSLBlockingPage::OnProceed() {
160  RecordSSLBlockingPageStats(PROCEED);
161
162  // Accepting the certificate resumes the loading of the page.
163  NotifyAllowCertificate();
164}
165
166void SSLBlockingPage::OnDontProceed() {
167  RecordSSLBlockingPageStats(DONT_PROCEED);
168
169  NotifyDenyCertificate();
170}
171
172void SSLBlockingPage::NotifyDenyCertificate() {
173  // It's possible that callback_ may not exist if the user clicks "Proceed"
174  // followed by pressing the back button before the interstitial is hidden.
175  // In that case the certificate will still be treated as allowed.
176  if (callback_.is_null())
177    return;
178
179  callback_.Run(false);
180  callback_.Reset();
181}
182
183void SSLBlockingPage::NotifyAllowCertificate() {
184  DCHECK(!callback_.is_null());
185
186  callback_.Run(true);
187  callback_.Reset();
188}
189
190// static
191void SSLBlockingPage::SetExtraInfo(
192    DictionaryValue* strings,
193    const std::vector<string16>& extra_info) {
194  DCHECK_LT(extra_info.size(), 5U);  // We allow 5 paragraphs max.
195  const char* keys[5] = {
196      "moreInfo1", "moreInfo2", "moreInfo3", "moreInfo4", "moreInfo5"
197  };
198  int i;
199  for (i = 0; i < static_cast<int>(extra_info.size()); i++) {
200    strings->SetString(keys[i], extra_info[i]);
201  }
202  for (; i < 5; i++) {
203    strings->SetString(keys[i], "");
204  }
205}
206