codeword/internal/controller/recovery/recovery_controller.go
2024-01-18 16:44:55 +03:00

101 lines
3.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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