using System.Security.Claims; using FastEndpoints; using FluentValidation; using TrackQrApi.Data; using TrackQrApi.Features.Auth.Common; namespace TrackQrApi.Features.Auth.Endpoints; public class ChangePasswordRequest { public string CurrentPassword { get; set; } = string.Empty; public string NewPassword { get; set; } = string.Empty; } public class ChangePasswordValidator : Validator { public ChangePasswordValidator() { RuleFor(x => x.CurrentPassword) .NotEmpty().WithMessage("Current password is required"); RuleFor(x => x.NewPassword) .NotEmpty().WithMessage("New password is required") .MinimumLength(8).WithMessage("New password must be at least 8 characters"); } } public class ChangePasswordEndpoint(AppDbContext db) : Endpoint { public override void Configure() { Post("/auth/change-password"); } public override async Task HandleAsync(ChangePasswordRequest req, CancellationToken ct) { var userId = Guid.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier)!); var user = await db.Users.FindAsync([userId], ct); if (user == null) { await HttpContext.Response.SendAsync(new MessageResponse("User not found"), 404, cancellation: ct); return; } // Verify current password if (!BCrypt.Net.BCrypt.Verify(req.CurrentPassword, user.PasswordHash)) { await HttpContext.Response.SendAsync(new MessageResponse("Current password is incorrect"), 400, cancellation: ct); return; } // Update password user.PasswordHash = BCrypt.Net.BCrypt.HashPassword(req.NewPassword); await db.SaveChangesAsync(ct); await HttpContext.Response.SendAsync(new MessageResponse("Password changed successfully"), cancellation: ct); } }