codeword/internal/services/recovery_service.go

140 lines
4.8 KiB
Go
Raw Normal View History

2023-12-29 11:30:20 +00:00
package services
import (
2024-01-04 14:57:30 +00:00
"codeword/internal/adapters/client"
2023-12-29 11:30:20 +00:00
"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-11 11:15:28 +00:00
StoreRecoveryRecord(ctx context.Context, deps models.StoreRecDeps) (string, error)
InsertToQueue(ctx context.Context, deps models.RecEmailDeps) 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
2024-01-04 14:57:30 +00:00
AuthClient *client.AuthClient
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
2024-01-04 14:57:30 +00:00
authClient *client.AuthClient
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,
2024-01-04 14:57:30 +00:00
authClient: deps.AuthClient,
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
}
2024-01-05 11:37:06 +00:00
// вызывает пингование в бд
2023-12-31 12:22:03 +00:00
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-11 11:15:28 +00:00
func (s *RecoveryService) StoreRecoveryRecord(ctx context.Context, deps models.StoreRecDeps) (string, error) {
id, err := s.repositoryCodeword.StoreRecoveryRecord(ctx, models.StoreRecDeps{UserID: deps.UserID, Email: deps.Email, Key: deps.Key, Url: deps.Url})
2024-01-03 15:45:41 +00:00
if err != nil {
2024-01-11 11:15:28 +00:00
s.logger.Error("Failed save data in mongoDB for email", zap.String("email", deps.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
}
2024-01-05 11:37:06 +00:00
// RecoveryEmailTask посылает письмо для восстановления доступа пользователю
2024-01-11 11:15:28 +00:00
func (s *RecoveryService) RecoveryEmailTask(ctx context.Context, deps models.RecEmailDeps) error {
err := s.repositoryCodeword.InsertToQueue(ctx, models.RecEmailDeps{UserID: deps.UserID, Email: deps.Email, SignWithID: deps.SignWithID, ID: deps.ID})
2024-01-04 11:27:50 +00:00
if err != nil {
2024-01-11 11:15:28 +00:00
s.logger.Error("Failed creating a task to send a worker by email", zap.String("email", deps.Email), zap.Error(err))
2024-01-04 11:27:50 +00:00
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) {
2024-01-07 11:13:07 +00:00
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
}
byteKey, err := base64.URLEncoding.DecodeString(req.Sign)
2024-01-04 11:27:50 +00:00
if err != nil {
s.logger.Error("Failed to decode string signature to []byte format", zap.String("signature", key), zap.Error(err))
return nil, err
}
2024-01-05 11:37:06 +00:00
// сомнительный вариант но как я думаю верный, что false==err
2024-01-04 11:27:50 +00:00
result, err := s.encrypt.VerifySignature(byteKey)
2024-01-11 12:07:17 +00:00
if err != nil || !result {
2024-01-04 11:27:50 +00:00
s.logger.Error("Failed to verify signature", zap.String("signature", key), zap.Error(err))
return nil, err
}
2024-01-04 11:32:27 +00:00
return req, nil
2023-12-29 11:30:20 +00:00
}
2024-01-05 11:37:06 +00:00
// меняет подпись на токены идя в auth сервис
2024-01-04 14:57:30 +00:00
func (s *RecoveryService) ExchangeForTokens(userID string, signature string) (map[string]string, error) {
tokens, err := s.authClient.RefreshAuthToken(userID, signature)
if err != nil {
s.logger.Error("Failed to refresh auth token", zap.Error(err))
return nil, err
}
return map[string]string{
"accessToken": tokens.AccessToken,
"refreshToken": tokens.RefreshToken,
}, nil
2023-12-29 11:30:20 +00:00
}