codeword/internal/controller/recovery/recovery_controller.go

101 lines
3.6 KiB
Go
Raw Normal View History

2024-01-11 18:20:33 +00:00
package recovery
2023-12-29 11:30:20 +00:00
import (
2024-01-11 11:15:28 +00:00
"codeword/internal/models"
2023-12-29 11:30:20 +00:00
"codeword/internal/services"
2024-01-04 11:27:50 +00:00
"encoding/base64"
2023-12-29 11:30:20 +00:00
"github.com/gofiber/fiber/v2"
"go.uber.org/zap"
"time"
)
type RecoveryController struct {
2024-01-03 15:45:41 +00:00
logger *zap.Logger
service *services.RecoveryService
defaultURL string
2023-12-29 11:30:20 +00:00
}
2024-01-03 15:45:41 +00:00
func NewRecoveryController(logger *zap.Logger, service *services.RecoveryService, defaultRedirectionURL string) *RecoveryController {
2023-12-29 11:30:20 +00:00
return &RecoveryController{
2024-01-03 15:45:41 +00:00
logger: logger,
service: service,
defaultURL: defaultRedirectionURL,
2023-12-29 11:30:20 +00:00
}
}
2023-12-31 12:22:03 +00:00
func (r *RecoveryController) HandlePingDB(c *fiber.Ctx) error {
return r.service.Ping(c.Context())
}
2023-12-29 11:30:20 +00:00
// HandleRecoveryRequest обрабатывает запрос на восстановление пароля
func (r *RecoveryController) HandleRecoveryRequest(c *fiber.Ctx) error {
email := c.FormValue("email")
2024-01-03 15:45:41 +00:00
referralURL := c.Get("Referrer")
redirectionURL := c.FormValue("RedirectionURL")
if redirectionURL == "" && referralURL != "" {
redirectionURL = referralURL
} else if redirectionURL == "" {
redirectionURL = r.defaultURL
}
2023-12-29 11:30:20 +00:00
2023-12-31 12:22:03 +00:00
user, err := r.service.FindUserByEmail(c.Context(), email)
if err != nil || user == nil {
2023-12-29 18:02:50 +00:00
r.logger.Error("Failed to find user by email", zap.Error(err))
2023-12-29 11:30:20 +00:00
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "User not found"})
}
2023-12-31 12:22:03 +00:00
2024-01-05 11:37:06 +00:00
key, err := r.service.GenerateKey()
if err != nil {
r.logger.Error("Failed to generate key", zap.Error(err))
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"})
}
2024-01-04 11:27:50 +00:00
signUrl := redirectionURL + base64.URLEncoding.EncodeToString(key)
sign := base64.URLEncoding.EncodeToString(key)
2024-01-03 15:45:41 +00:00
2024-01-11 11:15:28 +00:00
id, err := r.service.StoreRecoveryRecord(c.Context(), models.StoreRecDeps{UserID: user.ID.Hex(), Email: user.Email, Key: sign, Url: signUrl})
2023-12-29 11:30:20 +00:00
if err != nil {
2023-12-29 18:02:50 +00:00
r.logger.Error("Failed to store recovery record", zap.Error(err))
2023-12-29 11:30:20 +00:00
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"})
}
2023-12-31 12:22:03 +00:00
2024-01-07 11:26:38 +00:00
signWithID := sign + id // подпись с id записи
2024-01-07 11:13:07 +00:00
2024-01-11 11:15:28 +00:00
err = r.service.RecoveryEmailTask(c.Context(), models.RecEmailDeps{UserID: user.ID.Hex(), Email: email, SignWithID: signWithID, ID: id})
2023-12-29 11:30:20 +00:00
if err != nil {
2023-12-29 18:02:50 +00:00
r.logger.Error("Failed to send recovery email", zap.Error(err))
2023-12-29 11:30:20 +00:00
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"})
}
2024-01-03 15:45:41 +00:00
return c.Status(fiber.StatusOK).JSON(fiber.Map{
"id": id,
})
2023-12-29 11:30:20 +00:00
}
2024-01-05 11:37:06 +00:00
// todo тут скорее всего помимо подписи будет передаваться еще что-то, например email пользователя от фронта для поиска в бд
2023-12-29 11:30:20 +00:00
// HandleRecoveryLink обрабатывает ссылку восстановления и обменивает ее на токены
func (r *RecoveryController) HandleRecoveryLink(c *fiber.Ctx) error {
2023-12-31 12:22:03 +00:00
key := c.Params("sign")
2024-01-04 11:27:50 +00:00
record, err := r.service.GetRecoveryRecord(c.Context(), key)
2023-12-29 11:30:20 +00:00
if err != nil {
2023-12-29 18:02:50 +00:00
r.logger.Error("Failed to get recovery record", zap.Error(err))
2023-12-29 11:30:20 +00:00
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"})
}
if time.Since(record.CreatedAt) > 15*time.Minute {
2023-12-31 12:22:03 +00:00
r.logger.Error("Recovery link expired", zap.String("signature", key))
2024-01-05 11:37:06 +00:00
return c.Status(fiber.StatusNotAcceptable).JSON(fiber.Map{"error": "Recovery link expired"})
2023-12-29 11:30:20 +00:00
}
2024-01-04 14:57:30 +00:00
tokens, err := r.service.ExchangeForTokens(record.UserID, record.Sign)
2023-12-29 11:30:20 +00:00
if err != nil {
2023-12-29 18:02:50 +00:00
r.logger.Error("Failed to exchange recovery link for tokens", zap.Error(err))
2023-12-29 11:30:20 +00:00
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Internal Server Error"})
}
return c.Status(fiber.StatusOK).JSON(tokens)
}