| // Copyright 2015 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/unverified_download_policy.h" |
| |
| #include <algorithm> |
| |
| #include "base/bind.h" |
| #include "base/callback.h" |
| #include "base/files/file_path.h" |
| #include "base/metrics/sparse_histogram.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/safe_browsing/safe_browsing_service.h" |
| #include "chrome/browser/safe_browsing/unverified_download_field_trial.h" |
| #include "chrome/common/safe_browsing/download_protection_util.h" |
| #include "components/rappor/rappor_service.h" |
| #include "components/rappor/rappor_utils.h" |
| #include "components/safe_browsing_db/database_manager.h" |
| #include "content/public/browser/browser_thread.h" |
| |
| namespace safe_browsing { |
| |
| namespace { |
| using content::BrowserThread; |
| |
| // Record the uma_file_type to UMA as an enum, and the URL's eTLD+1 to Rappor. |
| void RecordPolicyMetricOnUIThread(const std::string& metric_name, |
| int uma_file_type, |
| const GURL& requestor) { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| UMA_HISTOGRAM_SPARSE_SLOWLY(metric_name, uma_file_type); |
| |
| rappor::RapporService* rappor_service = g_browser_process->rappor_service(); |
| if (rappor_service && requestor.is_valid()) { |
| rappor_service->RecordSample( |
| metric_name, rappor::SAFEBROWSING_RAPPOR_TYPE, |
| rappor::GetDomainAndRegistrySampleFromGURL(requestor)); |
| } |
| } |
| |
| void RecordPolicyMetric(const std::string& metric_name, |
| int uma_file_type, |
| const GURL& requestor) { |
| BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| base::Bind(&RecordPolicyMetricOnUIThread, metric_name, |
| uma_file_type, requestor)); |
| } |
| |
| void RespondWithPolicy( |
| const base::FilePath& file, |
| const UnverifiedDownloadCheckCompletionCallback& callback, |
| const GURL& requestor, |
| UnverifiedDownloadPolicy policy) { |
| int uma_file_type = |
| download_protection_util::GetSBClientDownloadExtensionValueForUMA(file); |
| if (policy == UnverifiedDownloadPolicy::ALLOWED) { |
| RecordPolicyMetric("SafeBrowsing.UnverifiedDownloads.Allowed", |
| uma_file_type, requestor); |
| } else { |
| RecordPolicyMetric("SafeBrowsing.UnverifiedDownloads.Blocked", |
| uma_file_type, requestor); |
| } |
| BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| base::Bind(callback, policy)); |
| } |
| |
| void CheckFieldTrialOnAnyThread( |
| const base::FilePath& file, |
| const std::vector<base::FilePath::StringType>& alternate_extensions, |
| const GURL& requestor, |
| const UnverifiedDownloadCheckCompletionCallback& callback) { |
| if (!IsUnverifiedDownloadAllowedByFieldTrial(file)) { |
| RespondWithPolicy(file, callback, requestor, |
| UnverifiedDownloadPolicy::DISALLOWED); |
| return; |
| } |
| |
| for (const auto& extension : alternate_extensions) { |
| base::FilePath alternate_filename = file.AddExtension(extension); |
| if (!IsUnverifiedDownloadAllowedByFieldTrial(alternate_filename)) { |
| RespondWithPolicy(alternate_filename, callback, requestor, |
| UnverifiedDownloadPolicy::DISALLOWED); |
| return; |
| } |
| } |
| |
| RespondWithPolicy(file, callback, requestor, |
| UnverifiedDownloadPolicy::ALLOWED); |
| } |
| |
| void CheckWhitelistOnIOThread( |
| scoped_refptr<SafeBrowsingService> service, |
| const GURL& requestor, |
| const base::FilePath& file, |
| const std::vector<base::FilePath::StringType>& alternate_extensions, |
| const UnverifiedDownloadCheckCompletionCallback& callback) { |
| DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| int uma_file_type = |
| download_protection_util::GetSBClientDownloadExtensionValueForUMA(file); |
| |
| if (!service || !service->enabled()) { |
| // If the SafeBrowsing service was disabled, don't try to check against the |
| // field trial list. Instead allow the download. We are assuming that if the |
| // SafeBrowsing service was disabled for this user, then we shouldn't |
| // interefere with unverified downloads. |
| RecordPolicyMetric( |
| "SafeBrowsing.UnverifiedDownloads.AllowedDueToDisabledService", |
| uma_file_type, requestor); |
| RespondWithPolicy(file, callback, requestor, |
| UnverifiedDownloadPolicy::ALLOWED); |
| return; |
| } |
| |
| if (service->database_manager() && |
| service->database_manager()->MatchDownloadWhitelistUrl(requestor)) { |
| RecordPolicyMetric("SafeBrowsing.UnverifiedDownloads.AllowedByWhitelist", |
| uma_file_type, requestor); |
| RespondWithPolicy(file, callback, requestor, |
| UnverifiedDownloadPolicy::ALLOWED); |
| return; |
| } |
| |
| CheckFieldTrialOnAnyThread(file, alternate_extensions, requestor, callback); |
| } |
| |
| } // namespace |
| |
| void CheckUnverifiedDownloadPolicy( |
| const GURL& requestor, |
| const base::FilePath& file, |
| const std::vector<base::FilePath::StringType>& alternate_extensions, |
| const UnverifiedDownloadCheckCompletionCallback& callback) { |
| // Record a count of alternate extensions. The count is capped so that it |
| // won't be unbounded. In practice, it's expected that numbers above 3 are |
| // rare. |
| int alternate_extension_count = |
| std::min<int>(alternate_extensions.size(), 16); |
| UMA_HISTOGRAM_SPARSE_SLOWLY( |
| "SafeBrowsing.UnverifiedDownloads.AlternateExtensionCount", |
| alternate_extension_count); |
| if (requestor.is_valid()) { |
| scoped_refptr<SafeBrowsingService> service = |
| g_browser_process->safe_browsing_service(); |
| BrowserThread::PostTask( |
| BrowserThread::IO, FROM_HERE, |
| base::Bind(&CheckWhitelistOnIOThread, service, requestor, file, |
| alternate_extensions, callback)); |
| return; |
| } |
| |
| CheckFieldTrialOnAnyThread(file, alternate_extensions, GURL(), callback); |
| } |
| |
| } // namespace safe_browsing |