using System.Data; using AMREZ.EOP.Abstractions.Applications.Tenancy; using AMREZ.EOP.Abstractions.Applications.UseCases.Authentications; using AMREZ.EOP.Abstractions.Infrastructures.Common; using AMREZ.EOP.Abstractions.Infrastructures.Repositories; using AMREZ.EOP.Abstractions.Security; using AMREZ.EOP.Contracts.DTOs.Authentications.ChangePassword; using Microsoft.AspNetCore.Http; namespace AMREZ.EOP.Application.UseCases.Authentications; public sealed class ChangePasswordUseCase : IChangePasswordUseCase { private readonly ITenantResolver _resolver; private readonly IUnitOfWork _uow; private readonly IUserRepository _users; private readonly IPasswordHasher _hasher; private readonly IHttpContextAccessor _http; public ChangePasswordUseCase(ITenantResolver r, IUnitOfWork uow, IUserRepository users, IPasswordHasher h, IHttpContextAccessor http) { _resolver = r; _uow = uow; _users = users; _hasher = h; _http = http; } public async Task ExecuteAsync(ChangePasswordRequest request, CancellationToken ct = default) { var http = _http.HttpContext ?? throw new InvalidOperationException("No HttpContext"); var tenant = _resolver.Resolve(http, request); if (tenant is null) return false; await _uow.BeginAsync(tenant, IsolationLevel.ReadCommitted, ct); try { var user = await _users.FindByIdAsync(request.UserId, ct); if (user is null) { await _uow.RollbackAsync(ct); return false; } if (!_hasher.Verify(request.OldPassword, user.PasswordHash)) { await _uow.RollbackAsync(ct); return false; } var newHash = _hasher.Hash(request.NewPassword); await _users.AddPasswordHistoryAsync(user.Id, user.PasswordHash, ct); await _users.ChangePasswordAsync(user.Id, newHash, ct); await _uow.CommitAsync(ct); return true; } catch { await _uow.RollbackAsync(ct); throw; } } }