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 53using base::UserMetricsAction; 54using content::BrowserThread; 55using content::InterstitialPage; 56using content::OpenURLParams; 57using content::Referrer; 58using content::WebContents; 59 60#if defined(ENABLE_EXTENSIONS) 61using extensions::ExperienceSamplingEvent; 62#endif 63 64namespace { 65 66// For malware interstitial pages, we link the problematic URL to Google's 67// diagnostic page. 68#if defined(GOOGLE_CHROME_BUILD) 69const char* const kSbDiagnosticUrl = 70 "http://safebrowsing.clients.google.com/safebrowsing/diagnostic?site=%s&client=googlechrome"; 71#else 72const 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. 77const char kLearnMoreMalwareUrlV2[] = 78 "https://www.google.com/transparencyreport/safebrowsing/"; 79const char kLearnMorePhishingUrlV2[] = 80 "https://www.google.com/transparencyreport/safebrowsing/"; 81 82const 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). 90const int64 kMalwareDetailsProceedDelayMilliSeconds = 3000; 91 92// The commands returned by the page when the user performs an action. 93const char kDoReportCommand[] = "doReport"; 94const char kDontReportCommand[] = "dontReport"; 95const char kExpandedSeeMoreCommand[] = "expandedSeeMore"; 96const char kLearnMoreCommand[] = "learnMore2"; 97const char kProceedCommand[] = "proceed"; 98const char kShowDiagnosticCommand[] = "showDiagnostic"; 99const char kShowPrivacyCommand[] = "showPrivacy"; 100const char kTakeMeBackCommand[] = "takeMeBack"; 101 102// Other constants used to communicate with the JavaScript. 103const char kBoxChecked[] = "boxchecked"; 104const char kDisplayCheckBox[] = "displaycheckbox"; 105 106// Constants for the Experience Sampling instrumentation. 107#if defined(ENABLE_EXTENSIONS) 108const char kEventNameMalware[] = "safebrowsing_interstitial_"; 109const char kEventNameHarmful[] = "harmful_interstitial_"; 110const char kEventNamePhishing[] = "phishing_interstitial_"; 111const char kEventNameOther[] = "safebrowsing_other_interstitial_"; 112#endif 113 114base::LazyInstance<SafeBrowsingBlockingPage::UnsafeResourceMap> 115 g_unsafe_resource_map = LAZY_INSTANCE_INITIALIZER; 116 117} // namespace 118 119// static 120SafeBrowsingBlockingPageFactory* SafeBrowsingBlockingPage::factory_ = NULL; 121 122// The default SafeBrowsingBlockingPageFactory. Global, made a singleton so we 123// don't leak it. 124class 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 145static base::LazyInstance<SafeBrowsingBlockingPageFactoryImpl> 146 g_safe_browsing_blocking_page_factory_impl = LAZY_INSTANCE_INITIALIZER; 147 148SafeBrowsingBlockingPage::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 254bool SafeBrowsingBlockingPage::CanShowMalwareDetailsOption() { 255 return (!web_contents_->GetBrowserContext()->IsOffTheRecord() && 256 web_contents_->GetURL().SchemeIs(url::kHttpScheme)); 257} 258 259SafeBrowsingBlockingPage::~SafeBrowsingBlockingPage() { 260} 261 262void 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 397void SafeBrowsingBlockingPage::OverrideRendererPrefs( 398 content::RendererPreferences* prefs) { 399 Profile* profile = Profile::FromBrowserContext( 400 web_contents_->GetBrowserContext()); 401 renderer_preferences_util::UpdateFromSystemSettings(prefs, profile); 402 } 403 404void 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 412void 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 438void SafeBrowsingBlockingPage::DontCreateViewForTesting() { 439 create_view_ = false; 440} 441 442void 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 451void 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 490void SafeBrowsingBlockingPage::OnGotHistoryCount(bool success, 491 int num_visits, 492 base::Time first_visit) { 493 if (success) 494 num_visits_ = num_visits; 495} 496 497void 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 549void 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 587void 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 603bool SafeBrowsingBlockingPage::IsPrefEnabled(const char* pref) { 604 Profile* profile = 605 Profile::FromBrowserContext(web_contents_->GetBrowserContext()); 606 return profile->GetPrefs()->GetBoolean(pref); 607} 608 609// static 610void 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 621SafeBrowsingBlockingPage::UnsafeResourceMap* 622 SafeBrowsingBlockingPage::GetUnsafeResourcesMap() { 623 return g_unsafe_resource_map.Pointer(); 624} 625 626// static 627SafeBrowsingBlockingPage* 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 641void 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 673bool 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 686std::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 727void 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 767void 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 802void 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