diff --git a/egress/redact.go b/egress/redact.go index 96ffe66c0..944e84c69 100644 --- a/egress/redact.go +++ b/egress/redact.go @@ -35,7 +35,7 @@ func RedactUpload(req UploadRequest) { s3.AccessKey = utils.Redact(s3.AccessKey, "{access_key}") s3.Secret = utils.Redact(s3.Secret, "{secret}") s3.AssumeRoleExternalId = utils.Redact(s3.AssumeRoleExternalId, "{external_id}") - s3.SessionToken = utils.Redact(s3.AssumeRoleExternalId, "{session_token}") + s3.SessionToken = utils.Redact(s3.SessionToken, "{session_token}") return } @@ -91,6 +91,11 @@ func RedactDirectOutputs(out DirectOutput) { if f := out.GetFile(); f != nil { RedactUpload(f) } + if track, ok := out.(*livekit.TrackEgressRequest); ok { + if ws, ok := track.Output.(*livekit.TrackEgressRequest_WebsocketUrl); ok { + ws.WebsocketUrl = utils.RedactUrlQueryValues(ws.WebsocketUrl) + } + } } func RedactStreamKeys(stream *livekit.StreamOutput) { diff --git a/egress/redact_test.go b/egress/redact_test.go index 561e67276..56791ae07 100644 --- a/egress/redact_test.go +++ b/egress/redact_test.go @@ -71,6 +71,20 @@ func TestRedactUpload(t *testing.T) { require.Equal(t, "{external_id}", cl.(*livekit.EncodedFileOutput).Output.(*livekit.EncodedFileOutput_S3).S3.AssumeRoleExternalId) require.Equal(t, "{session_token}", cl.(*livekit.EncodedFileOutput).Output.(*livekit.EncodedFileOutput_S3).S3.SessionToken) + sessionTokenOnly := &livekit.EncodedFileOutput{ + Output: &livekit.EncodedFileOutput_S3{ + S3: &livekit.S3Upload{ + AccessKey: "ACCESS_KEY", + Secret: "LONG_SECRET_STRING", + SessionToken: "SESSION_TOKEN", + }, + }, + } + cl = proto.Clone(sessionTokenOnly) + RedactUpload(cl.(UploadRequest)) + + require.Equal(t, "{session_token}", cl.(*livekit.EncodedFileOutput).Output.(*livekit.EncodedFileOutput_S3).S3.SessionToken) + cl = proto.Clone(image) RedactUpload(cl.(UploadRequest)) @@ -93,11 +107,17 @@ func TestRedactStreamOutput(t *testing.T) { so := &livekit.StreamOutput{ Urls: []string{ "rtmps://foo.bar.com/app/secret_stream_key", + "mux://8e0b1b9c-50a2-d893-ec0a-102056d112ae", + "twitch://live_12345678_abcdefghijklmnop", + "srt://foo.bar.com:9999", }, } RedactStreamKeys(so) require.Equal(t, "rtmps://foo.bar.com/app/{sec...key}", so.Urls[0]) + require.Equal(t, "mux://{8e0...2ae}", so.Urls[1]) + require.Equal(t, "twitch://{liv...nop}", so.Urls[2]) + require.Equal(t, "srt://foo.bar.com:9999", so.Urls[3]) } func TestRedactEncodedOutputs(t *testing.T) { @@ -154,4 +174,15 @@ func TestRedactDirectOutput(t *testing.T) { RedactDirectOutputs(track) require.Equal(t, "{access_key}", track.Output.(*livekit.TrackEgressRequest_File).File.Output.(*livekit.DirectFileOutput_S3).S3.AccessKey) require.Equal(t, "{secret}", track.Output.(*livekit.TrackEgressRequest_File).File.Output.(*livekit.DirectFileOutput_S3).S3.Secret) + + websocket := &livekit.TrackEgressRequest{ + Output: &livekit.TrackEgressRequest_WebsocketUrl{ + WebsocketUrl: "wss://foo.bar.com/audio?callId=12145&token=7df13dab0d4437602d6f7056b97e72b9", + }, + } + + RedactDirectOutputs(websocket) + require.Equal(t, + "wss://foo.bar.com/audio?callId={1...5}&token={7df...2b9}", + websocket.Output.(*livekit.TrackEgressRequest_WebsocketUrl).WebsocketUrl) } diff --git a/utils/redact.go b/utils/redact.go index d894f6efa..cf476b264 100644 --- a/utils/redact.go +++ b/utils/redact.go @@ -23,7 +23,14 @@ import ( // rtmp urls must be of format rtmp(s)://{host}(/{path})/{app}/{stream_key}( live=1) var rtmpRegexp = regexp.MustCompile(`^(rtmps?://)(.*/)(.*/)(\S*)( live=1)?$`) +// mux and twitch shorthand urls carry the stream key as the entire authority +var shorthandStreamRegexp = regexp.MustCompile(`^(mux|twitch)://(\S+)$`) + func RedactStreamKey(url string) (string, bool) { + if match := shorthandStreamRegexp.FindStringSubmatch(url); len(match) == 3 { + return match[1] + "://" + RedactIdentifier(match[2]), true + } + match := rtmpRegexp.FindStringSubmatch(url) if len(match) != 6 { return url, false @@ -33,6 +40,22 @@ func RedactStreamKey(url string) (string, bool) { return strings.Join(match[1:], ""), true } +// RedactUrlQueryValues redacts every query parameter value in rawUrl, keeping parameter names intact. +func RedactUrlQueryValues(rawUrl string) string { + base, query, found := strings.Cut(rawUrl, "?") + if !found || query == "" { + return rawUrl + } + + params := strings.Split(query, "&") + for i, p := range params { + if k, v, ok := strings.Cut(p, "="); ok && v != "" { + params[i] = k + "=" + RedactIdentifier(v) + } + } + return base + "?" + strings.Join(params, "&") +} + func RedactIdentifier(identifier string) string { var prefix, suffix string for i := 3; i > 0; i-- {