initial: ZeroTier-like P2P mesh VPN server with multi-tenant Web UI
This commit is contained in:
113
internal/service/auth.go
Normal file
113
internal/service/auth.go
Normal file
@@ -0,0 +1,113 @@
|
||||
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()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user