codeword/internal/services/recovery_service.go

128 lines
4.3 KiB
Go
Raw Normal View History

2023-12-29 11:30:20 +00:00
package services
import (
"codeword/internal/models"
2023-12-29 16:09:06 +00:00
"codeword/internal/utils/encrypt"
2023-12-31 12:22:03 +00:00
"context"
2024-01-04 11:27:50 +00:00
"encoding/base64"
2023-12-29 11:30:20 +00:00
"go.uber.org/zap"
)
2023-12-31 12:22:03 +00:00
type CodewordRepository interface {
2024-01-04 11:27:50 +00:00
StoreRecoveryRecord(ctx context.Context, userID, email, key, signUrl string) (string, error)
2024-01-03 15:45:41 +00:00
InsertToQueue(ctx context.Context, userID string, email string, key []byte, id string) error
2023-12-31 12:22:03 +00:00
Ping(ctx context.Context) error
2024-01-04 11:27:50 +00:00
GetRecoveryRecord(ctx context.Context, key string) (*models.RestoreRequest, error)
2023-12-29 11:30:20 +00:00
}
2023-12-31 12:22:03 +00:00
type UserRepository interface {
FindByEmail(ctx context.Context, email string) (*models.User, error)
2023-12-29 11:30:20 +00:00
}
2023-12-29 18:02:50 +00:00
type Deps struct {
2023-12-31 12:22:03 +00:00
Logger *zap.Logger
CodewordRepository CodewordRepository
UserRepository UserRepository
2024-01-04 11:27:50 +00:00
Encrypt *encrypt.Encrypt
2023-12-29 11:30:20 +00:00
}
2023-12-29 18:02:50 +00:00
type RecoveryService struct {
2023-12-31 12:22:03 +00:00
logger *zap.Logger
repositoryCodeword CodewordRepository
repositoryUser UserRepository
2024-01-04 11:27:50 +00:00
encrypt *encrypt.Encrypt
2023-12-29 18:02:50 +00:00
}
func NewRecoveryService(deps Deps) *RecoveryService {
2023-12-29 11:30:20 +00:00
return &RecoveryService{
2023-12-31 12:22:03 +00:00
logger: deps.Logger,
repositoryCodeword: deps.CodewordRepository,
repositoryUser: deps.UserRepository,
2024-01-04 11:27:50 +00:00
encrypt: deps.Encrypt,
2023-12-29 11:30:20 +00:00
}
}
// GenerateKey генерирует ключ, используя шифрование на основе эллиптической кривой
2023-12-31 12:22:03 +00:00
func (s *RecoveryService) GenerateKey() ([]byte, error) {
2024-01-04 11:27:50 +00:00
key, err := s.encrypt.SignCommonSecret()
2023-12-31 12:22:03 +00:00
if err != nil {
2024-01-04 11:27:50 +00:00
s.logger.Error("Failed to generate unique key for user", zap.Error(err))
2023-12-31 12:22:03 +00:00
return nil, err
}
return key, nil
}
func (s *RecoveryService) Ping(ctx context.Context) error {
2024-01-04 11:27:50 +00:00
err := s.repositoryCodeword.Ping(ctx)
if err != nil {
s.logger.Error("Failed to ping database", zap.Error(err))
return err
}
return nil
2023-12-29 11:30:20 +00:00
}
// FindUserByEmail ищет пользователя по электронной почте
2023-12-31 12:22:03 +00:00
func (s *RecoveryService) FindUserByEmail(ctx context.Context, email string) (*models.User, error) {
2024-01-04 11:27:50 +00:00
user, err := s.repositoryUser.FindByEmail(ctx, email)
if err != nil {
s.logger.Error("Failed to find user by email", zap.String("email", email), zap.Error(err))
return nil, err
}
if user == nil {
s.logger.Info("No user found with email", zap.String("email", email))
return nil, nil
}
return user, nil
2023-12-29 11:30:20 +00:00
}
// StoreRecoveryRecord сохраняет запись восстановления в базе данных
2024-01-04 11:27:50 +00:00
func (s *RecoveryService) StoreRecoveryRecord(ctx context.Context, userID, email, key, signUrl string) (string, error) {
id, err := s.repositoryCodeword.StoreRecoveryRecord(ctx, userID, email, key, signUrl)
2024-01-03 15:45:41 +00:00
if err != nil {
2024-01-04 11:27:50 +00:00
s.logger.Error("Failed save data in mongoDB for email", zap.String("email", email), zap.Error(err))
2024-01-03 15:45:41 +00:00
return "", err
}
return id, nil
2023-12-29 11:30:20 +00:00
}
2023-12-31 12:22:03 +00:00
// SendRecoveryEmail посылает письмо для восстановления доступа пользователю
2024-01-03 15:45:41 +00:00
func (s *RecoveryService) RecoveryEmailTask(ctx context.Context, userID string, email string, key []byte, id string) error {
2024-01-04 11:27:50 +00:00
err := s.repositoryCodeword.InsertToQueue(ctx, userID, email, key, id)
if err != nil {
s.logger.Error("Failed creating a task to send a worker by email", zap.String("email", email), zap.Error(err))
return err
}
return nil
2023-12-29 11:30:20 +00:00
}
2023-12-31 12:22:03 +00:00
// GetRecoveryRecord получает запись восстановления из базы данных
2024-01-04 11:27:50 +00:00
func (s *RecoveryService) GetRecoveryRecord(ctx context.Context, key string) (*models.RestoreRequest, error) {
byteKey, err := base64.URLEncoding.DecodeString(key)
if err != nil {
s.logger.Error("Failed to decode string signature to []byte format", zap.String("signature", key), zap.Error(err))
return nil, err
}
result, err := s.encrypt.VerifySignature(byteKey)
if err != nil {
s.logger.Error("Failed to verify signature", zap.String("signature", key), zap.Error(err))
return nil, err
}
if result {
req, err := s.repositoryCodeword.GetRecoveryRecord(ctx, key)
if err != nil {
s.logger.Error("Failed to obtain signature recovery data", zap.String("signature", key), zap.Error(err))
return nil, err
}
return req, nil
}
return nil, nil
2023-12-29 11:30:20 +00:00
}
// ExchangeForTokens обменивает ссылку восстановления на токены используя сервис аутентификации.
func (s *RecoveryService) ExchangeForTokens(userID string) (map[string]string, error) {
// TODO
return nil, nil
}