From 32e9524472681094103f130cbe9fec8a13d3a45a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Velimir=20=C4=90urkovi=C4=87?= Date: Fri, 28 Oct 2022 22:02:52 +0200 Subject: [PATCH] Refactoring: Added random character generator and string shuffler service --- Controllers/PasswordController.cs | 4 +- Interfaces/IPasswordGenerator.cs | 4 +- Interfaces/IRandomCharacterGenerator.cs | 14 +++++ Interfaces/IStringShuffler.cs | 6 ++ Program.cs | 8 ++- Properties/launchSettings.json | 2 +- Services/PasswordGenerator.cs | 76 ++++++++++--------------- Services/RandomCharacterGenerator.cs | 50 ++++++++++++++++ Services/StringShuffler.cs | 25 ++++++++ ShuffleExtension.cs | 2 +- demo-dotnet-web-api.csproj | 2 +- 11 files changed, 136 insertions(+), 57 deletions(-) create mode 100644 Interfaces/IRandomCharacterGenerator.cs create mode 100644 Interfaces/IStringShuffler.cs create mode 100644 Services/RandomCharacterGenerator.cs create mode 100644 Services/StringShuffler.cs diff --git a/Controllers/PasswordController.cs b/Controllers/PasswordController.cs index 230e17d..896c215 100644 --- a/Controllers/PasswordController.cs +++ b/Controllers/PasswordController.cs @@ -1,7 +1,7 @@ -using demo_dotnet_web_api.Interfaces; +using DemoDotnetWebApi.Interfaces; using Microsoft.AspNetCore.Mvc; -namespace demo_dotnet_web_api.Controllers; +namespace DemoDotnetWebApi.Controllers; [ApiController] [Route("api/v1/[controller]")] diff --git a/Interfaces/IPasswordGenerator.cs b/Interfaces/IPasswordGenerator.cs index 1ccb4cc..ce2b227 100644 --- a/Interfaces/IPasswordGenerator.cs +++ b/Interfaces/IPasswordGenerator.cs @@ -1,6 +1,6 @@ -namespace demo_dotnet_web_api.Interfaces; +namespace DemoDotnetWebApi.Interfaces; public interface IPasswordGenerator { String Generate(); -} \ No newline at end of file +} diff --git a/Interfaces/IRandomCharacterGenerator.cs b/Interfaces/IRandomCharacterGenerator.cs new file mode 100644 index 0000000..5d34d24 --- /dev/null +++ b/Interfaces/IRandomCharacterGenerator.cs @@ -0,0 +1,14 @@ +namespace DemoDotnetWebApi.Interfaces; + +public interface IRandomCharacterGenerator +{ + char GenerateUppercaseCharacter(); + + char GenerateLowercaseCharacter(); + + char GenerateDigitCharacter(); + + char GenerateSpecialCharacter(); + + char GenerateAllowedCharacter(); +} diff --git a/Interfaces/IStringShuffler.cs b/Interfaces/IStringShuffler.cs new file mode 100644 index 0000000..32d9a58 --- /dev/null +++ b/Interfaces/IStringShuffler.cs @@ -0,0 +1,6 @@ +namespace DemoDotnetWebApi.Interfaces; + +public interface IStringShuffler +{ + string Shuffle(string characters); +} diff --git a/Program.cs b/Program.cs index dce2e53..1b8cd58 100644 --- a/Program.cs +++ b/Program.cs @@ -1,10 +1,12 @@ -using demo_dotnet_web_api.Interfaces; -using demo_dotnet_web_api.Services; +using DemoDotnetWebApi.Interfaces; +using DemoDotnetWebApi.Services; var builder = WebApplication.CreateBuilder(args); // Add services to the container. -builder.Services.AddSingleton(); +builder.Services.AddTransient(); +builder.Services.AddTransient(); +builder.Services.AddTransient(); builder.Services.AddControllers(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle diff --git a/Properties/launchSettings.json b/Properties/launchSettings.json index 57e90ea..3cd099f 100644 --- a/Properties/launchSettings.json +++ b/Properties/launchSettings.json @@ -9,7 +9,7 @@ } }, "profiles": { - "demo_dotnet_web_api": { + "DemoDotnetWebApi": { "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": true, diff --git a/Services/PasswordGenerator.cs b/Services/PasswordGenerator.cs index 12099c1..6a890bf 100644 --- a/Services/PasswordGenerator.cs +++ b/Services/PasswordGenerator.cs @@ -1,62 +1,44 @@ using System.Text; -using demo_dotnet_web_api.Interfaces; +using DemoDotnetWebApi.Interfaces; -namespace demo_dotnet_web_api.Services; +namespace DemoDotnetWebApi.Services; public class PasswordGenerator : IPasswordGenerator { - private static readonly int PASSWORD_LENGTH = 16; - private static readonly String UPPERCASE_CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - private static readonly String LOWERCASE_CHARACTERS = "abcdefghijklmnopqrstuvwxyz"; - private static readonly String DIGIT_CHARACTERS = "0123456789"; - private static readonly String SPECIAL_CHARACTERS = "~`!@#$%^&*()-_=+[{]}\\|;:\'\",<.>/?"; - private static readonly String UNION_OF_ALLOWED_CHARACTERS = UPPERCASE_CHARACTERS + - LOWERCASE_CHARACTERS + - DIGIT_CHARACTERS + - SPECIAL_CHARACTERS; - private static readonly Random random = new Random(); + private readonly int passwordLength; + private readonly IRandomCharacterGenerator randomCharacterGenerator; + private readonly IStringShuffler stringShuffler; - /// - /// Generate random password - /// Generated password length is 16 - /// Generated password contains at least one uppercase character - /// Generated password contains at least one lowercase character - /// Generated password contains at least one digit character - /// Generated password contains at least one special character - /// - /// Generated password + public PasswordGenerator(IRandomCharacterGenerator randomCharacterGenerator, IStringShuffler stringShuffler) + { + this.passwordLength = 16; + this.randomCharacterGenerator = randomCharacterGenerator; + this.stringShuffler = stringShuffler; + } + + /// + /// Generate random password + /// Generated password length is 16 + /// Generated password contains at least one uppercase character + /// Generated password contains at least one lowercase character + /// Generated password contains at least one digit character + /// Generated password contains at least one special character + /// + /// Generated password public String Generate() { var stringBuilder = new StringBuilder(); - // generate at least one uppercase character - stringBuilder.Append(GenerateRandomCharacter(UPPERCASE_CHARACTERS)); - - // generate at least one lowercase character - stringBuilder.Append(GenerateRandomCharacter(LOWERCASE_CHARACTERS)); - - // generate at least one digit character - stringBuilder.Append(GenerateRandomCharacter(DIGIT_CHARACTERS)); + stringBuilder.Append(randomCharacterGenerator.GenerateUppercaseCharacter()); + stringBuilder.Append(randomCharacterGenerator.GenerateLowercaseCharacter()); + stringBuilder.Append(randomCharacterGenerator.GenerateDigitCharacter()); + stringBuilder.Append(randomCharacterGenerator.GenerateSpecialCharacter()); - // generate at least one special character - stringBuilder.Append(GenerateRandomCharacter(SPECIAL_CHARACTERS)); - - for (int i = 4; i < PASSWORD_LENGTH; i++) + for (int i = 0; i < passwordLength - 4; i++) { - // generate random character from union of allowed characters - stringBuilder.Append(GenerateRandomCharacter(UNION_OF_ALLOWED_CHARACTERS)); + stringBuilder.Append(randomCharacterGenerator.GenerateAllowedCharacter()); } - // shuffle generated characters - IList ch = stringBuilder.ToString().Split("").ToList(); - ch.Shuffle(); - - // return generated password - return string.Join("", ch); - } - - private char GenerateRandomCharacter(String characters) - { - return characters.ElementAt(random.Next(characters.Length)); + return stringShuffler.Shuffle(stringBuilder.ToString()); } -} \ No newline at end of file +} diff --git a/Services/RandomCharacterGenerator.cs b/Services/RandomCharacterGenerator.cs new file mode 100644 index 0000000..56c02ed --- /dev/null +++ b/Services/RandomCharacterGenerator.cs @@ -0,0 +1,50 @@ +using DemoDotnetWebApi.Interfaces; + +namespace DemoDotnetWebApi.Services; + +public class RandomCharacterGenerator : IRandomCharacterGenerator +{ + private readonly String uppercaseCharacters; + private readonly String lowercaseCharacters; + private readonly String digitCharacters; + private readonly String specialCharacters; + private readonly String allowedCharacters; + private readonly Random random = new Random(); + + public RandomCharacterGenerator() + { + uppercaseCharacters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + lowercaseCharacters = "abcdefghijklmnopqrstuvwxyz"; + digitCharacters = "0123456789"; + specialCharacters = "~`!@#$%^&*()-_=+[{]}\\|;:\'\",<.>/?"; + allowedCharacters = uppercaseCharacters + + lowercaseCharacters + + digitCharacters + + specialCharacters; + } + + public char GenerateAllowedCharacter() + { + return allowedCharacters.ElementAt(random.Next(allowedCharacters.Length)); + } + + public char GenerateDigitCharacter() + { + return digitCharacters.ElementAt(random.Next(digitCharacters.Length)); + } + + public char GenerateLowercaseCharacter() + { + return lowercaseCharacters.ElementAt(random.Next(lowercaseCharacters.Length)); + } + + public char GenerateSpecialCharacter() + { + return specialCharacters.ElementAt(random.Next(specialCharacters.Length)); + } + + public char GenerateUppercaseCharacter() + { + return uppercaseCharacters.ElementAt(random.Next(uppercaseCharacters.Length)); + } +} diff --git a/Services/StringShuffler.cs b/Services/StringShuffler.cs new file mode 100644 index 0000000..c7dc098 --- /dev/null +++ b/Services/StringShuffler.cs @@ -0,0 +1,25 @@ +using DemoDotnetWebApi.Interfaces; + +namespace DemoDotnetWebApi.Services; + +public class StringShuffler : IStringShuffler +{ + private readonly Random random = new Random(); + + public string Shuffle(string characters) + { + IList list = characters.Split("").ToList(); + int n = list.Count; + + while (n > 1) + { + n--; + int k = random.Next(n + 1); + string value = list[k]; + list[k] = list[n]; + list[n] = value; + } + + return string.Join("", list); + } +} diff --git a/ShuffleExtension.cs b/ShuffleExtension.cs index 11a2e90..0b882cb 100644 --- a/ShuffleExtension.cs +++ b/ShuffleExtension.cs @@ -1,4 +1,4 @@ -namespace demo_dotnet_web_api; +namespace DemoDotnetWebApi; public static class ShuffleExtension { diff --git a/demo-dotnet-web-api.csproj b/demo-dotnet-web-api.csproj index 770de7a..492f5d6 100644 --- a/demo-dotnet-web-api.csproj +++ b/demo-dotnet-web-api.csproj @@ -4,7 +4,7 @@ net6.0 enable enable - demo_dotnet_web_api + DemoDotnetWebApi