From 4b1d0013c04e0469dbfe9d6dbf155ee4bbee2850 Mon Sep 17 00:00:00 2001 From: rcourtman Date: Sun, 19 Oct 2025 08:31:05 +0000 Subject: [PATCH] fix: allow setup token auth for SSH config endpoint The ssh-config endpoint was using RequireAuth which only accepts Pulse API tokens, but the setup script sends a temporary setup token via the auth_token parameter. Updated to follow the same pattern as verify-temperature-ssh: check setup token first, then fall back to API auth. This fixes the 401 error when the setup script tries to configure ProxyJump for containerized Pulse deployments. --- internal/api/router.go | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/internal/api/router.go b/internal/api/router.go index 2c68bc2..a465adf 100644 --- a/internal/api/router.go +++ b/internal/api/router.go @@ -849,7 +849,7 @@ func (r *Router) setupRoutes() { r.systemSettingsHandler = NewSystemSettingsHandler(r.config, r.persistence, r.wsHub, r.monitor, r.reloadSystemSettings) r.mux.HandleFunc("/api/system/settings", r.systemSettingsHandler.HandleGetSystemSettings) r.mux.HandleFunc("/api/system/settings/update", r.systemSettingsHandler.HandleUpdateSystemSettings) - r.mux.HandleFunc("/api/system/ssh-config", RequireAuth(r.config, r.systemSettingsHandler.HandleSSHConfig)) + r.mux.HandleFunc("/api/system/ssh-config", r.handleSSHConfig) r.mux.HandleFunc("/api/system/verify-temperature-ssh", r.handleVerifyTemperatureSSH) r.mux.HandleFunc("/api/system/proxy-public-key", r.handleProxyPublicKey) // Old API token endpoints removed - now using /api/security/regenerate-token @@ -907,6 +907,38 @@ func (r *Router) handleVerifyTemperatureSSH(w http.ResponseWriter, req *http.Req } } +// handleSSHConfig handles SSH config writes with setup token or API auth +func (r *Router) handleSSHConfig(w http.ResponseWriter, req *http.Request) { + if r.systemSettingsHandler == nil { + http.Error(w, "Service unavailable", http.StatusServiceUnavailable) + return + } + + // Check setup token first (for setup scripts) + if token := extractSetupToken(req); token != "" { + if r.configHandlers != nil && r.configHandlers.ValidateSetupToken(token) { + r.systemSettingsHandler.HandleSSHConfig(w, req) + return + } + } + + // Fall back to standard API authentication + if CheckAuth(r.config, w, req) { + r.systemSettingsHandler.HandleSSHConfig(w, req) + return + } + + log.Warn(). + Str("ip", req.RemoteAddr). + Str("path", req.URL.Path). + Str("method", req.Method). + Msg("Unauthorized access attempt (ssh-config)") + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusUnauthorized) + w.Write([]byte(`{"error":"Authentication required"}`)) +} + // handleProxyPublicKey returns the temperature proxy's public SSH key (public endpoint) func (r *Router) handleProxyPublicKey(w http.ResponseWriter, req *http.Request) { if req.Method != http.MethodGet {