Add user agent field to RTMP, RTSP, WebRTC, and HLS (#5753)
Surface user agent in the auth HTTP webhook payload as "userAgent" and in the API structs for RTMP, RTSP, WebRTC and HLS connections. --------- Co-authored-by: aler9 <46489434+aler9@users.noreply.github.com>
This commit is contained in:
@@ -1213,6 +1213,8 @@ components:
|
|||||||
type: string
|
type: string
|
||||||
user:
|
user:
|
||||||
type: string
|
type: string
|
||||||
|
userAgent:
|
||||||
|
type: string
|
||||||
isCDN:
|
isCDN:
|
||||||
type: boolean
|
type: boolean
|
||||||
outboundBytes:
|
outboundBytes:
|
||||||
@@ -1281,6 +1283,8 @@ components:
|
|||||||
type: string
|
type: string
|
||||||
user:
|
user:
|
||||||
type: string
|
type: string
|
||||||
|
userAgent:
|
||||||
|
type: string
|
||||||
inboundBytes:
|
inboundBytes:
|
||||||
type: integer
|
type: integer
|
||||||
format: uint64
|
format: uint64
|
||||||
@@ -1376,6 +1380,8 @@ components:
|
|||||||
type: string
|
type: string
|
||||||
user:
|
user:
|
||||||
type: string
|
type: string
|
||||||
|
userAgent:
|
||||||
|
type: string
|
||||||
transport:
|
transport:
|
||||||
type: string
|
type: string
|
||||||
nullable: true
|
nullable: true
|
||||||
@@ -1774,6 +1780,8 @@ components:
|
|||||||
type: string
|
type: string
|
||||||
user:
|
user:
|
||||||
type: string
|
type: string
|
||||||
|
userAgent:
|
||||||
|
type: string
|
||||||
inboundBytes:
|
inboundBytes:
|
||||||
type: integer
|
type: integer
|
||||||
format: uint64
|
format: uint64
|
||||||
|
|||||||
@@ -93,7 +93,8 @@ Each time a user needs to be authenticated, the specified URL will be requested
|
|||||||
"path": "path",
|
"path": "path",
|
||||||
"protocol": "rtsp|rtmp|hls|webrtc|srt",
|
"protocol": "rtsp|rtmp|hls|webrtc|srt",
|
||||||
"id": "id",
|
"id": "id",
|
||||||
"query": "query"
|
"query": "query",
|
||||||
|
"userAgent": "userAgent"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
+20
-18
@@ -197,25 +197,27 @@ func (m *Manager) authenticateHTTP(req *Request, token string) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enc, _ := json.Marshal(struct {
|
enc, _ := json.Marshal(struct {
|
||||||
IP string `json:"ip"`
|
IP string `json:"ip"`
|
||||||
User string `json:"user"`
|
User string `json:"user"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
Token string `json:"token"`
|
Token string `json:"token"`
|
||||||
Action string `json:"action"`
|
Action string `json:"action"`
|
||||||
Path string `json:"path"`
|
Path string `json:"path"`
|
||||||
Protocol string `json:"protocol"`
|
Protocol string `json:"protocol"`
|
||||||
ID *uuid.UUID `json:"id"`
|
ID *uuid.UUID `json:"id"`
|
||||||
Query string `json:"query"`
|
Query string `json:"query"`
|
||||||
|
UserAgent string `json:"userAgent"`
|
||||||
}{
|
}{
|
||||||
IP: req.IP.String(),
|
IP: req.IP.String(),
|
||||||
User: req.Credentials.User,
|
User: req.Credentials.User,
|
||||||
Password: req.Credentials.Pass,
|
Password: req.Credentials.Pass,
|
||||||
Token: token,
|
Token: token,
|
||||||
Action: string(req.Action),
|
Action: string(req.Action),
|
||||||
Path: req.Path,
|
Path: req.Path,
|
||||||
Protocol: string(req.Protocol),
|
Protocol: string(req.Protocol),
|
||||||
ID: req.ID,
|
ID: req.ID,
|
||||||
Query: req.Query,
|
Query: req.Query,
|
||||||
|
UserAgent: req.UserAgent,
|
||||||
})
|
})
|
||||||
|
|
||||||
tr := &http.Transport{
|
tr := &http.Transport{
|
||||||
|
|||||||
@@ -274,14 +274,15 @@ func TestAuthHTTP(t *testing.T) {
|
|||||||
require.Equal(t, "/auth", r.URL.Path)
|
require.Equal(t, "/auth", r.URL.Path)
|
||||||
|
|
||||||
var in struct {
|
var in struct {
|
||||||
IP string `json:"ip"`
|
IP string `json:"ip"`
|
||||||
User string `json:"user"`
|
User string `json:"user"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
Path string `json:"path"`
|
Path string `json:"path"`
|
||||||
Protocol string `json:"protocol"`
|
Protocol string `json:"protocol"`
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Action string `json:"action"`
|
Action string `json:"action"`
|
||||||
Query string `json:"query"`
|
Query string `json:"query"`
|
||||||
|
UserAgent string `json:"userAgent"`
|
||||||
}
|
}
|
||||||
err := json.NewDecoder(r.Body).Decode(&in)
|
err := json.NewDecoder(r.Body).Decode(&in)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -293,6 +294,7 @@ func TestAuthHTTP(t *testing.T) {
|
|||||||
in.Protocol != "rtsp" ||
|
in.Protocol != "rtsp" ||
|
||||||
(firstReceived && in.ID == "") ||
|
(firstReceived && in.ID == "") ||
|
||||||
in.Action != "publish" ||
|
in.Action != "publish" ||
|
||||||
|
in.UserAgent != "testagent" ||
|
||||||
(in.Query != "user=testreader&pass=testpass¶m=value" &&
|
(in.Query != "user=testreader&pass=testpass¶m=value" &&
|
||||||
in.Query != "user=testpublisher&pass=testpass¶m=value" &&
|
in.Query != "user=testpublisher&pass=testpass¶m=value" &&
|
||||||
in.Query != "param=value") {
|
in.Query != "param=value") {
|
||||||
@@ -319,10 +321,11 @@ func TestAuthHTTP(t *testing.T) {
|
|||||||
|
|
||||||
if outcome == "ok" {
|
if outcome == "ok" {
|
||||||
req = &Request{
|
req = &Request{
|
||||||
Action: conf.AuthActionPublish,
|
Action: conf.AuthActionPublish,
|
||||||
Path: "teststream",
|
Path: "teststream",
|
||||||
Query: "param=value",
|
Query: "param=value",
|
||||||
Protocol: ProtocolRTSP,
|
Protocol: ProtocolRTSP,
|
||||||
|
UserAgent: "testagent",
|
||||||
Credentials: &Credentials{
|
Credentials: &Credentials{
|
||||||
User: "testpublisher",
|
User: "testpublisher",
|
||||||
Pass: "testpass",
|
Pass: "testpass",
|
||||||
@@ -331,10 +334,11 @@ func TestAuthHTTP(t *testing.T) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
req = &Request{
|
req = &Request{
|
||||||
Action: conf.AuthActionPublish,
|
Action: conf.AuthActionPublish,
|
||||||
Path: "teststream",
|
Path: "teststream",
|
||||||
Query: "param=value",
|
Query: "param=value",
|
||||||
Protocol: ProtocolRTSP,
|
Protocol: ProtocolRTSP,
|
||||||
|
UserAgent: "testagent",
|
||||||
Credentials: &Credentials{
|
Credentials: &Credentials{
|
||||||
User: "invalid",
|
User: "invalid",
|
||||||
Pass: "testpass",
|
Pass: "testpass",
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ type Request struct {
|
|||||||
Query string
|
Query string
|
||||||
Protocol Protocol // only for ActionPublish, ActionRead
|
Protocol Protocol // only for ActionPublish, ActionRead
|
||||||
ID *uuid.UUID // only for ActionPublish, ActionRead
|
ID *uuid.UUID // only for ActionPublish, ActionRead
|
||||||
|
UserAgent string
|
||||||
Credentials *Credentials
|
Credentials *Credentials
|
||||||
IP net.IP
|
IP net.IP
|
||||||
CustomVerifyFunc func(expectedUser string, expectedPass string) bool
|
CustomVerifyFunc func(expectedUser string, expectedPass string) bool
|
||||||
|
|||||||
@@ -679,6 +679,7 @@ func TestAPIProtocolListGet(t *testing.T) {
|
|||||||
"rtcpPacketsSent": float64(0),
|
"rtcpPacketsSent": float64(0),
|
||||||
"rtcpPacketsInError": float64(0),
|
"rtcpPacketsInError": float64(0),
|
||||||
"conns": out1.(map[string]any)["items"].([]any)[0].(map[string]any)["conns"],
|
"conns": out1.(map[string]any)["items"].([]any)[0].(map[string]any)["conns"],
|
||||||
|
"userAgent": "gortsplib",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, out1)
|
}, out1)
|
||||||
@@ -740,6 +741,7 @@ func TestAPIProtocolListGet(t *testing.T) {
|
|||||||
"rtcpPacketsSent": float64(0),
|
"rtcpPacketsSent": float64(0),
|
||||||
"rtcpPacketsInError": float64(0),
|
"rtcpPacketsInError": float64(0),
|
||||||
"conns": out1.(map[string]any)["items"].([]any)[0].(map[string]any)["conns"],
|
"conns": out1.(map[string]any)["items"].([]any)[0].(map[string]any)["conns"],
|
||||||
|
"userAgent": "gortsplib",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, out1)
|
}, out1)
|
||||||
@@ -762,6 +764,7 @@ func TestAPIProtocolListGet(t *testing.T) {
|
|||||||
"user": "",
|
"user": "",
|
||||||
"remoteAddr": out1.(map[string]any)["items"].([]any)[0].(map[string]any)["remoteAddr"],
|
"remoteAddr": out1.(map[string]any)["items"].([]any)[0].(map[string]any)["remoteAddr"],
|
||||||
"state": "publish",
|
"state": "publish",
|
||||||
|
"userAgent": "LNX 9,0,124,2",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, out1)
|
}, out1)
|
||||||
@@ -784,6 +787,7 @@ func TestAPIProtocolListGet(t *testing.T) {
|
|||||||
"user": "",
|
"user": "",
|
||||||
"remoteAddr": out1.(map[string]any)["items"].([]any)[0].(map[string]any)["remoteAddr"],
|
"remoteAddr": out1.(map[string]any)["items"].([]any)[0].(map[string]any)["remoteAddr"],
|
||||||
"state": "publish",
|
"state": "publish",
|
||||||
|
"userAgent": "LNX 9,0,124,2",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, out1)
|
}, out1)
|
||||||
@@ -802,6 +806,7 @@ func TestAPIProtocolListGet(t *testing.T) {
|
|||||||
"user": "",
|
"user": "",
|
||||||
"isCDN": false,
|
"isCDN": false,
|
||||||
"outboundBytes": out1.(map[string]any)["items"].([]any)[0].(map[string]any)["outboundBytes"],
|
"outboundBytes": out1.(map[string]any)["items"].([]any)[0].(map[string]any)["outboundBytes"],
|
||||||
|
"userAgent": "Go-http-client/1.1",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, out1)
|
}, out1)
|
||||||
@@ -855,6 +860,7 @@ func TestAPIProtocolListGet(t *testing.T) {
|
|||||||
"rtpPacketsLost": float64(0),
|
"rtpPacketsLost": float64(0),
|
||||||
"rtpPacketsReceived": float64(0),
|
"rtpPacketsReceived": float64(0),
|
||||||
"rtpPacketsSent": float64(1),
|
"rtpPacketsSent": float64(1),
|
||||||
|
"userAgent": "Go-http-client/1.1",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, out1)
|
}, out1)
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ type APIHLSSession struct {
|
|||||||
Path string `json:"path"`
|
Path string `json:"path"`
|
||||||
Query string `json:"query"`
|
Query string `json:"query"`
|
||||||
User string `json:"user"`
|
User string `json:"user"`
|
||||||
|
UserAgent string `json:"userAgent"`
|
||||||
IsCDN bool `json:"isCDN"`
|
IsCDN bool `json:"isCDN"`
|
||||||
OutboundBytes uint64 `json:"outboundBytes"`
|
OutboundBytes uint64 `json:"outboundBytes"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ type APIRTMPConn struct {
|
|||||||
Path string `json:"path"`
|
Path string `json:"path"`
|
||||||
Query string `json:"query"`
|
Query string `json:"query"`
|
||||||
User string `json:"user"`
|
User string `json:"user"`
|
||||||
|
UserAgent string `json:"userAgent"`
|
||||||
InboundBytes uint64 `json:"inboundBytes"`
|
InboundBytes uint64 `json:"inboundBytes"`
|
||||||
OutboundBytes uint64 `json:"outboundBytes"`
|
OutboundBytes uint64 `json:"outboundBytes"`
|
||||||
OutboundFramesDiscarded uint64 `json:"outboundFramesDiscarded"`
|
OutboundFramesDiscarded uint64 `json:"outboundFramesDiscarded"`
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ type APIRTSPSession struct {
|
|||||||
Path string `json:"path"`
|
Path string `json:"path"`
|
||||||
Query string `json:"query"`
|
Query string `json:"query"`
|
||||||
User string `json:"user"`
|
User string `json:"user"`
|
||||||
|
UserAgent string `json:"userAgent"`
|
||||||
Transport *string `json:"transport"`
|
Transport *string `json:"transport"`
|
||||||
Profile *string `json:"profile"`
|
Profile *string `json:"profile"`
|
||||||
Conns []uuid.UUID `json:"conns"`
|
Conns []uuid.UUID `json:"conns"`
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ type APIWebRTCSession struct {
|
|||||||
Path string `json:"path"`
|
Path string `json:"path"`
|
||||||
Query string `json:"query"`
|
Query string `json:"query"`
|
||||||
User string `json:"user"`
|
User string `json:"user"`
|
||||||
|
UserAgent string `json:"userAgent"`
|
||||||
InboundBytes uint64 `json:"inboundBytes"`
|
InboundBytes uint64 `json:"inboundBytes"`
|
||||||
InboundRTPPackets uint64 `json:"inboundRTPPackets"`
|
InboundRTPPackets uint64 `json:"inboundRTPPackets"`
|
||||||
InboundRTPPacketsLost uint64 `json:"inboundRTPPacketsLost"`
|
InboundRTPPacketsLost uint64 `json:"inboundRTPPacketsLost"`
|
||||||
|
|||||||
@@ -10,10 +10,11 @@ import (
|
|||||||
|
|
||||||
// PathAccessRequest is a path access request.
|
// PathAccessRequest is a path access request.
|
||||||
type PathAccessRequest struct {
|
type PathAccessRequest struct {
|
||||||
Name string
|
Name string
|
||||||
Query string
|
Query string
|
||||||
Publish bool
|
Publish bool
|
||||||
SkipAuth bool
|
SkipAuth bool
|
||||||
|
UserAgent string
|
||||||
|
|
||||||
// only if skipAuth = false
|
// only if skipAuth = false
|
||||||
Proto auth.Protocol
|
Proto auth.Protocol
|
||||||
@@ -36,6 +37,7 @@ func (r *PathAccessRequest) ToAuthRequest() *auth.Request {
|
|||||||
Query: r.Query,
|
Query: r.Query,
|
||||||
Protocol: r.Proto,
|
Protocol: r.Proto,
|
||||||
ID: r.ID,
|
ID: r.ID,
|
||||||
|
UserAgent: r.UserAgent,
|
||||||
Credentials: r.Credentials,
|
Credentials: r.Credentials,
|
||||||
IP: r.IP,
|
IP: r.IP,
|
||||||
CustomVerifyFunc: r.CustomVerifyFunc,
|
CustomVerifyFunc: r.CustomVerifyFunc,
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ type session struct {
|
|||||||
created time.Time
|
created time.Time
|
||||||
query string
|
query string
|
||||||
user string
|
user string
|
||||||
|
userAgent string
|
||||||
lastRequestTime atomic.Int64
|
lastRequestTime atomic.Int64
|
||||||
bytesSent atomic.Uint64
|
bytesSent atomic.Uint64
|
||||||
path defs.Path
|
path defs.Path
|
||||||
@@ -53,15 +54,17 @@ func (s *session) initialize(ctx *gin.Context) error {
|
|||||||
s.ip, _, _ = net.SplitHostPort(s.remoteAddr)
|
s.ip, _, _ = net.SplitHostPort(s.remoteAddr)
|
||||||
s.created = time.Now()
|
s.created = time.Now()
|
||||||
s.query = ctx.Request.URL.RawQuery
|
s.query = ctx.Request.URL.RawQuery
|
||||||
|
s.userAgent = ctx.Request.UserAgent()
|
||||||
s.lastRequestTime.Store(time.Now().UnixNano())
|
s.lastRequestTime.Store(time.Now().UnixNano())
|
||||||
|
|
||||||
accessReq := defs.PathAccessRequest{
|
accessReq := defs.PathAccessRequest{
|
||||||
Name: s.pathName,
|
Name: s.pathName,
|
||||||
Query: s.query,
|
Query: s.query,
|
||||||
Publish: false,
|
Publish: false,
|
||||||
Proto: auth.ProtocolHLS,
|
UserAgent: s.userAgent,
|
||||||
ID: &s.uuid,
|
Proto: auth.ProtocolHLS,
|
||||||
IP: net.ParseIP(ctx.ClientIP()),
|
ID: &s.uuid,
|
||||||
|
IP: net.ParseIP(ctx.ClientIP()),
|
||||||
}
|
}
|
||||||
if s.isCDN {
|
if s.isCDN {
|
||||||
accessReq.SkipAuth = true
|
accessReq.SkipAuth = true
|
||||||
@@ -167,6 +170,7 @@ func (s *session) apiItem() *defs.APIHLSSession {
|
|||||||
Path: s.pathName,
|
Path: s.pathName,
|
||||||
Query: s.query,
|
Query: s.query,
|
||||||
User: s.user,
|
User: s.user,
|
||||||
|
UserAgent: s.userAgent,
|
||||||
IsCDN: s.isCDN,
|
IsCDN: s.isCDN,
|
||||||
OutboundBytes: outboundBytes,
|
OutboundBytes: outboundBytes,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ type conn struct {
|
|||||||
pathName string
|
pathName string
|
||||||
query string
|
query string
|
||||||
user string
|
user string
|
||||||
|
userAgent string
|
||||||
reader *stream.Reader
|
reader *stream.Reader
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,6 +142,7 @@ func (c *conn) runReader() error {
|
|||||||
|
|
||||||
c.mutex.Lock()
|
c.mutex.Lock()
|
||||||
c.rconn = conn
|
c.rconn = conn
|
||||||
|
c.userAgent = conn.FlashVer
|
||||||
c.mutex.Unlock()
|
c.mutex.Unlock()
|
||||||
|
|
||||||
if !conn.Publish {
|
if !conn.Publish {
|
||||||
@@ -156,10 +158,11 @@ func (c *conn) runRead() error {
|
|||||||
res, err := c.pathManager.AddReader(defs.PathAddReaderReq{
|
res, err := c.pathManager.AddReader(defs.PathAddReaderReq{
|
||||||
Author: c,
|
Author: c,
|
||||||
AccessRequest: defs.PathAccessRequest{
|
AccessRequest: defs.PathAccessRequest{
|
||||||
Name: pathName,
|
Name: pathName,
|
||||||
Query: c.rconn.URL.RawQuery,
|
Query: c.rconn.URL.RawQuery,
|
||||||
Proto: auth.ProtocolRTMP,
|
UserAgent: c.userAgent,
|
||||||
ID: &c.uuid,
|
Proto: auth.ProtocolRTMP,
|
||||||
|
ID: &c.uuid,
|
||||||
Credentials: &auth.Credentials{
|
Credentials: &auth.Credentials{
|
||||||
User: query.Get("user"),
|
User: query.Get("user"),
|
||||||
Pass: query.Get("pass"),
|
Pass: query.Get("pass"),
|
||||||
@@ -249,11 +252,12 @@ func (c *conn) runPublish() error {
|
|||||||
UseRTPPackets: false,
|
UseRTPPackets: false,
|
||||||
ReplaceNTP: true,
|
ReplaceNTP: true,
|
||||||
AccessRequest: defs.PathAccessRequest{
|
AccessRequest: defs.PathAccessRequest{
|
||||||
Name: pathName,
|
Name: pathName,
|
||||||
Query: c.rconn.URL.RawQuery,
|
Query: c.rconn.URL.RawQuery,
|
||||||
Publish: true,
|
Publish: true,
|
||||||
Proto: auth.ProtocolRTMP,
|
UserAgent: c.userAgent,
|
||||||
ID: &c.uuid,
|
Proto: auth.ProtocolRTMP,
|
||||||
|
ID: &c.uuid,
|
||||||
Credentials: &auth.Credentials{
|
Credentials: &auth.Credentials{
|
||||||
User: query.Get("user"),
|
User: query.Get("user"),
|
||||||
Pass: query.Get("pass"),
|
Pass: query.Get("pass"),
|
||||||
@@ -344,6 +348,7 @@ func (c *conn) apiItem() *defs.APIRTMPConn {
|
|||||||
Path: c.pathName,
|
Path: c.pathName,
|
||||||
Query: c.query,
|
Query: c.query,
|
||||||
User: c.user,
|
User: c.user,
|
||||||
|
UserAgent: c.userAgent,
|
||||||
InboundBytes: bytesReceived,
|
InboundBytes: bytesReceived,
|
||||||
OutboundBytes: bytesSent,
|
OutboundBytes: bytesSent,
|
||||||
BytesReceived: bytesReceived,
|
BytesReceived: bytesReceived,
|
||||||
|
|||||||
@@ -196,6 +196,7 @@ func TestServerPublish(t *testing.T) {
|
|||||||
Path: "teststream",
|
Path: "teststream",
|
||||||
Query: "user=myuser&pass=mypass¶m=value",
|
Query: "user=myuser&pass=mypass¶m=value",
|
||||||
User: "myuser",
|
User: "myuser",
|
||||||
|
UserAgent: list.Items[0].UserAgent,
|
||||||
InboundBytes: list.Items[0].InboundBytes,
|
InboundBytes: list.Items[0].InboundBytes,
|
||||||
OutboundBytes: list.Items[0].OutboundBytes,
|
OutboundBytes: list.Items[0].OutboundBytes,
|
||||||
OutboundFramesDiscarded: list.Items[0].OutboundFramesDiscarded,
|
OutboundFramesDiscarded: list.Items[0].OutboundFramesDiscarded,
|
||||||
@@ -351,6 +352,7 @@ func TestServerRead(t *testing.T) {
|
|||||||
Path: "teststream",
|
Path: "teststream",
|
||||||
Query: "user=myuser&pass=mypass¶m=value",
|
Query: "user=myuser&pass=mypass¶m=value",
|
||||||
User: "myuser",
|
User: "myuser",
|
||||||
|
UserAgent: list.Items[0].UserAgent,
|
||||||
InboundBytes: list.Items[0].InboundBytes,
|
InboundBytes: list.Items[0].InboundBytes,
|
||||||
OutboundBytes: list.Items[0].OutboundBytes,
|
OutboundBytes: list.Items[0].OutboundBytes,
|
||||||
OutboundFramesDiscarded: list.Items[0].OutboundFramesDiscarded,
|
OutboundFramesDiscarded: list.Items[0].OutboundFramesDiscarded,
|
||||||
|
|||||||
@@ -188,6 +188,7 @@ func TestServerPublish(t *testing.T) {
|
|||||||
Path: "teststream",
|
Path: "teststream",
|
||||||
Query: "param=value",
|
Query: "param=value",
|
||||||
User: "myuser",
|
User: "myuser",
|
||||||
|
UserAgent: list.Items[0].UserAgent,
|
||||||
InboundBytes: list.Items[0].InboundBytes,
|
InboundBytes: list.Items[0].InboundBytes,
|
||||||
InboundRTPPackets: list.Items[0].InboundRTPPackets,
|
InboundRTPPackets: list.Items[0].InboundRTPPackets,
|
||||||
OutboundBytes: list.Items[0].OutboundBytes,
|
OutboundBytes: list.Items[0].OutboundBytes,
|
||||||
@@ -510,6 +511,7 @@ func TestServerRead(t *testing.T) {
|
|||||||
Path: "teststream",
|
Path: "teststream",
|
||||||
Query: "param=value",
|
Query: "param=value",
|
||||||
User: "myuser",
|
User: "myuser",
|
||||||
|
UserAgent: list.Items[0].UserAgent,
|
||||||
InboundBytes: list.Items[0].InboundBytes,
|
InboundBytes: list.Items[0].InboundBytes,
|
||||||
InboundRTPPackets: list.Items[0].InboundRTPPackets,
|
InboundRTPPackets: list.Items[0].InboundRTPPackets,
|
||||||
OutboundBytes: list.Items[0].OutboundBytes,
|
OutboundBytes: list.Items[0].OutboundBytes,
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ type session struct {
|
|||||||
outboundRTPPacketsDiscarded *counterdumper.Dumper
|
outboundRTPPacketsDiscarded *counterdumper.Dumper
|
||||||
mutex sync.RWMutex
|
mutex sync.RWMutex
|
||||||
user string
|
user string
|
||||||
|
userAgent string
|
||||||
mpegtsDemuxer *mpegtsDemuxer
|
mpegtsDemuxer *mpegtsDemuxer
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,11 +195,17 @@ func (s *session) onAnnounce(c *conn, ctx *gortsplib.ServerHandlerOnAnnounceCtx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var userAgent string
|
||||||
|
if ua, ok := ctx.Request.Header["User-Agent"]; ok && len(ua) > 0 {
|
||||||
|
userAgent = ua[0]
|
||||||
|
}
|
||||||
|
|
||||||
res, err := s.pathManager.FindPathConf(defs.PathFindPathConfReq{
|
res, err := s.pathManager.FindPathConf(defs.PathFindPathConfReq{
|
||||||
AccessRequest: defs.PathAccessRequest{
|
AccessRequest: defs.PathAccessRequest{
|
||||||
Name: ctx.Path,
|
Name: ctx.Path,
|
||||||
Query: ctx.Query,
|
Query: ctx.Query,
|
||||||
Publish: true,
|
Publish: true,
|
||||||
|
UserAgent: userAgent,
|
||||||
Proto: auth.ProtocolRTSP,
|
Proto: auth.ProtocolRTSP,
|
||||||
ID: &c.uuid,
|
ID: &c.uuid,
|
||||||
Credentials: rtsp.Credentials(ctx.Request),
|
Credentials: rtsp.Credentials(ctx.Request),
|
||||||
@@ -221,6 +228,7 @@ func (s *session) onAnnounce(c *conn, ctx *gortsplib.ServerHandlerOnAnnounceCtx)
|
|||||||
|
|
||||||
s.mutex.Lock()
|
s.mutex.Lock()
|
||||||
s.user = res.User
|
s.user = res.User
|
||||||
|
s.userAgent = userAgent
|
||||||
s.mutex.Unlock()
|
s.mutex.Unlock()
|
||||||
|
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
@@ -266,6 +274,11 @@ func (s *session) onSetup(c *conn, ctx *gortsplib.ServerHandlerOnSetupCtx,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var userAgent string
|
||||||
|
if ua, ok := ctx.Request.Header["User-Agent"]; ok && len(ua) > 0 {
|
||||||
|
userAgent = ua[0]
|
||||||
|
}
|
||||||
|
|
||||||
switch s.rsession.State() {
|
switch s.rsession.State() {
|
||||||
case gortsplib.ServerSessionStateInitial: // play
|
case gortsplib.ServerSessionStateInitial: // play
|
||||||
res, err := s.pathManager.AddReader(defs.PathAddReaderReq{
|
res, err := s.pathManager.AddReader(defs.PathAddReaderReq{
|
||||||
@@ -273,6 +286,7 @@ func (s *session) onSetup(c *conn, ctx *gortsplib.ServerHandlerOnSetupCtx,
|
|||||||
AccessRequest: defs.PathAccessRequest{
|
AccessRequest: defs.PathAccessRequest{
|
||||||
Name: ctx.Path,
|
Name: ctx.Path,
|
||||||
Query: ctx.Query,
|
Query: ctx.Query,
|
||||||
|
UserAgent: userAgent,
|
||||||
Proto: auth.ProtocolRTSP,
|
Proto: auth.ProtocolRTSP,
|
||||||
ID: &c.uuid,
|
ID: &c.uuid,
|
||||||
Credentials: rtsp.Credentials(ctx.Request),
|
Credentials: rtsp.Credentials(ctx.Request),
|
||||||
@@ -304,6 +318,7 @@ func (s *session) onSetup(c *conn, ctx *gortsplib.ServerHandlerOnSetupCtx,
|
|||||||
|
|
||||||
s.mutex.Lock()
|
s.mutex.Lock()
|
||||||
s.user = res.User
|
s.user = res.User
|
||||||
|
s.userAgent = userAgent
|
||||||
s.mutex.Unlock()
|
s.mutex.Unlock()
|
||||||
|
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
@@ -385,10 +400,11 @@ func (s *session) onRecord(_ *gortsplib.ServerHandlerOnRecordCtx) (*base.Respons
|
|||||||
ReplaceNTP: !s.pathConf.UseAbsoluteTimestamp,
|
ReplaceNTP: !s.pathConf.UseAbsoluteTimestamp,
|
||||||
ConfToCompare: s.pathConf,
|
ConfToCompare: s.pathConf,
|
||||||
AccessRequest: defs.PathAccessRequest{
|
AccessRequest: defs.PathAccessRequest{
|
||||||
Name: s.rsession.Path()[1:],
|
Name: s.rsession.Path()[1:],
|
||||||
Query: s.rsession.Query(),
|
Query: s.rsession.Query(),
|
||||||
Publish: true,
|
Publish: true,
|
||||||
SkipAuth: true,
|
SkipAuth: true,
|
||||||
|
UserAgent: s.userAgent,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -507,8 +523,9 @@ func (s *session) apiItem() *defs.APIRTSPSession {
|
|||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}(),
|
}(),
|
||||||
Query: s.rsession.Query(),
|
Query: s.rsession.Query(),
|
||||||
User: s.user,
|
User: s.user,
|
||||||
|
UserAgent: s.userAgent,
|
||||||
Transport: func() *string {
|
Transport: func() *string {
|
||||||
transport := s.rsession.Transport()
|
transport := s.rsession.Transport()
|
||||||
if transport == nil {
|
if transport == nil {
|
||||||
|
|||||||
@@ -142,6 +142,7 @@ func (s *httpServer) checkAuthOutsideSession(ctx *gin.Context, pathName string,
|
|||||||
Name: pathName,
|
Name: pathName,
|
||||||
Query: ctx.Request.URL.RawQuery,
|
Query: ctx.Request.URL.RawQuery,
|
||||||
Publish: publish,
|
Publish: publish,
|
||||||
|
UserAgent: ctx.Request.Header.Get("User-Agent"),
|
||||||
Proto: auth.ProtocolWebRTC,
|
Proto: auth.ProtocolWebRTC,
|
||||||
Credentials: httpp.Credentials(ctx.Request),
|
Credentials: httpp.Credentials(ctx.Request),
|
||||||
IP: net.ParseIP(ctx.ClientIP()),
|
IP: net.ParseIP(ctx.ClientIP()),
|
||||||
|
|||||||
@@ -469,6 +469,7 @@ func TestServerPublish(t *testing.T) {
|
|||||||
Path: "teststream",
|
Path: "teststream",
|
||||||
Query: "param=value",
|
Query: "param=value",
|
||||||
User: "myuser",
|
User: "myuser",
|
||||||
|
UserAgent: list.Items[0].UserAgent,
|
||||||
InboundBytes: list.Items[0].InboundBytes,
|
InboundBytes: list.Items[0].InboundBytes,
|
||||||
InboundRTPPackets: list.Items[0].InboundRTPPackets,
|
InboundRTPPackets: list.Items[0].InboundRTPPackets,
|
||||||
InboundRTPPacketsLost: list.Items[0].InboundRTPPacketsLost,
|
InboundRTPPacketsLost: list.Items[0].InboundRTPPacketsLost,
|
||||||
@@ -763,6 +764,7 @@ func TestServerRead(t *testing.T) {
|
|||||||
Path: "teststream",
|
Path: "teststream",
|
||||||
Query: "param=value",
|
Query: "param=value",
|
||||||
User: "myuser",
|
User: "myuser",
|
||||||
|
UserAgent: list.Items[0].UserAgent,
|
||||||
InboundBytes: list.Items[0].InboundBytes,
|
InboundBytes: list.Items[0].InboundBytes,
|
||||||
InboundRTPPackets: list.Items[0].InboundRTPPackets,
|
InboundRTPPackets: list.Items[0].InboundRTPPackets,
|
||||||
InboundRTPPacketsLost: list.Items[0].InboundRTPPacketsLost,
|
InboundRTPPacketsLost: list.Items[0].InboundRTPPacketsLost,
|
||||||
|
|||||||
@@ -341,6 +341,7 @@ func (s *session) runPublish(req *initialRequestReq) (int, error) {
|
|||||||
Name: s.pathName,
|
Name: s.pathName,
|
||||||
Query: s.httpRequest.URL.RawQuery,
|
Query: s.httpRequest.URL.RawQuery,
|
||||||
Publish: true,
|
Publish: true,
|
||||||
|
UserAgent: s.httpRequest.Header.Get("User-Agent"),
|
||||||
Proto: auth.ProtocolWebRTC,
|
Proto: auth.ProtocolWebRTC,
|
||||||
ID: &s.uuid,
|
ID: &s.uuid,
|
||||||
Credentials: httpp.Credentials(s.httpRequest),
|
Credentials: httpp.Credentials(s.httpRequest),
|
||||||
@@ -449,10 +450,11 @@ func (s *session) runPublish(req *initialRequestReq) (int, error) {
|
|||||||
ReplaceNTP: !res1.Conf.UseAbsoluteTimestamp,
|
ReplaceNTP: !res1.Conf.UseAbsoluteTimestamp,
|
||||||
ConfToCompare: res1.Conf,
|
ConfToCompare: res1.Conf,
|
||||||
AccessRequest: defs.PathAccessRequest{
|
AccessRequest: defs.PathAccessRequest{
|
||||||
Name: s.pathName,
|
Name: s.pathName,
|
||||||
Query: s.httpRequest.URL.RawQuery,
|
Query: s.httpRequest.URL.RawQuery,
|
||||||
Publish: true,
|
Publish: true,
|
||||||
SkipAuth: true,
|
SkipAuth: true,
|
||||||
|
UserAgent: s.httpRequest.Header.Get("User-Agent"),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -482,6 +484,7 @@ func (s *session) runRead(req *initialRequestReq) (int, error) {
|
|||||||
AccessRequest: defs.PathAccessRequest{
|
AccessRequest: defs.PathAccessRequest{
|
||||||
Name: s.pathName,
|
Name: s.pathName,
|
||||||
Query: s.httpRequest.URL.RawQuery,
|
Query: s.httpRequest.URL.RawQuery,
|
||||||
|
UserAgent: s.httpRequest.Header.Get("User-Agent"),
|
||||||
Proto: auth.ProtocolWebRTC,
|
Proto: auth.ProtocolWebRTC,
|
||||||
ID: &s.uuid,
|
ID: &s.uuid,
|
||||||
Credentials: httpp.Credentials(s.httpRequest),
|
Credentials: httpp.Credentials(s.httpRequest),
|
||||||
@@ -754,6 +757,7 @@ func (s *session) apiItem() *defs.APIWebRTCSession {
|
|||||||
Path: s.pathName,
|
Path: s.pathName,
|
||||||
Query: s.httpRequest.URL.RawQuery,
|
Query: s.httpRequest.URL.RawQuery,
|
||||||
User: s.user,
|
User: s.user,
|
||||||
|
UserAgent: s.httpRequest.Header.Get("User-Agent"),
|
||||||
InboundBytes: bytesReceived,
|
InboundBytes: bytesReceived,
|
||||||
InboundRTPPackets: rtpPacketsReceived,
|
InboundRTPPackets: rtpPacketsReceived,
|
||||||
InboundRTPPacketsLost: rtpPacketsLost,
|
InboundRTPPacketsLost: rtpPacketsLost,
|
||||||
|
|||||||
+1
-12
@@ -94,18 +94,7 @@ authInternalUsers:
|
|||||||
# HTTP-based authentication.
|
# HTTP-based authentication.
|
||||||
# URL called to perform authentication. Every time a user wants
|
# URL called to perform authentication. Every time a user wants
|
||||||
# to authenticate, the server calls this URL with the POST method
|
# to authenticate, the server calls this URL with the POST method
|
||||||
# and a body containing:
|
# and a payload described in the documentation.
|
||||||
# {
|
|
||||||
# "user": "user",
|
|
||||||
# "password": "password",
|
|
||||||
# "token": "token",
|
|
||||||
# "ip": "ip",
|
|
||||||
# "action": "publish|read|playback|api|metrics|pprof",
|
|
||||||
# "path": "path",
|
|
||||||
# "protocol": "rtsp|rtmp|hls|webrtc|srt",
|
|
||||||
# "id": "id",
|
|
||||||
# "query": "query"
|
|
||||||
# }
|
|
||||||
# If the response code is 20x, authentication is accepted, otherwise
|
# If the response code is 20x, authentication is accepted, otherwise
|
||||||
# it is discarded.
|
# it is discarded.
|
||||||
authHTTPAddress:
|
authHTTPAddress:
|
||||||
|
|||||||
Reference in New Issue
Block a user