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