| // Copyright 2023 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef COMPONENTS_PLUS_ADDRESSES_PLUS_ADDRESS_SERVICE_H_ |
| #define COMPONENTS_PLUS_ADDRESSES_PLUS_ADDRESS_SERVICE_H_ |
| |
| #include <optional> |
| #include <set> |
| #include <string> |
| #include <unordered_set> |
| |
| #include "base/scoped_observation.h" |
| #include "components/autofill/core/browser/autofill_plus_address_delegate.h" |
| #include "components/keyed_service/core/keyed_service.h" |
| #include "components/plus_addresses/plus_address_http_client.h" |
| #include "components/plus_addresses/plus_address_types.h" |
| #include "components/signin/public/identity_manager/account_info.h" |
| #include "components/signin/public/identity_manager/identity_manager.h" |
| #include "components/signin/public/identity_manager/primary_account_change_event.h" |
| #include "google_apis/gaia/google_service_auth_error.h" |
| #include "url/origin.h" |
| |
| class PrefService; |
| |
| namespace signin { |
| class IdentityManager; |
| class PersistentRepeatingTimer; |
| } // namespace signin |
| |
| namespace plus_addresses { |
| |
| // An experimental class for filling plus addresses (asdf+123@some-domain.com). |
| // Not intended for widespread use. |
| class PlusAddressService : public KeyedService, |
| public autofill::AutofillPlusAddressDelegate, |
| public signin::IdentityManager::Observer { |
| public: |
| // Limits the number of retries allowed for the initial poll request. |
| const int MAX_INITIAL_POLL_RETRY_ATTEMPTS = 1; |
| |
| // Used to simplify testing in cases where calls depending on external classes |
| // can be mocked out. |
| PlusAddressService(); |
| // Used to simplify testing in cases where calls depend on just the |
| // `IdentityManager`. |
| explicit PlusAddressService(signin::IdentityManager* identity_manager); |
| ~PlusAddressService() override; |
| |
| // Initialize the PlusAddressService with a `IdentityManager`, `PrefService`, |
| // and a `SharedURLLoaderFactory`. |
| PlusAddressService(signin::IdentityManager* identity_manager, |
| PrefService* pref_service, |
| PlusAddressHttpClient plus_address_client); |
| |
| // autofill::AutofillPlusAddressDelegate: |
| // Checks whether the passed-in string is a known plus address. |
| bool IsPlusAddress(const std::string& potential_plus_address) const override; |
| std::vector<autofill::Suggestion> GetSuggestions( |
| const url::Origin& last_committed_primary_main_frame_origin, |
| bool is_off_the_record, |
| std::u16string_view focused_field_value) override; |
| void RecordAutofillSuggestionEvent(SuggestionEvent suggestion_event) override; |
| |
| // Returns `true` when plus addresses are supported. This includes checks that |
| // the `kPlusAddressesEnabled` base::Feature is enabled, that there's a |
| // signed-in user, the ability to talk to the server, and that off-the-record |
| // sessions will not offer new plus address creation. |
| // Virtual to allow overriding the behavior in tests. This allows external |
| // tests (e.g., those in autofill that depend on this class) to substitute |
| // their own behavior. |
| bool SupportsPlusAddresses(const url::Origin& origin, |
| bool is_off_the_record) const; |
| |
| // Returns the suggestion label for creating a new plus address. |
| std::u16string GetCreateSuggestionLabel() const; |
| |
| // Same as `GetPlusAddress`, but packages the plus address along with its |
| // eTLD+1. |
| std::optional<PlusProfile> GetPlusProfile(const url::Origin& origin) const; |
| |
| // Gets a plus address, if one exists, for the passed-in origin. Note that all |
| // plus address activity is scoped to eTLD+1. This class owns the conversion |
| // of `origin` to its eTLD+1 form. |
| std::optional<std::string> GetPlusAddress(const url::Origin& origin) const; |
| |
| // Save a plus address for the given origin, which is converted to its eTLD+1 |
| // form prior to persistence. |
| void SavePlusAddress(url::Origin origin, std::string plus_address); |
| |
| // Asks the PlusAddressHttpClient to reserve a plus address for use on |
| // `origin`, and returns the plus address via `on_completed`. |
| // |
| // Virtual to allow overriding the behavior in tests. |
| virtual void ReservePlusAddress(const url::Origin& origin, |
| PlusAddressRequestCallback on_completed); |
| |
| // Asks the PlusAddressHttpClient to confirm `plus_address` for use on |
| // `origin`. and returns the plus address via `on_completed`. |
| // |
| // Virtual to allow overriding the behavior in tests. |
| virtual void ConfirmPlusAddress(const url::Origin& origin, |
| const std::string& plus_address, |
| PlusAddressRequestCallback on_completed); |
| |
| // Used for displaying the user's email address in the UI modal. |
| // virtual to allow mocking in tests that don't want to do identity setup. |
| virtual std::optional<std::string> GetPrimaryEmail(); |
| |
| // Gets the up-to-date mapping from the remote server from the |
| // PlusAddressHttpClient and returns it via `callback`. |
| // This is only intended to be called by the `repeating_timer_`. |
| // |
| // TODO (crbug.com/1467623): Make this private when testing improves. |
| // Virtual to allow overriding the behavior in tests. |
| virtual void SyncPlusAddressMapping(); |
| |
| bool is_enabled() const; |
| |
| protected: |
| // Creates and starts a timer to keep `plus_address_by_site_` and |
| // `plus_addresses` in sync with a remote plus address server. |
| // |
| // This has no effect if this service is not enabled, `pref_service_` is null |
| // or `repeating_timer_` has already been created. |
| void CreateAndStartTimer(); |
| |
| // Updates `plus_address_by_site_` and `plus_addresses_` using `map`. |
| void UpdatePlusAddressMap(const PlusAddressMap& map); |
| |
| // Error handling for failed requests made by GetAllPlusAddresses. |
| // |
| // This is used to determine if the account is forbidden on the startup poll. |
| void HandlePollingError(PlusAddressRequestError error); |
| |
| // signin::IdentityManager::Observer: |
| void OnPrimaryAccountChanged( |
| const signin::PrimaryAccountChangeEvent& event) override; |
| void OnErrorStateOfRefreshTokenUpdatedForAccount( |
| const CoreAccountInfo& account_info, |
| const GoogleServiceAuthError& error) override; |
| |
| void HandleSignout(); |
| |
| // Get and parse the excluded sites. |
| std::set<std::string> GetAndParseExcludedSites(); |
| |
| // Checks whether the `origin` supports plus address. |
| // Returns `true` when origin is not opaque, ETLD+1 of `origin` is not |
| // on `excluded_sites_` set, and scheme is http or https. |
| bool IsSupportedOrigin(const url::Origin& origin) const; |
| |
| // The user's existing set of plus addresses, scoped to sites. |
| PlusAddressMap plus_address_by_site_ GUARDED_BY_CONTEXT(sequence_checker_); |
| |
| // Used to drive the `IsPlusAddress` function, and derived from the values of |
| // `plus_profiles`. |
| std::unordered_set<std::string> plus_addresses_ |
| GUARDED_BY_CONTEXT(sequence_checker_); |
| |
| // Stores pointer to IdentityManager instance. It must outlive the |
| // PlusAddressService and can be null during tests. |
| const raw_ptr<signin::IdentityManager> identity_manager_; |
| |
| // Stores pointer to a PrefService to create `repeating_timer_` when the user |
| // signs in after PlusAddressService is created. |
| const raw_ptr<PrefService> pref_service_; |
| |
| // A timer to periodically retrieve all plus addresses from a remote server |
| // to keep this service in sync. |
| std::unique_ptr<signin::PersistentRepeatingTimer> repeating_timer_; |
| |
| // Handles requests to a remote server that this service uses. |
| PlusAddressHttpClient plus_address_client_; |
| |
| // Store set of excluded sites ETLD+1 where PlusAddressService is not |
| // supported. |
| std::set<std::string> excluded_sites_; |
| |
| // Stores last auth error (potentially NONE) to toggle is_enabled() on/off. |
| // Defaults to NONE to enable this service while refresh tokens (and potential |
| // auth errors) are loading. |
| GoogleServiceAuthError primary_account_auth_error_; |
| |
| // Tracks the number of attempts made to fetch the PlusAddressMap from the |
| // remote server after the initial request made at service construction. |
| int initial_poll_retry_attempt_ = 0; |
| |
| // Stores whether the account for this ProfileKeyedService is forbidden from |
| // using the remote server. This is populated once on the initial poll request |
| // and not updated afterwards. |
| std::optional<bool> account_is_forbidden_ = std::nullopt; |
| |
| base::ScopedObservation<signin::IdentityManager, |
| signin::IdentityManager::Observer> |
| identity_manager_observation_{this}; |
| |
| SEQUENCE_CHECKER(sequence_checker_); |
| }; |
| |
| } // namespace plus_addresses |
| |
| #endif // COMPONENTS_PLUS_ADDRESSES_PLUS_ADDRESS_SERVICE_H_ |