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/build_time.h"
8#include "base/command_line.h"
9#include "base/i18n/rtl.h"
10#include "base/i18n/time_formatting.h"
11#include "base/metrics/field_trial.h"
12#include "base/metrics/histogram.h"
13#include "base/process/launch.h"
14#include "base/strings/string_number_conversions.h"
15#include "base/strings/string_piece.h"
16#include "base/strings/string_util.h"
17#include "base/strings/stringprintf.h"
18#include "base/strings/utf_string_conversions.h"
19#include "base/time/time.h"
20#include "base/values.h"
21#include "chrome/browser/browser_process.h"
22#include "chrome/browser/chrome_notification_types.h"
23#include "chrome/browser/history/history_service_factory.h"
24#include "chrome/browser/profiles/profile.h"
25#include "chrome/browser/renderer_preferences_util.h"
26#include "chrome/browser/ssl/ssl_error_classification.h"
27#include "chrome/browser/ssl/ssl_error_info.h"
28#include "chrome/common/chrome_switches.h"
29#include "chrome/grit/chromium_strings.h"
30#include "chrome/grit/generated_resources.h"
31#include "components/google/core/browser/google_util.h"
32#include "content/public/browser/cert_store.h"
33#include "content/public/browser/interstitial_page.h"
34#include "content/public/browser/navigation_controller.h"
35#include "content/public/browser/navigation_entry.h"
36#include "content/public/browser/notification_service.h"
37#include "content/public/browser/notification_types.h"
38#include "content/public/browser/render_process_host.h"
39#include "content/public/browser/render_view_host.h"
40#include "content/public/browser/web_contents.h"
41#include "content/public/common/ssl_status.h"
42#include "grit/browser_resources.h"
43#include "net/base/hash_value.h"
44#include "net/base/net_errors.h"
45#include "net/base/net_util.h"
46#include "ui/base/l10n/l10n_util.h"
47#include "ui/base/resource/resource_bundle.h"
48#include "ui/base/webui/jstemplate_builder.h"
49#include "ui/base/webui/web_ui_util.h"
50
51#if defined(ENABLE_EXTENSIONS)
52#include "chrome/browser/extensions/api/experience_sampling_private/experience_sampling.h"
53#endif
54
55#if defined(OS_WIN)
56#include "base/base_paths_win.h"
57#include "base/path_service.h"
58#include "base/strings/string16.h"
59#include "base/win/windows_version.h"
60#endif
61
62#if defined(OS_CHROMEOS)
63#include "chrome/browser/profiles/profile_manager.h"
64#include "chrome/browser/ui/chrome_pages.h"
65#include "chrome/common/url_constants.h"
66#endif
67
68using base::ASCIIToUTF16;
69using base::TimeTicks;
70using content::InterstitialPage;
71using content::NavigationController;
72using content::NavigationEntry;
73
74#if defined(ENABLE_EXTENSIONS)
75using extensions::ExperienceSamplingEvent;
76#endif
77
78namespace {
79
80// URL for help page.
81const char kHelpURL[] = "https://support.google.com/chrome/answer/4454607";
82
83// Constants for the Experience Sampling instrumentation.
84#if defined(ENABLE_EXTENSIONS)
85const char kEventNameBase[] = "ssl_interstitial_";
86const char kEventNotOverridable[] = "notoverridable_";
87const char kEventOverridable[] = "overridable_";
88#endif
89
90// Events for UMA. Do not reorder or change!
91enum SSLBlockingPageEvent {
92  SHOW_ALL,
93  SHOW_OVERRIDABLE,
94  PROCEED_OVERRIDABLE,
95  PROCEED_NAME,
96  PROCEED_DATE,
97  PROCEED_AUTHORITY,
98  DONT_PROCEED_OVERRIDABLE,
99  DONT_PROCEED_NAME,
100  DONT_PROCEED_DATE,
101  DONT_PROCEED_AUTHORITY,
102  MORE,
103  SHOW_UNDERSTAND,  // Used by the summer 2013 Finch trial. Deprecated.
104  SHOW_INTERNAL_HOSTNAME,
105  PROCEED_INTERNAL_HOSTNAME,
106  SHOW_NEW_SITE,
107  PROCEED_NEW_SITE,
108  PROCEED_MANUAL_NONOVERRIDABLE,
109  // Captive Portal errors moved to ssl_error_classification.
110  DEPRECATED_CAPTIVE_PORTAL_DETECTION_ENABLED,
111  DEPRECATED_CAPTIVE_PORTAL_DETECTION_ENABLED_OVERRIDABLE,
112  DEPRECATED_CAPTIVE_PORTAL_PROBE_COMPLETED,
113  DEPRECATED_CAPTIVE_PORTAL_PROBE_COMPLETED_OVERRIDABLE,
114  DEPRECATED_CAPTIVE_PORTAL_NO_RESPONSE,
115  DEPRECATED_CAPTIVE_PORTAL_NO_RESPONSE_OVERRIDABLE,
116  DEPRECATED_CAPTIVE_PORTAL_DETECTED,
117  DEPRECATED_CAPTIVE_PORTAL_DETECTED_OVERRIDABLE,
118  UNUSED_BLOCKING_PAGE_EVENT,
119};
120
121// Events for UMA. Do not reorder or change!
122enum SSLExpirationAndDecision {
123  EXPIRED_AND_PROCEED,
124  EXPIRED_AND_DO_NOT_PROCEED,
125  NOT_EXPIRED_AND_PROCEED,
126  NOT_EXPIRED_AND_DO_NOT_PROCEED,
127  END_OF_SSL_EXPIRATION_AND_DECISION,
128};
129
130void RecordSSLBlockingPageEventStats(SSLBlockingPageEvent event) {
131  UMA_HISTOGRAM_ENUMERATION("interstitial.ssl",
132                            event,
133                            UNUSED_BLOCKING_PAGE_EVENT);
134}
135
136void RecordSSLExpirationPageEventState(bool expired_but_previously_allowed,
137                                       bool proceed,
138                                       bool overridable) {
139  SSLExpirationAndDecision event;
140  if (expired_but_previously_allowed && proceed)
141    event = EXPIRED_AND_PROCEED;
142  else if (expired_but_previously_allowed && !proceed)
143    event = EXPIRED_AND_DO_NOT_PROCEED;
144  else if (!expired_but_previously_allowed && proceed)
145    event = NOT_EXPIRED_AND_PROCEED;
146  else
147    event = NOT_EXPIRED_AND_DO_NOT_PROCEED;
148
149  if (overridable) {
150    UMA_HISTOGRAM_ENUMERATION(
151        "interstitial.ssl.expiration_and_decision.overridable",
152        event,
153        END_OF_SSL_EXPIRATION_AND_DECISION);
154  } else {
155    UMA_HISTOGRAM_ENUMERATION(
156        "interstitial.ssl.expiration_and_decision.nonoverridable",
157        event,
158        END_OF_SSL_EXPIRATION_AND_DECISION);
159  }
160}
161
162void RecordSSLBlockingPageDetailedStats(bool proceed,
163                                        int cert_error,
164                                        bool overridable,
165                                        bool internal,
166                                        int num_visits,
167                                        bool expired_but_previously_allowed) {
168  UMA_HISTOGRAM_ENUMERATION("interstitial.ssl_error_type",
169      SSLErrorInfo::NetErrorToErrorType(cert_error), SSLErrorInfo::END_OF_ENUM);
170  RecordSSLExpirationPageEventState(
171      expired_but_previously_allowed, proceed, overridable);
172  if (!overridable) {
173    if (proceed) {
174      RecordSSLBlockingPageEventStats(PROCEED_MANUAL_NONOVERRIDABLE);
175    }
176    // Overridable is false if the user didn't have any option except to turn
177    // back. If that's the case, don't record some of the metrics.
178    return;
179  }
180  if (num_visits == 0)
181    RecordSSLBlockingPageEventStats(SHOW_NEW_SITE);
182  if (proceed) {
183    RecordSSLBlockingPageEventStats(PROCEED_OVERRIDABLE);
184    if (internal)
185      RecordSSLBlockingPageEventStats(PROCEED_INTERNAL_HOSTNAME);
186    if (num_visits == 0)
187      RecordSSLBlockingPageEventStats(PROCEED_NEW_SITE);
188  } else if (!proceed) {
189    RecordSSLBlockingPageEventStats(DONT_PROCEED_OVERRIDABLE);
190  }
191  SSLErrorInfo::ErrorType type = SSLErrorInfo::NetErrorToErrorType(cert_error);
192  switch (type) {
193    case SSLErrorInfo::CERT_COMMON_NAME_INVALID: {
194      if (proceed)
195        RecordSSLBlockingPageEventStats(PROCEED_NAME);
196      else
197        RecordSSLBlockingPageEventStats(DONT_PROCEED_NAME);
198      break;
199    }
200    case SSLErrorInfo::CERT_DATE_INVALID: {
201      if (proceed)
202        RecordSSLBlockingPageEventStats(PROCEED_DATE);
203      else
204        RecordSSLBlockingPageEventStats(DONT_PROCEED_DATE);
205      break;
206    }
207    case SSLErrorInfo::CERT_AUTHORITY_INVALID: {
208      if (proceed)
209        RecordSSLBlockingPageEventStats(PROCEED_AUTHORITY);
210      else
211        RecordSSLBlockingPageEventStats(DONT_PROCEED_AUTHORITY);
212      break;
213    }
214    default: {
215      break;
216    }
217  }
218}
219
220void LaunchDateAndTimeSettings() {
221#if defined(OS_CHROMEOS)
222  std::string sub_page = std::string(chrome::kSearchSubPage) + "#" +
223      l10n_util::GetStringUTF8(IDS_OPTIONS_SETTINGS_SECTION_TITLE_DATETIME);
224  chrome::ShowSettingsSubPageForProfile(
225      ProfileManager::GetActiveUserProfile(), sub_page);
226  return;
227#elif defined(OS_ANDROID)
228  CommandLine command(base::FilePath("/system/bin/am"));
229  command.AppendArg("start");
230  command.AppendArg(
231      "'com.android.settings/.Settings$DateTimeSettingsActivity'");
232#elif defined(OS_IOS)
233  // Apparently, iOS really does not have a way to launch the date and time
234  // settings. Weird. TODO(palmer): Do something more graceful than ignoring
235  // the user's click! crbug.com/394993
236  return;
237#elif defined(OS_LINUX)
238  struct ClockCommand {
239    const char* pathname;
240    const char* argument;
241  };
242  static const ClockCommand kClockCommands[] = {
243    // GNOME
244    //
245    // NOTE: On old Ubuntu, naming control panels doesn't work, so it
246    // opens the overview. This will have to be good enough.
247    { "/usr/bin/gnome-control-center", "datetime" },
248    { "/usr/local/bin/gnome-control-center", "datetime" },
249    { "/opt/bin/gnome-control-center", "datetime" },
250    // KDE
251    { "/usr/bin/kcmshell4", "clock" },
252    { "/usr/local/bin/kcmshell4", "clock" },
253    { "/opt/bin/kcmshell4", "clock" },
254  };
255
256  CommandLine command(base::FilePath(""));
257  for (size_t i = 0; i < arraysize(kClockCommands); ++i) {
258    base::FilePath pathname(kClockCommands[i].pathname);
259    if (base::PathExists(pathname)) {
260      command.SetProgram(pathname);
261      command.AppendArg(kClockCommands[i].argument);
262      break;
263    }
264  }
265  if (command.GetProgram().empty()) {
266    // Alas, there is nothing we can do.
267    return;
268  }
269#elif defined(OS_MACOSX)
270  CommandLine command(base::FilePath("/usr/bin/open"));
271  command.AppendArg("/System/Library/PreferencePanes/DateAndTime.prefPane");
272#elif defined(OS_WIN)
273  base::FilePath path;
274  PathService::Get(base::DIR_SYSTEM, &path);
275  static const base::char16 kControlPanelExe[] = L"control.exe";
276  path = path.Append(base::string16(kControlPanelExe));
277  CommandLine command(path);
278  command.AppendArg(std::string("/name"));
279  command.AppendArg(std::string("Microsoft.DateAndTime"));
280#else
281  return;
282#endif
283
284#if !defined(OS_CHROMEOS)
285  base::LaunchOptions options;
286  options.wait = false;
287#if defined(OS_LINUX)
288  options.allow_new_privs = true;
289#endif
290  base::LaunchProcess(command, options, NULL);
291#endif
292}
293
294bool IsErrorDueToBadClock(const base::Time& now, int error) {
295  if (SSLErrorInfo::NetErrorToErrorType(error) !=
296          SSLErrorInfo::CERT_DATE_INVALID) {
297    return false;
298  }
299  return SSLErrorClassification::IsUserClockInThePast(now) ||
300      SSLErrorClassification::IsUserClockInTheFuture(now);
301}
302
303}  // namespace
304
305// Note that we always create a navigation entry with SSL errors.
306// No error happening loading a sub-resource triggers an interstitial so far.
307SSLBlockingPage::SSLBlockingPage(content::WebContents* web_contents,
308                                 int cert_error,
309                                 const net::SSLInfo& ssl_info,
310                                 const GURL& request_url,
311                                 int options_mask,
312                                 const base::Callback<void(bool)>& callback)
313    : callback_(callback),
314      web_contents_(web_contents),
315      cert_error_(cert_error),
316      ssl_info_(ssl_info),
317      request_url_(request_url),
318      overridable_(options_mask & OVERRIDABLE &&
319                   !(options_mask & STRICT_ENFORCEMENT)),
320      strict_enforcement_((options_mask & STRICT_ENFORCEMENT) != 0),
321      interstitial_page_(NULL),
322      internal_(false),
323      num_visits_(-1),
324      expired_but_previously_allowed_(
325          (options_mask & EXPIRED_BUT_PREVIOUSLY_ALLOWED) != 0) {
326  Profile* profile = Profile::FromBrowserContext(
327      web_contents->GetBrowserContext());
328  // For UMA stats.
329  if (net::IsHostnameNonUnique(request_url_.HostNoBrackets()))
330    internal_ = true;
331  RecordSSLBlockingPageEventStats(SHOW_ALL);
332  if (overridable_) {
333    RecordSSLBlockingPageEventStats(SHOW_OVERRIDABLE);
334    if (internal_)
335      RecordSSLBlockingPageEventStats(SHOW_INTERNAL_HOSTNAME);
336    HistoryService* history_service = HistoryServiceFactory::GetForProfile(
337        profile, Profile::EXPLICIT_ACCESS);
338    if (history_service) {
339      history_service->GetVisibleVisitCountToHost(
340          request_url_,
341          base::Bind(&SSLBlockingPage::OnGotHistoryCount,
342                     base::Unretained(this)),
343          &request_tracker_);
344    }
345  }
346
347  ssl_error_classification_.reset(new SSLErrorClassification(
348      web_contents_,
349      base::Time::NowFromSystemTime(),
350      request_url_,
351      cert_error_,
352      *ssl_info_.cert.get()));
353  ssl_error_classification_->RecordUMAStatistics(overridable_);
354
355#if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
356  ssl_error_classification_->RecordCaptivePortalUMAStatistics(overridable_);
357#endif
358
359#if defined(ENABLE_EXTENSIONS)
360  // ExperienceSampling: Set up new sampling event for this interstitial.
361  std::string event_name(kEventNameBase);
362  if (overridable_ && !strict_enforcement_)
363    event_name.append(kEventOverridable);
364  else
365    event_name.append(kEventNotOverridable);
366  event_name.append(net::ErrorToString(cert_error_));
367  sampling_event_.reset(new ExperienceSamplingEvent(
368      event_name,
369      request_url_,
370      web_contents_->GetLastCommittedURL(),
371      web_contents_->GetBrowserContext()));
372#endif
373
374  // Creating an interstitial without showing (e.g. from chrome://interstitials)
375  // it leaks memory, so don't create it here.
376}
377
378SSLBlockingPage::~SSLBlockingPage() {
379  // InvalidCommonNameSeverityScore() and InvalidDateSeverityScore() are in the
380  // destructor because they depend on knowing whether captive portal detection
381  // happened before the user made a decision.
382  SSLErrorInfo::ErrorType type =
383      SSLErrorInfo::NetErrorToErrorType(cert_error_);
384  switch (type) {
385    case SSLErrorInfo::CERT_DATE_INVALID:
386      ssl_error_classification_->InvalidDateSeverityScore();
387      break;
388    case SSLErrorInfo::CERT_COMMON_NAME_INVALID:
389      ssl_error_classification_->InvalidCommonNameSeverityScore();
390      break;
391    default:
392      break;
393  }
394  if (!callback_.is_null()) {
395    RecordSSLBlockingPageDetailedStats(false,
396                                       cert_error_,
397                                       overridable_,
398                                       internal_,
399                                       num_visits_,
400                                       expired_but_previously_allowed_);
401    // The page is closed without the user having chosen what to do, default to
402    // deny.
403    NotifyDenyCertificate();
404  }
405}
406
407void SSLBlockingPage::Show() {
408  DCHECK(!interstitial_page_);
409  interstitial_page_ = InterstitialPage::Create(
410      web_contents_, true, request_url_, this);
411  interstitial_page_->Show();
412}
413
414std::string SSLBlockingPage::GetHTMLContents() {
415  base::DictionaryValue load_time_data;
416  base::string16 url(ASCIIToUTF16(request_url_.host()));
417  if (base::i18n::IsRTL())
418    base::i18n::WrapStringWithLTRFormatting(&url);
419  webui::SetFontAndTextDirection(&load_time_data);
420
421  // Shared values for both the overridable and non-overridable versions.
422  load_time_data.SetBoolean("ssl", true);
423  load_time_data.SetBoolean("overridable", overridable_);
424  load_time_data.SetString(
425      "tabTitle", l10n_util::GetStringUTF16(IDS_SSL_V2_TITLE));
426  load_time_data.SetString(
427      "heading", l10n_util::GetStringUTF16(IDS_SSL_V2_HEADING));
428
429  base::Time now = base::Time::NowFromSystemTime();
430  bool bad_clock = IsErrorDueToBadClock(now, cert_error_);
431  if (bad_clock) {
432    load_time_data.SetString("primaryParagraph",
433                             l10n_util::GetStringFUTF16(
434                                 IDS_SSL_CLOCK_ERROR,
435                                 url,
436                                 base::TimeFormatShortDate(now)));
437  } else {
438    load_time_data.SetString(
439        "primaryParagraph",
440        l10n_util::GetStringFUTF16(IDS_SSL_V2_PRIMARY_PARAGRAPH, url));
441  }
442
443  load_time_data.SetString(
444     "openDetails",
445     l10n_util::GetStringUTF16(IDS_SSL_V2_OPEN_DETAILS_BUTTON));
446  load_time_data.SetString(
447     "closeDetails",
448     l10n_util::GetStringUTF16(IDS_SSL_V2_CLOSE_DETAILS_BUTTON));
449  load_time_data.SetString("errorCode", net::ErrorToString(cert_error_));
450
451  if (overridable_) {
452    SSLErrorInfo error_info =
453        SSLErrorInfo::CreateError(
454            SSLErrorInfo::NetErrorToErrorType(cert_error_),
455            ssl_info_.cert.get(),
456            request_url_);
457    if (bad_clock) {
458      load_time_data.SetString("explanationParagraph",
459                               l10n_util::GetStringFUTF16(
460                                   IDS_SSL_CLOCK_ERROR_EXPLANATION, url));
461    } else {
462      load_time_data.SetString("explanationParagraph", error_info.details());
463    }
464    load_time_data.SetString(
465        "primaryButtonText",
466        l10n_util::GetStringUTF16(IDS_SSL_OVERRIDABLE_SAFETY_BUTTON));
467    load_time_data.SetString(
468        "finalParagraph",
469        l10n_util::GetStringFUTF16(IDS_SSL_OVERRIDABLE_PROCEED_PARAGRAPH,
470                                   url));
471  } else {
472    SSLErrorInfo::ErrorType type =
473        SSLErrorInfo::NetErrorToErrorType(cert_error_);
474    if (type == SSLErrorInfo::CERT_INVALID && SSLErrorClassification::
475        MaybeWindowsLacksSHA256Support()) {
476      load_time_data.SetString(
477          "explanationParagraph",
478          l10n_util::GetStringFUTF16(
479              IDS_SSL_NONOVERRIDABLE_MORE_INVALID_SP3, url));
480    } else if (bad_clock) {
481      load_time_data.SetString("explanationParagraph",
482                               l10n_util::GetStringFUTF16(
483                                   IDS_SSL_CLOCK_ERROR_EXPLANATION, url));
484    } else {
485      load_time_data.SetString("explanationParagraph",
486                               l10n_util::GetStringFUTF16(
487                                   IDS_SSL_NONOVERRIDABLE_MORE, url));
488    }
489    load_time_data.SetString(
490        "primaryButtonText",
491        l10n_util::GetStringUTF16(IDS_SSL_NONOVERRIDABLE_RELOAD_BUTTON));
492    // Customize the help link depending on the specific error type.
493    // Only mark as HSTS if none of the more specific error types apply, and use
494    // INVALID as a fallback if no other string is appropriate.
495    load_time_data.SetInteger("errorType", type);
496    int help_string = IDS_SSL_NONOVERRIDABLE_INVALID;
497    switch (type) {
498      case SSLErrorInfo::CERT_REVOKED:
499        help_string = IDS_SSL_NONOVERRIDABLE_REVOKED;
500        break;
501      case SSLErrorInfo::CERT_PINNED_KEY_MISSING:
502        help_string = IDS_SSL_NONOVERRIDABLE_PINNED;
503        break;
504      case SSLErrorInfo::CERT_INVALID:
505        help_string = IDS_SSL_NONOVERRIDABLE_INVALID;
506        break;
507      default:
508        if (strict_enforcement_)
509          help_string = IDS_SSL_NONOVERRIDABLE_HSTS;
510    }
511    load_time_data.SetString(
512        "finalParagraph", l10n_util::GetStringFUTF16(help_string, url));
513  }
514
515  // Set debugging information at the bottom of the warning.
516  load_time_data.SetString(
517      "subject", ssl_info_.cert->subject().GetDisplayName());
518  load_time_data.SetString(
519      "issuer", ssl_info_.cert->issuer().GetDisplayName());
520  load_time_data.SetString(
521      "expirationDate",
522      base::TimeFormatShortDate(ssl_info_.cert->valid_expiry()));
523  load_time_data.SetString(
524      "currentDate", base::TimeFormatShortDate(now));
525  std::vector<std::string> encoded_chain;
526  ssl_info_.cert->GetPEMEncodedChain(&encoded_chain);
527  load_time_data.SetString("pem", JoinString(encoded_chain, std::string()));
528
529  base::StringPiece html(
530     ResourceBundle::GetSharedInstance().GetRawDataResource(
531         IRD_SECURITY_INTERSTITIAL_HTML));
532  webui::UseVersion2 version;
533  return webui::GetI18nTemplateHtml(html, &load_time_data);
534}
535
536void SSLBlockingPage::OverrideEntry(NavigationEntry* entry) {
537  int cert_id = content::CertStore::GetInstance()->StoreCert(
538      ssl_info_.cert.get(), web_contents_->GetRenderProcessHost()->GetID());
539  DCHECK(cert_id);
540
541  entry->GetSSL().security_style =
542      content::SECURITY_STYLE_AUTHENTICATION_BROKEN;
543  entry->GetSSL().cert_id = cert_id;
544  entry->GetSSL().cert_status = ssl_info_.cert_status;
545  entry->GetSSL().security_bits = ssl_info_.security_bits;
546}
547
548// This handles the commands sent from the interstitial JavaScript. They are
549// defined in chrome/browser/resources/ssl/ssl_errors_common.js.
550// DO NOT reorder or change this logic without also changing the JavaScript!
551void SSLBlockingPage::CommandReceived(const std::string& command) {
552  int cmd = 0;
553  bool retval = base::StringToInt(command, &cmd);
554  DCHECK(retval);
555  switch (cmd) {
556    case CMD_DONT_PROCEED: {
557      interstitial_page_->DontProceed();
558      break;
559    }
560    case CMD_PROCEED: {
561      interstitial_page_->Proceed();
562      break;
563    }
564    case CMD_MORE: {
565      RecordSSLBlockingPageEventStats(MORE);
566#if defined(ENABLE_EXTENSIONS)
567      if (sampling_event_.get())
568        sampling_event_->set_has_viewed_details(true);
569#endif
570      break;
571    }
572    case CMD_RELOAD: {
573      // The interstitial can't refresh itself.
574      web_contents_->GetController().Reload(true);
575      break;
576    }
577    case CMD_HELP: {
578      content::NavigationController::LoadURLParams help_page_params(
579          google_util::AppendGoogleLocaleParam(
580              GURL(kHelpURL), g_browser_process->GetApplicationLocale()));
581#if defined(ENABLE_EXTENSIONS)
582      if (sampling_event_.get())
583        sampling_event_->set_has_viewed_learn_more(true);
584#endif
585      web_contents_->GetController().LoadURLWithParams(help_page_params);
586      break;
587    }
588    case CMD_CLOCK: {
589      LaunchDateAndTimeSettings();
590      break;
591    }
592    default: {
593      NOTREACHED();
594    }
595  }
596}
597
598void SSLBlockingPage::OverrideRendererPrefs(
599      content::RendererPreferences* prefs) {
600  Profile* profile = Profile::FromBrowserContext(
601      web_contents_->GetBrowserContext());
602  renderer_preferences_util::UpdateFromSystemSettings(prefs, profile);
603}
604
605void SSLBlockingPage::OnProceed() {
606  RecordSSLBlockingPageDetailedStats(true,
607                                     cert_error_,
608                                     overridable_,
609                                     internal_,
610                                     num_visits_,
611                                     expired_but_previously_allowed_);
612#if defined(ENABLE_EXTENSIONS)
613  // ExperienceSampling: Notify that user decided to proceed.
614  if (sampling_event_.get())
615    sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kProceed);
616#endif
617
618  // Accepting the certificate resumes the loading of the page.
619  NotifyAllowCertificate();
620}
621
622void SSLBlockingPage::OnDontProceed() {
623  RecordSSLBlockingPageDetailedStats(false,
624                                     cert_error_,
625                                     overridable_,
626                                     internal_,
627                                     num_visits_,
628                                     expired_but_previously_allowed_);
629#if defined(ENABLE_EXTENSIONS)
630  // ExperienceSampling: Notify that user decided to not proceed.
631  // This also occurs if the user navigates away or closes the tab.
632  if (sampling_event_.get())
633    sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kDeny);
634#endif
635  NotifyDenyCertificate();
636}
637
638void SSLBlockingPage::NotifyDenyCertificate() {
639  // It's possible that callback_ may not exist if the user clicks "Proceed"
640  // followed by pressing the back button before the interstitial is hidden.
641  // In that case the certificate will still be treated as allowed.
642  if (callback_.is_null())
643    return;
644
645  callback_.Run(false);
646  callback_.Reset();
647}
648
649void SSLBlockingPage::NotifyAllowCertificate() {
650  DCHECK(!callback_.is_null());
651
652  callback_.Run(true);
653  callback_.Reset();
654}
655
656// static
657void SSLBlockingPage::SetExtraInfo(
658    base::DictionaryValue* strings,
659    const std::vector<base::string16>& extra_info) {
660  DCHECK_LT(extra_info.size(), 5U);  // We allow 5 paragraphs max.
661  const char* keys[5] = {
662      "moreInfo1", "moreInfo2", "moreInfo3", "moreInfo4", "moreInfo5"
663  };
664  int i;
665  for (i = 0; i < static_cast<int>(extra_info.size()); i++) {
666    strings->SetString(keys[i], extra_info[i]);
667  }
668  for (; i < 5; i++) {
669    strings->SetString(keys[i], std::string());
670  }
671}
672
673void SSLBlockingPage::OnGotHistoryCount(bool success,
674                                        int num_visits,
675                                        base::Time first_visit) {
676  num_visits_ = num_visits;
677}
678