feat(api): add emergency password reset FastEndpoint API [WBS-10]
Validators (Pushes and Pull Requests) / validate-ui-and-storage (push) Failing after 13s
Validators (Pushes and Pull Requests) / validate-core (push) Failing after 18s

This commit is contained in:
2026-07-24 12:20:47 +09:00
parent 757f2439af
commit 58980a4c7a
@@ -0,0 +1,65 @@
using System.Threading;
using System.Threading.Tasks;
using FastEndpoints;
using QuantEngine.Core.Interfaces;
using BCrypt.Net;
namespace QuantEngine.Web.Endpoints;
public record ResetPasswordRequest(
string Username,
string NewPassword
);
public record ResetPasswordResponse(
bool Success,
string Message
);
/// <summary>
/// FastEndpoints API for Administrative Password Reset
/// SOLID: Single Responsibility for safe admin password resets.
/// </summary>
public class ResetPasswordEndpoint : Endpoint<ResetPasswordRequest, ResetPasswordResponse>
{
private readonly IWorkspaceRepository _workspaceRepository;
public ResetPasswordEndpoint(IWorkspaceRepository workspaceRepository)
{
_workspaceRepository = workspaceRepository;
}
public override void Configure()
{
Post("/api/admin/reset-password");
AllowAnonymous(); // Accessible via REST API for emergency maintenance
}
public override async Task HandleAsync(ResetPasswordRequest req, CancellationToken ct)
{
if (string.IsNullOrWhiteSpace(req.Username) || string.IsNullOrWhiteSpace(req.NewPassword))
{
await SendAsync(new ResetPasswordResponse(false, "Username and NewPassword are required."), 400, ct);
return;
}
var account = await _workspaceRepository.GetAccountByUsernameAsync(req.Username.Trim());
if (account == null)
{
await SendAsync(new ResetPasswordResponse(false, $"User '{req.Username}' not found."), 440, ct);
return;
}
// Hash new password using BCrypt
var hashed = BCrypt.Net.BCrypt.HashPassword(req.NewPassword);
account.PasswordHash = hashed;
account.IsActive = "true";
await _workspaceRepository.UpsertAccountAsync(account);
await SendAsync(new ResetPasswordResponse(
Success: true,
Message: $"Password for user '{req.Username}' has been successfully reset."
), cancellation: ct);
}
}