package users_service import ( "context" "errors" "evening_detective_server/internal/modules/email_sender" "evening_detective_server/internal/modules/password_generator" "evening_detective_server/internal/modules/processor_jwt" "evening_detective_server/internal/repos/refresh_tokens_repo" "evening_detective_server/internal/repos/users_repo" "fmt" "time" "golang.org/x/crypto/bcrypt" ) type UsersService struct { usersRepo *users_repo.UsersRepo passwordGenerator password_generator.IPasswordGenerator emailSender email_sender.IEmailSender processorJWT processor_jwt.IProcessorJWT refreshTokensRepo *refresh_tokens_repo.RefreshTokensRepo } func NewUsersService( usersRepo *users_repo.UsersRepo, passwordGenerator password_generator.IPasswordGenerator, emailSender email_sender.IEmailSender, processorJWT processor_jwt.IProcessorJWT, refreshTokensRepo *refresh_tokens_repo.RefreshTokensRepo, ) *UsersService { return &UsersService{ usersRepo: usersRepo, passwordGenerator: passwordGenerator, emailSender: emailSender, processorJWT: processorJWT, refreshTokensRepo: refreshTokensRepo, } } func (s *UsersService) AddUser( ctx context.Context, username string, email string, ) error { password, err := s.passwordGenerator.Generate() if err != nil { return err } hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) if err != nil { return err } err = s.usersRepo.AddUser( ctx, username, email, string(hashedPassword), []string{"user"}, ) if err != nil { return err } err = s.emailSender.Send(ctx, email_sender.Message{ To: email, Subject: "Приветствую тебя, детектив!", Body: fmt.Sprintf("Вот твой пароль для входа в систему: %s", password), }) return err } func (s *UsersService) RefreshPassword( ctx context.Context, email string, ) error { password, err := s.passwordGenerator.Generate() if err != nil { return err } hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) if err != nil { return err } err = s.usersRepo.UpdateUserPassword( ctx, email, string(hashedPassword), ) if err != nil { return err } err = s.emailSender.Send(ctx, email_sender.Message{ To: email, Subject: "Приветствую тебя, детектив!", Body: fmt.Sprintf("Вот твой новый пароль для входа в систему, не теряй: %s", password), }) return err } func (s *UsersService) Login( ctx context.Context, email string, password string, ) (string, string, error) { user, err := s.usersRepo.GetUserByEmail( ctx, email, ) if err != nil { return "", "", err } if err = bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(password)); err != nil { return "", "", errors.New("Не верен email или пароль") } accessToken, err := s.processorJWT.GenerateAccessToken(user.ID, user.Email, user.Roles) if err != nil { return "", "", errors.New("Не получилось получить доступ") } refreshToken, err := s.processorJWT.GenerateRefreshToken(user.ID) if err != nil { return "", "", errors.New("Не получилось получить доступ") } refreshTokenClaims, err := s.processorJWT.GetClaims(refreshToken) if err != nil { return "", "", errors.New("Не получилось получить доступ") } if err := s.refreshTokensRepo.AddRefreshToken(ctx, user.ID, refreshTokenClaims.ExpiresAt.Time, refreshTokenClaims.ID); err != nil { return "", "", err } return accessToken, refreshToken, nil } func (s *UsersService) Refresh( ctx context.Context, token string, ) (string, string, error) { claims, err := s.processorJWT.GetClaims(token) if err != nil { return "", "", errors.New("Пользователь не найден") } now := time.Now() ok, err := s.refreshTokensRepo.ExistsRefreshToken(ctx, claims.UserID, claims.ID, now) if err != nil { return "", "", err } if !ok { return "", "", errors.New("Пользователь не найден") } if err := s.refreshTokensRepo.DeleteRefreshTokenByJti(ctx, claims.ID); err != nil { return "", "", err } user, err := s.usersRepo.GetUserByID(ctx, claims.UserID) if err != nil { return "", "", err } accessToken, err := s.processorJWT.GenerateAccessToken(user.ID, user.Email, user.Roles) if err != nil { return "", "", errors.New("Не получилось получить доступ") } refreshToken, err := s.processorJWT.GenerateRefreshToken(user.ID) if err != nil { return "", "", errors.New("Не получилось получить доступ") } refreshTokenClaims, err := s.processorJWT.GetClaims(refreshToken) if err != nil { return "", "", errors.New("Не получилось получить доступ") } if err := s.refreshTokensRepo.AddRefreshToken(ctx, user.ID, refreshTokenClaims.ExpiresAt.Time, refreshTokenClaims.ID); err != nil { return "", "", err } return accessToken, refreshToken, nil }