Fix credentials leaking in debug logs (#4)

Add a secret-masking slog.Handler that automatically replaces registered
passwords with "***" in all log output. Secrets are registered per-scan
when a discovery request arrives and unregistered when it completes.

This approach masks credentials everywhere they appear in logs — URL
userinfo, query parameters, path segments, and Go HTTP error messages —
without modifying any business logic in scanner, builder, tester, or
ONVIF components. API responses are unaffected and still return full
URLs with credentials for frontend use.
This commit is contained in:
eduard256
2026-03-20 11:03:01 +00:00
parent e269e243da
commit 8cf05a1576
7 changed files with 422 additions and 9 deletions
+11
View File
@@ -7,6 +7,7 @@ import (
"github.com/go-playground/validator/v10"
"github.com/eduard256/Strix/internal/camera/discovery"
"github.com/eduard256/Strix/internal/models"
"github.com/eduard256/Strix/internal/utils/logger"
"github.com/eduard256/Strix/pkg/sse"
)
@@ -15,6 +16,7 @@ type DiscoverHandler struct {
scanner *discovery.Scanner
sseServer *sse.Server
validator *validator.Validate
secrets *logger.SecretStore
logger interface{ Debug(string, ...any); Error(string, error, ...any); Info(string, ...any) }
}
@@ -22,11 +24,13 @@ type DiscoverHandler struct {
func NewDiscoverHandler(
scanner *discovery.Scanner,
sseServer *sse.Server,
secrets *logger.SecretStore,
logger interface{ Debug(string, ...any); Error(string, error, ...any); Info(string, ...any) },
) *DiscoverHandler {
return &DiscoverHandler{
scanner: scanner,
sseServer: sseServer,
secrets: secrets,
validator: validator.New(),
logger: logger,
}
@@ -65,6 +69,13 @@ func (h *DiscoverHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
}
// Register password as a secret so it gets masked in all log output.
// The secret is automatically unregistered when the request completes.
if req.Password != "" {
h.secrets.Add(req.Password)
defer h.secrets.Remove(req.Password)
}
h.logger.Info("stream discovery requested",
"target", req.Target,
"model", req.Model,