blob: 7c3ab4e07b0c23256c875a756bf6642aa912ca77 [file] [log] [blame]
// Copyright (c) 2012 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.
#include "chrome/browser/safe_browsing/ui_manager.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/macros.h"
#include "base/metrics/histogram_macros.h"
#include "base/threading/thread.h"
#include "base/threading/thread_restrictions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/history/history_service_factory.h"
#include "chrome/browser/interstitials/enterprise_util.h"
#include "chrome/browser/metrics/chrome_metrics_service_accessor.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/safe_browsing/safe_browsing_blocking_page.h"
#include "chrome/browser/safe_browsing/safe_browsing_service.h"
#include "chrome/browser/tab_contents/tab_util.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "components/prefs/pref_service.h"
#include "components/safe_browsing/browser/threat_details.h"
#include "components/safe_browsing/common/safe_browsing_prefs.h"
#include "components/safe_browsing/ping_manager.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/web_contents.h"
#include "ipc/ipc_message.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "net/ssl/ssl_info.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
#include "url/gurl.h"
using content::BrowserThread;
using content::NavigationEntry;
using content::WebContents;
using safe_browsing::HitReport;
using safe_browsing::SBThreatType;
namespace safe_browsing {
SafeBrowsingUIManager::SafeBrowsingUIManager(
const scoped_refptr<SafeBrowsingService>& service)
: sb_service_(service) {}
SafeBrowsingUIManager::~SafeBrowsingUIManager() {}
void SafeBrowsingUIManager::Stop(bool shutdown) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (shutdown)
sb_service_ = nullptr;
}
void SafeBrowsingUIManager::CreateAndSendHitReport(
const UnsafeResource& resource) {
WebContents* web_contents = resource.web_contents_getter.Run();
DCHECK(web_contents);
HitReport hit_report;
hit_report.malicious_url = resource.url;
hit_report.is_subresource = resource.is_subresource;
hit_report.threat_type = resource.threat_type;
hit_report.threat_source = resource.threat_source;
hit_report.population_id = resource.threat_metadata.population_id;
NavigationEntry* entry = resource.GetNavigationEntryForResource();
if (entry) {
hit_report.page_url = entry->GetURL();
hit_report.referrer_url = entry->GetReferrer().url;
}
// When the malicious url is on the main frame, and resource.original_url
// is not the same as the resource.url, that means we have a redirect from
// resource.original_url to resource.url.
// Also, at this point, page_url points to the _previous_ page that we
// were on. We replace page_url with resource.original_url and referrer
// with page_url.
if (!resource.is_subresource && !resource.original_url.is_empty() &&
resource.original_url != resource.url) {
hit_report.referrer_url = hit_report.page_url;
hit_report.page_url = resource.original_url;
}
Profile* profile =
Profile::FromBrowserContext(web_contents->GetBrowserContext());
hit_report.extended_reporting_level =
profile ? GetExtendedReportingLevel(*profile->GetPrefs())
: SBER_LEVEL_OFF;
hit_report.is_metrics_reporting_active =
ChromeMetricsServiceAccessor::IsMetricsAndCrashReportingEnabled();
MaybeReportSafeBrowsingHit(hit_report, web_contents);
for (Observer& observer : observer_list_)
observer.OnSafeBrowsingHit(resource);
}
void SafeBrowsingUIManager::ShowBlockingPageForResource(
const UnsafeResource& resource) {
SafeBrowsingBlockingPage::ShowBlockingPage(this, resource);
}
// static
bool SafeBrowsingUIManager::ShouldSendHitReport(
const HitReport& hit_report,
const WebContents* web_contents) {
return web_contents &&
hit_report.extended_reporting_level != SBER_LEVEL_OFF &&
!web_contents->GetBrowserContext()->IsOffTheRecord();
}
// A SafeBrowsing hit is sent after a blocking page for malware/phishing
// or after the warning dialog for download urls, only for
// extended-reporting users.
void SafeBrowsingUIManager::MaybeReportSafeBrowsingHit(
const HitReport& hit_report,
const WebContents* web_contents) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
// Send report if user opted-in to extended reporting and is not in
// incognito mode.
if (!ShouldSendHitReport(hit_report, web_contents))
return;
// The service may delete the ping manager (i.e. when user disabling service,
// etc). This happens on the IO thread.
if (!sb_service_ || !sb_service_->ping_manager())
return;
DVLOG(1) << "ReportSafeBrowsingHit: " << hit_report.malicious_url << " "
<< hit_report.page_url << " " << hit_report.referrer_url << " "
<< hit_report.is_subresource << " " << hit_report.threat_type;
sb_service_->ping_manager()->ReportSafeBrowsingHit(hit_report);
}
// Static.
void SafeBrowsingUIManager::CreateWhitelistForTesting(
content::WebContents* web_contents) {
EnsureWhitelistCreated(web_contents);
}
void SafeBrowsingUIManager::AddObserver(Observer* observer) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
observer_list_.AddObserver(observer);
}
void SafeBrowsingUIManager::RemoveObserver(Observer* observer) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
observer_list_.RemoveObserver(observer);
}
const std::string SafeBrowsingUIManager::app_locale() const {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
return g_browser_process->GetApplicationLocale();
}
history::HistoryService* SafeBrowsingUIManager::history_service(
content::WebContents* web_contents) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
return HistoryServiceFactory::GetForProfile(
Profile::FromBrowserContext(web_contents->GetBrowserContext()),
ServiceAccessType::EXPLICIT_ACCESS);
}
const GURL SafeBrowsingUIManager::default_safe_page() const {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
return GURL(chrome::kChromeUINewTabURL);
}
// If the user had opted-in to send ThreatDetails, this gets called
// when the report is ready.
void SafeBrowsingUIManager::SendSerializedThreatDetails(
const std::string& serialized) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
// The service may delete the ping manager (i.e. when user disabling service,
// etc). This happens on the IO thread.
if (sb_service_.get() == NULL || sb_service_->ping_manager() == NULL)
return;
if (!serialized.empty()) {
DVLOG(1) << "Sending serialized threat details.";
sb_service_->ping_manager()->ReportThreatDetails(serialized);
}
}
void SafeBrowsingUIManager::OnBlockingPageDone(
const std::vector<UnsafeResource>& resources,
bool proceed,
content::WebContents* web_contents,
const GURL& main_frame_url) {
BaseUIManager::OnBlockingPageDone(resources, proceed, web_contents,
main_frame_url);
if (proceed && resources.size() > 0) {
MaybeTriggerSecurityInterstitialProceededEvent(
web_contents, main_frame_url,
GetThreatTypeStringForInterstitial(resources[0].threat_type),
/*net_error_code=*/0);
}
}
// Static.
GURL SafeBrowsingUIManager::GetMainFrameWhitelistUrlForResourceForTesting(
const security_interstitials::UnsafeResource& resource) {
return GetMainFrameWhitelistUrlForResource(resource);
}
} // namespace safe_browsing