diff --git a/VERSION b/VERSION index 59aa759..599d6ff 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.1.124 +1.1.125 diff --git a/cmd/edgeguard-api/main.go b/cmd/edgeguard-api/main.go index 9fccb5f..4dc6502 100644 --- a/cmd/edgeguard-api/main.go +++ b/cmd/edgeguard-api/main.go @@ -60,7 +60,7 @@ import ( usersvc "git.netcell-it.de/projekte/edgeguard-native/internal/services/users" ) -var version = "1.1.124" +var version = "1.1.125" func main() { addr := os.Getenv("EDGEGUARD_API_ADDR") diff --git a/cmd/edgeguard-ctl/main.go b/cmd/edgeguard-ctl/main.go index 1a0b934..f1c0bb8 100644 --- a/cmd/edgeguard-ctl/main.go +++ b/cmd/edgeguard-ctl/main.go @@ -11,7 +11,7 @@ import ( "git.netcell-it.de/projekte/edgeguard-native/internal/services/setup" ) -var version = "1.1.124" +var version = "1.1.125" const usage = `edgeguard-ctl — EdgeGuard CLI diff --git a/cmd/edgeguard-scheduler/main.go b/cmd/edgeguard-scheduler/main.go index 757aa86..c3754f3 100644 --- a/cmd/edgeguard-scheduler/main.go +++ b/cmd/edgeguard-scheduler/main.go @@ -41,7 +41,7 @@ import ( "git.netcell-it.de/projekte/edgeguard-native/internal/services/tlscerts" ) -var version = "1.1.124" +var version = "1.1.125" const ( // renewTickInterval — how often we re-evaluate expiring certs. @@ -441,7 +441,7 @@ func runMemoryCheck(ctx context.Context, a *alerts.Service, d *dedupe) { " • Unbound-Cache zu groß (rrset-cache-size in /etc/edgeguard/unbound/unbound.conf)\n"+ " • Squid cache_mem zu groß (64 MB default)\n"+ " • PostgreSQL shared_buffers (default ~128 MB)\n"+ - " • Prozesse prüfen: ps aux --sort=-%mem | head -10", + " • Prozesse prüfen: ps aux --sort=-%%mem | head -10", usedPct, usedGB, totalGB) if _, err := a.Fire(ctx, "mem.high", sev, title, desc); err != nil { slog.Warn("scheduler: memory-check alert fire failed", "error", err) diff --git a/internal/handlers/auth.go b/internal/handlers/auth.go index 7e7ced6..f418a3c 100644 --- a/internal/handlers/auth.go +++ b/internal/handlers/auth.go @@ -194,12 +194,49 @@ type changePasswordRequest struct { // braucht das hier das current_password als Confirmation — verhindert // dass eine kompromittierte Session den Account übernimmt ohne dass // das alte Passwort bekannt ist. +// +// Lookup-Reihenfolge: 1) DB users-Tabelle (alle multi-user-Accounts), +// 2) setup-store Admin-Fallback (Legacy / pre-DB). Beim Setup-Admin +// werden beide Stores synchron gehalten. func (h *AuthHandler) ChangePassword(c *gin.Context) { var req changePasswordRequest if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, err) return } + + tok := CurrentToken(c) + if tok == nil { + response.Unauthorized(c, nil) + return + } + + // 1. DB-backed user (alle via User-Management erstellten Accounts). + if h.Users != nil { + u, hash, dbErr := h.Users.FindByEmail(c.Request.Context(), tok.Actor) + if dbErr == nil { + if !usersvc.VerifyPassword(hash, req.CurrentPassword) { + response.Unauthorized(c, errors.New("invalid_current_password")) + return + } + if err := h.Users.SetPassword(c.Request.Context(), u.ID, req.NewPassword); err != nil { + response.Internal(c, err) + return + } + // Setup-Store-Admin synchron halten, falls gleiche E-Mail. + if st, _ := h.Setup.Load(); st != nil && strings.EqualFold(st.AdminEmail, tok.Actor) { + _ = h.Setup.SetAdminPassword(req.NewPassword) + } + if h.Audit != nil { + _ = h.Audit.Log(c.Request.Context(), actorOf(c), "auth.password.change", + tok.Actor, gin.H{"actor": actorOf(c)}, h.NodeID) + } + response.OK(c, gin.H{"ok": true}) + return + } + } + + // 2. Fallback: setup-store Admin (vor DB-Migration oder nicht migriert). st, err := h.Setup.Load() if err != nil { response.Internal(c, err) @@ -209,10 +246,6 @@ func (h *AuthHandler) ChangePassword(c *gin.Context) { response.Err(c, http.StatusServiceUnavailable, errors.New("setup_required")) return } - // Authorisierte Session ist nicht automatisch der Admin (Phase 4 - // admin_users-Tabelle könnte mehrere Rollen haben). v1: aktuell - // nur der eine Admin-User; trotzdem prüfen wir das current_password - // gegen die persistierte Hash. if !st.VerifyAdminPassword(req.CurrentPassword) { response.Unauthorized(c, errors.New("invalid_current_password")) return @@ -225,10 +258,6 @@ func (h *AuthHandler) ChangePassword(c *gin.Context) { _ = h.Audit.Log(c.Request.Context(), actorOf(c), "auth.password.change", st.AdminEmail, gin.H{"actor": actorOf(c)}, h.NodeID) } - // Neue Session ausstellen — alte Cookie zeigt auf ein Token das - // noch gültig ist; das ist OK für UX (kein erzwungener Logout), - // sicherheitsbewusster: clearSession + force re-login. Wir - // halten's hier ruhig. response.OK(c, gin.H{"ok": true}) }