OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/ssl/bad_clock_blocking_page.h" | 5 #include "chrome/browser/ssl/bad_clock_blocking_page.h" |
6 | 6 |
7 #include "base/bind.h" | |
8 #include "base/bind_helpers.h" | |
9 #include "base/build_time.h" | |
10 #include "base/callback_helpers.h" | 7 #include "base/callback_helpers.h" |
11 #include "base/command_line.h" | 8 #include "base/prefs/pref_service.h" |
12 #include "base/files/file_util.h" | |
13 #include "base/i18n/rtl.h" | |
14 #include "base/i18n/time_formatting.h" | |
15 #include "base/process/launch.h" | |
16 #include "base/strings/string_number_conversions.h" | 9 #include "base/strings/string_number_conversions.h" |
17 #include "base/strings/string_piece.h" | 10 #include "chrome/browser/interstitials/chrome_controller_client.h" |
18 #include "base/strings/string_util.h" | |
19 #include "base/strings/stringprintf.h" | |
20 #include "base/strings/utf_string_conversions.h" | |
21 #include "base/time/time.h" | |
22 #include "base/values.h" | |
23 #include "chrome/browser/browser_process.h" | |
24 #include "chrome/browser/interstitials/chrome_metrics_helper.h" | 11 #include "chrome/browser/interstitials/chrome_metrics_helper.h" |
25 #include "chrome/browser/profiles/profile.h" | 12 #include "chrome/browser/profiles/profile.h" |
26 #include "chrome/browser/renderer_preferences_util.h" | 13 #include "chrome/browser/renderer_preferences_util.h" |
27 #include "chrome/browser/ssl/cert_report_helper.h" | 14 #include "chrome/browser/ssl/cert_report_helper.h" |
28 #include "chrome/browser/ssl/ssl_cert_reporter.h" | 15 #include "chrome/browser/ssl/ssl_cert_reporter.h" |
29 #include "chrome/common/pref_names.h" | 16 #include "chrome/common/pref_names.h" |
30 #include "chrome/grit/generated_resources.h" | 17 #include "components/security_interstitials/core/bad_clock_ui.h" |
31 #include "components/google/core/browser/google_util.h" | |
32 #include "components/security_interstitials/core/controller_client.h" | 18 #include "components/security_interstitials/core/controller_client.h" |
33 #include "components/ssl_errors/error_classification.h" | 19 #include "components/security_interstitials/core/metrics_helper.h" |
34 #include "content/public/browser/browser_thread.h" | |
35 #include "content/public/browser/cert_store.h" | 20 #include "content/public/browser/cert_store.h" |
36 #include "content/public/browser/interstitial_page.h" | 21 #include "content/public/browser/interstitial_page.h" |
37 #include "content/public/browser/interstitial_page_delegate.h" | 22 #include "content/public/browser/interstitial_page_delegate.h" |
38 #include "content/public/browser/navigation_controller.h" | 23 #include "content/public/browser/navigation_controller.h" |
39 #include "content/public/browser/navigation_entry.h" | 24 #include "content/public/browser/navigation_entry.h" |
40 #include "content/public/browser/render_process_host.h" | 25 #include "content/public/browser/render_process_host.h" |
41 #include "content/public/browser/render_view_host.h" | 26 #include "content/public/browser/render_view_host.h" |
42 #include "content/public/browser/signed_certificate_timestamp_store.h" | 27 #include "content/public/browser/signed_certificate_timestamp_store.h" |
43 #include "content/public/browser/web_contents.h" | 28 #include "content/public/browser/web_contents.h" |
44 #include "content/public/common/renderer_preferences.h" | 29 #include "content/public/common/renderer_preferences.h" |
45 #include "content/public/common/ssl_status.h" | 30 #include "content/public/common/ssl_status.h" |
46 #include "grit/browser_resources.h" | |
47 #include "grit/components_strings.h" | |
48 #include "net/base/net_errors.h" | 31 #include "net/base/net_errors.h" |
49 #include "net/base/net_util.h" | |
50 #include "net/cert/x509_certificate.h" | |
51 #include "ui/base/l10n/l10n_util.h" | |
52 | 32 |
53 #if defined(OS_ANDROID) | |
54 #include "chrome/browser/android/intent_helper.h" | |
55 #endif | |
56 | |
57 #if defined(OS_CHROMEOS) | |
58 #include "chrome/browser/profiles/profile_manager.h" | |
59 #include "chrome/browser/ui/chrome_pages.h" | |
60 #include "chrome/common/url_constants.h" | |
61 #endif | |
62 | |
63 #if defined(OS_WIN) | |
64 #include "base/base_paths_win.h" | |
65 #include "base/path_service.h" | |
66 #include "base/strings/string16.h" | |
67 #include "base/win/windows_version.h" | |
68 #endif | |
69 | |
70 using base::ASCIIToUTF16; | |
71 using base::TimeTicks; | |
72 using content::InterstitialPage; | |
73 using content::InterstitialPageDelegate; | 33 using content::InterstitialPageDelegate; |
74 using content::NavigationController; | 34 using content::NavigationController; |
75 using content::NavigationEntry; | 35 using content::NavigationEntry; |
76 | 36 |
77 namespace { | 37 namespace { |
78 | 38 |
79 const char kMetricsName[] = "bad_clock"; | 39 const char kMetricsName[] = "bad_clock"; |
80 | 40 |
81 void LaunchDateAndTimeSettings() { | |
82 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE); | |
83 // The code for each OS is completely separate, in order to avoid bugs like | |
84 // https://crbug.com/430877 . | |
85 #if defined(OS_ANDROID) | |
86 chrome::android::OpenDateAndTimeSettings(); | |
87 | |
88 #elif defined(OS_CHROMEOS) | |
89 std::string sub_page = | |
90 std::string(chrome::kSearchSubPage) + "#" + | |
91 l10n_util::GetStringUTF8(IDS_OPTIONS_SETTINGS_SECTION_TITLE_DATETIME); | |
92 chrome::ShowSettingsSubPageForProfile(ProfileManager::GetActiveUserProfile(), | |
93 sub_page); | |
94 | |
95 #elif defined(OS_IOS) | |
96 // iOS does not have a way to launch the date and time settings. | |
97 NOTREACHED(); | |
98 | |
99 #elif defined(OS_LINUX) | |
100 struct ClockCommand { | |
101 const char* pathname; | |
102 const char* argument; | |
103 }; | |
104 static const ClockCommand kClockCommands[] = { | |
105 // Unity | |
106 {"/usr/bin/unity-control-center", "datetime"}, | |
107 // GNOME | |
108 // | |
109 // NOTE: On old Ubuntu, naming control panels doesn't work, so it | |
110 // opens the overview. This will have to be good enough. | |
111 {"/usr/bin/gnome-control-center", "datetime"}, | |
112 {"/usr/local/bin/gnome-control-center", "datetime"}, | |
113 {"/opt/bin/gnome-control-center", "datetime"}, | |
114 // KDE | |
115 {"/usr/bin/kcmshell4", "clock"}, | |
116 {"/usr/local/bin/kcmshell4", "clock"}, | |
117 {"/opt/bin/kcmshell4", "clock"}, | |
118 }; | |
119 | |
120 base::CommandLine command(base::FilePath("")); | |
121 for (const ClockCommand& cmd : kClockCommands) { | |
122 base::FilePath pathname(cmd.pathname); | |
123 if (base::PathExists(pathname)) { | |
124 command.SetProgram(pathname); | |
125 command.AppendArg(cmd.argument); | |
126 break; | |
127 } | |
128 } | |
129 if (command.GetProgram().empty()) { | |
130 // Alas, there is nothing we can do. | |
131 return; | |
132 } | |
133 | |
134 base::LaunchOptions options; | |
135 options.wait = false; | |
136 options.allow_new_privs = true; | |
137 base::LaunchProcess(command, options); | |
138 | |
139 #elif defined(OS_MACOSX) | |
140 base::CommandLine command(base::FilePath("/usr/bin/open")); | |
141 command.AppendArg("/System/Library/PreferencePanes/DateAndTime.prefPane"); | |
142 | |
143 base::LaunchOptions options; | |
144 options.wait = false; | |
145 base::LaunchProcess(command, options); | |
146 | |
147 #elif defined(OS_WIN) | |
148 base::FilePath path; | |
149 PathService::Get(base::DIR_SYSTEM, &path); | |
150 static const base::char16 kControlPanelExe[] = L"control.exe"; | |
151 path = path.Append(base::string16(kControlPanelExe)); | |
152 base::CommandLine command(path); | |
153 command.AppendArg(std::string("/name")); | |
154 command.AppendArg(std::string("Microsoft.DateAndTime")); | |
155 | |
156 base::LaunchOptions options; | |
157 options.wait = false; | |
158 base::LaunchProcess(command, options); | |
159 | |
160 #else | |
161 NOTREACHED(); | |
162 | |
163 #endif | |
164 // Don't add code here! (See the comment at the beginning of the function.) | |
165 } | |
166 | |
167 } // namespace | 41 } // namespace |
168 | 42 |
169 // static | 43 // static |
170 InterstitialPageDelegate::TypeID BadClockBlockingPage::kTypeForTesting = | 44 InterstitialPageDelegate::TypeID BadClockBlockingPage::kTypeForTesting = |
171 &BadClockBlockingPage::kTypeForTesting; | 45 &BadClockBlockingPage::kTypeForTesting; |
172 | 46 |
173 // Note that we always create a navigation entry with SSL errors. | 47 // Note that we always create a navigation entry with SSL errors. |
174 // No error happening loading a sub-resource triggers an interstitial so far. | 48 // No error happening loading a sub-resource triggers an interstitial so far. |
175 // Creating an interstitial without showing (e.g. from chrome://interstitials) | 49 // Creating an interstitial without showing (e.g. from chrome://interstitials) |
176 // it leaks memory, so don't create it here. | 50 // it leaks memory, so don't create it here. |
177 BadClockBlockingPage::BadClockBlockingPage( | 51 BadClockBlockingPage::BadClockBlockingPage( |
178 content::WebContents* web_contents, | 52 content::WebContents* web_contents, |
179 int cert_error, | 53 int cert_error, |
180 const net::SSLInfo& ssl_info, | 54 const net::SSLInfo& ssl_info, |
181 const GURL& request_url, | 55 const GURL& request_url, |
182 const base::Time& time_triggered, | 56 const base::Time& time_triggered, |
183 scoped_ptr<SSLCertReporter> ssl_cert_reporter, | 57 scoped_ptr<SSLCertReporter> ssl_cert_reporter, |
184 const base::Callback<void(bool)>& callback) | 58 const base::Callback<void(bool)>& callback) |
185 : SecurityInterstitialPage(web_contents, request_url), | 59 : SecurityInterstitialPage(web_contents, request_url), |
186 callback_(callback), | 60 callback_(callback), |
187 cert_error_(cert_error), | 61 cert_error_(cert_error), |
188 ssl_info_(ssl_info), | 62 ssl_info_(ssl_info), |
189 time_triggered_(time_triggered) { | 63 time_triggered_(time_triggered), |
| 64 controller_(new ChromeControllerClient(web_contents)) { |
| 65 // Get the language for the BadClockUI. |
| 66 std::string languages; |
| 67 Profile* profile = |
| 68 Profile::FromBrowserContext(web_contents->GetBrowserContext()); |
| 69 if (profile) |
| 70 languages = profile->GetPrefs()->GetString(prefs::kAcceptLanguages); |
| 71 |
| 72 // Set up the metrics helper for the BadClockUI. |
190 security_interstitials::MetricsHelper::ReportDetails reporting_info; | 73 security_interstitials::MetricsHelper::ReportDetails reporting_info; |
191 reporting_info.metric_prefix = kMetricsName; | 74 reporting_info.metric_prefix = kMetricsName; |
192 scoped_ptr<ChromeMetricsHelper> chrome_metrics_helper(new ChromeMetricsHelper( | 75 ChromeMetricsHelper* chrome_metrics_helper = new ChromeMetricsHelper( |
193 web_contents, request_url, reporting_info, kMetricsName)); | 76 web_contents, request_url, reporting_info, kMetricsName); |
194 chrome_metrics_helper->StartRecordingCaptivePortalMetrics(false); | 77 chrome_metrics_helper->StartRecordingCaptivePortalMetrics(false); |
195 set_metrics_helper(chrome_metrics_helper.Pass()); | 78 scoped_ptr<security_interstitials::MetricsHelper> metrics_helper( |
196 metrics_helper()->RecordUserInteraction( | 79 chrome_metrics_helper); |
197 security_interstitials::MetricsHelper::TOTAL_VISITS); | 80 controller_->set_metrics_helper(metrics_helper.Pass()); |
198 | 81 |
199 cert_report_helper_.reset(new CertReportHelper( | 82 cert_report_helper_.reset(new CertReportHelper( |
200 ssl_cert_reporter.Pass(), web_contents, request_url, ssl_info, | 83 ssl_cert_reporter.Pass(), web_contents, request_url, ssl_info, |
201 certificate_reporting::ErrorReport::INTERSTITIAL_CLOCK, | 84 certificate_reporting::ErrorReport::INTERSTITIAL_CLOCK, |
202 false /* overridable */, metrics_helper())); | 85 false /* overridable */, controller_->metrics_helper())); |
203 | 86 |
204 // TODO(felt): Separate the clock statistics from the main ssl statistics. | 87 bad_clock_ui_.reset(new security_interstitials::BadClockUI( |
205 ssl_errors::RecordUMAStatistics(false, time_triggered_, request_url, | 88 request_url, cert_error, ssl_info, time_triggered, languages, |
206 cert_error_, *ssl_info_.cert.get()); | 89 controller_.get())); |
| 90 } |
| 91 |
| 92 BadClockBlockingPage::~BadClockBlockingPage() { |
| 93 if (!callback_.is_null()) { |
| 94 // Deny when the page is closed. |
| 95 NotifyDenyCertificate(); |
| 96 } |
207 } | 97 } |
208 | 98 |
209 bool BadClockBlockingPage::ShouldCreateNewNavigation() const { | 99 bool BadClockBlockingPage::ShouldCreateNewNavigation() const { |
210 return true; | 100 return true; |
211 } | 101 } |
212 | 102 |
213 InterstitialPageDelegate::TypeID BadClockBlockingPage::GetTypeForTesting() | 103 InterstitialPageDelegate::TypeID BadClockBlockingPage::GetTypeForTesting() |
214 const { | 104 const { |
215 return BadClockBlockingPage::kTypeForTesting; | 105 return BadClockBlockingPage::kTypeForTesting; |
216 } | 106 } |
217 | 107 |
218 BadClockBlockingPage::~BadClockBlockingPage() { | 108 void BadClockBlockingPage::AfterShow() { |
219 metrics_helper()->RecordShutdownMetrics(); | 109 controller_->set_interstitial_page(interstitial_page()); |
220 if (!callback_.is_null()) { | |
221 // Deny when the page is closed. | |
222 NotifyDenyCertificate(); | |
223 } | |
224 } | 110 } |
225 | 111 |
226 void BadClockBlockingPage::PopulateInterstitialStrings( | 112 void BadClockBlockingPage::PopulateInterstitialStrings( |
227 base::DictionaryValue* load_time_data) { | 113 base::DictionaryValue* load_time_data) { |
228 CHECK(load_time_data); | 114 bad_clock_ui_->PopulateStringsForHTML(load_time_data); |
229 base::string16 url(GetFormattedHostName()); | |
230 | |
231 // Values that are currently still shared with the SSL interstitial. | |
232 load_time_data->SetString("type", "SSL"); | |
233 load_time_data->SetString("errorCode", net::ErrorToString(cert_error_)); | |
234 load_time_data->SetString( | |
235 "openDetails", l10n_util::GetStringUTF16(IDS_SSL_OPEN_DETAILS_BUTTON)); | |
236 load_time_data->SetString( | |
237 "closeDetails", | |
238 l10n_util::GetStringUTF16(IDS_SSL_CLOSE_DETAILS_BUTTON)); | |
239 | |
240 // Strings for the bad clock warning specifically. | |
241 load_time_data->SetBoolean("bad_clock", true); | |
242 load_time_data->SetBoolean("overridable", false); | |
243 #if defined(OS_IOS) | |
244 load_time_data->SetBoolean("hide_primary_button", true); | |
245 #else | |
246 load_time_data->SetBoolean("hide_primary_button", false); | |
247 #endif | |
248 | |
249 int heading_string = ssl_errors::IsUserClockInTheFuture(time_triggered_) | |
250 ? IDS_CLOCK_ERROR_AHEAD_HEADING | |
251 : IDS_CLOCK_ERROR_BEHIND_HEADING; | |
252 | |
253 load_time_data->SetString("tabTitle", | |
254 l10n_util::GetStringUTF16(IDS_CLOCK_ERROR_TITLE)); | |
255 load_time_data->SetString("heading", | |
256 l10n_util::GetStringUTF16(heading_string)); | |
257 load_time_data->SetString( | |
258 "primaryParagraph", | |
259 l10n_util::GetStringFUTF16( | |
260 IDS_CLOCK_ERROR_PRIMARY_PARAGRAPH, url, | |
261 base::TimeFormatFriendlyDateAndTime(time_triggered_))); | |
262 | |
263 load_time_data->SetString( | |
264 "primaryButtonText", | |
265 l10n_util::GetStringUTF16(IDS_CLOCK_ERROR_UPDATE_DATE_AND_TIME)); | |
266 load_time_data->SetString( | |
267 "explanationParagraph", | |
268 l10n_util::GetStringUTF16(IDS_CLOCK_ERROR_EXPLANATION)); | |
269 | |
270 // The interstitial template expects this string, but we're not using it. | |
271 load_time_data->SetString("finalParagraph", std::string()); | |
272 | |
273 // Set debugging information at the bottom of the warning. | |
274 load_time_data->SetString("subject", | |
275 ssl_info_.cert->subject().GetDisplayName()); | |
276 load_time_data->SetString("issuer", | |
277 ssl_info_.cert->issuer().GetDisplayName()); | |
278 load_time_data->SetString( | |
279 "expirationDate", | |
280 base::TimeFormatShortDate(ssl_info_.cert->valid_expiry())); | |
281 load_time_data->SetString("currentDate", | |
282 base::TimeFormatShortDate(time_triggered_)); | |
283 std::vector<std::string> encoded_chain; | |
284 ssl_info_.cert->GetPEMEncodedChain(&encoded_chain); | |
285 load_time_data->SetString( | |
286 "pem", base::JoinString(encoded_chain, base::StringPiece())); | |
287 | |
288 cert_report_helper_->PopulateExtendedReportingOption(load_time_data); | 115 cert_report_helper_->PopulateExtendedReportingOption(load_time_data); |
289 } | 116 } |
290 | 117 |
291 void BadClockBlockingPage::OverrideEntry(NavigationEntry* entry) { | 118 void BadClockBlockingPage::OverrideEntry(NavigationEntry* entry) { |
292 const int process_id = web_contents()->GetRenderProcessHost()->GetID(); | 119 const int process_id = web_contents()->GetRenderProcessHost()->GetID(); |
293 const int cert_id = content::CertStore::GetInstance()->StoreCert( | 120 const int cert_id = content::CertStore::GetInstance()->StoreCert( |
294 ssl_info_.cert.get(), process_id); | 121 ssl_info_.cert.get(), process_id); |
295 DCHECK(cert_id); | 122 DCHECK(cert_id); |
296 | 123 |
297 content::SignedCertificateTimestampStore* sct_store( | 124 content::SignedCertificateTimestampStore* sct_store( |
(...skipping 10 matching lines...) Expand all Loading... |
308 content::SSLStatus(content::SECURITY_STYLE_AUTHENTICATION_BROKEN, cert_id, | 135 content::SSLStatus(content::SECURITY_STYLE_AUTHENTICATION_BROKEN, cert_id, |
309 sct_ids, ssl_info_); | 136 sct_ids, ssl_info_); |
310 } | 137 } |
311 | 138 |
312 void BadClockBlockingPage::SetSSLCertReporterForTesting( | 139 void BadClockBlockingPage::SetSSLCertReporterForTesting( |
313 scoped_ptr<SSLCertReporter> ssl_cert_reporter) { | 140 scoped_ptr<SSLCertReporter> ssl_cert_reporter) { |
314 cert_report_helper_->SetSSLCertReporterForTesting(ssl_cert_reporter.Pass()); | 141 cert_report_helper_->SetSSLCertReporterForTesting(ssl_cert_reporter.Pass()); |
315 } | 142 } |
316 | 143 |
317 // This handles the commands sent from the interstitial JavaScript. | 144 // This handles the commands sent from the interstitial JavaScript. |
318 // DO NOT reorder or change this logic without also changing the JavaScript! | |
319 void BadClockBlockingPage::CommandReceived(const std::string& command) { | 145 void BadClockBlockingPage::CommandReceived(const std::string& command) { |
320 if (command == "\"pageLoadComplete\"") { | 146 if (command == "\"pageLoadComplete\"") { |
321 // content::WaitForRenderFrameReady sends this message when the page | 147 // content::WaitForRenderFrameReady sends this message when the page |
322 // load completes. Ignore it. | 148 // load completes. Ignore it. |
323 return; | 149 return; |
324 } | 150 } |
325 | 151 |
326 int cmd = 0; | 152 int cmd = 0; |
327 bool retval = base::StringToInt(command, &cmd); | 153 bool retval = base::StringToInt(command, &cmd); |
328 DCHECK(retval); | 154 DCHECK(retval); |
329 switch (cmd) { | 155 |
330 case security_interstitials::CMD_DONT_PROCEED: | 156 bad_clock_ui_->HandleCommand( |
331 interstitial_page()->DontProceed(); | 157 static_cast<security_interstitials::SecurityInterstitialCommands>(cmd)); |
332 break; | |
333 case security_interstitials::CMD_DO_REPORT: | |
334 SetReportingPreference(true); | |
335 break; | |
336 case security_interstitials::CMD_DONT_REPORT: | |
337 SetReportingPreference(false); | |
338 break; | |
339 case security_interstitials::CMD_SHOW_MORE_SECTION: | |
340 metrics_helper()->RecordUserInteraction( | |
341 security_interstitials::MetricsHelper::SHOW_ADVANCED); | |
342 break; | |
343 case security_interstitials::CMD_OPEN_DATE_SETTINGS: | |
344 metrics_helper()->RecordUserInteraction( | |
345 security_interstitials::MetricsHelper::OPEN_TIME_SETTINGS); | |
346 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE, | |
347 base::Bind(&LaunchDateAndTimeSettings)); | |
348 break; | |
349 case security_interstitials::CMD_OPEN_REPORTING_PRIVACY: | |
350 OpenExtendedReportingPrivacyPolicy(); | |
351 break; | |
352 case security_interstitials::CMD_PROCEED: | |
353 case security_interstitials::CMD_OPEN_HELP_CENTER: | |
354 case security_interstitials::CMD_RELOAD: | |
355 case security_interstitials::CMD_OPEN_DIAGNOSTIC: | |
356 // Not supported for the bad clock interstitial. | |
357 NOTREACHED() << "Unexpected command: " << command; | |
358 } | |
359 } | 158 } |
360 | 159 |
361 void BadClockBlockingPage::OverrideRendererPrefs( | 160 void BadClockBlockingPage::OverrideRendererPrefs( |
362 content::RendererPreferences* prefs) { | 161 content::RendererPreferences* prefs) { |
363 Profile* profile = | 162 Profile* profile = |
364 Profile::FromBrowserContext(web_contents()->GetBrowserContext()); | 163 Profile::FromBrowserContext(web_contents()->GetBrowserContext()); |
365 renderer_preferences_util::UpdateFromSystemSettings(prefs, profile, | 164 renderer_preferences_util::UpdateFromSystemSettings(prefs, profile, |
366 web_contents()); | 165 web_contents()); |
367 } | 166 } |
368 | 167 |
369 void BadClockBlockingPage::OnDontProceed() { | 168 void BadClockBlockingPage::OnDontProceed() { |
370 cert_report_helper_->FinishCertCollection( | 169 cert_report_helper_->FinishCertCollection( |
371 certificate_reporting::ErrorReport::USER_DID_NOT_PROCEED); | 170 certificate_reporting::ErrorReport::USER_DID_NOT_PROCEED); |
372 NotifyDenyCertificate(); | 171 NotifyDenyCertificate(); |
373 } | 172 } |
374 | 173 |
375 void BadClockBlockingPage::NotifyDenyCertificate() { | 174 void BadClockBlockingPage::NotifyDenyCertificate() { |
376 // It's possible that callback_ may not exist if the user clicks "Proceed" | 175 // It's possible that callback_ may not exist if the user clicks "Proceed" |
377 // followed by pressing the back button before the interstitial is hidden. | 176 // followed by pressing the back button before the interstitial is hidden. |
378 // In that case the certificate will still be treated as allowed. | 177 // In that case the certificate will still be treated as allowed. |
379 if (callback_.is_null()) | 178 if (callback_.is_null()) |
380 return; | 179 return; |
381 | 180 |
382 base::ResetAndReturn(&callback_).Run(false); | 181 base::ResetAndReturn(&callback_).Run(false); |
383 } | 182 } |
OLD | NEW |