• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 //
5 // Implementation of the SafeBrowsingBlockingPage class.
6 
7 #include "chrome/browser/safe_browsing/safe_browsing_blocking_page.h"
8 
9 #include <string>
10 
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 "chrome/grit/locale_settings.h"
36 #include "components/google/core/browser/google_util.h"
37 #include "content/public/browser/browser_thread.h"
38 #include "content/public/browser/interstitial_page.h"
39 #include "content/public/browser/navigation_controller.h"
40 #include "content/public/browser/user_metrics.h"
41 #include "content/public/browser/web_contents.h"
42 #include "grit/browser_resources.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"
48 
49 #if defined(ENABLE_EXTENSIONS)
50 #include "chrome/browser/extensions/api/experience_sampling_private/experience_sampling.h"
51 #endif
52 
53 using base::UserMetricsAction;
54 using content::BrowserThread;
55 using content::InterstitialPage;
56 using content::OpenURLParams;
57 using content::Referrer;
58 using content::WebContents;
59 
60 #if defined(ENABLE_EXTENSIONS)
61 using extensions::ExperienceSamplingEvent;
62 #endif
63 
64 namespace {
65 
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
75 
76 // URL for malware and phishing, V2.
77 const char kLearnMoreMalwareUrlV2[] =
78     "https://www.google.com/transparencyreport/safebrowsing/";
79 const char kLearnMorePhishingUrlV2[] =
80     "https://www.google.com/transparencyreport/safebrowsing/";
81 
82 const char kPrivacyLinkHtml[] =
83     "<a id=\"privacy-link\" href=\"\" onclick=\"sendCommand('showPrivacy'); "
84     "return false;\" onmousedown=\"return false;\">%s</a>";
85 
86 // After a malware interstitial where the user opted-in to the report
87 // but clicked "proceed anyway", we delay the call to
88 // MalwareDetails::FinishCollection() by this much time (in
89 // milliseconds).
90 const int64 kMalwareDetailsProceedDelayMilliSeconds = 3000;
91 
92 // The commands returned by the page when the user performs an action.
93 const char kDoReportCommand[] = "doReport";
94 const char kDontReportCommand[] = "dontReport";
95 const char kExpandedSeeMoreCommand[] = "expandedSeeMore";
96 const char kLearnMoreCommand[] = "learnMore2";
97 const char kProceedCommand[] = "proceed";
98 const char kShowDiagnosticCommand[] = "showDiagnostic";
99 const char kShowPrivacyCommand[] = "showPrivacy";
100 const char kTakeMeBackCommand[] = "takeMeBack";
101 
102 // Other constants used to communicate with the JavaScript.
103 const char kBoxChecked[] = "boxchecked";
104 const char kDisplayCheckBox[] = "displaycheckbox";
105 
106 // Constants for the Experience Sampling instrumentation.
107 #if defined(ENABLE_EXTENSIONS)
108 const char kEventNameMalware[] = "safebrowsing_interstitial_";
109 const char kEventNameHarmful[] = "harmful_interstitial_";
110 const char kEventNamePhishing[] = "phishing_interstitial_";
111 const char kEventNameOther[] = "safebrowsing_other_interstitial_";
112 #endif
113 
114 base::LazyInstance<SafeBrowsingBlockingPage::UnsafeResourceMap>
115     g_unsafe_resource_map = LAZY_INSTANCE_INITIALIZER;
116 
117 }  // namespace
118 
119 // static
120 SafeBrowsingBlockingPageFactory* SafeBrowsingBlockingPage::factory_ = NULL;
121 
122 // The default SafeBrowsingBlockingPageFactory.  Global, made a singleton so we
123 // don't leak it.
124 class SafeBrowsingBlockingPageFactoryImpl
125     : public SafeBrowsingBlockingPageFactory {
126  public:
CreateSafeBrowsingPage(SafeBrowsingUIManager * ui_manager,WebContents * web_contents,const SafeBrowsingBlockingPage::UnsafeResourceList & unsafe_resources)127   virtual SafeBrowsingBlockingPage* CreateSafeBrowsingPage(
128       SafeBrowsingUIManager* ui_manager,
129       WebContents* web_contents,
130       const SafeBrowsingBlockingPage::UnsafeResourceList& unsafe_resources)
131       OVERRIDE {
132     return new SafeBrowsingBlockingPage(ui_manager, web_contents,
133         unsafe_resources);
134   }
135 
136  private:
137   friend struct base::DefaultLazyInstanceTraits<
138       SafeBrowsingBlockingPageFactoryImpl>;
139 
SafeBrowsingBlockingPageFactoryImpl()140   SafeBrowsingBlockingPageFactoryImpl() { }
141 
142   DISALLOW_COPY_AND_ASSIGN(SafeBrowsingBlockingPageFactoryImpl);
143 };
144 
145 static base::LazyInstance<SafeBrowsingBlockingPageFactoryImpl>
146     g_safe_browsing_blocking_page_factory_impl = LAZY_INSTANCE_INITIALIZER;
147 
SafeBrowsingBlockingPage(SafeBrowsingUIManager * ui_manager,WebContents * web_contents,const UnsafeResourceList & unsafe_resources)148 SafeBrowsingBlockingPage::SafeBrowsingBlockingPage(
149     SafeBrowsingUIManager* ui_manager,
150     WebContents* web_contents,
151     const UnsafeResourceList& unsafe_resources)
152     : malware_details_proceed_delay_ms_(
153           kMalwareDetailsProceedDelayMilliSeconds),
154       ui_manager_(ui_manager),
155       report_loop_(NULL),
156       is_main_frame_load_blocked_(IsMainPageLoadBlocked(unsafe_resources)),
157       unsafe_resources_(unsafe_resources),
158       proceeded_(false),
159       web_contents_(web_contents),
160       url_(unsafe_resources[0].url),
161       interstitial_page_(NULL),
162       create_view_(true),
163       num_visits_(-1) {
164   bool malware = false;
165   bool harmful = false;
166   bool phishing = false;
167   for (UnsafeResourceList::const_iterator iter = unsafe_resources_.begin();
168        iter != unsafe_resources_.end(); ++iter) {
169     const UnsafeResource& resource = *iter;
170     SBThreatType threat_type = resource.threat_type;
171     if (threat_type == SB_THREAT_TYPE_URL_MALWARE ||
172         threat_type == SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL) {
173       malware = true;
174     } else if (threat_type == SB_THREAT_TYPE_URL_HARMFUL) {
175       harmful = true;
176     } else {
177       DCHECK(threat_type == SB_THREAT_TYPE_URL_PHISHING ||
178              threat_type == SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL);
179       phishing = true;
180     }
181   }
182   DCHECK(phishing || malware || harmful);
183   if (malware)
184     interstitial_type_ = TYPE_MALWARE;
185   else if (harmful)
186     interstitial_type_ = TYPE_HARMFUL;
187   else
188     interstitial_type_ = TYPE_PHISHING;
189 
190   RecordUserDecision(SHOW);
191   RecordUserInteraction(TOTAL_VISITS);
192   if (IsPrefEnabled(prefs::kSafeBrowsingProceedAnywayDisabled))
193     RecordUserDecision(PROCEEDING_DISABLED);
194 
195   HistoryService* history_service = HistoryServiceFactory::GetForProfile(
196           Profile::FromBrowserContext(web_contents->GetBrowserContext()),
197           Profile::EXPLICIT_ACCESS);
198   if (history_service) {
199     history_service->GetVisibleVisitCountToHost(
200         url_,
201         base::Bind(&SafeBrowsingBlockingPage::OnGotHistoryCount,
202                    base::Unretained(this)),
203         &request_tracker_);
204   }
205 
206   if (!is_main_frame_load_blocked_) {
207     navigation_entry_index_to_remove_ =
208         web_contents->GetController().GetLastCommittedEntryIndex();
209   } else {
210     navigation_entry_index_to_remove_ = -1;
211   }
212 
213   // Start computing malware details. They will be sent only
214   // if the user opts-in on the blocking page later.
215   // If there's more than one malicious resources, it means the user
216   // clicked through the first warning, so we don't prepare additional
217   // reports.
218   if (unsafe_resources.size() == 1 &&
219       unsafe_resources[0].threat_type == SB_THREAT_TYPE_URL_MALWARE &&
220       malware_details_.get() == NULL && CanShowMalwareDetailsOption()) {
221     malware_details_ = MalwareDetails::NewMalwareDetails(
222         ui_manager_, web_contents, unsafe_resources[0]);
223   }
224 
225 #if defined(ENABLE_EXTENSIONS)
226   // ExperienceSampling: Set up new sampling event for this interstitial.
227   // This needs to handle all types of warnings this interstitial can show.
228   std::string event_name;
229   switch (interstitial_type_) {
230     case TYPE_MALWARE:
231       event_name = kEventNameMalware;
232       break;
233     case TYPE_HARMFUL:
234       event_name = kEventNameHarmful;
235       break;
236     case TYPE_PHISHING:
237       event_name = kEventNamePhishing;
238       break;
239     default:
240       event_name = kEventNameOther;
241       break;
242   }
243   sampling_event_.reset(new ExperienceSamplingEvent(
244       event_name,
245       url_,
246       web_contents_->GetLastCommittedURL(),
247       web_contents_->GetBrowserContext()));
248 #endif
249 
250   // Creating interstitial_page_ without showing it leaks memory, so don't
251   // create it here.
252 }
253 
CanShowMalwareDetailsOption()254 bool SafeBrowsingBlockingPage::CanShowMalwareDetailsOption() {
255   return (!web_contents_->GetBrowserContext()->IsOffTheRecord() &&
256           web_contents_->GetURL().SchemeIs(url::kHttpScheme));
257 }
258 
~SafeBrowsingBlockingPage()259 SafeBrowsingBlockingPage::~SafeBrowsingBlockingPage() {
260 }
261 
CommandReceived(const std::string & cmd)262 void SafeBrowsingBlockingPage::CommandReceived(const std::string& cmd) {
263   std::string command(cmd);  // Make a local copy so we can modify it.
264   // The Jasonified response has quotes, remove them.
265   if (command.length() > 1 && command[0] == '"') {
266     command = command.substr(1, command.length() - 2);
267   }
268   if (command == kDoReportCommand) {
269     SetReportingPreference(true);
270     return;
271   }
272 
273   if (command == kDontReportCommand) {
274     SetReportingPreference(false);
275     return;
276   }
277 
278   if (command == kLearnMoreCommand) {
279     // User pressed "Learn more".
280     RecordUserInteraction(SHOW_LEARN_MORE);
281     GURL learn_more_url(interstitial_type_ == TYPE_PHISHING ?
282                         kLearnMorePhishingUrlV2 : kLearnMoreMalwareUrlV2);
283     learn_more_url = google_util::AppendGoogleLocaleParam(
284         learn_more_url, g_browser_process->GetApplicationLocale());
285     OpenURLParams params(learn_more_url,
286                          Referrer(),
287                          CURRENT_TAB,
288                          ui::PAGE_TRANSITION_LINK,
289                          false);
290     web_contents_->OpenURL(params);
291     return;
292   }
293 
294   if (command == kShowPrivacyCommand) {
295     // User pressed "Safe Browsing privacy policy".
296     RecordUserInteraction(SHOW_PRIVACY_POLICY);
297     GURL privacy_url(
298         l10n_util::GetStringUTF8(IDS_SAFE_BROWSING_PRIVACY_POLICY_URL));
299     privacy_url = google_util::AppendGoogleLocaleParam(
300         privacy_url, g_browser_process->GetApplicationLocale());
301     OpenURLParams params(privacy_url,
302                          Referrer(),
303                          CURRENT_TAB,
304                          ui::PAGE_TRANSITION_LINK,
305                          false);
306     web_contents_->OpenURL(params);
307     return;
308   }
309 
310   bool proceed_blocked = false;
311   if (command == kProceedCommand) {
312     if (IsPrefEnabled(prefs::kSafeBrowsingProceedAnywayDisabled)) {
313       proceed_blocked = true;
314     } else {
315       RecordUserDecision(PROCEED);
316       interstitial_page_->Proceed();
317       // |this| has been deleted after Proceed() returns.
318       return;
319     }
320   }
321 
322   if (command == kTakeMeBackCommand || proceed_blocked) {
323     // Don't record the user action here because there are other ways of
324     // triggering DontProceed, like clicking the back button.
325     if (is_main_frame_load_blocked_) {
326       // If the load is blocked, we want to close the interstitial and discard
327       // the pending entry.
328       interstitial_page_->DontProceed();
329       // |this| has been deleted after DontProceed() returns.
330       return;
331     }
332 
333     // Otherwise the offending entry has committed, and we need to go back or
334     // to a safe page.  We will close the interstitial when that page commits.
335     if (web_contents_->GetController().CanGoBack()) {
336       web_contents_->GetController().GoBack();
337     } else {
338       web_contents_->GetController().LoadURL(
339           GURL(chrome::kChromeUINewTabURL),
340           content::Referrer(),
341           ui::PAGE_TRANSITION_AUTO_TOPLEVEL,
342           std::string());
343     }
344     return;
345   }
346 
347   // The "report error" and "show diagnostic" commands can have a number
348   // appended to them, which is the index of the element they apply to.
349   size_t element_index = 0;
350   size_t colon_index = command.find(':');
351   if (colon_index != std::string::npos) {
352     DCHECK(colon_index < command.size() - 1);
353     int result_int = 0;
354     bool result = base::StringToInt(base::StringPiece(command.begin() +
355                                                       colon_index + 1,
356                                                       command.end()),
357                                     &result_int);
358     command = command.substr(0, colon_index);
359     if (result)
360       element_index = static_cast<size_t>(result_int);
361   }
362 
363   if (element_index >= unsafe_resources_.size()) {
364     NOTREACHED();
365     return;
366   }
367 
368   std::string bad_url_spec = unsafe_resources_[element_index].url.spec();
369   if (command == kShowDiagnosticCommand) {
370     // We're going to take the user to Google's SafeBrowsing diagnostic page.
371     RecordUserInteraction(SHOW_DIAGNOSTIC);
372     std::string diagnostic =
373         base::StringPrintf(kSbDiagnosticUrl,
374             net::EscapeQueryParamValue(bad_url_spec, true).c_str());
375     GURL diagnostic_url(diagnostic);
376     diagnostic_url = google_util::AppendGoogleLocaleParam(
377         diagnostic_url, g_browser_process->GetApplicationLocale());
378     DCHECK(unsafe_resources_[element_index].threat_type ==
379            SB_THREAT_TYPE_URL_MALWARE ||
380            unsafe_resources_[element_index].threat_type ==
381            SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL);
382     OpenURLParams params(
383         diagnostic_url, Referrer(), CURRENT_TAB, ui::PAGE_TRANSITION_LINK,
384         false);
385     web_contents_->OpenURL(params);
386     return;
387   }
388 
389   if (command == kExpandedSeeMoreCommand) {
390     RecordUserInteraction(SHOW_ADVANCED);
391     return;
392   }
393 
394   NOTREACHED() << "Unexpected command: " << command;
395 }
396 
OverrideRendererPrefs(content::RendererPreferences * prefs)397 void SafeBrowsingBlockingPage::OverrideRendererPrefs(
398       content::RendererPreferences* prefs) {
399   Profile* profile = Profile::FromBrowserContext(
400       web_contents_->GetBrowserContext());
401   renderer_preferences_util::UpdateFromSystemSettings(prefs, profile);
402  }
403 
SetReportingPreference(bool report)404 void SafeBrowsingBlockingPage::SetReportingPreference(bool report) {
405   Profile* profile = Profile::FromBrowserContext(
406       web_contents_->GetBrowserContext());
407   PrefService* pref = profile->GetPrefs();
408   pref->SetBoolean(prefs::kSafeBrowsingExtendedReportingEnabled, report);
409   UMA_HISTOGRAM_BOOLEAN("SB2.SetExtendedReportingEnabled", report);
410 }
411 
OnProceed()412 void SafeBrowsingBlockingPage::OnProceed() {
413   proceeded_ = true;
414   // Send the malware details, if we opted to.
415   FinishMalwareDetails(malware_details_proceed_delay_ms_);
416 
417   NotifySafeBrowsingUIManager(ui_manager_, unsafe_resources_, true);
418 
419   // Check to see if some new notifications of unsafe resources have been
420   // received while we were showing the interstitial.
421   UnsafeResourceMap* unsafe_resource_map = GetUnsafeResourcesMap();
422   UnsafeResourceMap::iterator iter = unsafe_resource_map->find(web_contents_);
423   SafeBrowsingBlockingPage* blocking_page = NULL;
424   if (iter != unsafe_resource_map->end() && !iter->second.empty()) {
425     // Build an interstitial for all the unsafe resources notifications.
426     // Don't show it now as showing an interstitial while an interstitial is
427     // already showing would cause DontProceed() to be invoked.
428     blocking_page = factory_->CreateSafeBrowsingPage(ui_manager_, web_contents_,
429                                                      iter->second);
430     unsafe_resource_map->erase(iter);
431   }
432 
433   // Now that this interstitial is gone, we can show the new one.
434   if (blocking_page)
435     blocking_page->Show();
436 }
437 
DontCreateViewForTesting()438 void SafeBrowsingBlockingPage::DontCreateViewForTesting() {
439   create_view_ = false;
440 }
441 
Show()442 void SafeBrowsingBlockingPage::Show() {
443   DCHECK(!interstitial_page_);
444   interstitial_page_ = InterstitialPage::Create(
445       web_contents_, is_main_frame_load_blocked_, url_, this);
446   if (!create_view_)
447     interstitial_page_->DontCreateViewForTesting();
448   interstitial_page_->Show();
449 }
450 
OnDontProceed()451 void SafeBrowsingBlockingPage::OnDontProceed() {
452   // We could have already called Proceed(), in which case we must not notify
453   // the SafeBrowsingUIManager again, as the client has been deleted.
454   if (proceeded_)
455     return;
456 
457   if (!IsPrefEnabled(prefs::kSafeBrowsingProceedAnywayDisabled))
458     RecordUserDecision(DONT_PROCEED);
459 
460   // Send the malware details, if we opted to.
461   FinishMalwareDetails(0);  // No delay
462 
463   NotifySafeBrowsingUIManager(ui_manager_, unsafe_resources_, false);
464 
465   // The user does not want to proceed, clear the queued unsafe resources
466   // notifications we received while the interstitial was showing.
467   UnsafeResourceMap* unsafe_resource_map = GetUnsafeResourcesMap();
468   UnsafeResourceMap::iterator iter = unsafe_resource_map->find(web_contents_);
469   if (iter != unsafe_resource_map->end() && !iter->second.empty()) {
470     NotifySafeBrowsingUIManager(ui_manager_, iter->second, false);
471     unsafe_resource_map->erase(iter);
472   }
473 
474   // We don't remove the navigation entry if the tab is being destroyed as this
475   // would trigger a navigation that would cause trouble as the render view host
476   // for the tab has by then already been destroyed.  We also don't delete the
477   // current entry if it has been committed again, which is possible on a page
478   // that had a subresource warning.
479   int last_committed_index =
480       web_contents_->GetController().GetLastCommittedEntryIndex();
481   if (navigation_entry_index_to_remove_ != -1 &&
482       navigation_entry_index_to_remove_ != last_committed_index &&
483       !web_contents_->IsBeingDestroyed()) {
484     CHECK(web_contents_->GetController().RemoveEntryAtIndex(
485         navigation_entry_index_to_remove_));
486     navigation_entry_index_to_remove_ = -1;
487   }
488 }
489 
OnGotHistoryCount(bool success,int num_visits,base::Time first_visit)490 void SafeBrowsingBlockingPage::OnGotHistoryCount(bool success,
491                                                  int num_visits,
492                                                  base::Time first_visit) {
493   if (success)
494     num_visits_ = num_visits;
495 }
496 
RecordUserDecision(Decision decision)497 void SafeBrowsingBlockingPage::RecordUserDecision(Decision decision) {
498   switch (interstitial_type_) {
499     case TYPE_MALWARE:
500       UMA_HISTOGRAM_ENUMERATION("interstitial.malware.decision",
501                                 decision,
502                                 MAX_DECISION);
503       break;
504     case TYPE_HARMFUL:
505       UMA_HISTOGRAM_ENUMERATION("interstitial.harmful.decision",
506                                 decision,
507                                 MAX_DECISION);
508       break;
509     case TYPE_PHISHING:
510       UMA_HISTOGRAM_ENUMERATION("interstitial.phishing.decision",
511                                 decision,
512                                 MAX_DECISION);
513       break;
514   }
515 
516 #if defined(ENABLE_EXTENSIONS)
517   if (sampling_event_.get()) {
518     switch (decision) {
519       case PROCEED:
520         sampling_event_->CreateUserDecisionEvent(
521             ExperienceSamplingEvent::kProceed);
522         break;
523       case DONT_PROCEED:
524         sampling_event_->CreateUserDecisionEvent(
525             ExperienceSamplingEvent::kDeny);
526         break;
527       case SHOW:
528       case PROCEEDING_DISABLED:
529       case MAX_DECISION:
530         break;
531     }
532   }
533 #endif
534 
535   // Record additional information about malware sites that users have
536   // visited before.
537   if (num_visits_ < 1 || interstitial_type_ != TYPE_MALWARE)
538     return;
539   if (decision == PROCEED || decision == DONT_PROCEED) {
540     UMA_HISTOGRAM_ENUMERATION("interstitial.malware.decision.repeat_visit",
541                               SHOW,
542                               MAX_DECISION);
543     UMA_HISTOGRAM_ENUMERATION("interstitial.malware.decision.repeat_visit",
544                               decision,
545                               MAX_DECISION);
546   }
547 }
548 
RecordUserInteraction(Interaction interaction)549 void SafeBrowsingBlockingPage::RecordUserInteraction(Interaction interaction) {
550   switch (interstitial_type_) {
551     case TYPE_MALWARE:
552       UMA_HISTOGRAM_ENUMERATION("interstitial.malware.interaction",
553                                 interaction,
554                                 MAX_INTERACTION);
555       break;
556     case TYPE_HARMFUL:
557       UMA_HISTOGRAM_ENUMERATION("interstitial.harmful.interaction",
558                                 interaction,
559                                 MAX_INTERACTION);
560       break;
561     case TYPE_PHISHING:
562       UMA_HISTOGRAM_ENUMERATION("interstitial.phishing.interaction",
563                                 interaction,
564                                 MAX_INTERACTION);
565       break;
566   }
567 
568 #if defined(ENABLE_EXTENSIONS)
569   if (!sampling_event_.get())
570     return;
571   switch (interaction) {
572     case SHOW_LEARN_MORE:
573       sampling_event_->set_has_viewed_learn_more(true);
574       break;
575     case SHOW_ADVANCED:
576       sampling_event_->set_has_viewed_details(true);
577       break;
578     case SHOW_PRIVACY_POLICY:
579     case SHOW_DIAGNOSTIC:
580     case TOTAL_VISITS:
581     case MAX_INTERACTION:
582       break;
583   }
584 #endif
585 }
586 
FinishMalwareDetails(int64 delay_ms)587 void SafeBrowsingBlockingPage::FinishMalwareDetails(int64 delay_ms) {
588   if (malware_details_.get() == NULL)
589     return;  // Not all interstitials have malware details (eg phishing).
590 
591   const bool enabled =
592       IsPrefEnabled(prefs::kSafeBrowsingExtendedReportingEnabled);
593   UMA_HISTOGRAM_BOOLEAN("SB2.ExtendedReportingIsEnabled", enabled);
594   if (enabled) {
595     // Finish the malware details collection, send it over.
596     BrowserThread::PostDelayedTask(
597         BrowserThread::IO, FROM_HERE,
598         base::Bind(&MalwareDetails::FinishCollection, malware_details_.get()),
599         base::TimeDelta::FromMilliseconds(delay_ms));
600   }
601 }
602 
IsPrefEnabled(const char * pref)603 bool SafeBrowsingBlockingPage::IsPrefEnabled(const char* pref) {
604   Profile* profile =
605       Profile::FromBrowserContext(web_contents_->GetBrowserContext());
606   return profile->GetPrefs()->GetBoolean(pref);
607 }
608 
609 // static
NotifySafeBrowsingUIManager(SafeBrowsingUIManager * ui_manager,const UnsafeResourceList & unsafe_resources,bool proceed)610 void SafeBrowsingBlockingPage::NotifySafeBrowsingUIManager(
611     SafeBrowsingUIManager* ui_manager,
612     const UnsafeResourceList& unsafe_resources,
613     bool proceed) {
614   BrowserThread::PostTask(
615       BrowserThread::IO, FROM_HERE,
616       base::Bind(&SafeBrowsingUIManager::OnBlockingPageDone,
617                  ui_manager, unsafe_resources, proceed));
618 }
619 
620 // static
621 SafeBrowsingBlockingPage::UnsafeResourceMap*
GetUnsafeResourcesMap()622     SafeBrowsingBlockingPage::GetUnsafeResourcesMap() {
623   return g_unsafe_resource_map.Pointer();
624 }
625 
626 // static
CreateBlockingPage(SafeBrowsingUIManager * ui_manager,WebContents * web_contents,const UnsafeResource & unsafe_resource)627 SafeBrowsingBlockingPage* SafeBrowsingBlockingPage::CreateBlockingPage(
628     SafeBrowsingUIManager* ui_manager,
629     WebContents* web_contents,
630     const UnsafeResource& unsafe_resource) {
631   std::vector<UnsafeResource> resources;
632   resources.push_back(unsafe_resource);
633   // Set up the factory if this has not been done already (tests do that
634   // before this method is called).
635   if (!factory_)
636     factory_ = g_safe_browsing_blocking_page_factory_impl.Pointer();
637   return factory_->CreateSafeBrowsingPage(ui_manager, web_contents, resources);
638 }
639 
640 // static
ShowBlockingPage(SafeBrowsingUIManager * ui_manager,const UnsafeResource & unsafe_resource)641 void SafeBrowsingBlockingPage::ShowBlockingPage(
642     SafeBrowsingUIManager* ui_manager,
643     const UnsafeResource& unsafe_resource) {
644   DVLOG(1) << __FUNCTION__ << " " << unsafe_resource.url.spec();
645   WebContents* web_contents = tab_util::GetWebContentsByID(
646       unsafe_resource.render_process_host_id, unsafe_resource.render_view_id);
647 
648   InterstitialPage* interstitial =
649       InterstitialPage::GetInterstitialPage(web_contents);
650   if (interstitial && !unsafe_resource.is_subresource) {
651     // There is already an interstitial showing and we are about to display a
652     // new one for the main frame. Just hide the current one, it is now
653     // irrelevent
654     interstitial->DontProceed();
655     interstitial = NULL;
656   }
657 
658   if (!interstitial) {
659     // There are no interstitial currently showing in that tab, go ahead and
660     // show this interstitial.
661     SafeBrowsingBlockingPage* blocking_page =
662         CreateBlockingPage(ui_manager, web_contents, unsafe_resource);
663     blocking_page->Show();
664     return;
665   }
666 
667   // This is an interstitial for a page's resource, let's queue it.
668   UnsafeResourceMap* unsafe_resource_map = GetUnsafeResourcesMap();
669   (*unsafe_resource_map)[web_contents].push_back(unsafe_resource);
670 }
671 
672 // static
IsMainPageLoadBlocked(const UnsafeResourceList & unsafe_resources)673 bool SafeBrowsingBlockingPage::IsMainPageLoadBlocked(
674     const UnsafeResourceList& unsafe_resources) {
675   // Client-side phishing detection interstitials never block the main frame
676   // load, since they happen after the page is finished loading.
677   if (unsafe_resources[0].threat_type ==
678       SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL) {
679     return false;
680   }
681 
682   // Otherwise, check the threat type.
683   return unsafe_resources.size() == 1 && !unsafe_resources[0].is_subresource;
684 }
685 
GetHTMLContents()686 std::string SafeBrowsingBlockingPage::GetHTMLContents() {
687   DCHECK(!unsafe_resources_.empty());
688 
689   // Fill in the shared values.
690   base::DictionaryValue load_time_data;
691   webui::SetFontAndTextDirection(&load_time_data);
692   load_time_data.SetBoolean("ssl", false);
693   load_time_data.SetString(
694       "tabTitle", l10n_util::GetStringUTF16(IDS_SAFEBROWSING_V3_TITLE));
695   load_time_data.SetString(
696       "openDetails",
697       l10n_util::GetStringUTF16(IDS_SAFEBROWSING_V3_OPEN_DETAILS_BUTTON));
698   load_time_data.SetString(
699       "closeDetails",
700       l10n_util::GetStringUTF16(IDS_SAFEBROWSING_V3_CLOSE_DETAILS_BUTTON));
701   load_time_data.SetString(
702       "primaryButtonText",
703       l10n_util::GetStringUTF16(IDS_SAFEBROWSING_OVERRIDABLE_SAFETY_BUTTON));
704   load_time_data.SetBoolean(
705       "overridable",
706       !IsPrefEnabled(prefs::kSafeBrowsingProceedAnywayDisabled));
707 
708   switch (interstitial_type_) {
709     case TYPE_MALWARE:
710       PopulateMalwareLoadTimeData(&load_time_data);
711       break;
712     case TYPE_HARMFUL:
713       PopulateHarmfulLoadTimeData(&load_time_data);
714       break;
715     case TYPE_PHISHING:
716       PopulatePhishingLoadTimeData(&load_time_data);
717       break;
718   }
719 
720   base::StringPiece html(
721       ResourceBundle::GetSharedInstance().GetRawDataResource(
722           IRD_SECURITY_INTERSTITIAL_HTML));
723   webui::UseVersion2 version;
724   return webui::GetI18nTemplateHtml(html, &load_time_data);
725 }
726 
PopulateMalwareLoadTimeData(base::DictionaryValue * load_time_data)727 void SafeBrowsingBlockingPage::PopulateMalwareLoadTimeData(
728     base::DictionaryValue* load_time_data) {
729   load_time_data->SetBoolean("phishing", false);
730   load_time_data->SetString(
731       "heading", l10n_util::GetStringUTF16(IDS_MALWARE_V3_HEADING));
732   load_time_data->SetString(
733       "primaryParagraph",
734       l10n_util::GetStringFUTF16(
735           IDS_MALWARE_V3_PRIMARY_PARAGRAPH,
736           base::UTF8ToUTF16(url_.host())));
737   load_time_data->SetString(
738       "explanationParagraph",
739       is_main_frame_load_blocked_ ?
740           l10n_util::GetStringFUTF16(
741               IDS_MALWARE_V3_EXPLANATION_PARAGRAPH,
742               base::UTF8ToUTF16(url_.host())) :
743           l10n_util::GetStringFUTF16(
744               IDS_MALWARE_V3_EXPLANATION_PARAGRAPH_SUBRESOURCE,
745               base::UTF8ToUTF16(web_contents_->GetURL().host()),
746               base::UTF8ToUTF16(url_.host())));
747   load_time_data->SetString(
748       "finalParagraph",
749       l10n_util::GetStringUTF16(IDS_MALWARE_V3_PROCEED_PARAGRAPH));
750 
751   load_time_data->SetBoolean(kDisplayCheckBox, CanShowMalwareDetailsOption());
752   if (CanShowMalwareDetailsOption()) {
753     std::string privacy_link = base::StringPrintf(
754         kPrivacyLinkHtml,
755         l10n_util::GetStringUTF8(
756             IDS_SAFE_BROWSING_PRIVACY_POLICY_PAGE).c_str());
757     load_time_data->SetString(
758         "optInLink",
759         l10n_util::GetStringFUTF16(IDS_SAFE_BROWSING_MALWARE_REPORTING_AGREE,
760                                    base::UTF8ToUTF16(privacy_link)));
761     load_time_data->SetBoolean(
762         kBoxChecked,
763         IsPrefEnabled(prefs::kSafeBrowsingExtendedReportingEnabled));
764   }
765 }
766 
PopulateHarmfulLoadTimeData(base::DictionaryValue * load_time_data)767 void SafeBrowsingBlockingPage::PopulateHarmfulLoadTimeData(
768     base::DictionaryValue* load_time_data) {
769   load_time_data->SetBoolean("phishing", false);
770   load_time_data->SetString(
771       "heading", l10n_util::GetStringUTF16(IDS_HARMFUL_V3_HEADING));
772   load_time_data->SetString(
773       "primaryParagraph",
774       l10n_util::GetStringFUTF16(
775           IDS_HARMFUL_V3_PRIMARY_PARAGRAPH,
776           base::UTF8ToUTF16(url_.host())));
777   load_time_data->SetString(
778       "explanationParagraph",
779       l10n_util::GetStringFUTF16(
780           IDS_HARMFUL_V3_EXPLANATION_PARAGRAPH,
781           base::UTF8ToUTF16(url_.host())));
782   load_time_data->SetString(
783       "finalParagraph",
784       l10n_util::GetStringUTF16(IDS_HARMFUL_V3_PROCEED_PARAGRAPH));
785 
786   load_time_data->SetBoolean(kDisplayCheckBox, CanShowMalwareDetailsOption());
787   if (CanShowMalwareDetailsOption()) {
788     std::string privacy_link = base::StringPrintf(
789         kPrivacyLinkHtml,
790         l10n_util::GetStringUTF8(
791             IDS_SAFE_BROWSING_PRIVACY_POLICY_PAGE).c_str());
792     load_time_data->SetString(
793         "optInLink",
794         l10n_util::GetStringFUTF16(IDS_SAFE_BROWSING_MALWARE_REPORTING_AGREE,
795                                    base::UTF8ToUTF16(privacy_link)));
796     load_time_data->SetBoolean(
797         kBoxChecked,
798         IsPrefEnabled(prefs::kSafeBrowsingExtendedReportingEnabled));
799   }
800 }
801 
PopulatePhishingLoadTimeData(base::DictionaryValue * load_time_data)802 void SafeBrowsingBlockingPage::PopulatePhishingLoadTimeData(
803     base::DictionaryValue* load_time_data) {
804   load_time_data->SetBoolean("phishing", true);
805   load_time_data->SetString(
806       "heading",
807       l10n_util::GetStringUTF16(IDS_PHISHING_V3_HEADING));
808   load_time_data->SetString(
809       "primaryParagraph",
810       l10n_util::GetStringFUTF16(
811           IDS_PHISHING_V3_PRIMARY_PARAGRAPH,
812           base::UTF8ToUTF16(url_.host())));
813   load_time_data->SetString(
814       "explanationParagraph",
815       l10n_util::GetStringFUTF16(IDS_PHISHING_V3_EXPLANATION_PARAGRAPH,
816                                  base::UTF8ToUTF16(url_.host())));
817   load_time_data->SetString(
818       "finalParagraph",
819       l10n_util::GetStringUTF16(IDS_PHISHING_V3_PROCEED_PARAGRAPH));
820 }
821