diff --git a/internal/api/ws/ws.go b/internal/api/ws/ws.go index 981d1b41..02c2f90c 100644 --- a/internal/api/ws/ws.go +++ b/internal/api/ws/ws.go @@ -11,7 +11,7 @@ import ( "github.com/AlexxIT/go2rtc/internal/api" "github.com/AlexxIT/go2rtc/internal/app" - "github.com/AlexxIT/go2rtc/pkg/core" + "github.com/AlexxIT/go2rtc/pkg/creds" "github.com/gorilla/websocket" "github.com/rs/zerolog" ) @@ -133,7 +133,7 @@ func apiWS(w http.ResponseWriter, r *http.Request) { if handler := wsHandlers[msg.Type]; handler != nil { go func() { if err = handler(tr, msg); err != nil { - errMsg := core.StripUserinfo(err.Error()) + errMsg := creds.SecretString(err.Error()) tr.Write(&Message{Type: "error", Value: msg.Type + ": " + errMsg}) } }() diff --git a/pkg/core/helpers.go b/pkg/core/helpers.go index 52b969a7..45bbd0d5 100644 --- a/pkg/core/helpers.go +++ b/pkg/core/helpers.go @@ -2,7 +2,6 @@ package core import ( "crypto/rand" - "regexp" "runtime" "strconv" "strings" @@ -93,14 +92,3 @@ func Caller() string { _, file, line, _ := runtime.Caller(1) return file + ":" + strconv.Itoa(line) } - -const ( - unreserved = `A-Za-z0-9-._~` - subdelims = `!$&'()*+,;=` - userinfo = unreserved + subdelims + `%:` -) - -func StripUserinfo(s string) string { - sanitizer := regexp.MustCompile(`://[` + userinfo + `]+@`) - return sanitizer.ReplaceAllString(s, `://***@`) -} diff --git a/pkg/creds/secrets.go b/pkg/creds/secrets.go index a9a0094e..95ab4828 100644 --- a/pkg/creds/secrets.go +++ b/pkg/creds/secrets.go @@ -3,6 +3,7 @@ package creds import ( "io" "net/http" + "regexp" "slices" "strings" "sync" @@ -27,6 +28,7 @@ func AddSecret(value string) { var secrets []string var secretsMu sync.Mutex var secretsReplacer *strings.Replacer +var userinfoRegexp *regexp.Regexp func getReplacer() *strings.Replacer { secretsMu.Lock() @@ -40,14 +42,33 @@ func getReplacer() *strings.Replacer { secretsReplacer = strings.NewReplacer(oldnew...) } + if userinfoRegexp == nil { + userinfoRegexp = regexp.MustCompile(`://[` + userinfo + `]+@`) + } + return secretsReplacer } +// Uniform Resource Identifier (URI) +// https://datatracker.ietf.org/doc/html/rfc3986 +const ( + unreserved = `A-Za-z0-9-._~` + subdelims = `!$&'()*+,;=` + userinfo = unreserved + subdelims + `%:` +) + func SecretString(s string) string { re := getReplacer() + s = userinfoRegexp.ReplaceAllString(s, `://***@`) return re.Replace(s) } +func SecretWrite(w io.Writer, s string) (n int, err error) { + re := getReplacer() + s = userinfoRegexp.ReplaceAllString(s, `://***@`) + return re.WriteString(w, s) +} + func SecretWriter(w io.Writer) io.Writer { return &secretWriter{w} } @@ -57,27 +78,17 @@ type secretWriter struct { } func (s *secretWriter) Write(b []byte) (int, error) { - re := getReplacer() - return re.WriteString(s.w, string(b)) -} - -type secretResponse struct { - w http.ResponseWriter -} - -func (s *secretResponse) Header() http.Header { - return s.w.Header() -} - -func (s *secretResponse) Write(b []byte) (int, error) { - re := getReplacer() - return re.WriteString(s.w, string(b)) -} - -func (s *secretResponse) WriteHeader(statusCode int) { - s.w.WriteHeader(statusCode) + return SecretWrite(s.w, string(b)) } func SecretResponse(w http.ResponseWriter) http.ResponseWriter { return &secretResponse{w} } + +type secretResponse struct { + http.ResponseWriter +} + +func (s *secretResponse) Write(b []byte) (int, error) { + return SecretWrite(s.ResponseWriter, string(b)) +}