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: 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 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 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 154 bool SafeBrowsingBlockingPage::CanShowMalwareDetailsOption() { 155 return (!tab()->profile()->IsOffTheRecord() && 156 tab()->GetURL().SchemeIs(chrome::kHttpScheme)); 157 } 158 159 SafeBrowsingBlockingPage::~SafeBrowsingBlockingPage() { 160 } 161 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 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 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 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 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 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 487 void SafeBrowsingBlockingPage::SetReportingPreference(bool report) { 488 PrefService* pref = tab()->profile()->GetPrefs(); 489 pref->SetBoolean(prefs::kSafeBrowsingReportingEnabled, report); 490 } 491 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 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 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 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 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* 630 SafeBrowsingBlockingPage::GetUnsafeResourcesMap() { 631 return g_unsafe_resource_map.Pointer(); 632 } 633 634 // static 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 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