using System.Security.Cryptography; using System.Text; namespace Hutopy.Infrastructure.Security; // If we need to add special characters we can alternate between 2 pools. public static class PasswordGenerator { private const string LowerLetters = "abcdefghijklmnopqrstuvwxyz"; private const string UpperLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; private const string Numbers = "0123456789"; private const string SpecialCharacters = "!@#$%^&*()_+-=[];',./`~{}|:\"<>?"; private static readonly Random Random = new(); public static string Next( int length = 15, bool requireNumber = true, bool requireLowercase = true, bool requireCapital = true, bool requireSpecialCharacter = true) { // Create pools based on the requirements var characterPool = new StringBuilder(); if (requireNumber) characterPool.Append(LowerLetters); if (requireCapital) characterPool.Append(UpperLetters); if (requireNumber) characterPool.Append(Numbers); if (requireSpecialCharacter) characterPool.Append(SpecialCharacters); // Ensure that the length is within the specified bounds var password = new char[length]; // Ensure at least one character from each required category is included int index = 0; if (requireLowercase) password[index++] = LowerLetters[Random.Next(LowerLetters.Length)]; if (requireCapital) password[index++] = UpperLetters[Random.Next(UpperLetters.Length)]; if (requireNumber) password[index++] = Numbers[Random.Next(Numbers.Length)]; if (requireSpecialCharacter) password[index++] = SpecialCharacters[Random.Next(SpecialCharacters.Length)]; // Fill the rest with the password for (int i = index; i < length; i++) { password[i] = characterPool[RandomNumberGenerator.GetInt32(characterPool.Length)]; } // Shuffle the password to randomize the placement of the required characters Shuffle(password); return new string(password); } private static void Shuffle( char[] array) { for (int i = array.Length - 1; i > 0; i--) { int j = Random.Next(i + 1); (array[i], array[j]) = (array[j], array[i]); // Swap elements } } }