File size: 1,509 Bytes
48511d8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
package auth

import (
	"crypto/rsa"
	"errors"
	"time"

	"github.com/arpinfidel/p2p-llm/db"
	"github.com/golang-jwt/jwt"
	"golang.org/x/crypto/bcrypt"
)

type AuthService struct {
	keys     *rsa.PrivateKey
	authRepo db.APIKeyRepository
}

func NewAuthService(privateKey *rsa.PrivateKey, authRepo db.APIKeyRepository) *AuthService {
	return &AuthService{
		keys:     privateKey,
		authRepo: authRepo,
	}
}

func (s *AuthService) HashAPIKey(apiKey string) (string, error) {
	hash, err := bcrypt.GenerateFromPassword([]byte(apiKey), bcrypt.DefaultCost)
	if err != nil {
		return "", err
	}
	return string(hash), nil
}

func (s *AuthService) VerifyAPIKey(apiKey, hash string) bool {
	err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(apiKey))
	return err == nil
}

func (s *AuthService) GenerateJWT() (string, error) {
	token := jwt.New(jwt.SigningMethodRS256)
	claims := token.Claims.(jwt.MapClaims)
	claims["exp"] = time.Now().Add(time.Hour * 24).Unix() // Token expires in 24 hours
	claims["iat"] = time.Now().Unix()

	tokenString, err := token.SignedString(s.keys)
	if err != nil {
		return "", err
	}
	return tokenString, nil
}

func (s *AuthService) Authenticate(apiKey string) (string, error) {
	hash, err := s.authRepo.GetActiveKeyHash()
	if err != nil {
		return "", err
	}

	if !s.VerifyAPIKey(apiKey, hash) {
		return "", ErrInvalidAPIKey
	}

	return s.GenerateJWT()
}

var (
	ErrInvalidAPIKey = errors.New("invalid API key")
)