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