Files
terminalShop/pkg/auth/ssh_auth.go

113 lines
3.2 KiB
Go

package auth
import (
"fmt"
gossh "golang.org/x/crypto/ssh"
"gorm.io/gorm"
"terminalShop/pkg/models"
)
// SSHAuthService handles SSH key-based authentication
type SSHAuthService struct {
db *gorm.DB
jwtManager *JWTManager
}
// NewSSHAuthService creates a new SSH auth service
func NewSSHAuthService(db *gorm.DB, jwtManager *JWTManager) *SSHAuthService {
return &SSHAuthService{
db: db,
jwtManager: jwtManager,
}
}
// AuthenticateSSHKey authenticates a user by their SSH public key
// Auto-creates user on first connect (following terminal.shop pattern)
// Returns the user and a JWT token
func (s *SSHAuthService) AuthenticateSSHKey(publicKey gossh.PublicKey) (*models.User, string, error) {
fingerprint := GetSSHKeyFingerprint(publicKey)
sshKey := FormatSSHPublicKey(publicKey)
var user models.User
err := s.db.Where("ssh_key_fingerprint = ?", fingerprint).First(&user).Error
if err == gorm.ErrRecordNotFound {
// User not found - auto-create (no registration screen needed!)
user = models.User{
SSHKeyFingerprint: fingerprint,
SSHPublicKey: sshKey,
Anonymous: false,
}
if err := s.db.Create(&user).Error; err != nil {
return nil, "", fmt.Errorf("failed to create user: %w", err)
}
} else if err != nil {
return nil, "", fmt.Errorf("database error: %w", err)
}
// Generate JWT token for this session
token, err := s.jwtManager.GenerateToken(user.ID, "", fingerprint[:8])
if err != nil {
return nil, "", fmt.Errorf("failed to generate token: %w", err)
}
return &user, token, nil
}
// RegisterWithSSHKey creates a new user account with the given SSH key
// No username required - matches terminal.shop pattern
func (s *SSHAuthService) RegisterWithSSHKey(publicKey gossh.PublicKey, name, email string) (*models.User, string, error) {
fingerprint := GetSSHKeyFingerprint(publicKey)
sshKeyFormatted := FormatSSHPublicKey(publicKey)
// Check if SSH key is already registered
var existing models.User
err := s.db.Where("ssh_key_fingerprint = ?", fingerprint).First(&existing).Error
if err == nil {
return nil, "", fmt.Errorf("SSH key already registered")
}
if err != gorm.ErrRecordNotFound {
return nil, "", fmt.Errorf("database error: %w", err)
}
// Create new user (no username required!)
user := models.User{
SSHPublicKey: sshKeyFormatted,
SSHKeyFingerprint: fingerprint,
Name: name,
Email: email,
}
if err := s.db.Create(&user).Error; err != nil {
return nil, "", fmt.Errorf("failed to create user: %w", err)
}
// Generate JWT token
token, err := s.jwtManager.GenerateToken(user.ID, "", fingerprint[:8])
if err != nil {
return nil, "", fmt.Errorf("failed to generate token: %w", err)
}
return &user, token, nil
}
// IsSSHKeyRegistered checks if an SSH key is already registered
func (s *SSHAuthService) IsSSHKeyRegistered(publicKey gossh.PublicKey) (bool, error) {
fingerprint := GetSSHKeyFingerprint(publicKey)
var user models.User
err := s.db.Where("ssh_key_fingerprint = ?", fingerprint).First(&user).Error
if err == gorm.ErrRecordNotFound {
return false, nil
}
if err != nil {
return false, fmt.Errorf("database error: %w", err)
}
return true, nil
}