blob: 4cb3b1283b3e3c9098b32183d5d7fc513cd21c7c [file] [log] [blame]
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Implementation of the SafeBrowsingBlockingPage class.
#include "chrome/browser/safe_browsing/safe_browsing_blocking_page.h"
#include <string>
#include "base/bind.h"
#include "base/i18n/rtl.h"
#include "base/lazy_instance.h"
#include "base/string_number_conversions.h"
#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/dom_operation_notification_details.h"
#include "chrome/browser/google/google_util.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/safe_browsing/malware_details.h"
#include "chrome/browser/safe_browsing/safe_browsing_service.h"
#include "chrome/browser/tab_contents/tab_util.h"
#include "chrome/browser/ui/webui/ntp/new_tab_ui.h"
#include "chrome/common/jstemplate_builder.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "content/browser/browser_thread.h"
#include "content/browser/tab_contents/navigation_controller.h"
#include "content/browser/tab_contents/navigation_entry.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/browser/user_metrics.h"
#include "grit/browser_resources.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
#include "net/base/escape.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
// For malware interstitial pages, we link the problematic URL to Google's
// diagnostic page.
#if defined(GOOGLE_CHROME_BUILD)
static const char* const kSbDiagnosticUrl =
"http://safebrowsing.clients.google.com/safebrowsing/diagnostic?site=%s&client=googlechrome";
#else
static const char* const kSbDiagnosticUrl =
"http://safebrowsing.clients.google.com/safebrowsing/diagnostic?site=%s&client=chromium";
#endif
static const char* const kSbReportPhishingErrorUrl =
"http://www.google.com/safebrowsing/report_error/";
// URL for the "Learn more" link on the multi threat malware blocking page.
static const char* const kLearnMoreMalwareUrl =
"https://www.google.com/support/bin/answer.py?answer=45449&topic=360"
"&sa=X&oi=malwarewarninglink&resnum=1&ct=help";
// URL for the "Learn more" link on the phishing blocking page.
static const char* const kLearnMorePhishingUrl =
"https://www.google.com/support/bin/answer.py?answer=106318";
// URL for the "Safe Browsing Privacy Policies" link on the blocking page.
// Note: this page is not yet localized.
static const char* const kSbPrivacyPolicyUrl =
"http://www.google.com/intl/en_us/privacy/browsing.html";
static const char* const kSbDiagnosticHtml =
"<a href=\"\" onclick=\"sendCommand('showDiagnostic'); return false;\" "
"onmousedown=\"return false;\">%s</a>";
static const char* const kPLinkHtml =
"<a href=\"\" onclick=\"sendCommand('proceed'); return false;\" "
"onmousedown=\"return false;\">%s</a>";
static const char* const kPrivacyLinkHtml =
"<a href=\"\" onclick=\"sendCommand('showPrivacy'); return false;\" "
"onmousedown=\"return false;\">%s</a>";
// After a malware interstitial where the user opted-in to the report
// but clicked "proceed anyway", we delay the call to
// MalwareDetails::FinishCollection() by this much time (in
// milliseconds).
static const int64 kMalwareDetailsProceedDelayMilliSeconds = 3000;
// The commands returned by the page when the user performs an action.
static const char* const kShowDiagnosticCommand = "showDiagnostic";
static const char* const kReportErrorCommand = "reportError";
static const char* const kLearnMoreCommand = "learnMore";
static const char* const kShowPrivacyCommand = "showPrivacy";
static const char* const kProceedCommand = "proceed";
static const char* const kTakeMeBackCommand = "takeMeBack";
static const char* const kDoReportCommand = "doReport";
static const char* const kDontReportCommand = "dontReport";
static const char* const kDisplayCheckBox = "displaycheckbox";
static const char* const kBoxChecked = "boxchecked";
// static
SafeBrowsingBlockingPageFactory* SafeBrowsingBlockingPage::factory_ = NULL;
static base::LazyInstance<SafeBrowsingBlockingPage::UnsafeResourceMap>
g_unsafe_resource_map(base::LINKER_INITIALIZED);
// The default SafeBrowsingBlockingPageFactory. Global, made a singleton so we
// don't leak it.
class SafeBrowsingBlockingPageFactoryImpl
: public SafeBrowsingBlockingPageFactory {
public:
SafeBrowsingBlockingPage* CreateSafeBrowsingPage(
SafeBrowsingService* service,
TabContents* tab_contents,
const SafeBrowsingBlockingPage::UnsafeResourceList& unsafe_resources) {
return new SafeBrowsingBlockingPage(service, tab_contents,
unsafe_resources);
}
private:
friend struct base::DefaultLazyInstanceTraits<
SafeBrowsingBlockingPageFactoryImpl>;
SafeBrowsingBlockingPageFactoryImpl() { }
DISALLOW_COPY_AND_ASSIGN(SafeBrowsingBlockingPageFactoryImpl);
};
static base::LazyInstance<SafeBrowsingBlockingPageFactoryImpl>
g_safe_browsing_blocking_page_factory_impl(base::LINKER_INITIALIZED);
SafeBrowsingBlockingPage::SafeBrowsingBlockingPage(
SafeBrowsingService* sb_service,
TabContents* tab_contents,
const UnsafeResourceList& unsafe_resources)
: ChromeInterstitialPage(tab_contents,
IsMainPageLoadBlocked(unsafe_resources),
unsafe_resources[0].url),
malware_details_proceed_delay_ms_(
kMalwareDetailsProceedDelayMilliSeconds),
sb_service_(sb_service),
is_main_frame_load_blocked_(IsMainPageLoadBlocked(unsafe_resources)),
unsafe_resources_(unsafe_resources) {
RecordUserAction(SHOW);
if (!is_main_frame_load_blocked_) {
navigation_entry_index_to_remove_ =
tab()->controller().last_committed_entry_index();
} else {
navigation_entry_index_to_remove_ = -1;
}
// Start computing malware details. They will be sent only
// if the user opts-in on the blocking page later.
// If there's more than one malicious resources, it means the user
// clicked through the first warning, so we don't prepare additional
// reports.
if (unsafe_resources.size() == 1 &&
unsafe_resources[0].threat_type == SafeBrowsingService::URL_MALWARE &&
malware_details_ == NULL &&
CanShowMalwareDetailsOption()) {
malware_details_ = MalwareDetails::NewMalwareDetails(
sb_service_, tab(), unsafe_resources[0]);
}
}
bool SafeBrowsingBlockingPage::CanShowMalwareDetailsOption() {
return (!tab()->browser_context()->IsOffTheRecord() &&
tab()->GetURL().SchemeIs(chrome::kHttpScheme));
}
SafeBrowsingBlockingPage::~SafeBrowsingBlockingPage() {
}
std::string SafeBrowsingBlockingPage::GetHTMLContents() {
// Load the HTML page and create the template components.
DictionaryValue strings;
ResourceBundle& rb = ResourceBundle::GetSharedInstance();
std::string html;
if (unsafe_resources_.empty()) {
NOTREACHED();
return std::string();
}
if (unsafe_resources_.size() > 1) {
PopulateMultipleThreatStringDictionary(&strings);
html = rb.GetRawDataResource(
IDR_SAFE_BROWSING_MULTIPLE_THREAT_BLOCK).as_string();
} else {
SafeBrowsingService::UrlCheckResult threat_type =
unsafe_resources_[0].threat_type;
if (threat_type == SafeBrowsingService::URL_MALWARE) {
PopulateMalwareStringDictionary(&strings);
html = rb.GetRawDataResource(
IDR_SAFE_BROWSING_MALWARE_BLOCK).as_string();
} else { // Phishing.
DCHECK(threat_type == SafeBrowsingService::URL_PHISHING ||
threat_type == SafeBrowsingService::CLIENT_SIDE_PHISHING_URL);
PopulatePhishingStringDictionary(&strings);
html = rb.GetRawDataResource(
IDR_SAFE_BROWSING_PHISHING_BLOCK).as_string();
}
}
return jstemplate_builder::GetTemplatesHtml(html, &strings, "template_root");
}
void SafeBrowsingBlockingPage::PopulateStringDictionary(
DictionaryValue* strings,
const string16& title,
const string16& headline,
const string16& description1,
const string16& description2,
const string16& description3) {
strings->SetString("title", title);
strings->SetString("headLine", headline);
strings->SetString("description1", description1);
strings->SetString("description2", description2);
strings->SetString("description3", description3);
}
void SafeBrowsingBlockingPage::PopulateMultipleThreatStringDictionary(
DictionaryValue* strings) {
bool malware = false;
bool phishing = false;
string16 malware_label =
l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_LABEL);
string16 malware_link =
l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_DIAGNOSTIC_PAGE);
string16 phishing_label =
l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PHISHING_LABEL);
string16 phishing_link =
l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PHISHING_REPORT_ERROR);
ListValue* error_strings = new ListValue;
for (UnsafeResourceList::const_iterator iter = unsafe_resources_.begin();
iter != unsafe_resources_.end(); ++iter) {
const SafeBrowsingService::UnsafeResource& resource = *iter;
SafeBrowsingService::UrlCheckResult threat_type = resource.threat_type;
DictionaryValue* current_error_strings = new DictionaryValue;
if (threat_type == SafeBrowsingService::URL_MALWARE) {
malware = true;
current_error_strings->SetString("type", "malware");
current_error_strings->SetString("typeLabel", malware_label);
current_error_strings->SetString("errorLink", malware_link);
} else {
DCHECK(threat_type == SafeBrowsingService::URL_PHISHING ||
threat_type == SafeBrowsingService::CLIENT_SIDE_PHISHING_URL);
phishing = true;
current_error_strings->SetString("type", "phishing");
current_error_strings->SetString("typeLabel", phishing_label);
current_error_strings->SetString("errorLink", phishing_link);
}
current_error_strings->SetString("url", resource.url.spec());
error_strings->Append(current_error_strings);
}
strings->Set("errors", error_strings);
DCHECK(phishing || malware);
if (malware && phishing) {
PopulateStringDictionary(
strings,
// Use the malware headline, it is the scariest one.
l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MULTI_THREAT_TITLE),
l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_HEADLINE),
l10n_util::GetStringFUTF16(IDS_SAFE_BROWSING_MULTI_THREAT_DESCRIPTION1,
UTF8ToUTF16(tab()->GetURL().host())),
l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MULTI_THREAT_DESCRIPTION2),
string16());
} else if (malware) {
// Just malware.
PopulateStringDictionary(
strings,
l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_TITLE),
l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_HEADLINE),
l10n_util::GetStringFUTF16(IDS_SAFE_BROWSING_MULTI_MALWARE_DESCRIPTION1,
UTF8ToUTF16(tab()->GetURL().host())),
l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MULTI_MALWARE_DESCRIPTION2),
l10n_util::GetStringUTF16(
IDS_SAFE_BROWSING_MULTI_MALWARE_DESCRIPTION3));
} else {
// Just phishing.
PopulateStringDictionary(
strings,
l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PHISHING_TITLE),
l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PHISHING_HEADLINE),
l10n_util::GetStringFUTF16(
IDS_SAFE_BROWSING_MULTI_PHISHING_DESCRIPTION1,
UTF8ToUTF16(tab()->GetURL().host())),
string16(),
string16());
}
strings->SetString("confirm_text",
l10n_util::GetStringUTF16(
IDS_SAFE_BROWSING_MULTI_MALWARE_DESCRIPTION_AGREE));
strings->SetString("continue_button",
l10n_util::GetStringUTF16(
IDS_SAFE_BROWSING_MULTI_MALWARE_PROCEED_BUTTON));
strings->SetString("back_button",
l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_BACK_BUTTON));
strings->SetString("textdirection", base::i18n::IsRTL() ? "rtl" : "ltr");
}
void SafeBrowsingBlockingPage::PopulateMalwareStringDictionary(
DictionaryValue* strings) {
std::string diagnostic_link = base::StringPrintf(kSbDiagnosticHtml,
l10n_util::GetStringUTF8(
IDS_SAFE_BROWSING_MALWARE_DIAGNOSTIC_PAGE).c_str());
strings->SetString("badURL", url().host());
// Check to see if we're blocking the main page, or a sub-resource on the
// main page.
string16 description1, description3, description5;
if (is_main_frame_load_blocked_) {
description1 = l10n_util::GetStringFUTF16(
IDS_SAFE_BROWSING_MALWARE_DESCRIPTION1, UTF8ToUTF16(url().host()));
} else {
description1 = l10n_util::GetStringFUTF16(
IDS_SAFE_BROWSING_MALWARE_DESCRIPTION4,
UTF8ToUTF16(tab()->GetURL().host()),
UTF8ToUTF16(url().host()));
}
std::string proceed_link = base::StringPrintf(kPLinkHtml,
l10n_util::GetStringUTF8(IDS_SAFE_BROWSING_MALWARE_PROCEED_LINK).c_str());
description3 =
l10n_util::GetStringFUTF16(IDS_SAFE_BROWSING_MALWARE_DESCRIPTION3,
UTF8ToUTF16(proceed_link));
PopulateStringDictionary(
strings,
l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_TITLE),
l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_HEADLINE),
description1,
l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_DESCRIPTION2),
description3);
description5 =
l10n_util::GetStringFUTF16(IDS_SAFE_BROWSING_MALWARE_DESCRIPTION5,
UTF8ToUTF16(url().host()),
UTF8ToUTF16(url().host()),
UTF8ToUTF16(diagnostic_link));
strings->SetString("description5", description5);
strings->SetString("back_button",
l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_BACK_BUTTON));
strings->SetString("proceed_link",
l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_PROCEED_LINK));
strings->SetString("textdirection", base::i18n::IsRTL() ? "rtl" : "ltr");
if (!CanShowMalwareDetailsOption()) {
strings->SetBoolean(kDisplayCheckBox, false);
} else {
// Show the checkbox for sending malware details.
strings->SetBoolean(kDisplayCheckBox, true);
std::string privacy_link = base::StringPrintf(
kPrivacyLinkHtml,
l10n_util::GetStringUTF8(
IDS_SAFE_BROWSING_PRIVACY_POLICY_PAGE).c_str());
strings->SetString("confirm_text",
l10n_util::GetStringFUTF16(
IDS_SAFE_BROWSING_MALWARE_REPORTING_AGREE,
UTF8ToUTF16(privacy_link)));
Profile* profile = Profile::FromBrowserContext(tab()->browser_context());
const PrefService::Preference* pref =
profile->GetPrefs()->FindPreference(
prefs::kSafeBrowsingReportingEnabled);
bool value;
if (pref && pref->GetValue()->GetAsBoolean(&value) && value) {
strings->SetString(kBoxChecked, "yes");
} else {
strings->SetString(kBoxChecked, "");
}
}
}
void SafeBrowsingBlockingPage::PopulatePhishingStringDictionary(
DictionaryValue* strings) {
std::string proceed_link = base::StringPrintf(
kPLinkHtml,
l10n_util::GetStringUTF8(
IDS_SAFE_BROWSING_PHISHING_PROCEED_LINK).c_str());
string16 description3 = l10n_util::GetStringFUTF16(
IDS_SAFE_BROWSING_PHISHING_DESCRIPTION3,
UTF8ToUTF16(proceed_link));
PopulateStringDictionary(
strings,
l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PHISHING_TITLE),
l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PHISHING_HEADLINE),
l10n_util::GetStringFUTF16(IDS_SAFE_BROWSING_PHISHING_DESCRIPTION1,
UTF8ToUTF16(url().host())),
l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PHISHING_DESCRIPTION2),
description3);
strings->SetString("back_button",
l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PHISHING_BACK_BUTTON));
strings->SetString("report_error",
l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PHISHING_REPORT_ERROR));
strings->SetString("textdirection", base::i18n::IsRTL() ? "rtl" : "ltr");
}
void SafeBrowsingBlockingPage::CommandReceived(const std::string& cmd) {
std::string command(cmd); // Make a local copy so we can modify it.
// The Jasonified response has quotes, remove them.
if (command.length() > 1 && command[0] == '"') {
command = command.substr(1, command.length() - 2);
}
if (command == kDoReportCommand) {
SetReportingPreference(true);
return;
}
if (command == kDontReportCommand) {
SetReportingPreference(false);
return;
}
if (command == kLearnMoreCommand) {
// User pressed "Learn more".
GURL url;
SafeBrowsingService::UrlCheckResult threat_type =
unsafe_resources_[0].threat_type;
if (threat_type == SafeBrowsingService::URL_MALWARE) {
url = google_util::AppendGoogleLocaleParam(GURL(kLearnMoreMalwareUrl));
} else if (threat_type == SafeBrowsingService::URL_PHISHING ||
threat_type == SafeBrowsingService::CLIENT_SIDE_PHISHING_URL) {
url = google_util::AppendGoogleLocaleParam(GURL(kLearnMorePhishingUrl));
} else {
NOTREACHED();
}
tab()->OpenURL(url, GURL(), CURRENT_TAB, content::PAGE_TRANSITION_LINK);
return;
}
if (command == kShowPrivacyCommand) {
// User pressed "Safe Browsing privacy policy".
GURL url(kSbPrivacyPolicyUrl);
tab()->OpenURL(url, GURL(), CURRENT_TAB, content::PAGE_TRANSITION_LINK);
return;
}
if (command == kProceedCommand) {
Proceed();
// We are deleted after this.
return;
}
if (command == kTakeMeBackCommand) {
DontProceed();
// We are deleted after this.
return;
}
// The "report error" and "show diagnostic" commands can have a number
// appended to them, which is the index of the element they apply to.
int element_index = 0;
size_t colon_index = command.find(':');
if (colon_index != std::string::npos) {
DCHECK(colon_index < command.size() - 1);
bool result = base::StringToInt(command.begin() + colon_index + 1,
command.end(),
&element_index);
command = command.substr(0, colon_index);
DCHECK(result);
}
if (element_index >= static_cast<int>(unsafe_resources_.size())) {
NOTREACHED();
return;
}
std::string bad_url_spec = unsafe_resources_[element_index].url.spec();
if (command == kReportErrorCommand) {
// User pressed "Report error" for a phishing site.
// Note that we cannot just put a link in the interstitial at this point.
// It is not OK to navigate in the context of an interstitial page.
SafeBrowsingService::UrlCheckResult threat_type =
unsafe_resources_[element_index].threat_type;
DCHECK(threat_type == SafeBrowsingService::URL_PHISHING ||
threat_type == SafeBrowsingService::CLIENT_SIDE_PHISHING_URL);
GURL report_url =
safe_browsing_util::GeneratePhishingReportUrl(
kSbReportPhishingErrorUrl,
bad_url_spec,
threat_type == SafeBrowsingService::CLIENT_SIDE_PHISHING_URL);
tab()->OpenURL(
report_url, GURL(), CURRENT_TAB, content::PAGE_TRANSITION_LINK);
return;
}
if (command == kShowDiagnosticCommand) {
// We're going to take the user to Google's SafeBrowsing diagnostic page.
std::string diagnostic =
base::StringPrintf(kSbDiagnosticUrl,
net::EscapeQueryParamValue(bad_url_spec, true).c_str());
GURL diagnostic_url(diagnostic);
diagnostic_url = google_util::AppendGoogleLocaleParam(diagnostic_url);
DCHECK(unsafe_resources_[element_index].threat_type ==
SafeBrowsingService::URL_MALWARE);
tab()->OpenURL(
diagnostic_url, GURL(), CURRENT_TAB, content::PAGE_TRANSITION_LINK);
return;
}
NOTREACHED() << "Unexpected command: " << command;
}
void SafeBrowsingBlockingPage::SetReportingPreference(bool report) {
Profile* profile = Profile::FromBrowserContext(tab()->browser_context());
PrefService* pref = profile->GetPrefs();
pref->SetBoolean(prefs::kSafeBrowsingReportingEnabled, report);
}
void SafeBrowsingBlockingPage::Proceed() {
RecordUserAction(PROCEED);
// Send the malware details, if we opted to.
FinishMalwareDetails(malware_details_proceed_delay_ms_);
NotifySafeBrowsingService(sb_service_, unsafe_resources_, true);
// Check to see if some new notifications of unsafe resources have been
// received while we were showing the interstitial.
UnsafeResourceMap* unsafe_resource_map = GetUnsafeResourcesMap();
UnsafeResourceMap::iterator iter = unsafe_resource_map->find(tab());
SafeBrowsingBlockingPage* blocking_page = NULL;
if (iter != unsafe_resource_map->end() && !iter->second.empty()) {
// Build an interstitial for all the unsafe resources notifications.
// Don't show it now as showing an interstitial while an interstitial is
// already showing would cause DontProceed() to be invoked.
blocking_page = factory_->CreateSafeBrowsingPage(sb_service_, tab(),
iter->second);
unsafe_resource_map->erase(iter);
}
InterstitialPage::Proceed();
// We are now deleted.
// Now that this interstitial is gone, we can show the new one.
if (blocking_page)
blocking_page->Show();
}
void SafeBrowsingBlockingPage::DontProceed() {
DCHECK(action_taken() != DONT_PROCEED_ACTION);
// We could have already called Proceed(), in which case we must not notify
// the SafeBrowsingService again, as the client has been deleted.
if (action_taken() == PROCEED_ACTION) {
// We still want to hide the interstitial page.
InterstitialPage::DontProceed();
// We are now deleted.
return;
}
RecordUserAction(DONT_PROCEED);
// Send the malware details, if we opted to.
FinishMalwareDetails(0); // No delay
NotifySafeBrowsingService(sb_service_, unsafe_resources_, false);
// The user does not want to proceed, clear the queued unsafe resources
// notifications we received while the interstitial was showing.
UnsafeResourceMap* unsafe_resource_map = GetUnsafeResourcesMap();
UnsafeResourceMap::iterator iter = unsafe_resource_map->find(tab());
if (iter != unsafe_resource_map->end() && !iter->second.empty()) {
NotifySafeBrowsingService(sb_service_, iter->second, false);
unsafe_resource_map->erase(iter);
}
// We don't remove the navigation entry if the tab is being destroyed as this
// would trigger a navigation that would cause trouble as the render view host
// for the tab has by then already been destroyed.
if (navigation_entry_index_to_remove_ != -1 && !tab()->is_being_destroyed()) {
tab()->controller().RemoveEntryAtIndex(navigation_entry_index_to_remove_,
GURL(chrome::kChromeUINewTabURL));
navigation_entry_index_to_remove_ = -1;
}
InterstitialPage::DontProceed();
// We are now deleted.
}
void SafeBrowsingBlockingPage::RecordUserAction(BlockingPageEvent event) {
// Determine the interstitial type from the blocked resources.
// This is the same logic that is used to actually construct the
// page contents; we can look at the title to see which type of
// interstitial is being displayed.
DictionaryValue strings;
PopulateMultipleThreatStringDictionary(&strings);
string16 title;
bool success = strings.GetString("title", &title);
DCHECK(success);
std::string action = "SBInterstitial";
if (title ==
l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MULTI_THREAT_TITLE)) {
action.append("Multiple");
} else if (title ==
l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_MALWARE_TITLE)) {
action.append("Malware");
} else {
DCHECK_EQ(title,
l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PHISHING_TITLE));
action.append("Phishing");
}
switch (event) {
case SHOW:
action.append("Show");
break;
case PROCEED:
action.append("Proceed");
break;
case DONT_PROCEED:
action.append("DontProceed");
break;
default:
NOTREACHED() << "Unexpected event: " << event;
}
UserMetrics::RecordComputedAction(action);
}
void SafeBrowsingBlockingPage::FinishMalwareDetails(int64 delay_ms) {
if (malware_details_ == NULL)
return; // Not all interstitials have malware details (eg phishing).
Profile* profile = Profile::FromBrowserContext(tab()->browser_context());
const PrefService::Preference* pref =
profile->GetPrefs()->FindPreference(prefs::kSafeBrowsingReportingEnabled);
bool value;
if (pref && pref->GetValue()->GetAsBoolean(&value) && value) {
// Finish the malware details collection, send it over.
BrowserThread::PostDelayedTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&MalwareDetails::FinishCollection, malware_details_.get()),
delay_ms);
}
}
// static
void SafeBrowsingBlockingPage::NotifySafeBrowsingService(
SafeBrowsingService* sb_service,
const UnsafeResourceList& unsafe_resources,
bool proceed) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&SafeBrowsingService::OnBlockingPageDone,
sb_service, unsafe_resources, proceed));
}
// static
SafeBrowsingBlockingPage::UnsafeResourceMap*
SafeBrowsingBlockingPage::GetUnsafeResourcesMap() {
return g_unsafe_resource_map.Pointer();
}
// static
void SafeBrowsingBlockingPage::ShowBlockingPage(
SafeBrowsingService* sb_service,
const SafeBrowsingService::UnsafeResource& unsafe_resource) {
TabContents* tab_contents = tab_util::GetTabContentsByID(
unsafe_resource.render_process_host_id, unsafe_resource.render_view_id);
InterstitialPage* interstitial =
InterstitialPage::GetInterstitialPage(tab_contents);
if (interstitial && !unsafe_resource.is_subresource) {
// There is already an interstitial showing and we are about to display a
// new one for the main frame. Just hide the current one, it is now
// irrelevent
interstitial->DontProceed();
interstitial = NULL;
}
if (!interstitial) {
// There are no interstitial currently showing in that tab, go ahead and
// show this interstitial.
std::vector<SafeBrowsingService::UnsafeResource> resources;
resources.push_back(unsafe_resource);
// Set up the factory if this has not been done already (tests do that
// before this method is called).
if (!factory_)
factory_ = g_safe_browsing_blocking_page_factory_impl.Pointer();
SafeBrowsingBlockingPage* blocking_page =
factory_->CreateSafeBrowsingPage(sb_service, tab_contents, resources);
blocking_page->Show();
return;
}
// This is an interstitial for a page's resource, let's queue it.
UnsafeResourceMap* unsafe_resource_map = GetUnsafeResourcesMap();
(*unsafe_resource_map)[tab_contents].push_back(unsafe_resource);
}
// static
bool SafeBrowsingBlockingPage::IsMainPageLoadBlocked(
const UnsafeResourceList& unsafe_resources) {
// Client-side phishing detection interstitials never block the main frame
// load, since they happen after the page is finished loading.
if (unsafe_resources[0].threat_type ==
SafeBrowsingService::CLIENT_SIDE_PHISHING_URL) {
return false;
}
// Otherwise, check the threat type.
return unsafe_resources.size() == 1 && !unsafe_resources[0].is_subresource;
}