Files
social-media/backend/Modules/Identity/Handlers/ForgotPassword.cs

93 lines
3.7 KiB
C#

using System.Web;
using Hutopy.Infrastructure.Configuration;
using Hutopy.Infrastructure.Emailer.Contracts;
using Hutopy.Modules.Identity.Data;
using Microsoft.Extensions.Options;
namespace Hutopy.Modules.Identity.Handlers;
[PublicAPI]
public record ForgotPasswordRequest(
string Email);
[PublicAPI]
public class ForgotPasswordHandler(
UserManager userManager,
IEmailSender emailSender,
IOptionsSnapshot<WebsiteOptions> options)
: Endpoint<ForgotPasswordRequest>
{
public override void Configure()
{
AllowAnonymous();
Post("/api/users/forgot-password");
Options(o => o.WithTags("Users"));
}
public override async Task HandleAsync(
ForgotPasswordRequest request,
CancellationToken ct)
{
// Find user by email
User? user = await userManager.FindByEmailAsync(request.Email);
// Always return OK even if user not found to prevent email enumeration
if (user is null)
{
await SendOkAsync(ct);
return;
}
// Generate password reset token
string token = await userManager.GeneratePasswordResetTokenAsync(user);
// URL encode the token as it may contain characters that are not URL safe
string encodedToken = HttpUtility.UrlEncode(token);
// Build reset link
string resetLink =
$"{options.Value.FrontendBaseUrl}/reset-password?email={HttpUtility.UrlEncode(request.Email)}&token={encodedToken}";
// Create a styled email message
string subject = "Reset your Hutopy password";
string message = $"""
<div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; color: #333;">
<h1 style="color: #2c3e50; margin-bottom: 20px;">Reset Your Hutopy Password</h1>
<p style="font-size: 16px; line-height: 1.5; margin-bottom: 25px;">
Please click the button below to reset your password:
</p>
<div style="text-align: center; margin: 30px 0;">
<a href='{resetLink}'
style="background-color: #3498db;
color: white;
text-decoration: none;
padding: 12px 24px;
border-radius: 4px;
font-weight: bold;
display: inline-block;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);">
Reset Password
</a>
</div>
<p style="font-size: 14px; color: #7f8c8d; margin-top: 30px;">
If you did not request a password reset, please ignore this email.
</p>
<p style="font-size: 14px; color: #7f8c8d; margin-top: 20px;">
If the button doesn't work, you can copy and paste this link into your browser:
<br>
<a href='{resetLink}' style="color: #3498db; word-break: break-all;">{resetLink}</a>
</p>
</div>
""";
// Send email
await emailSender.SendEmailAsync(request.Email, subject, message);
await SendOkAsync(ct);
}
}