Sprint 8 #43
@@ -10,12 +10,15 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="coverlet.collector" Version="6.0.0" />
|
<PackageReference Include="coverlet.collector" Version="6.0.4">
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.3" />
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.5" />
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
||||||
<PackageReference Include="Moq" Version="4.20.72" />
|
<PackageReference Include="Moq" Version="4.20.72" />
|
||||||
<PackageReference Include="MSTest.TestAdapter" Version="3.1.1" />
|
<PackageReference Include="MSTest.TestAdapter" Version="3.9.1" />
|
||||||
<PackageReference Include="MSTest.TestFramework" Version="3.1.1" />
|
<PackageReference Include="MSTest.TestFramework" Version="3.9.1" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
62
MainProject.Tests/Utils/PasswordUtils_Test.cs
Normal file
62
MainProject.Tests/Utils/PasswordUtils_Test.cs
Normal file
@@ -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<string> 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<string> 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<string> errors = PasswordUtils.ValidatePassword("AaBC0*TGH1#");
|
||||||
|
Assert.IsTrue(errors.Contains(PasswordValidationEnum.MIN_LOWER));
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
Assert.Fail($"An exception was thrown: {exception}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
10
MainProject/Enum/PasswordValidationEnum.cs
Normal file
10
MainProject/Enum/PasswordValidationEnum.cs
Normal file
@@ -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";
|
||||||
|
}
|
||||||
@@ -30,21 +30,21 @@
|
|||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.5" />
|
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.5" />
|
||||||
<PackageReference Include="Microsoft.Identity.Web" Version="3.9.2" />
|
<PackageReference Include="Microsoft.Identity.Web" Version="3.9.3" />
|
||||||
<PackageReference Include="MongoDB.Driver" Version="3.4.0" />
|
<PackageReference Include="MongoDB.Driver" Version="3.4.0" />
|
||||||
<PackageReference Include="MongoDB.EntityFrameworkCore" Version="9.0.0" />
|
<PackageReference Include="MongoDB.EntityFrameworkCore" Version="9.0.0" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageReference Include="NLog" Version="5.4.0" />
|
<PackageReference Include="NLog" Version="5.5.0" />
|
||||||
<PackageReference Include="NLog.Extensions.Logging" Version="5.4.0" />
|
<PackageReference Include="NLog.Extensions.Logging" Version="5.5.0" />
|
||||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.4" />
|
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.4" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="8.1.2" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="8.1.4" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="8.1.2" />
|
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="8.1.4" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore.Filters" Version="8.0.3" />
|
<PackageReference Include="Swashbuckle.AspNetCore.Filters" Version="8.0.3" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore.Filters.Abstractions" Version="8.0.3" />
|
<PackageReference Include="Swashbuckle.AspNetCore.Filters.Abstractions" Version="8.0.3" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="8.1.2" />
|
<PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="8.1.4" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore.Swagger" Version="8.1.2" />
|
<PackageReference Include="Swashbuckle.AspNetCore.Swagger" Version="8.1.4" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="8.1.2" />
|
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="8.1.4" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="8.1.2" />
|
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="8.1.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
60
MainProject/Utils/PasswordUtils.cs
Normal file
60
MainProject/Utils/PasswordUtils.cs
Normal file
@@ -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<string> ValidatePassword(string password)
|
||||||
|
{
|
||||||
|
List<string> 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user