diff --git a/web/service/auth.go b/web/service/auth.go index e69de29b..7f29164e 100644 --- a/web/service/auth.go +++ b/web/service/auth.go @@ -0,0 +1,69 @@ +package service + +import ( + "errors" + "os" + "time" + + "github.com/golang-jwt/jwt/v5" + "golang.org/x/crypto/bcrypt" + + "github.com/mhsanaei/3x-ui/v2/database" + "github.com/mhsanaei/3x-ui/v2/database/model" + "gorm.io/gorm" +) + +type AuthService struct { + DB *gorm.DB + JWTSecret []byte +} + +func NewAuthService() *AuthService { + secret := os.Getenv("JWT_SECRET") + if secret == "" { + secret = "dev-secret-change-me" + } + return &AuthService{ + DB: database.GetDB(), + JWTSecret: []byte(secret), + } +} + +// Регистрация (используем существующую модель: Username + PasswordHash + Role) +func (s *AuthService) Register(username, rawPassword, role string) error { + if role == "" { + role = "reader" + } + hash, err := bcrypt.GenerateFromPassword([]byte(rawPassword), 12) + if err != nil { + return err + } + u := &model.User{ + Username: username, + PasswordHash: string(hash), + Role: role, + } + return s.DB.Create(u).Error +} + +func (s *AuthService) Login(username, rawPassword string) (string, *model.User, error) { + var u model.User + if err := s.DB.Where("username = ?", username).First(&u).Error; err != nil { + if database.IsNotFound(err) { + return "", nil, errors.New("user not found") + } + return "", nil, err + } + if err := bcrypt.CompareHashAndPassword([]byte(u.PasswordHash), []byte(rawPassword)); err != nil { + return "", nil, errors.New("invalid password") + } + + claims := jwt.MapClaims{ + "id": u.Id, + "username": u.Username, + "role": u.Role, + "exp": time.Now().Add(72 * time.Hour).Unix(), + } + tok, err := jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString(s.JWTSecret) + return tok, &u, err +}