using System.Security.Cryptography; using System.Text; namespace Phenix.Services; public class LoginService { private readonly Dictionary _users; private readonly string _sessionKey; private static readonly (string User, string Hash)[] OfficialUsers = [ ("marqueur", "34373780cc542a1eddb6a08488ec149323b94d66025421acd98ffc20eb5055a0:6f2fa05777d45a2da9db79b7fd11e3bc69eb1807642ccb53d41a0b9eb71a3311"), ("comite", "8649feff48a50f53448e59ce480db97b5549eef1d92c886c49b5a14ee22648e5:a0017b879c8834d2f34938e7a4fa3f4c7be8f70545b9bb22a28cf56ab2eb26d9"), ]; public LoginService(string sessionKey) { _users = OfficialUsers.ToDictionary(x => x.User, x => x.Hash); _sessionKey = sessionKey; } public bool ValidateCredentials(string username, string password) { if (!_users.TryGetValue(username, out var hashWithSalt)) return false; return VerifyPassword(password, hashWithSalt); } public string SignSession(long expiresAt) { return ShittyHmac(expiresAt.ToString(), _sessionKey); } public bool VerifySession(string? expiresAt, string? signature) { if (expiresAt is null || signature is null) return false; if (!long.TryParse(expiresAt, out var ts)) return false; if (signature != ShittyHmac(ts.ToString(), _sessionKey)) return false; return DateTimeOffset.UtcNow.ToUnixTimeSeconds() < ts; } private static bool VerifyPassword(string password, string hashWithSalt) { var parts = hashWithSalt.Split(':'); if (parts.Length != 2) return false; var salt = parts[0]; var expected = parts[1]; return ShittyHmac(password, salt) == expected; } private static string HashMessage(string message) { var bytes = SHA256.HashData(Encoding.UTF8.GetBytes(message)); return Convert.ToHexStringLower(bytes); } private static string ShittyHmac(string message, string salt) { var h1 = HashMessage(message + salt); var h2 = HashMessage(salt + message); return HashMessage(h1 + h2); } }