chromium/ios/chrome/browser/safe_browsing/model/chrome_password_protection_service.h

// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef IOS_CHROME_BROWSER_SAFE_BROWSING_MODEL_CHROME_PASSWORD_PROTECTION_SERVICE_H_
#define IOS_CHROME_BROWSER_SAFE_BROWSING_MODEL_CHROME_PASSWORD_PROTECTION_SERVICE_H_

#import <map>
#import <string>
#import <vector>

#import "base/gtest_prod_util.h"
#import "base/memory/raw_ptr.h"
#import "base/memory/weak_ptr.h"
#import "components/keyed_service/core/keyed_service.h"
#import "components/password_manager/core/browser/insecure_credentials_helper.h"
#import "components/password_manager/core/browser/password_reuse_detector.h"
#import "components/password_manager/core/browser/password_store/password_store_interface.h"
#import "components/safe_browsing/core/browser/password_protection/metrics_util.h"
#import "components/safe_browsing/core/common/proto/csd.pb.h"
#import "components/safe_browsing/ios/browser/password_protection/password_protection_service.h"
#import "components/sync/protocol/gaia_password_reuse.pb.h"
#import "ios/chrome/browser/shared/model/profile/profile_ios_forward.h"

class GURL;
class PrefService;
class SafeBrowsingService;

namespace history {
class HistoryService;
}

namespace password_manager {
class PasswordStore;
}  // namespace password_manager

namespace safe_browsing {
class PasswordProtectionRequest;
class SafeBrowsingMetricsCollector;
}  // namespace safe_browsing

namespace web {
class WebState;
}  // namespace web

