75 lines
2.0 KiB
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))
|
|
}
|