feat: Add detection for legacy SSH temperature monitoring
Added automatic detection to alert users when they're using the old SSH-in-container method for temperature monitoring so they can upgrade to the secure proxy architecture. **Detection Logic:** - Checks if Pulse is running in a container (Docker or LXC) - Checks if SSH keys exist in data directory (/etc/pulse/.ssh) - Checks if pulse-sensor-proxy socket is NOT available - Sets legacySSHDetected and recommendProxyUpgrade flags in health endpoint **API Changes:** - Added fields to HealthResponse: - legacySSHDetected: true when old method detected - recommendProxyUpgrade: true when upgrade is recommended - proxyInstallScriptAvailable: always true **Use Case:** Users who set up temperature monitoring before the proxy feature won't know they should upgrade. This detection allows the frontend to show a banner prompting them to re-run the setup script to migrate to the secure proxy architecture. **Frontend Integration (to be added):** Frontend can poll /api/health and show a dismissible banner similar to UpdateBanner when legacySSHDetected is true, with a button to view the setup script. Addresses #123
This commit is contained in:
parent
8d6ab4113d
commit
6d56917cd9
2 changed files with 65 additions and 6 deletions
|
|
@ -1128,6 +1128,56 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
}), allowEmbedding, allowedEmbedOrigins).ServeHTTP(w, req)
|
||||
}
|
||||
|
||||
// detectLegacySSH checks if Pulse is using legacy SSH for temperature monitoring
|
||||
func (r *Router) detectLegacySSH() (legacyDetected, recommendProxy bool) {
|
||||
// Check if running in a container
|
||||
inContainer := false
|
||||
if _, err := os.Stat("/.dockerenv"); err == nil {
|
||||
inContainer = true
|
||||
} else if data, err := os.ReadFile("/proc/1/cgroup"); err == nil {
|
||||
if strings.Contains(string(data), "docker") || strings.Contains(string(data), "lxc") {
|
||||
inContainer = true
|
||||
}
|
||||
}
|
||||
|
||||
// If not in container, no need for proxy
|
||||
if !inContainer {
|
||||
return false, false
|
||||
}
|
||||
|
||||
// Check if SSH keys are configured in the data directory
|
||||
sshKeysConfigured := false
|
||||
|
||||
// Check for SSH keys in the configured data directory
|
||||
dataDir := r.config.DataPath
|
||||
if dataDir == "" {
|
||||
dataDir = "/etc/pulse"
|
||||
}
|
||||
|
||||
sshPrivKeyPath := filepath.Join(dataDir, ".ssh", "id_ed25519")
|
||||
if _, err := os.Stat(sshPrivKeyPath); err == nil {
|
||||
sshKeysConfigured = true
|
||||
}
|
||||
|
||||
// Also check for RSA keys
|
||||
sshPrivKeyPathRSA := filepath.Join(dataDir, ".ssh", "id_rsa")
|
||||
if _, err := os.Stat(sshPrivKeyPathRSA); err == nil {
|
||||
sshKeysConfigured = true
|
||||
}
|
||||
|
||||
// If SSH keys exist, check if proxy is running
|
||||
if sshKeysConfigured {
|
||||
// Check if pulse-sensor-proxy is available via unix socket
|
||||
proxySocket := "/run/pulse-sensor-proxy/sensor.sock"
|
||||
if _, err := os.Stat(proxySocket); err != nil {
|
||||
// Socket doesn't exist - legacy SSH method detected
|
||||
return true, true
|
||||
}
|
||||
}
|
||||
|
||||
return false, false
|
||||
}
|
||||
|
||||
// handleHealth handles health check requests
|
||||
func (r *Router) handleHealth(w http.ResponseWriter, req *http.Request) {
|
||||
if req.Method != http.MethodGet && req.Method != http.MethodHead {
|
||||
|
|
@ -1135,10 +1185,16 @@ func (r *Router) handleHealth(w http.ResponseWriter, req *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
// Detect legacy SSH setup
|
||||
legacySSH, recommendProxy := r.detectLegacySSH()
|
||||
|
||||
response := HealthResponse{
|
||||
Status: "healthy",
|
||||
Timestamp: time.Now().Unix(),
|
||||
Uptime: time.Since(r.monitor.GetStartTime()).Seconds(),
|
||||
Status: "healthy",
|
||||
Timestamp: time.Now().Unix(),
|
||||
Uptime: time.Since(r.monitor.GetStartTime()).Seconds(),
|
||||
LegacySSHDetected: legacySSH,
|
||||
RecommendProxyUpgrade: recommendProxy,
|
||||
ProxyInstallScriptAvailable: true, // Install script is always available
|
||||
}
|
||||
|
||||
if err := utils.WriteJSONResponse(w, response); err != nil {
|
||||
|
|
|
|||
|
|
@ -11,9 +11,12 @@ import (
|
|||
|
||||
// HealthResponse represents the health check response
|
||||
type HealthResponse struct {
|
||||
Status string `json:"status"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
Uptime float64 `json:"uptime"`
|
||||
Status string `json:"status"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
Uptime float64 `json:"uptime"`
|
||||
LegacySSHDetected bool `json:"legacySSHDetected,omitempty"`
|
||||
RecommendProxyUpgrade bool `json:"recommendProxyUpgrade,omitempty"`
|
||||
ProxyInstallScriptAvailable bool `json:"proxyInstallScriptAvailable,omitempty"`
|
||||
}
|
||||
|
||||
// VersionResponse represents version information
|
||||
|
|
|
|||
Loading…
Reference in a new issue