add service
All checks were successful
Deploy Smart Search Backend / deploy (push) Successful in 1m47s

This commit is contained in:
vallyenfail
2026-01-20 19:02:06 +03:00
parent f8db0fd9e6
commit 8b9554720d
15 changed files with 2109 additions and 38 deletions

View File

@@ -9,6 +9,7 @@ import (
"git.techease.ru/Smart-search/smart-search-back/pkg/crypto"
"git.techease.ru/Smart-search/smart-search-back/pkg/errors"
"git.techease.ru/Smart-search/smart-search-back/pkg/jwt"
"git.techease.ru/Smart-search/smart-search-back/pkg/validation"
"github.com/jackc/pgx/v5"
)
@@ -40,8 +41,7 @@ func (s *authService) Login(ctx context.Context, email, password, ip, userAgent
return "", "", err
}
passwordHash := crypto.PasswordHash(password)
if user.PasswordHash != passwordHash {
if !crypto.PasswordVerify(password, user.PasswordHash) {
return "", "", errors.NewBusinessError(errors.AuthInvalidCredentials, "Invalid email or password")
}
@@ -71,22 +71,27 @@ func (s *authService) Login(ctx context.Context, email, password, ip, userAgent
return accessToken, refreshToken, nil
}
func (s *authService) Refresh(ctx context.Context, refreshToken string) (string, error) {
func (s *authService) Refresh(ctx context.Context, refreshToken string) (string, string, error) {
session, err := s.sessionRepo.FindByRefreshToken(ctx, refreshToken)
if err != nil {
return "", err
return "", "", err
}
newAccessToken, err := jwt.GenerateAccessToken(session.UserID, s.jwtSecret)
if err != nil {
return "", errors.NewInternalError(errors.InternalError, "failed to generate access token", err)
return "", "", errors.NewInternalError(errors.InternalError, "failed to generate access token", err)
}
if err := s.sessionRepo.UpdateAccessToken(ctx, refreshToken, newAccessToken); err != nil {
return "", err
newRefreshToken, err := jwt.GenerateRefreshToken(session.UserID, s.jwtSecret)
if err != nil {
return "", "", errors.NewInternalError(errors.InternalError, "failed to generate refresh token", err)
}
return newAccessToken, nil
if err := s.sessionRepo.UpdateTokens(ctx, refreshToken, newAccessToken, newRefreshToken); err != nil {
return "", "", err
}
return newAccessToken, newRefreshToken, nil
}
func (s *authService) Validate(ctx context.Context, accessToken string) (int, error) {
@@ -121,6 +126,10 @@ func (s *authService) Logout(ctx context.Context, accessToken string) error {
}
func (s *authService) Register(ctx context.Context, email, password, name, phone string, inviteCode int64, ip, userAgent string) (accessToken, refreshToken string, err error) {
if err := validation.ValidateRegistration(email, password, name, phone); err != nil {
return "", "", err
}
_, err = s.inviteRepo.FindActiveByCode(ctx, inviteCode)
if err != nil {
return "", "", err

View File

@@ -11,7 +11,7 @@ import (
type AuthService interface {
Register(ctx context.Context, email, password, name, phone string, inviteCode int64, ip, userAgent string) (accessToken, refreshToken string, err error)
Login(ctx context.Context, email, password, ip, userAgent string) (accessToken, refreshToken string, err error)
Refresh(ctx context.Context, refreshToken string) (string, error)
Refresh(ctx context.Context, refreshToken string) (newAccessToken, newRefreshToken string, err error)
Validate(ctx context.Context, accessToken string) (int, error)
Logout(ctx context.Context, accessToken string) error
}

View File

@@ -10,6 +10,7 @@ import (
"git.techease.ru/Smart-search/smart-search-back/internal/repository"
"git.techease.ru/Smart-search/smart-search-back/pkg/errors"
"git.techease.ru/Smart-search/smart-search-back/pkg/fileparser"
"git.techease.ru/Smart-search/smart-search-back/pkg/validation"
"github.com/google/uuid"
"github.com/jackc/pgx/v5"
)
@@ -45,6 +46,14 @@ func NewRequestService(
}
func (s *requestService) CreateTZ(ctx context.Context, userID int, requestTxt string, fileData []byte, fileName string) (uuid.UUID, string, error) {
if err := validation.ValidateRequestTxt(requestTxt); err != nil {
return uuid.Nil, "", err
}
if err := validation.ValidateFileSize(len(fileData)); err != nil {
return uuid.Nil, "", err
}
combinedText := requestTxt
if len(fileData) > 0 && fileName != "" {

View File

@@ -267,22 +267,24 @@ func (s *Suite) TestAuthService_Login_EmptyIPAndUserAgent() {
func (s *Suite) TestAuthService_Refresh_Success() {
session := createTestSession(1)
s.sessionRepo.FindByRefreshTokenMock.Return(session, nil)
s.sessionRepo.UpdateAccessTokenMock.Return(nil)
s.sessionRepo.UpdateTokensMock.Return(nil)
accessToken, err := s.authService.Refresh(s.ctx, "test-refresh-token")
accessToken, refreshToken, err := s.authService.Refresh(s.ctx, "test-refresh-token")
s.NoError(err)
s.NotEmpty(accessToken)
s.NotEmpty(refreshToken)
}
func (s *Suite) TestAuthService_Refresh_RefreshInvalid() {
err := apperrors.NewBusinessError(apperrors.RefreshInvalid, "refresh token is invalid or expired")
s.sessionRepo.FindByRefreshTokenMock.Return(nil, err)
accessToken, refreshErr := s.authService.Refresh(s.ctx, "invalid-token")
accessToken, refreshToken, refreshErr := s.authService.Refresh(s.ctx, "invalid-token")
s.Error(refreshErr)
s.Empty(accessToken)
s.Empty(refreshToken)
var appErr *apperrors.AppError
s.True(errors.As(refreshErr, &appErr))
@@ -293,10 +295,11 @@ func (s *Suite) TestAuthService_Refresh_DatabaseError_OnFindSession() {
dbErr := apperrors.NewInternalError(apperrors.DatabaseError, "failed to find session", nil)
s.sessionRepo.FindByRefreshTokenMock.Return(nil, dbErr)
accessToken, err := s.authService.Refresh(s.ctx, "test-refresh-token")
accessToken, refreshToken, err := s.authService.Refresh(s.ctx, "test-refresh-token")
s.Error(err)
s.Empty(accessToken)
s.Empty(refreshToken)
var appErr *apperrors.AppError
s.True(errors.As(err, &appErr))
@@ -307,34 +310,37 @@ func (s *Suite) TestAuthService_Refresh_EmptyToken() {
err := apperrors.NewBusinessError(apperrors.RefreshInvalid, "refresh token is invalid or expired")
s.sessionRepo.FindByRefreshTokenMock.Return(nil, err)
accessToken, refreshErr := s.authService.Refresh(s.ctx, "")
accessToken, refreshToken, refreshErr := s.authService.Refresh(s.ctx, "")
s.Error(refreshErr)
s.Empty(accessToken)
s.Empty(refreshToken)
}
func (s *Suite) TestAuthService_Refresh_UpdateAccessTokenError() {
func (s *Suite) TestAuthService_Refresh_UpdateTokensError() {
session := createTestSession(1)
s.sessionRepo.FindByRefreshTokenMock.Return(session, nil)
dbErr := apperrors.NewInternalError(apperrors.DatabaseError, "failed to update access token", nil)
s.sessionRepo.UpdateAccessTokenMock.Return(dbErr)
dbErr := apperrors.NewInternalError(apperrors.DatabaseError, "failed to update tokens", nil)
s.sessionRepo.UpdateTokensMock.Return(dbErr)
accessToken, err := s.authService.Refresh(s.ctx, "test-refresh-token")
accessToken, refreshToken, err := s.authService.Refresh(s.ctx, "test-refresh-token")
s.Error(err)
s.Empty(accessToken)
s.Empty(refreshToken)
}
func (s *Suite) TestAuthService_Refresh_UserIDZero() {
session := createTestSession(0)
s.sessionRepo.FindByRefreshTokenMock.Return(session, nil)
s.sessionRepo.UpdateAccessTokenMock.Return(nil)
s.sessionRepo.UpdateTokensMock.Return(nil)
accessToken, err := s.authService.Refresh(s.ctx, "test-refresh-token")
accessToken, refreshToken, err := s.authService.Refresh(s.ctx, "test-refresh-token")
s.NoError(err)
s.NotEmpty(accessToken)
s.NotEmpty(refreshToken)
}
func (s *Suite) TestAuthService_Validate_Success() {