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 StringBuilder characterPool = new(); 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 char[] 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 } } }