diff options
| -rw-r--r-- | src/IOL.Helpers/CryptographyHelpers.cs | 263 | ||||
| -rw-r--r-- | src/IOL.Helpers/DateTimeHelpers.cs | 37 | ||||
| -rw-r--r-- | src/IOL.Helpers/DoubleHelpers.cs | 13 | ||||
| -rw-r--r-- | src/IOL.Helpers/EnumHelpers.cs | 13 | ||||
| -rw-r--r-- | src/IOL.Helpers/HttpRequestHelpers.cs | 37 | ||||
| -rw-r--r-- | src/IOL.Helpers/InMemoryZipArchive.cs | 37 | ||||
| -rw-r--r-- | src/IOL.Helpers/PasswordHelpers.cs | 107 | ||||
| -rw-r--r-- | src/IOL.Helpers/QueryableHelpers.cs | 24 | ||||
| -rw-r--r-- | src/IOL.Helpers/RandomStringGenerator.cs | 19 | ||||
| -rw-r--r-- | src/IOL.Helpers/SlugGenerator.cs | 151 | ||||
| -rw-r--r-- | src/IOL.Helpers/StringHelpers.cs | 123 | ||||
| -rw-r--r-- | src/IOL.Helpers/Validators.cs | 21 |
12 files changed, 429 insertions, 416 deletions
diff --git a/src/IOL.Helpers/CryptographyHelpers.cs b/src/IOL.Helpers/CryptographyHelpers.cs index 6ea18b6..4821613 100644 --- a/src/IOL.Helpers/CryptographyHelpers.cs +++ b/src/IOL.Helpers/CryptographyHelpers.cs @@ -3,171 +3,170 @@ using System.Linq; using System.Security.Cryptography; using System.Text; -namespace IOL.Helpers +namespace IOL.Helpers; + +public static class CryptographyHelpers { - public static class CryptographyHelpers - { - // https://github.com/DuendeSoftware/IdentityServer/blob/main/src/IdentityServer/Extensions/HashExtensions.cs + // https://github.com/DuendeSoftware/IdentityServer/blob/main/src/IdentityServer/Extensions/HashExtensions.cs - private const int AES_BLOCK_BYTE_SIZE = 128 / 8; - private static readonly RandomNumberGenerator _random = RandomNumberGenerator.Create(); + private const int AES_BLOCK_BYTE_SIZE = 128 / 8; + private static readonly RandomNumberGenerator _random = RandomNumberGenerator.Create(); - /// <summary> - /// Creates a MD5 hash of the specified input. - /// </summary> - /// <returns>A hash</returns> - public static string Md5(this string input, string salt = default) { - if (input.IsNullOrWhiteSpace()) return string.Empty; + /// <summary> + /// Creates a MD5 hash of the specified input. + /// </summary> + /// <returns>A hash</returns> + public static string Md5(this string input, string salt = default) { + if (input.IsNullOrWhiteSpace()) return string.Empty; - var hmacMd5 = salt.HasValue() ? new HMACMD5(Encoding.UTF8.GetBytes(salt ?? "")) : new HMACMD5(); - var saltedHash = hmacMd5.ComputeHash(Encoding.UTF8.GetBytes(input)); - return Convert.ToBase64String(saltedHash); - } + var hmacMd5 = salt.HasValue() ? new HMACMD5(Encoding.UTF8.GetBytes(salt ?? "")) : new HMACMD5(); + var saltedHash = hmacMd5.ComputeHash(Encoding.UTF8.GetBytes(input)); + return Convert.ToBase64String(saltedHash); + } - /// <summary> - /// Method to perform a very simple (and classical) encryption for a string. This is NOT at - /// all secure, it is only intended to make the string value non-obvious at a first glance. - /// - /// The shiftOrUnshift argument is an arbitrary "key value", and must be a non-zero integer - /// between -65535 and 65535 (inclusive). To decrypt the encrypted string you use the negative - /// value. For example, if you encrypt with -42, then you decrypt with +42, or vice-versa. - /// - /// This is inspired by, and largely based on, this: - /// https://stackoverflow.com/a/13026595/253938 - /// </summary> - /// <param name="inputString">string to be encrypted or decrypted, must not be null</param> - /// <param name="shiftOrUnshift">see above</param> - /// <returns>encrypted or decrypted string</returns> - public static string CaesarCipher(string inputString, int shiftOrUnshift) { - const int C64_K = ushort.MaxValue + 1; - if (inputString == null) throw new ArgumentException("Must not be null.", nameof(inputString)); - switch (shiftOrUnshift) { - case 0: throw new ArgumentException("Must not be zero.", nameof(shiftOrUnshift)); - case <= -C64_K: - case >= C64_K: throw new ArgumentException("Out of range.", nameof(shiftOrUnshift)); - } + /// <summary> + /// Method to perform a very simple (and classical) encryption for a string. This is NOT at + /// all secure, it is only intended to make the string value non-obvious at a first glance. + /// + /// The shiftOrUnshift argument is an arbitrary "key value", and must be a non-zero integer + /// between -65535 and 65535 (inclusive). To decrypt the encrypted string you use the negative + /// value. For example, if you encrypt with -42, then you decrypt with +42, or vice-versa. + /// + /// This is inspired by, and largely based on, this: + /// https://stackoverflow.com/a/13026595/253938 + /// </summary> + /// <param name="inputString">string to be encrypted or decrypted, must not be null</param> + /// <param name="shiftOrUnshift">see above</param> + /// <returns>encrypted or decrypted string</returns> + public static string CaesarCipher(string inputString, int shiftOrUnshift) { + const int C64_K = ushort.MaxValue + 1; + if (inputString == null) throw new ArgumentException("Must not be null.", nameof(inputString)); + switch (shiftOrUnshift) { + case 0: throw new ArgumentException("Must not be zero.", nameof(shiftOrUnshift)); + case <= -C64_K: + case >= C64_K: throw new ArgumentException("Out of range.", nameof(shiftOrUnshift)); + } - // Perform the Caesar cipher shifting, using modulo operator to provide wrap-around - var charArray = new char[inputString.Length]; - for (var i = 0; i < inputString.Length; i++) { - charArray[i] = + // Perform the Caesar cipher shifting, using modulo operator to provide wrap-around + var charArray = new char[inputString.Length]; + for (var i = 0; i < inputString.Length; i++) { + charArray[i] = Convert.ToChar((Convert.ToInt32(inputString[i]) + shiftOrUnshift + C64_K) % C64_K); - } - - return new string(charArray); } - //https://tomrucki.com/posts/aes-encryption-in-csharp/ - public static string EncryptWithAes(this string toEncrypt, string password) { - var key = GetKey(password); + return new string(charArray); + } + + //https://tomrucki.com/posts/aes-encryption-in-csharp/ + public static string EncryptWithAes(this string toEncrypt, string password) { + var key = GetKey(password); - using var aes = CreateAes(); - var iv = GenerateRandomBytes(AES_BLOCK_BYTE_SIZE); - var plainText = Encoding.UTF8.GetBytes(toEncrypt); + using var aes = CreateAes(); + var iv = GenerateRandomBytes(AES_BLOCK_BYTE_SIZE); + var plainText = Encoding.UTF8.GetBytes(toEncrypt); - using var encryptor = aes.CreateEncryptor(key, iv); - var cipherText = encryptor + using var encryptor = aes.CreateEncryptor(key, iv); + var cipherText = encryptor .TransformFinalBlock(plainText, 0, plainText.Length); - var result = new byte[iv.Length + cipherText.Length]; - iv.CopyTo(result, 0); - cipherText.CopyTo(result, iv.Length); + var result = new byte[iv.Length + cipherText.Length]; + iv.CopyTo(result, 0); + cipherText.CopyTo(result, iv.Length); - return Convert.ToBase64String(result); - } + return Convert.ToBase64String(result); + } - private static Aes CreateAes() { - var aes = Aes.Create(); - aes.Mode = CipherMode.CBC; - aes.Padding = PaddingMode.PKCS7; - return aes; - } + private static Aes CreateAes() { + var aes = Aes.Create(); + aes.Mode = CipherMode.CBC; + aes.Padding = PaddingMode.PKCS7; + return aes; + } - public static string DecryptWithAes(this string input, string password) { - var key = GetKey(password); - var encryptedData = Convert.FromBase64String(input); + public static string DecryptWithAes(this string input, string password) { + var key = GetKey(password); + var encryptedData = Convert.FromBase64String(input); - using var aes = CreateAes(); - var iv = encryptedData.Take(AES_BLOCK_BYTE_SIZE).ToArray(); - var cipherText = encryptedData.Skip(AES_BLOCK_BYTE_SIZE).ToArray(); + using var aes = CreateAes(); + var iv = encryptedData.Take(AES_BLOCK_BYTE_SIZE).ToArray(); + var cipherText = encryptedData.Skip(AES_BLOCK_BYTE_SIZE).ToArray(); - using var decryptor = aes.CreateDecryptor(key, iv); - var decryptedBytes = decryptor + using var decryptor = aes.CreateDecryptor(key, iv); + var decryptedBytes = decryptor .TransformFinalBlock(cipherText, 0, cipherText.Length); - return Encoding.UTF8.GetString(decryptedBytes); - } - - private static byte[] GetKey(string password) { - var keyBytes = Encoding.UTF8.GetBytes(password); - using var md5 = MD5.Create(); - return md5.ComputeHash(keyBytes); - } + return Encoding.UTF8.GetString(decryptedBytes); + } - private static byte[] GenerateRandomBytes(int numberOfBytes) { - var randomBytes = new byte[numberOfBytes]; - _random.GetBytes(randomBytes); - return randomBytes; - } + private static byte[] GetKey(string password) { + var keyBytes = Encoding.UTF8.GetBytes(password); + using var md5 = MD5.Create(); + return md5.ComputeHash(keyBytes); + } + private static byte[] GenerateRandomBytes(int numberOfBytes) { + var randomBytes = new byte[numberOfBytes]; + _random.GetBytes(randomBytes); + return randomBytes; + } - /// <summary> - /// Creates a SHA256 hash of the specified input. - /// </summary> - /// <param name="input">The input.</param> - /// <returns>A hash</returns> - public static string Sha256(this string input) { - if (input.IsNullOrWhiteSpace()) return string.Empty; - using var sha = SHA256.Create(); - var bytes = Encoding.UTF8.GetBytes(input); - var hash = sha.ComputeHash(bytes); + /// <summary> + /// Creates a SHA256 hash of the specified input. + /// </summary> + /// <param name="input">The input.</param> + /// <returns>A hash</returns> + public static string Sha256(this string input) { + if (input.IsNullOrWhiteSpace()) return string.Empty; - return Convert.ToBase64String(hash); - } + using var sha = SHA256.Create(); + var bytes = Encoding.UTF8.GetBytes(input); + var hash = sha.ComputeHash(bytes); - /// <summary> - /// Creates a SHA256 hash of the specified input. - /// </summary> - /// <param name="input">The input.</param> - /// <returns>A hash.</returns> - public static byte[] Sha256(this byte[] input) { - if (input == null) { - return null; - } + return Convert.ToBase64String(hash); + } - using var sha = SHA256.Create(); - return sha.ComputeHash(input); + /// <summary> + /// Creates a SHA256 hash of the specified input. + /// </summary> + /// <param name="input">The input.</param> + /// <returns>A hash.</returns> + public static byte[] Sha256(this byte[] input) { + if (input == null) { + return null; } - /// <summary> - /// Creates a SHA512 hash of the specified input. - /// </summary> - /// <param name="input">The input.</param> - /// <returns>A hash</returns> - public static string Sha512(this string input) { - if (input.IsNullOrWhiteSpace()) return string.Empty; + using var sha = SHA256.Create(); + return sha.ComputeHash(input); + } - using var sha = SHA512.Create(); - var bytes = Encoding.UTF8.GetBytes(input); - var hash = sha.ComputeHash(bytes); + /// <summary> + /// Creates a SHA512 hash of the specified input. + /// </summary> + /// <param name="input">The input.</param> + /// <returns>A hash</returns> + public static string Sha512(this string input) { + if (input.IsNullOrWhiteSpace()) return string.Empty; - return Convert.ToBase64String(hash); - } + using var sha = SHA512.Create(); + var bytes = Encoding.UTF8.GetBytes(input); + var hash = sha.ComputeHash(bytes); + return Convert.ToBase64String(hash); + } - /// <summary> - /// Creates a SHA256 hash of the specified input. - /// </summary> - /// <param name="input">The input.</param> - /// <returns>A hash.</returns> - public static byte[] Sha512(this byte[] input) { - if (input == null) { - return null; - } - using var sha = SHA512.Create(); - return sha.ComputeHash(input); + /// <summary> + /// Creates a SHA256 hash of the specified input. + /// </summary> + /// <param name="input">The input.</param> + /// <returns>A hash.</returns> + public static byte[] Sha512(this byte[] input) { + if (input == null) { + return null; } + + using var sha = SHA512.Create(); + return sha.ComputeHash(input); } -}
\ No newline at end of file +} diff --git a/src/IOL.Helpers/DateTimeHelpers.cs b/src/IOL.Helpers/DateTimeHelpers.cs index 98b3ee9..16ece6b 100644 --- a/src/IOL.Helpers/DateTimeHelpers.cs +++ b/src/IOL.Helpers/DateTimeHelpers.cs @@ -1,27 +1,26 @@ using System; -namespace IOL.Helpers +namespace IOL.Helpers; + +public static class DateTimeHelpers { - public static class DateTimeHelpers - { - public static DateTime ToTimeZoneId(this DateTime value, string timeZoneId) { - try { - var cstZone = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId); - return TimeZoneInfo.ConvertTimeFromUtc(value, cstZone); - } catch (TimeZoneNotFoundException) { - Console.WriteLine("The registry does not define the " + timeZoneId + " zone."); - return default; - } catch (InvalidTimeZoneException) { - Console.WriteLine("Registry data on the " + timeZoneId + " zone has been corrupted."); - return default; - } + public static DateTime ToTimeZoneId(this DateTime value, string timeZoneId) { + try { + var cstZone = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId); + return TimeZoneInfo.ConvertTimeFromUtc(value, cstZone); + } catch (TimeZoneNotFoundException) { + Console.WriteLine("The registry does not define the " + timeZoneId + " zone."); + return default; + } catch (InvalidTimeZoneException) { + Console.WriteLine("Registry data on the " + timeZoneId + " zone has been corrupted."); + return default; } + } - public static DateTime ToOsloTimeZone(this DateTime value) => ToTimeZoneId(value, "Europe/Oslo"); + public static DateTime ToOsloTimeZone(this DateTime value) => ToTimeZoneId(value, "Europe/Oslo"); - public static DateTime StartOfWeek(this DateTime dt, DayOfWeek startOfWeek) { - var diff = (7 + (dt.DayOfWeek - startOfWeek)) % 7; - return dt.AddDays(-1 * diff).Date; - } + public static DateTime StartOfWeek(this DateTime dt, DayOfWeek startOfWeek) { + var diff = (7 + (dt.DayOfWeek - startOfWeek)) % 7; + return dt.AddDays(-1 * diff).Date; } } diff --git a/src/IOL.Helpers/DoubleHelpers.cs b/src/IOL.Helpers/DoubleHelpers.cs index 91d88ee..44f01d5 100644 --- a/src/IOL.Helpers/DoubleHelpers.cs +++ b/src/IOL.Helpers/DoubleHelpers.cs @@ -1,11 +1,10 @@ using System; -namespace IOL.Helpers +namespace IOL.Helpers; + +public static class DoubleHelpers { - public static class DoubleHelpers - { - public static string ToStringWithFixedDecimalPoints(this double value) { - return $"{Math.Truncate(value * 10) / 10:0.0}"; - } + public static string ToStringWithFixedDecimalPoints(this double value) { + return $"{Math.Truncate(value * 10) / 10:0.0}"; } -}
\ No newline at end of file +} diff --git a/src/IOL.Helpers/EnumHelpers.cs b/src/IOL.Helpers/EnumHelpers.cs index b63e045..5434992 100644 --- a/src/IOL.Helpers/EnumHelpers.cs +++ b/src/IOL.Helpers/EnumHelpers.cs @@ -2,12 +2,11 @@ using System; using System.Collections.Generic; using System.Linq; -namespace IOL.Helpers +namespace IOL.Helpers; + +public static class EnumHelpers { - public static class EnumHelpers - { - public static IEnumerable<T> GetValues<T>() { - return Enum.GetValues(typeof(T)).Cast<T>(); - } + public static IEnumerable<T> GetValues<T>() { + return Enum.GetValues(typeof(T)).Cast<T>(); } -}
\ No newline at end of file +} diff --git a/src/IOL.Helpers/HttpRequestHelpers.cs b/src/IOL.Helpers/HttpRequestHelpers.cs index 60dbd90..59332f4 100644 --- a/src/IOL.Helpers/HttpRequestHelpers.cs +++ b/src/IOL.Helpers/HttpRequestHelpers.cs @@ -1,25 +1,24 @@ using Microsoft.AspNetCore.Http; -namespace IOL.Helpers +namespace IOL.Helpers; + +public static class HttpRequestHelpers { - public static class HttpRequestHelpers - { - /// <summary> - /// Get's the scheme and host (scheme://host) value of the current HttpRequest - /// </summary> - /// <param name="request">HttpRequest to retrieve value from</param> - /// <param name="ignoreForwared">Ignore header values like X-Forwarded-Host|Proto</param> - /// <returns></returns> - public static string GetRequestHost(this HttpRequest request, bool ignoreForwared = false) { - if (!ignoreForwared) { - var forwardedHostHeader = request.Headers["X-Forwarded-Host"].ToString(); - var forwardedProtoHeader = request.Headers["X-Forwarded-Proto"].ToString(); - if (forwardedHostHeader.HasValue()) { - return (forwardedProtoHeader ?? "https") + "://" + forwardedHostHeader; - } + /// <summary> + /// Get's the scheme and host (scheme://host) value of the current HttpRequest + /// </summary> + /// <param name="request">HttpRequest to retrieve value from</param> + /// <param name="ignoreForwared">Ignore header values like X-Forwarded-Host|Proto</param> + /// <returns></returns> + public static string GetRequestHost(this HttpRequest request, bool ignoreForwared = false) { + if (!ignoreForwared) { + var forwardedHostHeader = request.Headers["X-Forwarded-Host"].ToString(); + var forwardedProtoHeader = request.Headers["X-Forwarded-Proto"].ToString(); + if (forwardedHostHeader.HasValue()) { + return (forwardedProtoHeader ?? "https") + "://" + forwardedHostHeader; } - - return request.Scheme + "://" + request.Host; } + + return request.Scheme + "://" + request.Host; } -}
\ No newline at end of file +} diff --git a/src/IOL.Helpers/InMemoryZipArchive.cs b/src/IOL.Helpers/InMemoryZipArchive.cs index 8d3fc94..efb4f79 100644 --- a/src/IOL.Helpers/InMemoryZipArchive.cs +++ b/src/IOL.Helpers/InMemoryZipArchive.cs @@ -3,28 +3,27 @@ using System.Collections.Generic; using System.IO; using System.IO.Compression; -namespace IOL.Helpers +namespace IOL.Helpers; + +public static class InMemoryZipArchive { - public static class InMemoryZipArchive - { - public static byte[] Create(IEnumerable<InMemoryFile> files, string unixPermissionString = "664") { - using var archiveStream = new MemoryStream(); - using (var archive = new ZipArchive(archiveStream, ZipArchiveMode.Create, true)) { - foreach (var file in files) { - var zipArchiveEntry = archive.CreateEntry(file.FileName, CompressionLevel.Fastest); - zipArchiveEntry.ExternalAttributes |= Convert.ToInt32(unixPermissionString, 8) << 16; - using var zipStream = zipArchiveEntry.Open(); - zipStream.Write(file.Content, 0, file.Content.Length); - } + public static byte[] Create(IEnumerable<InMemoryFile> files, string unixPermissionString = "664") { + using var archiveStream = new MemoryStream(); + using (var archive = new ZipArchive(archiveStream, ZipArchiveMode.Create, true)) { + foreach (var file in files) { + var zipArchiveEntry = archive.CreateEntry(file.FileName, CompressionLevel.Fastest); + zipArchiveEntry.ExternalAttributes |= Convert.ToInt32(unixPermissionString, 8) << 16; + using var zipStream = zipArchiveEntry.Open(); + zipStream.Write(file.Content, 0, file.Content.Length); } - - return archiveStream.ToArray(); } - public class InMemoryFile - { - public string FileName { get; set; } - public byte[] Content { get; set; } - } + return archiveStream.ToArray(); + } + + public class InMemoryFile + { + public string FileName { get; set; } + public byte[] Content { get; set; } } } diff --git a/src/IOL.Helpers/PasswordHelpers.cs b/src/IOL.Helpers/PasswordHelpers.cs index 5b85219..ebebeb9 100644 --- a/src/IOL.Helpers/PasswordHelpers.cs +++ b/src/IOL.Helpers/PasswordHelpers.cs @@ -3,68 +3,67 @@ using System.Collections.Generic; using System.Security.Cryptography; using Microsoft.AspNetCore.Cryptography.KeyDerivation; -namespace IOL.Helpers +namespace IOL.Helpers; + +public static class PasswordHelper { - public static class PasswordHelper - { - private const int ITERATION_COUNT = 10000; - private const int SALT_SIZE = 128 / 8; - private const KeyDerivationPrf PRF = KeyDerivationPrf.HMACSHA256; + private const int ITERATION_COUNT = 10000; + private const int SALT_SIZE = 128 / 8; + private const KeyDerivationPrf PRF = KeyDerivationPrf.HMACSHA256; - public static string HashPassword(string value) { - using var rng = RandomNumberGenerator.Create(); - var salt = new byte[SALT_SIZE]; - rng.GetBytes(salt); - var subkey = KeyDerivation.Pbkdf2(value, salt, PRF, ITERATION_COUNT, 256 / 8); - var outputBytes = new byte[13 + salt.Length + subkey.Length]; - WriteNetworkByteOrder(outputBytes, 1, (uint) PRF); - WriteNetworkByteOrder(outputBytes, 5, (uint) ITERATION_COUNT); - WriteNetworkByteOrder(outputBytes, 9, (uint) SALT_SIZE); - Buffer.BlockCopy(salt, 0, outputBytes, 13, salt.Length); - Buffer.BlockCopy(subkey, 0, outputBytes, 13 + SALT_SIZE, subkey.Length); - return Convert.ToBase64String(outputBytes); - } + public static string HashPassword(string value) { + using var rng = RandomNumberGenerator.Create(); + var salt = new byte[SALT_SIZE]; + rng.GetBytes(salt); + var subkey = KeyDerivation.Pbkdf2(value, salt, PRF, ITERATION_COUNT, 256 / 8); + var outputBytes = new byte[13 + salt.Length + subkey.Length]; + WriteNetworkByteOrder(outputBytes, 1, (uint)PRF); + WriteNetworkByteOrder(outputBytes, 5, ITERATION_COUNT); + WriteNetworkByteOrder(outputBytes, 9, SALT_SIZE); + Buffer.BlockCopy(salt, 0, outputBytes, 13, salt.Length); + Buffer.BlockCopy(subkey, 0, outputBytes, 13 + SALT_SIZE, subkey.Length); + return Convert.ToBase64String(outputBytes); + } - public static bool Verify(string password, string hashedPassword) { - var decodedHashedPassword = Convert.FromBase64String(hashedPassword); - if (decodedHashedPassword.Length == 0) return false; - try { - // Read header information - var networkByteOrder = (KeyDerivationPrf) ReadNetworkByteOrder(decodedHashedPassword, 1); - var saltLength = (int) ReadNetworkByteOrder(decodedHashedPassword, 9); + public static bool Verify(string password, string hashedPassword) { + var decodedHashedPassword = Convert.FromBase64String(hashedPassword); + if (decodedHashedPassword.Length == 0) return false; + try { + // Read header information + var networkByteOrder = (KeyDerivationPrf)ReadNetworkByteOrder(decodedHashedPassword, 1); + var saltLength = (int)ReadNetworkByteOrder(decodedHashedPassword, 9); - // Read the salt: must be >= 128 bits - if (saltLength < SALT_SIZE) return false; - var salt = new byte[saltLength]; - Buffer.BlockCopy(decodedHashedPassword, 13, salt, 0, salt.Length); + // Read the salt: must be >= 128 bits + if (saltLength < SALT_SIZE) return false; + var salt = new byte[saltLength]; + Buffer.BlockCopy(decodedHashedPassword, 13, salt, 0, salt.Length); - // Read the subkey (the rest of the payload): must be >= 128 bits - var subkeyLength = decodedHashedPassword.Length - 13 - salt.Length; - if (subkeyLength < SALT_SIZE) return false; - var expectedSubkey = new byte[subkeyLength]; - Buffer.BlockCopy(decodedHashedPassword, 13 + salt.Length, expectedSubkey, 0, expectedSubkey.Length); + // Read the subkey (the rest of the payload): must be >= 128 bits + var subkeyLength = decodedHashedPassword.Length - 13 - salt.Length; + if (subkeyLength < SALT_SIZE) return false; + var expectedSubkey = new byte[subkeyLength]; + Buffer.BlockCopy(decodedHashedPassword, 13 + salt.Length, expectedSubkey, 0, expectedSubkey.Length); - // Hash the incoming password and verify it - var actualSubkey = + // Hash the incoming password and verify it + var actualSubkey = KeyDerivation.Pbkdf2(password, salt, networkByteOrder, ITERATION_COUNT, subkeyLength); - return CryptographicOperations.FixedTimeEquals(actualSubkey, expectedSubkey); - } catch { - return false; - } + return CryptographicOperations.FixedTimeEquals(actualSubkey, expectedSubkey); + } catch { + return false; } + } - private static uint ReadNetworkByteOrder(IReadOnlyList<byte> buffer, int offset) { - return ((uint) buffer[offset + 0] << 24) - | ((uint) buffer[offset + 1] << 16) - | ((uint) buffer[offset + 2] << 8) - | buffer[offset + 3]; - } + private static uint ReadNetworkByteOrder(IReadOnlyList<byte> buffer, int offset) { + return ((uint)buffer[offset + 0] << 24) + | ((uint)buffer[offset + 1] << 16) + | ((uint)buffer[offset + 2] << 8) + | buffer[offset + 3]; + } - private static void WriteNetworkByteOrder(IList<byte> buffer, int offset, uint value) { - buffer[offset + 0] = (byte) (value >> 24); - buffer[offset + 1] = (byte) (value >> 16); - buffer[offset + 2] = (byte) (value >> 8); - buffer[offset + 3] = (byte) (value >> 0); - } + private static void WriteNetworkByteOrder(IList<byte> buffer, int offset, uint value) { + buffer[offset + 0] = (byte)(value >> 24); + buffer[offset + 1] = (byte)(value >> 16); + buffer[offset + 2] = (byte)(value >> 8); + buffer[offset + 3] = (byte)(value >> 0); } -}
\ No newline at end of file +} diff --git a/src/IOL.Helpers/QueryableHelpers.cs b/src/IOL.Helpers/QueryableHelpers.cs new file mode 100644 index 0000000..00f422b --- /dev/null +++ b/src/IOL.Helpers/QueryableHelpers.cs @@ -0,0 +1,24 @@ +using System; +using System.Linq; +using System.Linq.Expressions; + +namespace IOL.Helpers; + +public static class QueryableHelpers +{ + public static IQueryable<T> ConditionalWhere<T>( + this IQueryable<T> source, + Func<bool> condition, + Expression<Func<T, bool>> predicate + ) { + return condition() ? source.Where(predicate) : source; + } + + public static IQueryable<T> ConditionalWhere<T>( + this IQueryable<T> source, + bool condition, + Expression<Func<T, bool>> predicate + ) { + return condition ? source.Where(predicate) : source; + } +} diff --git a/src/IOL.Helpers/RandomStringGenerator.cs b/src/IOL.Helpers/RandomStringGenerator.cs index 0d691db..2f39d67 100644 --- a/src/IOL.Helpers/RandomStringGenerator.cs +++ b/src/IOL.Helpers/RandomStringGenerator.cs @@ -1,18 +1,17 @@ using System; using System.Linq; -namespace IOL.Helpers +namespace IOL.Helpers; + +public static class RandomString { - public static class RandomString - { - private static readonly Random _random = new Random(); + private static readonly Random _random = new(); - public static string Generate(int length, bool numeric = false) { - var chars = numeric switch { + public static string Generate(int length, bool numeric = false) { + var chars = numeric switch { false => "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", true => "0123456789" - }; - return new string(Enumerable.Repeat(chars, length).Select(s => s[_random.Next(s.Length)]).ToArray()); - } + }; + return new string(Enumerable.Repeat(chars, length).Select(s => s[_random.Next(s.Length)]).ToArray()); } -}
\ No newline at end of file +} diff --git a/src/IOL.Helpers/SlugGenerator.cs b/src/IOL.Helpers/SlugGenerator.cs index 3f53dd6..6e669c0 100644 --- a/src/IOL.Helpers/SlugGenerator.cs +++ b/src/IOL.Helpers/SlugGenerator.cs @@ -1,98 +1,98 @@ using System.Text; -namespace IOL.Helpers -{ - public static class Slug - { - public static string Generate(bool toLower, params string[] values) { - return Create(string.Join("-", values), toLower); - } +namespace IOL.Helpers; - /// <summary> - /// Creates a slug. - /// References: - /// http://www.unicode.org/reports/tr15/tr15-34.html - /// https://meta.stackexchange.com/questions/7435/non-us-ascii-characters-dropped-from-full-profile-url/7696#7696 - /// https://stackoverflow.com/questions/25259/how-do-you-include-a-webpage-title-as-part-of-a-webpage-url/25486#25486 - /// https://stackoverflow.com/questions/3769457/how-can-i-remove-accents-on-a-string - /// </summary> - /// <param name="value"></param> - /// <param name="toLower"></param> - /// <returns>Slugified string</returns> - public static string Create(string value, bool toLower) { - if (string.IsNullOrWhiteSpace(value)) - return value; +public static class Slug +{ + public static string Generate(bool toLower, params string[] values) { + return Create(string.Join("-", values), toLower); + } - var normalised = value.Normalize(NormalizationForm.FormKD); + /// <summary> + /// Creates a slug. + /// References: + /// http://www.unicode.org/reports/tr15/tr15-34.html + /// https://meta.stackexchange.com/questions/7435/non-us-ascii-characters-dropped-from-full-profile-url/7696#7696 + /// https://stackoverflow.com/questions/25259/how-do-you-include-a-webpage-title-as-part-of-a-webpage-url/25486#25486 + /// https://stackoverflow.com/questions/3769457/how-can-i-remove-accents-on-a-string + /// </summary> + /// <param name="value"></param> + /// <param name="toLower"></param> + /// <returns>Slugified string</returns> + public static string Create(string value, bool toLower) { + if (string.IsNullOrWhiteSpace(value)) + return value; - const int MAXLEN = 80; - var len = normalised.Length; - var prevDash = false; - var sb = new StringBuilder(len); + var normalised = value.Normalize(NormalizationForm.FormKD); - for (var i = 0; i < len; i++) { - var c = normalised[i]; - switch (c) { - case >= 'a' and <= 'z': - case >= '0' and <= '9': { - if (prevDash) { - sb.Append('-'); - prevDash = false; - } + const int MAXLEN = 80; + var len = normalised.Length; + var prevDash = false; + var sb = new StringBuilder(len); - sb.Append(c); - break; + for (var i = 0; i < len; i++) { + var c = normalised[i]; + switch (c) { + case >= 'a' and <= 'z': + case >= '0' and <= '9': { + if (prevDash) { + sb.Append('-'); + prevDash = false; } - case >= 'A' and <= 'Z': { - if (prevDash) { - sb.Append('-'); - prevDash = false; - } - // Tricky way to convert to lowercase - if (toLower) - sb.Append((char) (c | 32)); - else - sb.Append(c); - break; + sb.Append(c); + break; + } + case >= 'A' and <= 'Z': { + if (prevDash) { + sb.Append('-'); + prevDash = false; } - case ' ': - case ',': - case '.': - case '/': - case '\\': - case '-': - case '_': - case '=': { - if (!prevDash && sb.Length > 0) { - prevDash = true; - } - break; + // Tricky way to convert to lowercase + if (toLower) + sb.Append((char)(c | 32)); + else + sb.Append(c); + break; + } + case ' ': + case ',': + case '.': + case '/': + case '\\': + case '-': + case '_': + case '=': { + if (!prevDash && sb.Length > 0) { + prevDash = true; } - default: { - var swap = ConvertEdgeCases(c, toLower); - if (swap != null) { - if (prevDash) { - sb.Append('-'); - prevDash = false; - } - sb.Append(swap); + break; + } + default: { + var swap = ConvertEdgeCases(c, toLower); + if (swap != null) { + if (prevDash) { + sb.Append('-'); + prevDash = false; } - break; + sb.Append(swap); } - } - if (sb.Length == MAXLEN) break; + } } - return sb.ToString(); + if (sb.Length == MAXLEN) + break; } - private static string ConvertEdgeCases(char c, bool toLower) => c switch { + return sb.ToString(); + } + + private static string ConvertEdgeCases(char c, bool toLower) => c switch { 'ı' => "i", 'ł' => "l", 'Ł' => toLower ? "l" : "L", @@ -103,6 +103,5 @@ namespace IOL.Helpers 'æ' => "ae", 'Þ' => "th", _ => null - }; - } -}
\ No newline at end of file + }; +} diff --git a/src/IOL.Helpers/StringHelpers.cs b/src/IOL.Helpers/StringHelpers.cs index 6589df6..783d238 100644 --- a/src/IOL.Helpers/StringHelpers.cs +++ b/src/IOL.Helpers/StringHelpers.cs @@ -5,84 +5,83 @@ using System.Text; using System.Text.RegularExpressions; using Microsoft.Extensions.Configuration; -namespace IOL.Helpers -{ - public static class StringHelpers - { - public static bool IsNullOrWhiteSpace(this string value) { - return string.IsNullOrWhiteSpace(value); - } +namespace IOL.Helpers; - public static string Slugified(this string input) { - return Slug.Generate(true, input); - } +public static class StringHelpers +{ + public static bool IsNullOrWhiteSpace(this string value) { + return string.IsNullOrWhiteSpace(value); + } - public static bool HasValue(this string value) { - return !value.IsNullOrWhiteSpace(); - } + public static string Slugified(this string input) { + return Slug.Generate(true, input); + } - public static string UnicornFormat(this string input, IDictionary<string, string> values) { - if (string.IsNullOrWhiteSpace(input)) return default; - return values.Count == 0 ? default : values.Aggregate(input, (current, value1) => current.Replace("{" + value1.Key + "}", value1.Value)); - } + public static bool HasValue(this string value) { + return !value.IsNullOrWhiteSpace(); + } + public static string UnicornFormat(this string input, IDictionary<string, string> values) { + if (string.IsNullOrWhiteSpace(input)) return default; + return values.Count == 0 ? default : values.Aggregate(input, (current, value1) => current.Replace("{" + value1.Key + "}", value1.Value)); + } - public static string UnicornFormatWithEnvironment(this string input, IConfiguration configuration) { - if (string.IsNullOrWhiteSpace(input)) return default; - var matchList = Regex.Matches(input, "{[a-z|_]*}", RegexOptions.IgnoreCase); - foreach (var key in matchList.Select(match => match.Value)) { - var value = configuration.GetValue<string>(key.Substring(1, key.Length - 2)); - if (string.IsNullOrWhiteSpace(value)) continue; - input = input.Replace(key, value); - } - return input; + public static string UnicornFormatWithEnvironment(this string input, IConfiguration configuration) { + if (string.IsNullOrWhiteSpace(input)) return default; + var matchList = Regex.Matches(input, "{[a-z|_]*}", RegexOptions.IgnoreCase); + foreach (var key in matchList.Select(match => match.Value)) { + var value = configuration.GetValue<string>(key.Substring(1, key.Length - 2)); + if (string.IsNullOrWhiteSpace(value)) continue; + input = input.Replace(key, value); } - public static Guid ToGuid(this string value) { - return !Guid.TryParse(value, out var res) ? default : res; - } + return input; + } - public static string Base64Encode(this string text) { - return Convert.ToBase64String(Encoding.UTF8.GetBytes(text)); - } + public static Guid ToGuid(this string value) { + return !Guid.TryParse(value, out var res) ? default : res; + } - public static string ExtractFileName(this string value) { - if (value.IsNullOrWhiteSpace()) return default; - var lastIndex = value.LastIndexOf('.'); - return lastIndex <= 0 ? default : value[..lastIndex]; - } + public static string Base64Encode(this string text) { + return Convert.ToBase64String(Encoding.UTF8.GetBytes(text)); + } - public static string ExtractExtension(this string value) { - if (value.IsNullOrWhiteSpace()) return default; - var lastIndex = value.LastIndexOf('.'); - return lastIndex <= 0 ? default : value.Substring(lastIndex); - } + public static string ExtractFileName(this string value) { + if (value.IsNullOrWhiteSpace()) return default; + var lastIndex = value.LastIndexOf('.'); + return lastIndex <= 0 ? default : value[..lastIndex]; + } - public static string Capitalize(this string input) { - return input.IsNullOrWhiteSpace() - ? input - : Regex.Replace(input, @"\b(\w)", m => m.Value.ToUpper(), RegexOptions.None); - } + public static string ExtractExtension(this string value) { + if (value.IsNullOrWhiteSpace()) return default; + var lastIndex = value.LastIndexOf('.'); + return lastIndex <= 0 ? default : value.Substring(lastIndex); + } + public static string Capitalize(this string input) { + return input.IsNullOrWhiteSpace() + ? input + : Regex.Replace(input, @"\b(\w)", m => m.Value.ToUpper(), RegexOptions.None); + } - /// <summary> - /// Check if the given MIME is a JSON MIME. - /// </summary> - /// <param name="mime">MIME</param> - /// <returns>Returns true if MIME type is json.</returns> - public static bool IsJsonMime(this string mime) { - var jsonRegex = new Regex("(?i)^(application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(;.*)?$"); - return mime != null && (jsonRegex.IsMatch(mime) || mime.Equals("application/json-patch+json")); - } - public static string Obfuscate(this string value) { - var last4Chars = "****"; - if (value.HasValue() && value.Length > 4) { - last4Chars = value.Substring(value.Length - 4); - } + /// <summary> + /// Check if the given MIME is a JSON MIME. + /// </summary> + /// <param name="mime">MIME</param> + /// <returns>Returns true if MIME type is json.</returns> + public static bool IsJsonMime(this string mime) { + var jsonRegex = new Regex("(?i)^(application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(;.*)?$"); + return mime != null && (jsonRegex.IsMatch(mime) || mime.Equals("application/json-patch+json")); + } - return "****" + last4Chars; + public static string Obfuscate(this string value) { + var last4Chars = "****"; + if (value.HasValue() && value.Length > 4) { + last4Chars = value.Substring(value.Length - 4); } + + return "****" + last4Chars; } } diff --git a/src/IOL.Helpers/Validators.cs b/src/IOL.Helpers/Validators.cs index d60afcf..a6937d6 100644 --- a/src/IOL.Helpers/Validators.cs +++ b/src/IOL.Helpers/Validators.cs @@ -1,18 +1,17 @@ using System.Net.Mail; using System.Text.RegularExpressions; -namespace IOL.Helpers +namespace IOL.Helpers; + +public static class Validators { - public static class Validators - { - private static readonly Regex _norwegianPhoneNumber = new(@"^(0047|\+47|47)?[2-9]\d{7}$"); + private static readonly Regex _norwegianPhoneNumber = new(@"^(0047|\+47|47)?[2-9]\d{7}$"); - public static bool IsValidEmailAddress(this string value) { - return MailAddress.TryCreate(value, out _); - } + public static bool IsValidEmailAddress(this string value) { + return MailAddress.TryCreate(value, out _); + } - public static bool IsValidNorwegianPhoneNumber(this string value) { - return _norwegianPhoneNumber.IsMatch(value); - } + public static bool IsValidNorwegianPhoneNumber(this string value) { + return _norwegianPhoneNumber.IsMatch(value); } -}
\ No newline at end of file +} |
