Pulse/pkg/tlsutil/fingerprint.go
Pulse Monitor 7f5dae9b05 feat: Implement security, type safety, and error handling improvements
Security Enhancements:
- Add TLS fingerprint verification for Proxmox and PBS clients
- Create shared tlsutil package for secure TLS handling
- Implement proper CORS checking for WebSocket connections
- Add configurable allowed origins for WebSocket hub

Type Safety Improvements:
- Replace all TypeScript 'any' types with proper interfaces
- Add proper types for connectionHealth, apiCallDuration, metrics values
- Create typed BackupTask and StorageBackup interfaces
- Ensure all TypeScript code passes strict type checking

Error Handling Enhancements:
- Add comprehensive error handling middleware for API routes
- Implement structured error responses with proper status codes
- Add error boundaries to critical frontend components
- Fix WebSocket upgrade issues by preserving http.Hijacker interface
- Implement storage details endpoint (was TODO)

Code Quality:
- Fix Go vet mutex copy issues by creating StateSnapshot type
- Update ToFrontend() to use pointer receiver
- Ensure all code compiles without warnings
- Add proper error recovery and retry mechanisms

All changes tested and verified to work correctly.
2025-07-29 17:53:51 +00:00

59 lines
No EOL
1.7 KiB
Go

package tlsutil
import (
"crypto/sha256"
"crypto/tls"
"crypto/x509"
"encoding/hex"
"fmt"
"net/http"
"strings"
"time"
)
// FingerprintVerifier creates a custom TLS config that verifies server certificate fingerprint
func FingerprintVerifier(fingerprint string) *tls.Config {
// Normalize fingerprint (remove colons, convert to lowercase)
expectedFingerprint := strings.ToLower(strings.ReplaceAll(fingerprint, ":", ""))
return &tls.Config{
InsecureSkipVerify: true, // We'll do our own verification
VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
if len(rawCerts) == 0 {
return fmt.Errorf("no certificates presented by server")
}
// Calculate SHA256 fingerprint of the leaf certificate
fingerprint := sha256.Sum256(rawCerts[0])
actualFingerprint := hex.EncodeToString(fingerprint[:])
if actualFingerprint != expectedFingerprint {
return fmt.Errorf("certificate fingerprint mismatch: expected %s, got %s",
expectedFingerprint, actualFingerprint)
}
return nil
},
}
}
// CreateHTTPClient creates an HTTP client with appropriate TLS configuration
func CreateHTTPClient(verifySSL bool, fingerprint string) *http.Client {
transport := &http.Transport{
Proxy: http.ProxyFromEnvironment,
}
if !verifySSL && fingerprint == "" {
// Insecure mode - skip all verification
transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
} else if fingerprint != "" {
// Fingerprint verification mode
transport.TLSClientConfig = FingerprintVerifier(fingerprint)
}
// else: default secure mode with system CA verification
return &http.Client{
Transport: transport,
Timeout: 30 * time.Second,
}
}