Skip to content

Commit

Permalink
Validate received SDP earlier.
Browse files Browse the repository at this point in the history
  • Loading branch information
fancycode committed Apr 25, 2024
1 parent 9e2a896 commit afb13ce
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 47 deletions.
22 changes: 22 additions & 0 deletions api_signaling.go
Expand Up @@ -32,6 +32,7 @@ import (
"time"

"github.com/golang-jwt/jwt/v4"
"github.com/pion/sdp/v3"
)

const (
Expand Down Expand Up @@ -563,12 +564,33 @@ type MessageClientMessageData struct {
RoomType string `json:"roomType"`
Bitrate int `json:"bitrate,omitempty"`
Payload map[string]interface{} `json:"payload"`

offerSdp *sdp.SessionDescription // Only set if Type == "offer"
}

func (m *MessageClientMessageData) CheckValid() error {
if !IsValidStreamType(m.RoomType) {
return fmt.Errorf("invalid room type: %s", m.RoomType)
}
if m.Type == "offer" {
sdpValue, found := m.Payload["sdp"]
if !found {
return NewError("no_offer_sdp", "Offer does not contain a SDP.")
}
sdpText, ok := sdpValue.(string)
if !ok {
return NewError("invalid_offer_sdp", "Offer does not contain a valid SDP.")
}

var sdp sdp.SessionDescription
if err := sdp.Unmarshal([]byte(sdpText)); err != nil {
return NewErrorDetail("invalid_offer_sdp", "Error parsing offer SDP.", map[string]interface{}{
"error": err.Error(),
})
}

m.offerSdp = &sdp
}
return nil
}

Expand Down
44 changes: 7 additions & 37 deletions clientsession.go
Expand Up @@ -720,23 +720,6 @@ func (s *ClientSession) SubscriberClosed(subscriber McuSubscriber) {
}
}

type SdpError struct {
message string
}

func (e *SdpError) Error() string {
return e.message
}

type WrappedSdpError struct {
SdpError
err error
}

func (e *WrappedSdpError) Unwrap() error {
return e.err
}

type PermissionError struct {
permission Permission
}
Expand All @@ -749,23 +732,10 @@ func (e *PermissionError) Error() string {
return fmt.Sprintf("permission \"%s\" not found", e.permission)
}

func (s *ClientSession) isSdpAllowedToSendLocked(payload map[string]interface{}) (MediaType, error) {
sdpValue, found := payload["sdp"]
if !found {
return 0, &SdpError{"payload does not contain a sdp"}
}
sdpText, ok := sdpValue.(string)
if !ok {
return 0, &SdpError{"payload does not contain a valid sdp"}
}
var sdp sdp.SessionDescription
if err := sdp.Unmarshal([]byte(sdpText)); err != nil {
return 0, &WrappedSdpError{
SdpError: SdpError{
message: fmt.Sprintf("could not parse sdp: %s", err),
},
err: err,
}
func (s *ClientSession) isSdpAllowedToSendLocked(sdp *sdp.SessionDescription) (MediaType, error) {
if sdp == nil {
// Should have already been checked when data was validated.
return 0, fmt.Errorf("no offer sdp provided")
}

var mediaTypes MediaType
Expand Down Expand Up @@ -803,8 +773,8 @@ func (s *ClientSession) IsAllowedToSend(data *MessageClientMessageData) error {
// Client is allowed to publish any media (audio / video).
return nil
} else if data != nil && data.Type == "offer" {
// Parse SDP to check what user is trying to publish and check permissions accordingly.
if _, err := s.isSdpAllowedToSendLocked(data.Payload); err != nil {
// Check what user is trying to publish and check permissions accordingly.
if _, err := s.isSdpAllowedToSendLocked(data.offerSdp); err != nil {
return err
}

Expand Down Expand Up @@ -834,7 +804,7 @@ func (s *ClientSession) checkOfferTypeLocked(streamType StreamType, data *Messag

return MediaTypeScreen, nil
} else if data != nil && data.Type == "offer" {
mediaTypes, err := s.isSdpAllowedToSendLocked(data.Payload)
mediaTypes, err := s.isSdpAllowedToSendLocked(data.offerSdp)
if err != nil {
return 0, err
}
Expand Down
5 changes: 0 additions & 5 deletions hub.go
Expand Up @@ -2352,11 +2352,6 @@ func (h *Hub) processMcuMessage(session *ClientSession, client_message *ClientMe
sendNotAllowed(session, client_message, "Not allowed to publish.")
return
}
if err, ok := err.(*SdpError); ok {
log.Printf("Session %s sent unsupported offer %s, ignoring (%s)", session.PublicId(), data.RoomType, err)
sendNotAllowed(session, client_message, "Not allowed to publish.")
return
}
case "selectStream":
if session.PublicId() == message.Recipient.SessionId {
log.Printf("Not selecting substream for own %s stream in session %s", data.RoomType, session.PublicId())
Expand Down
18 changes: 13 additions & 5 deletions proxy/proxy_server.go
Expand Up @@ -777,9 +777,10 @@ func (s *ProxyServer) processPayload(ctx context.Context, client *ProxyClient, s
fallthrough
case "candidate":
mcuData = &signaling.MessageClientMessageData{
Type: payload.Type,
Sid: payload.Sid,
Payload: payload.Payload,
RoomType: string(mcuClient.StreamType()),
Type: payload.Type,
Sid: payload.Sid,
Payload: payload.Payload,
}
case "endOfCandidates":
// Ignore but confirm, not passed along to Janus anyway.
Expand All @@ -796,14 +797,21 @@ func (s *ProxyServer) processPayload(ctx context.Context, client *ProxyClient, s
fallthrough
case "sendoffer":
mcuData = &signaling.MessageClientMessageData{
Type: payload.Type,
Sid: payload.Sid,
RoomType: string(mcuClient.StreamType()),
Type: payload.Type,
Sid: payload.Sid,
}
default:
session.sendMessage(message.NewErrorServerMessage(UnsupportedPayload))
return
}

if err := mcuData.CheckValid(); err != nil {
log.Printf("Received invalid payload %+v for %s client %s: %s", mcuData, mcuClient.StreamType(), payload.ClientId, err)
session.sendMessage(message.NewErrorServerMessage(UnsupportedPayload))
return
}

mcuClient.SendMessage(ctx, nil, mcuData, func(err error, response map[string]interface{}) {
var responseMsg *signaling.ProxyServerMessage
if err != nil {
Expand Down

0 comments on commit afb13ce

Please sign in to comment.