From f8762e260d40f4ca5fde5bfb8d377f63586c065c Mon Sep 17 00:00:00 2001 From: Kolappan Nathan Date: Sat, 2 Dec 2023 13:08:09 +0530 Subject: [PATCH 1/8] updating to .net 8 --- src/WebApiBolierplate/API/API.csproj | 4 ++-- src/WebApiBolierplate/API/appsettings.Development.json | 2 +- src/WebApiBolierplate/API/appsettings.production.json | 2 +- src/WebApiBolierplate/Core.Constants/Core.Constants.csproj | 2 +- src/WebApiBolierplate/Core.Lib/Core.Lib.csproj | 2 +- src/WebApiBolierplate/Core.Test/Core.Test.csproj | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/WebApiBolierplate/API/API.csproj b/src/WebApiBolierplate/API/API.csproj index 5900e07..0a97d43 100644 --- a/src/WebApiBolierplate/API/API.csproj +++ b/src/WebApiBolierplate/API/API.csproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 enable @@ -13,7 +13,7 @@ - + diff --git a/src/WebApiBolierplate/API/appsettings.Development.json b/src/WebApiBolierplate/API/appsettings.Development.json index 5b83ab7..5a84306 100644 --- a/src/WebApiBolierplate/API/appsettings.Development.json +++ b/src/WebApiBolierplate/API/appsettings.Development.json @@ -13,7 +13,7 @@ "JWT": { "Audience": "https://www.example.com", "Issuer": "WebApiBoilerplate", - "Key": "This is a JWT secret key", + "Key": "JWT_keys_with_random_chars---m4sjcv46v06etirgflvcgdwixb9tg5wk5hy1mew85zcznjshivssia9mls539rsq", "HoursValid": 48 } } diff --git a/src/WebApiBolierplate/API/appsettings.production.json b/src/WebApiBolierplate/API/appsettings.production.json index 6f0aee1..75b412f 100644 --- a/src/WebApiBolierplate/API/appsettings.production.json +++ b/src/WebApiBolierplate/API/appsettings.production.json @@ -11,7 +11,7 @@ "JWT": { "Audience": "https://www.example.com", "Issuer": "WebApiBoilerplate", - "Key": "This is a JWT secret key", + "Key": "JWT_keys_with_random_chars---9sav3zkqd1gmgur2r7sdxqwtwvsxong36lylhdnwca3sfr5n6kqg7qpdr1nbhf1q", "HoursValid": 48 } } diff --git a/src/WebApiBolierplate/Core.Constants/Core.Constants.csproj b/src/WebApiBolierplate/Core.Constants/Core.Constants.csproj index 8268829..58990cd 100644 --- a/src/WebApiBolierplate/Core.Constants/Core.Constants.csproj +++ b/src/WebApiBolierplate/Core.Constants/Core.Constants.csproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 diff --git a/src/WebApiBolierplate/Core.Lib/Core.Lib.csproj b/src/WebApiBolierplate/Core.Lib/Core.Lib.csproj index 156828f..4baba19 100644 --- a/src/WebApiBolierplate/Core.Lib/Core.Lib.csproj +++ b/src/WebApiBolierplate/Core.Lib/Core.Lib.csproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 diff --git a/src/WebApiBolierplate/Core.Test/Core.Test.csproj b/src/WebApiBolierplate/Core.Test/Core.Test.csproj index 895ea08..47f41d1 100644 --- a/src/WebApiBolierplate/Core.Test/Core.Test.csproj +++ b/src/WebApiBolierplate/Core.Test/Core.Test.csproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 false From e27be1cfb0ed257fcc6ce55024b9f3f40ff794b5 Mon Sep 17 00:00:00 2001 From: Kolappan Nathan Date: Sat, 2 Dec 2023 13:09:53 +0530 Subject: [PATCH 2/8] added validation for empty strings --- src/WebApiBolierplate/API/Models/LoginDTO.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/WebApiBolierplate/API/Models/LoginDTO.cs b/src/WebApiBolierplate/API/Models/LoginDTO.cs index dced690..d817ff1 100644 --- a/src/WebApiBolierplate/API/Models/LoginDTO.cs +++ b/src/WebApiBolierplate/API/Models/LoginDTO.cs @@ -9,9 +9,9 @@ public LoginDTO() } - [Required(ErrorMessage = "No name. No game.")] + [Required(ErrorMessage = "No name. No game.", AllowEmptyStrings = false)] public string UserName { get; set; } - [Required(ErrorMessage = "No password?! Are you kidding?")] + [Required(ErrorMessage = "No password?! Are you kidding?", AllowEmptyStrings = false)] public string Password { get; set; } } From 790e550e72571b1f091de86b1d7c6b06b8d1e795 Mon Sep 17 00:00:00 2001 From: Kolappan Nathan Date: Sat, 2 Dec 2023 13:38:23 +0530 Subject: [PATCH 3/8] updated random string, removed random no --- .../Utilities/Interfaces/IRandomUtils.cs | 11 ----- .../Core.Lib/Utilities/RandomUtils.cs | 42 ++++--------------- .../Core.Test/Utilities/RandomUtilsTest.cs | 9 ---- 3 files changed, 7 insertions(+), 55 deletions(-) diff --git a/src/WebApiBolierplate/Core.Lib/Utilities/Interfaces/IRandomUtils.cs b/src/WebApiBolierplate/Core.Lib/Utilities/Interfaces/IRandomUtils.cs index d140c45..9dcea1d 100644 --- a/src/WebApiBolierplate/Core.Lib/Utilities/Interfaces/IRandomUtils.cs +++ b/src/WebApiBolierplate/Core.Lib/Utilities/Interfaces/IRandomUtils.cs @@ -12,15 +12,4 @@ public interface IRandomUtils /// /// public string GenRandomChar(int length, CharSet charSet); - - - /// - /// Generates a random number using cryptography within the specified range - /// Ref: https://stackoverflow.com/a/38669162/5407188 - /// - /// minimum value for the random number - /// maximum value for the random number - /// - /// - public int GenRandomNumber(int min, int max); } diff --git a/src/WebApiBolierplate/Core.Lib/Utilities/RandomUtils.cs b/src/WebApiBolierplate/Core.Lib/Utilities/RandomUtils.cs index 4188caa..537bfde 100644 --- a/src/WebApiBolierplate/Core.Lib/Utilities/RandomUtils.cs +++ b/src/WebApiBolierplate/Core.Lib/Utilities/RandomUtils.cs @@ -9,9 +9,9 @@ public sealed class RandomUtils : IRandomUtils { #region [Declarations] - private string _uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - private string _lowercase = "abcdefghijklmnopqrstuvwxyz"; - private string _numbers = "0123456789"; + private readonly string _uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + private readonly string _lowercase = "abcdefghijklmnopqrstuvwxyz"; + private readonly string _numbers = "0123456789"; #endregion Declarations @@ -60,40 +60,12 @@ public string GenRandomChar(int length, CharSet charSet) { if (length <= 0) { - throw new ArgumentException("length", "Length of the random character must be greater than zero"); + throw new ArgumentException("Length of the random character must be greater than zero", nameof(length)); } - char[] chars = GetChars(charSet); - var stringChars = new char[length]; - - for (int i = 0; i < length; i++) - { - stringChars[i] = chars[GenRandomNumber(0, chars.Length)]; - } - - var finalString = new String(stringChars); - return finalString; - } - - public int GenRandomNumber(int min, int max) - { - if (min >= max) - { - throw new ArgumentException("The value of min should be less than max"); - } - - using (var generator = RandomNumberGenerator.Create()) - { - // Generate four random bytes - var four_bytes = new byte[4]; - generator.GetBytes(four_bytes); - - // Convert the bytes to a UInt32 - var scale = BitConverter.ToUInt32(four_bytes, 0); - - // And use that to pick a random number >= min and < max - return (int)(min + (max - min) * (scale / (uint.MaxValue + 1.0))); - } + var chars = GetChars(charSet); + var stringChars = RandomNumberGenerator.GetString(chars, length); + return new string(stringChars); } #endregion [Public Functions] diff --git a/src/WebApiBolierplate/Core.Test/Utilities/RandomUtilsTest.cs b/src/WebApiBolierplate/Core.Test/Utilities/RandomUtilsTest.cs index 0b276c5..9b6bcb7 100644 --- a/src/WebApiBolierplate/Core.Test/Utilities/RandomUtilsTest.cs +++ b/src/WebApiBolierplate/Core.Test/Utilities/RandomUtilsTest.cs @@ -21,13 +21,4 @@ public void TestingRandomChar() var randomChars = _randomUtils.GenRandomChar(length, Constants.Enums.CharSet.Alphabets); Assert.AreEqual(randomChars.Length, length); } - - [TestMethod] - public void TestRandomNo() - { - const int min = 0, max = 108; - var randomChars = _randomUtils.GenRandomNumber(min, max); - Assert.IsTrue(randomChars <= max); - Assert.IsTrue(randomChars >= min); - } } From ff873711655ede0a13a53fab6d23d62672024df9 Mon Sep 17 00:00:00 2001 From: Kolappan Nathan Date: Sat, 2 Dec 2023 14:42:31 +0530 Subject: [PATCH 4/8] Simplifying Argument exceptions --- src/WebApiBolierplate/Core.Lib/Utilities/JwtUtils.cs | 6 +----- src/WebApiBolierplate/Core.Lib/Utilities/RandomUtils.cs | 5 +---- .../Core.Test/Utilities/RandomUtilsTest.cs | 5 +++++ 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/WebApiBolierplate/Core.Lib/Utilities/JwtUtils.cs b/src/WebApiBolierplate/Core.Lib/Utilities/JwtUtils.cs index ac8412b..df9adad 100644 --- a/src/WebApiBolierplate/Core.Lib/Utilities/JwtUtils.cs +++ b/src/WebApiBolierplate/Core.Lib/Utilities/JwtUtils.cs @@ -34,11 +34,7 @@ public string GenerateToken() private void EnsureArguments() { ArgumentNullException.ThrowIfNull(_securityKey); - - if (_expiryInHours == 0) - { - throw new ArgumentNullException("Expiry Time"); - } + ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(_expiryInHours, 0); } /// diff --git a/src/WebApiBolierplate/Core.Lib/Utilities/RandomUtils.cs b/src/WebApiBolierplate/Core.Lib/Utilities/RandomUtils.cs index 537bfde..9c2fb60 100644 --- a/src/WebApiBolierplate/Core.Lib/Utilities/RandomUtils.cs +++ b/src/WebApiBolierplate/Core.Lib/Utilities/RandomUtils.cs @@ -58,10 +58,7 @@ private char[] GetChars(CharSet charSet) public string GenRandomChar(int length, CharSet charSet) { - if (length <= 0) - { - throw new ArgumentException("Length of the random character must be greater than zero", nameof(length)); - } + ArgumentOutOfRangeException.ThrowIfLessThan(length, 1); var chars = GetChars(charSet); var stringChars = RandomNumberGenerator.GetString(chars, length); diff --git a/src/WebApiBolierplate/Core.Test/Utilities/RandomUtilsTest.cs b/src/WebApiBolierplate/Core.Test/Utilities/RandomUtilsTest.cs index 9b6bcb7..cd232ee 100644 --- a/src/WebApiBolierplate/Core.Test/Utilities/RandomUtilsTest.cs +++ b/src/WebApiBolierplate/Core.Test/Utilities/RandomUtilsTest.cs @@ -1,6 +1,7 @@ using Core.Lib.Utilities; using Core.Lib.Utilities.Interfaces; using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; namespace Core.Test.Utilities; @@ -20,5 +21,9 @@ public void TestingRandomChar() const int length = 10; var randomChars = _randomUtils.GenRandomChar(length, Constants.Enums.CharSet.Alphabets); Assert.AreEqual(randomChars.Length, length); + + Assert.ThrowsException(() => { + _randomUtils.GenRandomChar(0, Constants.Enums.CharSet.Alphabets); + }); } } From 6c24240ebf87f0d599726512570614b2fd4a8fce Mon Sep 17 00:00:00 2001 From: Kolappan Nathan Date: Sat, 2 Dec 2023 14:44:21 +0530 Subject: [PATCH 5/8] adding salts for bcrypt --- .../Core.Lib/Utilities/Interfaces/ISecurityUtils.cs | 6 ++++-- .../Core.Lib/Utilities/SecurityUtils.cs | 10 ++++++---- .../Core.Test/Utilities/SecurityUtilsTest.cs | 5 +++-- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/WebApiBolierplate/Core.Lib/Utilities/Interfaces/ISecurityUtils.cs b/src/WebApiBolierplate/Core.Lib/Utilities/Interfaces/ISecurityUtils.cs index fa2aef1..231519e 100644 --- a/src/WebApiBolierplate/Core.Lib/Utilities/Interfaces/ISecurityUtils.cs +++ b/src/WebApiBolierplate/Core.Lib/Utilities/Interfaces/ISecurityUtils.cs @@ -15,18 +15,20 @@ public interface ISecurityUtils /// Hashes the plaintext password using BCrypt and returns the hash /// /// + /// /// /// /// - public string HashBCrypt(string plainText); + public string HashBCrypt(string plainText, string salt); /// /// Verfies the hash and password with Brcypt /// /// + /// /// /// /// /// - public bool VerifyBCrypt(string plainText, string hash); + public bool VerifyBCrypt(string plainText, string salt, string hash); } diff --git a/src/WebApiBolierplate/Core.Lib/Utilities/SecurityUtils.cs b/src/WebApiBolierplate/Core.Lib/Utilities/SecurityUtils.cs index 1aaeaec..0c9c2b8 100644 --- a/src/WebApiBolierplate/Core.Lib/Utilities/SecurityUtils.cs +++ b/src/WebApiBolierplate/Core.Lib/Utilities/SecurityUtils.cs @@ -60,20 +60,22 @@ public string DecryptString(string cipherText, string encryptionKey) } } - public string HashBCrypt(string plainText) + public string HashBCrypt(string plainText, string salt) { ArgumentException.ThrowIfNullOrEmpty(plainText); + ArgumentException.ThrowIfNullOrEmpty(salt); - var hash = BCrypt.Net.BCrypt.HashPassword(plainText, workFactor: 10); + var hash = BCrypt.Net.BCrypt.HashPassword(plainText + salt, workFactor: 10); return hash; } - public bool VerifyBCrypt(string plainText, string hash) + public bool VerifyBCrypt(string plainText, string salt, string hash) { ArgumentException.ThrowIfNullOrEmpty(plainText); + ArgumentException.ThrowIfNullOrEmpty(salt); ArgumentException.ThrowIfNullOrEmpty(hash); - var isMatch = BCrypt.Net.BCrypt.Verify(plainText, hash); + var isMatch = BCrypt.Net.BCrypt.Verify(plainText + salt, hash); return isMatch; } } diff --git a/src/WebApiBolierplate/Core.Test/Utilities/SecurityUtilsTest.cs b/src/WebApiBolierplate/Core.Test/Utilities/SecurityUtilsTest.cs index 06cd791..9548594 100644 --- a/src/WebApiBolierplate/Core.Test/Utilities/SecurityUtilsTest.cs +++ b/src/WebApiBolierplate/Core.Test/Utilities/SecurityUtilsTest.cs @@ -10,6 +10,7 @@ public sealed class SecurityUtilsTest private readonly ISecurityUtils _securityUtils; private const string _sampleString = "This is a sample string"; private const string _key = "THk5emRHRmphMjkyWlhKbWJHOTNMbU52YlM5eGRXVnpkR2x2Ym5Ndk16azJORGs1TnpZdmFYTXRh"; + private const string _salt = "umssxcahqnumssxcahqnumssxcahqn"; public SecurityUtilsTest() { @@ -20,8 +21,8 @@ public SecurityUtilsTest() public void TestHash() { - var hashedValue = _securityUtils.HashBCrypt(_sampleString); - var hashComparission = _securityUtils.VerifyBCrypt(_sampleString, hashedValue); + var hashedValue = _securityUtils.HashBCrypt(_sampleString, _salt); + var hashComparission = _securityUtils.VerifyBCrypt(_sampleString, _salt, hashedValue); Assert.IsTrue(hashComparission); } From 2dc31f40749a9ae249e697e4bad73b4aa7a9aa8b Mon Sep 17 00:00:00 2001 From: Kolappan Nathan Date: Sat, 2 Dec 2023 14:45:46 +0530 Subject: [PATCH 6/8] Update spellright.dict --- .vscode/spellright.dict | 1 + 1 file changed, 1 insertion(+) diff --git a/.vscode/spellright.dict b/.vscode/spellright.dict index 0987f19..7f45979 100644 --- a/.vscode/spellright.dict +++ b/.vscode/spellright.dict @@ -6,3 +6,4 @@ launchsettings.json editorconfig db Serilog +Bcrypt From e74e8dd5aa3761c70d1904a9b861325c7f10c6fc Mon Sep 17 00:00:00 2001 From: Kolappan Nathan Date: Sat, 2 Dec 2023 14:46:24 +0530 Subject: [PATCH 7/8] v8.0.0 --- CHANGELOG.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fbcdfea..73aa6e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,21 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [Unreleased] +## [8.0.0] - 2023-12-02 +### Added + - Salt added as separate param for Bcrypt in Security lib. Previously it was indented to be already added and sent with the plain text password. + - New test cases in postman + +### Changed + - Updated .NET version to 8 + - Moved Configurators into a separate folder to simplify Program.cs + - Updated Random String Generator to use `System.Security.Cryptography.RandomNumberGenerator`. + - Using updated checks for Argument exceptions + - Updated dependencies + +### Removed + - Removed the random number generating function. The built-in function with RandomNumberGenerator to be used instead. + ## [7.1.0] - 2023-03-02 ### Added - Added interfaces for library classes, helper functions. From 2aecde48ca0087215fd9266daa951b1b643a711c Mon Sep 17 00:00:00 2001 From: Kolappan Nathan Date: Sat, 2 Dec 2023 14:47:39 +0530 Subject: [PATCH 8/8] added tests --- .../Web API Boilerplate.postman_collection.json | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/postman/Web API Boilerplate.postman_collection.json b/src/postman/Web API Boilerplate.postman_collection.json index 68ee45d..e40be61 100644 --- a/src/postman/Web API Boilerplate.postman_collection.json +++ b/src/postman/Web API Boilerplate.postman_collection.json @@ -108,6 +108,11 @@ "exec": [ "pm.test(\"Status code is 401\", function () {\r", " pm.response.to.have.status(401);\r", + "});\r", + "\r", + "pm.test(\"Check error message\", function () {\r", + " var jsonData = pm.response.json();\r", + " pm.expect(jsonData.message).to.eql(\"The credentials are invalid.\");\r", "});" ], "type": "text/javascript" @@ -235,6 +240,11 @@ "exec": [ "pm.test(\"Status code is 500\", function () {\r", " pm.response.to.have.status(500);\r", + "});\r", + "\r", + "pm.test(\"Check Error msg\", function () {\r", + " var jsonData = pm.response.json();\r", + " pm.expect(jsonData.message).to.eql(\"Oops! An Internal Error Occured.\");\r", "});" ], "type": "text/javascript" @@ -274,6 +284,11 @@ "exec": [ "pm.test(\"Status code is 400\", function () {\r", " pm.response.to.have.status(400);\r", + "});\r", + "\r", + "pm.test(\"Check error message\", function () {\r", + " var jsonData = pm.response.json();\r", + " pm.expect(jsonData.message).to.eql(\"No name. No game.\");\r", "});" ], "type": "text/javascript"