Files
2026-06-26 10:29:23 +02:00

84 lines
4.0 KiB
C#

using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using adas_core.Domain.Models.GroupedObservations;
using MongoDB.Bson;
namespace adas_core.Domain.Utils;
/// <summary>
/// Provides a static container for cryptographic operations and utilities related to the Adas domain.
/// </summary>
public static class CryptoAdas
{
private static readonly Regex PassRegex = new("^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$");
/// <summary>
/// Computes the MD5 hash of the specified input string and returns it as an uppercase hexadecimal string.
/// The hash bytes are iterated in reverse order before being formatted.
/// </summary>
/// <param name="input">The string to hash. Its ASCII byte representation is used as the input to the MD5 algorithm.</param>
/// <returns>The MD5 hash of <paramref name="input"/> formatted as an uppercase hexadecimal string.</returns>
public static string CreateMd5(string input)
{
using var md5 = MD5.Create();
var inputBytes = Encoding.ASCII.GetBytes(input);
var hashBytes = md5.ComputeHash(inputBytes);
var sb = new StringBuilder();
for (var i = hashBytes.Length - 1; i >= 0; i--) sb.Append(hashBytes[i].ToString("X2"));
var res = sb.ToString();
return res;
}
/// <summary>
/// Creates a deterministic MD5 hash that uniquely identifies a grouped field configuration for a specific patient.
/// Falls back to a single-element list containing the group's name (or empty string) when the <see cref="GroupedField.Names"/> collection is null or empty.
/// </summary>
/// <param name="gF">The grouped field whose names, max, since, regularity, and results are included in the hash input.</param>
/// <param name="patientId">The identifier of the patient whose data is being hashed.</param>
/// <returns>An MD5 hash string representing the combined patient and grouped field data.</returns>
public static string CreateMd5GroupedObs(GroupedField gF, ObjectId patientId)
{
var names = CollectionsUtils.IfEmptyOrNull(gF.Names, [gF.Name ?? string.Empty]);
return CreateMd5(patientId +
string.Join("+", names.Select(c => c.ToString())) +
gF.Max +
gF.Since +
gF.Regularity +
string.Join("+", gF.Result.Select(c => c.ToString())));
}
/// <summary>
/// Creates a BCrypt hash from the provided input string, typically used for securely storing passwords.
/// </summary>
/// <param name="input">The plain text string to be hashed.</param>
/// <returns>A BCrypt hashed representation of the input string.</returns>
public static string CreateBCrypt(string input)
{
return BCrypt.Net.BCrypt.HashPassword(input);
}
/// <summary>
/// Verifies that the provided plain text password matches the stored BCrypt password hash.
/// </summary>
/// <param name="loginPass">The plain text password entered by the user during login.</param>
/// <param name="passwordHash">The stored BCrypt hash to compare the password against.</param>
/// <returns><c>true</c> if the password matches the hash; otherwise, <c>false</c>.</returns>
public static bool VerifyPassword(string loginPass, string passwordHash)
{
return BCrypt.Net.BCrypt.Verify(loginPass, passwordHash);
}
/// <summary>
/// Determines whether the specified password meets the strong password criteria defined by the password regex pattern.
/// </summary>
/// <param name="password">The password string to evaluate against the strong password requirements.</param>
/// <returns><c>true</c> if the password matches the strong password pattern; otherwise, <c>false</c>.</returns>
public static bool IsStrongPassword(string password)
{
return PassRegex.IsMatch(password);
}
}