class ChromePasswordProtectionService
    : public safe_browsing::PasswordProtectionService,
      public KeyedService {
 public:
  using ChangePhishedCredentialsCallback = base::RepeatingCallback<void(
      password_manager::PasswordStoreInterface*,
      const password_manager::MatchingReusedCredential&)>;
  ChromePasswordProtectionService(
      SafeBrowsingService* sb_service,
      ChromeBrowserState* browser_state,
      history::HistoryService* history_service,
      safe_browsing::SafeBrowsingMetricsCollector*
          safe_browsing_metrics_collector,
      ChangePhishedCredentialsCallback add_phished_credentials =
          base::BindRepeating(&password_manager::AddPhishedCredentials),
      ChangePhishedCredentialsCallback remove_phished_credentials =
          base::BindRepeating(&password_manager::RemovePhishedCredentials));
  ~ChromePasswordProtectionService() override;

  // PasswordProtectionServiceBase:
  void RequestFinished(
      safe_browsing::PasswordProtectionRequest* request,
      safe_browsing::RequestOutcome outcome,
      std::unique_ptr<safe_browsing::LoginReputationClientResponse> response)
      override;

  void ShowModalWarning(
      safe_browsing::PasswordProtectionRequest* request,
      safe_browsing::LoginReputationClientResponse::VerdictType verdict_type,
      const std::string& verdict_token,
      safe_browsing::ReusedPasswordAccountType password_type) override;

  // Stores `verdict` in the cache based on its `trigger_type`, `url`,
  // reused `password_type`, `verdict` and `receive_time`.
  void CacheVerdict(
      const GURL& url,
      safe_browsing::LoginReputationClientRequest::TriggerType trigger_type,
      safe_browsing::ReusedPasswordAccountType password_type,
      const safe_browsing::LoginReputationClientResponse& verdict,
      const base::Time& receive_time) override;

  // Looks up the cached verdict response. If verdict is not available or is
  // expired, return VERDICT_TYPE_UNSPECIFIED. Can be called on any thread.
  safe_browsing::LoginReputationClientResponse::VerdictType GetCachedVerdict(
      const GURL& url,
      safe_browsing::LoginReputationClientRequest::TriggerType trigger_type,
      safe_browsing::ReusedPasswordAccountType password_type,
      safe_browsing::LoginReputationClientResponse* out_response) override;

  // Returns the number of saved verdicts for the given `trigger_type`.
  int GetStoredVerdictCount(
      safe_browsing::LoginReputationClientRequest::TriggerType trigger_type)
      override;

  void MaybeReportPasswordReuseDetected(
      const GURL& main_frame_url,
      const std::string& username,
      safe_browsing::PasswordType password_type,
      bool is_phishing_url,
      bool warning_shown) override;

  void ReportPasswordChanged() override;

  void FillReferrerChain(
      const GURL& event_url,
      SessionID event_tab_id,  // SessionID::InvalidValue()
                               // if tab not available.
      safe_browsing::LoginReputationClientRequest::Frame* frame) override;

  void SanitizeReferrerChain(
      safe_browsing::ReferrerChain* referrer_chain) override;

  void PersistPhishedSavedPasswordCredential(
      const std::vector<password_manager::MatchingReusedCredential>&
          matching_reused_credentials) override;

  void RemovePhishedSavedPasswordCredential(
      const std::vector<password_manager::MatchingReusedCredential>&
          matching_reused_credentials) override;

  safe_browsing::RequestOutcome GetPingNotSentReason(
      safe_browsing::LoginReputationClientRequest::TriggerType trigger_type,
      const GURL& url,
      safe_browsing::ReusedPasswordAccountType password_type) override;

  void RemoveUnhandledSyncPasswordReuseOnURLsDeleted(
      bool all_history,
      const history::URLRows& deleted_rows) override;

  bool UserClickedThroughSBInterstitial(
      safe_browsing::PasswordProtectionRequest* request) override;

  safe_browsing::PasswordProtectionTrigger
  GetPasswordProtectionWarningTriggerPref(
      safe_browsing::ReusedPasswordAccountType password_type) const override;

  safe_browsing::LoginReputationClientRequest::UrlDisplayExperiment
  GetUrlDisplayExperiment() const override;

  AccountInfo GetAccountInfo() const override;

  safe_browsing::ChromeUserPopulation::UserPopulation GetUserPopulationPref()
      const override;

  AccountInfo GetAccountInfoForUsername(
      const std::string& username) const override;

  safe_browsing::LoginReputationClientRequest::PasswordReuseEvent::
      SyncAccountType
      GetSyncAccountType() const override;

  bool CanShowInterstitial(
      safe_browsing::ReusedPasswordAccountType password_type,
      const GURL& main_frame_url) override;

  bool IsURLAllowlistedForPasswordEntry(const GURL& url) const override;

  bool IsInPasswordAlertMode(
      safe_browsing::ReusedPasswordAccountType password_type) override;

  bool CanSendSamplePing() override;

  bool IsPingingEnabled(
      safe_browsing::LoginReputationClientRequest::TriggerType trigger_type,
      safe_browsing::ReusedPasswordAccountType password_type) override;

  bool IsIncognito() override;

  bool IsExtendedReporting() override;

  bool IsPrimaryAccountSyncingHistory() const override;

  bool IsPrimaryAccountSignedIn() const override;

  bool IsAccountGmail(const std::string& username) const override;

  bool IsInExcludedCountry() override;

  // PasswordProtectionService override.
  void MaybeStartProtectedPasswordEntryRequest(
      web::WebState* web_state,
      const GURL& main_frame_url,
      const std::string& username,
      safe_browsing::PasswordType password_type,
      const std::vector<password_manager::MatchingReusedCredential>&
          matching_reused_credentials,
      bool password_field_exists,
      safe_browsing::PasswordProtectionService::ShowWarningCallback
          show_warning_callback) override;

  // PasswordProtectionService override.
  void MaybeLogPasswordReuseLookupEvent(
      web::WebState* web_state,
      safe_browsing::RequestOutcome outcome,
      safe_browsing::PasswordType password_type,
      const safe_browsing::LoginReputationClientResponse* response) override;

  // PasswordProtectionService override.
  void MaybeLogPasswordReuseDetectedEvent(web::WebState* web_state) override;

  // Records a Chrome Sync event with the result of the user's interaction with
  // the warning dialog.
  void MaybeLogPasswordReuseDialogInteraction(
      int64_t navigation_id,
      sync_pb::GaiaPasswordReuse::PasswordReuseDialogInteraction::
          InteractionResult interaction_result);

  // Gets the detailed warning text that should show in the modal warning
  // dialog.
  std::u16string GetWarningDetailText(
      safe_browsing::ReusedPasswordAccountType password_type) const;

  // Creates, starts, and tracks a new request.
  void StartRequest(
      web::WebState* web_state,
      const GURL& main_frame_url,
      const std::string& username,
      safe_browsing::PasswordType password_type,
      const std::vector<password_manager::MatchingReusedCredential>&
          matching_reused_credentials,
      safe_browsing::LoginReputationClientRequest::TriggerType trigger_type,
      bool password_field_exists,
      safe_browsing::PasswordProtectionService::ShowWarningCallback
          show_warning_callback);

  // Called when user interacts with password protection UIs.
  void OnUserAction(web::WebState* web_state,
                    safe_browsing::ReusedPasswordAccountType password_type,
                    safe_browsing::WarningAction action);

 protected:
  FRIEND_TEST_ALL_PREFIXES(ChromePasswordProtectionServiceTest,
                           VerifySendsPingForAboutBlank);

  void FillUserPopulation(
      const GURL& main_frame_url,
      safe_browsing::LoginReputationClientRequest* request_proto) override;

 private:
  // Returns true if the `web_state` is already showing a warning dialog.
  bool IsModalWarningShowingInWebState(web::WebState* web_state);
  // Removes all warning requests for `web_state`.
  void RemoveWarningRequestsByWebState(web::WebState* web_state);

  password_manager::PasswordStoreInterface* GetStoreForReusedCredential(
      const password_manager::MatchingReusedCredential& reused_credential);

  // Returns the profile PasswordStore associated with this instance.
  password_manager::PasswordStoreInterface* GetProfilePasswordStore() const;

  // Returns the GAIA-account-scoped PasswordStore associated with this
  // instance. The account password store contains passwords stored in the
  // account and is accessible only when the user is signed in and non syncing.
  password_manager::PasswordStoreInterface* GetAccountPasswordStore() const;

  // Gets prefs associated with `browser_state_`.
  PrefService* GetPrefs() const;

  // Returns whether `browser_state_` has safe browsing service enabled.
  bool IsSafeBrowsingEnabled();

  // Lookup for a callback for showing a warning for a given request.
  std::map<safe_browsing::PasswordProtectionRequest*,
           safe_browsing::PasswordProtectionService::ShowWarningCallback>
      show_warning_callbacks_;

  raw_ptr<ChromeBrowserState> browser_state_;

  // Calls `password_manager::AddPhishedCredentials`. Used to facilitate
  // testing.
  ChangePhishedCredentialsCallback add_phished_credentials_;

  // Calls `password_manager::RemovePhishedCredentials`. Used to facilitate
  // testing.
  ChangePhishedCredentialsCallback remove_phished_credentials_;

  base::WeakPtrFactory<ChromePasswordProtectionService> weak_factory_{this};
};

#endif  // IOS_CHROME_BROWSER_SAFE_BROWSING_MODEL_CHROME_PASSWORD_PROTECTION_SERVICE_H_