forked from kevin/meshtastic_mqtt_server
105 lines
2.7 KiB
Go
105 lines
2.7 KiB
Go
package store
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
var ErrUserAlreadyExists = errors.New("user already exists")
|
|
|
|
func (s *Store) GetUserByUsername(username string) (*UserRecord, error) {
|
|
var user UserRecord
|
|
if err := s.db.Where("username = ?", username).Take(&user).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
return &user, nil
|
|
}
|
|
|
|
func (s *Store) GetUserByID(id uint64) (*UserRecord, error) {
|
|
var user UserRecord
|
|
if err := s.db.Where("id = ?", id).Take(&user).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
return &user, nil
|
|
}
|
|
|
|
func (s *Store) ListUsers() ([]UserRecord, error) {
|
|
var users []UserRecord
|
|
return users, s.db.Order("id ASC").Find(&users).Error
|
|
}
|
|
|
|
func (s *Store) CreateAdminUser(username, password string) (*UserRecord, error) {
|
|
username = strings.TrimSpace(username)
|
|
if username == "" {
|
|
return nil, fmt.Errorf("username is required")
|
|
}
|
|
if password == "" {
|
|
return nil, fmt.Errorf("password is required")
|
|
}
|
|
if _, err := s.GetUserByUsername(username); err == nil {
|
|
return nil, ErrUserAlreadyExists
|
|
} else if !errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return nil, err
|
|
}
|
|
hash, err := hashPassword(password)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("hash user password: %w", err)
|
|
}
|
|
user := UserRecord{Username: username, PasswordHash: hash, Role: AdminRole}
|
|
if err := s.db.Create(&user).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
return &user, nil
|
|
}
|
|
|
|
func (s *Store) UpdateUserPassword(id uint64, password string) (*UserRecord, error) {
|
|
if id == 0 {
|
|
return nil, fmt.Errorf("user id is required")
|
|
}
|
|
if password == "" {
|
|
return nil, fmt.Errorf("password is required")
|
|
}
|
|
user, err := s.GetUserByID(id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
hash, err := hashPassword(password)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("hash user password: %w", err)
|
|
}
|
|
// 改密同时递增 pwd_version,使该用户所有已签发 session 立即失效。
|
|
if err := s.db.Model(&UserRecord{}).Where("id = ?", id).Updates(map[string]any{
|
|
"password_hash": hash,
|
|
"pwd_version": gorm.Expr("pwd_version + 1"),
|
|
"updated_at": time.Now(),
|
|
}).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
user.PasswordHash = hash
|
|
return s.GetUserByID(id)
|
|
}
|
|
|
|
func (s *Store) EnsureDefaultAdmin(username, password string) error {
|
|
var existing UserRecord
|
|
err := s.db.Where("username = ?", username).Take(&existing).Error
|
|
if err == nil {
|
|
return nil
|
|
}
|
|
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return err
|
|
}
|
|
hash, err := hashPassword(password)
|
|
if err != nil {
|
|
return fmt.Errorf("hash admin password: %w", err)
|
|
}
|
|
user := UserRecord{Username: username, PasswordHash: hash, Role: AdminRole}
|
|
if err := s.db.Create(&user).Error; err != nil {
|
|
return fmt.Errorf("create default admin user: %w", err)
|
|
}
|
|
return nil
|
|
}
|