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.
5 // Implementation of the SafeBrowsingBlockingPage class.
7 #include "chrome/browser/safe_browsing/safe_browsing_blocking_page.h"
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"
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
;
66 // For malware interstitial pages, we link the problematic URL to Google's
68 #if defined(GOOGLE_CHROME_BUILD)
69 const char* const kSbDiagnosticUrl
=
70 "http://safebrowsing.clients.google.com/safebrowsing/diagnostic?site=%s&client=googlechrome";
72 const char* const kSbDiagnosticUrl
=
73 "http://safebrowsing.clients.google.com/safebrowsing/diagnostic?site=%s&client=chromium";
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
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_";
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
,
140 void RecordDetailedUserAction(DetailedDecision decision
) {
141 UMA_HISTOGRAM_ENUMERATION("SB2.InterstitialActionDetails",
143 MAX_DETAILED_ACTION
);
149 SafeBrowsingBlockingPageFactory
* SafeBrowsingBlockingPage::factory_
= NULL
;
151 // The default SafeBrowsingBlockingPageFactory. Global, made a singleton so we
153 class SafeBrowsingBlockingPageFactoryImpl
154 : public SafeBrowsingBlockingPageFactory
{
156 virtual SafeBrowsingBlockingPage
* CreateSafeBrowsingPage(
157 SafeBrowsingUIManager
* ui_manager
,
158 WebContents
* web_contents
,
159 const SafeBrowsingBlockingPage::UnsafeResourceList
& unsafe_resources
)
161 return new SafeBrowsingBlockingPage(ui_manager
, web_contents
,
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
),
185 is_main_frame_load_blocked_(IsMainPageLoadBlocked(unsafe_resources
)),
186 unsafe_resources_(unsafe_resources
),
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),
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
) {
205 DCHECK(threat_type
== SB_THREAT_TYPE_URL_PHISHING
||
206 threat_type
== SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL
);
210 DCHECK(phishing
|| malware
);
211 if (malware
&& phishing
)
212 interstitial_type_
= TYPE_MALWARE_AND_PHISHING
;
214 interstitial_type_
= TYPE_MALWARE
;
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(
225 base::Bind(&SafeBrowsingBlockingPage::OnGotHistoryCount
,
226 base::Unretained(this)),
230 if (!is_main_frame_load_blocked_
) {
231 navigation_entry_index_to_remove_
=
232 web_contents
->GetController().GetLastCommittedEntryIndex();
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
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
;
258 event_name
= kEventNameMalware
;
261 event_name
= kEventNamePhishing
;
264 event_name
= kEventNameOther
;
267 sampling_event_
.reset(new ExperienceSamplingEvent(
270 web_contents_
->GetLastCommittedURL(),
271 web_contents_
->GetBrowserContext()));
274 // Creating interstitial_page_ without showing it leaks memory, so don't
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);
298 if (command
== kDontReportCommand
) {
299 SetReportingPreference(false);
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);
311 OpenURLParams
params(
312 url
, Referrer(), CURRENT_TAB
, content::PAGE_TRANSITION_LINK
, false);
313 web_contents_
->OpenURL(params
);
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
);
326 bool proceed_blocked
= false;
327 if (command
== kProceedCommand
) {
328 if (IsPrefEnabled(prefs::kSafeBrowsingProceedAnywayDisabled
)) {
329 proceed_blocked
= true;
331 interstitial_page_
->Proceed();
332 // |this| has been deleted after Proceed() returns.
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.
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();
351 web_contents_
->GetController().LoadURL(
352 GURL(chrome::kChromeUINewTabURL
),
354 content::PAGE_TRANSITION_AUTO_TOPLEVEL
,
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);
367 bool result
= base::StringToInt(base::StringPiece(command
.begin() +
371 command
= command
.substr(0, colon_index
);
373 element_index
= static_cast<size_t>(result_int
);
376 if (element_index
>= unsafe_resources_
.size()) {
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
);
390 safe_browsing_util::GeneratePhishingReportUrl(
391 kSbReportPhishingErrorUrl
,
393 threat_type
== SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL
);
394 OpenURLParams
params(
395 report_url
, Referrer(), CURRENT_TAB
, content::PAGE_TRANSITION_LINK
,
397 web_contents_
->OpenURL(params
);
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
,
416 web_contents_
->OpenURL(params
);
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
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);
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_
)
460 if (IsPrefEnabled(prefs::kSafeBrowsingExtendedReportingEnabled
))
462 Profile
* profile
= Profile::FromBrowserContext(
463 web_contents_
->GetBrowserContext());
464 if (profile
->GetPrefs()->HasPrefPath(
465 prefs::kSafeBrowsingExtendedReportingEnabled
))
467 SetReportingPreference(true);
470 void SafeBrowsingBlockingPage::OnProceed() {
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_
,
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
);
499 // Now that this interstitial is gone, we can show the new one.
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);
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.
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
);
564 void SafeBrowsingBlockingPage::OnGotHistoryCount(bool success
,
566 base::Time first_visit
) {
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.
576 MALWARE_DONT_PROCEED
,
577 MALWARE_FORCED_DONT_PROCEED
,
580 MULTIPLE_DONT_PROCEED
,
581 MULTIPLE_FORCED_DONT_PROCEED
,
584 PHISHING_DONT_PROCEED
,
585 PHISHING_FORCED_DONT_PROCEED
,
587 MALWARE_SHOW_ADVANCED
,
588 MULTIPLE_SHOW_ADVANCED
,
589 PHISHING_SHOW_ADVANCED
,
591 } histogram_action
= MAX_ACTION
;
595 switch (interstitial_type_
) {
596 case TYPE_MALWARE_AND_PHISHING
:
597 histogram_action
= MULTIPLE_SHOW
;
600 histogram_action
= MALWARE_SHOW
;
603 histogram_action
= PHISHING_SHOW
;
608 switch (interstitial_type_
) {
609 case TYPE_MALWARE_AND_PHISHING
:
610 histogram_action
= MULTIPLE_PROCEED
;
613 histogram_action
= MALWARE_PROCEED
;
616 histogram_action
= PHISHING_PROCEED
;
621 if (IsPrefEnabled(prefs::kSafeBrowsingProceedAnywayDisabled
)) {
622 switch (interstitial_type_
) {
623 case TYPE_MALWARE_AND_PHISHING
:
624 histogram_action
= MULTIPLE_FORCED_DONT_PROCEED
;
627 histogram_action
= MALWARE_FORCED_DONT_PROCEED
;
630 histogram_action
= PHISHING_FORCED_DONT_PROCEED
;
634 switch (interstitial_type_
) {
635 case TYPE_MALWARE_AND_PHISHING
:
636 histogram_action
= MULTIPLE_DONT_PROCEED
;
639 histogram_action
= MALWARE_DONT_PROCEED
;
642 histogram_action
= PHISHING_DONT_PROCEED
;
648 switch (interstitial_type_
) {
649 case TYPE_MALWARE_AND_PHISHING
:
650 histogram_action
= MULTIPLE_SHOW_ADVANCED
;
653 histogram_action
= MALWARE_SHOW_ADVANCED
;
656 histogram_action
= PHISHING_SHOW_ADVANCED
;
661 NOTREACHED() << "Unexpected event: " << event
;
663 if (histogram_action
== MAX_ACTION
) {
666 UMA_HISTOGRAM_ENUMERATION("SB2.InterstitialAction", histogram_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",
715 } else if (command
== kLearnMoreCommand
) {
716 UMA_HISTOGRAM_MEDIUM_TIMES("SB2.MalwareInterstitialLearnMore",
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
723 if (has_expanded_see_more_section_
)
725 RecordUserAction(SHOW_ADVANCED
);
726 UMA_HISTOGRAM_MEDIUM_TIMES("SB2.MalwareInterstitialTimeExpandedSeeMore",
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.
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
750 if (has_expanded_see_more_section_
)
752 RecordUserAction(SHOW_ADVANCED
);
753 UMA_HISTOGRAM_MEDIUM_TIMES("SB2.PhishingInterstitialTimeExpandedSeeMore",
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.
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).
772 IsPrefEnabled(prefs::kSafeBrowsingExtendedReportingEnabled
);
773 UMA_HISTOGRAM_BOOLEAN("SB2.ExtendedReportingIsEnabled", 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
) {
785 Profile::FromBrowserContext(web_contents_
->GetBrowserContext());
786 return profile
->GetPrefs()->GetBoolean(pref
);
790 void SafeBrowsingBlockingPage::NotifySafeBrowsingUIManager(
791 SafeBrowsingUIManager
* ui_manager
,
792 const UnsafeResourceList
& unsafe_resources
,
794 BrowserThread::PostTask(
795 BrowserThread::IO
, FROM_HERE
,
796 base::Bind(&SafeBrowsingUIManager::OnBlockingPageDone
,
797 ui_manager
, unsafe_resources
, proceed
));
801 SafeBrowsingBlockingPage::UnsafeResourceMap
*
802 SafeBrowsingBlockingPage::GetUnsafeResourcesMap() {
803 return g_unsafe_resource_map
.Pointer();
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).
816 factory_
= g_safe_browsing_blocking_page_factory_impl
.Pointer();
817 return factory_
->CreateSafeBrowsingPage(ui_manager
, web_contents
, resources
);
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
834 interstitial
->DontProceed();
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();
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
);
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
) {
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(
877 l10n_util::GetStringUTF16(IDS_SAFEBROWSING_V3_OPEN_DETAILS_BUTTON
));
878 load_time_data
.SetString(
880 l10n_util::GetStringUTF16(IDS_SAFEBROWSING_V3_CLOSE_DETAILS_BUTTON
));
881 load_time_data
.SetString(
883 l10n_util::GetStringUTF16(IDS_SAFEBROWSING_OVERRIDABLE_SAFETY_BUTTON
));
884 load_time_data
.SetBoolean(
886 !IsPrefEnabled(prefs::kSafeBrowsingProceedAnywayDisabled
));
888 if (interstitial_type_
== TYPE_PHISHING
)
889 PopulatePhishingLoadTimeData(&load_time_data
);
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(
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(
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(
930 l10n_util::GetStringUTF8(
931 IDS_SAFE_BROWSING_PRIVACY_POLICY_PAGE
).c_str());
932 load_time_data
->SetString(
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(
956 l10n_util::GetStringUTF16(IDS_PHISHING_V3_HEADING
));
957 load_time_data
->SetString(
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(
968 l10n_util::GetStringUTF16(IDS_PHISHING_V3_PROCEED_PARAGRAPH
));