To gitea and beyond, let's go(-yco)

This commit is contained in:
2025-11-10 19:12:09 +01:00
parent 8f6133392d
commit 71a031342b
245 changed files with 83994 additions and 0 deletions

View File

@@ -0,0 +1,124 @@
package services
import (
"fmt"
"golang.org/x/crypto/bcrypt"
"goyco/internal/database"
"goyco/internal/repositories"
)
type SessionService struct {
jwtService *JWTService
userRepo repositories.UserRepository
}
func NewSessionService(jwtService *JWTService, userRepo repositories.UserRepository) *SessionService {
return &SessionService{
jwtService: jwtService,
userRepo: userRepo,
}
}
func (s *SessionService) Login(username, password string) (*AuthResult, error) {
trimmedUsername := TrimString(username)
if trimmedUsername == "" {
return nil, ErrInvalidCredentials
}
user, err := s.userRepo.GetByUsername(trimmedUsername)
if err != nil {
if IsRecordNotFound(err) {
return nil, ErrInvalidCredentials
}
return nil, fmt.Errorf("lookup user: %w", err)
}
if !user.EmailVerified {
return nil, ErrEmailNotVerified
}
if user.Locked {
return nil, ErrAccountLocked
}
if compareErr := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)); compareErr != nil {
return nil, ErrInvalidCredentials
}
return s.issueAuthResult(user)
}
func (s *SessionService) VerifyToken(tokenString string) (uint, error) {
return s.jwtService.VerifyAccessToken(tokenString)
}
func (s *SessionService) issueAuthResult(user *database.User) (*AuthResult, error) {
accessToken, err := s.jwtService.GenerateAccessToken(user)
if err != nil {
return nil, fmt.Errorf("generate access token: %w", err)
}
refreshToken, err := s.jwtService.GenerateRefreshToken(user)
if err != nil {
return nil, fmt.Errorf("generate refresh token: %w", err)
}
return &AuthResult{
AccessToken: accessToken,
RefreshToken: refreshToken,
User: sanitizeUser(user),
}, nil
}
func (s *SessionService) RefreshAccessToken(refreshToken string) (*AuthResult, error) {
accessToken, err := s.jwtService.RefreshAccessToken(refreshToken)
if err != nil {
return nil, err
}
userID, err := s.jwtService.VerifyAccessToken(accessToken)
if err != nil {
return nil, fmt.Errorf("verify new access token: %w", err)
}
user, err := s.userRepo.GetByID(userID)
if err != nil {
return nil, fmt.Errorf("lookup user: %w", err)
}
return &AuthResult{
AccessToken: accessToken,
RefreshToken: refreshToken,
User: sanitizeUser(user),
}, nil
}
func (s *SessionService) RevokeRefreshToken(refreshToken string) error {
return s.jwtService.RevokeRefreshToken(refreshToken)
}
func (s *SessionService) RevokeAllUserTokens(userID uint) error {
return s.jwtService.RevokeAllRefreshTokens(userID)
}
func (s *SessionService) InvalidateAllSessions(userID uint) error {
user, err := s.userRepo.GetByID(userID)
if err != nil {
return fmt.Errorf("load user: %w", err)
}
user.SessionVersion++
if err := s.userRepo.Update(user); err != nil {
return fmt.Errorf("update session version: %w", err)
}
if err := s.jwtService.RevokeAllRefreshTokens(userID); err != nil {
return fmt.Errorf("revoke refresh tokens: %w", err)
}
return nil
}
func (s *SessionService) CleanupExpiredTokens() error {
return s.jwtService.CleanupExpiredTokens()
}