chromium/ios/web_view/internal/passwords/cwv_reuse_check_service.mm

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

#import "ios/web_view/internal/passwords/cwv_reuse_check_service_internal.h"

#import "base/containers/flat_set.h"
#import "base/functional/callback.h"
#import "base/strings/sys_string_conversions.h"
#import "components/affiliations/core/browser/affiliation_service.h"
#import "components/affiliations/core/browser/affiliation_utils.h"
#import "components/password_manager/core/browser/ui/affiliated_group.h"
#import "components/password_manager/core/browser/ui/credential_ui_entry.h"
#import "components/password_manager/core/browser/ui/passwords_grouper.h"
#import "components/password_manager/core/browser/ui/reuse_check_utility.h"
#import "components/password_manager/core/common/password_manager_features.h"
#import "components/sync/base/features.h"
#import "ios/web_view/internal/affiliations/web_view_affiliation_service_factory.h"
#import "ios/web_view/internal/passwords/cwv_password_internal.h"
#import "ios/web_view/internal/web_view_global_state_util.h"

@implementation CWVReuseCheckService {
  affiliations::AffiliationService* _affiliation_service;
  std::unique_ptr<password_manager::PasswordsGrouper> _passwords_grouper;
}

- (instancetype)initWithAffiliationService:
    (affiliations::AffiliationService*)affiliationService {
  DCHECK(affiliationService);
  self = [super init];
  if (self) {
    _affiliation_service = affiliationService;
    _passwords_grouper = std::make_unique<password_manager::PasswordsGrouper>(
        _affiliation_service);
  }
  return self;
}

- (void)groupPasswordsWithCompletionHandler:
            (void (^)(NSSet<NSString*>* reusedPasswords))completionHandler
                                  passwords:(NSArray<CWVPassword*>*)passwords {
  std::vector<password_manager::CredentialUIEntry> credentialEntries =
      _passwords_grouper->GetAllCredentials();

  std::vector<password_manager::AffiliatedGroup> groups =
      _passwords_grouper->GetAffiliatedGroupsWithGroupingInfo();

  base::flat_set<std::u16string> reusedPasswords =
      password_manager::BulkReuseCheck(credentialEntries, groups);

  NSMutableArray<NSString*>* reusedPasswordsArray = [NSMutableArray array];

  for (auto string : reusedPasswords) {
    NSString* reusedPassword = base::SysUTF16ToNSString(string);
    [reusedPasswordsArray addObject:reusedPassword];
  }

  completionHandler([NSSet setWithArray:reusedPasswordsArray]);
}

- (void)checkReusedPasswords:(NSArray<CWVPassword*>*)passwords
           completionHandler:
               (void (^)(NSSet<NSString*>* reusedPasswords))completionHandler {
  std::vector<password_manager::PasswordForm> passwordForms;
  for (CWVPassword* password in passwords) {
    passwordForms.push_back(*password.internalPasswordForm);
  }

  // Convert forms to Facets.
  std::vector<affiliations::FacetURI> facets;
  facets.reserve(passwordForms.size());
  for (const auto& form : passwordForms) {
    // Blocked forms aren't grouped.
    if (form.blocked_by_user) {
      continue;
    }
    facets.emplace_back(affiliations::FacetURI::FromPotentiallyInvalidSpec(
        GetFacetRepresentation(form)));
  }

  base::OnceClosure updateAffiliationsAndBrandingClosure = base::BindOnce(^{
    base::OnceClosure groupCredentialsClosure = base::BindOnce(^{
      [self groupPasswordsWithCompletionHandler:completionHandler
                                      passwords:std::move(passwords)];
    });

    self->_passwords_grouper->GroupCredentials(
        passwordForms, {}, std::move(groupCredentialsClosure));
  });

  _affiliation_service->UpdateAffiliationsAndBranding(
      facets, std::move(updateAffiliationsAndBrandingClosure));
}

@end