• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/command_line.h"
8 #include "base/i18n/rtl.h"
9 #include "base/metrics/field_trial.h"
10 #include "base/metrics/histogram.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_piece.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/values.h"
16 #include "chrome/browser/chrome_notification_types.h"
17 #include "chrome/browser/history/history_service_factory.h"
18 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/browser/renderer_preferences_util.h"
20 #include "chrome/browser/ssl/ssl_error_info.h"
21 #include "chrome/common/chrome_switches.h"
22 #include "content/public/browser/cert_store.h"
23 #include "content/public/browser/interstitial_page.h"
24 #include "content/public/browser/navigation_controller.h"
25 #include "content/public/browser/navigation_entry.h"
26 #include "content/public/browser/notification_service.h"
27 #include "content/public/browser/notification_types.h"
28 #include "content/public/browser/render_process_host.h"
29 #include "content/public/browser/render_view_host.h"
30 #include "content/public/browser/web_contents.h"
31 #include "content/public/common/ssl_status.h"
32 #include "grit/app_locale_settings.h"
33 #include "grit/browser_resources.h"
34 #include "grit/generated_resources.h"
35 #include "net/base/hash_value.h"
36 #include "net/base/net_errors.h"
37 #include "net/base/net_util.h"
38 #include "ui/base/l10n/l10n_util.h"
39 #include "ui/base/resource/resource_bundle.h"
40 #include "ui/base/webui/jstemplate_builder.h"
41 #include "ui/base/webui/web_ui_util.h"
42 
43 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
44 #include "chrome/browser/captive_portal/captive_portal_service.h"
45 #include "chrome/browser/captive_portal/captive_portal_service_factory.h"
46 #endif
47 
48 #if defined(OS_WIN)
49 #include "base/win/windows_version.h"
50 #endif
51 
52 using base::ASCIIToUTF16;
53 using base::TimeTicks;
54 using content::InterstitialPage;
55 using content::NavigationController;
56 using content::NavigationEntry;
57 
58 namespace {
59 
60 // Events for UMA. Do not reorder or change!
61 enum SSLBlockingPageEvent {
62   SHOW_ALL,
63   SHOW_OVERRIDABLE,
64   PROCEED_OVERRIDABLE,
65   PROCEED_NAME,
66   PROCEED_DATE,
67   PROCEED_AUTHORITY,
68   DONT_PROCEED_OVERRIDABLE,
69   DONT_PROCEED_NAME,
70   DONT_PROCEED_DATE,
71   DONT_PROCEED_AUTHORITY,
72   MORE,
73   SHOW_UNDERSTAND,  // Used by the summer 2013 Finch trial. Deprecated.
74   SHOW_INTERNAL_HOSTNAME,
75   PROCEED_INTERNAL_HOSTNAME,
76   SHOW_NEW_SITE,
77   PROCEED_NEW_SITE,
78   PROCEED_MANUAL_NONOVERRIDABLE,
79   CAPTIVE_PORTAL_DETECTION_ENABLED,
80   CAPTIVE_PORTAL_DETECTION_ENABLED_OVERRIDABLE,
81   CAPTIVE_PORTAL_PROBE_COMPLETED,
82   CAPTIVE_PORTAL_PROBE_COMPLETED_OVERRIDABLE,
83   CAPTIVE_PORTAL_NO_RESPONSE,
84   CAPTIVE_PORTAL_NO_RESPONSE_OVERRIDABLE,
85   CAPTIVE_PORTAL_DETECTED,
86   CAPTIVE_PORTAL_DETECTED_OVERRIDABLE,
87   UNUSED_BLOCKING_PAGE_EVENT,
88 };
89 
RecordSSLBlockingPageEventStats(SSLBlockingPageEvent event)90 void RecordSSLBlockingPageEventStats(SSLBlockingPageEvent event) {
91   UMA_HISTOGRAM_ENUMERATION("interstitial.ssl",
92                             event,
93                             UNUSED_BLOCKING_PAGE_EVENT);
94 }
95 
RecordSSLBlockingPageDetailedStats(bool proceed,int cert_error,bool overridable,bool internal,int num_visits,bool captive_portal_detection_enabled,bool captive_portal_probe_completed,bool captive_portal_no_response,bool captive_portal_detected)96 void RecordSSLBlockingPageDetailedStats(
97     bool proceed,
98     int cert_error,
99     bool overridable,
100     bool internal,
101     int num_visits,
102     bool captive_portal_detection_enabled,
103     bool captive_portal_probe_completed,
104     bool captive_portal_no_response,
105     bool captive_portal_detected) {
106   UMA_HISTOGRAM_ENUMERATION("interstitial.ssl_error_type",
107       SSLErrorInfo::NetErrorToErrorType(cert_error), SSLErrorInfo::END_OF_ENUM);
108 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
109   if (captive_portal_detection_enabled)
110     RecordSSLBlockingPageEventStats(
111         overridable ?
112         CAPTIVE_PORTAL_DETECTION_ENABLED_OVERRIDABLE :
113         CAPTIVE_PORTAL_DETECTION_ENABLED);
114   if (captive_portal_probe_completed)
115     RecordSSLBlockingPageEventStats(
116         overridable ?
117         CAPTIVE_PORTAL_PROBE_COMPLETED_OVERRIDABLE :
118         CAPTIVE_PORTAL_PROBE_COMPLETED);
119   // Log only one of portal detected and no response results.
120   if (captive_portal_detected)
121     RecordSSLBlockingPageEventStats(
122         overridable ?
123         CAPTIVE_PORTAL_DETECTED_OVERRIDABLE :
124         CAPTIVE_PORTAL_DETECTED);
125   else if (captive_portal_no_response)
126     RecordSSLBlockingPageEventStats(
127         overridable ?
128         CAPTIVE_PORTAL_NO_RESPONSE_OVERRIDABLE :
129         CAPTIVE_PORTAL_NO_RESPONSE);
130 #endif
131   if (!overridable) {
132     if (proceed) {
133       RecordSSLBlockingPageEventStats(PROCEED_MANUAL_NONOVERRIDABLE);
134     }
135     // Overridable is false if the user didn't have any option except to turn
136     // back. If that's the case, don't record some of the metrics.
137     return;
138   }
139   if (num_visits == 0)
140     RecordSSLBlockingPageEventStats(SHOW_NEW_SITE);
141   if (proceed) {
142     RecordSSLBlockingPageEventStats(PROCEED_OVERRIDABLE);
143     if (internal)
144       RecordSSLBlockingPageEventStats(PROCEED_INTERNAL_HOSTNAME);
145     if (num_visits == 0)
146       RecordSSLBlockingPageEventStats(PROCEED_NEW_SITE);
147   } else if (!proceed) {
148     RecordSSLBlockingPageEventStats(DONT_PROCEED_OVERRIDABLE);
149   }
150   SSLErrorInfo::ErrorType type = SSLErrorInfo::NetErrorToErrorType(cert_error);
151   switch (type) {
152     case SSLErrorInfo::CERT_COMMON_NAME_INVALID: {
153       if (proceed)
154         RecordSSLBlockingPageEventStats(PROCEED_NAME);
155       else
156         RecordSSLBlockingPageEventStats(DONT_PROCEED_NAME);
157       break;
158     }
159     case SSLErrorInfo::CERT_DATE_INVALID: {
160       if (proceed)
161         RecordSSLBlockingPageEventStats(PROCEED_DATE);
162       else
163         RecordSSLBlockingPageEventStats(DONT_PROCEED_DATE);
164       break;
165     }
166     case SSLErrorInfo::CERT_AUTHORITY_INVALID: {
167       if (proceed)
168         RecordSSLBlockingPageEventStats(PROCEED_AUTHORITY);
169       else
170         RecordSSLBlockingPageEventStats(DONT_PROCEED_AUTHORITY);
171       break;
172     }
173     default: {
174       break;
175     }
176   }
177 }
178 
179 }  // namespace
180 
181 // Note that we always create a navigation entry with SSL errors.
182 // No error happening loading a sub-resource triggers an interstitial so far.
SSLBlockingPage(content::WebContents * web_contents,int cert_error,const net::SSLInfo & ssl_info,const GURL & request_url,bool overridable,bool strict_enforcement,const base::Callback<void (bool)> & callback)183 SSLBlockingPage::SSLBlockingPage(
184     content::WebContents* web_contents,
185     int cert_error,
186     const net::SSLInfo& ssl_info,
187     const GURL& request_url,
188     bool overridable,
189     bool strict_enforcement,
190     const base::Callback<void(bool)>& callback)
191     : callback_(callback),
192       web_contents_(web_contents),
193       cert_error_(cert_error),
194       ssl_info_(ssl_info),
195       request_url_(request_url),
196       overridable_(overridable),
197       strict_enforcement_(strict_enforcement),
198       internal_(false),
199       num_visits_(-1),
200       captive_portal_detection_enabled_(false),
201       captive_portal_probe_completed_(false),
202       captive_portal_no_response_(false),
203       captive_portal_detected_(false) {
204   Profile* profile = Profile::FromBrowserContext(
205       web_contents->GetBrowserContext());
206   // For UMA stats.
207   if (net::IsHostnameNonUnique(request_url_.HostNoBrackets()))
208     internal_ = true;
209   RecordSSLBlockingPageEventStats(SHOW_ALL);
210   if (overridable_ && !strict_enforcement_) {
211     RecordSSLBlockingPageEventStats(SHOW_OVERRIDABLE);
212     if (internal_)
213       RecordSSLBlockingPageEventStats(SHOW_INTERNAL_HOSTNAME);
214     HistoryService* history_service = HistoryServiceFactory::GetForProfile(
215         profile, Profile::EXPLICIT_ACCESS);
216     if (history_service) {
217       history_service->GetVisibleVisitCountToHost(
218           request_url_,
219           &request_consumer_,
220           base::Bind(&SSLBlockingPage::OnGotHistoryCount,
221                     base::Unretained(this)));
222     }
223   }
224 
225 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
226   CaptivePortalService* captive_portal_service =
227       CaptivePortalServiceFactory::GetForProfile(profile);
228   captive_portal_detection_enabled_ = captive_portal_service ->enabled();
229   captive_portal_service ->DetectCaptivePortal();
230   registrar_.Add(this,
231                  chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT,
232                  content::Source<Profile>(profile));
233 #endif
234 
235   interstitial_page_ = InterstitialPage::Create(
236       web_contents_, true, request_url, this);
237   interstitial_page_->Show();
238 }
239 
~SSLBlockingPage()240 SSLBlockingPage::~SSLBlockingPage() {
241   if (!callback_.is_null()) {
242     RecordSSLBlockingPageDetailedStats(false,
243                                        cert_error_,
244                                        overridable_ && !strict_enforcement_,
245                                        internal_,
246                                        num_visits_,
247                                        captive_portal_detection_enabled_,
248                                        captive_portal_probe_completed_,
249                                        captive_portal_no_response_,
250                                        captive_portal_detected_);
251     // The page is closed without the user having chosen what to do, default to
252     // deny.
253     NotifyDenyCertificate();
254   }
255 }
256 
GetHTMLContents()257 std::string SSLBlockingPage::GetHTMLContents() {
258   if (CommandLine::ForCurrentProcess()->HasSwitch(
259           switches::kSSLInterstitialVersionV1) ||
260       base::FieldTrialList::FindFullName("SSLInterstitialVersion") == "V1") {
261     return GetHTMLContentsV1();
262   }
263   return GetHTMLContentsV2();
264 }
265 
GetHTMLContentsV1()266 std::string SSLBlockingPage::GetHTMLContentsV1() {
267   base::DictionaryValue strings;
268   int resource_id;
269   if (overridable_ && !strict_enforcement_) {
270     // Let's build the overridable error page.
271     SSLErrorInfo error_info =
272         SSLErrorInfo::CreateError(
273             SSLErrorInfo::NetErrorToErrorType(cert_error_),
274             ssl_info_.cert.get(),
275             request_url_);
276 
277     resource_id = IDR_SSL_ROAD_BLOCK_HTML;
278     strings.SetString("headLine", error_info.title());
279     strings.SetString("description", error_info.details());
280     strings.SetString("moreInfoTitle",
281         l10n_util::GetStringUTF16(IDS_CERT_ERROR_EXTRA_INFO_TITLE));
282     SetExtraInfo(&strings, error_info.extra_information());
283 
284     strings.SetString(
285         "exit", l10n_util::GetStringUTF16(IDS_SSL_OVERRIDABLE_PAGE_EXIT));
286     strings.SetString(
287         "title", l10n_util::GetStringUTF16(IDS_SSL_OVERRIDABLE_PAGE_TITLE));
288     strings.SetString(
289         "proceed", l10n_util::GetStringUTF16(IDS_SSL_OVERRIDABLE_PAGE_PROCEED));
290     strings.SetString(
291         "reasonForNotProceeding", l10n_util::GetStringUTF16(
292             IDS_SSL_OVERRIDABLE_PAGE_SHOULD_NOT_PROCEED));
293     strings.SetString("errorType", "overridable");
294     strings.SetString("textdirection", base::i18n::IsRTL() ? "rtl" : "ltr");
295   } else {
296     // Let's build the blocking error page.
297     resource_id = IDR_SSL_BLOCKING_HTML;
298 
299     // Strings that are not dependent on the URL.
300     strings.SetString(
301         "title", l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_TITLE));
302     strings.SetString(
303         "reloadMsg", l10n_util::GetStringUTF16(IDS_ERRORPAGES_BUTTON_RELOAD));
304     strings.SetString(
305         "more", l10n_util::GetStringUTF16(IDS_ERRORPAGES_BUTTON_MORE));
306     strings.SetString(
307         "less", l10n_util::GetStringUTF16(IDS_ERRORPAGES_BUTTON_LESS));
308     strings.SetString(
309         "moreTitle",
310         l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_MORE_TITLE));
311     strings.SetString(
312         "techTitle",
313         l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_TECH_TITLE));
314 
315     // Strings that are dependent on the URL.
316     base::string16 url(ASCIIToUTF16(request_url_.host()));
317     bool rtl = base::i18n::IsRTL();
318     strings.SetString("textDirection", rtl ? "rtl" : "ltr");
319     if (rtl)
320       base::i18n::WrapStringWithLTRFormatting(&url);
321     strings.SetString(
322         "headline", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_HEADLINE,
323                                                url.c_str()));
324     strings.SetString(
325         "message", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_BODY_TEXT,
326                                               url.c_str()));
327     strings.SetString(
328         "moreMessage",
329         l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_MORE_TEXT,
330                                    url.c_str()));
331     strings.SetString("reloadUrl", request_url_.spec());
332 
333     // Strings that are dependent on the error type.
334     SSLErrorInfo::ErrorType type =
335         SSLErrorInfo::NetErrorToErrorType(cert_error_);
336     base::string16 errorType;
337     if (type == SSLErrorInfo::CERT_REVOKED) {
338       errorType = base::string16(ASCIIToUTF16("Key revocation"));
339       strings.SetString(
340           "failure",
341           l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_REVOKED));
342     } else if (type == SSLErrorInfo::CERT_INVALID) {
343       errorType = base::string16(ASCIIToUTF16("Malformed certificate"));
344       strings.SetString(
345           "failure",
346           l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_FORMATTED));
347     } else if (type == SSLErrorInfo::CERT_PINNED_KEY_MISSING) {
348       errorType = base::string16(ASCIIToUTF16("Certificate pinning failure"));
349       strings.SetString(
350           "failure",
351           l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_PINNING,
352                                      url.c_str()));
353     } else if (type == SSLErrorInfo::CERT_WEAK_KEY_DH) {
354       errorType = base::string16(ASCIIToUTF16("Weak DH public key"));
355       strings.SetString(
356           "failure",
357           l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_WEAK_DH,
358                                      url.c_str()));
359     } else {
360       // HSTS failure.
361       errorType = base::string16(ASCIIToUTF16("HSTS failure"));
362       strings.SetString(
363           "failure",
364           l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_HSTS, url.c_str()));
365     }
366     if (rtl)
367       base::i18n::WrapStringWithLTRFormatting(&errorType);
368     strings.SetString(
369         "errorType", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_ERROR,
370                                                 errorType.c_str()));
371 
372     // Strings that display the invalid cert.
373     base::string16 subject(
374         ASCIIToUTF16(ssl_info_.cert->subject().GetDisplayName()));
375     base::string16 issuer(
376         ASCIIToUTF16(ssl_info_.cert->issuer().GetDisplayName()));
377     std::string hashes;
378     for (std::vector<net::HashValue>::const_iterator it =
379             ssl_info_.public_key_hashes.begin();
380          it != ssl_info_.public_key_hashes.end();
381          ++it) {
382       base::StringAppendF(&hashes, "%s ", it->ToString().c_str());
383     }
384     base::string16 fingerprint(ASCIIToUTF16(hashes));
385     if (rtl) {
386       // These are always going to be LTR.
387       base::i18n::WrapStringWithLTRFormatting(&subject);
388       base::i18n::WrapStringWithLTRFormatting(&issuer);
389       base::i18n::WrapStringWithLTRFormatting(&fingerprint);
390     }
391     strings.SetString(
392         "subject", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_SUBJECT,
393                                               subject.c_str()));
394     strings.SetString(
395         "issuer", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_ISSUER,
396                                              issuer.c_str()));
397     strings.SetString(
398         "fingerprint",
399         l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_HASHES,
400                                    fingerprint.c_str()));
401   }
402 
403   base::StringPiece html(
404       ResourceBundle::GetSharedInstance().GetRawDataResource(
405           resource_id));
406   return webui::GetI18nTemplateHtml(html, &strings);
407 }
408 
GetHTMLContentsV2()409 std::string SSLBlockingPage::GetHTMLContentsV2() {
410   base::DictionaryValue load_time_data;
411   base::string16 url(ASCIIToUTF16(request_url_.host()));
412   if (base::i18n::IsRTL())
413     base::i18n::WrapStringWithLTRFormatting(&url);
414   webui::SetFontAndTextDirection(&load_time_data);
415 
416   // Shared values for both the overridable and non-overridable versions.
417   load_time_data.SetBoolean("ssl", true);
418   load_time_data.SetBoolean(
419       "overridable", overridable_ && !strict_enforcement_);
420   load_time_data.SetString(
421       "tabTitle", l10n_util::GetStringUTF16(IDS_SSL_V2_TITLE));
422   load_time_data.SetString(
423       "heading", l10n_util::GetStringUTF16(IDS_SSL_V2_HEADING));
424   load_time_data.SetString(
425       "primaryParagraph",
426       l10n_util::GetStringFUTF16(IDS_SSL_V2_PRIMARY_PARAGRAPH, url));
427   load_time_data.SetString(
428      "openDetails",
429      l10n_util::GetStringUTF16(IDS_SSL_V2_OPEN_DETAILS_BUTTON));
430   load_time_data.SetString(
431      "closeDetails",
432      l10n_util::GetStringUTF16(IDS_SSL_V2_CLOSE_DETAILS_BUTTON));
433 
434   if (overridable_ && !strict_enforcement_) {  // Overridable.
435     SSLErrorInfo error_info =
436         SSLErrorInfo::CreateError(
437             SSLErrorInfo::NetErrorToErrorType(cert_error_),
438             ssl_info_.cert.get(),
439             request_url_);
440     load_time_data.SetString(
441         "explanationParagraph", error_info.details());
442     load_time_data.SetString(
443         "primaryButtonText",
444         l10n_util::GetStringUTF16(IDS_SSL_OVERRIDABLE_SAFETY_BUTTON));
445     load_time_data.SetString(
446         "finalParagraph",
447         l10n_util::GetStringFUTF16(IDS_SSL_OVERRIDABLE_PROCEED_PARAGRAPH, url));
448   } else {  // Non-overridable.
449     load_time_data.SetBoolean("overridable", false);
450     load_time_data.SetString(
451         "explanationParagraph",
452         l10n_util::GetStringFUTF16(IDS_SSL_NONOVERRIDABLE_MORE, url));
453     load_time_data.SetString(
454         "primaryButtonText",
455         l10n_util::GetStringUTF16(IDS_SSL_NONOVERRIDABLE_RELOAD_BUTTON));
456     // Customize the help link depending on the specific error type.
457     // Only mark as HSTS if none of the more specific error types apply, and use
458     // INVALID as a fallback if no other string is appropriate.
459     SSLErrorInfo::ErrorType type =
460         SSLErrorInfo::NetErrorToErrorType(cert_error_);
461     load_time_data.SetInteger("errorType", type);
462     int help_string = IDS_SSL_NONOVERRIDABLE_INVALID;
463     switch (type) {
464       case SSLErrorInfo::CERT_REVOKED:
465         help_string = IDS_SSL_NONOVERRIDABLE_REVOKED;
466         break;
467       case SSLErrorInfo::CERT_PINNED_KEY_MISSING:
468         help_string = IDS_SSL_NONOVERRIDABLE_PINNED;
469         break;
470       case SSLErrorInfo::CERT_INVALID:
471         help_string = IDS_SSL_NONOVERRIDABLE_INVALID;
472         break;
473       default:
474         if (strict_enforcement_)
475           help_string = IDS_SSL_NONOVERRIDABLE_HSTS;
476     }
477     load_time_data.SetString(
478         "finalParagraph", l10n_util::GetStringFUTF16(help_string, url));
479     load_time_data.SetString("errorCode", net::ErrorToString(cert_error_));
480   }
481 
482   base::StringPiece html(
483      ResourceBundle::GetSharedInstance().GetRawDataResource(
484          IRD_SSL_INTERSTITIAL_V2_HTML));
485   webui::UseVersion2 version;
486   return webui::GetI18nTemplateHtml(html, &load_time_data);
487 }
488 
OverrideEntry(NavigationEntry * entry)489 void SSLBlockingPage::OverrideEntry(NavigationEntry* entry) {
490   int cert_id = content::CertStore::GetInstance()->StoreCert(
491       ssl_info_.cert.get(), web_contents_->GetRenderProcessHost()->GetID());
492   DCHECK(cert_id);
493 
494   entry->GetSSL().security_style =
495       content::SECURITY_STYLE_AUTHENTICATION_BROKEN;
496   entry->GetSSL().cert_id = cert_id;
497   entry->GetSSL().cert_status = ssl_info_.cert_status;
498   entry->GetSSL().security_bits = ssl_info_.security_bits;
499 }
500 
501 // This handles the commands sent from the interstitial JavaScript. They are
502 // defined in chrome/browser/resources/ssl/ssl_errors_common.js.
503 // DO NOT reorder or change this logic without also changing the JavaScript!
CommandReceived(const std::string & command)504 void SSLBlockingPage::CommandReceived(const std::string& command) {
505   int cmd = 0;
506   bool retval = base::StringToInt(command, &cmd);
507   DCHECK(retval);
508   switch (cmd) {
509     case CMD_DONT_PROCEED: {
510       interstitial_page_->DontProceed();
511       break;
512     }
513     case CMD_PROCEED: {
514       interstitial_page_->Proceed();
515       break;
516     }
517     case CMD_MORE: {
518       RecordSSLBlockingPageEventStats(MORE);
519       break;
520     }
521     case CMD_RELOAD: {
522       // The interstitial can't refresh itself.
523       web_contents_->GetController().Reload(true);
524       break;
525     }
526     case CMD_HELP: {
527       // The interstitial can't open a popup or navigate itself.
528       // TODO(felt): We're going to need a new help page.
529       content::NavigationController::LoadURLParams help_page_params(GURL(
530           "https://support.google.com/chrome/answer/4454607"));
531       web_contents_->GetController().LoadURLWithParams(help_page_params);
532       break;
533     }
534     default: {
535       NOTREACHED();
536     }
537   }
538 }
539 
OverrideRendererPrefs(content::RendererPreferences * prefs)540 void SSLBlockingPage::OverrideRendererPrefs(
541       content::RendererPreferences* prefs) {
542   Profile* profile = Profile::FromBrowserContext(
543       web_contents_->GetBrowserContext());
544   renderer_preferences_util::UpdateFromSystemSettings(prefs, profile);
545 }
546 
OnProceed()547 void SSLBlockingPage::OnProceed() {
548   RecordSSLBlockingPageDetailedStats(true,
549                                      cert_error_,
550                                      overridable_ && !strict_enforcement_,
551                                      internal_,
552                                      num_visits_,
553                                      captive_portal_detection_enabled_,
554                                      captive_portal_probe_completed_,
555                                      captive_portal_no_response_,
556                                      captive_portal_detected_);
557   // Accepting the certificate resumes the loading of the page.
558   NotifyAllowCertificate();
559 }
560 
OnDontProceed()561 void SSLBlockingPage::OnDontProceed() {
562   RecordSSLBlockingPageDetailedStats(false,
563                                      cert_error_,
564                                      overridable_ && !strict_enforcement_,
565                                      internal_,
566                                      num_visits_,
567                                      captive_portal_detection_enabled_,
568                                      captive_portal_probe_completed_,
569                                      captive_portal_no_response_,
570                                      captive_portal_detected_);
571   NotifyDenyCertificate();
572 }
573 
NotifyDenyCertificate()574 void SSLBlockingPage::NotifyDenyCertificate() {
575   // It's possible that callback_ may not exist if the user clicks "Proceed"
576   // followed by pressing the back button before the interstitial is hidden.
577   // In that case the certificate will still be treated as allowed.
578   if (callback_.is_null())
579     return;
580 
581   callback_.Run(false);
582   callback_.Reset();
583 }
584 
NotifyAllowCertificate()585 void SSLBlockingPage::NotifyAllowCertificate() {
586   DCHECK(!callback_.is_null());
587 
588   callback_.Run(true);
589   callback_.Reset();
590 }
591 
592 // static
SetExtraInfo(base::DictionaryValue * strings,const std::vector<base::string16> & extra_info)593 void SSLBlockingPage::SetExtraInfo(
594     base::DictionaryValue* strings,
595     const std::vector<base::string16>& extra_info) {
596   DCHECK_LT(extra_info.size(), 5U);  // We allow 5 paragraphs max.
597   const char* keys[5] = {
598       "moreInfo1", "moreInfo2", "moreInfo3", "moreInfo4", "moreInfo5"
599   };
600   int i;
601   for (i = 0; i < static_cast<int>(extra_info.size()); i++) {
602     strings->SetString(keys[i], extra_info[i]);
603   }
604   for (; i < 5; i++) {
605     strings->SetString(keys[i], std::string());
606   }
607 }
608 
OnGotHistoryCount(HistoryService::Handle handle,bool success,int num_visits,base::Time first_visit)609 void SSLBlockingPage::OnGotHistoryCount(HistoryService::Handle handle,
610                                         bool success,
611                                         int num_visits,
612                                         base::Time first_visit) {
613   num_visits_ = num_visits;
614 }
615 
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)616 void SSLBlockingPage::Observe(
617     int type,
618     const content::NotificationSource& source,
619     const content::NotificationDetails& details) {
620 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
621   // When detection is disabled, captive portal service always sends
622   // RESULT_INTERNET_CONNECTED. Ignore any probe results in that case.
623   if (!captive_portal_detection_enabled_)
624     return;
625   if (type == chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT) {
626     captive_portal_probe_completed_ = true;
627     CaptivePortalService::Results* results =
628         content::Details<CaptivePortalService::Results>(
629             details).ptr();
630     // If a captive portal was detected at any point when the interstitial was
631     // displayed, assume that the interstitial was caused by a captive portal.
632     // Example scenario:
633     // 1- Interstitial displayed and captive portal detected, setting the flag.
634     // 2- Captive portal detection automatically opens portal login page.
635     // 3- User logs in on the portal login page.
636     // A notification will be received here for RESULT_INTERNET_CONNECTED. Make
637     // sure we don't clear the captive portal flag, since the interstitial was
638     // potentially caused by the captive portal.
639     captive_portal_detected_ = captive_portal_detected_ ||
640         (results->result == captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL);
641     // Also keep track of non-HTTP portals and error cases.
642     captive_portal_no_response_ = captive_portal_no_response_ ||
643         (results->result == captive_portal::RESULT_NO_RESPONSE);
644   }
645 #endif
646 }
647