69 lines
3.0 KiB
C#
69 lines
3.0 KiB
C#
using LanguageExt.Common;
|
|
using MediatR;
|
|
using Microsoft.AspNetCore.Identity;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using W542.GandalfReborn.Commands;
|
|
using W542.GandalfReborn.Data.Database.Repositories;
|
|
using W542.GandalfReborn.Data.Dto;
|
|
using W542.GandalfReborn.Data.Entities.Subject.SignIn;
|
|
using W542.GandalfReborn.Extensions;
|
|
using W542.GandalfReborn.Handlers.Commands;
|
|
|
|
namespace W542.GandalfReborn.Handlers.Security;
|
|
|
|
public class AuthCodeRequestCommandHandler(IPasswordHasher<object> passwordHasher, ISubjectRepository subjectRepository, IMediator mediator) : IGrCommandHandler<AuthCodeRequestCommand, Result<AuthCodeDto>>
|
|
{
|
|
private static readonly object MicrosoftIsAMeme = new();
|
|
|
|
public async Task<Result<AuthCodeDto>> Handle(AuthCodeRequestCommand command, CancellationToken cancellationToken)
|
|
{
|
|
var subjectResult = await subjectRepository.GetSingle(query => query
|
|
.Where(subject => subject.Name == command.UsernameOrEmail || subject.SignInMethods.Any(signIn => signIn.Method == SignInMethod.Simple && signIn.Email == command.UsernameOrEmail))
|
|
.Include(x => x.SignInMethods)
|
|
);
|
|
|
|
if (subjectResult.IsFaulted)
|
|
{
|
|
return $"User {command.UsernameOrEmail} does not exist.".AsErrorResult<AuthCodeDto>();
|
|
}
|
|
|
|
var subject = subjectResult.GetValue();
|
|
|
|
var simpleSignIn = subject.SignInMethods.SingleOrDefault(x => x.Method == SignInMethod.Simple);
|
|
|
|
if (simpleSignIn?.PasswordHash is null)
|
|
{
|
|
return "User does not support simple password.".AsErrorResult<AuthCodeDto>();
|
|
}
|
|
|
|
var verification = passwordHasher.VerifyHashedPassword(MicrosoftIsAMeme, simpleSignIn.PasswordHash, command.Password);
|
|
|
|
switch (verification)
|
|
{
|
|
case PasswordVerificationResult.Failed:
|
|
return "Wrong Password.".AsErrorResult<AuthCodeDto>();
|
|
|
|
case PasswordVerificationResult.Success:
|
|
return await mediator.Send(new CreateAuthCodeCommand { SubjectId = subject.Id!.Value, CodeChallenge = command.CodeChallenge, Algorithm = command.Algorithm }, cancellationToken);
|
|
|
|
case PasswordVerificationResult.SuccessRehashNeeded:
|
|
var newHashResult = await mediator.Send(new HashPasswordCommand { RawPassword = command.Password }, cancellationToken);
|
|
|
|
if (newHashResult.IsFaulted)
|
|
{
|
|
return newHashResult.AsErrorResult<AuthCodeDto, string>();
|
|
}
|
|
|
|
var newHash = newHashResult.GetValue();
|
|
|
|
simpleSignIn.PasswordHash = newHash;
|
|
|
|
await subjectRepository.SaveChanges();
|
|
|
|
return await mediator.Send(new CreateAuthCodeCommand { SubjectId = subject.Id!.Value, CodeChallenge = command.CodeChallenge, Algorithm = command.Algorithm }, cancellationToken);
|
|
|
|
default:
|
|
return $"Password verification type not supported: {verification}".AsErrorResult<AuthCodeDto>();
|
|
}
|
|
}
|
|
} |