mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-07-14 16:26:57 +08:00
fix(auth): single-user deployment by default, no open registration
Registration logic redesigned: - Empty DB (first-time setup): registration always open, no config needed - After first user exists: registration closed by default - Multi-user opt-in: set REGISTRATION_ENABLED=true + MAX_USERS=N in .env Config defaults changed: - RegistrationEnabled: true → false (closed after first user) - MaxUsers: 10 → 1 (single-user deployment default) This eliminates the confusion of multiple users appearing in a personal deployment where Telegram is bound to a single admin account.
This commit is contained in:
@@ -3152,14 +3152,33 @@ func (s *Server) handleLogout(c *gin.Context) {
|
|||||||
c.JSON(http.StatusOK, gin.H{"message": "Logged out"})
|
c.JSON(http.StatusOK, gin.H{"message": "Logged out"})
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleRegister Handle user registration request
|
// handleRegister Handle user registration request.
|
||||||
|
// Registration is only open when no users exist yet (first-time setup) OR when
|
||||||
|
// explicitly enabled via REGISTRATION_ENABLED=true env var AND within MAX_USERS limit.
|
||||||
func (s *Server) handleRegister(c *gin.Context) {
|
func (s *Server) handleRegister(c *gin.Context) {
|
||||||
// Check if registration is allowed
|
userCount, err := s.store.User().Count()
|
||||||
if !config.Get().RegistrationEnabled {
|
if err != nil {
|
||||||
c.JSON(http.StatusForbidden, gin.H{"error": "Registration is disabled"})
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to check user count"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// First-time setup: allow registration when DB is empty, regardless of config.
|
||||||
|
firstTimeSetup := userCount == 0
|
||||||
|
|
||||||
|
if !firstTimeSetup {
|
||||||
|
// After first user exists: require explicit opt-in via REGISTRATION_ENABLED=true.
|
||||||
|
if !config.Get().RegistrationEnabled {
|
||||||
|
c.JSON(http.StatusForbidden, gin.H{"error": "Registration is disabled"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Enforce max users limit.
|
||||||
|
maxUsers := config.Get().MaxUsers
|
||||||
|
if maxUsers > 0 && userCount >= maxUsers {
|
||||||
|
c.JSON(http.StatusForbidden, gin.H{"error": "Maximum number of users reached"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var req struct {
|
var req struct {
|
||||||
Email string `json:"email" binding:"required,email"`
|
Email string `json:"email" binding:"required,email"`
|
||||||
Password string `json:"password" binding:"required,min=6"`
|
Password string `json:"password" binding:"required,min=6"`
|
||||||
@@ -3171,26 +3190,12 @@ func (s *Server) handleRegister(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if email already exists
|
// Check if email already exists
|
||||||
_, err := s.store.User().GetByEmail(req.Email)
|
_, err = s.store.User().GetByEmail(req.Email)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
c.JSON(http.StatusConflict, gin.H{"error": "Email already registered"})
|
c.JSON(http.StatusConflict, gin.H{"error": "Email already registered"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check max users limit (only for new users)
|
|
||||||
maxUsers := config.Get().MaxUsers
|
|
||||||
if maxUsers > 0 {
|
|
||||||
userCount, err := s.store.User().Count()
|
|
||||||
if err != nil {
|
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to check user count"})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if userCount >= maxUsers {
|
|
||||||
c.JSON(http.StatusForbidden, gin.H{"error": "Not on whitelist"})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate password hash
|
// Generate password hash
|
||||||
passwordHash, err := auth.HashPassword(req.Password)
|
passwordHash, err := auth.HashPassword(req.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -55,8 +55,8 @@ type Config struct {
|
|||||||
func Init() {
|
func Init() {
|
||||||
cfg := &Config{
|
cfg := &Config{
|
||||||
APIServerPort: 8080,
|
APIServerPort: 8080,
|
||||||
RegistrationEnabled: true,
|
RegistrationEnabled: false, // Default: closed after first user registers (first-time setup always allowed)
|
||||||
MaxUsers: 10, // Default: 10 users allowed
|
MaxUsers: 1, // Default: single-user deployment
|
||||||
ExperienceImprovement: true, // Default: enabled to help improve the product
|
ExperienceImprovement: true, // Default: enabled to help improve the product
|
||||||
// Database defaults
|
// Database defaults
|
||||||
DBType: "sqlite",
|
DBType: "sqlite",
|
||||||
|
|||||||
Reference in New Issue
Block a user