4d34c6d31a
CI / test (push) Failing after 12m45s
- Add AdminUser model (bcrypt hashed passwords) and admin_users table - Add AdminJWTService for HS256 JWT sessions (24h TTL) - Add AdminSessionAuth middleware for /api/v1/admin/* routes - Add admin handlers: login, logout, me, change-password, users CRUD - Keys and model management routes now require admin JWT session - Remove ADMIN_TOKEN, add ADMIN_USERNAME, ADMIN_PASSWORD env vars - Update frontend: username/password login, admin_session storage, AdminUsers CRUD view
60 lines
1.3 KiB
Go
60 lines
1.3 KiB
Go
package db
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"encoding/hex"
|
|
"log/slog"
|
|
"strings"
|
|
|
|
"golang.org/x/crypto/bcrypt"
|
|
"github.com/google/uuid"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
func generateRandomPassword(length int) (string, error) {
|
|
bytes := make([]byte, length)
|
|
if _, err := rand.Read(bytes); err != nil {
|
|
return "", err
|
|
}
|
|
return hex.EncodeToString(bytes)[:length], nil
|
|
}
|
|
|
|
func SeedAdminUser(db *gorm.DB, username, password string) error {
|
|
var count int64
|
|
db.Model(&AdminUser{}).Count(&count)
|
|
if count > 0 {
|
|
slog.Info("admin user already exists, skipping seed")
|
|
return nil
|
|
}
|
|
|
|
pwd := password
|
|
if pwd == "" {
|
|
var err error
|
|
pwd, err = generateRandomPassword(24)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
slog.Warn("no ADMIN_PASSWORD set — generated random password (save this, it won't be shown again)")
|
|
}
|
|
|
|
hash, err := bcrypt.GenerateFromPassword([]byte(pwd), bcrypt.DefaultCost)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
admin := AdminUser{
|
|
ID: uuid.New(),
|
|
Username: strings.ToLower(username),
|
|
PasswordHash: string(hash),
|
|
IsActive: true,
|
|
}
|
|
|
|
if err := db.Create(&admin).Error; err != nil {
|
|
return err
|
|
}
|
|
|
|
slog.Info("admin user seeded", "username", admin.Username)
|
|
slog.Warn("ADMIN USER: username=" + username + " password=" + pwd + " (save this, it won't be shown again)")
|
|
return nil
|
|
}
|