iceserver.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. //go:build !js
  2. // +build !js
  3. package webrtc
  4. import (
  5. "encoding/json"
  6. "github.com/pion/ice/v2"
  7. "github.com/pion/webrtc/v3/pkg/rtcerr"
  8. )
  9. // ICEServer describes a single STUN and TURN server that can be used by
  10. // the ICEAgent to establish a connection with a peer.
  11. type ICEServer struct {
  12. URLs []string `json:"urls"`
  13. Username string `json:"username,omitempty"`
  14. Credential interface{} `json:"credential,omitempty"`
  15. CredentialType ICECredentialType `json:"credentialType,omitempty"`
  16. }
  17. func (s ICEServer) parseURL(i int) (*ice.URL, error) {
  18. return ice.ParseURL(s.URLs[i])
  19. }
  20. func (s ICEServer) validate() error {
  21. _, err := s.urls()
  22. return err
  23. }
  24. func (s ICEServer) urls() ([]*ice.URL, error) {
  25. urls := []*ice.URL{}
  26. for i := range s.URLs {
  27. url, err := s.parseURL(i)
  28. if err != nil {
  29. return nil, &rtcerr.InvalidAccessError{Err: err}
  30. }
  31. if url.Scheme == ice.SchemeTypeTURN || url.Scheme == ice.SchemeTypeTURNS {
  32. // https://www.w3.org/TR/webrtc/#set-the-configuration (step #11.3.2)
  33. if s.Username == "" || s.Credential == nil {
  34. return nil, &rtcerr.InvalidAccessError{Err: ErrNoTurnCredentials}
  35. }
  36. url.Username = s.Username
  37. switch s.CredentialType {
  38. case ICECredentialTypePassword:
  39. // https://www.w3.org/TR/webrtc/#set-the-configuration (step #11.3.3)
  40. password, ok := s.Credential.(string)
  41. if !ok {
  42. return nil, &rtcerr.InvalidAccessError{Err: ErrTurnCredentials}
  43. }
  44. url.Password = password
  45. case ICECredentialTypeOauth:
  46. // https://www.w3.org/TR/webrtc/#set-the-configuration (step #11.3.4)
  47. if _, ok := s.Credential.(OAuthCredential); !ok {
  48. return nil, &rtcerr.InvalidAccessError{Err: ErrTurnCredentials}
  49. }
  50. default:
  51. return nil, &rtcerr.InvalidAccessError{Err: ErrTurnCredentials}
  52. }
  53. }
  54. urls = append(urls, url)
  55. }
  56. return urls, nil
  57. }
  58. func iceserverUnmarshalUrls(val interface{}) (*[]string, error) {
  59. s, ok := val.([]interface{})
  60. if !ok {
  61. return nil, errInvalidICEServer
  62. }
  63. out := make([]string, len(s))
  64. for idx, url := range s {
  65. out[idx], ok = url.(string)
  66. if !ok {
  67. return nil, errInvalidICEServer
  68. }
  69. }
  70. return &out, nil
  71. }
  72. func iceserverUnmarshalOauth(val interface{}) (*OAuthCredential, error) {
  73. c, ok := val.(map[string]interface{})
  74. if !ok {
  75. return nil, errInvalidICEServer
  76. }
  77. MACKey, ok := c["MACKey"].(string)
  78. if !ok {
  79. return nil, errInvalidICEServer
  80. }
  81. AccessToken, ok := c["AccessToken"].(string)
  82. if !ok {
  83. return nil, errInvalidICEServer
  84. }
  85. return &OAuthCredential{
  86. MACKey: MACKey,
  87. AccessToken: AccessToken,
  88. }, nil
  89. }
  90. func (s *ICEServer) iceserverUnmarshalFields(m map[string]interface{}) error {
  91. if val, ok := m["urls"]; ok {
  92. u, err := iceserverUnmarshalUrls(val)
  93. if err != nil {
  94. return err
  95. }
  96. s.URLs = *u
  97. } else {
  98. s.URLs = []string{}
  99. }
  100. if val, ok := m["username"]; ok {
  101. s.Username, ok = val.(string)
  102. if !ok {
  103. return errInvalidICEServer
  104. }
  105. }
  106. if val, ok := m["credentialType"]; ok {
  107. ct, ok := val.(string)
  108. if !ok {
  109. return errInvalidICEServer
  110. }
  111. tpe, err := newICECredentialType(ct)
  112. if err != nil {
  113. return err
  114. }
  115. s.CredentialType = tpe
  116. } else {
  117. s.CredentialType = ICECredentialTypePassword
  118. }
  119. if val, ok := m["credential"]; ok {
  120. switch s.CredentialType {
  121. case ICECredentialTypePassword:
  122. s.Credential = val
  123. case ICECredentialTypeOauth:
  124. c, err := iceserverUnmarshalOauth(val)
  125. if err != nil {
  126. return err
  127. }
  128. s.Credential = *c
  129. default:
  130. return errInvalidICECredentialTypeString
  131. }
  132. }
  133. return nil
  134. }
  135. // UnmarshalJSON parses the JSON-encoded data and stores the result
  136. func (s *ICEServer) UnmarshalJSON(b []byte) error {
  137. var tmp interface{}
  138. err := json.Unmarshal(b, &tmp)
  139. if err != nil {
  140. return err
  141. }
  142. if m, ok := tmp.(map[string]interface{}); ok {
  143. return s.iceserverUnmarshalFields(m)
  144. }
  145. return errInvalidICEServer
  146. }
  147. // MarshalJSON returns the JSON encoding
  148. func (s ICEServer) MarshalJSON() ([]byte, error) {
  149. m := make(map[string]interface{})
  150. m["urls"] = s.URLs
  151. if s.Username != "" {
  152. m["username"] = s.Username
  153. }
  154. if s.Credential != nil {
  155. m["credential"] = s.Credential
  156. }
  157. m["credentialType"] = s.CredentialType
  158. return json.Marshal(m)
  159. }