#include "chrome/browser/safe_browsing/chrome_password_protection_service.h"
#include <memory>
#include <utility>
#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/bind.h"
#include "base/test/mock_callback.h"
#include "build/build_config.h"
#include "chrome/browser/enterprise/connectors/reporting/realtime_reporting_client_factory.h"
#include "chrome/browser/password_manager/account_password_store_factory.h"
#include "chrome/browser/password_manager/profile_password_store_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/safe_browsing/chrome_safe_browsing_blocking_page_factory.h"
#include "chrome/browser/safe_browsing/chrome_ui_manager_delegate.h"
#include "chrome/browser/signin/chrome_signin_client_factory.h"
#include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
#include "chrome/browser/signin/test_signin_client_builder.h"
#include "chrome/browser/sync/user_event_service_factory.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "chrome/test/base/scoped_testing_local_state.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "components/password_manager/core/browser/hash_password_manager.h"
#include "components/password_manager/core/browser/password_manager_metrics_util.h"
#include "components/password_manager/core/browser/password_manager_test_utils.h"
#include "components/password_manager/core/browser/password_reuse_detector.h"
#include "components/password_manager/core/browser/password_store/mock_password_store_interface.h"
#include "components/password_manager/core/browser/split_stores_and_local_upm.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/scoped_user_pref_update.h"
#include "components/safe_browsing/content/browser/password_protection/password_protection_commit_deferring_condition.h"
#include "components/safe_browsing/content/browser/password_protection/password_protection_request_content.h"
#include "components/safe_browsing/content/browser/ui_manager.h"
#include "components/safe_browsing/core/browser/db/v4_protocol_manager_util.h"
#include "components/safe_browsing/core/browser/verdict_cache_manager.h"
#include "components/safe_browsing/core/common/features.h"
#include "components/safe_browsing/core/common/utils.h"
#include "components/signin/public/identity_manager/account_info.h"
#include "components/strings/grit/components_strings.h"
#include "components/sync/model/data_type_controller_delegate.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "components/sync_user_events/fake_user_event_service.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/mock_navigation_handle.h"
#include "net/http/http_util.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/l10n/l10n_util.h"
#if BUILDFLAG(IS_ANDROID)
#include "base/android/build_info.h"
#include "chrome/browser/password_manager/android/mock_password_checkup_launcher_helper.h"
#include "chrome/browser/sync/sync_service_factory.h"
#include "components/sync/test/test_sync_service.h"
#endif
#if !BUILDFLAG(IS_ANDROID)
#include "chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router_factory.h"
#include "chrome/browser/safe_browsing/test_extension_event_observer.h"
#include "chrome/common/extensions/api/safe_browsing_private.h"
#include "extensions/browser/test_event_router.h"
#endif
MatchingReusedCredential;
UserEventSpecifics;
GaiaPasswordReuse;
GaiaPasswordCaptured;
PasswordReuseDialogInteraction;
PasswordReuseEvent;
PasswordReuseLookup;
_;
Return;
WithArg;
#if !BUILDFLAG(IS_ANDROID)
OnPolicySpecifiedPasswordReuseDetected;
OnPolicySpecifiedPasswordChanged;
#endif
class MockSecurityEventRecorder : public SecurityEventRecorder { … };
namespace safe_browsing {
namespace {
const char kPhishingURL[] = …;
const char kTestEmail[] = …;
const char kUserName[] = …;
const char kRedirectURL[] = …;
#if !BUILDFLAG(IS_ANDROID)
const char kPasswordReuseURL[] = …;
const char kTestGmail[] = …;
#endif
BrowserContextKeyedServiceFactory::TestingFactory
GetFakeUserEventServiceFactory() { … }
constexpr struct { … } kTestCasesWithoutVerdict[]{ … };
#if BUILDFLAG(IS_ANDROID)
std::unique_ptr<KeyedService> CreateTestSyncService(
content::BrowserContext* context) {
return std::make_unique<syncer::TestSyncService>();
}
#endif
}
class MockChromePasswordProtectionService
: public ChromePasswordProtectionService { … };
class ChromePasswordProtectionServiceTest
: public ChromeRenderViewHostTestHarness { … };
TEST_F(ChromePasswordProtectionServiceTest,
VerifyUserPopulationForPasswordOnFocusPing) { … }
TEST_F(ChromePasswordProtectionServiceTest,
VerifyUserPopulationForSavedPasswordEntryPing) { … }
TEST_F(ChromePasswordProtectionServiceTest,
VerifyUserPopulationForSyncPasswordEntryPing) { … }
TEST_F(ChromePasswordProtectionServiceTest,
VerifyPingingIsSkippedIfMatchEnterpriseAllowlist) { … }
TEST_F(ChromePasswordProtectionServiceTest,
VerifyPersistPhishedSavedPasswordCredential) { … }
TEST_F(ChromePasswordProtectionServiceTest,
VerifyRemovePhishedSavedPasswordCredential) { … }
TEST_F(ChromePasswordProtectionServiceTest, VerifyCanSendSamplePing) { … }
TEST_F(ChromePasswordProtectionServiceTest, VerifyGetOrganizationTypeGmail) { … }
TEST_F(ChromePasswordProtectionServiceTest, VerifyGetOrganizationTypeGSuite) { … }
TEST_F(ChromePasswordProtectionServiceTest, VerifyUpdateSecurityState) { … }
TEST_F(ChromePasswordProtectionServiceTest,
VerifyPasswordReuseUserEventNotRecordedDueToIncognito) { … }
TEST_F(ChromePasswordProtectionServiceTest,
VerifyPasswordReuseDetectedUserEventRecorded) { … }
TEST_F(ChromePasswordProtectionServiceTest,
VerifyPasswordReuseDetectedSecurityEventRecorded) { … }
#if !BUILDFLAG(IS_ANDROID)
TEST_F(ChromePasswordProtectionServiceTest,
VerifyPasswordCaptureEventScheduledOnStartup) { … }
TEST_F(ChromePasswordProtectionServiceTest,
VerifyPasswordCaptureEventScheduledFromPref) { … }
TEST_F(ChromePasswordProtectionServiceTest,
VerifyPasswordCaptureEventRecorded) { … }
TEST_F(ChromePasswordProtectionServiceTest,
VerifyPasswordCaptureEventReschedules) { … }
#endif
TEST_F(ChromePasswordProtectionServiceTest,
VerifyPasswordReuseLookupUserEventRecorded) { … }
TEST_F(ChromePasswordProtectionServiceTest, VerifyGetDefaultChangePasswordURL) { … }
TEST_F(ChromePasswordProtectionServiceTest, VerifyGetEnterprisePasswordURL) { … }
TEST_F(ChromePasswordProtectionServiceTest,
VerifyNavigationDuringPasswordOnFocusPingNotBlocked) { … }
TEST_F(ChromePasswordProtectionServiceTest,
VerifyNavigationDuringPasswordReusePingDeferred) { … }
TEST_F(ChromePasswordProtectionServiceTest,
VerifyNavigationDuringModalWarningDeferred) { … }
TEST_F(ChromePasswordProtectionServiceTest,
VerifyCommitDeferringConditionRemovedWhenNavigationHandleIsGone) { … }
TEST_F(ChromePasswordProtectionServiceTest,
VerifyUnhandledSyncPasswordReuseUponClearHistoryDeletion) { … }
#if !BUILDFLAG(IS_ANDROID)
TEST_F(ChromePasswordProtectionServiceTest,
VerifyOnPolicySpecifiedPasswordChangedEvent) { … }
TEST_F(
ChromePasswordProtectionServiceTest,
VerifyTriggerOnPolicySpecifiedPasswordReuseDetectedForEnterprisePasswordWithAlertMode) { … }
TEST_F(
ChromePasswordProtectionServiceTest,
VerifyTriggerOnPolicySpecifiedPasswordReuseDetectedForEnterprisePasswordOnChromeExtension) { … }
TEST_F(ChromePasswordProtectionServiceTest,
VerifyTriggerOnPolicySpecifiedPasswordReuseDetectedForGsuiteUser) { … }
TEST_F(ChromePasswordProtectionServiceTest,
VerifyTriggerOnPolicySpecifiedPasswordReuseDetectedForGmailUser) { … }
#endif
TEST_F(ChromePasswordProtectionServiceTest, VerifyGetWarningDetailTextSaved) { … }
TEST_F(ChromePasswordProtectionServiceTest,
VerifyGetWarningDetailTextEnterprise) { … }
TEST_F(ChromePasswordProtectionServiceTest, VerifyGetWarningDetailTextGmail) { … }
TEST_F(ChromePasswordProtectionServiceTest, VerifyCanShowInterstitial) { … }
TEST_F(ChromePasswordProtectionServiceTest, VerifySendsPingForAboutBlank) { … }
TEST_F(ChromePasswordProtectionServiceTest, VerifyGetPingNotSentReason) { … }
TEST_F(ChromePasswordProtectionServiceTest, VerifyPageLoadToken) { … }
namespace {
class ChromePasswordProtectionServiceWithAccountPasswordStoreTest
: public ChromePasswordProtectionServiceTest { … };
TEST_F(ChromePasswordProtectionServiceWithAccountPasswordStoreTest,
VerifyPersistPhishedSavedPasswordCredential) { … }
TEST_F(ChromePasswordProtectionServiceWithAccountPasswordStoreTest,
VerifyRemovePhishedSavedPasswordCredential) { … }
#if BUILDFLAG(IS_ANDROID)
class PasswordCheckupWithPhishGuardTest
: public ChromePasswordProtectionServiceTest {
protected:
void SetUpSyncService(bool is_syncing_passwords) {
CoreAccountInfo account;
account.email = profile()->GetProfileUserName();
sync_service_ = static_cast<syncer::TestSyncService*>(
SyncServiceFactory::GetInstance()->SetTestingFactoryAndUse(
profile(), base::BindRepeating(&CreateTestSyncService)));
sync_service_->SetSignedIn(signin::ConsentLevel::kSync, account);
ASSERT_TRUE(sync_service_->IsSyncFeatureEnabled());
sync_service_->GetUserSettings()->SetSelectedType(
syncer::UserSelectableType::kPasswords, is_syncing_passwords);
}
void SimulateChangePasswordDialogAction(bool is_syncing) {
ReusedPasswordAccountType password_account_type;
password_account_type.set_account_type(
ReusedPasswordAccountType::SAVED_PASSWORD);
password_account_type.set_is_account_syncing(is_syncing);
service_->OnUserAction(
web_contents(), password_account_type, RequestOutcome::UNKNOWN,
LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED, "unused_token",
WarningUIType::MODAL_DIALOG, WarningAction::CHANGE_PASSWORD);
}
raw_ptr<syncer::TestSyncService> sync_service_ = nullptr;
};
class PasswordCheckupWithPhishGuardAfterPasswordStoreSplitAndroidTest
: public PasswordCheckupWithPhishGuardTest {
public:
void SetUp() override {
base::android::BuildInfo::GetInstance()->set_gms_version_code_for_test(
base::NumberToString(password_manager::GetLocalUpmMinGmsVersion()));
PasswordCheckupWithPhishGuardTest::SetUp();
}
};
TEST_F(PasswordCheckupWithPhishGuardAfterPasswordStoreSplitAndroidTest,
VerifyPhishGuardDialogOpensPasswordCheckupForAccountStoreSyncing) {
service_->ConfigService(false,
true);
std::vector<password_manager::MatchingReusedCredential> credentials = {
{"http://example.test", u"username",
password_manager::PasswordForm::Store::kAccountStore}};
service_->set_saved_passwords_matching_reused_credentials(credentials);
SetUpSyncService(true);
EXPECT_CALL(
*mock_checkup_launcher_,
LaunchCheckupOnDevice(
_, profile(), web_contents()->GetTopLevelNativeWindow(),
password_manager::PasswordCheckReferrerAndroid::kPhishedWarningDialog,
TestingProfile::kDefaultProfileUserName));
SimulateChangePasswordDialogAction(true);
}
TEST_F(PasswordCheckupWithPhishGuardAfterPasswordStoreSplitAndroidTest,
VerifyPhishGuardDialogOpensPasswordCheckupForProfileStoreSyncing) {
service_->ConfigService(false,
true);
std::vector<password_manager::MatchingReusedCredential> credentials = {
{"http://example.test", u"username",
password_manager::PasswordForm::Store::kProfileStore}};
service_->set_saved_passwords_matching_reused_credentials(credentials);
SetUpSyncService(true);
EXPECT_CALL(
*mock_checkup_launcher_,
LaunchCheckupOnDevice(
_, profile(), web_contents()->GetTopLevelNativeWindow(),
password_manager::PasswordCheckReferrerAndroid::kPhishedWarningDialog,
""));
SimulateChangePasswordDialogAction(true);
}
TEST_F(PasswordCheckupWithPhishGuardAfterPasswordStoreSplitAndroidTest,
VerifyPhishGuardDialogOpensPasswordCheckupForProfileStoreNotSyncing) {
service_->ConfigService(false,
true);
std::vector<password_manager::MatchingReusedCredential> credentials = {
{"http://example.test", u"username",
password_manager::PasswordForm::Store::kProfileStore}};
service_->set_saved_passwords_matching_reused_credentials(credentials);
SetUpSyncService(false);
EXPECT_CALL(
*mock_checkup_launcher_,
LaunchCheckupOnDevice(
_, profile(), web_contents()->GetTopLevelNativeWindow(),
password_manager::PasswordCheckReferrerAndroid::kPhishedWarningDialog,
""));
SimulateChangePasswordDialogAction(false);
}
TEST_F(PasswordCheckupWithPhishGuardAfterPasswordStoreSplitAndroidTest,
VerifyPhishGuardDialogOpensSafetyCheckMenuForBothStoresSyncing) {
service_->ConfigService(false,
true);
std::vector<password_manager::MatchingReusedCredential> credentials = {
{"http://example.test", u"username",
password_manager::PasswordForm::Store::kProfileStore},
{"http://2.example.test", u"username",
password_manager::PasswordForm::Store::kAccountStore}};
service_->set_saved_passwords_matching_reused_credentials(credentials);
SetUpSyncService(true);
EXPECT_CALL(*mock_checkup_launcher_,
LaunchSafetyCheck(_, web_contents()->GetTopLevelNativeWindow()));
SimulateChangePasswordDialogAction(true);
}
class PasswordCheckupWithPhishGuardUPMBeforeStoreSplitAndroidTest
: public PasswordCheckupWithPhishGuardTest {
public:
void SetUp() override {
base::android::BuildInfo::GetInstance()->set_gms_version_code_for_test("0");
PasswordCheckupWithPhishGuardTest::SetUp();
}
};
TEST_F(
PasswordCheckupWithPhishGuardUPMBeforeStoreSplitAndroidTest,
VerifyPhishGuardDialogOpensPasswordCheckupEmptyAccountForNonSyncingUser) {
service_->ConfigService(false,
true);
std::vector<password_manager::MatchingReusedCredential> credentials = {
{"http://example.test", u"username",
password_manager::PasswordForm::Store::kProfileStore}};
service_->set_saved_passwords_matching_reused_credentials(credentials);
SetUpSyncService(false);
EXPECT_CALL(
*mock_checkup_launcher_,
LaunchCheckupOnDevice(
_, profile(), web_contents()->GetTopLevelNativeWindow(),
password_manager::PasswordCheckReferrerAndroid::kPhishedWarningDialog,
""));
SimulateChangePasswordDialogAction(false);
}
TEST_F(PasswordCheckupWithPhishGuardUPMBeforeStoreSplitAndroidTest,
VerifyPhishGuardDialogOpensPasswordCheckupWithAnAccountForSyncingUser) {
service_->ConfigService(false,
true);
std::vector<password_manager::MatchingReusedCredential> credentials = {
{"http://example.test", u"username",
password_manager::PasswordForm::Store::kProfileStore}};
service_->set_saved_passwords_matching_reused_credentials(credentials);
SetUpSyncService(true);
EXPECT_CALL(
*mock_checkup_launcher_,
LaunchCheckupOnDevice(
_, profile(), web_contents()->GetTopLevelNativeWindow(),
password_manager::PasswordCheckReferrerAndroid::kPhishedWarningDialog,
TestingProfile::kDefaultProfileUserName));
SimulateChangePasswordDialogAction(true);
}
#endif
}
}