- Add Access-Control-Expose-Headers to allow frontend to read X-CSRF-Token response header - Implement proactive CSRF token issuance on GET requests when session exists but CSRF cookie is missing - Ensures frontend always has valid CSRF token before making POST requests - Fixes 403 Forbidden errors when toggling system settings This resolves CSRF validation failures that occurred when CSRF tokens expired or were missing while valid sessions existed.
99 lines
2.2 KiB
Go
99 lines
2.2 KiB
Go
package monitoring
|
|
|
|
import (
|
|
"context"
|
|
stderrors "errors"
|
|
"sync"
|
|
|
|
"github.com/rcourtman/pulse-go-rewrite/internal/models"
|
|
)
|
|
|
|
var (
|
|
// ErrTemperatureMonitoringDisabled indicates that temperature polling is disabled globally.
|
|
ErrTemperatureMonitoringDisabled = stderrors.New("temperature monitoring disabled")
|
|
// ErrTemperatureCollectorUnavailable indicates the collector could not be created or is misconfigured.
|
|
ErrTemperatureCollectorUnavailable = stderrors.New("temperature collector unavailable")
|
|
)
|
|
|
|
// TemperatureService defines the contract used by the monitor to collect temperature data.
|
|
type TemperatureService interface {
|
|
Enabled() bool
|
|
Collect(ctx context.Context, host, nodeName string) (*models.Temperature, error)
|
|
Enable()
|
|
Disable()
|
|
}
|
|
|
|
type temperatureService struct {
|
|
mu sync.RWMutex
|
|
enabled bool
|
|
user string
|
|
keyPath string
|
|
collector *TemperatureCollector
|
|
}
|
|
|
|
func newTemperatureService(enabled bool, user, keyPath string) TemperatureService {
|
|
return &temperatureService{
|
|
enabled: enabled,
|
|
user: user,
|
|
keyPath: keyPath,
|
|
}
|
|
}
|
|
|
|
func (s *temperatureService) Enabled() bool {
|
|
s.mu.RLock()
|
|
defer s.mu.RUnlock()
|
|
return s.enabled
|
|
}
|
|
|
|
func (s *temperatureService) Enable() {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
|
|
if s.enabled {
|
|
return
|
|
}
|
|
|
|
s.enabled = true
|
|
if s.collector == nil && s.user != "" && s.keyPath != "" {
|
|
s.collector = NewTemperatureCollector(s.user, s.keyPath)
|
|
}
|
|
}
|
|
|
|
func (s *temperatureService) Disable() {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
|
|
s.enabled = false
|
|
s.collector = nil
|
|
}
|
|
|
|
func (s *temperatureService) Collect(ctx context.Context, host, nodeName string) (*models.Temperature, error) {
|
|
s.mu.RLock()
|
|
enabled := s.enabled
|
|
collector := s.collector
|
|
s.mu.RUnlock()
|
|
|
|
if !enabled {
|
|
return nil, ErrTemperatureMonitoringDisabled
|
|
}
|
|
|
|
if collector == nil {
|
|
s.mu.Lock()
|
|
if s.enabled && s.collector == nil && s.user != "" && s.keyPath != "" {
|
|
s.collector = NewTemperatureCollector(s.user, s.keyPath)
|
|
}
|
|
collector = s.collector
|
|
enabled = s.enabled
|
|
s.mu.Unlock()
|
|
|
|
if !enabled {
|
|
return nil, ErrTemperatureMonitoringDisabled
|
|
}
|
|
}
|
|
|
|
if collector == nil {
|
|
return nil, ErrTemperatureCollectorUnavailable
|
|
}
|
|
|
|
return collector.CollectTemperature(ctx, host, nodeName)
|
|
}
|