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