| // Copyright 2020 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #import "ios/components/security_interstitials/safe_browsing/safe_browsing_service_impl.h" |
| |
| #import "base/files/scoped_temp_dir.h" |
| #import "base/memory/raw_ptr.h" |
| #import "base/path_service.h" |
| #import "base/run_loop.h" |
| #import "base/test/bind.h" |
| #import "base/test/metrics/histogram_tester.h" |
| #import "base/test/scoped_feature_list.h" |
| #import "components/content_settings/core/browser/host_content_settings_map.h" |
| #import "components/prefs/pref_service.h" |
| #import "components/prefs/testing_pref_service.h" |
| #import "components/safe_browsing/core/browser/db/database_manager.h" |
| #import "components/safe_browsing/core/browser/db/metadata.pb.h" |
| #import "components/safe_browsing/core/browser/db/util.h" |
| #import "components/safe_browsing/core/browser/db/v4_database.h" |
| #import "components/safe_browsing/core/browser/db/v4_get_hash_protocol_manager.h" |
| #import "components/safe_browsing/core/browser/db/v4_protocol_manager_util.h" |
| #import "components/safe_browsing/core/browser/db/v4_test_util.h" |
| #import "components/safe_browsing/core/browser/realtime/url_lookup_service.h" |
| #import "components/safe_browsing/core/browser/safe_browsing_token_fetcher.h" |
| #import "components/safe_browsing/core/browser/safe_browsing_url_checker_impl.h" |
| #import "components/safe_browsing/core/browser/verdict_cache_manager.h" |
| #import "components/safe_browsing/core/common/features.h" |
| #import "components/safe_browsing/core/common/proto/realtimeapi.pb.h" |
| #import "components/safe_browsing/core/common/safe_browsing_prefs.h" |
| #import "components/safe_browsing/core/common/safebrowsing_constants.h" |
| #import "components/safe_browsing/ios/browser/safe_browsing_url_allow_list.h" |
| #import "components/sync_preferences/pref_service_syncable.h" |
| #import "components/sync_preferences/testing_pref_service_syncable.h" |
| #import "components/unified_consent/pref_names.h" |
| #import "components/unified_consent/unified_consent_service.h" |
| #import "ios/components/security_interstitials/safe_browsing/fake_safe_browsing_client.h" |
| #import "ios/components/security_interstitials/safe_browsing/safe_browsing_query_manager.h" |
| #import "ios/components/security_interstitials/safe_browsing/safe_browsing_unsafe_resource_container.h" |
| #import "ios/web/public/test/fakes/fake_browser_state.h" |
| #import "ios/web/public/test/fakes/fake_web_state.h" |
| #import "ios/web/public/test/web_task_environment.h" |
| #import "ios/web/public/thread/web_task_traits.h" |
| #import "ios/web/public/thread/web_thread.h" |
| #import "net/test/embedded_test_server/default_handlers.h" |
| #import "net/test/embedded_test_server/embedded_test_server.h" |
| #import "net/traffic_annotation/network_traffic_annotation_test_helper.h" |
| #import "services/network/public/cpp/shared_url_loader_factory.h" |
| #import "services/network/public/cpp/simple_url_loader.h" |
| #import "testing/platform_test.h" |
| |
| namespace { |
| |
| const char kSafePage[] = "https://example.test/safe.html"; |
| const char kMalwarePage[] = "https://unsafe.test/malware.html"; |
| |
| class TestUrlCheckerClient { |
| public: |
| TestUrlCheckerClient(SafeBrowsingService* safe_browsing_service, |
| web::BrowserState* browser_state, |
| SafeBrowsingClient* safe_browsing_client) |
| : safe_browsing_service_(safe_browsing_service), |
| safe_browsing_client_(safe_browsing_client) { |
| SafeBrowsingQueryManager::CreateForWebState(&web_state_, |
| safe_browsing_client_); |
| SafeBrowsingUrlAllowList::CreateForWebState(&web_state_); |
| SafeBrowsingUnsafeResourceContainer::CreateForWebState(&web_state_); |
| web_state_.SetBrowserState(browser_state); |
| } |
| |
| ~TestUrlCheckerClient() = default; |
| |
| TestUrlCheckerClient(const TestUrlCheckerClient&) = delete; |
| TestUrlCheckerClient& operator=(const TestUrlCheckerClient&) = delete; |
| |
| bool url_is_unsafe() const { return url_is_unsafe_; } |
| |
| safe_browsing::SafeBrowsingUrlCheckerImpl::PerformedCheck performed_check() |
| const { |
| return performed_check_; |
| } |
| |
| void CheckUrl(const GURL& url) { |
| result_pending_ = true; |
| url_checker_ = safe_browsing_service_->CreateUrlChecker( |
| network::mojom::RequestDestination::kDocument, &web_state_, |
| safe_browsing_client_); |
| if (base::FeatureList::IsEnabled(safe_browsing::kSafeBrowsingOnUIThread)) { |
| CheckUrlOnSBThread(url); |
| } else { |
| web::GetIOThreadTaskRunner({})->PostTask( |
| FROM_HERE, base::BindOnce(&TestUrlCheckerClient::CheckUrlOnSBThread, |
| base::Unretained(this), url)); |
| } |
| } |
| |
| void CheckSubFrameUrl(const GURL& url) { |
| result_pending_ = true; |
| url_checker_ = safe_browsing_service_->CreateUrlChecker( |
| network::mojom::RequestDestination::kIframe, &web_state_, |
| safe_browsing_client_); |
| if (base::FeatureList::IsEnabled(safe_browsing::kSafeBrowsingOnUIThread)) { |
| CheckUrlOnSBThread(url); |
| } else { |
| web::GetIOThreadTaskRunner({})->PostTask( |
| FROM_HERE, base::BindOnce(&TestUrlCheckerClient::CheckUrlOnSBThread, |
| base::Unretained(this), url)); |
| } |
| } |
| |
| bool result_pending() const { return result_pending_; } |
| |
| void WaitForResult() { |
| while (result_pending()) { |
| base::RunLoop().RunUntilIdle(); |
| } |
| } |
| |
| private: |
| void CheckUrlOnSBThread(const GURL& url) { |
| url_checker_->CheckUrl( |
| url, "GET", |
| base::BindOnce(&TestUrlCheckerClient::OnCheckUrlResult, |
| base::Unretained(this))); |
| } |
| |
| void OnCheckUrlResult( |
| safe_browsing::SafeBrowsingUrlCheckerImpl::NativeUrlCheckNotifier* |
| slow_check_notifier, |
| bool proceed, |
| bool showed_interstitial, |
| bool has_post_commit_interstitial_skipped, |
| safe_browsing::SafeBrowsingUrlCheckerImpl::PerformedCheck |
| performed_check) { |
| if (slow_check_notifier) { |
| *slow_check_notifier = |
| base::BindOnce(&TestUrlCheckerClient::OnCheckUrlResult, |
| base::Unretained(this), nullptr); |
| return; |
| } |
| url_is_unsafe_ = !proceed; |
| result_pending_ = false; |
| performed_check_ = performed_check; |
| url_checker_.reset(); |
| } |
| |
| void CheckDone() { result_pending_ = false; } |
| |
| bool result_pending_ = false; |
| bool url_is_unsafe_ = false; |
| safe_browsing::SafeBrowsingUrlCheckerImpl::PerformedCheck performed_check_ = |
| safe_browsing::SafeBrowsingUrlCheckerImpl::PerformedCheck::kUnknown; |
| raw_ptr<SafeBrowsingService> safe_browsing_service_; |
| web::FakeWebState web_state_; |
| std::unique_ptr<safe_browsing::SafeBrowsingUrlCheckerImpl> url_checker_; |
| raw_ptr<SafeBrowsingClient> safe_browsing_client_; |
| }; |
| |
| } // namespace |
| |
| class SafeBrowsingServiceTest : public PlatformTest { |
| public: |
| SafeBrowsingServiceTest() |
| : task_environment_(web::WebTaskEnvironment::IO_MAINLOOP), |
| browser_state_(new web::FakeBrowserState()) { |
| store_factory_ = new safe_browsing::TestV4StoreFactory(); |
| safe_browsing::V4Database::RegisterStoreFactoryForTest( |
| base::WrapUnique(store_factory_.get())); |
| |
| v4_db_factory_ = new safe_browsing::TestV4DatabaseFactory(); |
| safe_browsing::V4Database::RegisterDatabaseFactoryForTest( |
| base::WrapUnique(v4_db_factory_.get())); |
| |
| v4_get_hash_factory_ = |
| new safe_browsing::TestV4GetHashProtocolManagerFactory(); |
| safe_browsing::V4GetHashProtocolManager::RegisterFactory( |
| base::WrapUnique(v4_get_hash_factory_.get())); |
| |
| pref_service_ = |
| std::make_unique<sync_preferences::TestingPrefServiceSyncable>(); |
| HostContentSettingsMap::RegisterProfilePrefs(pref_service_->registry()); |
| safe_browsing::RegisterProfilePrefs(pref_service_->registry()); |
| unified_consent::UnifiedConsentService::RegisterPrefs( |
| pref_service_->registry()); |
| |
| safe_browsing_service_ = base::MakeRefCounted<SafeBrowsingServiceImpl>(); |
| |
| CHECK(temp_dir_.CreateUniqueTempDir()); |
| safe_browsing_service_->Initialize( |
| pref_service_.get(), temp_dir_.GetPath(), |
| /*safe_browsing_metrics_collector=*/nullptr); |
| base::RunLoop().RunUntilIdle(); |
| |
| SetupUrlLookupService(); |
| } |
| |
| SafeBrowsingServiceTest(const SafeBrowsingServiceTest&) = delete; |
| SafeBrowsingServiceTest& operator=(const SafeBrowsingServiceTest&) = delete; |
| |
| ~SafeBrowsingServiceTest() override { |
| safe_browsing_service_->ShutDown(); |
| if (host_content_settings_map_) { |
| host_content_settings_map_->ShutdownOnUIThread(); |
| } |
| |
| safe_browsing::V4GetHashProtocolManager::RegisterFactory(nullptr); |
| safe_browsing::V4Database::RegisterDatabaseFactoryForTest(nullptr); |
| safe_browsing::V4Database::RegisterStoreFactoryForTest(nullptr); |
| } |
| |
| void MarkUrlAsMalware(const GURL& bad_url) { |
| if (base::FeatureList::IsEnabled(safe_browsing::kSafeBrowsingOnUIThread)) { |
| MarkUrlAsMalwareOnSBThread(bad_url); |
| } else { |
| web::GetIOThreadTaskRunner({})->PostTask( |
| FROM_HERE, |
| base::BindOnce(&SafeBrowsingServiceTest::MarkUrlAsMalwareOnSBThread, |
| base::Unretained(this), bad_url)); |
| } |
| } |
| |
| // Adds the given `safe_url` to the allowlist used by real-time checks. |
| void MarkUrlAsRealTimeSafe(const GURL& safe_url) { |
| if (base::FeatureList::IsEnabled(safe_browsing::kSafeBrowsingOnUIThread)) { |
| MarkUrlAsSafeOnSBThread(safe_url); |
| } else { |
| web::GetIOThreadTaskRunner({})->PostTask( |
| FROM_HERE, |
| base::BindOnce(&SafeBrowsingServiceTest::MarkUrlAsSafeOnSBThread, |
| base::Unretained(this), safe_url)); |
| } |
| } |
| |
| // Caches the given `bad_url` as unsafe in the VerdictCacheManager used by |
| // real-time checks. |
| void MarkUrlAsRealTimeUnsafe(const GURL& bad_url) { |
| safe_browsing::RTLookupResponse response; |
| safe_browsing::RTLookupResponse::ThreatInfo* threat_info = |
| response.add_threat_info(); |
| threat_info->set_verdict_type( |
| safe_browsing::RTLookupResponse::ThreatInfo::DANGEROUS); |
| threat_info->set_threat_type( |
| safe_browsing::RTLookupResponse::ThreatInfo::SOCIAL_ENGINEERING); |
| threat_info->set_cache_duration_sec(100); |
| threat_info->set_cache_expression_using_match_type(bad_url.host() + "/"); |
| threat_info->set_cache_expression_match_type( |
| safe_browsing::RTLookupResponse::ThreatInfo::COVERING_MATCH); |
| verdict_cache_manager_->CacheRealTimeUrlVerdict(response, |
| base::Time::Now()); |
| } |
| |
| protected: |
| void SetUpVerdict(GURL url, bool is_unsafe) { |
| verdict_cache_manager_->CacheArtificialHashRealTimeLookupVerdict(url.spec(), |
| is_unsafe); |
| } |
| |
| web::WebTaskEnvironment task_environment_; |
| scoped_refptr<SafeBrowsingService> safe_browsing_service_; |
| std::unique_ptr<web::FakeBrowserState> browser_state_; |
| std::unique_ptr<sync_preferences::TestingPrefServiceSyncable> pref_service_; |
| FakeSafeBrowsingClient safe_browsing_client_; |
| safe_browsing::hash_realtime_utils::GoogleChromeBrandingPretenderForTesting |
| apply_branding_; |
| base::test::ScopedFeatureList scoped_feature_list_; |
| web::FakeWebState web_state_; |
| |
| private: |
| void MarkUrlAsMalwareOnSBThread(const GURL& bad_url) { |
| safe_browsing::FullHashInfo full_hash_info = |
| safe_browsing::GetFullHashInfoWithMetadata( |
| bad_url, safe_browsing::GetUrlMalwareId(), |
| safe_browsing::ThreatMetadata()); |
| v4_db_factory_->MarkPrefixAsBad(safe_browsing::GetUrlMalwareId(), |
| full_hash_info.full_hash); |
| v4_get_hash_factory_->AddToFullHashCache(full_hash_info); |
| } |
| |
| void MarkUrlAsSafeOnSBThread(const GURL& bad_url) { |
| safe_browsing::FullHashInfo full_hash_info = |
| safe_browsing::GetFullHashInfoWithMetadata( |
| bad_url, safe_browsing::GetUrlMalwareId(), |
| safe_browsing::ThreatMetadata()); |
| v4_db_factory_->MarkPrefixAsBad( |
| safe_browsing::GetUrlHighConfidenceAllowlistId(), |
| full_hash_info.full_hash); |
| v4_get_hash_factory_->AddToFullHashCache(full_hash_info); |
| } |
| |
| void SetupUrlLookupService() { |
| host_content_settings_map_ = base::MakeRefCounted<HostContentSettingsMap>( |
| pref_service_.get(), /*is_off_the_record=*/false, |
| /*store_last_modified=*/false, /*restore_session=*/false, |
| /*should_record_metrics=*/false); |
| verdict_cache_manager_ = |
| std::make_unique<safe_browsing::VerdictCacheManager>( |
| /*history_service=*/nullptr, host_content_settings_map_.get(), |
| pref_service_.get(), /*sync_observer=*/nullptr); |
| lookup_service_ = std::make_unique<safe_browsing::RealTimeUrlLookupService>( |
| safe_browsing_service_->GetURLLoaderFactory(), |
| verdict_cache_manager_.get(), base::BindRepeating([] { |
| safe_browsing::ChromeUserPopulation population; |
| return population; |
| }), |
| pref_service_.get(), |
| /*token_fetcher=*/nullptr, |
| base::BindRepeating([](bool) { return false; }), |
| /*is_off_the_record=*/false, |
| /*variations_service=*/nullptr, |
| /*referrer_chain_provider=*/nullptr, |
| /*webui_delegate=*/nullptr); |
| safe_browsing_client_.set_real_time_url_lookup_service( |
| lookup_service_.get()); |
| } |
| |
| base::ScopedTempDir temp_dir_; |
| |
| // Owned by V4Database. |
| raw_ptr<safe_browsing::TestV4DatabaseFactory> v4_db_factory_; |
| // Owned by V4GetHashProtocolManager. |
| raw_ptr<safe_browsing::TestV4GetHashProtocolManagerFactory> |
| v4_get_hash_factory_; |
| // Owned by V4Database. |
| raw_ptr<safe_browsing::TestV4StoreFactory> store_factory_; |
| scoped_refptr<HostContentSettingsMap> host_content_settings_map_; |
| std::unique_ptr<safe_browsing::VerdictCacheManager> verdict_cache_manager_; |
| std::unique_ptr<safe_browsing::RealTimeUrlLookupService> lookup_service_; |
| }; |
| |
| TEST_F(SafeBrowsingServiceTest, SafeAndUnsafePages) { |
| // Verify that queries to the Safe Browsing database owned by |
| // SafeBrowsingService receive responses. |
| TestUrlCheckerClient client(safe_browsing_service_.get(), |
| browser_state_.get(), &safe_browsing_client_); |
| GURL safe_url = GURL(kSafePage); |
| client.CheckUrl(safe_url); |
| if (!base::FeatureList::IsEnabled(safe_browsing::kSafeBrowsingOnUIThread)) { |
| EXPECT_TRUE(client.result_pending()); |
| client.WaitForResult(); |
| } |
| EXPECT_FALSE(client.result_pending()); |
| EXPECT_FALSE(client.url_is_unsafe()); |
| |
| GURL unsafe_url = GURL(kMalwarePage); |
| MarkUrlAsMalware(unsafe_url); |
| client.CheckUrl(unsafe_url); |
| EXPECT_TRUE(client.result_pending()); |
| client.WaitForResult(); |
| EXPECT_FALSE(client.result_pending()); |
| EXPECT_TRUE(client.url_is_unsafe()); |
| |
| // Disable Safe Browsing, and ensure that unsafe URLs are no longer flagged. |
| pref_service_->SetBoolean(prefs::kSafeBrowsingEnabled, false); |
| client.CheckUrl(unsafe_url); |
| if (!base::FeatureList::IsEnabled(safe_browsing::kSafeBrowsingOnUIThread)) { |
| EXPECT_TRUE(client.result_pending()); |
| client.WaitForResult(); |
| } |
| EXPECT_FALSE(client.result_pending()); |
| EXPECT_FALSE(client.url_is_unsafe()); |
| } |
| |
| // Verifies that safe and unsafe URLs are identified correctly when real-time |
| // lookups are enabled, and that opting out of real-time checks works as |
| // expected. |
| TEST_F(SafeBrowsingServiceTest, RealTimeSafeAndUnsafePages) { |
| TestUrlCheckerClient client(safe_browsing_service_.get(), |
| browser_state_.get(), &safe_browsing_client_); |
| |
| // Wait for an initial result to make sure the Safe Browsing database has |
| // been initialized, before calling into functions that mark URLs as safe |
| // or unsafe in the database. |
| GURL safe_url(kSafePage); |
| client.CheckUrl(safe_url); |
| client.WaitForResult(); |
| |
| // Opt into real-time checks. |
| pref_service_->SetBoolean( |
| unified_consent::prefs::kUrlKeyedAnonymizedDataCollectionEnabled, true); |
| |
| MarkUrlAsRealTimeSafe(safe_url); |
| client.CheckUrl(safe_url); |
| EXPECT_TRUE(client.result_pending()); |
| client.WaitForResult(); |
| EXPECT_FALSE(client.result_pending()); |
| EXPECT_FALSE(client.url_is_unsafe()); |
| |
| GURL unsafe_url(kMalwarePage); |
| MarkUrlAsRealTimeUnsafe(unsafe_url); |
| client.CheckUrl(unsafe_url); |
| EXPECT_TRUE(client.result_pending()); |
| client.WaitForResult(); |
| EXPECT_FALSE(client.result_pending()); |
| EXPECT_TRUE(client.url_is_unsafe()); |
| |
| // Opt out of real-time checks, and ensure that unsafe URLs are no longer |
| // flagged. |
| pref_service_->SetBoolean( |
| unified_consent::prefs::kUrlKeyedAnonymizedDataCollectionEnabled, false); |
| client.CheckUrl(unsafe_url); |
| if (!base::FeatureList::IsEnabled(safe_browsing::kSafeBrowsingOnUIThread)) { |
| EXPECT_TRUE(client.result_pending()); |
| client.WaitForResult(); |
| } |
| EXPECT_FALSE(client.result_pending()); |
| EXPECT_FALSE(client.url_is_unsafe()); |
| } |
| |
| TEST_F(SafeBrowsingServiceTest, |
| RealTimeSafeAndUnsafePagesWithEnhancedProtection) { |
| TestUrlCheckerClient client(safe_browsing_service_.get(), |
| browser_state_.get(), &safe_browsing_client_); |
| |
| // Wait for an initial result to make sure the Safe Browsing database has |
| // been initialized, before calling into functions that mark URLs as safe |
| // or unsafe in the database. |
| GURL safe_url(kSafePage); |
| client.CheckUrl(safe_url); |
| client.WaitForResult(); |
| |
| // Opt into real-time checks. |
| pref_service_->SetBoolean(prefs::kSafeBrowsingEnhanced, true); |
| |
| MarkUrlAsRealTimeSafe(safe_url); |
| client.CheckUrl(safe_url); |
| EXPECT_TRUE(client.result_pending()); |
| client.WaitForResult(); |
| EXPECT_FALSE(client.result_pending()); |
| EXPECT_FALSE(client.url_is_unsafe()); |
| |
| MarkUrlAsRealTimeSafe(safe_url); |
| client.CheckSubFrameUrl(safe_url); |
| EXPECT_TRUE(client.result_pending()); |
| client.WaitForResult(); |
| EXPECT_FALSE(client.result_pending()); |
| EXPECT_FALSE(client.url_is_unsafe()); |
| |
| GURL unsafe_url(kMalwarePage); |
| MarkUrlAsRealTimeUnsafe(unsafe_url); |
| client.CheckUrl(unsafe_url); |
| EXPECT_TRUE(client.result_pending()); |
| client.WaitForResult(); |
| EXPECT_FALSE(client.result_pending()); |
| EXPECT_TRUE(client.url_is_unsafe()); |
| |
| // Subframe URL should not be checked. |
| MarkUrlAsRealTimeUnsafe(unsafe_url); |
| client.CheckSubFrameUrl(unsafe_url); |
| EXPECT_TRUE(client.result_pending()); |
| client.WaitForResult(); |
| EXPECT_FALSE(client.result_pending()); |
| EXPECT_FALSE(client.url_is_unsafe()); |
| |
| // Opt out of real-time checks, and ensure that unsafe URLs are no longer |
| // flagged. |
| pref_service_->SetBoolean(prefs::kSafeBrowsingEnhanced, false); |
| client.CheckUrl(unsafe_url); |
| if (!base::FeatureList::IsEnabled(safe_browsing::kSafeBrowsingOnUIThread)) { |
| EXPECT_TRUE(client.result_pending()); |
| client.WaitForResult(); |
| } |
| EXPECT_FALSE(client.result_pending()); |
| EXPECT_FALSE(client.url_is_unsafe()); |
| } |
| |
| // Verifies that cookies are persisted across calls to |
| // SafeBrowsingServiceImpl::GetURLLoaderFactory. |
| TEST_F(SafeBrowsingServiceTest, PersistentCookies) { |
| net::EmbeddedTestServer server(net::EmbeddedTestServer::TYPE_HTTPS); |
| net::test_server::RegisterDefaultHandlers(&server); |
| ASSERT_TRUE(server.Start()); |
| std::string cookie = "test=123"; |
| std::unique_ptr<network::ResourceRequest> resource_request = |
| std::make_unique<network::ResourceRequest>(); |
| |
| // Set a cookie that expires in an hour. |
| resource_request->url = server.GetURL("/set-cookie?" + cookie + |
| ";max-age=3600;SameSite=None;Secure"); |
| std::unique_ptr<network::SimpleURLLoader> url_loader = |
| network::SimpleURLLoader::Create(std::move(resource_request), |
| TRAFFIC_ANNOTATION_FOR_TESTS); |
| base::RunLoop run_loop1; |
| url_loader->DownloadHeadersOnly( |
| safe_browsing_service_->GetURLLoaderFactory().get(), |
| base::BindLambdaForTesting( |
| [&](scoped_refptr<net::HttpResponseHeaders> headers) { |
| run_loop1.Quit(); |
| })); |
| run_loop1.Run(); |
| |
| // Make another request to the same site, and verify that the cookie is still |
| // set. |
| resource_request = std::make_unique<network::ResourceRequest>(); |
| resource_request->url = server.GetURL("/echoheader?Cookie"); |
| url_loader = network::SimpleURLLoader::Create(std::move(resource_request), |
| TRAFFIC_ANNOTATION_FOR_TESTS); |
| base::RunLoop run_loop2; |
| url_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie( |
| safe_browsing_service_->GetURLLoaderFactory().get(), |
| base::BindLambdaForTesting([&](std::unique_ptr<std::string> body) { |
| EXPECT_NE(std::string::npos, body->find(cookie)); |
| run_loop2.Quit(); |
| })); |
| run_loop2.Run(); |
| } |
| |
| // Verifies that cookies are cleared when ClearCookies() is called with a |
| // time range of all-time, but not otherwise. |
| TEST_F(SafeBrowsingServiceTest, ClearCookies) { |
| net::EmbeddedTestServer server(net::EmbeddedTestServer::TYPE_HTTPS); |
| net::test_server::RegisterDefaultHandlers(&server); |
| ASSERT_TRUE(server.Start()); |
| std::string cookie = "test=123"; |
| std::unique_ptr<network::ResourceRequest> resource_request = |
| std::make_unique<network::ResourceRequest>(); |
| |
| // Set a cookie that expires in an hour. |
| resource_request->url = server.GetURL("/set-cookie?" + cookie + |
| ";max-age=3600;SameSite=None;Secure"); |
| std::unique_ptr<network::SimpleURLLoader> url_loader = |
| network::SimpleURLLoader::Create(std::move(resource_request), |
| TRAFFIC_ANNOTATION_FOR_TESTS); |
| base::RunLoop run_loop1; |
| url_loader->DownloadHeadersOnly( |
| safe_browsing_service_->GetURLLoaderFactory().get(), |
| base::BindLambdaForTesting( |
| [&](scoped_refptr<net::HttpResponseHeaders> headers) { |
| run_loop1.Quit(); |
| })); |
| run_loop1.Run(); |
| |
| // Call ClearCookies() with a non-all-time time range, and verify that the |
| // cookie is still set. |
| base::RunLoop run_loop2; |
| safe_browsing_service_->ClearCookies( |
| net::CookieDeletionInfo::TimeRange(base::Time(), base::Time::Now()), |
| base::BindLambdaForTesting([&]() { run_loop2.Quit(); })); |
| run_loop2.Run(); |
| |
| resource_request = std::make_unique<network::ResourceRequest>(); |
| resource_request->url = server.GetURL("/echoheader?Cookie"); |
| url_loader = network::SimpleURLLoader::Create(std::move(resource_request), |
| TRAFFIC_ANNOTATION_FOR_TESTS); |
| base::RunLoop run_loop3; |
| url_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie( |
| safe_browsing_service_->GetURLLoaderFactory().get(), |
| base::BindLambdaForTesting([&](std::unique_ptr<std::string> body) { |
| EXPECT_NE(std::string::npos, body->find(cookie)); |
| run_loop3.Quit(); |
| })); |
| run_loop3.Run(); |
| |
| // Call ClearCookies() with a time range of all-time, and verify that the |
| // cookie is no longer set. |
| base::RunLoop run_loop4; |
| safe_browsing_service_->ClearCookies( |
| net::CookieDeletionInfo::TimeRange(base::Time(), base::Time::Max()), |
| base::BindLambdaForTesting([&]() { run_loop4.Quit(); })); |
| run_loop4.Run(); |
| |
| resource_request = std::make_unique<network::ResourceRequest>(); |
| resource_request->url = server.GetURL("/echoheader?Cookie"); |
| url_loader = network::SimpleURLLoader::Create(std::move(resource_request), |
| TRAFFIC_ANNOTATION_FOR_TESTS); |
| base::RunLoop run_loop5; |
| url_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie( |
| safe_browsing_service_->GetURLLoaderFactory().get(), |
| base::BindLambdaForTesting([&](std::unique_ptr<std::string> body) { |
| EXPECT_EQ(std::string::npos, body->find(cookie)); |
| run_loop5.Quit(); |
| })); |
| run_loop5.Run(); |
| } |
| |
| // Verfies that http requests sent by SafeBrowsingServiceImpl's network context |
| // have a non-empty User-Agent header. |
| TEST_F(SafeBrowsingServiceTest, NonEmptyUserAgent) { |
| net::EmbeddedTestServer server(net::EmbeddedTestServer::TYPE_HTTPS); |
| net::test_server::RegisterDefaultHandlers(&server); |
| ASSERT_TRUE(server.Start()); |
| std::unique_ptr<network::ResourceRequest> resource_request = |
| std::make_unique<network::ResourceRequest>(); |
| |
| // Ask the server to echo the User-Agent header and verify that the echoed |
| // value is non-empty. |
| resource_request = std::make_unique<network::ResourceRequest>(); |
| resource_request->url = server.GetURL("/echoheader?User-Agent"); |
| std::unique_ptr<network::SimpleURLLoader> url_loader = |
| network::SimpleURLLoader::Create(std::move(resource_request), |
| TRAFFIC_ANNOTATION_FOR_TESTS); |
| base::RunLoop run_loop; |
| url_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie( |
| safe_browsing_service_->GetURLLoaderFactory().get(), |
| base::BindLambdaForTesting([&](std::unique_ptr<std::string> body) { |
| EXPECT_FALSE(body->empty()); |
| run_loop.Quit(); |
| })); |
| run_loop.Run(); |
| } |
| |
| // Verifies that Safe Browsing hash prefix metrics are correctly recorded and |
| // the performed check is correct when the hash prefix feature is enabled. |
| TEST_F(SafeBrowsingServiceTest, HashPrefixEnabled) { |
| scoped_feature_list_.InitAndEnableFeature( |
| safe_browsing::kHashPrefixRealTimeLookups); |
| TestUrlCheckerClient client(safe_browsing_service_.get(), |
| browser_state_.get(), &safe_browsing_client_); |
| pref_service_->SetBoolean(prefs::kSafeBrowsingEnabled, true); |
| |
| base::HistogramTester histogram_tester; |
| GURL url = GURL(kMalwarePage); |
| SetUpVerdict(url, /*is_unsafe=*/true); |
| client.CheckUrl(url); |
| |
| EXPECT_TRUE(client.result_pending()); |
| client.WaitForResult(); |
| EXPECT_FALSE(client.result_pending()); |
| EXPECT_EQ(safe_browsing::SafeBrowsingUrlCheckerImpl::PerformedCheck:: |
| kHashRealTimeCheck, |
| client.performed_check()); |
| histogram_tester.ExpectBucketCount( |
| "SafeBrowsing.HPRT.Ineligible.IneligibleForSessionOrLocation", |
| /*sample=*/false, |
| /*expected_bucket_count=*/1); |
| |
| task_environment_.RunUntilIdle(); |
| } |
| |
| // Verifies that Safe Browsing hash prefix metrics are correctly recorded and |
| // the performed check is correct when the hash prefix feature is disabled. |
| TEST_F(SafeBrowsingServiceTest, HashPrefixDisabled) { |
| scoped_feature_list_.InitAndDisableFeature( |
| safe_browsing::kHashPrefixRealTimeLookups); |
| TestUrlCheckerClient client(safe_browsing_service_.get(), |
| browser_state_.get(), &safe_browsing_client_); |
| |
| pref_service_->SetBoolean(prefs::kSafeBrowsingEnabled, true); |
| |
| base::HistogramTester histogram_tester; |
| GURL url = GURL(kMalwarePage); |
| SetUpVerdict(url, /*is_unsafe=*/true); |
| client.CheckUrl(url); |
| |
| EXPECT_TRUE(client.result_pending()); |
| client.WaitForResult(); |
| EXPECT_FALSE(client.result_pending()); |
| EXPECT_EQ(safe_browsing::SafeBrowsingUrlCheckerImpl::PerformedCheck:: |
| kHashDatabaseCheck, |
| client.performed_check()); |
| histogram_tester.ExpectBucketCount( |
| "SafeBrowsing.HPRT.Ineligible.IneligibleForSessionOrLocation", |
| /*sample=*/true, |
| /*expected_bucket_count=*/1); |
| |
| task_environment_.RunUntilIdle(); |
| } |
| |
| using SafeBrowsingServiceInitializationTest = PlatformTest; |
| |
| // Verifies that GetURLLoaderFactory() has a non-null return value when called |
| // immediately after initialization. |
| TEST_F(SafeBrowsingServiceInitializationTest, GetURLLoaderFactory) { |
| web::WebTaskEnvironment task_environment; |
| |
| std::unique_ptr<web::FakeBrowserState> browser_state = |
| std::make_unique<web::FakeBrowserState>(); |
| std::unique_ptr<sync_preferences::TestingPrefServiceSyncable> prefs = |
| std::make_unique<sync_preferences::TestingPrefServiceSyncable>(); |
| safe_browsing::RegisterProfilePrefs(prefs->registry()); |
| |
| base::ScopedTempDir temp_dir; |
| ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
| |
| scoped_refptr<SafeBrowsingService> safe_browsing_service = |
| base::MakeRefCounted<SafeBrowsingServiceImpl>(); |
| safe_browsing_service->Initialize( |
| prefs.get(), temp_dir.GetPath(), |
| /*safe_browsing_metrics_collector=*/nullptr); |
| |
| EXPECT_TRUE(safe_browsing_service->GetURLLoaderFactory()); |
| |
| safe_browsing_service->ShutDown(); |
| task_environment.RunUntilIdle(); |
| } |
| |
| // Verifies that Safe Browsing preference metrics are correctly recorded when |
| // Safe Browsing is enabled but Enhanced Safe Browsing is not. |
| TEST_F(SafeBrowsingServiceInitializationTest, |
| PreferenceMetricsStandardSafeBrowsing) { |
| web::WebTaskEnvironment task_environment; |
| |
| std::unique_ptr<web::FakeBrowserState> browser_state = |
| std::make_unique<web::FakeBrowserState>(); |
| std::unique_ptr<sync_preferences::TestingPrefServiceSyncable> prefs = |
| std::make_unique<sync_preferences::TestingPrefServiceSyncable>(); |
| safe_browsing::RegisterProfilePrefs(prefs->registry()); |
| |
| base::ScopedTempDir temp_dir; |
| ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
| |
| scoped_refptr<SafeBrowsingService> safe_browsing_service = |
| base::MakeRefCounted<SafeBrowsingServiceImpl>(); |
| prefs->SetBoolean(prefs::kSafeBrowsingEnabled, true); |
| prefs->SetBoolean(prefs::kSafeBrowsingEnhanced, false); |
| base::HistogramTester histogram_tester; |
| safe_browsing_service->Initialize( |
| prefs.get(), temp_dir.GetPath(), |
| /*safe_browsing_metrics_collector=*/nullptr); |
| histogram_tester.ExpectUniqueSample( |
| safe_browsing::kSafeBrowsingEnabledHistogramName, /*sample=*/1, |
| /*count=*/1); |
| histogram_tester.ExpectUniqueSample("SafeBrowsing.Pref.Enhanced", |
| /*sample=*/0, /*count=*/1); |
| |
| safe_browsing_service->ShutDown(); |
| task_environment.RunUntilIdle(); |
| } |
| |
| // Verifies that Safe Browsing preference metrics are correctly recorded when |
| // Enhanced Safe Browsing is enabled. |
| TEST_F(SafeBrowsingServiceInitializationTest, |
| PreferenceMetricsEnhancedSafeBrowsing) { |
| web::WebTaskEnvironment task_environment; |
| |
| std::unique_ptr<web::FakeBrowserState> browser_state = |
| std::make_unique<web::FakeBrowserState>(); |
| std::unique_ptr<sync_preferences::TestingPrefServiceSyncable> prefs = |
| std::make_unique<sync_preferences::TestingPrefServiceSyncable>(); |
| safe_browsing::RegisterProfilePrefs(prefs->registry()); |
| |
| base::ScopedTempDir temp_dir; |
| ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
| |
| scoped_refptr<SafeBrowsingService> safe_browsing_service = |
| base::MakeRefCounted<SafeBrowsingServiceImpl>(); |
| prefs->SetBoolean(prefs::kSafeBrowsingEnabled, true); |
| prefs->SetBoolean(prefs::kSafeBrowsingEnhanced, true); |
| base::HistogramTester histogram_tester; |
| safe_browsing_service->Initialize( |
| prefs.get(), temp_dir.GetPath(), |
| /*safe_browsing_metrics_collector=*/nullptr); |
| histogram_tester.ExpectUniqueSample( |
| safe_browsing::kSafeBrowsingEnabledHistogramName, /*sample=*/1, |
| /*count=*/1); |
| histogram_tester.ExpectUniqueSample("SafeBrowsing.Pref.Enhanced", |
| /*sample=*/1, /*count=*/1); |
| |
| safe_browsing_service->ShutDown(); |
| task_environment.RunUntilIdle(); |
| } |
| |
| // Verifies that Safe Browsing preference metrics are correctly recorded when |
| // Safe Browsing is disabled. |
| TEST_F(SafeBrowsingServiceInitializationTest, PreferenceMetricsNoSafeBrowsing) { |
| web::WebTaskEnvironment task_environment; |
| |
| std::unique_ptr<web::FakeBrowserState> browser_state = |
| std::make_unique<web::FakeBrowserState>(); |
| std::unique_ptr<sync_preferences::TestingPrefServiceSyncable> prefs = |
| std::make_unique<sync_preferences::TestingPrefServiceSyncable>(); |
| safe_browsing::RegisterProfilePrefs(prefs->registry()); |
| |
| base::ScopedTempDir temp_dir; |
| ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
| |
| scoped_refptr<SafeBrowsingService> safe_browsing_service = |
| base::MakeRefCounted<SafeBrowsingServiceImpl>(); |
| prefs->SetBoolean(prefs::kSafeBrowsingEnabled, false); |
| prefs->SetBoolean(prefs::kSafeBrowsingEnhanced, false); |
| base::HistogramTester histogram_tester; |
| safe_browsing_service->Initialize( |
| prefs.get(), temp_dir.GetPath(), |
| /*safe_browsing_metrics_collector=*/nullptr); |
| histogram_tester.ExpectUniqueSample( |
| safe_browsing::kSafeBrowsingEnabledHistogramName, /*sample=*/0, |
| /*count=*/1); |
| histogram_tester.ExpectUniqueSample("SafeBrowsing.Pref.Enhanced", |
| /*sample=*/0, /*count=*/1); |
| |
| safe_browsing_service->ShutDown(); |
| task_environment.RunUntilIdle(); |
| } |