using Microsoft.AspNetCore.Identity; namespace ErsatzTV.Application.Auth; /// /// backed by ASP.NET Core Identity's /// (PBKDF2-HMAC-SHA512, per-hash random salt, format-versioned so a future work-factor bump is a /// transparent rehash-on-verify). Stateless and thread-safe → registered as a singleton. /// public sealed class LocalPasswordHasher : ILocalPasswordHasher { // The generic user parameter is unused by the hasher (it takes no per-user data), so a shared sentinel // is fine. private static readonly object Sentinel = new(); private readonly PasswordHasher _hasher = new(); private readonly Lazy _dummyHash; public LocalPasswordHasher() => _dummyHash = new Lazy(() => _hasher.HashPassword(Sentinel, "not-a-real-password")); public string DummyHash => _dummyHash.Value; public string Hash(string password) => _hasher.HashPassword(Sentinel, password); public LocalPasswordVerification Verify(string hash, string password) => _hasher.VerifyHashedPassword(Sentinel, hash, password) switch { PasswordVerificationResult.Success => LocalPasswordVerification.Success, PasswordVerificationResult.SuccessRehashNeeded => LocalPasswordVerification.SuccessRehashNeeded, _ => LocalPasswordVerification.Failed }; }