chromium/ios/chrome/browser/ui/settings/utils/password_utils.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/chrome/browser/ui/settings/utils/password_utils.h"

#import "base/check.h"
#import "base/strings/sys_string_conversions.h"
#import "ios/chrome/browser/ui/settings/password/password_settings/scoped_password_settings_reauth_module_override.h"
#import "ios/chrome/common/ui/reauthentication/reauthentication_module.h"
#import "ios/chrome/common/ui/reauthentication/reauthentication_protocol.h"
#import "ios/chrome/grit/ios_strings.h"
#import "ui/base/l10n/l10n_util.h"

namespace password_manager {

namespace {

// Returns whether `string` contains `substring`. The comparison
// is done in lower-case (`substring` must be lower case).
bool ContainsSubStringLowerCase(const std::string& string,
                                const std::string& substring) {
  DCHECK_EQ(substring, base::ToLowerASCII(substring));

  const std::string lower_case_string = base::ToLowerASCII(string);
  return lower_case_string.find(substring) != std::string::npos;
}

// Returns whether any of the credential groups matches the given search term.
bool MatchGroupCredentialsForTerm(const AffiliatedGroup& affiliated_group,
                                  const std::string& search_term) {
  for (const auto& credential : affiliated_group.GetCredentials()) {
    if (MatchCredentialForTerm(credential, search_term)) {
      return true;
    }
  }
  return false;
}

}  // namespace

std::pair<NSString*, NSString*> GetPasswordAlertTitleAndMessageForOrigins(
    NSArray<NSString*>* origins) {
  DCHECK(origins.count >= 1);
  NSString* title;
  NSString* message;
  if (origins.count == 1) {
    title =
        l10n_util::GetNSStringF(IDS_IOS_DELETE_PASSWORD_TITLE_FOR_SINGLE_URL,
                                base::SysNSStringToUTF16(origins[0]));
    // Message: Your <URL 1> account won't be deleted.
    message = l10n_util::GetNSStringF(
        IDS_IOS_DELETE_PASSWORD_DESCRIPTION_FOR_SINGLE_URL,
        base::SysNSStringToUTF16(origins[0]));
  } else {
    NSString* count_string =
        [[NSNumber numberWithInteger:origins.count] stringValue];
    title =
        l10n_util::GetNSStringF(IDS_IOS_DELETE_PASSWORD_TITLE_FOR_MULTI_GROUPS,
                                base::SysNSStringToUTF16(count_string));
    if (origins.count == 2) {
      // Message: Password for <URL 1> and <URL 2> will be deleted. Your
      // accounts won't be deleted.
      message = l10n_util::GetNSStringF(
          IDS_IOS_DELETE_PASSWORD_DESCRIPTION_FOR_TWO_URLS,
          base::SysNSStringToUTF16(origins[0]),
          base::SysNSStringToUTF16(origins[1]));
    } else if (origins.count == 3) {
      // Message: Password for <URL 1>, <URL 2> and <URL 3> will be deleted.
      // Your accounts won't be deleted.
      message = l10n_util::GetNSStringF(
          IDS_IOS_DELETE_PASSWORD_DESCRIPTION_FOR_THREE_URLS,
          base::SysNSStringToUTF16(origins[0]),
          base::SysNSStringToUTF16(origins[1]),
          base::SysNSStringToUTF16(origins[2]));
    } else {
      // Message: Password for <URL 1>, <URL 2> and <number> others will be
      // deleted. Your accounts won't be deleted.
      NSString* leftover_count_string =
          [[NSNumber numberWithInteger:(origins.count - 2)] stringValue];
      message = l10n_util::GetNSStringF(
          IDS_IOS_DELETE_PASSWORD_DESCRIPTION_FOR_MULTI_URLS,
          base::SysNSStringToUTF16(origins[0]),
          base::SysNSStringToUTF16(origins[1]),
          base::SysNSStringToUTF16(leftover_count_string));
    }
  }
  std::pair<NSString*, NSString*> pair;
  pair.first = title;
  pair.second = message;
  return pair;
}

id<ReauthenticationProtocol> BuildReauthenticationModule(
    id<SuccessfulReauthTimeAccessor> successfulReauthTimeAccessor) {
  // Return override for tests if one is set or use the real implementation.
  id<ReauthenticationProtocol> overrideModule =
      ScopedPasswordSettingsReauthModuleOverride::Get();
  if (overrideModule) {
    return overrideModule;
  }

  return successfulReauthTimeAccessor
             ? [[ReauthenticationModule alloc]
                   initWithSuccessfulReauthTimeAccessor:
                       successfulReauthTimeAccessor]
             : [[ReauthenticationModule alloc] init];
}

bool MatchCredentialForTerm(const CredentialUIEntry& credential,
                            const std::string& search_term) {
  DCHECK(!search_term.empty());
  DCHECK_EQ(search_term, base::ToLowerASCII(search_term));

  for (const auto& domain_info : credential.GetAffiliatedDomains()) {
    if (ContainsSubStringLowerCase(domain_info.name, search_term)) {
      return true;
    }
  }
  return false;
}

bool MatchAffiliatedGroupsForTerm(const AffiliatedGroup& affiliated_group,
                                  const std::string& search_term) {
  DCHECK(!search_term.empty());
  DCHECK_EQ(search_term, base::ToLowerASCII(search_term));

  return ContainsSubStringLowerCase(affiliated_group.GetDisplayName(),
                                    search_term) ||
         MatchGroupCredentialsForTerm(affiliated_group, search_term);
}

}  // namespace password_manager