package auth import ( "encoding/json" "net/http" "gitea.perlbach24.de/scripte/nexarch/internal/user" ) // ChangePasswordHandler stellt die Passwortaenderung fuer den bereits // angemeldeten Benutzer bereit (IAM-08 Akzeptanzkriterium 2). Getrennt von // Handler (Login/Logout), weil hier zusaetzlich der TenantUserStore fuer das // Aktualisieren des Hashes gebraucht wird. type ChangePasswordHandler struct { users *user.TenantUserStore } func NewChangePasswordHandler(users *user.TenantUserStore) *ChangePasswordHandler { return &ChangePasswordHandler{users: users} } type changePasswordRequest struct { CurrentPassword string `json:"current_password"` NewPassword string `json:"new_password"` } // ChangePassword verlangt das aktuelle Passwort, bevor ein neues gesetzt wird // — ohne diese Pruefung koennte ein gekapertes, noch gueltiges Session-Cookie // allein zur vollstaendigen Kontoübernahme reichen (Passwort setzen, alte // Session unbrauchbar machen). Muss hinter RequireAuth haengen. func (h *ChangePasswordHandler) ChangePassword(w http.ResponseWriter, r *http.Request) { claims, ok := ClaimsFromContext(r.Context()) if !ok { http.Error(w, "nicht angemeldet", http.StatusUnauthorized) return } var req changePasswordRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { http.Error(w, "ungueltige Anfrage", http.StatusBadRequest) return } creds, err := h.users.GetByIDForAuth(r.Context(), claims.UserID) if err != nil { http.Error(w, "Aktuelles Passwort oder neues Passwort ungültig.", http.StatusBadRequest) return } if !VerifyPassword(creds.PasswordHash, req.CurrentPassword) { http.Error(w, "Aktuelles Passwort oder neues Passwort ungültig.", http.StatusBadRequest) return } newHash, err := HashPassword(req.NewPassword) if err != nil { http.Error(w, "Aktuelles Passwort oder neues Passwort ungültig.", http.StatusBadRequest) return } if err := h.users.SetPasswordHash(r.Context(), claims.UserID, newHash); err != nil { http.Error(w, "Passwort konnte nicht gespeichert werden.", http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) }