Changeset 0.9.2 (#52)
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
||||
"encoding/hex"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -77,8 +78,8 @@ func (h *AuthHandler) Register(c *gin.Context) {
|
||||
defaultActive, _ := h.stores.Policies.GetBool(c.Request.Context(), "default_user_active")
|
||||
|
||||
user := &models.User{
|
||||
Username: req.Username,
|
||||
Email: req.Email,
|
||||
Username: strings.ToLower(req.Username),
|
||||
Email: strings.ToLower(req.Email),
|
||||
PasswordHash: string(hash),
|
||||
Role: models.UserRoleUser,
|
||||
IsActive: defaultActive,
|
||||
@@ -269,8 +270,8 @@ func BootstrapAdmin(cfg *config.Config, s store.Stores) {
|
||||
}
|
||||
|
||||
user := &models.User{
|
||||
Username: cfg.AdminUsername,
|
||||
Email: email,
|
||||
Username: strings.ToLower(cfg.AdminUsername),
|
||||
Email: strings.ToLower(email),
|
||||
PasswordHash: string(hash),
|
||||
Role: models.UserRoleAdmin,
|
||||
IsActive: true,
|
||||
@@ -283,6 +284,83 @@ func BootstrapAdmin(cfg *config.Config, s store.Stores) {
|
||||
log.Printf(" ✅ Admin user '%s' created", cfg.AdminUsername)
|
||||
}
|
||||
|
||||
// SeedUsers creates or updates users from the SEED_USERS env var.
|
||||
// Format: "user:pass:role,user2:pass2:role2" where role is "admin" or "user".
|
||||
// Upsert: existing users get their password and role refreshed on every restart.
|
||||
// Gated to non-production environments.
|
||||
func SeedUsers(cfg *config.Config, s store.Stores) {
|
||||
if cfg.SeedUsers == "" {
|
||||
log.Printf(" ℹ SEED_USERS not set, skipping")
|
||||
return
|
||||
}
|
||||
|
||||
if cfg.Environment == "production" {
|
||||
log.Printf("⚠ SEED_USERS ignored in production environment")
|
||||
return
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
entries := strings.Split(cfg.SeedUsers, ",")
|
||||
log.Printf(" 🌱 SEED_USERS: %d entries to process", len(entries))
|
||||
|
||||
for _, entry := range entries {
|
||||
entry = strings.TrimSpace(entry)
|
||||
if entry == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
parts := strings.SplitN(entry, ":", 3)
|
||||
if len(parts) < 2 {
|
||||
log.Printf("⚠ Seed user skipped (bad format, want user:pass[:role]): %q", entry)
|
||||
continue
|
||||
}
|
||||
|
||||
username := strings.ToLower(strings.TrimSpace(parts[0]))
|
||||
password := strings.TrimSpace(parts[1])
|
||||
role := models.UserRoleUser
|
||||
if len(parts) >= 3 && strings.TrimSpace(parts[2]) == "admin" {
|
||||
role = models.UserRoleAdmin
|
||||
}
|
||||
|
||||
if username == "" || password == "" {
|
||||
log.Printf("⚠ Seed user skipped (empty username or password)")
|
||||
continue
|
||||
}
|
||||
|
||||
hash, err := bcrypt.GenerateFromPassword([]byte(password), bcryptCost)
|
||||
if err != nil {
|
||||
log.Printf("⚠ Seed user '%s' skipped (hash error): %v", username, err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Upsert: update password+role if user exists, create if not
|
||||
existing, _ := s.Users.GetByUsername(ctx, username)
|
||||
if existing != nil {
|
||||
s.Users.Update(ctx, existing.ID, map[string]interface{}{
|
||||
"password_hash": string(hash),
|
||||
"role": role,
|
||||
"is_active": true,
|
||||
})
|
||||
log.Printf(" 🌱 Seed user '%s' updated (role=%s)", username, role)
|
||||
continue
|
||||
}
|
||||
|
||||
user := &models.User{
|
||||
Username: username,
|
||||
Email: username + "@switchboard.local",
|
||||
PasswordHash: string(hash),
|
||||
Role: role,
|
||||
IsActive: true,
|
||||
}
|
||||
|
||||
if err := s.Users.Create(ctx, user); err != nil {
|
||||
log.Printf("⚠ Seed user '%s' failed: %v", username, err)
|
||||
continue
|
||||
}
|
||||
log.Printf(" 🌱 Seed user '%s' created (role=%s, active=true)", username, role)
|
||||
}
|
||||
}
|
||||
|
||||
// IsRegistrationEnabled checks the platform policy.
|
||||
func IsRegistrationEnabled(s store.Stores) bool {
|
||||
val, _ := s.Policies.GetBool(context.Background(), "allow_registration")
|
||||
|
||||
Reference in New Issue
Block a user