• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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/i18n/rtl.h"
12 #include "base/lazy_instance.h"
13 #include "base/string_number_conversions.h"
14 #include "base/utf_string_conversions.h"
15 #include "base/values.h"
16 #include "chrome/browser/browser_process.h"
17 #include "chrome/browser/dom_operation_notification_details.h"
18 #include "chrome/browser/google/google_util.h"
19 #include "chrome/browser/metrics/user_metrics.h"
20 #include "chrome/browser/prefs/pref_service.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/browser/safe_browsing/malware_details.h"
23 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
24 #include "chrome/browser/tab_contents/tab_util.h"
25 #include "chrome/browser/ui/webui/new_tab_ui.h"
26 #include "chrome/common/jstemplate_builder.h"
27 #include "chrome/common/pref_names.h"
28 #include "chrome/common/url_constants.h"
29 #include "content/browser/browser_thread.h"
30 #include "content/browser/tab_contents/navigation_controller.h"
31 #include "content/browser/tab_contents/navigation_entry.h"
32 #include "content/browser/tab_contents/tab_contents.h"
33 #include "grit/browser_resources.h"
34 #include "grit/generated_resources.h"
35 #include "grit/locale_settings.h"
36 #include "net/base/escape.h"
37 #include "ui/base/l10n/l10n_util.h"
38 #include "ui/base/resource/resource_bundle.h"
39 
40 // For malware interstitial pages, we link the problematic URL to Google's
41 // diagnostic page.
42 #if defined(GOOGLE_CHROME_BUILD)
43 static const char* const kSbDiagnosticUrl =
44     "http://safebrowsing.clients.google.com/safebrowsing/diagnostic?site=%s&client=googlechrome";
45 #else
46 static const char* const kSbDiagnosticUrl =
47     "http://safebrowsing.clients.google.com/safebrowsing/diagnostic?site=%s&client=chromium";
48 #endif
49 
50 static const char* const kSbReportPhishingUrl =
51     "http://www.google.com/safebrowsing/report_error/";
52 
53 // URL for the "Learn more" link on the multi threat malware blocking page.
54 static const char* const kLearnMoreMalwareUrl =
55     "https://www.google.com/support/bin/answer.py?answer=45449&topic=360"
56     "&sa=X&oi=malwarewarninglink&resnum=1&ct=help";
57 
58 // URL for the "Learn more" link on the phishing blocking page.
59 static const char* const kLearnMorePhishingUrl =
60     "https://www.google.com/support/bin/answer.py?answer=106318";
61 
62 // URL for the "Safe Browsing Privacy Policies" link on the blocking page.
63 // Note: this page is not yet localized.
64 static const char* const kSbPrivacyPolicyUrl =
65     "http://www.google.com/intl/en_us/privacy/browsing.html";
66 
67 static const char* const kSbDiagnosticHtml =
68     "<a href=\"\" onclick=\"sendCommand('showDiagnostic'); return false;\" "
69     "onmousedown=\"return false;\">%s</a>";
70 
71 static const char* const kPLinkHtml =
72     "<a href=\"\" onclick=\"sendCommand('proceed'); return false;\" "
73     "onmousedown=\"return false;\">%s</a>";
74 
75 static const char* const kPrivacyLinkHtml =
76     "<a href=\"\" onclick=\"sendCommand('showPrivacy'); return false;\" "
77     "onmousedown=\"return false;\">%s</a>";
78 
79 // The commands returned by the page when the user performs an action.
80 static const char* const kShowDiagnosticCommand = "showDiagnostic";
81 static const char* const kReportErrorCommand = "reportError";
82 static const char* const kLearnMoreCommand = "learnMore";
83 static const char* const kShowPrivacyCommand = "showPrivacy";
84 static const char* const kProceedCommand = "proceed";
85 static const char* const kTakeMeBackCommand = "takeMeBack";
86 static const char* const kDoReportCommand = "doReport";
87 static const char* const kDontReportCommand = "dontReport";
88 static const char* const kDisplayCheckBox = "displaycheckbox";
89 static const char* const kBoxChecked = "boxchecked";
90 
91 // static
92 SafeBrowsingBlockingPageFactory* SafeBrowsingBlockingPage::factory_ = NULL;
93 
94 static base::LazyInstance<SafeBrowsingBlockingPage::UnsafeResourceMap>
95     g_unsafe_resource_map(base::LINKER_INITIALIZED);
96 
97 // The default SafeBrowsingBlockingPageFactory.  Global, made a singleton so we
98 // don't leak it.
99 class SafeBrowsingBlockingPageFactoryImpl
100     : public SafeBrowsingBlockingPageFactory {
101  public:
CreateSafeBrowsingPage(SafeBrowsingService * service,TabContents * tab_contents,const SafeBrowsingBlockingPage::UnsafeResourceList & unsafe_resources)102   SafeBrowsingBlockingPage* CreateSafeBrowsingPage(
103       SafeBrowsingService* service,
104       TabContents* tab_contents,
105       const SafeBrowsingBlockingPage::UnsafeResourceList& unsafe_resources) {
106     return new SafeBrowsingBlockingPage(service, tab_contents,
107                                         unsafe_resources);
108   }
109 
110  private:
111   friend struct base::DefaultLazyInstanceTraits<
112       SafeBrowsingBlockingPageFactoryImpl>;
113 
SafeBrowsingBlockingPageFactoryImpl()114   SafeBrowsingBlockingPageFactoryImpl() { }
115 
116   DISALLOW_COPY_AND_ASSIGN(SafeBrowsingBlockingPageFactoryImpl);
117 };
118 
119 static base::LazyInstance<SafeBrowsingBlockingPageFactoryImpl>
120     g_safe_browsing_blocking_page_factory_impl(base::LINKER_INITIALIZED);
121 
SafeBrowsingBlockingPage(SafeBrowsingService * sb_service,TabContents * tab_contents,const UnsafeResourceList & unsafe_resources)122 SafeBrowsingBlockingPage::SafeBrowsingBlockingPage(
123     SafeBrowsingService* sb_service,
124     TabContents* tab_contents,
125     const UnsafeResourceList& unsafe_resources)
126     : InterstitialPage(tab_contents,
127                        IsMainPage(unsafe_resources),
128                        unsafe_resources[0].url),
129       sb_service_(sb_service),
130       is_main_frame_(IsMainPage(unsafe_resources)),
131       unsafe_resources_(unsafe_resources) {
132   RecordUserAction(SHOW);
133   if (!is_main_frame_) {
134     navigation_entry_index_to_remove_ =
135         tab()->controller().last_committed_entry_index();
136   } else {
137     navigation_entry_index_to_remove_ = -1;
138   }
139 
140   // Start computing malware details. They will be sent only
141   // if the user opts-in on the blocking page later.
142   // If there's more than one malicious resources, it means the user
143   // clicked through the first warning, so we don't prepare additional
144   // reports.
145   if (unsafe_resources.size() == 1 &&
146       unsafe_resources[0].threat_type == SafeBrowsingService::URL_MALWARE &&
147       malware_details_ == NULL &&
148       CanShowMalwareDetailsOption()) {
149     malware_details_ = MalwareDetails::NewMalwareDetails(
150         sb_service_, tab(), unsafe_resources[0]);
151   }
152 }
153 
CanShowMalwareDetailsOption()154 bool SafeBrowsingBlockingPage::CanShowMalwareDetailsOption() {
155   return (!tab()->profile()->IsOffTheRecord() &&
156           tab()->GetURL().SchemeIs(chrome::kHttpScheme));
157 }
158 
~SafeBrowsingBlockingPage()159 SafeBrowsingBlockingPage::~SafeBrowsingBlockingPage() {
160 }
161 
GetHTMLContents()162 std::string SafeBrowsingBlockingPage::GetHTMLContents() {
163   // Load the HTML page and create the template components.
164   DictionaryValue strings;
165   ResourceBundle& rb = ResourceBundle::GetSharedInstance();
166   std::string html;
167 
168   if (unsafe_resources_.empty()) {
169     NOTREACHED();
170     return std::string();
171   }
172 
173   if (unsafe_resources_.size() > 1) {
174     PopulateMultipleThreatStringDictionary(&strings);
175     html = rb.GetRawDataResource(
176         IDR_SAFE_BROWSING_MULTIPLE_THREAT_BLOCK).as_string();
177   } else if (unsafe_resources_[0].threat_type ==
178              SafeBrowsingService::URL_MALWARE) {
179     PopulateMalwareStringDictionary(&strings);
180     html = rb.GetRawDataResource(IDR_SAFE_BROWSING_MALWARE_BLOCK).as_string();
181   } else {  // Phishing.
182     DCHECK(unsafe_resources_[0].threat_type ==
183            SafeBrowsingService::URL_PHISHING);
184     PopulatePhishingStringDictionary(&strings);
185     html = rb.GetRawDataResource(IDR_SAFE_BROWSING_PHISHING_BLOCK).as_string();
186   }
187 
188   return jstemplate_builder::GetTemplatesHtml(html, &strings, "template_root");
189 }
190 
PopulateStringDictionary(DictionaryValue * strings,const string16 & title,const string16 & headline,const string16 & description1,const string16 & description2,const string16 & description3)191 void SafeBrowsingBlockingPage::PopulateStringDictionary(
192     DictionaryValue* strings,
193     const string16& title,
194     const string16& headline,
195     const string16& description1,
196     const string16& description2,
197     const string16& description3) {
198   strings->SetString("title", title);
199   strings->SetString("headLine", headline);
200   strings->SetString("description1", description1);
201   strings->SetString("description2", description2);
202   strings->SetString("description3", description3);
203 }
204 
PopulateMultipleThreatStringDictionary(DictionaryValue * strings)205 void SafeBrowsingBlockingPage::PopulateMultipleThreatStringDictionary(
206     DictionaryValue* strings) {
207   bool malware = false;
208   bool phishing = false;
209 
210   string16 malware_label =
211       l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_LABEL);
212   string16 malware_link =
213       l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_DIAGNOSTIC_PAGE);
214   string16 phishing_label =
215       l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PHISHING_LABEL);
216   string16 phishing_link =
217       l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PHISHING_REPORT_ERROR);
218 
219   ListValue* error_strings = new ListValue;
220   for (UnsafeResourceList::const_iterator iter = unsafe_resources_.begin();
221        iter != unsafe_resources_.end(); ++iter) {
222     const SafeBrowsingService::UnsafeResource& resource = *iter;
223     DictionaryValue* current_error_strings = new DictionaryValue;
224     if (resource.threat_type == SafeBrowsingService::URL_MALWARE) {
225       malware = true;
226       current_error_strings->SetString("type", "malware");
227       current_error_strings->SetString("typeLabel", malware_label);
228       current_error_strings->SetString("errorLink", malware_link);
229     } else {
230       DCHECK(resource.threat_type == SafeBrowsingService::URL_PHISHING);
231       phishing = true;
232       current_error_strings->SetString("type", "phishing");
233       current_error_strings->SetString("typeLabel", phishing_label);
234       current_error_strings->SetString("errorLink", phishing_link);
235     }
236     current_error_strings->SetString("url", resource.url.spec());
237     error_strings->Append(current_error_strings);
238   }
239   strings->Set("errors", error_strings);
240   DCHECK(phishing || malware);
241 
242   if (malware && phishing) {
243     PopulateStringDictionary(
244         strings,
245         // Use the malware headline, it is the scariest one.
246         l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MULTI_THREAT_TITLE),
247         l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_HEADLINE),
248         l10n_util::GetStringFUTF16(IDS_SAFE_BROWSING_MULTI_THREAT_DESCRIPTION1,
249                                    UTF8ToUTF16(tab()->GetURL().host())),
250         l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MULTI_THREAT_DESCRIPTION2),
251         string16());
252   } else if (malware) {
253     // Just malware.
254     PopulateStringDictionary(
255         strings,
256         l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_TITLE),
257         l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_HEADLINE),
258         l10n_util::GetStringFUTF16(IDS_SAFE_BROWSING_MULTI_MALWARE_DESCRIPTION1,
259                                    UTF8ToUTF16(tab()->GetURL().host())),
260         l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MULTI_MALWARE_DESCRIPTION2),
261         l10n_util::GetStringUTF16(
262             IDS_SAFE_BROWSING_MULTI_MALWARE_DESCRIPTION3));
263   } else {
264     // Just phishing.
265     PopulateStringDictionary(
266         strings,
267         l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PHISHING_TITLE),
268         l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PHISHING_HEADLINE),
269         l10n_util::GetStringFUTF16(
270             IDS_SAFE_BROWSING_MULTI_PHISHING_DESCRIPTION1,
271             UTF8ToUTF16(tab()->GetURL().host())),
272         string16(),
273         string16());
274   }
275 
276   strings->SetString("confirm_text",
277                      l10n_util::GetStringUTF16(
278                          IDS_SAFE_BROWSING_MULTI_MALWARE_DESCRIPTION_AGREE));
279   strings->SetString("continue_button",
280                      l10n_util::GetStringUTF16(
281                          IDS_SAFE_BROWSING_MULTI_MALWARE_PROCEED_BUTTON));
282   strings->SetString("back_button",
283       l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_BACK_BUTTON));
284   strings->SetString("textdirection", base::i18n::IsRTL() ? "rtl" : "ltr");
285 }
286 
PopulateMalwareStringDictionary(DictionaryValue * strings)287 void SafeBrowsingBlockingPage::PopulateMalwareStringDictionary(
288     DictionaryValue* strings) {
289   std::string diagnostic_link = StringPrintf(kSbDiagnosticHtml,
290       l10n_util::GetStringUTF8(
291         IDS_SAFE_BROWSING_MALWARE_DIAGNOSTIC_PAGE).c_str());
292 
293   strings->SetString("badURL", url().host());
294   // Check to see if we're blocking the main page, or a sub-resource on the
295   // main page.
296   string16 description1, description3, description5;
297   if (is_main_frame_) {
298     description1 = l10n_util::GetStringFUTF16(
299         IDS_SAFE_BROWSING_MALWARE_DESCRIPTION1, UTF8ToUTF16(url().host()));
300   } else {
301     description1 = l10n_util::GetStringFUTF16(
302         IDS_SAFE_BROWSING_MALWARE_DESCRIPTION4,
303         UTF8ToUTF16(tab()->GetURL().host()),
304         UTF8ToUTF16(url().host()));
305   }
306 
307   std::string proceed_link = StringPrintf(kPLinkHtml,
308       l10n_util::GetStringUTF8(IDS_SAFE_BROWSING_MALWARE_PROCEED_LINK).c_str());
309   description3 =
310       l10n_util::GetStringFUTF16(IDS_SAFE_BROWSING_MALWARE_DESCRIPTION3,
311                                  UTF8ToUTF16(proceed_link));
312 
313   PopulateStringDictionary(
314       strings,
315       l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_TITLE),
316       l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_HEADLINE),
317       description1,
318       l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_DESCRIPTION2),
319       description3);
320 
321   description5 =
322       l10n_util::GetStringFUTF16(IDS_SAFE_BROWSING_MALWARE_DESCRIPTION5,
323                                  UTF8ToUTF16(url().host()),
324                                  UTF8ToUTF16(url().host()),
325                                  UTF8ToUTF16(diagnostic_link));
326 
327   strings->SetString("description5", description5);
328 
329   strings->SetString("back_button",
330       l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_BACK_BUTTON));
331   strings->SetString("proceed_link",
332       l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_PROCEED_LINK));
333   strings->SetString("textdirection", base::i18n::IsRTL() ? "rtl" : "ltr");
334 
335   if (!CanShowMalwareDetailsOption()) {
336     strings->SetBoolean(kDisplayCheckBox, false);
337   } else {
338     // Show the checkbox for sending malware details.
339     strings->SetBoolean(kDisplayCheckBox, true);
340 
341     std::string privacy_link = StringPrintf(
342         kPrivacyLinkHtml,
343         l10n_util::GetStringUTF8(
344             IDS_SAFE_BROWSING_PRIVACY_POLICY_PAGE).c_str());
345 
346     strings->SetString("confirm_text",
347                        l10n_util::GetStringFUTF16(
348                            IDS_SAFE_BROWSING_MALWARE_REPORTING_AGREE,
349                            UTF8ToUTF16(privacy_link)));
350 
351     const PrefService::Preference* pref =
352         tab()->profile()->GetPrefs()->FindPreference(
353             prefs::kSafeBrowsingReportingEnabled);
354 
355     bool value;
356     if (pref && pref->GetValue()->GetAsBoolean(&value) && value) {
357       strings->SetString(kBoxChecked, "yes");
358     } else {
359       strings->SetString(kBoxChecked, "");
360     }
361   }
362 }
363 
PopulatePhishingStringDictionary(DictionaryValue * strings)364 void SafeBrowsingBlockingPage::PopulatePhishingStringDictionary(
365     DictionaryValue* strings) {
366   std::string proceed_link = StringPrintf(kPLinkHtml, l10n_util::GetStringUTF8(
367       IDS_SAFE_BROWSING_PHISHING_PROCEED_LINK).c_str());
368   string16 description3 = l10n_util::GetStringFUTF16(
369       IDS_SAFE_BROWSING_PHISHING_DESCRIPTION3,
370       UTF8ToUTF16(proceed_link));
371 
372   PopulateStringDictionary(
373       strings,
374       l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PHISHING_TITLE),
375       l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PHISHING_HEADLINE),
376       l10n_util::GetStringFUTF16(IDS_SAFE_BROWSING_PHISHING_DESCRIPTION1,
377                                  UTF8ToUTF16(url().host())),
378       l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PHISHING_DESCRIPTION2),
379       description3);
380 
381   strings->SetString("back_button",
382       l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PHISHING_BACK_BUTTON));
383   strings->SetString("report_error",
384       l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PHISHING_REPORT_ERROR));
385   strings->SetString("textdirection", base::i18n::IsRTL() ? "rtl" : "ltr");
386 }
387 
CommandReceived(const std::string & cmd)388 void SafeBrowsingBlockingPage::CommandReceived(const std::string& cmd) {
389   std::string command(cmd);  // Make a local copy so we can modify it.
390   // The Jasonified response has quotes, remove them.
391   if (command.length() > 1 && command[0] == '"') {
392     command = command.substr(1, command.length() - 2);
393   }
394 
395   if (command == kDoReportCommand) {
396     SetReportingPreference(true);
397     return;
398   }
399 
400   if (command == kDontReportCommand) {
401     SetReportingPreference(false);
402     return;
403   }
404 
405   if (command == kLearnMoreCommand) {
406     // User pressed "Learn more".
407     GURL url;
408     if (unsafe_resources_[0].threat_type == SafeBrowsingService::URL_MALWARE) {
409       url = google_util::AppendGoogleLocaleParam(GURL(kLearnMoreMalwareUrl));
410     } else if (unsafe_resources_[0].threat_type ==
411                SafeBrowsingService::URL_PHISHING) {
412       url = google_util::AppendGoogleLocaleParam(GURL(kLearnMorePhishingUrl));
413     } else {
414       NOTREACHED();
415     }
416     tab()->OpenURL(url, GURL(), CURRENT_TAB, PageTransition::LINK);
417     return;
418   }
419 
420   if (command == kShowPrivacyCommand) {
421     // User pressed "Safe Browsing privacy policy".
422     GURL url(kSbPrivacyPolicyUrl);
423     tab()->OpenURL(url, GURL(), CURRENT_TAB, PageTransition::LINK);
424     return;
425   }
426 
427   if (command == kProceedCommand) {
428     Proceed();
429     // We are deleted after this.
430     return;
431   }
432 
433   if (command == kTakeMeBackCommand) {
434     DontProceed();
435     // We are deleted after this.
436     return;
437   }
438 
439   // The "report error" and "show diagnostic" commands can have a number
440   // appended to them, which is the index of the element they apply to.
441   int element_index = 0;
442   size_t colon_index = command.find(':');
443   if (colon_index != std::string::npos) {
444     DCHECK(colon_index < command.size() - 1);
445     bool result = base::StringToInt(command.begin() + colon_index + 1,
446                                     command.end(),
447                                     &element_index);
448     command = command.substr(0, colon_index);
449     DCHECK(result);
450   }
451 
452   if (element_index >= static_cast<int>(unsafe_resources_.size())) {
453     NOTREACHED();
454     return;
455   }
456 
457   std::string bad_url_spec = unsafe_resources_[element_index].url.spec();
458   if (command == kReportErrorCommand) {
459     // User pressed "Report error" for a phishing site.
460     // Note that we cannot just put a link in the interstitial at this point.
461     // It is not OK to navigate in the context of an interstitial page.
462     DCHECK(unsafe_resources_[element_index].threat_type ==
463            SafeBrowsingService::URL_PHISHING);
464     GURL report_url =
465         safe_browsing_util::GeneratePhishingReportUrl(kSbReportPhishingUrl,
466                                                       bad_url_spec);
467     tab()->OpenURL(report_url, GURL(), CURRENT_TAB, PageTransition::LINK);
468     return;
469   }
470 
471   if (command == kShowDiagnosticCommand) {
472     // We're going to take the user to Google's SafeBrowsing diagnostic page.
473     std::string diagnostic =
474         StringPrintf(kSbDiagnosticUrl,
475                      EscapeQueryParamValue(bad_url_spec, true).c_str());
476     GURL diagnostic_url(diagnostic);
477     diagnostic_url = google_util::AppendGoogleLocaleParam(diagnostic_url);
478     DCHECK(unsafe_resources_[element_index].threat_type ==
479            SafeBrowsingService::URL_MALWARE);
480     tab()->OpenURL(diagnostic_url, GURL(), CURRENT_TAB, PageTransition::LINK);
481     return;
482   }
483 
484   NOTREACHED() << "Unexpected command: " << command;
485 }
486 
SetReportingPreference(bool report)487 void SafeBrowsingBlockingPage::SetReportingPreference(bool report) {
488   PrefService* pref = tab()->profile()->GetPrefs();
489   pref->SetBoolean(prefs::kSafeBrowsingReportingEnabled, report);
490 }
491 
Proceed()492 void SafeBrowsingBlockingPage::Proceed() {
493   RecordUserAction(PROCEED);
494   FinishMalwareDetails();  // Send the malware details, if we opted to.
495 
496   NotifySafeBrowsingService(sb_service_, unsafe_resources_, true);
497 
498   // Check to see if some new notifications of unsafe resources have been
499   // received while we were showing the interstitial.
500   UnsafeResourceMap* unsafe_resource_map = GetUnsafeResourcesMap();
501   UnsafeResourceMap::iterator iter = unsafe_resource_map->find(tab());
502   SafeBrowsingBlockingPage* blocking_page = NULL;
503   if (iter != unsafe_resource_map->end() && !iter->second.empty()) {
504     // Build an interstitial for all the unsafe resources notifications.
505     // Don't show it now as showing an interstitial while an interstitial is
506     // already showing would cause DontProceed() to be invoked.
507     blocking_page = factory_->CreateSafeBrowsingPage(sb_service_, tab(),
508                                                      iter->second);
509     unsafe_resource_map->erase(iter);
510   }
511 
512   InterstitialPage::Proceed();
513   // We are now deleted.
514 
515   // Now that this interstitial is gone, we can show the new one.
516   if (blocking_page)
517     blocking_page->Show();
518 }
519 
DontProceed()520 void SafeBrowsingBlockingPage::DontProceed() {
521   DCHECK(action_taken() != DONT_PROCEED_ACTION);
522   // We could have already called Proceed(), in which case we must not notify
523   // the SafeBrowsingService again, as the client has been deleted.
524   if (action_taken() == PROCEED_ACTION) {
525     // We still want to hide the interstitial page.
526     InterstitialPage::DontProceed();
527     // We are now deleted.
528     return;
529   }
530 
531   RecordUserAction(DONT_PROCEED);
532   FinishMalwareDetails();  // Send the malware details, if we opted to.
533 
534   NotifySafeBrowsingService(sb_service_, unsafe_resources_, false);
535 
536   // The user does not want to proceed, clear the queued unsafe resources
537   // notifications we received while the interstitial was showing.
538   UnsafeResourceMap* unsafe_resource_map = GetUnsafeResourcesMap();
539   UnsafeResourceMap::iterator iter = unsafe_resource_map->find(tab());
540   if (iter != unsafe_resource_map->end() && !iter->second.empty()) {
541     NotifySafeBrowsingService(sb_service_, iter->second, false);
542     unsafe_resource_map->erase(iter);
543   }
544 
545   // We don't remove the navigation entry if the tab is being destroyed as this
546   // would trigger a navigation that would cause trouble as the render view host
547   // for the tab has by then already been destroyed.
548   if (navigation_entry_index_to_remove_ != -1 && !tab()->is_being_destroyed()) {
549     tab()->controller().RemoveEntryAtIndex(navigation_entry_index_to_remove_,
550                                            GURL(chrome::kChromeUINewTabURL));
551     navigation_entry_index_to_remove_ = -1;
552   }
553   InterstitialPage::DontProceed();
554   // We are now deleted.
555 }
556 
RecordUserAction(BlockingPageEvent event)557 void SafeBrowsingBlockingPage::RecordUserAction(BlockingPageEvent event) {
558   // Determine the interstitial type from the blocked resources.
559   // This is the same logic that is used to actually construct the
560   // page contents; we can look at the title to see which type of
561   // interstitial is being displayed.
562   DictionaryValue strings;
563   PopulateMultipleThreatStringDictionary(&strings);
564 
565   string16 title;
566   DCHECK(strings.GetString("title", &title));
567 
568   std::string action = "SBInterstitial";
569   if (title ==
570           l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MULTI_THREAT_TITLE)) {
571     action.append("Multiple");
572   } else if (title ==
573                  l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_TITLE)) {
574     action.append("Malware");
575   } else {
576     DCHECK_EQ(title,
577               l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PHISHING_TITLE));
578     action.append("Phishing");
579   }
580 
581   switch (event) {
582     case SHOW:
583       action.append("Show");
584       break;
585     case PROCEED:
586       action.append("Proceed");
587       break;
588     case DONT_PROCEED:
589       action.append("DontProceed");
590       break;
591     default:
592       NOTREACHED() << "Unexpected event: " << event;
593   }
594 
595   UserMetrics::RecordComputedAction(action);
596 }
597 
FinishMalwareDetails()598 void SafeBrowsingBlockingPage::FinishMalwareDetails() {
599   if (malware_details_ == NULL)
600     return;  // Not all interstitials have malware details (eg phishing).
601 
602   const PrefService::Preference* pref =
603       tab()->profile()->GetPrefs()->FindPreference(
604           prefs::kSafeBrowsingReportingEnabled);
605 
606   bool value;
607   if (pref && pref->GetValue()->GetAsBoolean(&value) && value) {
608     // Finish the malware details collection, send it over.
609     BrowserThread::PostTask(
610         BrowserThread::IO, FROM_HERE,
611         NewRunnableMethod(
612             malware_details_.get(), &MalwareDetails::FinishCollection));
613   }
614 }
615 
616 // static
NotifySafeBrowsingService(SafeBrowsingService * sb_service,const UnsafeResourceList & unsafe_resources,bool proceed)617 void SafeBrowsingBlockingPage::NotifySafeBrowsingService(
618     SafeBrowsingService* sb_service,
619     const UnsafeResourceList& unsafe_resources,
620     bool proceed) {
621   BrowserThread::PostTask(
622       BrowserThread::IO, FROM_HERE,
623       NewRunnableMethod(
624           sb_service, &SafeBrowsingService::OnBlockingPageDone,
625           unsafe_resources, proceed));
626 }
627 
628 // static
629 SafeBrowsingBlockingPage::UnsafeResourceMap*
GetUnsafeResourcesMap()630     SafeBrowsingBlockingPage::GetUnsafeResourcesMap() {
631   return g_unsafe_resource_map.Pointer();
632 }
633 
634 // static
ShowBlockingPage(SafeBrowsingService * sb_service,const SafeBrowsingService::UnsafeResource & unsafe_resource)635 void SafeBrowsingBlockingPage::ShowBlockingPage(
636     SafeBrowsingService* sb_service,
637     const SafeBrowsingService::UnsafeResource& unsafe_resource) {
638   TabContents* tab_contents = tab_util::GetTabContentsByID(
639       unsafe_resource.render_process_host_id, unsafe_resource.render_view_id);
640 
641   InterstitialPage* interstitial =
642       InterstitialPage::GetInterstitialPage(tab_contents);
643   if (interstitial &&
644       unsafe_resource.resource_type == ResourceType::MAIN_FRAME) {
645     // There is already an interstitial showing and we are about to display a
646     // new one for the main frame. Just hide the current one, it is now
647     // irrelevent
648     interstitial->DontProceed();
649     interstitial = NULL;
650   }
651 
652   if (!interstitial) {
653     // There are no interstitial currently showing in that tab, go ahead and
654     // show this interstitial.
655     std::vector<SafeBrowsingService::UnsafeResource> resources;
656     resources.push_back(unsafe_resource);
657     // Set up the factory if this has not been done already (tests do that
658     // before this method is called).
659     if (!factory_)
660       factory_ = g_safe_browsing_blocking_page_factory_impl.Pointer();
661     SafeBrowsingBlockingPage* blocking_page =
662         factory_->CreateSafeBrowsingPage(sb_service, tab_contents, resources);
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)[tab_contents].push_back(unsafe_resource);
670 }
671 
672 // static
IsMainPage(const UnsafeResourceList & unsafe_resources)673 bool SafeBrowsingBlockingPage::IsMainPage(
674     const UnsafeResourceList& unsafe_resources) {
675   return unsafe_resources.size() == 1 &&
676          unsafe_resources[0].resource_type == ResourceType::MAIN_FRAME;
677 }
678