| // Copyright 2017 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/download_protection/download_url_sb_client.h" |
| |
| #include "base/metrics/histogram_macros.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "chrome/browser/metrics/chrome_metrics_service_accessor.h" |
| #include "chrome/browser/profiles/profile_manager.h" |
| #include "chrome/browser/safe_browsing/download_protection/download_protection_service.h" |
| #include "chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.h" |
| #include "chrome/browser/safe_browsing/ui_manager.h" |
| |
| namespace safe_browsing { |
| |
| DownloadUrlSBClient::DownloadUrlSBClient( |
| content::DownloadItem* item, |
| DownloadProtectionService* service, |
| const CheckDownloadCallback& callback, |
| const scoped_refptr<SafeBrowsingUIManager>& ui_manager, |
| const scoped_refptr<SafeBrowsingDatabaseManager>& database_manager) |
| : item_(item), |
| sha256_hash_(item->GetHash()), |
| url_chain_(item->GetUrlChain()), |
| referrer_url_(item->GetReferrerUrl()), |
| total_type_(DOWNLOAD_URL_CHECKS_TOTAL), |
| dangerous_type_(DOWNLOAD_URL_CHECKS_MALWARE), |
| service_(service), |
| callback_(callback), |
| ui_manager_(ui_manager), |
| start_time_(base::TimeTicks::Now()), |
| database_manager_(database_manager), |
| download_item_observer_(this) { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| DCHECK(item_); |
| DCHECK(service_); |
| download_item_observer_.Add(item_); |
| Profile* profile = Profile::FromBrowserContext(item_->GetBrowserContext()); |
| extended_reporting_level_ = |
| profile ? GetExtendedReportingLevel(*profile->GetPrefs()) |
| : SBER_LEVEL_OFF; |
| } |
| |
| // Implements DownloadItem::Observer. |
| void DownloadUrlSBClient::OnDownloadDestroyed(content::DownloadItem* download) { |
| download_item_observer_.Remove(item_); |
| item_ = nullptr; |
| } |
| |
| void DownloadUrlSBClient::StartCheck() { |
| DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| if (!database_manager_.get() || |
| database_manager_->CheckDownloadUrl(url_chain_, this)) { |
| CheckDone(SB_THREAT_TYPE_SAFE); |
| } else { |
| // Add a reference to this object to prevent it from being destroyed |
| // before url checking result is returned. |
| AddRef(); |
| } |
| } |
| |
| bool DownloadUrlSBClient::IsDangerous(SBThreatType threat_type) const { |
| return threat_type == SB_THREAT_TYPE_URL_BINARY_MALWARE; |
| } |
| |
| // Implements SafeBrowsingDatabaseManager::Client. |
| void DownloadUrlSBClient::OnCheckDownloadUrlResult( |
| const std::vector<GURL>& url_chain, |
| SBThreatType threat_type) { |
| CheckDone(threat_type); |
| UMA_HISTOGRAM_TIMES("SB2.DownloadUrlCheckDuration", |
| base::TimeTicks::Now() - start_time_); |
| Release(); |
| } |
| |
| DownloadUrlSBClient::~DownloadUrlSBClient() { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| } |
| |
| void DownloadUrlSBClient::CheckDone(SBThreatType threat_type) { |
| DownloadCheckResult result = IsDangerous(threat_type) |
| ? DownloadCheckResult::DANGEROUS |
| : DownloadCheckResult::SAFE; |
| UpdateDownloadCheckStats(total_type_); |
| if (threat_type != SB_THREAT_TYPE_SAFE) { |
| UpdateDownloadCheckStats(dangerous_type_); |
| BrowserThread::PostTask( |
| BrowserThread::UI, FROM_HERE, |
| base::BindOnce(&DownloadUrlSBClient::ReportMalware, this, threat_type)); |
| } else { |
| // Identify download referrer chain, which will be used in |
| // ClientDownloadRequest. |
| BrowserThread::PostTask( |
| BrowserThread::UI, FROM_HERE, |
| base::BindOnce(&DownloadUrlSBClient::IdentifyReferrerChain, this)); |
| } |
| BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| base::BindOnce(callback_, result)); |
| } |
| |
| void DownloadUrlSBClient::ReportMalware(SBThreatType threat_type) { |
| std::string post_data; |
| if (!sha256_hash_.empty()) { |
| post_data += |
| base::HexEncode(sha256_hash_.data(), sha256_hash_.size()) + "\n"; |
| } |
| for (size_t i = 0; i < url_chain_.size(); ++i) { |
| post_data += url_chain_[i].spec() + "\n"; |
| } |
| |
| safe_browsing::HitReport hit_report; |
| hit_report.malicious_url = url_chain_.back(); |
| hit_report.page_url = url_chain_.front(); |
| hit_report.referrer_url = referrer_url_; |
| hit_report.is_subresource = true; |
| hit_report.threat_type = threat_type; |
| hit_report.threat_source = database_manager_->GetThreatSource(); |
| hit_report.post_data = post_data; |
| hit_report.extended_reporting_level = extended_reporting_level_; |
| hit_report.is_metrics_reporting_active = |
| ChromeMetricsServiceAccessor::IsMetricsAndCrashReportingEnabled(); |
| |
| ui_manager_->MaybeReportSafeBrowsingHit(hit_report, item_->GetWebContents()); |
| } |
| |
| void DownloadUrlSBClient::IdentifyReferrerChain() { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| if (!item_) |
| return; |
| |
| item_->SetUserData(kDownloadReferrerChainDataKey, |
| base::MakeUnique<ReferrerChainData>( |
| service_->IdentifyReferrerChain(*item_))); |
| } |
| |
| void DownloadUrlSBClient::UpdateDownloadCheckStats(SBStatsType stat_type) { |
| UMA_HISTOGRAM_ENUMERATION("SB2.DownloadChecks", stat_type, |
| DOWNLOAD_CHECKS_MAX); |
| } |
| |
| } // namespace safe_browsing |