diff --git a/MainProject.Tests/MainProject.Tests.csproj b/MainProject.Tests/MainProject.Tests.csproj
index 45f0343..b083669 100644
--- a/MainProject.Tests/MainProject.Tests.csproj
+++ b/MainProject.Tests/MainProject.Tests.csproj
@@ -10,12 +10,15 @@
-
-
-
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
-
-
+
+
diff --git a/MainProject.Tests/Utils/PasswordUtils_Test.cs b/MainProject.Tests/Utils/PasswordUtils_Test.cs
new file mode 100644
index 0000000..2f2d6e6
--- /dev/null
+++ b/MainProject.Tests/Utils/PasswordUtils_Test.cs
@@ -0,0 +1,62 @@
+using BasicDotnetTemplate.MainProject.Utils;
+using BasicDotnetTemplate.MainProject.Models.Common;
+using BasicDotnetTemplate.MainProject.Enum;
+
+
+namespace BasicDotnetTemplate.MainProject.Tests;
+
+[TestClass]
+public class PasswordUtils_Test
+{
+ [TestMethod]
+ public void PasswordValidation_Valid()
+ {
+ try
+ {
+ List errors = PasswordUtils.ValidatePassword("#aBcDeFgHi01245#");
+ Assert.IsTrue(errors == null || errors.Count == 0);
+ }
+ catch (Exception exception)
+ {
+ Assert.Fail($"An exception was thrown: {exception}");
+ }
+ }
+
+ [TestMethod]
+ public void PasswordValidation_Invalid()
+ {
+ try
+ {
+ List errors = PasswordUtils.ValidatePassword("aAa1#");
+ Assert.IsTrue(errors.Contains(PasswordValidationEnum.MIN_LENGTH));
+ Assert.IsTrue(errors.Contains(PasswordValidationEnum.MIN_UPPER));
+ Assert.IsTrue(errors.Contains(PasswordValidationEnum.MIN_NUMBER));
+ Assert.IsTrue(errors.Contains(PasswordValidationEnum.MIN_SPECIAL));
+ Assert.IsTrue(errors.Contains(PasswordValidationEnum.IDENTICAL_CHARS));
+ Assert.IsTrue(!errors.Contains(PasswordValidationEnum.MIN_LOWER));
+ }
+ catch (Exception exception)
+ {
+ Assert.Fail($"An exception was thrown: {exception}");
+ }
+ }
+
+ [TestMethod]
+ public void PasswordValidation_ToLowerInvalid()
+ {
+ try
+ {
+ List errors = PasswordUtils.ValidatePassword("AaBC0*TGH1#");
+ Assert.IsTrue(errors.Contains(PasswordValidationEnum.MIN_LOWER));
+ }
+ catch (Exception exception)
+ {
+ Assert.Fail($"An exception was thrown: {exception}");
+ }
+ }
+
+}
+
+
+
+
diff --git a/MainProject/Enum/PasswordValidationEnum.cs b/MainProject/Enum/PasswordValidationEnum.cs
new file mode 100644
index 0000000..b821805
--- /dev/null
+++ b/MainProject/Enum/PasswordValidationEnum.cs
@@ -0,0 +1,10 @@
+namespace BasicDotnetTemplate.MainProject.Enum;
+public static class PasswordValidationEnum
+{
+ public const string MIN_LENGTH = "Password must be at least 8 characters long";
+ public const string MIN_UPPER = "Password must have at least 2 uppercase letters";
+ public const string MIN_LOWER = "Password must have at least 2 lowercase letters";
+ public const string MIN_NUMBER = "Password must be at least 2 numbers";
+ public const string MIN_SPECIAL = "Password must be at least 2 special characters";
+ public const string IDENTICAL_CHARS = "Password cannot have 3 or more consecutive identical characters";
+}
diff --git a/MainProject/MainProject.csproj b/MainProject/MainProject.csproj
index 24c681d..801b05c 100644
--- a/MainProject/MainProject.csproj
+++ b/MainProject/MainProject.csproj
@@ -30,21 +30,21 @@
all
-
+
-
-
+
+
-
-
+
+
-
-
-
-
+
+
+
+
diff --git a/MainProject/Utils/PasswordUtils.cs b/MainProject/Utils/PasswordUtils.cs
new file mode 100644
index 0000000..25e28e1
--- /dev/null
+++ b/MainProject/Utils/PasswordUtils.cs
@@ -0,0 +1,60 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using System.Security.Cryptography;
+using System.Text;
+using System.Text.RegularExpressions;
+using BasicDotnetTemplate.MainProject.Enum;
+using BasicDotnetTemplate.MainProject.Models.Settings;
+
+namespace BasicDotnetTemplate.MainProject.Utils;
+public partial class PasswordUtils
+{
+ private const int MIN_LENGTH = 8;
+ private const int MIN_UPPER = 2;
+ private const int MIN_LOWER = 2;
+ private const int MIN_NUMBER = 2;
+ private const int MIN_SPECIAL = 2;
+
+ [GeneratedRegex("[A-Z]")]
+ private static partial Regex RegexUpper();
+
+ [GeneratedRegex("[a-z]")]
+ private static partial Regex RegexLower();
+
+ [GeneratedRegex("[0-9]")]
+ private static partial Regex RegexNumber();
+
+ [GeneratedRegex("[^a-zA-Z0-9]")]
+ private static partial Regex RegexSpecial();
+
+ [GeneratedRegex(@"(\S)\1{2,}", RegexOptions.IgnoreCase | RegexOptions.Compiled)]
+ private static partial Regex RegexIdenticalChars();
+
+ public static List ValidatePassword(string password)
+ {
+ List errors = [];
+
+ if (password.Length < 8)
+ errors.Add(PasswordValidationEnum.MIN_LENGTH);
+
+ if (RegexUpper().Matches(password).Count < MIN_UPPER)
+ errors.Add(PasswordValidationEnum.MIN_UPPER);
+
+ if (RegexLower().Matches(password).Count < MIN_LOWER)
+ errors.Add(PasswordValidationEnum.MIN_LOWER);
+
+ if (RegexNumber().Matches(password).Count < MIN_NUMBER)
+ errors.Add(PasswordValidationEnum.MIN_NUMBER);
+
+ if (RegexSpecial().Matches(password).Count < MIN_SPECIAL)
+ errors.Add(PasswordValidationEnum.MIN_SPECIAL);
+
+ if (RegexIdenticalChars().IsMatch(password))
+ errors.Add(PasswordValidationEnum.IDENTICAL_CHARS);
+
+ return errors;
+ }
+
+
+}
+