internal/server/tls.go
Rama main · réplica de lectura del repositorio original.
package server
import (
"fmt"
"net"
"net/http"
"strings"
"armdash/internal/config"
)
const (
tlsCertKey = "core.tls_cert"
tlsKeyKey = "core.tls_key"
)
// TLSFiles returns the certificate and key paths, both empty when TLS is off.
// One without the other is an error rather than a quiet fall back to HTTP.
func TLSFiles(cfg *config.Config) (cert, key string, err error) {
cert, key = cfg.Get(tlsCertKey), cfg.Get(tlsKeyKey)
if (cert == "") != (key == "") {
return "", "", fmt.Errorf("%s and %s must be set together",
config.EnvName(tlsCertKey), config.EnvName(tlsKeyKey))
}
return cert, key, nil
}
// PlainHandler serves the plain HTTP listener once TLS is on. /metrics stays
// here so Prometheus keeps scraping over loopback without having to trust the
// certificate, everything else is sent to the HTTPS listener at tlsAddr.
//
// There is deliberately no Strict-Transport-Security header: a pin on a LAN
// host name signed by a private CA would lock out every device that does not
// trust that CA.
func (s *Server) PlainHandler(tlsAddr string) http.Handler {
_, port, err := net.SplitHostPort(tlsAddr)
if err != nil || port == "" {
port = "443"
}
mux := http.NewServeMux()
mux.HandleFunc("GET /metrics", func(w http.ResponseWriter, r *http.Request) { s.tree().handleMetrics(w, r) })
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
host := r.Host
if h, _, err := net.SplitHostPort(host); err == nil {
host = h
}
host = strings.Trim(host, "[]")
target := strings.TrimSuffix(net.JoinHostPort(host, port), ":443")
http.Redirect(w, r, "https://"+target+r.URL.RequestURI(), http.StatusMovedPermanently)
})
return mux
}