using LiteCharms.Features.Abstractions; namespace LiteCharms.Features.Hasher; public sealed partial class HashService(IHashids hasher) : IService { [GeneratedRegex(@"\A\b[0-9a-fA-F]+\b\Z", RegexOptions.None, matchTimeoutMilliseconds: 100)] private static partial Regex HexHashRegex { get; } [GeneratedRegex(@"\A[0-9a-fA-F]{32}\Z", RegexOptions.None, matchTimeoutMilliseconds: 100)] private static partial Regex Md5Regex { get; } [GeneratedRegex(@"\A[0-9a-fA-F]{64}\Z", RegexOptions.None, matchTimeoutMilliseconds: 100)] private static partial Regex Sha256Regex { get; } public static bool IsMd5Hash(string? value) => !string.IsNullOrWhiteSpace(value) && Md5Regex.IsMatch(value); public static bool IsSha256Hash(string? value) => !string.IsNullOrWhiteSpace(value) && Sha256Regex.IsMatch(value); public static string? StringToSha256Hash(string? input) => string.IsNullOrEmpty(input) ? null : Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(input))); public static string? StreamToSha256Hash(Stream stream) => stream is null ? null : Convert.ToHexString(SHA256.HashData(stream)); public static string? BytesToSha256Hash(byte[] bytes) => bytes is null ? null : Convert.ToHexString(SHA256.HashData(bytes)); public static Result ToMd5Hash(string input) { if (string.IsNullOrEmpty(input)) return Result.Fail("Input content cannot be null or empty for MD5 processing."); byte[] bytes = MD5.HashData(Encoding.UTF8.GetBytes(input)); return Result.Ok(Convert.ToHexString(bytes).ToLowerInvariant()); } public Result HashEncodeHex(string input) => string.IsNullOrWhiteSpace(input) || !HexHashRegex.IsMatch(input) ? Result.Fail("Input must be a valid hexadecimal string.") : Result.Ok(hasher.EncodeHex(input)); public Result HashEncodeIntId(int id) => id < 0 ? Result.Fail("Id cannot be negative.") : Result.Ok(hasher.Encode(id)); public Result HashEncodeLongId(long id) => id < 0 ? Result.Fail("Id cannot be negative.") : Result.Ok(hasher.EncodeLong(id)); public Result DecodeIntIdHash(string hash) { if (string.IsNullOrWhiteSpace(hash)) return Result.Fail("Invalid token layout."); int[] decoded = hasher.Decode(hash); return decoded.Length == 1 ? Result.Ok(decoded[0]) : Result.Fail("Invalid or modified Int hash token."); } public Result DecodeLongIdHash(string hash) { if (string.IsNullOrWhiteSpace(hash)) return Result.Fail("Invalid token layout."); long[] decoded = hasher.DecodeLong(hash); return decoded.Length == 1 ? Result.Ok(decoded[0]) : Result.Fail("Invalid or modified Long hash token."); } public Result DecodeHexHash(string hex) { try { string decoded = hasher.DecodeHex(hex); return string.IsNullOrEmpty(decoded) ? Result.Fail("Invalid or corrupted hex hash.") : Result.Ok(decoded); } catch (FormatException fex) { return Result.Fail(new Error("Invalid hash structure.").CausedBy(fex)); } catch (Exception ex) { return Result.Fail(new Error(ex.Message).CausedBy(ex)); } } }