package auth import ( "crypto/sha256" "encoding/hex" "errors" "fmt" "time" "github.com/golang-jwt/jwt/v5" gossh "golang.org/x/crypto/ssh" ) // Claims represents the JWT claims type Claims struct { UserID uint `json:"user_id"` Email string `json:"email"` Username string `json:"username"` jwt.RegisteredClaims } // JWTManager handles JWT token generation and validation type JWTManager struct { secretKey string tokenDuration time.Duration } // NewJWTManager creates a new JWT manager func NewJWTManager(secretKey string, tokenDuration time.Duration) *JWTManager { return &JWTManager{ secretKey: secretKey, tokenDuration: tokenDuration, } } // GenerateToken generates a new JWT token for a user func (m *JWTManager) GenerateToken(userID uint, email, username string) (string, error) { claims := Claims{ UserID: userID, Email: email, Username: username, RegisteredClaims: jwt.RegisteredClaims{ ExpiresAt: jwt.NewNumericDate(time.Now().Add(m.tokenDuration)), IssuedAt: jwt.NewNumericDate(time.Now()), NotBefore: jwt.NewNumericDate(time.Now()), Issuer: "terminalshop", }, } token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) return token.SignedString([]byte(m.secretKey)) } // ValidateToken validates a JWT token and returns the claims func (m *JWTManager) ValidateToken(tokenString string) (*Claims, error) { token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) { // Verify signing method if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) } return []byte(m.secretKey), nil }) if err != nil { return nil, err } if claims, ok := token.Claims.(*Claims); ok && token.Valid { return claims, nil } return nil, errors.New("invalid token") } // GetSSHKeyFingerprint returns the MD5 fingerprint of an SSH public key // This matches the format shown by `ssh-keygen -lf ~/.ssh/id_rsa.pub` func GetSSHKeyFingerprint(pubKey gossh.PublicKey) string { hash := sha256.Sum256(pubKey.Marshal()) return "SHA256:" + hex.EncodeToString(hash[:]) } // FormatSSHPublicKey formats an SSH public key in authorized_keys format func FormatSSHPublicKey(pubKey gossh.PublicKey) string { return string(gossh.MarshalAuthorizedKey(pubKey)) }