chromium/ios/chrome/app/credential_provider_migrator_app_agent.mm

// 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.

#import "ios/chrome/app/credential_provider_migrator_app_agent.h"

#import "components/keyed_service/core/service_access_type.h"
#import "components/password_manager/core/browser/features/password_manager_features_util.h"
#import "components/password_manager/core/browser/password_form.h"
#import "ios/chrome/app/application_delegate/app_state.h"
#import "ios/chrome/browser/credential_provider/model/credential_provider_migrator.h"
#import "ios/chrome/browser/passwords/model/ios_chrome_account_password_store_factory.h"
#import "ios/chrome/browser/passwords/model/ios_chrome_profile_password_store_factory.h"
#import "ios/chrome/browser/shared/coordinator/scene/scene_state.h"
#import "ios/chrome/browser/shared/model/application_context/application_context.h"
#import "ios/chrome/browser/shared/model/browser/browser.h"
#import "ios/chrome/browser/shared/model/browser/browser_provider.h"
#import "ios/chrome/browser/shared/model/browser/browser_provider_interface.h"
#import "ios/chrome/browser/shared/model/profile/profile_ios.h"
#import "ios/chrome/browser/shared/model/profile/profile_manager_ios.h"
#import "ios/chrome/browser/sync/model/sync_service_factory.h"
#import "ios/chrome/browser/webauthn/model/ios_passkey_model_factory.h"
#import "ios/chrome/common/app_group/app_group_constants.h"
#import "ios/chrome/common/credential_provider/constants.h"

@interface CredentialProviderMigratorAppAgent ()

// Keep track of the migration status of each browser state.
@property(nonatomic, strong) NSMutableSet<NSString*>* migratingTracker;

@end

@implementation CredentialProviderMigratorAppAgent

// Migrate the password when Chrome comes to foreground.
- (void)appDidEnterForeground {
  NSString* key = AppGroupUserDefaultsCredentialProviderNewCredentials();
  NSUserDefaults* userDefaults = app_group::GetGroupUserDefaults();

  const std::vector<ChromeBrowserState*> loadedProfiles =
      GetApplicationContext()->GetProfileManager()->GetLoadedProfiles();
  if (!self.migratingTracker) {
    self.migratingTracker =
        [NSMutableSet setWithCapacity:loadedProfiles.size()];
  }

  for (ChromeBrowserState* browserState : loadedProfiles) {
    NSString* browserStatePathString =
        [NSString stringWithCString:browserState->GetStatePath()
                                        .BaseName()
                                        .MaybeAsASCII()
                                        .c_str()
                           encoding:NSASCIIStringEncoding];
    // Do nothing if the migration for a browser state already started.
    if ([self.migratingTracker containsObject:browserStatePathString]) {
      continue;
    }

    webauthn::PasskeyModel* passkeyStore =
        IOSPasskeyModelFactory::GetForBrowserState(browserState);
    password_manager::PasswordForm::Store defaultStore =
        password_manager::features_util::GetDefaultPasswordStore(
            browserState->GetPrefs(),
            SyncServiceFactory::GetForBrowserState(browserState));
    scoped_refptr<password_manager::PasswordStoreInterface> storeToSave =
        defaultStore == password_manager::PasswordForm::Store::kAccountStore
            ? IOSChromeAccountPasswordStoreFactory::GetForBrowserState(
                  browserState, ServiceAccessType::IMPLICIT_ACCESS)
            : IOSChromeProfilePasswordStoreFactory::GetForBrowserState(
                  browserState, ServiceAccessType::IMPLICIT_ACCESS);
    CredentialProviderMigrator* migrator =
        [[CredentialProviderMigrator alloc] initWithUserDefaults:userDefaults
                                                             key:key
                                                   passwordStore:storeToSave
                                                    passkeyStore:passkeyStore];
    [self.migratingTracker addObject:browserStatePathString];
    __weak __typeof__(self) weakSelf = self;
    [migrator startMigrationWithCompletion:^(BOOL success, NSError* error) {
      DCHECK(success) << error.localizedDescription;
      if (weakSelf) {
        [weakSelf.migratingTracker removeObject:browserStatePathString];
      }
    }];
  }
}

@end