blob: ff9e1c6b83b82f3622e5b9b5698e2aa3d1dacc94 [file] [log] [blame]
// Copyright 2019 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_reporter.h"
#include "base/strings/string_number_conversions.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/download/simple_download_manager_coordinator_factory.h"
#include "chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.h"
#include "chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_key.h"
#include "chrome/browser/safe_browsing/safe_browsing_service.h"
#include "components/download/public/common/download_danger_type.h"
#include "components/download/public/common/download_item.h"
#include "components/download/public/common/simple_download_manager_coordinator.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/download_item_utils.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_service.h"
namespace safe_browsing {
namespace {
bool DangerTypeIsDangerous(download::DownloadDangerType danger_type) {
return (danger_type == download::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE ||
danger_type == download::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL ||
danger_type == download::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT ||
danger_type == download::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT ||
danger_type == download::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST ||
danger_type == download::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED);
}
std::string DangerTypeToThreatType(download::DownloadDangerType danger_type) {
switch (danger_type) {
case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE:
return "DANGEROUS_FILE_TYPE";
case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
return "DANGEROUS_URL";
case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
return "DANGEROUS";
case download::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT:
return "UNCOMMON";
case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST:
return "DANGEROUS_HOST";
case download::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED:
return "POTENTIALLY_UNWANTED";
default:
// Expects to only be called with the dangerous threat types listed above.
NOTREACHED() << "Unexpected danger type: " << danger_type;
return "UNKNOWN";
}
}
void ReportDangerousDownloadWarning(download::DownloadItem* download) {
content::BrowserContext* browser_context =
content::DownloadItemUtils::GetBrowserContext(download);
Profile* profile = Profile::FromBrowserContext(browser_context);
if (profile) {
std::string raw_digest_sha256 = download->GetHash();
extensions::SafeBrowsingPrivateEventRouterFactory::GetForProfile(profile)
->OnDangerousDownloadWarning(
download->GetURL(), download->GetTargetFilePath().AsUTF8Unsafe(),
base::HexEncode(raw_digest_sha256.data(), raw_digest_sha256.size()),
DangerTypeToThreatType(download->GetDangerType()),
download->GetMimeType(), download->GetTotalBytes());
}
}
void ReportDangerousDownloadWarningBypassed(
download::DownloadItem* download,
download::DownloadDangerType original_danger_type) {
content::BrowserContext* browser_context =
content::DownloadItemUtils::GetBrowserContext(download);
Profile* profile = Profile::FromBrowserContext(browser_context);
if (profile) {
std::string raw_digest_sha256 = download->GetHash();
extensions::SafeBrowsingPrivateEventRouterFactory::GetForProfile(profile)
->OnDangerousDownloadWarningBypassed(
download->GetURL(), download->GetTargetFilePath().AsUTF8Unsafe(),
base::HexEncode(raw_digest_sha256.data(), raw_digest_sha256.size()),
DangerTypeToThreatType(original_danger_type),
download->GetMimeType(), download->GetTotalBytes());
}
}
} // namespace
DownloadReporter::DownloadReporter() {
profiles_registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED,
content::NotificationService::AllSources());
}
DownloadReporter::~DownloadReporter() = default;
void DownloadReporter::Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
DCHECK_EQ(type, chrome::NOTIFICATION_PROFILE_CREATED);
Profile* profile = content::Source<Profile>(source).ptr();
download::SimpleDownloadManagerCoordinator* coordinator =
SimpleDownloadManagerCoordinatorFactory::GetForKey(
profile->GetProfileKey());
observed_coordinators_.Add(coordinator);
}
void DownloadReporter::OnManagerGoingDown(
download::SimpleDownloadManagerCoordinator* coordinator) {
observed_coordinators_.Remove(coordinator);
}
void DownloadReporter::OnDownloadCreated(download::DownloadItem* download) {
danger_types_[download] = download->GetDangerType();
observed_downloads_.Add(download);
}
void DownloadReporter::OnDownloadDestroyed(download::DownloadItem* download) {
observed_downloads_.Remove(download);
danger_types_.erase(download);
}
void DownloadReporter::OnDownloadUpdated(download::DownloadItem* download) {
// If the update isn't a change in danger type, we can ignore it.
if (danger_types_[download] == download->GetDangerType())
return;
download::DownloadDangerType old_danger_type = danger_types_[download];
download::DownloadDangerType current_danger_type = download->GetDangerType();
if (!DangerTypeIsDangerous(old_danger_type) &&
DangerTypeIsDangerous(current_danger_type)) {
ReportDangerousDownloadWarning(download);
}
if (DangerTypeIsDangerous(old_danger_type) &&
current_danger_type == download::DOWNLOAD_DANGER_TYPE_USER_VALIDATED) {
ReportDangerousDownloadWarningBypassed(download, old_danger_type);
}
danger_types_[download] = current_danger_type;
}
} // namespace safe_browsing