104 lines
2.4 KiB
Go
104 lines
2.4 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"crypto/rand"
|
|
"encoding/base64"
|
|
"errors"
|
|
"tailly_back_v2/internal/domain"
|
|
"tailly_back_v2/internal/repository"
|
|
"time"
|
|
)
|
|
|
|
type SessionService interface {
|
|
InitiateSession(ctx context.Context, device *domain.Device) error
|
|
ConfirmSession(ctx context.Context, token string) (*domain.Session, error)
|
|
GetActiveSessions(ctx context.Context, userID int) ([]*domain.Session, error)
|
|
TerminateSession(ctx context.Context, sessionID int) error
|
|
}
|
|
|
|
type sessionService struct {
|
|
sessionRepo repository.SessionRepository
|
|
deviceRepo repository.DeviceRepository
|
|
mailer MailService
|
|
}
|
|
|
|
func (s *sessionService) InitiateSession(ctx context.Context, device *domain.Device) error {
|
|
// Генерация токена подтверждения
|
|
token := make([]byte, 32)
|
|
if _, err := rand.Read(token); err != nil {
|
|
return err
|
|
}
|
|
|
|
device.ConfirmationToken = base64.URLEncoding.EncodeToString(token)
|
|
device.ExpiresAt = time.Now().Add(24 * time.Hour)
|
|
|
|
if err := s.deviceRepo.Save(ctx, device); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Отправка письма
|
|
user, err := s.userRepo.GetByID(ctx, device.UserID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return s.mailer.SendSessionConfirmation(
|
|
user.Email,
|
|
device.ConfirmationToken,
|
|
device.IPAddress,
|
|
device.UserAgent,
|
|
)
|
|
}
|
|
|
|
func (s *sessionService) ConfirmSession(ctx context.Context, token string) (*domain.Session, error) {
|
|
device, err := s.deviceRepo.GetByToken(ctx, token)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if time.Now().After(device.ExpiresAt) {
|
|
return nil, errors.New("confirmation token expired")
|
|
}
|
|
|
|
session := &domain.Session{
|
|
UserID: device.UserID,
|
|
DeviceID: device.ID,
|
|
StartedAt: time.Now(),
|
|
}
|
|
|
|
if err := s.sessionRepo.Save(ctx, session); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return session, nil
|
|
}
|
|
|
|
func (s *sessionService) GetUserSessions(ctx context.Context, userID int) ([]*domain.Session, error) {
|
|
sessions, err := s.sessionRepo.GetActiveByUser(ctx, userID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
currentSessionID, _ := ctx.Value("sessionID").(int)
|
|
|
|
for _, session := range sessions {
|
|
session.IsCurrent = (session.ID == currentSessionID)
|
|
}
|
|
|
|
return sessions, nil
|
|
}
|
|
|
|
func (s *sessionService) Terminate(ctx context.Context, userID, sessionID int) error {
|
|
session, err := s.sessionRepo.GetByID(ctx, sessionID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if session.UserID != userID {
|
|
return errors.New("unauthorized")
|
|
}
|
|
|
|
return s.sessionRepo.Terminate(ctx, sessionID)
|
|
}
|