• 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 "components/google/core/browser/google_util.h"
35 #include "content/public/browser/browser_thread.h"
36 #include "content/public/browser/interstitial_page.h"
37 #include "content/public/browser/navigation_controller.h"
38 #include "content/public/browser/user_metrics.h"
39 #include "content/public/browser/web_contents.h"
40 #include "grit/browser_resources.h"
41 #include "grit/chromium_strings.h"
42 #include "grit/generated_resources.h"
43 #include "grit/locale_settings.h"
44 #include "net/base/escape.h"
45 #include "ui/base/l10n/l10n_util.h"
46 #include "ui/base/resource/resource_bundle.h"
47 #include "ui/base/webui/jstemplate_builder.h"
48 #include "ui/base/webui/web_ui_util.h"
49 
50 using base::UserMetricsAction;
51 using content::BrowserThread;
52 using content::InterstitialPage;
53 using content::OpenURLParams;
54 using content::Referrer;
55 using content::WebContents;
56 
57 namespace {
58 
59 // For malware interstitial pages, we link the problematic URL to Google's
60 // diagnostic page.
61 #if defined(GOOGLE_CHROME_BUILD)
62 const char* const kSbDiagnosticUrl =
63     "http://safebrowsing.clients.google.com/safebrowsing/diagnostic?site=%s&client=googlechrome";
64 #else
65 const char* const kSbDiagnosticUrl =
66     "http://safebrowsing.clients.google.com/safebrowsing/diagnostic?site=%s&client=chromium";
67 #endif
68 
69 const char kSbReportPhishingErrorUrl[] =
70     "http://www.google.com/safebrowsing/report_error/";
71 
72 // URL for the "Learn more" link on the multi threat malware blocking page.
73 const char kLearnMoreMalwareUrl[] =
74     "https://www.google.com/support/bin/answer.py?answer=45449&topic=360"
75     "&sa=X&oi=malwarewarninglink&resnum=1&ct=help";
76 
77 // URL for malware and phishing, V2.
78 const char kLearnMoreMalwareUrlV2[] =
79     "https://www.google.com/transparencyreport/safebrowsing/";
80 const char kLearnMorePhishingUrlV2[] =
81     "https://www.google.com/transparencyreport/safebrowsing/";
82 
83 // URL for the "Learn more" link on the phishing blocking page.
84 const char kLearnMorePhishingUrl[] =
85     "https://www.google.com/support/bin/answer.py?answer=106318";
86 
87 const char kPrivacyLinkHtml[] =
88     "<a id=\"privacy-link\" href=\"\" onclick=\"sendCommand('showPrivacy'); "
89     "return false;\" onmousedown=\"return false;\">%s</a>";
90 
91 // After a malware interstitial where the user opted-in to the report
92 // but clicked "proceed anyway", we delay the call to
93 // MalwareDetails::FinishCollection() by this much time (in
94 // milliseconds).
95 const int64 kMalwareDetailsProceedDelayMilliSeconds = 3000;
96 
97 // The commands returned by the page when the user performs an action.
98 const char kDoReportCommand[] = "doReport";
99 const char kDontReportCommand[] = "dontReport";
100 const char kExpandedSeeMoreCommand[] = "expandedSeeMore";
101 const char kLearnMoreCommand[] = "learnMore";
102 const char kLearnMoreCommandV2[] = "learnMore2";
103 const char kProceedCommand[] = "proceed";
104 const char kReportErrorCommand[] = "reportError";
105 const char kShowDiagnosticCommand[] = "showDiagnostic";
106 const char kShowPrivacyCommand[] = "showPrivacy";
107 const char kTakeMeBackCommand[] = "takeMeBack";
108 // Special command that we use when the user navigated away from the
109 // page.  E.g., closed the tab or the window.  This is only used by
110 // RecordUserReactionTime.
111 const char kNavigatedAwayMetaCommand[] = "closed";
112 
113 // Other constants used to communicate with the JavaScript.
114 const char kBoxChecked[] = "boxchecked";
115 const char kDisplayCheckBox[] = "displaycheckbox";
116 
117 base::LazyInstance<SafeBrowsingBlockingPage::UnsafeResourceMap>
118     g_unsafe_resource_map = LAZY_INSTANCE_INITIALIZER;
119 
120 // This enum is used for a histogram.  Don't reorder, delete, or insert
121 // elements.  New elements should be added before MAX_ACTION only.
122 enum DetailedDecision {
123   MALWARE_SHOW_NEW_SITE = 0,
124   MALWARE_PROCEED_NEW_SITE,
125   MALWARE_SHOW_CROSS_SITE,
126   MALWARE_PROCEED_CROSS_SITE,
127   PHISHING_SHOW_NEW_SITE,
128   PHISHING_PROCEED_NEW_SITE,
129   PHISHING_SHOW_CROSS_SITE,
130   PHISHING_PROCEED_CROSS_SITE,
131   MAX_DETAILED_ACTION
132 };
133 
RecordDetailedUserAction(DetailedDecision decision)134 void RecordDetailedUserAction(DetailedDecision decision) {
135   UMA_HISTOGRAM_ENUMERATION("SB2.InterstitialActionDetails",
136                             decision,
137                             MAX_DETAILED_ACTION);
138 }
139 
140 // Constants for the M37 Finch trial.
141 const char kV3StudyName[]         = "MalwareInterstitialVersion";
142 const char kCondV2[]              = "V2";
143 const char kCondV3[]              = "V3";
144 const char kCondV3Advice[]        = "V3Advice";
145 const char kCondV3Social[]        = "V3Social";
146 const char kCondV3NotRecommend[]  = "V3NotRecommend";
147 const char kCondV3History[]       = "V3History";
148 
149 // Default to V3 unless a flag or field trial says otherwise. Flags override
150 // field trial settings.
GetTrialCondition()151 const char* GetTrialCondition() {
152   if (CommandLine::ForCurrentProcess()->HasSwitch(
153           switches::kMalwareInterstitialV2)) {
154     return kCondV2;
155   }
156   if (CommandLine::ForCurrentProcess()->HasSwitch(
157           switches::kMalwareInterstitialV3)) {
158     return kCondV3;
159   }
160   if (CommandLine::ForCurrentProcess()->HasSwitch(
161           switches::kMalwareInterstitialV3Advice)) {
162     return kCondV3Advice;
163   }
164   if (CommandLine::ForCurrentProcess()->HasSwitch(
165           switches::kMalwareInterstitialV3Social)) {
166     return kCondV3Social;
167   }
168   if (CommandLine::ForCurrentProcess()->HasSwitch(
169           switches::kMalwareInterstitialV3NotRecommend)) {
170     return kCondV3NotRecommend;
171   }
172   if (CommandLine::ForCurrentProcess()->HasSwitch(
173           switches::kMalwareInterstitialV3History)) {
174     return kCondV3History;
175   }
176 
177   // Make sure that the return value is one of the expected types instead of
178   // directly returning base::FieldTrialList::FindFullName.
179   if (base::FieldTrialList::FindFullName(kV3StudyName) == kCondV2)
180     return kCondV2;
181   if (base::FieldTrialList::FindFullName(kV3StudyName) == kCondV3)
182     return kCondV3;
183   if (base::FieldTrialList::FindFullName(kV3StudyName) == kCondV3Advice)
184     return kCondV3Advice;
185   if (base::FieldTrialList::FindFullName(kV3StudyName) == kCondV3Social)
186     return kCondV3Social;
187   if (base::FieldTrialList::FindFullName(kV3StudyName) == kCondV3NotRecommend)
188     return kCondV3NotRecommend;
189   if (base::FieldTrialList::FindFullName(kV3StudyName) == kCondV3History)
190     return kCondV3History;
191   return kCondV3;
192 }
193 
194 }  // namespace
195 
196 // static
197 SafeBrowsingBlockingPageFactory* SafeBrowsingBlockingPage::factory_ = NULL;
198 
199 // The default SafeBrowsingBlockingPageFactory.  Global, made a singleton so we
200 // don't leak it.
201 class SafeBrowsingBlockingPageFactoryImpl
202     : public SafeBrowsingBlockingPageFactory {
203  public:
CreateSafeBrowsingPage(SafeBrowsingUIManager * ui_manager,WebContents * web_contents,const SafeBrowsingBlockingPage::UnsafeResourceList & unsafe_resources)204   virtual SafeBrowsingBlockingPage* CreateSafeBrowsingPage(
205       SafeBrowsingUIManager* ui_manager,
206       WebContents* web_contents,
207       const SafeBrowsingBlockingPage::UnsafeResourceList& unsafe_resources)
208       OVERRIDE {
209     // Only use the V2 page if the interstitial is for a single malware or
210     // phishing resource, the multi-threat interstitial has not been updated to
211     // V2 yet.
212     if (unsafe_resources.size() == 1 &&
213         (unsafe_resources[0].threat_type == SB_THREAT_TYPE_URL_MALWARE ||
214          unsafe_resources[0].threat_type ==
215          SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL ||
216          unsafe_resources[0].threat_type == SB_THREAT_TYPE_URL_PHISHING ||
217          unsafe_resources[0].threat_type ==
218          SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL)) {
219       if (GetTrialCondition() == kCondV2) {
220         return new SafeBrowsingBlockingPageV2(ui_manager, web_contents,
221             unsafe_resources);
222       } else {
223         return new SafeBrowsingBlockingPageV3(ui_manager, web_contents,
224             unsafe_resources);
225       }
226     }
227     return new SafeBrowsingBlockingPageV1(ui_manager, web_contents,
228                                           unsafe_resources);
229   }
230 
231  private:
232   friend struct base::DefaultLazyInstanceTraits<
233       SafeBrowsingBlockingPageFactoryImpl>;
234 
SafeBrowsingBlockingPageFactoryImpl()235   SafeBrowsingBlockingPageFactoryImpl() { }
236 
237   DISALLOW_COPY_AND_ASSIGN(SafeBrowsingBlockingPageFactoryImpl);
238 };
239 
240 static base::LazyInstance<SafeBrowsingBlockingPageFactoryImpl>
241     g_safe_browsing_blocking_page_factory_impl = LAZY_INSTANCE_INITIALIZER;
242 
SafeBrowsingBlockingPage(SafeBrowsingUIManager * ui_manager,WebContents * web_contents,const UnsafeResourceList & unsafe_resources)243 SafeBrowsingBlockingPage::SafeBrowsingBlockingPage(
244     SafeBrowsingUIManager* ui_manager,
245     WebContents* web_contents,
246     const UnsafeResourceList& unsafe_resources)
247     : malware_details_proceed_delay_ms_(
248           kMalwareDetailsProceedDelayMilliSeconds),
249       ui_manager_(ui_manager),
250       report_loop_(NULL),
251       is_main_frame_load_blocked_(IsMainPageLoadBlocked(unsafe_resources)),
252       unsafe_resources_(unsafe_resources),
253       proceeded_(false),
254       web_contents_(web_contents),
255       url_(unsafe_resources[0].url),
256       has_expanded_see_more_section_(false),
257       reporting_checkbox_checked_(false),
258       num_visits_(-1) {
259   bool malware = false;
260   bool phishing = false;
261   for (UnsafeResourceList::const_iterator iter = unsafe_resources_.begin();
262        iter != unsafe_resources_.end(); ++iter) {
263     const UnsafeResource& resource = *iter;
264     SBThreatType threat_type = resource.threat_type;
265     if (threat_type == SB_THREAT_TYPE_URL_MALWARE ||
266         threat_type == SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL) {
267       malware = true;
268     } else {
269       DCHECK(threat_type == SB_THREAT_TYPE_URL_PHISHING ||
270              threat_type == SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL);
271       phishing = true;
272     }
273   }
274   DCHECK(phishing || malware);
275   if (malware && phishing)
276     interstitial_type_ = TYPE_MALWARE_AND_PHISHING;
277   else if (malware)
278     interstitial_type_ = TYPE_MALWARE;
279   else
280     interstitial_type_ = TYPE_PHISHING;
281 
282   RecordUserAction(SHOW);
283   HistoryService* history_service = HistoryServiceFactory::GetForProfile(
284           Profile::FromBrowserContext(web_contents->GetBrowserContext()),
285           Profile::EXPLICIT_ACCESS);
286   if (history_service) {
287     history_service->GetVisibleVisitCountToHost(
288         url_,
289         &request_consumer_,
290         base::Bind(&SafeBrowsingBlockingPage::OnGotHistoryCount,
291                   base::Unretained(this)));
292   }
293 
294   if (!is_main_frame_load_blocked_) {
295     navigation_entry_index_to_remove_ =
296         web_contents->GetController().GetLastCommittedEntryIndex();
297   } else {
298     navigation_entry_index_to_remove_ = -1;
299   }
300 
301   // Start computing malware details. They will be sent only
302   // if the user opts-in on the blocking page later.
303   // If there's more than one malicious resources, it means the user
304   // clicked through the first warning, so we don't prepare additional
305   // reports.
306   if (unsafe_resources.size() == 1 &&
307       unsafe_resources[0].threat_type == SB_THREAT_TYPE_URL_MALWARE &&
308       malware_details_.get() == NULL && CanShowMalwareDetailsOption()) {
309     malware_details_ = MalwareDetails::NewMalwareDetails(
310         ui_manager_, web_contents, unsafe_resources[0]);
311   }
312 
313   interstitial_page_ = InterstitialPage::Create(
314       web_contents, IsMainPageLoadBlocked(unsafe_resources), url_, this);
315 }
316 
CanShowMalwareDetailsOption()317 bool SafeBrowsingBlockingPage::CanShowMalwareDetailsOption() {
318   return (!web_contents_->GetBrowserContext()->IsOffTheRecord() &&
319           web_contents_->GetURL().SchemeIs(url::kHttpScheme));
320 }
321 
~SafeBrowsingBlockingPage()322 SafeBrowsingBlockingPage::~SafeBrowsingBlockingPage() {
323 }
324 
CommandReceived(const std::string & cmd)325 void SafeBrowsingBlockingPage::CommandReceived(const std::string& cmd) {
326   std::string command(cmd);  // Make a local copy so we can modify it.
327   // The Jasonified response has quotes, remove them.
328   if (command.length() > 1 && command[0] == '"') {
329     command = command.substr(1, command.length() - 2);
330   }
331   RecordUserReactionTime(command);
332   if (command == kDoReportCommand) {
333     SetReportingPreference(true);
334     return;
335   }
336 
337   if (command == kDontReportCommand) {
338     SetReportingPreference(false);
339     return;
340   }
341 
342   if (command == kLearnMoreCommand) {
343     // User pressed "Learn more".
344     GURL url;
345     SBThreatType threat_type = unsafe_resources_[0].threat_type;
346     if (threat_type == SB_THREAT_TYPE_URL_MALWARE ||
347         threat_type == SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL) {
348       url = GURL(kLearnMoreMalwareUrl);
349     } else if (threat_type == SB_THREAT_TYPE_URL_PHISHING ||
350                threat_type == SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL) {
351       url = GURL(kLearnMorePhishingUrl);
352     } else {
353       NOTREACHED();
354     }
355 
356     OpenURLParams params(
357         url, Referrer(), CURRENT_TAB, content::PAGE_TRANSITION_LINK, false);
358     web_contents_->OpenURL(params);
359     return;
360   }
361 
362   if (command == kLearnMoreCommandV2) {
363     // User pressed "Learn more".
364     GURL url;
365     SBThreatType threat_type = unsafe_resources_[0].threat_type;
366     if (threat_type == SB_THREAT_TYPE_URL_MALWARE ||
367         threat_type == SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL) {
368       url = GURL(kLearnMoreMalwareUrlV2);
369     } else if (threat_type == SB_THREAT_TYPE_URL_PHISHING ||
370                threat_type == SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL) {
371       url = GURL(kLearnMorePhishingUrlV2);
372     } else {
373       NOTREACHED();
374     }
375 
376     OpenURLParams params(
377         url, Referrer(), CURRENT_TAB, content::PAGE_TRANSITION_LINK, false);
378     web_contents_->OpenURL(params);
379     return;
380   }
381 
382   if (command == kShowPrivacyCommand) {
383     // User pressed "Safe Browsing privacy policy".
384     GURL url(l10n_util::GetStringUTF8(IDS_SAFE_BROWSING_PRIVACY_POLICY_URL));
385     OpenURLParams params(
386         url, Referrer(), CURRENT_TAB, content::PAGE_TRANSITION_LINK, false);
387     web_contents_->OpenURL(params);
388     return;
389   }
390 
391   bool proceed_blocked = false;
392   if (command == kProceedCommand) {
393     if (IsPrefEnabled(prefs::kSafeBrowsingProceedAnywayDisabled)) {
394       proceed_blocked = true;
395     } else {
396       interstitial_page_->Proceed();
397       // |this| has been deleted after Proceed() returns.
398       return;
399     }
400   }
401 
402   if (command == kTakeMeBackCommand || proceed_blocked) {
403     if (is_main_frame_load_blocked_) {
404       // If the load is blocked, we want to close the interstitial and discard
405       // the pending entry.
406       interstitial_page_->DontProceed();
407       // |this| has been deleted after DontProceed() returns.
408       return;
409     }
410 
411     // Otherwise the offending entry has committed, and we need to go back or
412     // to a safe page.  We will close the interstitial when that page commits.
413     if (web_contents_->GetController().CanGoBack()) {
414       web_contents_->GetController().GoBack();
415     } else {
416       web_contents_->GetController().LoadURL(
417           GURL(chrome::kChromeUINewTabURL),
418           content::Referrer(),
419           content::PAGE_TRANSITION_AUTO_TOPLEVEL,
420           std::string());
421     }
422     return;
423   }
424 
425   // The "report error" and "show diagnostic" commands can have a number
426   // appended to them, which is the index of the element they apply to.
427   size_t element_index = 0;
428   size_t colon_index = command.find(':');
429   if (colon_index != std::string::npos) {
430     DCHECK(colon_index < command.size() - 1);
431     int result_int = 0;
432     bool result = base::StringToInt(base::StringPiece(command.begin() +
433                                                       colon_index + 1,
434                                                       command.end()),
435                                     &result_int);
436     command = command.substr(0, colon_index);
437     if (result)
438       element_index = static_cast<size_t>(result_int);
439   }
440 
441   if (element_index >= unsafe_resources_.size()) {
442     NOTREACHED();
443     return;
444   }
445 
446   std::string bad_url_spec = unsafe_resources_[element_index].url.spec();
447   if (command == kReportErrorCommand) {
448     // User pressed "Report error" for a phishing site.
449     // Note that we cannot just put a link in the interstitial at this point.
450     // It is not OK to navigate in the context of an interstitial page.
451     SBThreatType threat_type = unsafe_resources_[element_index].threat_type;
452     DCHECK(threat_type == SB_THREAT_TYPE_URL_PHISHING ||
453            threat_type == SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL);
454     GURL report_url =
455         safe_browsing_util::GeneratePhishingReportUrl(
456             kSbReportPhishingErrorUrl,
457             bad_url_spec,
458             threat_type == SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL);
459     OpenURLParams params(
460         report_url, Referrer(), CURRENT_TAB, content::PAGE_TRANSITION_LINK,
461         false);
462     web_contents_->OpenURL(params);
463     return;
464   }
465 
466   if (command == kShowDiagnosticCommand) {
467     // We're going to take the user to Google's SafeBrowsing diagnostic page.
468     std::string diagnostic =
469         base::StringPrintf(kSbDiagnosticUrl,
470             net::EscapeQueryParamValue(bad_url_spec, true).c_str());
471     GURL diagnostic_url(diagnostic);
472     diagnostic_url = google_util::AppendGoogleLocaleParam(
473         diagnostic_url, g_browser_process->GetApplicationLocale());
474     DCHECK(unsafe_resources_[element_index].threat_type ==
475            SB_THREAT_TYPE_URL_MALWARE ||
476            unsafe_resources_[element_index].threat_type ==
477            SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL);
478     OpenURLParams params(
479         diagnostic_url, Referrer(), CURRENT_TAB, content::PAGE_TRANSITION_LINK,
480         false);
481     web_contents_->OpenURL(params);
482     return;
483   }
484 
485   if (command == kExpandedSeeMoreCommand) {
486     // User expanded the "see more info" section of the page.  We don't actually
487     // do any action based on this, it's just so that RecordUserReactionTime can
488     // track it.
489     return;
490   }
491 
492   NOTREACHED() << "Unexpected command: " << command;
493 }
494 
OverrideRendererPrefs(content::RendererPreferences * prefs)495 void SafeBrowsingBlockingPage::OverrideRendererPrefs(
496       content::RendererPreferences* prefs) {
497   Profile* profile = Profile::FromBrowserContext(
498       web_contents_->GetBrowserContext());
499   renderer_preferences_util::UpdateFromSystemSettings(prefs, profile);
500  }
501 
SetReportingPreference(bool report)502 void SafeBrowsingBlockingPage::SetReportingPreference(bool report) {
503   Profile* profile = Profile::FromBrowserContext(
504       web_contents_->GetBrowserContext());
505   PrefService* pref = profile->GetPrefs();
506   pref->SetBoolean(prefs::kSafeBrowsingExtendedReportingEnabled, report);
507   UMA_HISTOGRAM_BOOLEAN("SB2.SetExtendedReportingEnabled", report);
508   reporting_checkbox_checked_ = report;
509   pref->ClearPref(prefs::kSafeBrowsingReportingEnabled);
510   pref->ClearPref(prefs::kSafeBrowsingDownloadFeedbackEnabled);
511 }
512 
513 // If the reporting checkbox was left checked on close, the new pref
514 // kSafeBrowsingExtendedReportingEnabled should be updated.
515 // TODO(felt): Remove this in M-39. crbug.com/384668
UpdateReportingPref()516 void SafeBrowsingBlockingPage::UpdateReportingPref() {
517   if (!reporting_checkbox_checked_)
518     return;
519   if (IsPrefEnabled(prefs::kSafeBrowsingExtendedReportingEnabled))
520     return;
521   Profile* profile = Profile::FromBrowserContext(
522       web_contents_->GetBrowserContext());
523   if (profile->GetPrefs()->HasPrefPath(
524       prefs::kSafeBrowsingExtendedReportingEnabled))
525     return;
526   SetReportingPreference(true);
527 }
528 
OnProceed()529 void SafeBrowsingBlockingPage::OnProceed() {
530   proceeded_ = true;
531   RecordUserAction(PROCEED);
532   UpdateReportingPref();
533   // Send the malware details, if we opted to.
534   FinishMalwareDetails(malware_details_proceed_delay_ms_);
535 
536   NotifySafeBrowsingUIManager(ui_manager_, unsafe_resources_, true);
537 
538   // Check to see if some new notifications of unsafe resources have been
539   // received while we were showing the interstitial.
540   UnsafeResourceMap* unsafe_resource_map = GetUnsafeResourcesMap();
541   UnsafeResourceMap::iterator iter = unsafe_resource_map->find(web_contents_);
542   SafeBrowsingBlockingPage* blocking_page = NULL;
543   if (iter != unsafe_resource_map->end() && !iter->second.empty()) {
544     // Build an interstitial for all the unsafe resources notifications.
545     // Don't show it now as showing an interstitial while an interstitial is
546     // already showing would cause DontProceed() to be invoked.
547     blocking_page = factory_->CreateSafeBrowsingPage(ui_manager_, web_contents_,
548                                                      iter->second);
549     unsafe_resource_map->erase(iter);
550   }
551 
552   // Now that this interstitial is gone, we can show the new one.
553   if (blocking_page)
554     blocking_page->interstitial_page_->Show();
555 }
556 
OnDontProceed()557 void SafeBrowsingBlockingPage::OnDontProceed() {
558   // Calling this method twice will not double-count.
559   RecordUserReactionTime(kNavigatedAwayMetaCommand);
560   // We could have already called Proceed(), in which case we must not notify
561   // the SafeBrowsingUIManager again, as the client has been deleted.
562   if (proceeded_)
563     return;
564 
565   RecordUserAction(DONT_PROCEED);
566   UpdateReportingPref();
567   // Send the malware details, if we opted to.
568   FinishMalwareDetails(0);  // No delay
569 
570   NotifySafeBrowsingUIManager(ui_manager_, unsafe_resources_, false);
571 
572   // The user does not want to proceed, clear the queued unsafe resources
573   // notifications we received while the interstitial was showing.
574   UnsafeResourceMap* unsafe_resource_map = GetUnsafeResourcesMap();
575   UnsafeResourceMap::iterator iter = unsafe_resource_map->find(web_contents_);
576   if (iter != unsafe_resource_map->end() && !iter->second.empty()) {
577     NotifySafeBrowsingUIManager(ui_manager_, iter->second, false);
578     unsafe_resource_map->erase(iter);
579   }
580 
581   // We don't remove the navigation entry if the tab is being destroyed as this
582   // would trigger a navigation that would cause trouble as the render view host
583   // for the tab has by then already been destroyed.  We also don't delete the
584   // current entry if it has been committed again, which is possible on a page
585   // that had a subresource warning.
586   int last_committed_index =
587       web_contents_->GetController().GetLastCommittedEntryIndex();
588   if (navigation_entry_index_to_remove_ != -1 &&
589       navigation_entry_index_to_remove_ != last_committed_index &&
590       !web_contents_->IsBeingDestroyed()) {
591     CHECK(web_contents_->GetController().RemoveEntryAtIndex(
592         navigation_entry_index_to_remove_));
593     navigation_entry_index_to_remove_ = -1;
594   }
595 }
596 
OnGotHistoryCount(HistoryService::Handle handle,bool success,int num_visits,base::Time first_visit)597 void SafeBrowsingBlockingPage::OnGotHistoryCount(HistoryService::Handle handle,
598                                                  bool success,
599                                                  int num_visits,
600                                                  base::Time first_visit) {
601   if (success)
602     num_visits_ = num_visits;
603 }
604 
RecordUserAction(BlockingPageEvent event)605 void SafeBrowsingBlockingPage::RecordUserAction(BlockingPageEvent event) {
606   // This enum is used for a histogram.  Don't reorder, delete, or insert
607   // elements.  New elements should be added before MAX_ACTION only.
608   enum {
609     MALWARE_SHOW = 0,
610     MALWARE_DONT_PROCEED,
611     MALWARE_FORCED_DONT_PROCEED,
612     MALWARE_PROCEED,
613     MULTIPLE_SHOW,
614     MULTIPLE_DONT_PROCEED,
615     MULTIPLE_FORCED_DONT_PROCEED,
616     MULTIPLE_PROCEED,
617     PHISHING_SHOW,
618     PHISHING_DONT_PROCEED,
619     PHISHING_FORCED_DONT_PROCEED,
620     PHISHING_PROCEED,
621     MALWARE_SHOW_ADVANCED,
622     MULTIPLE_SHOW_ADVANCED,
623     PHISHING_SHOW_ADVANCED,
624     MAX_ACTION
625   } histogram_action = MAX_ACTION;
626 
627   switch (event) {
628     case SHOW:
629       switch (interstitial_type_) {
630         case TYPE_MALWARE_AND_PHISHING:
631           histogram_action = MULTIPLE_SHOW;
632           break;
633         case TYPE_MALWARE:
634           histogram_action = MALWARE_SHOW;
635           break;
636         case TYPE_PHISHING:
637           histogram_action = PHISHING_SHOW;
638           break;
639       }
640       break;
641     case PROCEED:
642       switch (interstitial_type_) {
643         case TYPE_MALWARE_AND_PHISHING:
644           histogram_action = MULTIPLE_PROCEED;
645           break;
646         case TYPE_MALWARE:
647           histogram_action = MALWARE_PROCEED;
648           break;
649         case TYPE_PHISHING:
650           histogram_action = PHISHING_PROCEED;
651           break;
652       }
653       break;
654     case DONT_PROCEED:
655       if (IsPrefEnabled(prefs::kSafeBrowsingProceedAnywayDisabled)) {
656         switch (interstitial_type_) {
657           case TYPE_MALWARE_AND_PHISHING:
658             histogram_action = MULTIPLE_FORCED_DONT_PROCEED;
659             break;
660           case TYPE_MALWARE:
661             histogram_action = MALWARE_FORCED_DONT_PROCEED;
662             break;
663           case TYPE_PHISHING:
664             histogram_action = PHISHING_FORCED_DONT_PROCEED;
665             break;
666         }
667       } else {
668         switch (interstitial_type_) {
669           case TYPE_MALWARE_AND_PHISHING:
670             histogram_action = MULTIPLE_DONT_PROCEED;
671             break;
672           case TYPE_MALWARE:
673             histogram_action = MALWARE_DONT_PROCEED;
674             break;
675           case TYPE_PHISHING:
676             histogram_action = PHISHING_DONT_PROCEED;
677             break;
678         }
679       }
680       break;
681     case SHOW_ADVANCED:
682       switch (interstitial_type_) {
683         case TYPE_MALWARE_AND_PHISHING:
684           histogram_action = MULTIPLE_SHOW_ADVANCED;
685           break;
686         case TYPE_MALWARE:
687           histogram_action = MALWARE_SHOW_ADVANCED;
688           break;
689         case TYPE_PHISHING:
690           histogram_action = PHISHING_SHOW_ADVANCED;
691           break;
692       }
693       break;
694     default:
695       NOTREACHED() << "Unexpected event: " << event;
696   }
697   if (histogram_action == MAX_ACTION) {
698     NOTREACHED();
699   } else {
700     UMA_HISTOGRAM_ENUMERATION("SB2.InterstitialAction", histogram_action,
701                               MAX_ACTION);
702   }
703 
704   if (event == PROCEED || event == DONT_PROCEED) {
705     if (num_visits_ == 0 && interstitial_type_ != TYPE_MALWARE_AND_PHISHING) {
706       RecordDetailedUserAction((interstitial_type_ == TYPE_MALWARE) ?
707                                MALWARE_SHOW_NEW_SITE : PHISHING_SHOW_NEW_SITE);
708       if (event == PROCEED) {
709         RecordDetailedUserAction((interstitial_type_ == TYPE_MALWARE) ?
710             MALWARE_PROCEED_NEW_SITE : PHISHING_PROCEED_NEW_SITE);
711       }
712     }
713     if (unsafe_resources_[0].is_subresource &&
714         interstitial_type_ != TYPE_MALWARE_AND_PHISHING) {
715       RecordDetailedUserAction((interstitial_type_ == TYPE_MALWARE) ?
716           MALWARE_SHOW_CROSS_SITE : PHISHING_SHOW_CROSS_SITE);
717       if (event == PROCEED) {
718         RecordDetailedUserAction((interstitial_type_ == TYPE_MALWARE) ?
719             MALWARE_PROCEED_CROSS_SITE : PHISHING_PROCEED_CROSS_SITE);
720       }
721     }
722   }
723 
724   // TODO(felt): Get rid of the old interstitial histogram.
725   std::string action = "SBInterstitial";
726   switch (interstitial_type_) {
727     case TYPE_MALWARE_AND_PHISHING:
728       action.append("Multiple");
729       break;
730     case TYPE_MALWARE:
731       action.append("Malware");
732       break;
733     case TYPE_PHISHING:
734       action.append("Phishing");
735       break;
736   }
737 
738   switch (event) {
739     case SHOW:
740       action.append("Show");
741       break;
742     case PROCEED:
743       action.append("Proceed");
744       break;
745     case DONT_PROCEED:
746       if (IsPrefEnabled(prefs::kSafeBrowsingProceedAnywayDisabled))
747         action.append("ForcedDontProceed");
748       else
749         action.append("DontProceed");
750       break;
751     case SHOW_ADVANCED:
752       break;
753     default:
754       NOTREACHED() << "Unexpected event: " << event;
755   }
756 
757   content::RecordComputedAction(action);
758 }
759 
RecordUserReactionTime(const std::string & command)760 void SafeBrowsingBlockingPage::RecordUserReactionTime(
761     const std::string& command) {
762   if (interstitial_show_time_.is_null())
763     return;  // We already reported the user reaction time.
764   base::TimeDelta dt = base::TimeTicks::Now() - interstitial_show_time_;
765   DVLOG(1) << "User reaction time for command:" << command
766            << " on interstitial_type_:" << interstitial_type_
767            << " warning took " << dt.InMilliseconds() << "ms";
768   bool recorded = true;
769   if (interstitial_type_ == TYPE_MALWARE ||
770       interstitial_type_ == TYPE_MALWARE_AND_PHISHING) {
771     // There are six ways in which the malware interstitial can go
772     // away.  We handle all of them here but we group two together: closing the
773     // tag / browser window and clicking on the back button in the browser (not
774     // the big green button) are considered the same action.
775     if (command == kProceedCommand) {
776       UMA_HISTOGRAM_MEDIUM_TIMES("SB2.MalwareInterstitialTimeProceed", dt);
777     } else if (command == kTakeMeBackCommand) {
778       UMA_HISTOGRAM_MEDIUM_TIMES("SB2.MalwareInterstitialTimeTakeMeBack", dt);
779     } else if (command == kShowDiagnosticCommand) {
780       UMA_HISTOGRAM_MEDIUM_TIMES("SB2.MalwareInterstitialTimeDiagnostic", dt);
781     } else if (command == kShowPrivacyCommand) {
782       UMA_HISTOGRAM_MEDIUM_TIMES("SB2.MalwareInterstitialTimePrivacyPolicy",
783                                  dt);
784     } else if (command == kLearnMoreCommand || command == kLearnMoreCommandV2) {
785       UMA_HISTOGRAM_MEDIUM_TIMES("SB2.MalwareInterstitialLearnMore",
786                                  dt);
787     } else if (command == kNavigatedAwayMetaCommand) {
788       UMA_HISTOGRAM_MEDIUM_TIMES("SB2.MalwareInterstitialTimeClosed", dt);
789     } else if (command == kExpandedSeeMoreCommand) {
790       // Only record the expanded histogram once per display of the
791       // interstitial.
792       if (has_expanded_see_more_section_)
793         return;
794       RecordUserAction(SHOW_ADVANCED);
795       UMA_HISTOGRAM_MEDIUM_TIMES("SB2.MalwareInterstitialTimeExpandedSeeMore",
796                                  dt);
797       has_expanded_see_more_section_ = true;
798       // Expanding the "See More" section doesn't finish the interstitial, so
799       // don't mark the reaction time as recorded.
800       recorded = false;
801     } else {
802       recorded = false;
803     }
804   } else {
805     // Same as above but for phishing warnings.
806     if (command == kProceedCommand) {
807       UMA_HISTOGRAM_MEDIUM_TIMES("SB2.PhishingInterstitialTimeProceed", dt);
808     } else if (command == kTakeMeBackCommand) {
809       UMA_HISTOGRAM_MEDIUM_TIMES("SB2.PhishingInterstitialTimeTakeMeBack", dt);
810     } else if (command == kShowDiagnosticCommand) {
811       UMA_HISTOGRAM_MEDIUM_TIMES("SB2.PhishingInterstitialTimeReportError", dt);
812     } else if (command == kLearnMoreCommand || command == kLearnMoreCommandV2) {
813       UMA_HISTOGRAM_MEDIUM_TIMES("SB2.PhishingInterstitialTimeLearnMore", dt);
814     } else if (command == kNavigatedAwayMetaCommand) {
815       UMA_HISTOGRAM_MEDIUM_TIMES("SB2.PhishingInterstitialTimeClosed", dt);
816     } else if (command == kExpandedSeeMoreCommand) {
817       // Only record the expanded histogram once per display of the
818       // interstitial.
819       if (has_expanded_see_more_section_)
820         return;
821       RecordUserAction(SHOW_ADVANCED);
822       UMA_HISTOGRAM_MEDIUM_TIMES("SB2.PhishingInterstitialTimeExpandedSeeMore",
823                                  dt);
824       has_expanded_see_more_section_ = true;
825       // Expanding the "See More" section doesn't finish the interstitial, so
826       // don't mark the reaction time as recorded.
827       recorded = false;
828     } else {
829       recorded = false;
830     }
831   }
832   if (recorded)  // Making sure we don't double-count reaction times.
833     interstitial_show_time_ = base::TimeTicks();  //  Resets the show time.
834 }
835 
FinishMalwareDetails(int64 delay_ms)836 void SafeBrowsingBlockingPage::FinishMalwareDetails(int64 delay_ms) {
837   if (malware_details_.get() == NULL)
838     return;  // Not all interstitials have malware details (eg phishing).
839 
840   const bool enabled =
841       IsPrefEnabled(prefs::kSafeBrowsingExtendedReportingEnabled);
842   UMA_HISTOGRAM_BOOLEAN("SB2.ExtendedReportingIsEnabled", enabled);
843   if (enabled) {
844     // Finish the malware details collection, send it over.
845     BrowserThread::PostDelayedTask(
846         BrowserThread::IO, FROM_HERE,
847         base::Bind(&MalwareDetails::FinishCollection, malware_details_.get()),
848         base::TimeDelta::FromMilliseconds(delay_ms));
849   }
850 }
851 
IsPrefEnabled(const char * pref)852 bool SafeBrowsingBlockingPage::IsPrefEnabled(const char* pref) {
853   Profile* profile =
854       Profile::FromBrowserContext(web_contents_->GetBrowserContext());
855   return profile->GetPrefs()->GetBoolean(pref);
856 }
857 
858 // static
NotifySafeBrowsingUIManager(SafeBrowsingUIManager * ui_manager,const UnsafeResourceList & unsafe_resources,bool proceed)859 void SafeBrowsingBlockingPage::NotifySafeBrowsingUIManager(
860     SafeBrowsingUIManager* ui_manager,
861     const UnsafeResourceList& unsafe_resources,
862     bool proceed) {
863   BrowserThread::PostTask(
864       BrowserThread::IO, FROM_HERE,
865       base::Bind(&SafeBrowsingUIManager::OnBlockingPageDone,
866                  ui_manager, unsafe_resources, proceed));
867 }
868 
869 // static
870 SafeBrowsingBlockingPage::UnsafeResourceMap*
GetUnsafeResourcesMap()871     SafeBrowsingBlockingPage::GetUnsafeResourcesMap() {
872   return g_unsafe_resource_map.Pointer();
873 }
874 
875 // static
ShowBlockingPage(SafeBrowsingUIManager * ui_manager,const UnsafeResource & unsafe_resource)876 void SafeBrowsingBlockingPage::ShowBlockingPage(
877     SafeBrowsingUIManager* ui_manager,
878     const UnsafeResource& unsafe_resource) {
879   DVLOG(1) << __FUNCTION__ << " " << unsafe_resource.url.spec();
880   WebContents* web_contents = tab_util::GetWebContentsByID(
881       unsafe_resource.render_process_host_id, unsafe_resource.render_view_id);
882 
883   InterstitialPage* interstitial =
884       InterstitialPage::GetInterstitialPage(web_contents);
885   if (interstitial && !unsafe_resource.is_subresource) {
886     // There is already an interstitial showing and we are about to display a
887     // new one for the main frame. Just hide the current one, it is now
888     // irrelevent
889     interstitial->DontProceed();
890     interstitial = NULL;
891   }
892 
893   if (!interstitial) {
894     // There are no interstitial currently showing in that tab, go ahead and
895     // show this interstitial.
896     std::vector<UnsafeResource> resources;
897     resources.push_back(unsafe_resource);
898     // Set up the factory if this has not been done already (tests do that
899     // before this method is called).
900     if (!factory_)
901       factory_ = g_safe_browsing_blocking_page_factory_impl.Pointer();
902     SafeBrowsingBlockingPage* blocking_page =
903         factory_->CreateSafeBrowsingPage(ui_manager, web_contents, resources);
904     blocking_page->interstitial_page_->Show();
905     return;
906   }
907 
908   // This is an interstitial for a page's resource, let's queue it.
909   UnsafeResourceMap* unsafe_resource_map = GetUnsafeResourcesMap();
910   (*unsafe_resource_map)[web_contents].push_back(unsafe_resource);
911 }
912 
913 // static
IsMainPageLoadBlocked(const UnsafeResourceList & unsafe_resources)914 bool SafeBrowsingBlockingPage::IsMainPageLoadBlocked(
915     const UnsafeResourceList& unsafe_resources) {
916   // Client-side phishing detection interstitials never block the main frame
917   // load, since they happen after the page is finished loading.
918   if (unsafe_resources[0].threat_type ==
919       SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL) {
920     return false;
921   }
922 
923   // Otherwise, check the threat type.
924   return unsafe_resources.size() == 1 && !unsafe_resources[0].is_subresource;
925 }
926 
SafeBrowsingBlockingPageV1(SafeBrowsingUIManager * ui_manager,WebContents * web_contents,const UnsafeResourceList & unsafe_resources)927 SafeBrowsingBlockingPageV1::SafeBrowsingBlockingPageV1(
928     SafeBrowsingUIManager* ui_manager,
929     WebContents* web_contents,
930     const UnsafeResourceList& unsafe_resources)
931   : SafeBrowsingBlockingPage(ui_manager, web_contents, unsafe_resources) {
932 }
933 
GetHTMLContents()934 std::string SafeBrowsingBlockingPageV1::GetHTMLContents() {
935   // Load the HTML page and create the template components.
936   base::DictionaryValue strings;
937   ResourceBundle& rb = ResourceBundle::GetSharedInstance();
938   std::string html;
939 
940   if (unsafe_resources_.empty()) {
941     NOTREACHED();
942     return std::string();
943   }
944 
945   DCHECK_GT(unsafe_resources_.size(), 1U);
946   PopulateMultipleThreatStringDictionary(&strings);
947   html = rb.GetRawDataResource(
948       IDR_SAFE_BROWSING_MULTIPLE_THREAT_BLOCK).as_string();
949   interstitial_show_time_ = base::TimeTicks::Now();
950   return webui::GetTemplatesHtml(html, &strings, "template_root");
951 }
952 
PopulateStringDictionary(base::DictionaryValue * strings,const base::string16 & title,const base::string16 & headline,const base::string16 & description1,const base::string16 & description2,const base::string16 & description3)953 void SafeBrowsingBlockingPageV1::PopulateStringDictionary(
954     base::DictionaryValue* strings,
955     const base::string16& title,
956     const base::string16& headline,
957     const base::string16& description1,
958     const base::string16& description2,
959     const base::string16& description3) {
960   strings->SetString("title", title);
961   strings->SetString("headLine", headline);
962   strings->SetString("description1", description1);
963   strings->SetString("description2", description2);
964   strings->SetString("description3", description3);
965   strings->SetBoolean("proceedDisabled",
966                       IsPrefEnabled(prefs::kSafeBrowsingProceedAnywayDisabled));
967 }
968 
PopulateMultipleThreatStringDictionary(base::DictionaryValue * strings)969 void SafeBrowsingBlockingPageV1::PopulateMultipleThreatStringDictionary(
970     base::DictionaryValue* strings) {
971 
972   base::string16 malware_label =
973       l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_LABEL);
974   base::string16 malware_link =
975       l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_DIAGNOSTIC_PAGE);
976   base::string16 phishing_label =
977       l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PHISHING_LABEL);
978   base::string16 phishing_link =
979       l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PHISHING_REPORT_ERROR);
980 
981   base::ListValue* error_strings = new base::ListValue;
982   for (UnsafeResourceList::const_iterator iter = unsafe_resources_.begin();
983        iter != unsafe_resources_.end(); ++iter) {
984     const UnsafeResource& resource = *iter;
985     SBThreatType threat_type = resource.threat_type;
986     base::DictionaryValue* current_error_strings = new base::DictionaryValue;
987     if (threat_type == SB_THREAT_TYPE_URL_MALWARE ||
988         threat_type == SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL) {
989       current_error_strings->SetString("type", "malware");
990       current_error_strings->SetString("typeLabel", malware_label);
991       current_error_strings->SetString("errorLink", malware_link);
992     } else {
993       DCHECK(threat_type == SB_THREAT_TYPE_URL_PHISHING ||
994              threat_type == SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL);
995       current_error_strings->SetString("type", "phishing");
996       current_error_strings->SetString("typeLabel", phishing_label);
997       current_error_strings->SetString("errorLink", phishing_link);
998     }
999     current_error_strings->SetString("url", resource.url.spec());
1000     error_strings->Append(current_error_strings);
1001   }
1002   strings->Set("errors", error_strings);
1003 
1004   switch (interstitial_type_) {
1005     case TYPE_MALWARE_AND_PHISHING:
1006       PopulateStringDictionary(
1007           strings,
1008           // Use the malware headline, it is the scariest one.
1009           l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MULTI_THREAT_TITLE),
1010           l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_HEADLINE),
1011           l10n_util::GetStringFUTF16(
1012               IDS_SAFE_BROWSING_MULTI_THREAT_DESCRIPTION1,
1013               base::UTF8ToUTF16(web_contents_->GetURL().host())),
1014           l10n_util::GetStringUTF16(
1015               IDS_SAFE_BROWSING_MULTI_THREAT_DESCRIPTION2),
1016           base::string16());
1017       break;
1018     case TYPE_MALWARE:
1019       PopulateStringDictionary(
1020           strings,
1021           l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_TITLE),
1022           l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_HEADLINE),
1023           l10n_util::GetStringFUTF16(
1024               IDS_SAFE_BROWSING_MULTI_MALWARE_DESCRIPTION1,
1025               base::UTF8ToUTF16(web_contents_->GetURL().host())),
1026           l10n_util::GetStringUTF16(
1027               IDS_SAFE_BROWSING_MULTI_MALWARE_DESCRIPTION2),
1028           l10n_util::GetStringUTF16(
1029               IDS_SAFE_BROWSING_MULTI_MALWARE_DESCRIPTION3));
1030       break;
1031     case TYPE_PHISHING:
1032       PopulateStringDictionary(
1033           strings,
1034           l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PHISHING_TITLE),
1035           l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PHISHING_HEADLINE),
1036           l10n_util::GetStringFUTF16(
1037               IDS_SAFE_BROWSING_MULTI_PHISHING_DESCRIPTION1,
1038               base::UTF8ToUTF16(web_contents_->GetURL().host())),
1039           base::string16(),
1040           base::string16());
1041       break;
1042   }
1043 
1044   strings->SetString("confirm_text",
1045                      l10n_util::GetStringUTF16(
1046                          IDS_SAFE_BROWSING_MULTI_MALWARE_DESCRIPTION_AGREE));
1047   strings->SetString("continue_button",
1048                      l10n_util::GetStringUTF16(
1049                          IDS_SAFE_BROWSING_MULTI_MALWARE_PROCEED_BUTTON));
1050   strings->SetString("back_button",
1051       l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_BACK_BUTTON));
1052   strings->SetString("textdirection", base::i18n::IsRTL() ? "rtl" : "ltr");
1053 }
1054 
PopulateMalwareStringDictionary(base::DictionaryValue * strings)1055 void SafeBrowsingBlockingPageV1::PopulateMalwareStringDictionary(
1056     base::DictionaryValue* strings) {
1057   NOTREACHED();
1058 }
1059 
PopulatePhishingStringDictionary(base::DictionaryValue * strings)1060 void SafeBrowsingBlockingPageV1::PopulatePhishingStringDictionary(
1061     base::DictionaryValue* strings) {
1062   NOTREACHED();
1063 }
1064 
SafeBrowsingBlockingPageV2(SafeBrowsingUIManager * ui_manager,WebContents * web_contents,const UnsafeResourceList & unsafe_resources)1065 SafeBrowsingBlockingPageV2::SafeBrowsingBlockingPageV2(
1066     SafeBrowsingUIManager* ui_manager,
1067     WebContents* web_contents,
1068     const UnsafeResourceList& unsafe_resources)
1069   : SafeBrowsingBlockingPage(ui_manager, web_contents, unsafe_resources) {
1070 }
1071 
GetHTMLContents()1072 std::string SafeBrowsingBlockingPageV2::GetHTMLContents() {
1073   // Load the HTML page and create the template components.
1074   base::DictionaryValue strings;
1075   ResourceBundle& rb = ResourceBundle::GetSharedInstance();
1076   std::string html;
1077 
1078   if (unsafe_resources_.empty()) {
1079     NOTREACHED();
1080     return std::string();
1081   }
1082 
1083   if (unsafe_resources_.size() > 1) {
1084     // TODO(felt): Implement new multi-threat interstitial and remove
1085     // SafeBrowsingBlockingPageV1 entirely.  (http://crbug.com/160336)
1086     NOTREACHED();
1087   } else {
1088     SBThreatType threat_type = unsafe_resources_[0].threat_type;
1089     if (threat_type == SB_THREAT_TYPE_URL_MALWARE ||
1090         threat_type == SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL) {
1091       PopulateMalwareStringDictionary(&strings);
1092     } else {  // Phishing.
1093       DCHECK(threat_type == SB_THREAT_TYPE_URL_PHISHING ||
1094              threat_type == SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL);
1095       PopulatePhishingStringDictionary(&strings);
1096     }
1097     html = rb.GetRawDataResource(IDR_SAFE_BROWSING_MALWARE_BLOCK_V2).
1098         as_string();
1099   }
1100   interstitial_show_time_ = base::TimeTicks::Now();
1101   return webui::GetTemplatesHtml(html, &strings, "template-root");
1102 }
1103 
PopulateStringDictionary(base::DictionaryValue * strings,const base::string16 & title,const base::string16 & headline,const base::string16 & description1,const base::string16 & description2,const base::string16 & description3)1104 void SafeBrowsingBlockingPageV2::PopulateStringDictionary(
1105     base::DictionaryValue* strings,
1106     const base::string16& title,
1107     const base::string16& headline,
1108     const base::string16& description1,
1109     const base::string16& description2,
1110     const base::string16& description3) {
1111   strings->SetString("title", title);
1112   strings->SetString("headLine", headline);
1113   strings->SetString("description1", description1);
1114   strings->SetString("description2", description2);
1115   strings->SetString("description3", description3);
1116   strings->SetBoolean("proceedDisabled",
1117                       IsPrefEnabled(prefs::kSafeBrowsingProceedAnywayDisabled));
1118   strings->SetBoolean("isMainFrame", is_main_frame_load_blocked_);
1119   strings->SetBoolean("isPhishing", interstitial_type_ == TYPE_PHISHING);
1120 
1121   strings->SetString("back_button",
1122       l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_BACK_BUTTON));
1123   strings->SetString("seeMore", l10n_util::GetStringUTF16(
1124       IDS_SAFE_BROWSING_MALWARE_V2_SEE_MORE));
1125   strings->SetString("proceed",
1126       l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_V2_PROCEED_LINK));
1127   webui::SetFontAndTextDirection(strings);
1128 }
1129 
PopulateMultipleThreatStringDictionary(base::DictionaryValue * strings)1130 void SafeBrowsingBlockingPageV2::PopulateMultipleThreatStringDictionary(
1131     base::DictionaryValue* strings) {
1132   NOTREACHED();
1133 }
1134 
PopulateMalwareStringDictionary(base::DictionaryValue * strings)1135 void SafeBrowsingBlockingPageV2::PopulateMalwareStringDictionary(
1136     base::DictionaryValue* strings) {
1137   // Check to see if we're blocking the main page, or a sub-resource on the
1138   // main page.
1139   base::string16 headline, description1, description2, description3;
1140 
1141 
1142   description3 = l10n_util::GetStringUTF16(
1143       IDS_SAFE_BROWSING_MALWARE_V2_DESCRIPTION3);
1144   if (is_main_frame_load_blocked_) {
1145     headline = l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_V2_HEADLINE);
1146     description1 = l10n_util::GetStringFUTF16(
1147         IDS_SAFE_BROWSING_MALWARE_V2_DESCRIPTION1,
1148         l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
1149         base::UTF8ToUTF16(url_.host()));
1150     description2 = l10n_util::GetStringUTF16(
1151         IDS_SAFE_BROWSING_MALWARE_V2_DESCRIPTION2);
1152     strings->SetString("details", l10n_util::GetStringUTF16(
1153           IDS_SAFE_BROWSING_MALWARE_V2_DETAILS));
1154   } else {
1155     headline = l10n_util::GetStringUTF16(
1156         IDS_SAFE_BROWSING_MALWARE_V2_HEADLINE_SUBRESOURCE);
1157     description1 = l10n_util::GetStringFUTF16(
1158         IDS_SAFE_BROWSING_MALWARE_V2_DESCRIPTION1_SUBRESOURCE,
1159         l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
1160         base::UTF8ToUTF16(web_contents_->GetURL().host()));
1161     description2 = l10n_util::GetStringFUTF16(
1162         IDS_SAFE_BROWSING_MALWARE_V2_DESCRIPTION2_SUBRESOURCE,
1163         base::UTF8ToUTF16(url_.host()));
1164     strings->SetString("details", l10n_util::GetStringFUTF16(
1165           IDS_SAFE_BROWSING_MALWARE_V2_DETAILS_SUBRESOURCE,
1166           base::UTF8ToUTF16(url_.host())));
1167   }
1168 
1169   PopulateStringDictionary(
1170       strings,
1171       l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_V2_TITLE),
1172       headline,
1173       description1,
1174       description2,
1175       description3);
1176 
1177   if (!CanShowMalwareDetailsOption()) {
1178     strings->SetBoolean(kDisplayCheckBox, false);
1179     strings->SetString("confirm_text", std::string());
1180     strings->SetString(kBoxChecked, std::string());
1181   } else {
1182     // Show the checkbox for sending malware details.
1183     strings->SetBoolean(kDisplayCheckBox, true);
1184 
1185     std::string privacy_link = base::StringPrintf(
1186         kPrivacyLinkHtml,
1187         l10n_util::GetStringUTF8(
1188             IDS_SAFE_BROWSING_PRIVACY_POLICY_PAGE_V2).c_str());
1189 
1190     strings->SetString("confirm_text",
1191                        l10n_util::GetStringFUTF16(
1192                            IDS_SAFE_BROWSING_MALWARE_V2_REPORTING_AGREE,
1193                            base::UTF8ToUTF16(privacy_link)));
1194     Profile* profile = Profile::FromBrowserContext(
1195        web_contents_->GetBrowserContext());
1196     if (profile->GetPrefs()->HasPrefPath(
1197             prefs::kSafeBrowsingExtendedReportingEnabled)) {
1198       reporting_checkbox_checked_ =
1199           IsPrefEnabled(prefs::kSafeBrowsingExtendedReportingEnabled);
1200     } else if (IsPrefEnabled(prefs::kSafeBrowsingReportingEnabled) ||
1201          IsPrefEnabled(prefs::kSafeBrowsingDownloadFeedbackEnabled)) {
1202       reporting_checkbox_checked_ = true;
1203     }
1204     strings->SetString(kBoxChecked,
1205                        reporting_checkbox_checked_ ? "yes" : std::string());
1206   }
1207 
1208   strings->SetString("report_error", base::string16());
1209   strings->SetString("learnMore",
1210       l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_V2_LEARN_MORE));
1211 }
1212 
PopulatePhishingStringDictionary(base::DictionaryValue * strings)1213 void SafeBrowsingBlockingPageV2::PopulatePhishingStringDictionary(
1214     base::DictionaryValue* strings) {
1215   PopulateStringDictionary(
1216       strings,
1217       l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PHISHING_V2_TITLE),
1218       l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PHISHING_V2_HEADLINE),
1219       l10n_util::GetStringFUTF16(IDS_SAFE_BROWSING_PHISHING_V2_DESCRIPTION1,
1220                                  l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
1221                                  base::UTF8ToUTF16(url_.host())),
1222       base::string16(),
1223       l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PHISHING_V2_DESCRIPTION2));
1224 
1225   strings->SetString("details", std::string());
1226   strings->SetString("confirm_text", std::string());
1227   strings->SetString(kBoxChecked, std::string());
1228   strings->SetString(
1229       "report_error",
1230       l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PHISHING_V2_REPORT_ERROR));
1231   strings->SetBoolean(kDisplayCheckBox, false);
1232   strings->SetString("learnMore",
1233       l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_V2_LEARN_MORE));
1234 }
1235 
SafeBrowsingBlockingPageV3(SafeBrowsingUIManager * ui_manager,WebContents * web_contents,const UnsafeResourceList & unsafe_resources)1236 SafeBrowsingBlockingPageV3::SafeBrowsingBlockingPageV3(
1237     SafeBrowsingUIManager* ui_manager,
1238     WebContents* web_contents,
1239     const UnsafeResourceList& unsafe_resources)
1240     : SafeBrowsingBlockingPage(ui_manager, web_contents, unsafe_resources),
1241       trial_condition_(GetTrialCondition()) {
1242 }
1243 
GetHTMLContents()1244 std::string SafeBrowsingBlockingPageV3::GetHTMLContents() {
1245   if (unsafe_resources_.empty() || unsafe_resources_.size() > 1) {
1246     // TODO(felt): Implement new multi-threat interstitial. crbug.com/160336
1247     NOTIMPLEMENTED();
1248     return std::string();
1249   }
1250 
1251   // Fill in the shared values.
1252   base::DictionaryValue load_time_data;
1253   webui::SetFontAndTextDirection(&load_time_data);
1254   load_time_data.SetBoolean("ssl", false);
1255   load_time_data.SetString(
1256       "tabTitle", l10n_util::GetStringUTF16(IDS_SAFEBROWSING_V3_TITLE));
1257   load_time_data.SetString(
1258       "openDetails",
1259       l10n_util::GetStringUTF16(IDS_SAFEBROWSING_V3_OPEN_DETAILS_BUTTON));
1260   load_time_data.SetString(
1261       "closeDetails",
1262       l10n_util::GetStringUTF16(IDS_SAFEBROWSING_V3_CLOSE_DETAILS_BUTTON));
1263   load_time_data.SetString(
1264       "primaryButtonText",
1265       l10n_util::GetStringUTF16(IDS_SAFEBROWSING_OVERRIDABLE_SAFETY_BUTTON));
1266   load_time_data.SetBoolean(
1267       "overridable",
1268       !IsPrefEnabled(prefs::kSafeBrowsingProceedAnywayDisabled));
1269 
1270   // Fill in the values that are specific to malware or phishing.
1271   SBThreatType threat_type = unsafe_resources_[0].threat_type;
1272   switch (threat_type) {
1273     case SB_THREAT_TYPE_URL_MALWARE:
1274     case SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL:
1275       PopulateMalwareLoadTimeData(&load_time_data);
1276       break;
1277     case SB_THREAT_TYPE_URL_PHISHING:
1278     case SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL:
1279       PopulatePhishingLoadTimeData(&load_time_data);
1280       break;
1281     case SB_THREAT_TYPE_SAFE:
1282     case SB_THREAT_TYPE_BINARY_MALWARE_URL:
1283     case SB_THREAT_TYPE_EXTENSION:
1284       NOTREACHED();
1285   }
1286 
1287   interstitial_show_time_ = base::TimeTicks::Now();
1288 
1289   base::StringPiece html(
1290       ResourceBundle::GetSharedInstance().GetRawDataResource(
1291           IRD_SSL_INTERSTITIAL_V2_HTML));
1292   webui::UseVersion2 version;
1293   return webui::GetI18nTemplateHtml(html, &load_time_data);
1294 }
1295 
PopulateMalwareLoadTimeData(base::DictionaryValue * load_time_data)1296 void SafeBrowsingBlockingPageV3::PopulateMalwareLoadTimeData(
1297     base::DictionaryValue* load_time_data) {
1298   load_time_data->SetString("trialCondition", trial_condition_);
1299   load_time_data->SetBoolean("phishing", false);
1300   load_time_data->SetString(
1301       "heading", l10n_util::GetStringUTF16(IDS_MALWARE_V3_HEADING));
1302   load_time_data->SetString(
1303       "primaryParagraph",
1304       l10n_util::GetStringFUTF16(
1305           IDS_MALWARE_V3_PRIMARY_PARAGRAPH,
1306           base::UTF8ToUTF16(url_.host())));
1307   if (trial_condition_ == kCondV3History) {
1308     load_time_data->SetString(
1309         "explanationParagraph",
1310         is_main_frame_load_blocked_ ?
1311             l10n_util::GetStringFUTF16(
1312                 IDS_MALWARE_V3_EXPLANATION_PARAGRAPH_HISTORY,
1313                 base::UTF8ToUTF16(url_.host())) :
1314             l10n_util::GetStringFUTF16(
1315                 IDS_MALWARE_V3_EXPLANATION_PARAGRAPH_SUBRESOURCE_HISTORY,
1316                 base::UTF8ToUTF16(web_contents_->GetURL().host()),
1317                 base::UTF8ToUTF16(url_.host())));
1318   } else if (trial_condition_ == kCondV3Advice) {
1319     load_time_data->SetString(
1320         "explanationParagraph",
1321         is_main_frame_load_blocked_ ?
1322             l10n_util::GetStringFUTF16(
1323                 IDS_MALWARE_V3_EXPLANATION_PARAGRAPH_ADVICE,
1324                 base::UTF8ToUTF16(url_.host())) :
1325             l10n_util::GetStringFUTF16(
1326                 IDS_MALWARE_V3_EXPLANATION_PARAGRAPH_SUBRESOURCE_ADVICE,
1327                 base::UTF8ToUTF16(web_contents_->GetURL().host()),
1328                 base::UTF8ToUTF16(url_.host())));
1329     load_time_data->SetString(
1330         "adviceHeading",
1331         l10n_util::GetStringUTF16(IDS_MALWARE_V3_ADVICE_HEADING));
1332   } else {
1333     load_time_data->SetString(
1334         "explanationParagraph",
1335         is_main_frame_load_blocked_ ?
1336             l10n_util::GetStringFUTF16(
1337                 IDS_MALWARE_V3_EXPLANATION_PARAGRAPH,
1338                 base::UTF8ToUTF16(url_.host())) :
1339             l10n_util::GetStringFUTF16(
1340                 IDS_MALWARE_V3_EXPLANATION_PARAGRAPH_SUBRESOURCE,
1341                 base::UTF8ToUTF16(web_contents_->GetURL().host()),
1342                 base::UTF8ToUTF16(url_.host())));
1343   }
1344   if (trial_condition_ == kCondV3Social) {
1345     load_time_data->SetString(
1346         "finalParagraph",
1347         l10n_util::GetStringUTF16(IDS_MALWARE_V3_PROCEED_PARAGRAPH_SOCIAL));
1348   } else if (trial_condition_ == kCondV3NotRecommend) {
1349     load_time_data->SetString(
1350         "finalParagraph",
1351         l10n_util::GetStringUTF16(
1352             IDS_MALWARE_V3_PROCEED_PARAGRAPH_NOT_RECOMMEND));
1353   } else {
1354     load_time_data->SetString(
1355         "finalParagraph",
1356         l10n_util::GetStringUTF16(IDS_MALWARE_V3_PROCEED_PARAGRAPH));
1357   }
1358 
1359   load_time_data->SetBoolean(kDisplayCheckBox, CanShowMalwareDetailsOption());
1360   if (CanShowMalwareDetailsOption()) {
1361     std::string privacy_link = base::StringPrintf(
1362         kPrivacyLinkHtml,
1363         l10n_util::GetStringUTF8(
1364             IDS_SAFE_BROWSING_PRIVACY_POLICY_PAGE_V2).c_str());
1365     load_time_data->SetString(
1366         "optInLink",
1367         l10n_util::GetStringFUTF16(IDS_SAFE_BROWSING_MALWARE_V2_REPORTING_AGREE,
1368                                    base::UTF8ToUTF16(privacy_link)));
1369     Profile* profile = Profile::FromBrowserContext(
1370        web_contents_->GetBrowserContext());
1371     if (profile->GetPrefs()->HasPrefPath(
1372             prefs::kSafeBrowsingExtendedReportingEnabled)) {
1373       reporting_checkbox_checked_ =
1374           IsPrefEnabled(prefs::kSafeBrowsingExtendedReportingEnabled);
1375     } else if (IsPrefEnabled(prefs::kSafeBrowsingReportingEnabled) ||
1376          IsPrefEnabled(prefs::kSafeBrowsingDownloadFeedbackEnabled)) {
1377       reporting_checkbox_checked_ = true;
1378     }
1379     load_time_data->SetBoolean(
1380         kBoxChecked, reporting_checkbox_checked_);
1381   }
1382 }
1383 
PopulatePhishingLoadTimeData(base::DictionaryValue * load_time_data)1384 void SafeBrowsingBlockingPageV3::PopulatePhishingLoadTimeData(
1385     base::DictionaryValue* load_time_data) {
1386   load_time_data->SetString("trialCondition", std::string());
1387   load_time_data->SetBoolean("phishing", true);
1388   load_time_data->SetString(
1389       "heading",
1390       l10n_util::GetStringUTF16(IDS_PHISHING_V3_HEADING));
1391   load_time_data->SetString(
1392       "primaryParagraph",
1393       l10n_util::GetStringFUTF16(
1394           IDS_PHISHING_V3_PRIMARY_PARAGRAPH,
1395           base::UTF8ToUTF16(url_.host())));
1396   load_time_data->SetString(
1397       "explanationParagraph",
1398       l10n_util::GetStringFUTF16(IDS_PHISHING_V3_EXPLANATION_PARAGRAPH,
1399                                  base::UTF8ToUTF16(url_.host())));
1400   load_time_data->SetString(
1401       "finalParagraph",
1402       l10n_util::GetStringUTF16(IDS_PHISHING_V3_PROCEED_PARAGRAPH));
1403 }
1404