2025-05-25 22:37:46 +02:00

76 lines
2.8 KiB
C#

using LanguageExt.Common;
using MediatR;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Suspectus.Gandalf.Core.Abstractions.CQRS;
using Suspectus.Gandalf.Core.Abstractions.Extensions;
using Suspectus.Gandalf.Palantir.Api.Commands;
using Suspectus.Gandalf.Palantir.Api.Handlers.Commands;
using Suspectus.Gandalf.Palantir.Data.Database;
using Suspectus.Gandalf.Palantir.Data.Dto;
namespace Suspectus.Gandalf.Palantir.Api.Handlers.Security;
public class PasswordHashingHandler(ApplicationContext applicationContext, IMediator mediator, IPasswordHasher<object> passwordHasher) : ICommandHandler<HashPasswordCommand, string>, ICommandHandler<VerifyPasswordCommand, bool>
{
private static readonly object MicrosoftIsAMeme = new();
public Task<Result<string>> Handle(HashPasswordCommand command, CancellationToken cancellationToken)
{
try
{
var hash = passwordHasher.HashPassword(MicrosoftIsAMeme, command.RawPassword);
return Task.FromResult(hash.AsResult());
}
catch (Exception)
{
return Task.FromResult("Something went wrong while hashing password.".AsErrorResult<string>());
}
}
public async Task<Result<bool>> Handle(VerifyPasswordCommand request, CancellationToken cancellationToken)
{
var signIn = await applicationContext.SignIns.SingleOrDefaultAsync(x => x.Id == request.SignInId, cancellationToken: cancellationToken);
if (signIn is null)
{
return "Sign-in method not found.".AsErrorResult<bool>();
}
if (signIn.PasswordHash is null)
{
return "Sign-in method does not have a password hash.".AsErrorResult<bool>();
}
var verification = passwordHasher.VerifyHashedPassword(MicrosoftIsAMeme, signIn.PasswordHash, request.RawPassword);
switch (verification)
{
case PasswordVerificationResult.Failed:
return false;
case PasswordVerificationResult.Success:
return true;
case PasswordVerificationResult.SuccessRehashNeeded:
var newHashResult = await mediator.Send(new HashPasswordCommand { RawPassword = request.RawPassword }, cancellationToken);
if (newHashResult.IsFaulted)
{
return newHashResult.AsErrorResult<bool, string>();
}
var newHash = newHashResult.GetValue();
signIn.PasswordHash = newHash;
await applicationContext.SaveChangesAsync(cancellationToken);
return true;
default:
return $"Password verification type not supported: {verification}".AsErrorResult<bool>();
}
}
}