diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/IOL.Helpers.Tests/IOL.Helpers.Tests.csproj | 27 | ||||
| -rw-r--r-- | src/IOL.Helpers.Tests/StringHelpersTests.cs | 76 | ||||
| -rw-r--r-- | src/IOL.Helpers.sln | 14 | ||||
| -rw-r--r-- | src/IOL.Helpers/CryptographyHelpers.cs | 160 | ||||
| -rw-r--r-- | src/IOL.Helpers/SlugGenerator.cs | 5 | ||||
| -rw-r--r-- | src/IOL.Helpers/StringHelpers.cs | 148 |
6 files changed, 301 insertions, 129 deletions
diff --git a/src/IOL.Helpers.Tests/IOL.Helpers.Tests.csproj b/src/IOL.Helpers.Tests/IOL.Helpers.Tests.csproj new file mode 100644 index 0000000..aeb661a --- /dev/null +++ b/src/IOL.Helpers.Tests/IOL.Helpers.Tests.csproj @@ -0,0 +1,27 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <TargetFramework>net6.0</TargetFramework> + <Nullable>enable</Nullable> + + <IsPackable>false</IsPackable> + </PropertyGroup> + + <ItemGroup> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" /> + <PackageReference Include="xunit" Version="2.4.1" /> + <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3"> + <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> + <PrivateAssets>all</PrivateAssets> + </PackageReference> + <PackageReference Include="coverlet.collector" Version="3.1.0"> + <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> + <PrivateAssets>all</PrivateAssets> + </PackageReference> + </ItemGroup> + + <ItemGroup> + <ProjectReference Include="..\IOL.Helpers\IOL.Helpers.csproj" /> + </ItemGroup> + +</Project> diff --git a/src/IOL.Helpers.Tests/StringHelpersTests.cs b/src/IOL.Helpers.Tests/StringHelpersTests.cs new file mode 100644 index 0000000..210a3ee --- /dev/null +++ b/src/IOL.Helpers.Tests/StringHelpersTests.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using Xunit; + +namespace IOL.Helpers.Tests; + +public class StringHelpersTests +{ + [Fact] + public void Base64_Encode_Decode_Behaves() { + const string input = "value"; + var encoded = input.AsBase64EncodedString(); + Assert.Equal(input, encoded.AsBase64DecodedString()); + } + + [Fact] + public void Unicorn_Format_Behaves() { + const string input = "Hello, {name}"; + var result = input.UnicornFormat(new Dictionary<string, string> { + { + "name", "World" + } + }); + Assert.Equal("Hello, World", result); + } + + [Fact] + public void IsNullOrWhiteSpace_Behaves() { + const string stringWithValue = "value"; + const string emptyString = ""; + const string onlyWhitespace = " "; + Assert.False(stringWithValue.IsNullOrWhiteSpace()); + Assert.True(emptyString.IsNullOrWhiteSpace()); + Assert.True(onlyWhitespace.IsNullOrWhiteSpace()); + } + + [Fact] + public void AsSnakeCasedString_Behaves() { + Assert.Equal("snake_case", "SNAKE Case ".AsSnakeCasedString()); + } + + [Fact] + public void AsSlug_Behaves() { + Assert.Equal("tromso-at-night", "Tromsø @ night".AsSlug()); + } + + [Fact] + public void HasValue_Behaves() { + Assert.True("asdf".HasValue()); + Assert.False(" ".HasValue()); + } + + [Fact] + public void AsGuid_Behaves() { + Assert.Equal(new Guid("bb7e2fd8-2ded-4fe9-a770-efeba661539c"), "bb7e2fd8-2ded-4fe9-a770-efeba661539c".AsGuid()); + Assert.Throws<FormatException>(() => "not-a-guid".AsGuid()); + } + + [Fact] + public void AsGuidOrDefault_Behaves() { + Assert.Equal(new Guid("bb7e2fd8-2ded-4fe9-a770-efeba661539c"), "bb7e2fd8-2ded-4fe9-a770-efeba661539c".AsGuid()); + Assert.Equal(default(Guid), "not-a-guid".AsGuidOrDefault()); + } + + [Fact] + public void Capitalize_Behaves() { + Assert.Equal("The File", "the file".Capitalize()); + Assert.Equal("The file", "the file".Capitalize(true)); + } + + [Fact] + public void Obfuscate_Behaves() { + Assert.Equal("********", "asdf".Obfuscate()); + Assert.Equal("****1234", "asdfasdf1234".Obfuscate()); + } +} diff --git a/src/IOL.Helpers.sln b/src/IOL.Helpers.sln index b166d6e..6f0640d 100644 --- a/src/IOL.Helpers.sln +++ b/src/IOL.Helpers.sln @@ -5,6 +5,8 @@ VisualStudioVersion = 16.6.30114.105 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IOL.Helpers", "IOL.Helpers\IOL.Helpers.csproj", "{DE4D43B0-FBE6-40B7-9C8F-FFFA7987F87B}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IOL.Helpers.Tests", "IOL.Helpers.Tests\IOL.Helpers.Tests.csproj", "{434C1F70-2092-4403-AD90-530DEC82D2CE}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -30,5 +32,17 @@ Global {DE4D43B0-FBE6-40B7-9C8F-FFFA7987F87B}.Release|x64.Build.0 = Release|Any CPU {DE4D43B0-FBE6-40B7-9C8F-FFFA7987F87B}.Release|x86.ActiveCfg = Release|Any CPU {DE4D43B0-FBE6-40B7-9C8F-FFFA7987F87B}.Release|x86.Build.0 = Release|Any CPU + {434C1F70-2092-4403-AD90-530DEC82D2CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {434C1F70-2092-4403-AD90-530DEC82D2CE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {434C1F70-2092-4403-AD90-530DEC82D2CE}.Debug|x64.ActiveCfg = Debug|Any CPU + {434C1F70-2092-4403-AD90-530DEC82D2CE}.Debug|x64.Build.0 = Debug|Any CPU + {434C1F70-2092-4403-AD90-530DEC82D2CE}.Debug|x86.ActiveCfg = Debug|Any CPU + {434C1F70-2092-4403-AD90-530DEC82D2CE}.Debug|x86.Build.0 = Debug|Any CPU + {434C1F70-2092-4403-AD90-530DEC82D2CE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {434C1F70-2092-4403-AD90-530DEC82D2CE}.Release|Any CPU.Build.0 = Release|Any CPU + {434C1F70-2092-4403-AD90-530DEC82D2CE}.Release|x64.ActiveCfg = Release|Any CPU + {434C1F70-2092-4403-AD90-530DEC82D2CE}.Release|x64.Build.0 = Release|Any CPU + {434C1F70-2092-4403-AD90-530DEC82D2CE}.Release|x86.ActiveCfg = Release|Any CPU + {434C1F70-2092-4403-AD90-530DEC82D2CE}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/src/IOL.Helpers/CryptographyHelpers.cs b/src/IOL.Helpers/CryptographyHelpers.cs index df53055..237116b 100644 --- a/src/IOL.Helpers/CryptographyHelpers.cs +++ b/src/IOL.Helpers/CryptographyHelpers.cs @@ -7,8 +7,6 @@ namespace IOL.Helpers; public static class CryptographyHelpers { - // 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(); @@ -16,15 +14,25 @@ public static class CryptographyHelpers /// 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; + public static byte[] AsMD5Hash(this string input, string salt = default) { + if (input.IsNullOrWhiteSpace()) { + return default; + } var hmacMd5 = salt.HasValue() ? new HMACMD5(Encoding.UTF8.GetBytes(salt ?? "")) : new HMACMD5(); - var saltedHash = hmacMd5.ComputeHash(Encoding.UTF8.GetBytes(input)); - return Convert.ToBase64String(saltedHash); + return hmacMd5.ComputeHash(Encoding.UTF8.GetBytes(input)); } + public static byte[] AsMD5Hash(this byte[] input, string salt = default) { + if (input == null) { + return default; + } + + var hmacMd5 = salt.HasValue() ? new HMACMD5(Encoding.UTF8.GetBytes(salt ?? "")) : new HMACMD5(); + return hmacMd5.ComputeHash(input); + } + // https://stackoverflow.com/a/13026595/253938 /// <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. @@ -32,16 +40,17 @@ public static class CryptographyHelpers /// 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="input">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) { + public static string CaesarCipher(this string input, int shiftOrUnshift) { + if (input.IsNullOrWhiteSpace()) { + return default; + } + const int C64_K = ushort.MaxValue + 1; - if (inputString == null) throw new ArgumentException("Must not be null.", nameof(inputString)); + if (input == null) throw new ArgumentException("Must not be null.", nameof(input)); switch (shiftOrUnshift) { case 0: throw new ArgumentException("Must not be zero.", nameof(shiftOrUnshift)); case <= -C64_K: @@ -49,26 +58,43 @@ public static class CryptographyHelpers } // 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); + var charArray = new char[input.Length]; + for (var i = 0; i < input.Length; i++) { + charArray[i] = Convert.ToChar((Convert.ToInt32(input[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); + /// <summary> + /// Encrypts a string input with aes encryption + /// </summary> + /// <param name="input">The string to encrypt</param> + /// <param name="encryptionKey">The key to encrypt the input with</param> + /// <returns>A base 64 encoded string of the encrypted input</returns> + /// <exception cref="ArgumentNullException">Throws null if encryptionKey is empty or null</exception> + public static string EncryptWithAes(this string input, string encryptionKey) { + if (input.IsNullOrWhiteSpace()) { + return default; + } + + if (encryptionKey.IsNullOrWhiteSpace()) { + throw new ArgumentNullException(nameof(encryptionKey)); + } + + var key = encryptionKey.AsMD5Hash(); + + using var aes = Aes.Create(); + aes.Mode = CipherMode.CBC; + aes.Padding = PaddingMode.PKCS7; - using var aes = CreateAes(); - var iv = GenerateRandomBytes(AES_BLOCK_BYTE_SIZE); - var plainText = Encoding.UTF8.GetBytes(toEncrypt); + var iv = new byte[AES_BLOCK_BYTE_SIZE]; + _random.GetBytes(iv); + var plainText = Encoding.UTF8.GetBytes(input); using var encryptor = aes.CreateEncryptor(key, iv); - var cipherText = encryptor - .TransformFinalBlock(plainText, 0, plainText.Length); + var cipherText = encryptor.TransformFinalBlock(plainText, 0, plainText.Length); var result = new byte[iv.Length + cipherText.Length]; iv.CopyTo(result, 0); @@ -77,65 +103,54 @@ public static class CryptographyHelpers return Convert.ToBase64String(result); } - private static Aes CreateAes() { - var aes = Aes.Create(); - aes.Mode = CipherMode.CBC; - aes.Padding = PaddingMode.PKCS7; - return aes; - } + /// <summary> + /// Decrypts a string input with aes encryption + /// </summary> + /// <param name="input">The base 64 encoded string to decrypt</param> + /// <param name="encryptionKey">The key to decrypt the input with</param> + /// <returns>A string of the decrypted input</returns> + /// <exception cref="ArgumentNullException">Throws null if encryptionKey is empty or null</exception> + public static string DecryptWithAes(this string input, string encryptionKey) { + if (input.IsNullOrWhiteSpace()) { + return default; + } - public static string DecryptWithAes(this string input, string password) { - var key = GetKey(password); - var encryptedData = Convert.FromBase64String(input); + if (encryptionKey.IsNullOrWhiteSpace()) { + throw new ArgumentNullException(nameof(encryptionKey)); + } - using var aes = CreateAes(); + var key = encryptionKey.AsMD5Hash(); + var encryptedData = Convert.FromBase64String(input); + using var aes = Aes.Create(); + aes.Mode = CipherMode.CBC; + aes.Padding = PaddingMode.PKCS7; 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 - .TransformFinalBlock(cipherText, 0, cipherText.Length); + 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); - } - - 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; - + /// <param name="input">The input</param> + /// <returns>A base 64 encoded hash string of the input</returns> + public static string AsSHA256Hash(this string input) { + if (input.IsNullOrWhiteSpace()) return default; using var sha = SHA256.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[] Sha256(this byte[] input) { - if (input == null) { - return null; - } - + /// <param name="input">The input</param> + /// <returns>A byte array containing the hash of the input</returns> + public static byte[] AsSHA256Hash(this byte[] input) { + if (input == null) return default; using var sha = SHA256.Create(); return sha.ComputeHash(input); } @@ -143,28 +158,23 @@ public static class CryptographyHelpers /// <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; - + /// <param name="input">The input</param> + /// <returns>A base 64 encoded hash string of the input</returns> + public static string AsSHA512(this string input) { + if (input.IsNullOrWhiteSpace()) return default; 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; - } - + /// <param name="input">The input</param> + /// <returns>A byte array containing the hash of the input</returns> + public static byte[] AsSHA512(this byte[] input) { + if (input == null) return default; using var sha = SHA512.Create(); return sha.ComputeHash(input); } diff --git a/src/IOL.Helpers/SlugGenerator.cs b/src/IOL.Helpers/SlugGenerator.cs index 6e669c0..9032303 100644 --- a/src/IOL.Helpers/SlugGenerator.cs +++ b/src/IOL.Helpers/SlugGenerator.cs @@ -18,8 +18,8 @@ public static class Slug /// </summary> /// <param name="value"></param> /// <param name="toLower"></param> - /// <returns>Slugified string</returns> - public static string Create(string value, bool toLower) { + /// <returns>AsSlug string</returns> + private static string Create(string value, bool toLower) { if (string.IsNullOrWhiteSpace(value)) return value; @@ -102,6 +102,7 @@ public static class Slug 'å' => "aa", 'æ' => "ae", 'Þ' => "th", + '@' => "at", _ => null }; } diff --git a/src/IOL.Helpers/StringHelpers.cs b/src/IOL.Helpers/StringHelpers.cs index 366ca00..20def44 100644 --- a/src/IOL.Helpers/StringHelpers.cs +++ b/src/IOL.Helpers/StringHelpers.cs @@ -1,92 +1,136 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; 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); + /// <summary> + /// Check wheter or not the given string has a value + /// </summary> + /// <param name="input"></param> + /// <returns>False if the input string is null or only whitespace, otherwise it returns true</returns> + public static bool IsNullOrWhiteSpace(this string input) { + return string.IsNullOrWhiteSpace(input); } - public static string Slugified(this string input) { - return Slug.Generate(true, input); + /// <summary> + /// Convert a string to snake_casing + /// </summary> + /// <param name="input">The input string to convert</param> + /// <returns>A snake cased string representation of the input string</returns> + public static string AsSnakeCasedString(this string input) { + if (input.IsNullOrWhiteSpace()) return default; + input = input.ToLower().Trim(); + return input.Replace(" ", "_"); } - public static string ToSnakeCase(this string str) { - return string.Concat(str.Select((x, i) => i > 0 && char.IsUpper(x) ? "_" + x : x.ToString())).ToLower(); + /// <summary> + /// Creatas a url safe string (slug) of the input + /// </summary> + /// <param name="input">The string to convert into a slug</param> + /// <returns>A string (slug) representation of the input</returns> + public static string AsSlug(this string input) { + return Slug.Generate(true, input); } - public static bool HasValue(this string value) { - return !value.IsNullOrWhiteSpace(); + /// <summary> + /// Check wheter or not the given string has a value + /// </summary> + /// <param name="input"></param> + /// <returns>False if the input string is null or only whitespace, otherwise it returns true</returns> + public static bool HasValue(this string input) { + return !input.IsNullOrWhiteSpace(); } + /// <summary> + /// Performs a unicorn format on the input. + /// </summary> + /// <example> + /// const string input = "Hello, {name}"; + /// var result = input.UnicornFormat(new Dictionary<string, string> { + /// { + /// "name", "World" + /// } + /// }); + /// // result -> "Hello, World" + /// </example> + /// <param name="input"></param> + /// <param name="values"></param> + /// <returns></returns> 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)); + if (values.Count == 0) return input; + return 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; + /// <summary> + /// Converts a string input to it's Guid representation, if the string does not conform to the guid specification a FormatException will be thrown + /// </summary> + /// <param name="value">The string to interpret as a guid</param> + /// <returns>The input string as a guid</returns> + public static Guid AsGuid(this string input) { + return new Guid(input); } - public static Guid ToGuid(this string value) { - return new Guid(value); + /// <summary> + /// Converts a string input to it's Guid representation, if the string does not conform to the guid specification, a default input will be returned + /// </summary> + /// <param name="value">The string to interpret as a guid</param> + /// <returns>The string as a guid or the default input for guids</returns> + public static Guid AsGuidOrDefault(this string input) { + return !Guid.TryParse(input, out var res) ? default : res; } - public static Guid ToGuidOrDefault(this string value) { - return !Guid.TryParse(value, out var res) ? default : res; + /// <summary> + /// Encodes a string input to it's base 64 equalient + /// </summary> + /// <param name="input">The input to encode</param> + /// <returns>The base 64 encoded string</returns> + public static string AsBase64EncodedString(this string input) { + return input.IsNullOrWhiteSpace() ? default : Convert.ToBase64String(Encoding.UTF8.GetBytes(input)); } - public static string Base64Encode(this string text) { - return Convert.ToBase64String(Encoding.UTF8.GetBytes(text)); + /// <summary> + /// Decodes a string input to it's original input + /// </summary> + /// <param name="input">The input to decode</param> + /// <returns>The decoded string input of the base 64 string</returns> + public static string AsBase64DecodedString(this string input) { + return input.IsNullOrWhiteSpace() ? default : Encoding.UTF8.GetString(Convert.FromBase64String(input)); } - public static string ExtractFileName(this string value) { - if (value.IsNullOrWhiteSpace()) return default; - var lastIndex = value.LastIndexOf('.'); - return lastIndex <= 0 ? default : value[..lastIndex]; - } + /// <summary> + /// Capitalize the input + /// </summary> + /// <param name="input">The string input to capitalize</param> + /// <returns></returns> + public static string Capitalize(this string input, bool onlyFirstChar = false) { + if (input.IsNullOrWhiteSpace()) return default; + input = input.Trim(); - public static string ExtractExtension(this string value) { - if (value.IsNullOrWhiteSpace()) return default; - var lastIndex = value.LastIndexOf('.'); - return lastIndex <= 0 ? default : value.Substring(lastIndex); - } + if (!onlyFirstChar) { + return Regex.Replace(input, @"\b(\w)", m => m.Value.ToUpper(), RegexOptions.None); + } - public static string Capitalize(this string input) { - return input.IsNullOrWhiteSpace() - ? input - : Regex.Replace(input, @"\b(\w)", m => m.Value.ToUpper(), RegexOptions.None); + input = char.ToUpper(input[0]) + input.Substring(1, input.Length - 1); + return input; } - /// <summary> - /// Check if the given MIME is a JSON MIME. + /// Obfucates the input string /// </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) { + /// <param name="input"></param> + /// <returns></returns> + public static string Obfuscate(this string input) { + if (input.IsNullOrWhiteSpace()) return default; var last4Chars = "****"; - if (value.HasValue() && value.Length > 4) { - last4Chars = value.Substring(value.Length - 4); + if (input.HasValue() && input.Length > 4) { + last4Chars = input[^4..]; } return "****" + last4Chars; |
