Files
gortsplib/pkg/auth/sender.go
2023-05-07 19:34:20 +02:00

113 lines
2.3 KiB
Go

package auth
import (
"fmt"
"strings"
"github.com/bluenviron/gortsplib/v3/pkg/base"
"github.com/bluenviron/gortsplib/v3/pkg/headers"
)
func findHeader(v base.HeaderValue, prefix string) string {
for _, vi := range v {
if strings.HasPrefix(vi, prefix) {
return vi
}
}
return ""
}
// Sender allows to send credentials.
type Sender struct {
user string
pass string
method headers.AuthMethod
realm string
nonce string
}
// NewSender allocates a Sender.
// It requires a WWW-Authenticate header (provided by the server)
// and a set of credentials.
func NewSender(v base.HeaderValue, user string, pass string) (*Sender, error) {
// prefer digest
if v0 := findHeader(v, "Digest"); v0 != "" {
var auth headers.Authenticate
err := auth.Unmarshal(base.HeaderValue{v0})
if err != nil {
return nil, err
}
if auth.Realm == nil {
return nil, fmt.Errorf("realm is missing")
}
if auth.Nonce == nil {
return nil, fmt.Errorf("nonce is missing")
}
return &Sender{
user: user,
pass: pass,
method: headers.AuthDigest,
realm: *auth.Realm,
nonce: *auth.Nonce,
}, nil
}
if v0 := findHeader(v, "Basic"); v0 != "" {
var auth headers.Authenticate
err := auth.Unmarshal(base.HeaderValue{v0})
if err != nil {
return nil, err
}
if auth.Realm == nil {
return nil, fmt.Errorf("realm is missing")
}
return &Sender{
user: user,
pass: pass,
method: headers.AuthBasic,
realm: *auth.Realm,
}, nil
}
return nil, fmt.Errorf("no authentication methods available")
}
// AddAuthorization adds the Authorization header to a Request.
func (se *Sender) AddAuthorization(req *base.Request) {
urStr := req.URL.CloneWithoutCredentials().String()
h := headers.Authorization{
Method: se.method,
}
switch se.method {
case headers.AuthBasic:
h.BasicUser = se.user
h.BasicPass = se.pass
default: // headers.AuthDigest
response := md5Hex(md5Hex(se.user+":"+se.realm+":"+se.pass) + ":" +
se.nonce + ":" + md5Hex(string(req.Method)+":"+urStr))
h.DigestValues = headers.Authenticate{
Method: headers.AuthDigest,
Username: &se.user,
Realm: &se.realm,
Nonce: &se.nonce,
URI: &urStr,
Response: &response,
}
}
if req.Header == nil {
req.Header = make(base.Header)
}
req.Header["Authorization"] = h.Marshal()
}