Update mojo surfaces bindings and mojo/cc/ glue
[chromium-blink-merge.git] / chrome / browser / safe_browsing / safe_browsing_blocking_page.cc
blobf1c4a72bcb5bfeab39398343018657dd8b084e84
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 // Implementation of the SafeBrowsingBlockingPage class.
7 #include "chrome/browser/safe_browsing/safe_browsing_blocking_page.h"
9 #include <string>
11 #include "base/bind.h"
12 #include "base/command_line.h"
13 #include "base/i18n/rtl.h"
14 #include "base/lazy_instance.h"
15 #include "base/metrics/field_trial.h"
16 #include "base/metrics/histogram.h"
17 #include "base/prefs/pref_service.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "base/strings/string_piece.h"
20 #include "base/strings/stringprintf.h"
21 #include "base/strings/utf_string_conversions.h"
22 #include "base/time/time.h"
23 #include "base/values.h"
24 #include "chrome/browser/browser_process.h"
25 #include "chrome/browser/history/history_service_factory.h"
26 #include "chrome/browser/profiles/profile.h"
27 #include "chrome/browser/renderer_preferences_util.h"
28 #include "chrome/browser/safe_browsing/malware_details.h"
29 #include "chrome/browser/safe_browsing/ui_manager.h"
30 #include "chrome/browser/tab_contents/tab_util.h"
31 #include "chrome/common/chrome_switches.h"
32 #include "chrome/common/pref_names.h"
33 #include "chrome/common/url_constants.h"
34 #include "chrome/grit/generated_resources.h"
35 #include "components/google/core/browser/google_util.h"
36 #include "content/public/browser/browser_thread.h"
37 #include "content/public/browser/interstitial_page.h"
38 #include "content/public/browser/navigation_controller.h"
39 #include "content/public/browser/user_metrics.h"
40 #include "content/public/browser/web_contents.h"
41 #include "grit/browser_resources.h"
42 #include "grit/locale_settings.h"
43 #include "net/base/escape.h"
44 #include "ui/base/l10n/l10n_util.h"
45 #include "ui/base/resource/resource_bundle.h"
46 #include "ui/base/webui/jstemplate_builder.h"
47 #include "ui/base/webui/web_ui_util.h"
49 #if defined(ENABLE_EXTENSIONS)
50 #include "chrome/browser/extensions/api/experience_sampling_private/experience_sampling.h"
51 #endif
53 using base::UserMetricsAction;
54 using content::BrowserThread;
55 using content::InterstitialPage;
56 using content::OpenURLParams;
57 using content::Referrer;
58 using content::WebContents;
60 #if defined(ENABLE_EXTENSIONS)
61 using extensions::ExperienceSamplingEvent;
62 #endif
64 namespace {
66 // For malware interstitial pages, we link the problematic URL to Google's
67 // diagnostic page.
68 #if defined(GOOGLE_CHROME_BUILD)
69 const char* const kSbDiagnosticUrl =
70 "http://safebrowsing.clients.google.com/safebrowsing/diagnostic?site=%s&client=googlechrome";
71 #else
72 const char* const kSbDiagnosticUrl =
73 "http://safebrowsing.clients.google.com/safebrowsing/diagnostic?site=%s&client=chromium";
74 #endif
76 const char kSbReportPhishingErrorUrl[] =
77 "http://www.google.com/safebrowsing/report_error/";
79 // URL for malware and phishing, V2.
80 const char kLearnMoreMalwareUrlV2[] =
81 "https://www.google.com/transparencyreport/safebrowsing/";
82 const char kLearnMorePhishingUrlV2[] =
83 "https://www.google.com/transparencyreport/safebrowsing/";
85 const char kPrivacyLinkHtml[] =
86 "<a id=\"privacy-link\" href=\"\" onclick=\"sendCommand('showPrivacy'); "
87 "return false;\" onmousedown=\"return false;\">%s</a>";
89 // After a malware interstitial where the user opted-in to the report
90 // but clicked "proceed anyway", we delay the call to
91 // MalwareDetails::FinishCollection() by this much time (in
92 // milliseconds).
93 const int64 kMalwareDetailsProceedDelayMilliSeconds = 3000;
95 // The commands returned by the page when the user performs an action.
96 const char kDoReportCommand[] = "doReport";
97 const char kDontReportCommand[] = "dontReport";
98 const char kExpandedSeeMoreCommand[] = "expandedSeeMore";
99 const char kLearnMoreCommand[] = "learnMore2";
100 const char kProceedCommand[] = "proceed";
101 const char kReportErrorCommand[] = "reportError";
102 const char kShowDiagnosticCommand[] = "showDiagnostic";
103 const char kShowPrivacyCommand[] = "showPrivacy";
104 const char kTakeMeBackCommand[] = "takeMeBack";
105 // Special command that we use when the user navigated away from the
106 // page. E.g., closed the tab or the window. This is only used by
107 // RecordUserReactionTime.
108 const char kNavigatedAwayMetaCommand[] = "closed";
110 // Other constants used to communicate with the JavaScript.
111 const char kBoxChecked[] = "boxchecked";
112 const char kDisplayCheckBox[] = "displaycheckbox";
114 // Constants for the Experience Sampling instrumentation.
115 #if defined(ENABLE_EXTENSIONS)
116 const char kEventNameMalware[] = "safebrowsing_interstitial_";
117 const char kEventNamePhishing[] = "phishing_interstitial_";
118 const char kEventNameMalwareAndPhishing[] =
119 "malware_and_phishing_interstitial_";
120 const char kEventNameOther[] = "safebrowsing_other_interstitial_";
121 #endif
123 base::LazyInstance<SafeBrowsingBlockingPage::UnsafeResourceMap>
124 g_unsafe_resource_map = LAZY_INSTANCE_INITIALIZER;
126 // This enum is used for a histogram. Don't reorder, delete, or insert
127 // elements. New elements should be added before MAX_ACTION only.
128 enum DetailedDecision {
129 MALWARE_SHOW_NEW_SITE = 0,
130 MALWARE_PROCEED_NEW_SITE,
131 MALWARE_SHOW_CROSS_SITE,
132 MALWARE_PROCEED_CROSS_SITE,
133 PHISHING_SHOW_NEW_SITE,
134 PHISHING_PROCEED_NEW_SITE,
135 PHISHING_SHOW_CROSS_SITE,
136 PHISHING_PROCEED_CROSS_SITE,
137 MAX_DETAILED_ACTION
140 void RecordDetailedUserAction(DetailedDecision decision) {
141 UMA_HISTOGRAM_ENUMERATION("SB2.InterstitialActionDetails",
142 decision,
143 MAX_DETAILED_ACTION);
146 } // namespace
148 // static
149 SafeBrowsingBlockingPageFactory* SafeBrowsingBlockingPage::factory_ = NULL;
151 // The default SafeBrowsingBlockingPageFactory. Global, made a singleton so we
152 // don't leak it.
153 class SafeBrowsingBlockingPageFactoryImpl
154 : public SafeBrowsingBlockingPageFactory {
155 public:
156 virtual SafeBrowsingBlockingPage* CreateSafeBrowsingPage(
157 SafeBrowsingUIManager* ui_manager,
158 WebContents* web_contents,
159 const SafeBrowsingBlockingPage::UnsafeResourceList& unsafe_resources)
160 OVERRIDE {
161 return new SafeBrowsingBlockingPage(ui_manager, web_contents,
162 unsafe_resources);
165 private:
166 friend struct base::DefaultLazyInstanceTraits<
167 SafeBrowsingBlockingPageFactoryImpl>;
169 SafeBrowsingBlockingPageFactoryImpl() { }
171 DISALLOW_COPY_AND_ASSIGN(SafeBrowsingBlockingPageFactoryImpl);
174 static base::LazyInstance<SafeBrowsingBlockingPageFactoryImpl>
175 g_safe_browsing_blocking_page_factory_impl = LAZY_INSTANCE_INITIALIZER;
177 SafeBrowsingBlockingPage::SafeBrowsingBlockingPage(
178 SafeBrowsingUIManager* ui_manager,
179 WebContents* web_contents,
180 const UnsafeResourceList& unsafe_resources)
181 : malware_details_proceed_delay_ms_(
182 kMalwareDetailsProceedDelayMilliSeconds),
183 ui_manager_(ui_manager),
184 report_loop_(NULL),
185 is_main_frame_load_blocked_(IsMainPageLoadBlocked(unsafe_resources)),
186 unsafe_resources_(unsafe_resources),
187 proceeded_(false),
188 web_contents_(web_contents),
189 url_(unsafe_resources[0].url),
190 interstitial_page_(NULL),
191 has_expanded_see_more_section_(false),
192 reporting_checkbox_checked_(false),
193 create_view_(true),
194 num_visits_(-1) {
195 bool malware = false;
196 bool phishing = false;
197 for (UnsafeResourceList::const_iterator iter = unsafe_resources_.begin();
198 iter != unsafe_resources_.end(); ++iter) {
199 const UnsafeResource& resource = *iter;
200 SBThreatType threat_type = resource.threat_type;
201 if (threat_type == SB_THREAT_TYPE_URL_MALWARE ||
202 threat_type == SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL) {
203 malware = true;
204 } else {
205 DCHECK(threat_type == SB_THREAT_TYPE_URL_PHISHING ||
206 threat_type == SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL);
207 phishing = true;
210 DCHECK(phishing || malware);
211 if (malware && phishing)
212 interstitial_type_ = TYPE_MALWARE_AND_PHISHING;
213 else if (malware)
214 interstitial_type_ = TYPE_MALWARE;
215 else
216 interstitial_type_ = TYPE_PHISHING;
218 RecordUserAction(SHOW);
219 HistoryService* history_service = HistoryServiceFactory::GetForProfile(
220 Profile::FromBrowserContext(web_contents->GetBrowserContext()),
221 Profile::EXPLICIT_ACCESS);
222 if (history_service) {
223 history_service->GetVisibleVisitCountToHost(
224 url_,
225 base::Bind(&SafeBrowsingBlockingPage::OnGotHistoryCount,
226 base::Unretained(this)),
227 &request_tracker_);
230 if (!is_main_frame_load_blocked_) {
231 navigation_entry_index_to_remove_ =
232 web_contents->GetController().GetLastCommittedEntryIndex();
233 } else {
234 navigation_entry_index_to_remove_ = -1;
237 // Start computing malware details. They will be sent only
238 // if the user opts-in on the blocking page later.
239 // If there's more than one malicious resources, it means the user
240 // clicked through the first warning, so we don't prepare additional
241 // reports.
242 if (unsafe_resources.size() == 1 &&
243 unsafe_resources[0].threat_type == SB_THREAT_TYPE_URL_MALWARE &&
244 malware_details_.get() == NULL && CanShowMalwareDetailsOption()) {
245 malware_details_ = MalwareDetails::NewMalwareDetails(
246 ui_manager_, web_contents, unsafe_resources[0]);
249 #if defined(ENABLE_EXTENSIONS)
250 // ExperienceSampling: Set up new sampling event for this interstitial.
251 // This needs to handle all types of warnings this interstitial can show.
252 std::string event_name;
253 switch (interstitial_type_) {
254 case TYPE_MALWARE_AND_PHISHING:
255 event_name = kEventNameMalwareAndPhishing;
256 break;
257 case TYPE_MALWARE:
258 event_name = kEventNameMalware;
259 break;
260 case TYPE_PHISHING:
261 event_name = kEventNamePhishing;
262 break;
263 default:
264 event_name = kEventNameOther;
265 break;
267 sampling_event_.reset(new ExperienceSamplingEvent(
268 event_name,
269 url_,
270 web_contents_->GetLastCommittedURL(),
271 web_contents_->GetBrowserContext()));
272 #endif
274 // Creating interstitial_page_ without showing it leaks memory, so don't
275 // create it here.
278 bool SafeBrowsingBlockingPage::CanShowMalwareDetailsOption() {
279 return (!web_contents_->GetBrowserContext()->IsOffTheRecord() &&
280 web_contents_->GetURL().SchemeIs(url::kHttpScheme));
283 SafeBrowsingBlockingPage::~SafeBrowsingBlockingPage() {
286 void SafeBrowsingBlockingPage::CommandReceived(const std::string& cmd) {
287 std::string command(cmd); // Make a local copy so we can modify it.
288 // The Jasonified response has quotes, remove them.
289 if (command.length() > 1 && command[0] == '"') {
290 command = command.substr(1, command.length() - 2);
292 RecordUserReactionTime(command);
293 if (command == kDoReportCommand) {
294 SetReportingPreference(true);
295 return;
298 if (command == kDontReportCommand) {
299 SetReportingPreference(false);
300 return;
303 if (command == kLearnMoreCommand) {
304 // User pressed "Learn more".
305 GURL url(interstitial_type_ == TYPE_PHISHING ?
306 kLearnMorePhishingUrlV2 : kLearnMoreMalwareUrlV2);
307 #if defined(ENABLE_EXTENSIONS)
308 if (sampling_event_.get())
309 sampling_event_->set_has_viewed_learn_more(true);
310 #endif
311 OpenURLParams params(
312 url, Referrer(), CURRENT_TAB, content::PAGE_TRANSITION_LINK, false);
313 web_contents_->OpenURL(params);
314 return;
317 if (command == kShowPrivacyCommand) {
318 // User pressed "Safe Browsing privacy policy".
319 GURL url(l10n_util::GetStringUTF8(IDS_SAFE_BROWSING_PRIVACY_POLICY_URL));
320 OpenURLParams params(
321 url, Referrer(), CURRENT_TAB, content::PAGE_TRANSITION_LINK, false);
322 web_contents_->OpenURL(params);
323 return;
326 bool proceed_blocked = false;
327 if (command == kProceedCommand) {
328 if (IsPrefEnabled(prefs::kSafeBrowsingProceedAnywayDisabled)) {
329 proceed_blocked = true;
330 } else {
331 interstitial_page_->Proceed();
332 // |this| has been deleted after Proceed() returns.
333 return;
337 if (command == kTakeMeBackCommand || proceed_blocked) {
338 if (is_main_frame_load_blocked_) {
339 // If the load is blocked, we want to close the interstitial and discard
340 // the pending entry.
341 interstitial_page_->DontProceed();
342 // |this| has been deleted after DontProceed() returns.
343 return;
346 // Otherwise the offending entry has committed, and we need to go back or
347 // to a safe page. We will close the interstitial when that page commits.
348 if (web_contents_->GetController().CanGoBack()) {
349 web_contents_->GetController().GoBack();
350 } else {
351 web_contents_->GetController().LoadURL(
352 GURL(chrome::kChromeUINewTabURL),
353 content::Referrer(),
354 content::PAGE_TRANSITION_AUTO_TOPLEVEL,
355 std::string());
357 return;
360 // The "report error" and "show diagnostic" commands can have a number
361 // appended to them, which is the index of the element they apply to.
362 size_t element_index = 0;
363 size_t colon_index = command.find(':');
364 if (colon_index != std::string::npos) {
365 DCHECK(colon_index < command.size() - 1);
366 int result_int = 0;
367 bool result = base::StringToInt(base::StringPiece(command.begin() +
368 colon_index + 1,
369 command.end()),
370 &result_int);
371 command = command.substr(0, colon_index);
372 if (result)
373 element_index = static_cast<size_t>(result_int);
376 if (element_index >= unsafe_resources_.size()) {
377 NOTREACHED();
378 return;
381 std::string bad_url_spec = unsafe_resources_[element_index].url.spec();
382 if (command == kReportErrorCommand) {
383 // User pressed "Report error" for a phishing site.
384 // Note that we cannot just put a link in the interstitial at this point.
385 // It is not OK to navigate in the context of an interstitial page.
386 SBThreatType threat_type = unsafe_resources_[element_index].threat_type;
387 DCHECK(threat_type == SB_THREAT_TYPE_URL_PHISHING ||
388 threat_type == SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL);
389 GURL report_url =
390 safe_browsing_util::GeneratePhishingReportUrl(
391 kSbReportPhishingErrorUrl,
392 bad_url_spec,
393 threat_type == SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL);
394 OpenURLParams params(
395 report_url, Referrer(), CURRENT_TAB, content::PAGE_TRANSITION_LINK,
396 false);
397 web_contents_->OpenURL(params);
398 return;
401 if (command == kShowDiagnosticCommand) {
402 // We're going to take the user to Google's SafeBrowsing diagnostic page.
403 std::string diagnostic =
404 base::StringPrintf(kSbDiagnosticUrl,
405 net::EscapeQueryParamValue(bad_url_spec, true).c_str());
406 GURL diagnostic_url(diagnostic);
407 diagnostic_url = google_util::AppendGoogleLocaleParam(
408 diagnostic_url, g_browser_process->GetApplicationLocale());
409 DCHECK(unsafe_resources_[element_index].threat_type ==
410 SB_THREAT_TYPE_URL_MALWARE ||
411 unsafe_resources_[element_index].threat_type ==
412 SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL);
413 OpenURLParams params(
414 diagnostic_url, Referrer(), CURRENT_TAB, content::PAGE_TRANSITION_LINK,
415 false);
416 web_contents_->OpenURL(params);
417 return;
420 if (command == kExpandedSeeMoreCommand) {
421 // User expanded the "see more info" section of the page. We don't actually
422 // do any action based on this, it's just so that RecordUserReactionTime can
423 // track it.
425 #if defined(ENABLE_EXTENSIONS)
426 // ExperienceSampling: We track that the user expanded the details.
427 if (sampling_event_.get())
428 sampling_event_->set_has_viewed_details(true);
429 #endif
430 return;
433 NOTREACHED() << "Unexpected command: " << command;
436 void SafeBrowsingBlockingPage::OverrideRendererPrefs(
437 content::RendererPreferences* prefs) {
438 Profile* profile = Profile::FromBrowserContext(
439 web_contents_->GetBrowserContext());
440 renderer_preferences_util::UpdateFromSystemSettings(prefs, profile);
443 void SafeBrowsingBlockingPage::SetReportingPreference(bool report) {
444 Profile* profile = Profile::FromBrowserContext(
445 web_contents_->GetBrowserContext());
446 PrefService* pref = profile->GetPrefs();
447 pref->SetBoolean(prefs::kSafeBrowsingExtendedReportingEnabled, report);
448 UMA_HISTOGRAM_BOOLEAN("SB2.SetExtendedReportingEnabled", report);
449 reporting_checkbox_checked_ = report;
450 pref->ClearPref(prefs::kSafeBrowsingReportingEnabled);
451 pref->ClearPref(prefs::kSafeBrowsingDownloadFeedbackEnabled);
454 // If the reporting checkbox was left checked on close, the new pref
455 // kSafeBrowsingExtendedReportingEnabled should be updated.
456 // TODO(felt): Remove this in M-39. crbug.com/384668
457 void SafeBrowsingBlockingPage::UpdateReportingPref() {
458 if (!reporting_checkbox_checked_)
459 return;
460 if (IsPrefEnabled(prefs::kSafeBrowsingExtendedReportingEnabled))
461 return;
462 Profile* profile = Profile::FromBrowserContext(
463 web_contents_->GetBrowserContext());
464 if (profile->GetPrefs()->HasPrefPath(
465 prefs::kSafeBrowsingExtendedReportingEnabled))
466 return;
467 SetReportingPreference(true);
470 void SafeBrowsingBlockingPage::OnProceed() {
471 proceeded_ = true;
472 RecordUserAction(PROCEED);
473 UpdateReportingPref();
474 // Send the malware details, if we opted to.
475 FinishMalwareDetails(malware_details_proceed_delay_ms_);
477 NotifySafeBrowsingUIManager(ui_manager_, unsafe_resources_, true);
479 // Check to see if some new notifications of unsafe resources have been
480 // received while we were showing the interstitial.
481 UnsafeResourceMap* unsafe_resource_map = GetUnsafeResourcesMap();
482 UnsafeResourceMap::iterator iter = unsafe_resource_map->find(web_contents_);
483 SafeBrowsingBlockingPage* blocking_page = NULL;
484 if (iter != unsafe_resource_map->end() && !iter->second.empty()) {
485 // Build an interstitial for all the unsafe resources notifications.
486 // Don't show it now as showing an interstitial while an interstitial is
487 // already showing would cause DontProceed() to be invoked.
488 blocking_page = factory_->CreateSafeBrowsingPage(ui_manager_, web_contents_,
489 iter->second);
490 unsafe_resource_map->erase(iter);
493 #if defined(ENABLE_EXTENSIONS)
494 // ExperienceSampling: Notify that user decided to proceed.
495 if (sampling_event_.get())
496 sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kProceed);
497 #endif
499 // Now that this interstitial is gone, we can show the new one.
500 if (blocking_page)
501 blocking_page->Show();
504 void SafeBrowsingBlockingPage::DontCreateViewForTesting() {
505 create_view_ = false;
508 void SafeBrowsingBlockingPage::Show() {
509 DCHECK(!interstitial_page_);
510 interstitial_page_ = InterstitialPage::Create(
511 web_contents_, is_main_frame_load_blocked_, url_, this);
512 if (!create_view_)
513 interstitial_page_->DontCreateViewForTesting();
514 interstitial_page_->Show();
517 void SafeBrowsingBlockingPage::OnDontProceed() {
518 // Calling this method twice will not double-count.
519 RecordUserReactionTime(kNavigatedAwayMetaCommand);
520 // We could have already called Proceed(), in which case we must not notify
521 // the SafeBrowsingUIManager again, as the client has been deleted.
522 if (proceeded_)
523 return;
525 RecordUserAction(DONT_PROCEED);
526 UpdateReportingPref();
527 // Send the malware details, if we opted to.
528 FinishMalwareDetails(0); // No delay
530 NotifySafeBrowsingUIManager(ui_manager_, unsafe_resources_, false);
532 // The user does not want to proceed, clear the queued unsafe resources
533 // notifications we received while the interstitial was showing.
534 UnsafeResourceMap* unsafe_resource_map = GetUnsafeResourcesMap();
535 UnsafeResourceMap::iterator iter = unsafe_resource_map->find(web_contents_);
536 if (iter != unsafe_resource_map->end() && !iter->second.empty()) {
537 NotifySafeBrowsingUIManager(ui_manager_, iter->second, false);
538 unsafe_resource_map->erase(iter);
541 // We don't remove the navigation entry if the tab is being destroyed as this
542 // would trigger a navigation that would cause trouble as the render view host
543 // for the tab has by then already been destroyed. We also don't delete the
544 // current entry if it has been committed again, which is possible on a page
545 // that had a subresource warning.
546 int last_committed_index =
547 web_contents_->GetController().GetLastCommittedEntryIndex();
548 if (navigation_entry_index_to_remove_ != -1 &&
549 navigation_entry_index_to_remove_ != last_committed_index &&
550 !web_contents_->IsBeingDestroyed()) {
551 CHECK(web_contents_->GetController().RemoveEntryAtIndex(
552 navigation_entry_index_to_remove_));
553 navigation_entry_index_to_remove_ = -1;
556 #if defined(ENABLE_EXTENSIONS)
557 // ExperienceSampling: Notify that user decided to go back.
558 // This also occurs if the user navigates away or closes the tab.
559 if (sampling_event_.get())
560 sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kDeny);
561 #endif
564 void SafeBrowsingBlockingPage::OnGotHistoryCount(bool success,
565 int num_visits,
566 base::Time first_visit) {
567 if (success)
568 num_visits_ = num_visits;
571 void SafeBrowsingBlockingPage::RecordUserAction(BlockingPageEvent event) {
572 // This enum is used for a histogram. Don't reorder, delete, or insert
573 // elements. New elements should be added before MAX_ACTION only.
574 enum {
575 MALWARE_SHOW = 0,
576 MALWARE_DONT_PROCEED,
577 MALWARE_FORCED_DONT_PROCEED,
578 MALWARE_PROCEED,
579 MULTIPLE_SHOW,
580 MULTIPLE_DONT_PROCEED,
581 MULTIPLE_FORCED_DONT_PROCEED,
582 MULTIPLE_PROCEED,
583 PHISHING_SHOW,
584 PHISHING_DONT_PROCEED,
585 PHISHING_FORCED_DONT_PROCEED,
586 PHISHING_PROCEED,
587 MALWARE_SHOW_ADVANCED,
588 MULTIPLE_SHOW_ADVANCED,
589 PHISHING_SHOW_ADVANCED,
590 MAX_ACTION
591 } histogram_action = MAX_ACTION;
593 switch (event) {
594 case SHOW:
595 switch (interstitial_type_) {
596 case TYPE_MALWARE_AND_PHISHING:
597 histogram_action = MULTIPLE_SHOW;
598 break;
599 case TYPE_MALWARE:
600 histogram_action = MALWARE_SHOW;
601 break;
602 case TYPE_PHISHING:
603 histogram_action = PHISHING_SHOW;
604 break;
606 break;
607 case PROCEED:
608 switch (interstitial_type_) {
609 case TYPE_MALWARE_AND_PHISHING:
610 histogram_action = MULTIPLE_PROCEED;
611 break;
612 case TYPE_MALWARE:
613 histogram_action = MALWARE_PROCEED;
614 break;
615 case TYPE_PHISHING:
616 histogram_action = PHISHING_PROCEED;
617 break;
619 break;
620 case DONT_PROCEED:
621 if (IsPrefEnabled(prefs::kSafeBrowsingProceedAnywayDisabled)) {
622 switch (interstitial_type_) {
623 case TYPE_MALWARE_AND_PHISHING:
624 histogram_action = MULTIPLE_FORCED_DONT_PROCEED;
625 break;
626 case TYPE_MALWARE:
627 histogram_action = MALWARE_FORCED_DONT_PROCEED;
628 break;
629 case TYPE_PHISHING:
630 histogram_action = PHISHING_FORCED_DONT_PROCEED;
631 break;
633 } else {
634 switch (interstitial_type_) {
635 case TYPE_MALWARE_AND_PHISHING:
636 histogram_action = MULTIPLE_DONT_PROCEED;
637 break;
638 case TYPE_MALWARE:
639 histogram_action = MALWARE_DONT_PROCEED;
640 break;
641 case TYPE_PHISHING:
642 histogram_action = PHISHING_DONT_PROCEED;
643 break;
646 break;
647 case SHOW_ADVANCED:
648 switch (interstitial_type_) {
649 case TYPE_MALWARE_AND_PHISHING:
650 histogram_action = MULTIPLE_SHOW_ADVANCED;
651 break;
652 case TYPE_MALWARE:
653 histogram_action = MALWARE_SHOW_ADVANCED;
654 break;
655 case TYPE_PHISHING:
656 histogram_action = PHISHING_SHOW_ADVANCED;
657 break;
659 break;
660 default:
661 NOTREACHED() << "Unexpected event: " << event;
663 if (histogram_action == MAX_ACTION) {
664 NOTREACHED();
665 } else {
666 UMA_HISTOGRAM_ENUMERATION("SB2.InterstitialAction", histogram_action,
667 MAX_ACTION);
670 if (event == PROCEED || event == DONT_PROCEED) {
671 if (num_visits_ == 0 && interstitial_type_ != TYPE_MALWARE_AND_PHISHING) {
672 RecordDetailedUserAction((interstitial_type_ == TYPE_MALWARE) ?
673 MALWARE_SHOW_NEW_SITE : PHISHING_SHOW_NEW_SITE);
674 if (event == PROCEED) {
675 RecordDetailedUserAction((interstitial_type_ == TYPE_MALWARE) ?
676 MALWARE_PROCEED_NEW_SITE : PHISHING_PROCEED_NEW_SITE);
679 if (unsafe_resources_[0].is_subresource &&
680 interstitial_type_ != TYPE_MALWARE_AND_PHISHING) {
681 RecordDetailedUserAction((interstitial_type_ == TYPE_MALWARE) ?
682 MALWARE_SHOW_CROSS_SITE : PHISHING_SHOW_CROSS_SITE);
683 if (event == PROCEED) {
684 RecordDetailedUserAction((interstitial_type_ == TYPE_MALWARE) ?
685 MALWARE_PROCEED_CROSS_SITE : PHISHING_PROCEED_CROSS_SITE);
691 void SafeBrowsingBlockingPage::RecordUserReactionTime(
692 const std::string& command) {
693 if (interstitial_show_time_.is_null())
694 return; // We already reported the user reaction time.
695 base::TimeDelta dt = base::TimeTicks::Now() - interstitial_show_time_;
696 DVLOG(1) << "User reaction time for command:" << command
697 << " on interstitial_type_:" << interstitial_type_
698 << " warning took " << dt.InMilliseconds() << "ms";
699 bool recorded = true;
700 if (interstitial_type_ == TYPE_MALWARE ||
701 interstitial_type_ == TYPE_MALWARE_AND_PHISHING) {
702 // There are six ways in which the malware interstitial can go
703 // away. We handle all of them here but we group two together: closing the
704 // tag / browser window and clicking on the back button in the browser (not
705 // the big green button) are considered the same action.
706 if (command == kProceedCommand) {
707 UMA_HISTOGRAM_MEDIUM_TIMES("SB2.MalwareInterstitialTimeProceed", dt);
708 } else if (command == kTakeMeBackCommand) {
709 UMA_HISTOGRAM_MEDIUM_TIMES("SB2.MalwareInterstitialTimeTakeMeBack", dt);
710 } else if (command == kShowDiagnosticCommand) {
711 UMA_HISTOGRAM_MEDIUM_TIMES("SB2.MalwareInterstitialTimeDiagnostic", dt);
712 } else if (command == kShowPrivacyCommand) {
713 UMA_HISTOGRAM_MEDIUM_TIMES("SB2.MalwareInterstitialTimePrivacyPolicy",
714 dt);
715 } else if (command == kLearnMoreCommand) {
716 UMA_HISTOGRAM_MEDIUM_TIMES("SB2.MalwareInterstitialLearnMore",
717 dt);
718 } else if (command == kNavigatedAwayMetaCommand) {
719 UMA_HISTOGRAM_MEDIUM_TIMES("SB2.MalwareInterstitialTimeClosed", dt);
720 } else if (command == kExpandedSeeMoreCommand) {
721 // Only record the expanded histogram once per display of the
722 // interstitial.
723 if (has_expanded_see_more_section_)
724 return;
725 RecordUserAction(SHOW_ADVANCED);
726 UMA_HISTOGRAM_MEDIUM_TIMES("SB2.MalwareInterstitialTimeExpandedSeeMore",
727 dt);
728 has_expanded_see_more_section_ = true;
729 // Expanding the "See More" section doesn't finish the interstitial, so
730 // don't mark the reaction time as recorded.
731 recorded = false;
732 } else {
733 recorded = false;
735 } else {
736 // Same as above but for phishing warnings.
737 if (command == kProceedCommand) {
738 UMA_HISTOGRAM_MEDIUM_TIMES("SB2.PhishingInterstitialTimeProceed", dt);
739 } else if (command == kTakeMeBackCommand) {
740 UMA_HISTOGRAM_MEDIUM_TIMES("SB2.PhishingInterstitialTimeTakeMeBack", dt);
741 } else if (command == kShowDiagnosticCommand) {
742 UMA_HISTOGRAM_MEDIUM_TIMES("SB2.PhishingInterstitialTimeReportError", dt);
743 } else if (command == kLearnMoreCommand) {
744 UMA_HISTOGRAM_MEDIUM_TIMES("SB2.PhishingInterstitialTimeLearnMore", dt);
745 } else if (command == kNavigatedAwayMetaCommand) {
746 UMA_HISTOGRAM_MEDIUM_TIMES("SB2.PhishingInterstitialTimeClosed", dt);
747 } else if (command == kExpandedSeeMoreCommand) {
748 // Only record the expanded histogram once per display of the
749 // interstitial.
750 if (has_expanded_see_more_section_)
751 return;
752 RecordUserAction(SHOW_ADVANCED);
753 UMA_HISTOGRAM_MEDIUM_TIMES("SB2.PhishingInterstitialTimeExpandedSeeMore",
754 dt);
755 has_expanded_see_more_section_ = true;
756 // Expanding the "See More" section doesn't finish the interstitial, so
757 // don't mark the reaction time as recorded.
758 recorded = false;
759 } else {
760 recorded = false;
763 if (recorded) // Making sure we don't double-count reaction times.
764 interstitial_show_time_ = base::TimeTicks(); // Resets the show time.
767 void SafeBrowsingBlockingPage::FinishMalwareDetails(int64 delay_ms) {
768 if (malware_details_.get() == NULL)
769 return; // Not all interstitials have malware details (eg phishing).
771 const bool enabled =
772 IsPrefEnabled(prefs::kSafeBrowsingExtendedReportingEnabled);
773 UMA_HISTOGRAM_BOOLEAN("SB2.ExtendedReportingIsEnabled", enabled);
774 if (enabled) {
775 // Finish the malware details collection, send it over.
776 BrowserThread::PostDelayedTask(
777 BrowserThread::IO, FROM_HERE,
778 base::Bind(&MalwareDetails::FinishCollection, malware_details_.get()),
779 base::TimeDelta::FromMilliseconds(delay_ms));
783 bool SafeBrowsingBlockingPage::IsPrefEnabled(const char* pref) {
784 Profile* profile =
785 Profile::FromBrowserContext(web_contents_->GetBrowserContext());
786 return profile->GetPrefs()->GetBoolean(pref);
789 // static
790 void SafeBrowsingBlockingPage::NotifySafeBrowsingUIManager(
791 SafeBrowsingUIManager* ui_manager,
792 const UnsafeResourceList& unsafe_resources,
793 bool proceed) {
794 BrowserThread::PostTask(
795 BrowserThread::IO, FROM_HERE,
796 base::Bind(&SafeBrowsingUIManager::OnBlockingPageDone,
797 ui_manager, unsafe_resources, proceed));
800 // static
801 SafeBrowsingBlockingPage::UnsafeResourceMap*
802 SafeBrowsingBlockingPage::GetUnsafeResourcesMap() {
803 return g_unsafe_resource_map.Pointer();
806 // static
807 SafeBrowsingBlockingPage* SafeBrowsingBlockingPage::CreateBlockingPage(
808 SafeBrowsingUIManager* ui_manager,
809 WebContents* web_contents,
810 const UnsafeResource& unsafe_resource) {
811 std::vector<UnsafeResource> resources;
812 resources.push_back(unsafe_resource);
813 // Set up the factory if this has not been done already (tests do that
814 // before this method is called).
815 if (!factory_)
816 factory_ = g_safe_browsing_blocking_page_factory_impl.Pointer();
817 return factory_->CreateSafeBrowsingPage(ui_manager, web_contents, resources);
820 // static
821 void SafeBrowsingBlockingPage::ShowBlockingPage(
822 SafeBrowsingUIManager* ui_manager,
823 const UnsafeResource& unsafe_resource) {
824 DVLOG(1) << __FUNCTION__ << " " << unsafe_resource.url.spec();
825 WebContents* web_contents = tab_util::GetWebContentsByID(
826 unsafe_resource.render_process_host_id, unsafe_resource.render_view_id);
828 InterstitialPage* interstitial =
829 InterstitialPage::GetInterstitialPage(web_contents);
830 if (interstitial && !unsafe_resource.is_subresource) {
831 // There is already an interstitial showing and we are about to display a
832 // new one for the main frame. Just hide the current one, it is now
833 // irrelevent
834 interstitial->DontProceed();
835 interstitial = NULL;
838 if (!interstitial) {
839 // There are no interstitial currently showing in that tab, go ahead and
840 // show this interstitial.
841 SafeBrowsingBlockingPage* blocking_page =
842 CreateBlockingPage(ui_manager, web_contents, unsafe_resource);
843 blocking_page->Show();
844 return;
847 // This is an interstitial for a page's resource, let's queue it.
848 UnsafeResourceMap* unsafe_resource_map = GetUnsafeResourcesMap();
849 (*unsafe_resource_map)[web_contents].push_back(unsafe_resource);
852 // static
853 bool SafeBrowsingBlockingPage::IsMainPageLoadBlocked(
854 const UnsafeResourceList& unsafe_resources) {
855 // Client-side phishing detection interstitials never block the main frame
856 // load, since they happen after the page is finished loading.
857 if (unsafe_resources[0].threat_type ==
858 SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL) {
859 return false;
862 // Otherwise, check the threat type.
863 return unsafe_resources.size() == 1 && !unsafe_resources[0].is_subresource;
866 std::string SafeBrowsingBlockingPage::GetHTMLContents() {
867 DCHECK(!unsafe_resources_.empty());
869 // Fill in the shared values.
870 base::DictionaryValue load_time_data;
871 webui::SetFontAndTextDirection(&load_time_data);
872 load_time_data.SetBoolean("ssl", false);
873 load_time_data.SetString(
874 "tabTitle", l10n_util::GetStringUTF16(IDS_SAFEBROWSING_V3_TITLE));
875 load_time_data.SetString(
876 "openDetails",
877 l10n_util::GetStringUTF16(IDS_SAFEBROWSING_V3_OPEN_DETAILS_BUTTON));
878 load_time_data.SetString(
879 "closeDetails",
880 l10n_util::GetStringUTF16(IDS_SAFEBROWSING_V3_CLOSE_DETAILS_BUTTON));
881 load_time_data.SetString(
882 "primaryButtonText",
883 l10n_util::GetStringUTF16(IDS_SAFEBROWSING_OVERRIDABLE_SAFETY_BUTTON));
884 load_time_data.SetBoolean(
885 "overridable",
886 !IsPrefEnabled(prefs::kSafeBrowsingProceedAnywayDisabled));
888 if (interstitial_type_ == TYPE_PHISHING)
889 PopulatePhishingLoadTimeData(&load_time_data);
890 else
891 PopulateMalwareLoadTimeData(&load_time_data);
893 interstitial_show_time_ = base::TimeTicks::Now();
895 base::StringPiece html(
896 ResourceBundle::GetSharedInstance().GetRawDataResource(
897 IRD_SECURITY_INTERSTITIAL_HTML));
898 webui::UseVersion2 version;
899 return webui::GetI18nTemplateHtml(html, &load_time_data);
902 void SafeBrowsingBlockingPage::PopulateMalwareLoadTimeData(
903 base::DictionaryValue* load_time_data) {
904 load_time_data->SetBoolean("phishing", false);
905 load_time_data->SetString(
906 "heading", l10n_util::GetStringUTF16(IDS_MALWARE_V3_HEADING));
907 load_time_data->SetString(
908 "primaryParagraph",
909 l10n_util::GetStringFUTF16(
910 IDS_MALWARE_V3_PRIMARY_PARAGRAPH,
911 base::UTF8ToUTF16(url_.host())));
912 load_time_data->SetString(
913 "explanationParagraph",
914 is_main_frame_load_blocked_ ?
915 l10n_util::GetStringFUTF16(
916 IDS_MALWARE_V3_EXPLANATION_PARAGRAPH,
917 base::UTF8ToUTF16(url_.host())) :
918 l10n_util::GetStringFUTF16(
919 IDS_MALWARE_V3_EXPLANATION_PARAGRAPH_SUBRESOURCE,
920 base::UTF8ToUTF16(web_contents_->GetURL().host()),
921 base::UTF8ToUTF16(url_.host())));
922 load_time_data->SetString(
923 "finalParagraph",
924 l10n_util::GetStringUTF16(IDS_MALWARE_V3_PROCEED_PARAGRAPH));
926 load_time_data->SetBoolean(kDisplayCheckBox, CanShowMalwareDetailsOption());
927 if (CanShowMalwareDetailsOption()) {
928 std::string privacy_link = base::StringPrintf(
929 kPrivacyLinkHtml,
930 l10n_util::GetStringUTF8(
931 IDS_SAFE_BROWSING_PRIVACY_POLICY_PAGE).c_str());
932 load_time_data->SetString(
933 "optInLink",
934 l10n_util::GetStringFUTF16(IDS_SAFE_BROWSING_MALWARE_REPORTING_AGREE,
935 base::UTF8ToUTF16(privacy_link)));
936 Profile* profile = Profile::FromBrowserContext(
937 web_contents_->GetBrowserContext());
938 if (profile->GetPrefs()->HasPrefPath(
939 prefs::kSafeBrowsingExtendedReportingEnabled)) {
940 reporting_checkbox_checked_ =
941 IsPrefEnabled(prefs::kSafeBrowsingExtendedReportingEnabled);
942 } else if (IsPrefEnabled(prefs::kSafeBrowsingReportingEnabled) ||
943 IsPrefEnabled(prefs::kSafeBrowsingDownloadFeedbackEnabled)) {
944 reporting_checkbox_checked_ = true;
946 load_time_data->SetBoolean(
947 kBoxChecked, reporting_checkbox_checked_);
951 void SafeBrowsingBlockingPage::PopulatePhishingLoadTimeData(
952 base::DictionaryValue* load_time_data) {
953 load_time_data->SetBoolean("phishing", true);
954 load_time_data->SetString(
955 "heading",
956 l10n_util::GetStringUTF16(IDS_PHISHING_V3_HEADING));
957 load_time_data->SetString(
958 "primaryParagraph",
959 l10n_util::GetStringFUTF16(
960 IDS_PHISHING_V3_PRIMARY_PARAGRAPH,
961 base::UTF8ToUTF16(url_.host())));
962 load_time_data->SetString(
963 "explanationParagraph",
964 l10n_util::GetStringFUTF16(IDS_PHISHING_V3_EXPLANATION_PARAGRAPH,
965 base::UTF8ToUTF16(url_.host())));
966 load_time_data->SetString(
967 "finalParagraph",
968 l10n_util::GetStringUTF16(IDS_PHISHING_V3_PROCEED_PARAGRAPH));