diff --git a/api/openapi.yaml b/api/openapi.yaml index 3a23d5c7..cea1f795 100644 --- a/api/openapi.yaml +++ b/api/openapi.yaml @@ -431,6 +431,8 @@ components: type: string # WHEP source + whepBearerToken: + type: string whepSTUNGatherTimeout: type: string whepHandshakeTimeout: diff --git a/internal/conf/path.go b/internal/conf/path.go index 6c7b35b2..be0c6a22 100644 --- a/internal/conf/path.go +++ b/internal/conf/path.go @@ -229,6 +229,7 @@ type Path struct { RTPUDPReadBufferSize *uint `json:"rtpUDPReadBufferSize,omitempty"` // deprecated // WHEP source + WHEPBearerToken string `json:"whepBearerToken"` WHEPSTUNGatherTimeout Duration `json:"whepSTUNGatherTimeout"` WHEPHandshakeTimeout Duration `json:"whepHandshakeTimeout"` WHEPTrackGatherTimeout Duration `json:"whepTrackGatherTimeout"` diff --git a/internal/protocols/whip/client.go b/internal/protocols/whip/client.go index 59affec0..1e28f185 100644 --- a/internal/protocols/whip/client.go +++ b/internal/protocols/whip/client.go @@ -24,6 +24,7 @@ type Client struct { Publish bool OutgoingTracks []*webrtc.OutgoingTrack HTTPClient *http.Client + BearerToken string UDPReadBufferSize uint STUNGatherTimeout time.Duration HandshakeTimeout time.Duration @@ -197,6 +198,10 @@ func (c *Client) optionsICEServers( return nil, err } + if c.BearerToken != "" { + req.Header.Set("Authorization", "Bearer "+c.BearerToken) + } + res, err := c.HTTPClient.Do(req) if err != nil { return nil, err @@ -225,6 +230,10 @@ func (c *Client) postOffer( return nil, err } + if c.BearerToken != "" { + req.Header.Set("Authorization", "Bearer "+c.BearerToken) + } + req.Header.Set("Content-Type", "application/sdp") res, err := c.HTTPClient.Do(req) @@ -288,6 +297,10 @@ func (c *Client) patchCandidate( return err } + if c.BearerToken != "" { + req.Header.Set("Authorization", "Bearer "+c.BearerToken) + } + req.Header.Set("Content-Type", "application/trickle-ice-sdpfrag") req.Header.Set("If-Match", etag) @@ -312,6 +325,10 @@ func (c *Client) deleteSession( return err } + if c.BearerToken != "" { + req.Header.Set("Authorization", "Bearer "+c.BearerToken) + } + res, err := c.HTTPClient.Do(req) if err != nil { return err diff --git a/internal/protocols/whip/client_test.go b/internal/protocols/whip/client_test.go index bd49a8fa..19d20fb2 100644 --- a/internal/protocols/whip/client_test.go +++ b/internal/protocols/whip/client_test.go @@ -435,3 +435,67 @@ func TestClientPublish(t *testing.T) { }) } } + +func TestClientBearerToken(t *testing.T) { + pc := &webrtc.PeerConnection{ + LocalRandomUDP: true, + IPsFromInterfaces: true, + Log: test.NilLogger, + } + err := pc.Start() + require.NoError(t, err) + defer pc.Close() + + httpServ := &http.Server{ + Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + require.Equal(t, "Bearer my_secret_token", r.Header.Get("Authorization")) + + switch r.Method { + case http.MethodOptions: + w.WriteHeader(http.StatusNoContent) + + case http.MethodPost: + body, err2 := io.ReadAll(r.Body) + require.NoError(t, err2) + offer := whipOffer(body) + + answer, err2 := pc.CreateFullAnswer(offer) + require.NoError(t, err2) + + w.Header().Set("Content-Type", "application/sdp") + w.Header().Set("ETag", "test_etag") + w.WriteHeader(http.StatusCreated) + w.Write([]byte(answer.SDP)) + } + }), + } + + ln, err := net.Listen("tcp", "localhost:9005") + require.NoError(t, err) + + go httpServ.Serve(ln) + defer httpServ.Shutdown(context.Background()) + + u, err := url.Parse("http://localhost:9005/my/resource") + require.NoError(t, err) + + outgoingTracks := []*webrtc.OutgoingTrack{{ + Caps: pwebrtc.RTPCodecCapability{ + MimeType: "audio/opus", + ClockRate: 48000, + Channels: 2, + }, + }} + + cl := &Client{ + URL: u, + HTTPClient: &http.Client{}, + BearerToken: "my_secret_token", + Log: test.NilLogger, + Publish: true, + OutgoingTracks: outgoingTracks, + } + err = cl.Initialize(context.Background()) + require.NoError(t, err) + defer cl.Close() //nolint:errcheck +} diff --git a/internal/staticsources/webrtc/source.go b/internal/staticsources/webrtc/source.go index b854f933..c53e3ca3 100644 --- a/internal/staticsources/webrtc/source.go +++ b/internal/staticsources/webrtc/source.go @@ -59,6 +59,7 @@ func (s *Source) Run(params defs.StaticSourceRunParams) error { Timeout: time.Duration(s.ReadTimeout), Transport: tr, }, + BearerToken: params.Conf.WHEPBearerToken, UDPReadBufferSize: s.UDPReadBufferSize, STUNGatherTimeout: time.Duration(params.Conf.WHEPSTUNGatherTimeout), HandshakeTimeout: time.Duration(params.Conf.WHEPHandshakeTimeout), diff --git a/mediamtx.yml b/mediamtx.yml index 0b8edca4..ed408420 100644 --- a/mediamtx.yml +++ b/mediamtx.yml @@ -573,6 +573,8 @@ pathDefaults: ############################################### # Default path settings -> WebRTC / WHEP source (when source is WHEP) + # Token to insert in the Authorization: Bearer header. + whepBearerToken: '' # Maximum time to gather STUN candidates. whepSTUNGatherTimeout: 5s # Time to wait for the WebRTC handshake to complete.