blob: 198c3458fccc01530ee85358427706d033055399 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// 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/safe_browsing_service.h"
#include <memory>
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "build/build_config.h"
#include "chrome/browser/download/download_item_warning_data.h"
#include "chrome/browser/prefs/browser_prefs.h"
#include "chrome/browser/safe_browsing/chrome_ping_manager_factory.h"
#include "chrome/browser/safe_browsing/download_protection/download_protection_service.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile.h"
#include "components/download/public/common/download_danger_type.h"
#include "components/download/public/common/mock_download_item.h"
#include "components/prefs/testing_pref_service.h"
#include "components/safe_browsing/content/browser/safe_browsing_service_interface.h"
#include "components/safe_browsing/core/browser/ping_manager.h"
#include "components/safe_browsing/core/common/features.h"
#include "components/safe_browsing/core/common/proto/csd.pb.h"
#include "components/safe_browsing/core/common/safe_browsing_policy_handler.h"
#include "components/safe_browsing/core/common/safe_browsing_prefs.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "components/unified_consent/pref_names.h"
#include "content/public/browser/download_item_utils.h"
#include "content/public/test/browser_task_environment.h"
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
#include "services/network/test/test_url_loader_factory.h"
#include "services/network/test/test_utils.h"
using network::GetUploadData;
using testing::Return;
using testing::ReturnRef;
using WarningSurface = DownloadItemWarningData::WarningSurface;
using WarningAction = DownloadItemWarningData::WarningAction;
using WarningActionEvent = DownloadItemWarningData::WarningActionEvent;
using DownloadWarningAction =
safe_browsing::ClientSafeBrowsingReportRequest::DownloadWarningAction;
namespace safe_browsing {
namespace {
const char kTestDownloadUrl[] = "https://example.com";
}
// Mock SafeBrowsingPrefChangeHandler.
class MockSafeBrowsingPrefChangeHandler
: public safe_browsing::SafeBrowsingPrefChangeHandler {
public:
explicit MockSafeBrowsingPrefChangeHandler(Profile* profile)
: SafeBrowsingPrefChangeHandler(profile) {}
MOCK_METHOD(void,
MaybeShowEnhancedProtectionSettingChangeNotification,
(),
(override));
};
class SafeBrowsingServiceTest : public testing::Test {
public:
SafeBrowsingServiceTest() {
feature_list_.InitAndDisableFeature(
safe_browsing::kExtendedReportingRemovePrefDependency);
}
void SetUp() override {
browser_process_ = TestingBrowserProcess::GetGlobal();
safe_browsing::SafeBrowsingServiceInterface::RegisterFactory(
GetSafeBrowsingServiceFactory());
// TODO(crbug.com/41437292): Port consumers of the |sb_service_| to use
// the interface in components/safe_browsing, and remove this cast.
sb_service_ = static_cast<SafeBrowsingService*>(
safe_browsing::SafeBrowsingService::CreateSafeBrowsingService());
auto ref_counted_url_loader_factory =
base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
&test_url_loader_factory_);
sb_service_->SetURLLoaderFactoryForTesting(ref_counted_url_loader_factory);
browser_process_->SetSafeBrowsingService(sb_service_.get());
sb_service_->Initialize();
base::RunLoop().RunUntilIdle();
profile_ = std::make_unique<TestingProfile>();
profile2_ = std::make_unique<TestingProfile>();
}
void TearDown() override {
sb_service_->SetURLLoaderFactoryForTesting(nullptr);
browser_process_->safe_browsing_service()->ShutDown();
browser_process_->SetSafeBrowsingService(nullptr);
safe_browsing::SafeBrowsingServiceInterface::RegisterFactory(nullptr);
base::RunLoop().RunUntilIdle();
}
Profile* profile() { return profile_.get(); }
void ResetAndReinitFeatures(
const std::vector<base::test::FeatureRef>& enabled_features,
const std::vector<base::test::FeatureRef>& disabled_features) {
feature_list_.Reset();
feature_list_.InitWithFeatures(enabled_features, disabled_features);
}
protected:
void SetUpDownload() {
content::DownloadItemUtils::AttachInfoForTesting(&download_item_, profile(),
/*web_contents=*/nullptr);
EXPECT_CALL(download_item_, GetDangerType())
.WillRepeatedly(Return(download::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST));
EXPECT_CALL(download_item_, IsDangerous()).WillRepeatedly(Return(true));
EXPECT_CALL(download_item_, GetURL())
.WillRepeatedly(ReturnRef(download_url_));
DownloadProtectionService::SetDownloadProtectionData(
&download_item_, "download_token",
ClientDownloadResponse::DANGEROUS_HOST,
ClientDownloadResponse::TailoredVerdict());
DownloadItemWarningData::AddWarningActionEvent(
&download_item_, WarningSurface::BUBBLE_MAINPAGE, WarningAction::SHOWN);
DownloadItemWarningData::AddWarningActionEvent(
&download_item_, WarningSurface::BUBBLE_SUBPAGE, WarningAction::CLOSE);
DownloadItemWarningData::AddWarningActionEvent(
&download_item_, WarningSurface::DOWNLOADS_PAGE,
WarningAction::DISCARD);
}
std::unique_ptr<ClientSafeBrowsingReportRequest> GetActualRequest(
const network::ResourceRequest& request) {
std::string request_string = GetUploadData(request);
auto actual_request = std::make_unique<ClientSafeBrowsingReportRequest>();
actual_request->ParseFromString(request_string);
return actual_request;
}
void VerifyDownloadReportRequest(
ClientSafeBrowsingReportRequest* actual_request) {
EXPECT_EQ(actual_request->type(),
ClientSafeBrowsingReportRequest::DANGEROUS_DOWNLOAD_OPENED);
EXPECT_EQ(actual_request->download_verdict(),
ClientDownloadResponse::DANGEROUS_HOST);
EXPECT_EQ(actual_request->url(), download_url_.spec());
EXPECT_TRUE(actual_request->did_proceed());
EXPECT_TRUE(actual_request->show_download_in_folder());
EXPECT_EQ(actual_request->token(), "download_token");
}
void VerifyInteractionOccurrenceCount(
const ClientSafeBrowsingReportRequest& report,
const ClientSafeBrowsingReportRequest::PhishySiteInteraction::
PhishySiteInteractionType& expected_interaction_type,
const int& expected_occurrence_count) {
// Find the interaction within the report by comparing
// security_interstitial_interaction.
for (auto interaction : report.phishy_site_interactions()) {
if (interaction.phishy_site_interaction_type() ==
expected_interaction_type) {
EXPECT_EQ(interaction.occurrence_count(), expected_occurrence_count);
break;
}
}
}
void VerifyPhishySiteReportRequest(
ClientSafeBrowsingReportRequest* actual_request,
GURL& expected_url,
int expected_interaction_size,
int expected_click_occurrences,
int expected_key_occurrences,
int expected_paste_occurrences) {
EXPECT_EQ(actual_request->type(),
ClientSafeBrowsingReportRequest::PHISHY_SITE_INTERACTIONS);
EXPECT_EQ(actual_request->url(), expected_url.spec());
EXPECT_EQ(actual_request->phishy_site_interactions_size(),
expected_interaction_size);
VerifyInteractionOccurrenceCount(
*actual_request,
ClientSafeBrowsingReportRequest::PhishySiteInteraction::
PHISHY_CLICK_EVENT,
expected_click_occurrences);
VerifyInteractionOccurrenceCount(
*actual_request,
ClientSafeBrowsingReportRequest::PhishySiteInteraction::
PHISHY_KEY_EVENT,
expected_key_occurrences);
VerifyInteractionOccurrenceCount(
*actual_request,
ClientSafeBrowsingReportRequest::PhishySiteInteraction::
PHISHY_PASTE_EVENT,
expected_paste_occurrences);
}
void VerifyDownloadWarningAction(
const ClientSafeBrowsingReportRequest::DownloadWarningAction&
warning_action,
DownloadWarningAction::Surface surface,
DownloadWarningAction::Action action,
bool is_terminal_action,
int64_t interval_msec) {
EXPECT_EQ(warning_action.surface(), surface);
EXPECT_EQ(warning_action.action(), action);
EXPECT_EQ(warning_action.is_terminal_action(), is_terminal_action);
EXPECT_EQ(warning_action.interval_msec(), interval_msec);
}
content::BrowserTaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
raw_ptr<TestingBrowserProcess> browser_process_;
scoped_refptr<SafeBrowsingService> sb_service_;
TestingProfile::Builder profile_builder_;
std::unique_ptr<TestingProfile> profile_;
std::unique_ptr<TestingProfile> profile2_;
raw_ptr<TestingProfile> otr_profile_;
::testing::NiceMock<download::MockDownloadItem> download_item_;
GURL download_url_ = GURL(kTestDownloadUrl);
private:
network::TestURLLoaderFactory test_url_loader_factory_;
base::test::ScopedFeatureList feature_list_;
ChromePingManagerAllowerForTesting allow_ping_manager_;
};
TEST_F(SafeBrowsingServiceTest, SendDownloadReport_Success) {
base::HistogramTester histogram_tester;
SetUpDownload();
SetExtendedReportingPrefForTests(profile_->GetPrefs(), true);
auto* ping_manager =
ChromePingManagerFactory::GetForBrowserContext(profile());
network::TestURLLoaderFactory test_url_loader_factory;
test_url_loader_factory.SetInterceptor(
base::BindLambdaForTesting([&](const network::ResourceRequest& request) {
std::unique_ptr<ClientSafeBrowsingReportRequest> actual_request =
GetActualRequest(request);
VerifyDownloadReportRequest(actual_request.get());
ASSERT_EQ(actual_request->download_warning_actions().size(), 2);
VerifyDownloadWarningAction(
actual_request->download_warning_actions().Get(0),
DownloadWarningAction::BUBBLE_SUBPAGE, DownloadWarningAction::CLOSE,
/*is_terminal_action=*/false, /*interval_msec=*/0);
VerifyDownloadWarningAction(
actual_request->download_warning_actions().Get(1),
DownloadWarningAction::DOWNLOADS_PAGE,
DownloadWarningAction::DISCARD,
/*is_terminal_action=*/true, /*interval_msec=*/0);
EXPECT_TRUE(actual_request->has_warning_shown_timestamp_msec());
}));
ping_manager->SetURLLoaderFactoryForTesting(
base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
&test_url_loader_factory));
sb_service_->SendDownloadReport(
&download_item_,
ClientSafeBrowsingReportRequest::DANGEROUS_DOWNLOAD_OPENED,
/*did_proceed=*/true,
/*show_download_in_folder=*/true);
histogram_tester.ExpectUniqueSample(
"SafeBrowsing.ClientSafeBrowsingReport.SendDownloadReportResult",
PingManager::ReportThreatDetailsResult::SUCCESS, 1);
}
TEST_F(
SafeBrowsingServiceTest,
SendDownloadReport_NoDownloadWarningActionWhenExtendedReportingDisabled) {
base::HistogramTester histogram_tester;
SetUpDownload();
SetExtendedReportingPrefForTests(profile_->GetPrefs(), false);
auto* ping_manager =
ChromePingManagerFactory::GetForBrowserContext(profile());
network::TestURLLoaderFactory test_url_loader_factory;
test_url_loader_factory.SetInterceptor(
base::BindLambdaForTesting([&](const network::ResourceRequest& request) {
std::unique_ptr<ClientSafeBrowsingReportRequest> actual_request =
GetActualRequest(request);
EXPECT_TRUE(actual_request->download_warning_actions().empty());
EXPECT_FALSE(actual_request->has_warning_shown_timestamp_msec());
}));
ping_manager->SetURLLoaderFactoryForTesting(
base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
&test_url_loader_factory));
sb_service_->SendDownloadReport(
&download_item_,
ClientSafeBrowsingReportRequest::DANGEROUS_DOWNLOAD_RECOVERY,
/*did_proceed=*/true,
/*show_download_in_folder=*/true);
histogram_tester.ExpectUniqueSample(
"SafeBrowsing.ClientSafeBrowsingReport.SendDownloadReportResult",
PingManager::ReportThreatDetailsResult::SUCCESS, 1);
}
TEST_F(SafeBrowsingServiceTest,
WhenUserIsInSPAndNotPolicyOrSIncognitoReturnsTrue) {
// Default scenario: User is in standard protection normally
EXPECT_TRUE(SafeBrowsingService::IsUserEligibleForESBPromo(profile()));
}
TEST_F(SafeBrowsingServiceTest, WhenSPIsSetByPolicyReturnsFalse) {
// Default scenario: User is in standard protection normally
EXPECT_TRUE(SafeBrowsingService::IsUserEligibleForESBPromo(profile()));
// Setting Standard protection through policy
profile_->GetTestingPrefService()->SetManagedPref(
prefs::kSafeBrowsingEnabled, std::make_unique<base::Value>(true));
profile_->GetTestingPrefService()->SetManagedPref(
prefs::kSafeBrowsingEnhanced, std::make_unique<base::Value>(false));
EXPECT_TRUE(
safe_browsing::IsSafeBrowsingPolicyManaged(*profile_->GetPrefs()));
EXPECT_FALSE(SafeBrowsingService::IsUserEligibleForESBPromo(profile()));
}
TEST_F(SafeBrowsingServiceTest, WhenEPIsSetByPolicyReturnsFalse) {
// Default scenario: User is in standard protection normally
EXPECT_TRUE(SafeBrowsingService::IsUserEligibleForESBPromo(profile()));
// Setting Enhanced protection through policy
profile_->GetTestingPrefService()->SetManagedPref(
prefs::kSafeBrowsingEnabled, std::make_unique<base::Value>(true));
profile_->GetTestingPrefService()->SetManagedPref(
prefs::kSafeBrowsingEnhanced, std::make_unique<base::Value>(true));
EXPECT_TRUE(
safe_browsing::IsSafeBrowsingPolicyManaged(*profile_->GetPrefs()));
EXPECT_FALSE(SafeBrowsingService::IsUserEligibleForESBPromo(profile()));
}
TEST_F(SafeBrowsingServiceTest, WhenNoProtectionIsSetByPolicyReturnsFalse) {
// Default scenario: User is in standard protection normally
EXPECT_TRUE(SafeBrowsingService::IsUserEligibleForESBPromo(profile()));
// Setting no protection by policy
profile_->GetTestingPrefService()->SetManagedPref(
prefs::kSafeBrowsingEnabled, std::make_unique<base::Value>(false));
profile_->GetTestingPrefService()->SetManagedPref(
prefs::kSafeBrowsingEnhanced, std::make_unique<base::Value>(false));
EXPECT_TRUE(
safe_browsing::IsSafeBrowsingPolicyManaged(*profile_->GetPrefs()));
EXPECT_FALSE(SafeBrowsingService::IsUserEligibleForESBPromo(profile()));
}
TEST_F(SafeBrowsingServiceTest, WhenUserIsInEPNormallyReturnsFalse) {
// Default scenario: User is in standard protection normally
EXPECT_TRUE(SafeBrowsingService::IsUserEligibleForESBPromo(profile()));
// Set enhanced protection normally
safe_browsing::SetSafeBrowsingState(
profile()->GetPrefs(),
safe_browsing::SafeBrowsingState::ENHANCED_PROTECTION);
EXPECT_FALSE(SafeBrowsingService::IsUserEligibleForESBPromo(profile()));
}
TEST_F(SafeBrowsingServiceTest, WhenUserIsIncognitoReturnsFalse) {
// Default scenario: User is in standard protection normally
EXPECT_TRUE(SafeBrowsingService::IsUserEligibleForESBPromo(profile()));
// Set profile to incognito
otr_profile_ = std::move(profile_builder_.BuildIncognito(profile_.get()));
EXPECT_FALSE(
SafeBrowsingService::IsUserEligibleForESBPromo(otr_profile_.get()));
}
TEST_F(SafeBrowsingServiceTest, WhenUserIsInNoProtectionNormallyoReturnsFalse) {
// Default scenario: User is in standard protection normally
EXPECT_TRUE(SafeBrowsingService::IsUserEligibleForESBPromo(profile()));
// Set no protection normally
safe_browsing::SetSafeBrowsingState(
profile()->GetPrefs(),
safe_browsing::SafeBrowsingState::NO_SAFE_BROWSING);
EXPECT_FALSE(SafeBrowsingService::IsUserEligibleForESBPromo(profile()));
}
TEST_F(SafeBrowsingServiceTest,
SaveExtendedReportingPrefValueOnProfileAddedFeatureFlagEnabled) {
ResetAndReinitFeatures(
{safe_browsing::kExtendedReportingRemovePrefDependency}, {});
SetExtendedReportingPrefForTests(profile_->GetPrefs(), true);
sb_service_->OnProfileAdded(profile());
// Since the user enabled Extended Reporting, the preference value used to
// record the state of Extended Reporting before its deprecation should be set
// to true.
EXPECT_TRUE(profile_->GetPrefs()->GetBoolean(
prefs::kSafeBrowsingScoutReportingEnabledWhenDeprecated));
}
TEST_F(SafeBrowsingServiceTest,
SaveExtendedReportingPrefValueOnProfileAddedFeatureFlagDisabled) {
// SetUp:
// * disable kExtendedReportingRemovePrefDependency
// * Setup SBER enabled and
// kSafeBrowsingScoutReportingEnabledWhenDeprecated true
ResetAndReinitFeatures(
{}, {safe_browsing::kExtendedReportingRemovePrefDependency});
SetExtendedReportingPrefForTests(profile_->GetPrefs(), true);
// Simulate that kSafeBrowsingScoutReportingEnabledWhenDeprecated was set to
// true previously.
profile_->GetPrefs()->SetBoolean(
prefs::kSafeBrowsingScoutReportingEnabledWhenDeprecated, true);
EXPECT_TRUE(profile_->GetPrefs()->GetBoolean(
prefs::kSafeBrowsingScoutReportingEnabledWhenDeprecated));
// Add the profile to trigger the function.
sb_service_->OnProfileAdded(profile());
// The value of the pref should be reverted to false because the feature is
// disabled now.
EXPECT_FALSE(profile_->GetPrefs()->GetBoolean(
prefs::kSafeBrowsingScoutReportingEnabledWhenDeprecated));
}
TEST_F(SafeBrowsingServiceTest, TestMinAllowedTimeForReferrerChains) {
sb_service_->OnProfileAdded(profile());
// If real-time URL lookups are disabled, referrer chains are not allowed.
EXPECT_EQ(sb_service_->GetMinAllowedTimestampForReferrerChains(profile()),
base::Time::Max());
// Enable ESB and check the timestamp is updated.
auto time_esb_enabled = base::Time::Now();
SetEnhancedProtectionPrefForTests(profile_->GetPrefs(), true);
EXPECT_EQ(sb_service_->GetMinAllowedTimestampForReferrerChains(profile()),
time_esb_enabled);
// Enable MBB and check the timestamp hasn't changed, since ESB is already
// enabled.
task_environment_.FastForwardBy(base::Seconds(1));
profile_->GetPrefs()->SetBoolean(
unified_consent::prefs::kUrlKeyedAnonymizedDataCollectionEnabled, true);
EXPECT_EQ(sb_service_->GetMinAllowedTimestampForReferrerChains(profile()),
time_esb_enabled);
// Disable MBB and check the timestamp hasn't changed, since ESB is still
// enabled.
task_environment_.FastForwardBy(base::Seconds(1));
profile_->GetPrefs()->SetBoolean(
unified_consent::prefs::kUrlKeyedAnonymizedDataCollectionEnabled, false);
EXPECT_EQ(sb_service_->GetMinAllowedTimestampForReferrerChains(profile()),
time_esb_enabled);
// Disable ESB and confirm the timestamp is the max time (referrer chains are
// not allowed).
SetEnhancedProtectionPrefForTests(profile_->GetPrefs(), false);
EXPECT_EQ(sb_service_->GetMinAllowedTimestampForReferrerChains(profile()),
base::Time::Max());
// Enable MBB and check the timestamp is updated.
task_environment_.FastForwardBy(base::Seconds(1));
auto time_mbb_enabled = base::Time::Now();
profile_->GetPrefs()->SetBoolean(
unified_consent::prefs::kUrlKeyedAnonymizedDataCollectionEnabled, true);
EXPECT_EQ(sb_service_->GetMinAllowedTimestampForReferrerChains(profile()),
time_mbb_enabled);
// Enable ESB and check the timestamp hasn't changed, since MBB is already
// enabled.
task_environment_.FastForwardBy(base::Seconds(1));
SetEnhancedProtectionPrefForTests(profile_->GetPrefs(), true);
EXPECT_EQ(sb_service_->GetMinAllowedTimestampForReferrerChains(profile()),
time_mbb_enabled);
// Disable ESB and check the timestamp hasn't changed, since MBB is still
// enabled.
task_environment_.FastForwardBy(base::Seconds(1));
SetEnhancedProtectionPrefForTests(profile_->GetPrefs(), false);
EXPECT_EQ(sb_service_->GetMinAllowedTimestampForReferrerChains(profile()),
time_mbb_enabled);
// Disable MBB and confirm the timestamp is the max time (referrer chains are
// not allowed).
profile_->GetPrefs()->SetBoolean(
unified_consent::prefs::kUrlKeyedAnonymizedDataCollectionEnabled, false);
EXPECT_EQ(sb_service_->GetMinAllowedTimestampForReferrerChains(profile()),
base::Time::Max());
}
TEST_F(SafeBrowsingServiceTest,
TestMinAllowedTimeForReferrerChains_EsbEnabledOnStartup) {
SetEnhancedProtectionPrefForTests(profile_->GetPrefs(), true);
sb_service_->OnProfileAdded(profile());
auto time_profile_added = base::Time::Now();
task_environment_.FastForwardBy(base::Seconds(1));
EXPECT_EQ(sb_service_->GetMinAllowedTimestampForReferrerChains(profile()),
time_profile_added);
}
TEST_F(SafeBrowsingServiceTest,
TestMinAllowedTimeForReferrerChains_MbbEnabledOnStartup) {
profile_->GetPrefs()->SetBoolean(
unified_consent::prefs::kUrlKeyedAnonymizedDataCollectionEnabled, true);
sb_service_->OnProfileAdded(profile());
auto time_profile_added = base::Time::Now();
task_environment_.FastForwardBy(base::Seconds(1));
EXPECT_EQ(sb_service_->GetMinAllowedTimestampForReferrerChains(profile()),
time_profile_added);
}
TEST_F(SafeBrowsingServiceTest,
TestMinAllowedTimeForReferrerChains_MultipleProfiles) {
profile_->GetPrefs()->SetBoolean(
unified_consent::prefs::kUrlKeyedAnonymizedDataCollectionEnabled, true);
sb_service_->OnProfileAdded(profile());
auto time_original_profile_enabled = base::Time::Now();
EXPECT_EQ(sb_service_->GetMinAllowedTimestampForReferrerChains(profile()),
time_original_profile_enabled);
auto second_profile = std::make_unique<TestingProfile>();
second_profile->GetPrefs()->SetBoolean(
unified_consent::prefs::kUrlKeyedAnonymizedDataCollectionEnabled, true);
// Checking a profile not currently tracked is not expected, but if it
// happens, it should not cause a crash.
EXPECT_EQ(sb_service_->GetMinAllowedTimestampForReferrerChains(
second_profile.get()),
base::Time::Max());
// Confirm the original profile still returns the original time and the second
// profile does not.
EXPECT_EQ(sb_service_->GetMinAllowedTimestampForReferrerChains(profile()),
time_original_profile_enabled);
EXPECT_EQ(sb_service_->GetMinAllowedTimestampForReferrerChains(
second_profile.get()),
base::Time::Max());
// Now add the second profile and again confirm the two profile return
// different time stamps.
task_environment_.FastForwardBy(base::Seconds(1));
sb_service_->OnProfileAdded(second_profile.get());
auto time_second_profile_enabled = base::Time::Now();
EXPECT_EQ(sb_service_->GetMinAllowedTimestampForReferrerChains(profile()),
time_original_profile_enabled);
EXPECT_EQ(sb_service_->GetMinAllowedTimestampForReferrerChains(
second_profile.get()),
time_second_profile_enabled);
// Triggering profile destruction should reset the timestamp back to the max
// timestamp.
sb_service_->OnProfileWillBeDestroyed(profile());
EXPECT_EQ(sb_service_->GetMinAllowedTimestampForReferrerChains(profile()),
base::Time::Max());
EXPECT_EQ(sb_service_->GetMinAllowedTimestampForReferrerChains(
second_profile.get()),
time_second_profile_enabled);
sb_service_->OnProfileWillBeDestroyed(second_profile.get());
EXPECT_EQ(sb_service_->GetMinAllowedTimestampForReferrerChains(profile()),
base::Time::Max());
EXPECT_EQ(sb_service_->GetMinAllowedTimestampForReferrerChains(
second_profile.get()),
base::Time::Max());
}
TEST_F(SafeBrowsingServiceTest, EnhancedProtectionPrefChange_SingleProfile) {
// 1. Create a single profile (using the fixture's profile).
Profile* profile1 = profile();
// 2. Create a mock SafeBrowsingPrefChangeHandler.
auto mock_handler1 =
std::make_unique<::testing::NiceMock<MockSafeBrowsingPrefChangeHandler>>(
profile1);
// 3. Set the expectation: The mock should be called once.
EXPECT_CALL(*mock_handler1,
MaybeShowEnhancedProtectionSettingChangeNotification());
// 4. Add the mock handler to the map.
sb_service_->pref_change_handlers_map_[profile1] = std::move(mock_handler1);
// 5. Call the method under test.
sb_service_->EnhancedProtectionPrefChange(profile1);
}
TEST_F(SafeBrowsingServiceTest,
EnhancedProtectionPrefChange_SupportsMultipleProfiles) {
// 1. Create multiple profiles.
Profile* profile1 = profile();
Profile* profile2_ptr = profile2_.get(); // Store the pointer before moving
// 2. Create mock SafeBrowsingPrefChangeHandlers for each profile.
auto mock_handler1 =
std::make_unique<::testing::NiceMock<MockSafeBrowsingPrefChangeHandler>>(
profile1);
auto mock_handler2 =
std::make_unique<::testing::NiceMock<MockSafeBrowsingPrefChangeHandler>>(
profile2_ptr);
// 3. Set expectations: Each mock should be called once.
EXPECT_CALL(*mock_handler1.get(),
MaybeShowEnhancedProtectionSettingChangeNotification());
EXPECT_CALL(*mock_handler2.get(),
MaybeShowEnhancedProtectionSettingChangeNotification());
// 4. Add the mock handlers to the map, associating them with their profiles.
sb_service_->pref_change_handlers_map_[profile1] = std::move(mock_handler1);
sb_service_->pref_change_handlers_map_[profile2_ptr] =
std::move(mock_handler2);
// 5. Call the method under test for each profile.
sb_service_->EnhancedProtectionPrefChange(profile1);
sb_service_->EnhancedProtectionPrefChange(profile2_ptr);
}
class SafeBrowsingServiceAntiPhishingTelemetryTest
: public SafeBrowsingServiceTest {
protected:
PhishySiteInteractionMap SetUpPhishyInteractionMap(
int expected_click_occurrences,
int expected_key_occurrences,
int expected_paste_occurrences) {
PhishySiteInteractionMap new_map;
if (expected_click_occurrences > 0) {
new_map.insert_or_assign(
ClientSafeBrowsingReportRequest::PhishySiteInteraction::
PHISHY_CLICK_EVENT,
PhishyPageInteractionDetails(
expected_click_occurrences,
base::Time::Now().InMillisecondsSinceUnixEpoch(),
base::Time::Now().InMillisecondsSinceUnixEpoch()));
}
if (expected_key_occurrences > 0) {
new_map.insert_or_assign(
ClientSafeBrowsingReportRequest::PhishySiteInteraction::
PHISHY_KEY_EVENT,
PhishyPageInteractionDetails(
expected_key_occurrences,
base::Time::Now().InMillisecondsSinceUnixEpoch(),
base::Time::Now().InMillisecondsSinceUnixEpoch()));
}
if (expected_paste_occurrences > 0) {
new_map.insert_or_assign(
ClientSafeBrowsingReportRequest::PhishySiteInteraction::
PHISHY_PASTE_EVENT,
PhishyPageInteractionDetails(
expected_paste_occurrences,
base::Time::Now().InMillisecondsSinceUnixEpoch(),
base::Time::Now().InMillisecondsSinceUnixEpoch()));
}
return new_map;
}
};
TEST_F(SafeBrowsingServiceAntiPhishingTelemetryTest,
SendPhishyInteractionsReport_Success) {
const int kExpectedClickEventCount = 5;
const int kExpectedKeyEventCount = 2;
const int kExpectedPasteEventCount = 0;
SetExtendedReportingPrefForTests(profile_->GetPrefs(), true);
GURL test_url("http://phishing.com");
GURL test_page_url("http://page_url.com");
PhishySiteInteractionMap test_map = SetUpPhishyInteractionMap(
kExpectedClickEventCount, kExpectedKeyEventCount,
kExpectedPasteEventCount);
auto* ping_manager =
ChromePingManagerFactory::GetForBrowserContext(profile());
network::TestURLLoaderFactory test_url_loader_factory;
test_url_loader_factory.SetInterceptor(
base::BindLambdaForTesting([&](const network::ResourceRequest& request) {
std::unique_ptr<ClientSafeBrowsingReportRequest> actual_request =
GetActualRequest(request);
VerifyPhishySiteReportRequest(
actual_request.get(), test_url, 2, kExpectedClickEventCount,
kExpectedKeyEventCount, kExpectedPasteEventCount);
}));
ping_manager->SetURLLoaderFactoryForTesting(
base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
&test_url_loader_factory));
EXPECT_TRUE(sb_service_->SendPhishyInteractionsReport(
profile(), test_url, test_page_url, test_map));
}
TEST_F(SafeBrowsingServiceAntiPhishingTelemetryTest,
WhenUserIsIncognitoDontSendReport) {
// Set profile to incognito
otr_profile_ = std::move(profile_builder_.BuildIncognito(profile_.get()));
const int kExpectedClickEventCount = 5;
const int kExpectedKeyEventCount = 2;
const int kExpectedPasteEventCount = 0;
SetExtendedReportingPrefForTests(otr_profile_->GetPrefs(), true);
GURL test_url("http://phishing.com");
GURL test_page_url("http://page_url.com");
PhishySiteInteractionMap test_map = SetUpPhishyInteractionMap(
kExpectedClickEventCount, kExpectedKeyEventCount,
kExpectedPasteEventCount);
EXPECT_FALSE(sb_service_->SendPhishyInteractionsReport(
otr_profile_.get(), test_url, test_page_url, test_map));
}
class SendNotificationsAcceptedTest : public SafeBrowsingServiceTest {
public:
void EnableNotificationsAcceptedFeature() {
scoped_feature_list_.InitAndEnableFeature(
safe_browsing::kCreateNotificationsAcceptedClientSafeBrowsingReports);
}
void DisableNotificationsAcceptedFeature() {
scoped_feature_list_.InitAndDisableFeature(
safe_browsing::kCreateNotificationsAcceptedClientSafeBrowsingReports);
}
std::unique_ptr<ClientSafeBrowsingReportRequest> GetActualRequest(
const network::ResourceRequest& request) {
std::string request_string = GetUploadData(request);
auto actual_request = std::make_unique<ClientSafeBrowsingReportRequest>();
actual_request->ParseFromString(request_string);
return actual_request;
}
void VerifyNotificationAcceptedReportRequest(
ClientSafeBrowsingReportRequest* actual_request,
GURL& expected_url,
GURL& expected_page_url,
GURL& expected_permission_prompt_origin,
int64_t expected_prompt_duration) {
EXPECT_EQ(
actual_request->type(),
ClientSafeBrowsingReportRequest::NOTIFICATION_PERMISSION_ACCEPTED);
EXPECT_EQ(actual_request->url(), expected_url.spec());
EXPECT_EQ(actual_request->page_url(), expected_page_url.spec());
EXPECT_EQ(actual_request->permission_prompt_info().origin(),
expected_permission_prompt_origin.spec());
EXPECT_EQ(actual_request->permission_prompt_info().display_duration_sec(),
expected_prompt_duration);
}
void SetUrlIsAllowlistedForTesting() {
sb_service_->SetUrlIsAllowlistedForTesting();
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
TEST_F(SendNotificationsAcceptedTest, SendReportForAllowlistedURL) {
EnableNotificationsAcceptedFeature();
SetUrlIsAllowlistedForTesting();
SetExtendedReportingPrefForTests(profile_->GetPrefs(), true);
GURL notification_url1("http://www.notification1.com/");
GURL notification_url2("http://www.notification2.com/");
GURL notification_url3("http://www.notification3.com/");
base::TimeDelta display_duration = base::Seconds(10);
auto* ping_manager =
ChromePingManagerFactory::GetForBrowserContext(profile());
network::TestURLLoaderFactory test_url_loader_factory;
bool request_validated = false;
test_url_loader_factory.SetInterceptor(
base::BindLambdaForTesting([&](const network::ResourceRequest& request) {
std::unique_ptr<ClientSafeBrowsingReportRequest> actual_request =
GetActualRequest(request);
VerifyNotificationAcceptedReportRequest(
actual_request.get(), notification_url1, notification_url2,
notification_url3, display_duration.InSeconds());
request_validated = true;
}));
ping_manager->SetURLLoaderFactoryForTesting(
base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
&test_url_loader_factory));
EXPECT_TRUE(sb_service_->MaybeSendNotificationsAcceptedReport(
nullptr, profile(), notification_url1, notification_url2,
notification_url3, display_duration));
EXPECT_TRUE(request_validated);
}
TEST_F(SendNotificationsAcceptedTest,
DontSendReportForNonExtendedReportingUser) {
EnableNotificationsAcceptedFeature();
SetUrlIsAllowlistedForTesting();
GURL notification_url1("http://www.notification1.com/");
GURL notification_url2("http://www.notification2.com/");
GURL notification_url3("http://www.notification3.com/");
base::TimeDelta display_duration = base::Seconds(10);
EXPECT_FALSE(sb_service_->MaybeSendNotificationsAcceptedReport(
nullptr, profile(), notification_url1, notification_url2,
notification_url3, display_duration));
}
TEST_F(SendNotificationsAcceptedTest, DontSendReportWhenFeatureIsNotEnabled) {
DisableNotificationsAcceptedFeature();
SetUrlIsAllowlistedForTesting();
SetExtendedReportingPrefForTests(profile_->GetPrefs(), true);
GURL notification_url1("http://www.notification1.com/");
GURL notification_url2("http://www.notification2.com/");
GURL notification_url3("http://www.notification3.com/");
base::TimeDelta display_duration = base::Seconds(10);
auto* ping_manager =
ChromePingManagerFactory::GetForBrowserContext(profile());
network::TestURLLoaderFactory test_url_loader_factory;
test_url_loader_factory.SetInterceptor(
base::BindLambdaForTesting([&](const network::ResourceRequest& request) {
std::unique_ptr<ClientSafeBrowsingReportRequest> actual_request =
GetActualRequest(request);
VerifyNotificationAcceptedReportRequest(
actual_request.get(), notification_url1, notification_url2,
notification_url3, display_duration.InSeconds());
}));
ping_manager->SetURLLoaderFactoryForTesting(
base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
&test_url_loader_factory));
EXPECT_FALSE(sb_service_->MaybeSendNotificationsAcceptedReport(
nullptr, profile(), notification_url1, notification_url2,
notification_url3, display_duration));
}
TEST_F(SendNotificationsAcceptedTest, DontSendReportWhenUserIsIncognito) {
// Set profile to incognito
otr_profile_ = std::move(profile_builder_.BuildIncognito(profile_.get()));
SetExtendedReportingPrefForTests(otr_profile_->GetPrefs(), true);
EnableNotificationsAcceptedFeature();
SetUrlIsAllowlistedForTesting();
GURL notification_url1("http://www.notification1.com/");
GURL notification_url2("http://www.notification2.com/");
GURL notification_url3("http://www.notification3.com/");
base::TimeDelta display_duration = base::Seconds(10);
EXPECT_FALSE(sb_service_->MaybeSendNotificationsAcceptedReport(
nullptr, otr_profile_.get(), notification_url1, notification_url2,
notification_url3, display_duration));
}
} // namespace safe_browsing