Files
go2rtc/pkg/tcp/auth.go
2022-09-13 21:57:07 +03:00

105 lines
1.8 KiB
Go

package tcp
import (
"crypto/md5"
"encoding/base64"
"encoding/hex"
"fmt"
"net/url"
"strings"
)
type Auth struct {
Method byte
user string
pass string
header string
h1nonce string
}
const (
AuthNone byte = iota
AuthUnknown
AuthBasic
AuthDigest
)
func NewAuth(user *url.Userinfo) *Auth {
a := new(Auth)
a.user = user.Username()
a.pass, _ = user.Password()
if a.user != "" {
a.Method = AuthUnknown
}
return a
}
func (a *Auth) Read(res *Response) bool {
auth := res.Header.Get("WWW-Authenticate")
if len(auth) < 6 {
return false
}
switch auth[:6] {
case "Basic ":
a.header = "Basic " + B64(a.user, a.pass)
a.Method = AuthBasic
return true
case "Digest":
realm := Between(auth, `realm="`, `"`)
nonce := Between(auth, `nonce="`, `"`)
a.h1nonce = HexMD5(a.user, realm, a.pass) + ":" + nonce
a.header = fmt.Sprintf(
`Digest username="%s", realm="%s", nonce="%s"`,
a.user, realm, nonce,
)
a.Method = AuthDigest
return true
default:
return false
}
}
func (a *Auth) Write(req *Request) {
if a == nil {
return
}
switch a.Method {
case AuthBasic:
req.Header.Set("Authorization", a.header)
case AuthDigest:
uri := req.URL.RequestURI()
h2 := HexMD5(req.Method, uri)
response := HexMD5(a.h1nonce, h2)
header := a.header + fmt.Sprintf(
`, uri="%s", response="%s"`, uri, response,
)
req.Header.Set("Authorization", header)
}
}
func Between(s, sub1, sub2 string) string {
i := strings.Index(s, sub1)
if i < 0 {
return ""
}
s = s[i+len(sub1):]
i = strings.Index(s, sub2)
if i < 0 {
return ""
}
return s[:i]
}
func HexMD5(s ...string) string {
b := md5.Sum([]byte(strings.Join(s, ":")))
return hex.EncodeToString(b[:])
}
func B64(s ...string) string {
b := []byte(strings.Join(s, ":"))
return base64.StdEncoding.EncodeToString(b)
}