blob: 01cb659e328ade15c7120ea974d78ccbd1f17aaa [file] [log] [blame]
// Copyright 2024 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_SIGNIN_MODEL_ACCOUNT_PROFILE_MAPPER_H_
#define IOS_CHROME_BROWSER_SIGNIN_MODEL_ACCOUNT_PROFILE_MAPPER_H_
#import <UIKit/UIKit.h>
#include <map>
#include <set>
#include <string>
#import "base/functional/callback.h"
#import "base/observer_list.h"
#import "base/observer_list_types.h"
#import "base/scoped_observation.h"
#import "google_apis/gaia/gaia_id.h"
#import "ios/chrome/browser/signin/model/system_account_updater.h"
#import "ios/chrome/browser/signin/model/system_identity_manager.h"
@protocol ChangeProfileCommands;
class GaiaId;
class PrefService;
class ProfileManagerIOS;
@protocol SystemIdentity;
// Class to map the identities from SystemIdentityManager to profiles.
class AccountProfileMapper {
public:
class Observer : public base::CheckedObserver {
public:
Observer() = default;
~Observer() override = default;
// Called when the list of identities in a profile has changed.
virtual void OnIdentitiesInProfileChanged() {}
// Called when the list of identities on device has changed.
virtual void OnIdentitiesOnDeviceChanged() {}
// Called when information about an `identity` (such as the name or the
// image) in a profile have been updated.
virtual void OnIdentityInProfileUpdated(id<SystemIdentity> identity) {}
// Called when information about an `identity` (such as the name or the
// image) on the device have been updated.
virtual void OnIdentityOnDeviceUpdated(id<SystemIdentity> identity) {}
// Called on identity refresh token updated events.
// `identity` is the the identity for which the refresh token was updated.
virtual void OnIdentityRefreshTokenUpdated(id<SystemIdentity> identity) {}
// Called on access token refresh failed events.
// `identity` is the the identity for which the access token refresh failed.
// `error` is an opaque type containing information about the error.
virtual void OnIdentityAccessTokenRefreshFailed(
id<SystemIdentity> identity,
id<RefreshAccessTokenError> error,
const std::set<std::string>& scopes) {}
};
// Value returned by IdentityIteratorCallback.
enum class IteratorResult {
kContinueIteration,
kInterruptIteration,
};
// Callback invoked for each id<SystemIdentity> when iterating over them
// with `IterateOverIdentities()`. The returned value can be used to stop
// the iteration prematurely.
using IdentityIteratorCallback =
base::RepeatingCallback<IteratorResult(id<SystemIdentity>)>;
AccountProfileMapper(SystemIdentityManager* system_identity_manager,
ProfileManagerIOS* profile_manager,
PrefService* local_pref_service);
AccountProfileMapper(const AccountProfileMapper&) = delete;
AccountProfileMapper& operator=(const AccountProfileMapper&) = delete;
~AccountProfileMapper();
// Sets the ChangeProfileCommands handler.
void SetChangeProfileCommandsHandler(id<ChangeProfileCommands> handler);
// Adds/removes observers for a profile based on `profile_name`.
void AddObserver(Observer* observer, std::string_view profile_name);
void RemoveObserver(Observer* observer, std::string_view profile_name);
// Returns whether signin is supported by the provider.
bool IsSigninSupported();
// Returns the name of the profile to which `gaia_id` is assigned, or nullopt
// if no such profile exists.
std::optional<std::string> FindProfileNameForGaiaID(
const GaiaId& gaia_id) const;
// Iterates over all known identities for `profile_name`, sorted by
// the ordering used in system identity manager, which is typically based
// on the keychain ordering of the accounts.
void IterateOverIdentities(IdentityIteratorCallback callback,
std::string_view profile_name);
// Iterates over all known identities on the device, i.e. including the ones
// assigned to other profiles. Using this should be rare!
void IterateOverAllIdentitiesOnDevice(IdentityIteratorCallback callback);
// Returns the name of the personal profile, queried from the
// ProfileAttributesStorageIOS.
std::string GetPersonalProfileName();
// Returns whether the profile assigned to `gaia_id` has been fully
// initialized.
bool IsProfileForGaiaIDFullyInitialized(const GaiaId& gaia_id);
// Marks the personal profile as managed, attaches the given `gaia_id`, and
// moves all personal accounts to a new empty personal profile. Deletes the
// managed profile to which `gaia_id` was attached. That profile must not be
// fully initialized yet (per ProfileAttributesIOS::IsFullyInitialized()).
// This is meant for two situations:
// 1. Signing in with a managed account during the FRE. In this case, there
// can't be any pre-existing local data, so no need to move to a new empty
// profile (and it's easier to continue the flow in the existing profile).
// 2. Signing in with a managed account, while not signed in yet in the
// personal profile. In this case, the user *may* be offered to take
// existing local data along into the managed profile, which is implemented
// as converting the personal profile into a managed one.
void MakePersonalProfileManagedWithGaiaID(const GaiaId& gaia_id);
// For testing purposes, this moves the account with `gaia_id` from its
// current (managed) profile into the personal profile. This simulates the
// situation where a managed account was already signed in before
// kSeparateProfilesForManagedAccounts was enabled (but makes test setup much
// easier).
void MoveManagedAccountToPersonalProfileForTesting(const GaiaId& gaia_id);
private:
class Assigner;
using ProfileNameToGaiaIds =
std::map<std::string, std::set<GaiaId, std::less<>>, std::less<>>;
// Iterator callback for SystemIdentityManager. Calls `callback` when
// receiving an identity assigned to the profile with `profile_name`.
SystemIdentityManager::IteratorResult FilterIdentitiesForProfile(
std::string_view profile_name,
IdentityIteratorCallback callback,
id<SystemIdentity> identity);
// Called by the Assigner whenever the list of identities on the device
// changes.
void IdentitiesOnDeviceChanged();
// Called by the Assigner when any profile<->account mappings have been
// updated.
void MappingUpdated(const ProfileNameToGaiaIds& old_mapping,
const ProfileNameToGaiaIds& new_mapping);
// Called by the Assigner on the corresponding SystemIdentityManager events.
void IdentityUpdated(id<SystemIdentity> identity);
void IdentityRefreshTokenUpdated(id<SystemIdentity> identity);
void IdentityAccessTokenRefreshFailed(id<SystemIdentity> identity,
id<RefreshAccessTokenError> error,
const std::set<std::string>& scopes);
// Invokes `OnIdentityListChanged(...)` for all observers in
// `profile_names_to_notify`. If `kSeparateProfilesForManagedAccounts` is
// disabled, all observers are notified, and `profile_names_to_notify` is
// ignored.
void NotifyIdentityListChanged(
const std::set<std::string>& profile_names_to_notify);
// Invokes `OnIdentityUpdated(...)` for all observers for `profile_name`. If
// `kSeparateProfilesForManagedAccounts` is disabled, all observers are
// notified, and `profile_name` is ignored.
void NotifyIdentityUpdated(id<SystemIdentity> identity,
const std::optional<std::string>& profile_name);
// Invokes `OnIdentityRefreshTokenUpdated(...)` for all observers for
// the profile with `profile_name`. If `kSeparateProfilesForManagedAccounts`
// is disabled, all observers are notified, and `profile_name` is ignored.
void NotifyRefreshTokenUpdated(
id<SystemIdentity> identity,
const std::optional<std::string>& profile_name);
// Invokes `OnIdentityAccessTokenRefreshFailed(...)` for all observers for
// the profile with `profile_name`. If `kSeparateProfilesForManagedAccounts`
// is disabled, all observers are notified, and `profile_name` is ignored.
void NotifyAccessTokenRefreshFailed(
id<SystemIdentity> identity,
id<RefreshAccessTokenError> error,
const std::optional<std::string>& profile_name,
const std::set<std::string>& scopes);
// The AccountProfileMapper is sequence-affine.
SEQUENCE_CHECKER(sequence_checker_);
raw_ptr<SystemIdentityManager> system_identity_manager_;
raw_ptr<ProfileManagerIOS> profile_manager_;
std::unique_ptr<SystemAccountUpdater> system_account_updater_;
std::unique_ptr<Assigner> assigner_;
// Registered observers.
std::map<std::string, base::ObserverList<Observer>, std::less<>>
observer_lists_per_profile_name_;
};
#endif // IOS_CHROME_BROWSER_SIGNIN_MODEL_ACCOUNT_PROFILE_MAPPER_H_