114 lines
3.2 KiB
Go
114 lines
3.2 KiB
Go
package service
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"golang.org/x/crypto/bcrypt"
|
|
|
|
"zeromesh/internal/config"
|
|
"zeromesh/internal/middleware"
|
|
"zeromesh/internal/model"
|
|
"zeromesh/internal/repository"
|
|
)
|
|
|
|
type AuthService struct {
|
|
userRepo *repository.UserRepo
|
|
jwtCfg config.JWTConfig
|
|
}
|
|
|
|
func NewAuthService(userRepo *repository.UserRepo, jwtCfg config.JWTConfig) *AuthService {
|
|
return &AuthService{userRepo: userRepo, jwtCfg: jwtCfg}
|
|
}
|
|
|
|
func (s *AuthService) Login(username, password string) (string, *model.User, error) {
|
|
user, err := s.userRepo.FindByUsername(username)
|
|
if err != nil {
|
|
return "", nil, errors.New("invalid credentials")
|
|
}
|
|
// Migrate old SHA256 hashes to bcrypt on login
|
|
if len(user.Password) < 4 || user.Password[:4] != "$2a$" {
|
|
if sha256Hash(password) != user.Password {
|
|
return "", nil, errors.New("invalid credentials")
|
|
}
|
|
hashed, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
|
if err != nil {
|
|
return "", nil, fmt.Errorf("migrate password: %w", err)
|
|
}
|
|
user.Password = string(hashed)
|
|
_ = s.userRepo.UpdatePassword(user.ID, user.Password)
|
|
} else if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)); err != nil {
|
|
return "", nil, errors.New("invalid credentials")
|
|
}
|
|
token, err := middleware.GenerateToken(s.jwtCfg.Secret, user.ID, user.Username, user.Role, s.jwtCfg.ExpireHours)
|
|
if err != nil {
|
|
return "", nil, fmt.Errorf("generate token: %w", err)
|
|
}
|
|
user.Token = token
|
|
return token, user, nil
|
|
}
|
|
|
|
func (s *AuthService) Register(username, password string) (*model.User, string, error) {
|
|
hashed, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
|
if err != nil {
|
|
return nil, "", fmt.Errorf("hash password: %w", err)
|
|
}
|
|
user := &model.User{
|
|
Username: username,
|
|
Password: string(hashed),
|
|
Role: "user",
|
|
}
|
|
if err := s.userRepo.Create(user); err != nil {
|
|
return nil, "", err
|
|
}
|
|
token, err := middleware.GenerateToken(s.jwtCfg.Secret, user.ID, user.Username, user.Role, s.jwtCfg.ExpireHours)
|
|
if err != nil {
|
|
return nil, "", fmt.Errorf("generate token: %w", err)
|
|
}
|
|
user.Token = token
|
|
return user, token, nil
|
|
}
|
|
|
|
func (s *AuthService) InitAdmin(username, password string) (*model.User, string, error) {
|
|
count, err := s.userRepo.Count()
|
|
if err != nil {
|
|
return nil, "", err
|
|
}
|
|
if count > 0 {
|
|
return nil, "", fmt.Errorf("admin already exists")
|
|
}
|
|
hashed, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
|
if err != nil {
|
|
return nil, "", fmt.Errorf("hash password: %w", err)
|
|
}
|
|
user := &model.User{
|
|
Username: username,
|
|
Password: string(hashed),
|
|
Role: "admin",
|
|
QuotaNetworks: -1,
|
|
QuotaNodes: -1,
|
|
}
|
|
if err := s.userRepo.Create(user); err != nil {
|
|
return nil, "", err
|
|
}
|
|
token, err := middleware.GenerateToken(s.jwtCfg.Secret, user.ID, user.Username, user.Role, s.jwtCfg.ExpireHours)
|
|
if err != nil {
|
|
return nil, "", fmt.Errorf("generate token: %w", err)
|
|
}
|
|
user.Token = token
|
|
return user, token, nil
|
|
}
|
|
|
|
func sha256Hash(password string) string {
|
|
h := sha256.Sum256([]byte(password))
|
|
return hex.EncodeToString(h[:])
|
|
}
|
|
|
|
func (s *AuthService) CheckAdmin() (bool, error) {
|
|
return s.userRepo.HasAdmin()
|
|
}
|
|
|
|
|