fix(auth): flujo de recuperación de contraseña usa email en vez de usuario
- login.html: corregir link roto /password/reset → /request-password-reset
- request-password-reset.html: reescribir — pide email, AJAX, diseño de la app
- RequestPasswordResetPost: buscar por email (GetUserByEmail), no revela si
el correo existe o no (misma respuesta siempre — seguridad)
- password-reset.html: reescribir — eliminar campo nombre_usuario redundante,
validación de contraseñas en cliente, diseño consistente con el resto del app
- PasswordResetPost: usar c.Locals("email") del token (ya validado por
middleware) en vez de nombre_usuario del form
- password_reset.go middleware: ampliar expiración de token de 5 min a 1 hora
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
37648724f8
commit
e937676160
@@ -80,25 +80,26 @@ func ReenvioEmail(c *fiber.Ctx) error {
|
||||
|
||||
// Función para manejar la solicitud de restablecimiento de contraseña
|
||||
func RequestPasswordResetPost(c *fiber.Ctx) error {
|
||||
usuario := c.FormValue("nombre_usuario")
|
||||
fmt.Println("Usuario recibido:", usuario)
|
||||
|
||||
user, err := models.GetUserByUsuario(usuario)
|
||||
if err != nil || user == nil {
|
||||
email := strings.TrimSpace(c.FormValue("email"))
|
||||
if email == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"success": false,
|
||||
"message": "Usuario inactivo o no existente",
|
||||
"message": "El correo electrónico es requerido.",
|
||||
})
|
||||
}
|
||||
|
||||
usuario_email := user.Email
|
||||
log.Println("Sending password reset email to:", usuario_email)
|
||||
|
||||
go services.SendPasswordResetEmail(usuario_email, services.GetPublicURL())
|
||||
// Intentar enviar el correo solo si el usuario existe — mismo mensaje en ambos casos por seguridad
|
||||
user, err := models.GetUserByEmail(email)
|
||||
if err == nil && user != nil && user.Email != "" {
|
||||
log.Println("[Reset] Enviando enlace de recuperación a:", email)
|
||||
go services.SendPasswordResetEmail(user.Email, services.GetPublicURL())
|
||||
} else {
|
||||
log.Println("[Reset] Correo no encontrado (no se revela al cliente):", email)
|
||||
}
|
||||
|
||||
return c.JSON(fiber.Map{
|
||||
"success": true,
|
||||
"message": "We've sent an email to reset your password to your registered email address",
|
||||
"message": "Si el correo está registrado, recibirás instrucciones en los próximos minutos.",
|
||||
})
|
||||
}
|
||||
|
||||
@@ -207,53 +208,56 @@ func PasswordReset(c *fiber.Ctx) error {
|
||||
}
|
||||
|
||||
func PasswordResetPost(c *fiber.Ctx) error {
|
||||
// Recuperar el nombre de usuario y la nueva contraseña del formulario
|
||||
nombreUsuario := c.FormValue("nombre_usuario")
|
||||
password := c.FormValue("password")
|
||||
// El email fue validado y extraído del token por el middleware ValidatePasswordResetPost
|
||||
emailLocal := c.Locals("email")
|
||||
if emailLocal == nil {
|
||||
return c.Status(fiber.StatusBadRequest).Render("auth/password-reset", fiber.Map{
|
||||
"Token": c.Params("token"),
|
||||
"error": "Token inválido. Solicita un nuevo enlace.",
|
||||
}, "layouts/landing")
|
||||
}
|
||||
email := fmt.Sprintf("%v", emailLocal)
|
||||
|
||||
// Validar que ambos campos estén presentes
|
||||
if nombreUsuario == "" || password == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"message": "Los campos nombre_usuario y password son obligatorios.",
|
||||
"error": true,
|
||||
})
|
||||
password := c.FormValue("password")
|
||||
cPassword := c.FormValue("c_password")
|
||||
|
||||
if password == "" || len(password) < 6 {
|
||||
return c.Render("auth/password-reset", fiber.Map{
|
||||
"Token": c.Params("token"),
|
||||
"error": "La contraseña debe tener al menos 6 caracteres.",
|
||||
}, "layouts/landing")
|
||||
}
|
||||
if password != cPassword {
|
||||
return c.Render("auth/password-reset", fiber.Map{
|
||||
"Token": c.Params("token"),
|
||||
"error": "Las contraseñas no coinciden.",
|
||||
}, "layouts/landing")
|
||||
}
|
||||
|
||||
// Imprimir los datos recibidos (opcional para depuración)
|
||||
fmt.Printf("Datos recibidos: nombre_usuario=%s, password=%s\n", nombreUsuario, password)
|
||||
|
||||
// Buscar al usuario en la base de datos por nombre de usuario
|
||||
user, err := models.GetUserByUsuario(nombreUsuario)
|
||||
user, err := models.GetUserByEmail(email)
|
||||
if err != nil || user == nil {
|
||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
||||
"message": "Usuario no encontrado.",
|
||||
"error": true,
|
||||
})
|
||||
return c.Render("auth/password-reset", fiber.Map{
|
||||
"Token": c.Params("token"),
|
||||
"error": "No se encontró una cuenta asociada a este enlace.",
|
||||
}, "layouts/landing")
|
||||
}
|
||||
|
||||
hash := config.Hash{}
|
||||
|
||||
// Encripta la nueva contraseña
|
||||
hashedPassword, err := hash.Create(password)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": "Error al encriptar la contraseña",
|
||||
"error": true,
|
||||
})
|
||||
return c.Render("auth/password-reset", fiber.Map{
|
||||
"Token": c.Params("token"),
|
||||
"error": "Error al procesar la contraseña. Intenta de nuevo.",
|
||||
}, "layouts/landing")
|
||||
}
|
||||
// Asigna la contraseña encriptada al modelo
|
||||
password = hashedPassword
|
||||
|
||||
// Actualizar la contraseña del usuario
|
||||
err = models.UpdateUserPassword(user.ID, password)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": "Error al actualizar la contraseña.",
|
||||
"error": true,
|
||||
})
|
||||
if err := models.UpdateUserPassword(user.ID, hashedPassword); err != nil {
|
||||
return c.Render("auth/password-reset", fiber.Map{
|
||||
"Token": c.Params("token"),
|
||||
"error": "No se pudo actualizar la contraseña. Intenta de nuevo.",
|
||||
}, "layouts/landing")
|
||||
}
|
||||
|
||||
// Redirigir al usuario al formulario de inicio de sesión después del éxito
|
||||
return c.Redirect("/login")
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user