v0.7.0: Phase 1 — Authentication, Persistence & Settings Page
- New settings.json persistence layer (internal/settings/settings.go) - Atomic write (tmp + rename), thread-safe with sync.RWMutex - Stores password hash overrides and DB validation cache - Auto-creates on first save, graceful handling if missing - Auth improvements - Password resolution priority: settings.json > controller.yaml > none - Session duration extended to 7 days (was 24h) - ?next= redirect after session expiry (returns to original page) - Flash messages on login page (used after password change) - Conditional logout link (hidden when auth disabled) - Session invalidation on password change - New Settings page (/settings) - Read-only system config display (customer, domain, git, backup, monitoring) - Password change form with validation (min 8 chars, match check) - Sidebar "Beállítások" item pinned to bottom above version - DB validation persistence - Validation results saved to settings.json after each dump - Cached data survives container restarts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -13,6 +13,7 @@ import (
|
||||
"gitea.dooplex.hu/admin/felhom-controller/internal/backup"
|
||||
"gitea.dooplex.hu/admin/felhom-controller/internal/config"
|
||||
"gitea.dooplex.hu/admin/felhom-controller/internal/scheduler"
|
||||
"gitea.dooplex.hu/admin/felhom-controller/internal/settings"
|
||||
"gitea.dooplex.hu/admin/felhom-controller/internal/stacks"
|
||||
"gitea.dooplex.hu/admin/felhom-controller/internal/system"
|
||||
)
|
||||
@@ -23,6 +24,7 @@ type Server struct {
|
||||
cpuCollector *system.CPUCollector
|
||||
backupMgr *backup.Manager
|
||||
scheduler *scheduler.Scheduler
|
||||
settings *settings.Settings
|
||||
logger *log.Logger
|
||||
version string
|
||||
tmpl *template.Template
|
||||
@@ -32,13 +34,14 @@ type Server struct {
|
||||
done chan struct{}
|
||||
}
|
||||
|
||||
func NewServer(cfg *config.Config, stackMgr *stacks.Manager, cpuCollector *system.CPUCollector, backupMgr *backup.Manager, sched *scheduler.Scheduler, logger *log.Logger, version string) *Server {
|
||||
func NewServer(cfg *config.Config, stackMgr *stacks.Manager, cpuCollector *system.CPUCollector, backupMgr *backup.Manager, sched *scheduler.Scheduler, sett *settings.Settings, logger *log.Logger, version string) *Server {
|
||||
s := &Server{
|
||||
cfg: cfg,
|
||||
stackMgr: stackMgr,
|
||||
cpuCollector: cpuCollector,
|
||||
backupMgr: backupMgr,
|
||||
scheduler: sched,
|
||||
settings: sett,
|
||||
logger: logger,
|
||||
version: version,
|
||||
sessions: make(map[string]*session),
|
||||
@@ -46,6 +49,16 @@ func NewServer(cfg *config.Config, stackMgr *stacks.Manager, cpuCollector *syste
|
||||
}
|
||||
s.loadTemplates()
|
||||
go s.cleanupSessions()
|
||||
|
||||
// Log auth source on startup
|
||||
if sett != nil && sett.GetPasswordHash() != "" {
|
||||
logger.Printf("[INFO] Auth: using password from settings.json")
|
||||
} else if cfg.Web.PasswordHash != "" {
|
||||
logger.Printf("[INFO] Auth: using password from controller.yaml")
|
||||
} else {
|
||||
logger.Printf("[INFO] Auth: no password configured — dashboard is open")
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
@@ -68,6 +81,10 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
s.backupsHandler(w, r)
|
||||
case path == "/monitoring":
|
||||
s.monitoringHandler(w, r)
|
||||
case path == "/settings":
|
||||
s.settingsHandler(w, r)
|
||||
case path == "/settings/password" && r.Method == http.MethodPost:
|
||||
s.settingsPasswordHandler(w, r)
|
||||
case strings.HasPrefix(path, "/stacks/") && strings.HasSuffix(path, "/logs"):
|
||||
name := strings.TrimPrefix(path, "/stacks/")
|
||||
name = strings.TrimSuffix(name, "/logs")
|
||||
|
||||
Reference in New Issue
Block a user