Files
agent/backend/internal/auth/service.go

75 lines
2.0 KiB
Go

package auth
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"errors"
"fmt"
"strings"
"golang.org/x/crypto/bcrypt"
"gorm.io/gorm"
"senlinai-agent/backend/internal/domain"
)
type Service struct {
db *gorm.DB
secret string
}
func NewService(database *gorm.DB, secret string) *Service {
return &Service{db: database, secret: secret}
}
func (s *Service) CreateInvite(adminID uint, email string) (string, error) {
normalized := strings.ToLower(strings.TrimSpace(email))
if normalized == "" {
return "", errors.New("email is required")
}
return normalized + "." + s.sign(normalized), nil
}
func (s *Service) RegisterWithInvite(token, email, displayName, password string) (*domain.User, error) {
separator := strings.LastIndex(token, ".")
if separator < 1 || separator == len(token)-1 {
return nil, errors.New("invalid invite token")
}
inviteEmail := token[:separator]
signature := token[separator+1:]
if !hmac.Equal([]byte(signature), []byte(s.sign(inviteEmail))) {
return nil, errors.New("invalid invite signature")
}
if inviteEmail != strings.ToLower(strings.TrimSpace(email)) {
return nil, errors.New("invite email mismatch")
}
hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
return nil, err
}
user := &domain.User{
Email: inviteEmail,
DisplayName: strings.TrimSpace(displayName),
PasswordHash: string(hash),
Role: "user",
}
return user, s.db.Create(user).Error
}
func (s *Service) Login(email, password string) (string, error) {
var user domain.User
if err := s.db.Where("email = ?", strings.ToLower(strings.TrimSpace(email))).First(&user).Error; err != nil {
return "", errors.New("invalid credentials")
}
if err := bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(password)); err != nil {
return "", errors.New("invalid credentials")
}
return fmt.Sprintf("user:%d", user.ID), nil
}
func (s *Service) sign(value string) string {
mac := hmac.New(sha256.New, []byte(s.secret))
mac.Write([]byte(value))
return hex.EncodeToString(mac.Sum(nil))
}