Brijesh's Git Server — argus-core @ main

Logging service

internal/auth/twirp_server.go (view raw)

 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
package auth

import (
	"context"
	"time"

	pb "argus-core/rpc/auth"

	"github.com/golang-jwt/jwt/v5"
	"github.com/twitchtv/twirp"
)

// TwirpServer implements the generated Twirp AuthService interface
type TwirpServer struct {
	auth Service // existing auth service
}

// NewTwirpServer creates a new Twirp server wrapper around the existing auth service
func NewTwirpServer(auth Service) pb.AuthService {
	return &TwirpServer{auth: auth}
}

// Register implements the Twirp AuthService Register method
func (s *TwirpServer) Register(ctx context.Context, req *pb.RegisterRequest) (*pb.RegisterResponse, error) {
	if req.Email == "" || req.Password == "" {
		return nil, twirp.NewError(twirp.InvalidArgument, "email and password are required")
	}

	user, err := s.auth.Register(req.Email, req.Password)
	if err != nil {
		if err == ErrUserExists {
			return nil, twirp.NewError(twirp.AlreadyExists, "user already exists")
		}
		return nil, twirp.InternalErrorWith(err)
	}

	return &pb.RegisterResponse{
		User: &pb.User{
			Id:        user.ID.String(),
			Email:     user.Email,
			CreatedAt: user.CreatedAt.Format(time.RFC3339),
			UpdatedAt: user.UpdatedAt.Format(time.RFC3339),
		},
	}, nil
}

// Login implements the Twirp AuthService Login method
func (s *TwirpServer) Login(ctx context.Context, req *pb.LoginRequest) (*pb.LoginResponse, error) {
	if req.Email == "" || req.Password == "" {
		return nil, twirp.NewError(twirp.InvalidArgument, "email and password are required")
	}

	token, user, err := s.auth.Login(req.Email, req.Password)
	if err != nil {
		if err == ErrInvalidCredentials {
			return nil, twirp.NewError(twirp.Unauthenticated, "invalid credentials")
		}
		return nil, twirp.InternalErrorWith(err)
	}

	return &pb.LoginResponse{
		Token: token,
		User: &pb.User{
			Id:        user.ID.String(),
			Email:     user.Email,
			CreatedAt: user.CreatedAt.Format(time.RFC3339),
			UpdatedAt: user.UpdatedAt.Format(time.RFC3339),
		},
	}, nil
}

// ValidateToken implements the Twirp AuthService ValidateToken method
func (s *TwirpServer) ValidateToken(ctx context.Context, req *pb.ValidateTokenRequest) (*pb.ValidateTokenResponse, error) {
	if req.Token == "" {
		return nil, twirp.NewError(twirp.InvalidArgument, "token is required")
	}

	// Parse token to check expiration first
	token, err := jwt.Parse(req.Token, func(token *jwt.Token) (interface{}, error) {
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, twirp.NewError(twirp.Unauthenticated, "invalid token signing method")
		}
		return s.auth.(*service).jwtSecret, nil // Note: This requires the secret to be accessible
	})

	if err != nil {
		if err.Error() == "Token is expired" {
			return nil, twirp.NewError(twirp.Unauthenticated, "token has expired")
		}
		return nil, twirp.NewError(twirp.Unauthenticated, "invalid token")
	}

	if !token.Valid {
		return nil, twirp.NewError(twirp.Unauthenticated, "invalid token")
	}

	// Now use the service's ValidateToken which will get the user
	user, err := s.auth.ValidateToken(req.Token)
	if err != nil {
		if err == ErrInvalidToken {
			return nil, twirp.NewError(twirp.Unauthenticated, "invalid token")
		}
		return nil, twirp.InternalErrorWith(err)
	}

	return &pb.ValidateTokenResponse{
		User: &pb.User{
			Id:        user.ID.String(),
			Email:     user.Email,
			CreatedAt: user.CreatedAt.Format(time.RFC3339),
			UpdatedAt: user.UpdatedAt.Format(time.RFC3339),
		},
	}, nil
}