support multiple CORS origins (#5150)

Co-authored-by: aler9 <46489434+aler9@users.noreply.github.com>
This commit is contained in:
KHuynh 2025-11-21 02:00:46 +01:00 committed by GitHub
parent 14ab95f39c
commit ade0cddeb3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 441 additions and 180 deletions

View file

@ -124,8 +124,10 @@ components:
type: string type: string
apiServerCert: apiServerCert:
type: string type: string
apiAllowOrigin: apiAllowOrigins:
type: string type: array
items:
type: string
apiTrustedProxies: apiTrustedProxies:
type: array type: array
items: items:
@ -142,8 +144,10 @@ components:
type: string type: string
metricsServerCert: metricsServerCert:
type: string type: string
metricsAllowOrigin: metricsAllowOrigins:
type: string type: array
items:
type: string
metricsTrustedProxies: metricsTrustedProxies:
type: array type: array
items: items:
@ -160,8 +164,10 @@ components:
type: string type: string
pprofServerCert: pprofServerCert:
type: string type: string
pprofAllowOrigin: pprofAllowOrigins:
type: string type: array
items:
type: string
pprofTrustedProxies: pprofTrustedProxies:
type: array type: array
items: items:
@ -178,8 +184,10 @@ components:
type: string type: string
playbackServerCert: playbackServerCert:
type: string type: string
playbackAllowOrigin: playbackAllowOrigins:
type: string type: array
items:
type: string
playbackTrustedProxies: playbackTrustedProxies:
type: array type: array
items: items:
@ -254,8 +262,10 @@ components:
type: string type: string
hlsServerCert: hlsServerCert:
type: string type: string
hlsAllowOrigin: hlsAllowOrigins:
type: string type: array
items:
type: string
hlsTrustedProxies: hlsTrustedProxies:
type: array type: array
items: items:
@ -289,8 +299,10 @@ components:
type: string type: string
webrtcServerCert: webrtcServerCert:
type: string type: string
webrtcAllowOrigin: webrtcAllowOrigins:
type: string type: array
items:
type: string
webrtcTrustedProxies: webrtcTrustedProxies:
type: array type: array
items: items:

View file

@ -94,7 +94,7 @@ type API struct {
Encryption bool Encryption bool
ServerKey string ServerKey string
ServerCert string ServerCert string
AllowOrigin string AllowOrigins []string
TrustedProxies conf.IPNetworks TrustedProxies conf.IPNetworks
ReadTimeout conf.Duration ReadTimeout conf.Duration
WriteTimeout conf.Duration WriteTimeout conf.Duration
@ -119,7 +119,7 @@ func (a *API) Initialize() error {
router := gin.New() router := gin.New()
router.SetTrustedProxies(a.TrustedProxies.ToTrustedProxies()) //nolint:errcheck router.SetTrustedProxies(a.TrustedProxies.ToTrustedProxies()) //nolint:errcheck
router.Use(a.middlewareOrigin) router.Use(a.middlewarePreflightRequests)
router.Use(a.middlewareAuth) router.Use(a.middlewareAuth)
group := router.Group("/v3") group := router.Group("/v3")
@ -195,6 +195,7 @@ func (a *API) Initialize() error {
a.httpServer = &httpp.Server{ a.httpServer = &httpp.Server{
Address: a.Address, Address: a.Address,
AllowOrigins: a.AllowOrigins,
ReadTimeout: time.Duration(a.ReadTimeout), ReadTimeout: time.Duration(a.ReadTimeout),
WriteTimeout: time.Duration(a.WriteTimeout), WriteTimeout: time.Duration(a.WriteTimeout),
Encryption: a.Encryption, Encryption: a.Encryption,
@ -234,11 +235,7 @@ func (a *API) writeError(ctx *gin.Context, status int, err error) {
}) })
} }
func (a *API) middlewareOrigin(ctx *gin.Context) { func (a *API) middlewarePreflightRequests(ctx *gin.Context) {
ctx.Header("Access-Control-Allow-Origin", a.AllowOrigin)
ctx.Header("Access-Control-Allow-Credentials", "true")
// preflight requests
if ctx.Request.Method == http.MethodOptions && if ctx.Request.Method == http.MethodOptions &&
ctx.Request.Header.Get("Access-Control-Request-Method") != "" { ctx.Request.Header.Get("Access-Control-Request-Method") != "" {
ctx.Header("Access-Control-Allow-Methods", "OPTIONS, GET, POST, PATCH, DELETE") ctx.Header("Access-Control-Allow-Methods", "OPTIONS, GET, POST, PATCH, DELETE")

View file

@ -83,7 +83,7 @@ func checkError(t *testing.T, msg string, body io.Reader) {
func TestPreflightRequest(t *testing.T) { func TestPreflightRequest(t *testing.T) {
api := API{ api := API{
Address: "localhost:9997", Address: "localhost:9997",
AllowOrigin: "*", AllowOrigins: []string{"*"},
ReadTimeout: conf.Duration(10 * time.Second), ReadTimeout: conf.Duration(10 * time.Second),
WriteTimeout: conf.Duration(10 * time.Second), WriteTimeout: conf.Duration(10 * time.Second),
AuthManager: test.NilAuthManager, AuthManager: test.NilAuthManager,

View file

@ -0,0 +1,4 @@
package conf
// AllowedOrigins is a list of allowed CORS origins.
type AllowedOrigins []string

View file

@ -177,40 +177,44 @@ type Conf struct {
AuthJWTInHTTPQuery bool `json:"authJWTInHTTPQuery"` AuthJWTInHTTPQuery bool `json:"authJWTInHTTPQuery"`
// Control API // Control API
API bool `json:"api"` API bool `json:"api"`
APIAddress string `json:"apiAddress"` APIAddress string `json:"apiAddress"`
APIEncryption bool `json:"apiEncryption"` APIEncryption bool `json:"apiEncryption"`
APIServerKey string `json:"apiServerKey"` APIServerKey string `json:"apiServerKey"`
APIServerCert string `json:"apiServerCert"` APIServerCert string `json:"apiServerCert"`
APIAllowOrigin string `json:"apiAllowOrigin"` APIAllowOrigin *string `json:"apiAllowOrigin,omitempty"` // deprecated
APITrustedProxies IPNetworks `json:"apiTrustedProxies"` APIAllowOrigins AllowedOrigins `json:"apiAllowOrigins"`
APITrustedProxies IPNetworks `json:"apiTrustedProxies"`
// Metrics // Metrics
Metrics bool `json:"metrics"` Metrics bool `json:"metrics"`
MetricsAddress string `json:"metricsAddress"` MetricsAddress string `json:"metricsAddress"`
MetricsEncryption bool `json:"metricsEncryption"` MetricsEncryption bool `json:"metricsEncryption"`
MetricsServerKey string `json:"metricsServerKey"` MetricsServerKey string `json:"metricsServerKey"`
MetricsServerCert string `json:"metricsServerCert"` MetricsServerCert string `json:"metricsServerCert"`
MetricsAllowOrigin string `json:"metricsAllowOrigin"` MetricsAllowOrigin *string `json:"metricsAllowOrigin,omitempty"` // deprecated
MetricsTrustedProxies IPNetworks `json:"metricsTrustedProxies"` MetricsAllowOrigins AllowedOrigins `json:"metricsAllowOrigins"`
MetricsTrustedProxies IPNetworks `json:"metricsTrustedProxies"`
// PPROF // PPROF
PPROF bool `json:"pprof"` PPROF bool `json:"pprof"`
PPROFAddress string `json:"pprofAddress"` PPROFAddress string `json:"pprofAddress"`
PPROFEncryption bool `json:"pprofEncryption"` PPROFEncryption bool `json:"pprofEncryption"`
PPROFServerKey string `json:"pprofServerKey"` PPROFServerKey string `json:"pprofServerKey"`
PPROFServerCert string `json:"pprofServerCert"` PPROFServerCert string `json:"pprofServerCert"`
PPROFAllowOrigin string `json:"pprofAllowOrigin"` PPROFAllowOrigin *string `json:"pprofAllowOrigin,omitempty"` // deprecated
PPROFTrustedProxies IPNetworks `json:"pprofTrustedProxies"` PPROFAllowOrigins AllowedOrigins `json:"pprofAllowOrigins"`
PPROFTrustedProxies IPNetworks `json:"pprofTrustedProxies"`
// Playback // Playback
Playback bool `json:"playback"` Playback bool `json:"playback"`
PlaybackAddress string `json:"playbackAddress"` PlaybackAddress string `json:"playbackAddress"`
PlaybackEncryption bool `json:"playbackEncryption"` PlaybackEncryption bool `json:"playbackEncryption"`
PlaybackServerKey string `json:"playbackServerKey"` PlaybackServerKey string `json:"playbackServerKey"`
PlaybackServerCert string `json:"playbackServerCert"` PlaybackServerCert string `json:"playbackServerCert"`
PlaybackAllowOrigin string `json:"playbackAllowOrigin"` PlaybackAllowOrigin *string `json:"playbackAllowOrigin,omitempty"` // deprecated
PlaybackTrustedProxies IPNetworks `json:"playbackTrustedProxies"` PlaybackAllowOrigins AllowedOrigins `json:"playbackAllowOrigins"`
PlaybackTrustedProxies IPNetworks `json:"playbackTrustedProxies"`
// RTSP server // RTSP server
RTSP bool `json:"rtsp"` RTSP bool `json:"rtsp"`
@ -248,22 +252,23 @@ type Conf struct {
RTMPServerCert string `json:"rtmpServerCert"` RTMPServerCert string `json:"rtmpServerCert"`
// HLS server // HLS server
HLS bool `json:"hls"` HLS bool `json:"hls"`
HLSDisable *bool `json:"hlsDisable,omitempty"` // deprecated HLSDisable *bool `json:"hlsDisable,omitempty"` // deprecated
HLSAddress string `json:"hlsAddress"` HLSAddress string `json:"hlsAddress"`
HLSEncryption bool `json:"hlsEncryption"` HLSEncryption bool `json:"hlsEncryption"`
HLSServerKey string `json:"hlsServerKey"` HLSServerKey string `json:"hlsServerKey"`
HLSServerCert string `json:"hlsServerCert"` HLSServerCert string `json:"hlsServerCert"`
HLSAllowOrigin string `json:"hlsAllowOrigin"` HLSAllowOrigin *string `json:"hlsAllowOrigin,omitempty"` // deprecated
HLSTrustedProxies IPNetworks `json:"hlsTrustedProxies"` HLSAllowOrigins AllowedOrigins `json:"hlsAllowOrigins"`
HLSAlwaysRemux bool `json:"hlsAlwaysRemux"` HLSTrustedProxies IPNetworks `json:"hlsTrustedProxies"`
HLSVariant HLSVariant `json:"hlsVariant"` HLSAlwaysRemux bool `json:"hlsAlwaysRemux"`
HLSSegmentCount int `json:"hlsSegmentCount"` HLSVariant HLSVariant `json:"hlsVariant"`
HLSSegmentDuration Duration `json:"hlsSegmentDuration"` HLSSegmentCount int `json:"hlsSegmentCount"`
HLSPartDuration Duration `json:"hlsPartDuration"` HLSSegmentDuration Duration `json:"hlsSegmentDuration"`
HLSSegmentMaxSize StringSize `json:"hlsSegmentMaxSize"` HLSPartDuration Duration `json:"hlsPartDuration"`
HLSDirectory string `json:"hlsDirectory"` HLSSegmentMaxSize StringSize `json:"hlsSegmentMaxSize"`
HLSMuxerCloseAfter Duration `json:"hlsMuxerCloseAfter"` HLSDirectory string `json:"hlsDirectory"`
HLSMuxerCloseAfter Duration `json:"hlsMuxerCloseAfter"`
// WebRTC server // WebRTC server
WebRTC bool `json:"webrtc"` WebRTC bool `json:"webrtc"`
@ -272,7 +277,8 @@ type Conf struct {
WebRTCEncryption bool `json:"webrtcEncryption"` WebRTCEncryption bool `json:"webrtcEncryption"`
WebRTCServerKey string `json:"webrtcServerKey"` WebRTCServerKey string `json:"webrtcServerKey"`
WebRTCServerCert string `json:"webrtcServerCert"` WebRTCServerCert string `json:"webrtcServerCert"`
WebRTCAllowOrigin string `json:"webrtcAllowOrigin"` WebRTCAllowOrigin *string `json:"webrtcAllowOrigin,omitempty"` // deprecated
WebRTCAllowOrigins AllowedOrigins `json:"webrtcAllowOrigins"`
WebRTCTrustedProxies IPNetworks `json:"webrtcTrustedProxies"` WebRTCTrustedProxies IPNetworks `json:"webrtcTrustedProxies"`
WebRTCLocalUDPAddress string `json:"webrtcLocalUDPAddress"` WebRTCLocalUDPAddress string `json:"webrtcLocalUDPAddress"`
WebRTCLocalTCPAddress string `json:"webrtcLocalTCPAddress"` WebRTCLocalTCPAddress string `json:"webrtcLocalTCPAddress"`
@ -340,25 +346,25 @@ func (conf *Conf) setDefaults() {
conf.APIAddress = ":9997" conf.APIAddress = ":9997"
conf.APIServerKey = "server.key" conf.APIServerKey = "server.key"
conf.APIServerCert = "server.crt" conf.APIServerCert = "server.crt"
conf.APIAllowOrigin = "*" conf.APIAllowOrigins = []string{"*"}
// Metrics // Metrics
conf.MetricsAddress = ":9998" conf.MetricsAddress = ":9998"
conf.MetricsServerKey = "server.key" conf.MetricsServerKey = "server.key"
conf.MetricsServerCert = "server.crt" conf.MetricsServerCert = "server.crt"
conf.MetricsAllowOrigin = "*" conf.MetricsAllowOrigins = []string{"*"}
// PPROF // PPROF
conf.PPROFAddress = ":9999" conf.PPROFAddress = ":9999"
conf.PPROFServerKey = "server.key" conf.PPROFServerKey = "server.key"
conf.PPROFServerCert = "server.crt" conf.PPROFServerCert = "server.crt"
conf.PPROFAllowOrigin = "*" conf.PPROFAllowOrigins = []string{"*"}
// Playback server // Playback server
conf.PlaybackAddress = ":9996" conf.PlaybackAddress = ":9996"
conf.PlaybackServerKey = "server.key" conf.PlaybackServerKey = "server.key"
conf.PlaybackServerCert = "server.crt" conf.PlaybackServerCert = "server.crt"
conf.PlaybackAllowOrigin = "*" conf.PlaybackAllowOrigins = []string{"*"}
// RTSP server // RTSP server
conf.RTSP = true conf.RTSP = true
@ -394,7 +400,7 @@ func (conf *Conf) setDefaults() {
conf.HLSAddress = ":8888" conf.HLSAddress = ":8888"
conf.HLSServerKey = "server.key" conf.HLSServerKey = "server.key"
conf.HLSServerCert = "server.crt" conf.HLSServerCert = "server.crt"
conf.HLSAllowOrigin = "*" conf.HLSAllowOrigins = []string{"*"}
conf.HLSVariant = HLSVariant(gohlslib.MuxerVariantLowLatency) conf.HLSVariant = HLSVariant(gohlslib.MuxerVariantLowLatency)
conf.HLSSegmentCount = 7 conf.HLSSegmentCount = 7
conf.HLSSegmentDuration = 1 * Duration(time.Second) conf.HLSSegmentDuration = 1 * Duration(time.Second)
@ -407,7 +413,7 @@ func (conf *Conf) setDefaults() {
conf.WebRTCAddress = ":8889" conf.WebRTCAddress = ":8889"
conf.WebRTCServerKey = "server.key" conf.WebRTCServerKey = "server.key"
conf.WebRTCServerCert = "server.crt" conf.WebRTCServerCert = "server.crt"
conf.WebRTCAllowOrigin = "*" conf.WebRTCAllowOrigins = []string{"*"}
conf.WebRTCLocalUDPAddress = ":8189" conf.WebRTCLocalUDPAddress = ":8189"
conf.WebRTCIPsFromInterfaces = true conf.WebRTCIPsFromInterfaces = true
conf.WebRTCIPsFromInterfacesList = []string{} conf.WebRTCIPsFromInterfacesList = []string{}
@ -522,16 +528,20 @@ func (conf *Conf) Validate(l logger.Writer) error {
if conf.ReadTimeout <= 0 { if conf.ReadTimeout <= 0 {
return fmt.Errorf("'readTimeout' must be greater than zero") return fmt.Errorf("'readTimeout' must be greater than zero")
} }
if conf.WriteTimeout <= 0 { if conf.WriteTimeout <= 0 {
return fmt.Errorf("'writeTimeout' must be greater than zero") return fmt.Errorf("'writeTimeout' must be greater than zero")
} }
if conf.ReadBufferCount != nil { if conf.ReadBufferCount != nil {
l.Log(logger.Warn, "parameter 'readBufferCount' is deprecated and has been replaced with 'writeQueueSize'") l.Log(logger.Warn, "parameter 'readBufferCount' is deprecated and has been replaced with 'writeQueueSize'")
conf.WriteQueueSize = *conf.ReadBufferCount conf.WriteQueueSize = *conf.ReadBufferCount
} }
if (conf.WriteQueueSize & (conf.WriteQueueSize - 1)) != 0 { if (conf.WriteQueueSize & (conf.WriteQueueSize - 1)) != 0 {
return fmt.Errorf("'writeQueueSize' must be a power of two") return fmt.Errorf("'writeQueueSize' must be a power of two")
} }
if conf.UDPMaxPayloadSize > 1472 { if conf.UDPMaxPayloadSize > 1472 {
return fmt.Errorf("'udpMaxPayloadSize' must be less than 1472") return fmt.Errorf("'udpMaxPayloadSize' must be less than 1472")
} }
@ -544,16 +554,19 @@ func (conf *Conf) Validate(l logger.Writer) error {
conf.AuthMethod = AuthMethodHTTP conf.AuthMethod = AuthMethodHTTP
conf.AuthHTTPAddress = *conf.ExternalAuthenticationURL conf.AuthHTTPAddress = *conf.ExternalAuthenticationURL
} }
if conf.AuthHTTPAddress != "" && if conf.AuthHTTPAddress != "" &&
!strings.HasPrefix(conf.AuthHTTPAddress, "http://") && !strings.HasPrefix(conf.AuthHTTPAddress, "http://") &&
!strings.HasPrefix(conf.AuthHTTPAddress, "https://") { !strings.HasPrefix(conf.AuthHTTPAddress, "https://") {
return fmt.Errorf("'externalAuthenticationURL' must be a HTTP URL") return fmt.Errorf("'externalAuthenticationURL' must be a HTTP URL")
} }
if conf.AuthJWTJWKS != "" && if conf.AuthJWTJWKS != "" &&
!strings.HasPrefix(conf.AuthJWTJWKS, "http://") && !strings.HasPrefix(conf.AuthJWTJWKS, "http://") &&
!strings.HasPrefix(conf.AuthJWTJWKS, "https://") { !strings.HasPrefix(conf.AuthJWTJWKS, "https://") {
return fmt.Errorf("'authJWTJWKS' must be a HTTP URL") return fmt.Errorf("'authJWTJWKS' must be a HTTP URL")
} }
deprecatedCredentialsMode := false deprecatedCredentialsMode := false
if anyPathHasDeprecatedCredentials(conf.PathDefaults, conf.OptionalPaths) { if anyPathHasDeprecatedCredentials(conf.PathDefaults, conf.OptionalPaths) {
l.Log(logger.Warn, "you are using one or more authentication-related deprecated parameters "+ l.Log(logger.Warn, "you are using one or more authentication-related deprecated parameters "+
@ -592,6 +605,7 @@ func (conf *Conf) Validate(l logger.Writer) error {
} }
deprecatedCredentialsMode = true deprecatedCredentialsMode = true
} }
switch conf.AuthMethod { switch conf.AuthMethod {
case AuthMethodHTTP: case AuthMethodHTTP:
if conf.AuthHTTPAddress == "" { if conf.AuthHTTPAddress == "" {
@ -607,24 +621,56 @@ func (conf *Conf) Validate(l logger.Writer) error {
} }
} }
// RTSP // Control API
if conf.APIAllowOrigin != nil {
l.Log(logger.Warn, "parameter 'apiAllowOrigin' is deprecated and has been replaced with 'apiAllowOrigins'")
conf.APIAllowOrigins = []string{*conf.APIAllowOrigin}
}
// Metrics
if conf.MetricsAllowOrigin != nil {
l.Log(logger.Warn, "parameter 'metricsAllowOrigin' is deprecated and has been replaced with 'metricsAllowOrigins'")
conf.MetricsAllowOrigins = []string{*conf.MetricsAllowOrigin}
}
// PPROF
if conf.PPROFAllowOrigin != nil {
l.Log(logger.Warn, "parameter 'pprofAllowOrigin' is deprecated and has been replaced with 'pprofAllowOrigins'")
conf.PPROFAllowOrigins = []string{*conf.PPROFAllowOrigin}
}
// Playback
if conf.PlaybackAllowOrigin != nil {
l.Log(logger.Warn, "parameter 'playbackAllowOrigin' is deprecated and has been replaced with 'playbackAllowOrigins'")
conf.PlaybackAllowOrigins = []string{*conf.PlaybackAllowOrigin}
}
// RTSP server
if conf.RTSPDisable != nil { if conf.RTSPDisable != nil {
l.Log(logger.Warn, "parameter 'rtspDisabled' is deprecated and has been replaced with 'rtsp'") l.Log(logger.Warn, "parameter 'rtspDisabled' is deprecated and has been replaced with 'rtsp'")
conf.RTSP = !*conf.RTSPDisable conf.RTSP = !*conf.RTSPDisable
} }
if conf.Protocols != nil { if conf.Protocols != nil {
l.Log(logger.Warn, "parameter 'protocols' is deprecated and has been replaced with 'rtspTransports'") l.Log(logger.Warn, "parameter 'protocols' is deprecated and has been replaced with 'rtspTransports'")
conf.RTSPTransports = *conf.Protocols conf.RTSPTransports = *conf.Protocols
} }
if conf.Encryption != nil { if conf.Encryption != nil {
l.Log(logger.Warn, "parameter 'encryption' is deprecated and has been replaced with 'rtspEncryption'") l.Log(logger.Warn, "parameter 'encryption' is deprecated and has been replaced with 'rtspEncryption'")
conf.RTSPEncryption = *conf.Encryption conf.RTSPEncryption = *conf.Encryption
} }
if conf.AuthMethods != nil { if conf.AuthMethods != nil {
l.Log(logger.Warn, "parameter 'authMethods' is deprecated and has been replaced with 'rtspAuthMethods'") l.Log(logger.Warn, "parameter 'authMethods' is deprecated and has been replaced with 'rtspAuthMethods'")
conf.RTSPAuthMethods = *conf.AuthMethods conf.RTSPAuthMethods = *conf.AuthMethods
} }
if slices.Contains(conf.RTSPAuthMethods, auth.VerifyMethodDigestMD5) { if slices.Contains(conf.RTSPAuthMethods, auth.VerifyMethodDigestMD5) {
if conf.AuthMethod != AuthMethodInternal { if conf.AuthMethod != AuthMethodInternal {
return fmt.Errorf("when RTSP digest is enabled, the only supported auth method is 'internal'") return fmt.Errorf("when RTSP digest is enabled, the only supported auth method is 'internal'")
@ -635,14 +681,17 @@ func (conf *Conf) Validate(l logger.Writer) error {
} }
} }
} }
if conf.ServerCert != nil { if conf.ServerCert != nil {
l.Log(logger.Warn, "parameter 'serverCert' is deprecated and has been replaced with 'rtspServerCert'") l.Log(logger.Warn, "parameter 'serverCert' is deprecated and has been replaced with 'rtspServerCert'")
conf.RTSPServerCert = *conf.ServerCert conf.RTSPServerCert = *conf.ServerCert
} }
if conf.ServerKey != nil { if conf.ServerKey != nil {
l.Log(logger.Warn, "parameter 'serverKey' is deprecated and has been replaced with 'rtspServerKey'") l.Log(logger.Warn, "parameter 'serverKey' is deprecated and has been replaced with 'rtspServerKey'")
conf.RTSPServerKey = *conf.ServerKey conf.RTSPServerKey = *conf.ServerKey
} }
if len(conf.RTSPAuthMethods) == 0 { if len(conf.RTSPAuthMethods) == 0 {
return fmt.Errorf("at least one 'rtspAuthMethods' must be provided") return fmt.Errorf("at least one 'rtspAuthMethods' must be provided")
} }
@ -661,27 +710,36 @@ func (conf *Conf) Validate(l logger.Writer) error {
conf.HLS = !*conf.HLSDisable conf.HLS = !*conf.HLSDisable
} }
if conf.HLSAllowOrigin != nil {
l.Log(logger.Warn, "parameter 'hlsAllowOrigin' is deprecated and has been replaced with 'hlsAllowOrigins'")
conf.HLSAllowOrigins = []string{*conf.HLSAllowOrigin}
}
// WebRTC // WebRTC
if conf.WebRTCDisable != nil { if conf.WebRTCDisable != nil {
l.Log(logger.Warn, "parameter 'webrtcDisable' is deprecated and has been replaced with 'webrtc'") l.Log(logger.Warn, "parameter 'webrtcDisable' is deprecated and has been replaced with 'webrtc'")
conf.WebRTC = !*conf.WebRTCDisable conf.WebRTC = !*conf.WebRTCDisable
} }
if conf.WebRTCICEUDPMuxAddress != nil { if conf.WebRTCICEUDPMuxAddress != nil {
l.Log(logger.Warn, "parameter 'webrtcICEUDPMuxAdderss' is deprecated "+ l.Log(logger.Warn, "parameter 'webrtcICEUDPMuxAdderss' is deprecated "+
"and has been replaced with 'webrtcLocalUDPAddress'") "and has been replaced with 'webrtcLocalUDPAddress'")
conf.WebRTCLocalUDPAddress = *conf.WebRTCICEUDPMuxAddress conf.WebRTCLocalUDPAddress = *conf.WebRTCICEUDPMuxAddress
} }
if conf.WebRTCICETCPMuxAddress != nil { if conf.WebRTCICETCPMuxAddress != nil {
l.Log(logger.Warn, "parameter 'webrtcICETCPMuxAddress' is deprecated "+ l.Log(logger.Warn, "parameter 'webrtcICETCPMuxAddress' is deprecated "+
"and has been replaced with 'webrtcLocalTCPAddress'") "and has been replaced with 'webrtcLocalTCPAddress'")
conf.WebRTCLocalTCPAddress = *conf.WebRTCICETCPMuxAddress conf.WebRTCLocalTCPAddress = *conf.WebRTCICETCPMuxAddress
} }
if conf.WebRTCICEHostNAT1To1IPs != nil { if conf.WebRTCICEHostNAT1To1IPs != nil {
l.Log(logger.Warn, "parameter 'webrtcICEHostNAT1To1IPs' is deprecated "+ l.Log(logger.Warn, "parameter 'webrtcICEHostNAT1To1IPs' is deprecated "+
"and has been replaced with 'webrtcAdditionalHosts'") "and has been replaced with 'webrtcAdditionalHosts'")
conf.WebRTCAdditionalHosts = *conf.WebRTCICEHostNAT1To1IPs conf.WebRTCAdditionalHosts = *conf.WebRTCICEHostNAT1To1IPs
} }
if conf.WebRTCICEServers != nil { if conf.WebRTCICEServers != nil {
l.Log(logger.Warn, "parameter 'webrtcICEServers' is deprecated "+ l.Log(logger.Warn, "parameter 'webrtcICEServers' is deprecated "+
"and has been replaced with 'webrtcICEServers2'") "and has been replaced with 'webrtcICEServers2'")
@ -701,6 +759,7 @@ func (conf *Conf) Validate(l logger.Writer) error {
} }
} }
} }
for _, server := range conf.WebRTCICEServers2 { for _, server := range conf.WebRTCICEServers2 {
if !strings.HasPrefix(server.URL, "stun:") && if !strings.HasPrefix(server.URL, "stun:") &&
!strings.HasPrefix(server.URL, "turn:") && !strings.HasPrefix(server.URL, "turn:") &&
@ -708,18 +767,25 @@ func (conf *Conf) Validate(l logger.Writer) error {
return fmt.Errorf("invalid ICE server: '%s'", server.URL) return fmt.Errorf("invalid ICE server: '%s'", server.URL)
} }
} }
if conf.WebRTCLocalUDPAddress == "" && if conf.WebRTCLocalUDPAddress == "" &&
conf.WebRTCLocalTCPAddress == "" && conf.WebRTCLocalTCPAddress == "" &&
len(conf.WebRTCICEServers2) == 0 { len(conf.WebRTCICEServers2) == 0 {
return fmt.Errorf("at least one between 'webrtcLocalUDPAddress'," + return fmt.Errorf("at least one between 'webrtcLocalUDPAddress'," +
" 'webrtcLocalTCPAddress' or 'webrtcICEServers2' must be filled") " 'webrtcLocalTCPAddress' or 'webrtcICEServers2' must be filled")
} }
if conf.WebRTCLocalUDPAddress != "" || conf.WebRTCLocalTCPAddress != "" { if conf.WebRTCLocalUDPAddress != "" || conf.WebRTCLocalTCPAddress != "" {
if !conf.WebRTCIPsFromInterfaces && len(conf.WebRTCAdditionalHosts) == 0 { if !conf.WebRTCIPsFromInterfaces && len(conf.WebRTCAdditionalHosts) == 0 {
return fmt.Errorf("at least one between 'webrtcIPsFromInterfaces' or 'webrtcAdditionalHosts' must be filled") return fmt.Errorf("at least one between 'webrtcIPsFromInterfaces' or 'webrtcAdditionalHosts' must be filled")
} }
} }
if conf.WebRTCAllowOrigin != nil {
l.Log(logger.Warn, "parameter 'webrtcAllowOrigin' is deprecated and has been replaced with 'webrtcAllowOrigins'")
conf.WebRTCAllowOrigins = []string{*conf.WebRTCAllowOrigin}
}
// Record (deprecated) // Record (deprecated)
if conf.Record != nil { if conf.Record != nil {
@ -727,26 +793,31 @@ func (conf *Conf) Validate(l logger.Writer) error {
"and has been replaced with 'pathDefaults.record'") "and has been replaced with 'pathDefaults.record'")
conf.PathDefaults.Record = *conf.Record conf.PathDefaults.Record = *conf.Record
} }
if conf.RecordPath != nil { if conf.RecordPath != nil {
l.Log(logger.Warn, "parameter 'recordPath' is deprecated "+ l.Log(logger.Warn, "parameter 'recordPath' is deprecated "+
"and has been replaced with 'pathDefaults.recordPath'") "and has been replaced with 'pathDefaults.recordPath'")
conf.PathDefaults.RecordPath = *conf.RecordPath conf.PathDefaults.RecordPath = *conf.RecordPath
} }
if conf.RecordFormat != nil { if conf.RecordFormat != nil {
l.Log(logger.Warn, "parameter 'recordFormat' is deprecated "+ l.Log(logger.Warn, "parameter 'recordFormat' is deprecated "+
"and has been replaced with 'pathDefaults.recordFormat'") "and has been replaced with 'pathDefaults.recordFormat'")
conf.PathDefaults.RecordFormat = *conf.RecordFormat conf.PathDefaults.RecordFormat = *conf.RecordFormat
} }
if conf.RecordPartDuration != nil { if conf.RecordPartDuration != nil {
l.Log(logger.Warn, "parameter 'recordPartDuration' is deprecated "+ l.Log(logger.Warn, "parameter 'recordPartDuration' is deprecated "+
"and has been replaced with 'pathDefaults.recordPartDuration'") "and has been replaced with 'pathDefaults.recordPartDuration'")
conf.PathDefaults.RecordPartDuration = *conf.RecordPartDuration conf.PathDefaults.RecordPartDuration = *conf.RecordPartDuration
} }
if conf.RecordSegmentDuration != nil { if conf.RecordSegmentDuration != nil {
l.Log(logger.Warn, "parameter 'recordSegmentDuration' is deprecated "+ l.Log(logger.Warn, "parameter 'recordSegmentDuration' is deprecated "+
"and has been replaced with 'pathDefaults.recordSegmentDuration'") "and has been replaced with 'pathDefaults.recordSegmentDuration'")
conf.PathDefaults.RecordSegmentDuration = *conf.RecordSegmentDuration conf.PathDefaults.RecordSegmentDuration = *conf.RecordSegmentDuration
} }
if conf.RecordDeleteAfter != nil { if conf.RecordDeleteAfter != nil {
l.Log(logger.Warn, "parameter 'recordDeleteAfter' is deprecated "+ l.Log(logger.Warn, "parameter 'recordDeleteAfter' is deprecated "+
"and has been replaced with 'pathDefaults.recordDeleteAfter'") "and has been replaced with 'pathDefaults.recordDeleteAfter'")

View file

@ -10,6 +10,7 @@ import (
"path/filepath" "path/filepath"
"reflect" "reflect"
"runtime" "runtime"
"slices"
"strings" "strings"
"syscall" "syscall"
"time" "time"
@ -323,7 +324,7 @@ func (p *Core) createResources(initial bool) error {
Encryption: p.conf.MetricsEncryption, Encryption: p.conf.MetricsEncryption,
ServerKey: p.conf.MetricsServerKey, ServerKey: p.conf.MetricsServerKey,
ServerCert: p.conf.MetricsServerCert, ServerCert: p.conf.MetricsServerCert,
AllowOrigin: p.conf.MetricsAllowOrigin, AllowOrigins: p.conf.MetricsAllowOrigins,
TrustedProxies: p.conf.MetricsTrustedProxies, TrustedProxies: p.conf.MetricsTrustedProxies,
ReadTimeout: p.conf.ReadTimeout, ReadTimeout: p.conf.ReadTimeout,
WriteTimeout: p.conf.WriteTimeout, WriteTimeout: p.conf.WriteTimeout,
@ -344,7 +345,7 @@ func (p *Core) createResources(initial bool) error {
Encryption: p.conf.PPROFEncryption, Encryption: p.conf.PPROFEncryption,
ServerKey: p.conf.PPROFServerKey, ServerKey: p.conf.PPROFServerKey,
ServerCert: p.conf.PPROFServerCert, ServerCert: p.conf.PPROFServerCert,
AllowOrigin: p.conf.PPROFAllowOrigin, AllowOrigins: p.conf.PPROFAllowOrigins,
TrustedProxies: p.conf.PPROFTrustedProxies, TrustedProxies: p.conf.PPROFTrustedProxies,
ReadTimeout: p.conf.ReadTimeout, ReadTimeout: p.conf.ReadTimeout,
WriteTimeout: p.conf.WriteTimeout, WriteTimeout: p.conf.WriteTimeout,
@ -374,7 +375,7 @@ func (p *Core) createResources(initial bool) error {
Encryption: p.conf.PlaybackEncryption, Encryption: p.conf.PlaybackEncryption,
ServerKey: p.conf.PlaybackServerKey, ServerKey: p.conf.PlaybackServerKey,
ServerCert: p.conf.PlaybackServerCert, ServerCert: p.conf.PlaybackServerCert,
AllowOrigin: p.conf.PlaybackAllowOrigin, AllowOrigins: p.conf.PlaybackAllowOrigins,
TrustedProxies: p.conf.PlaybackTrustedProxies, TrustedProxies: p.conf.PlaybackTrustedProxies,
ReadTimeout: p.conf.ReadTimeout, ReadTimeout: p.conf.ReadTimeout,
WriteTimeout: p.conf.WriteTimeout, WriteTimeout: p.conf.WriteTimeout,
@ -562,7 +563,7 @@ func (p *Core) createResources(initial bool) error {
Encryption: p.conf.HLSEncryption, Encryption: p.conf.HLSEncryption,
ServerKey: p.conf.HLSServerKey, ServerKey: p.conf.HLSServerKey,
ServerCert: p.conf.HLSServerCert, ServerCert: p.conf.HLSServerCert,
AllowOrigin: p.conf.HLSAllowOrigin, AllowOrigins: p.conf.HLSAllowOrigins,
TrustedProxies: p.conf.HLSTrustedProxies, TrustedProxies: p.conf.HLSTrustedProxies,
AlwaysRemux: p.conf.HLSAlwaysRemux, AlwaysRemux: p.conf.HLSAlwaysRemux,
Variant: p.conf.HLSVariant, Variant: p.conf.HLSVariant,
@ -592,7 +593,7 @@ func (p *Core) createResources(initial bool) error {
Encryption: p.conf.WebRTCEncryption, Encryption: p.conf.WebRTCEncryption,
ServerKey: p.conf.WebRTCServerKey, ServerKey: p.conf.WebRTCServerKey,
ServerCert: p.conf.WebRTCServerCert, ServerCert: p.conf.WebRTCServerCert,
AllowOrigin: p.conf.WebRTCAllowOrigin, AllowOrigins: p.conf.WebRTCAllowOrigins,
TrustedProxies: p.conf.WebRTCTrustedProxies, TrustedProxies: p.conf.WebRTCTrustedProxies,
ReadTimeout: p.conf.ReadTimeout, ReadTimeout: p.conf.ReadTimeout,
WriteTimeout: p.conf.WriteTimeout, WriteTimeout: p.conf.WriteTimeout,
@ -650,7 +651,7 @@ func (p *Core) createResources(initial bool) error {
Encryption: p.conf.APIEncryption, Encryption: p.conf.APIEncryption,
ServerKey: p.conf.APIServerKey, ServerKey: p.conf.APIServerKey,
ServerCert: p.conf.APIServerCert, ServerCert: p.conf.APIServerCert,
AllowOrigin: p.conf.APIAllowOrigin, AllowOrigins: p.conf.APIAllowOrigins,
TrustedProxies: p.conf.APITrustedProxies, TrustedProxies: p.conf.APITrustedProxies,
ReadTimeout: p.conf.ReadTimeout, ReadTimeout: p.conf.ReadTimeout,
WriteTimeout: p.conf.WriteTimeout, WriteTimeout: p.conf.WriteTimeout,
@ -712,7 +713,7 @@ func (p *Core) closeResources(newConf *conf.Conf, calledByAPI bool) {
newConf.MetricsEncryption != p.conf.MetricsEncryption || newConf.MetricsEncryption != p.conf.MetricsEncryption ||
newConf.MetricsServerKey != p.conf.MetricsServerKey || newConf.MetricsServerKey != p.conf.MetricsServerKey ||
newConf.MetricsServerCert != p.conf.MetricsServerCert || newConf.MetricsServerCert != p.conf.MetricsServerCert ||
newConf.MetricsAllowOrigin != p.conf.MetricsAllowOrigin || !slices.Equal(newConf.MetricsAllowOrigins, p.conf.MetricsAllowOrigins) ||
!reflect.DeepEqual(newConf.MetricsTrustedProxies, p.conf.MetricsTrustedProxies) || !reflect.DeepEqual(newConf.MetricsTrustedProxies, p.conf.MetricsTrustedProxies) ||
newConf.ReadTimeout != p.conf.ReadTimeout || newConf.ReadTimeout != p.conf.ReadTimeout ||
newConf.WriteTimeout != p.conf.WriteTimeout || newConf.WriteTimeout != p.conf.WriteTimeout ||
@ -725,7 +726,7 @@ func (p *Core) closeResources(newConf *conf.Conf, calledByAPI bool) {
newConf.PPROFEncryption != p.conf.PPROFEncryption || newConf.PPROFEncryption != p.conf.PPROFEncryption ||
newConf.PPROFServerKey != p.conf.PPROFServerKey || newConf.PPROFServerKey != p.conf.PPROFServerKey ||
newConf.PPROFServerCert != p.conf.PPROFServerCert || newConf.PPROFServerCert != p.conf.PPROFServerCert ||
newConf.PPROFAllowOrigin != p.conf.PPROFAllowOrigin || !slices.Equal(newConf.PPROFAllowOrigins, p.conf.PPROFAllowOrigins) ||
!reflect.DeepEqual(newConf.PPROFTrustedProxies, p.conf.PPROFTrustedProxies) || !reflect.DeepEqual(newConf.PPROFTrustedProxies, p.conf.PPROFTrustedProxies) ||
newConf.ReadTimeout != p.conf.ReadTimeout || newConf.ReadTimeout != p.conf.ReadTimeout ||
newConf.WriteTimeout != p.conf.WriteTimeout || newConf.WriteTimeout != p.conf.WriteTimeout ||
@ -745,7 +746,7 @@ func (p *Core) closeResources(newConf *conf.Conf, calledByAPI bool) {
newConf.PlaybackEncryption != p.conf.PlaybackEncryption || newConf.PlaybackEncryption != p.conf.PlaybackEncryption ||
newConf.PlaybackServerKey != p.conf.PlaybackServerKey || newConf.PlaybackServerKey != p.conf.PlaybackServerKey ||
newConf.PlaybackServerCert != p.conf.PlaybackServerCert || newConf.PlaybackServerCert != p.conf.PlaybackServerCert ||
newConf.PlaybackAllowOrigin != p.conf.PlaybackAllowOrigin || !slices.Equal(newConf.PlaybackAllowOrigins, p.conf.PlaybackAllowOrigins) ||
!reflect.DeepEqual(newConf.PlaybackTrustedProxies, p.conf.PlaybackTrustedProxies) || !reflect.DeepEqual(newConf.PlaybackTrustedProxies, p.conf.PlaybackTrustedProxies) ||
newConf.ReadTimeout != p.conf.ReadTimeout || newConf.ReadTimeout != p.conf.ReadTimeout ||
newConf.WriteTimeout != p.conf.WriteTimeout || newConf.WriteTimeout != p.conf.WriteTimeout ||
@ -852,7 +853,7 @@ func (p *Core) closeResources(newConf *conf.Conf, calledByAPI bool) {
newConf.HLSEncryption != p.conf.HLSEncryption || newConf.HLSEncryption != p.conf.HLSEncryption ||
newConf.HLSServerKey != p.conf.HLSServerKey || newConf.HLSServerKey != p.conf.HLSServerKey ||
newConf.HLSServerCert != p.conf.HLSServerCert || newConf.HLSServerCert != p.conf.HLSServerCert ||
newConf.HLSAllowOrigin != p.conf.HLSAllowOrigin || !slices.Equal(newConf.HLSAllowOrigins, p.conf.HLSAllowOrigins) ||
!reflect.DeepEqual(newConf.HLSTrustedProxies, p.conf.HLSTrustedProxies) || !reflect.DeepEqual(newConf.HLSTrustedProxies, p.conf.HLSTrustedProxies) ||
newConf.HLSAlwaysRemux != p.conf.HLSAlwaysRemux || newConf.HLSAlwaysRemux != p.conf.HLSAlwaysRemux ||
newConf.HLSVariant != p.conf.HLSVariant || newConf.HLSVariant != p.conf.HLSVariant ||
@ -874,7 +875,7 @@ func (p *Core) closeResources(newConf *conf.Conf, calledByAPI bool) {
newConf.WebRTCEncryption != p.conf.WebRTCEncryption || newConf.WebRTCEncryption != p.conf.WebRTCEncryption ||
newConf.WebRTCServerKey != p.conf.WebRTCServerKey || newConf.WebRTCServerKey != p.conf.WebRTCServerKey ||
newConf.WebRTCServerCert != p.conf.WebRTCServerCert || newConf.WebRTCServerCert != p.conf.WebRTCServerCert ||
newConf.WebRTCAllowOrigin != p.conf.WebRTCAllowOrigin || !slices.Equal(newConf.WebRTCAllowOrigins, p.conf.WebRTCAllowOrigins) ||
!reflect.DeepEqual(newConf.WebRTCTrustedProxies, p.conf.WebRTCTrustedProxies) || !reflect.DeepEqual(newConf.WebRTCTrustedProxies, p.conf.WebRTCTrustedProxies) ||
newConf.ReadTimeout != p.conf.ReadTimeout || newConf.ReadTimeout != p.conf.ReadTimeout ||
newConf.WriteTimeout != p.conf.WriteTimeout || newConf.WriteTimeout != p.conf.WriteTimeout ||
@ -911,7 +912,7 @@ func (p *Core) closeResources(newConf *conf.Conf, calledByAPI bool) {
newConf.APIEncryption != p.conf.APIEncryption || newConf.APIEncryption != p.conf.APIEncryption ||
newConf.APIServerKey != p.conf.APIServerKey || newConf.APIServerKey != p.conf.APIServerKey ||
newConf.APIServerCert != p.conf.APIServerCert || newConf.APIServerCert != p.conf.APIServerCert ||
newConf.APIAllowOrigin != p.conf.APIAllowOrigin || !slices.Equal(newConf.APIAllowOrigins, p.conf.APIAllowOrigins) ||
!reflect.DeepEqual(newConf.APITrustedProxies, p.conf.APITrustedProxies) || !reflect.DeepEqual(newConf.APITrustedProxies, p.conf.APITrustedProxies) ||
newConf.ReadTimeout != p.conf.ReadTimeout || newConf.ReadTimeout != p.conf.ReadTimeout ||
newConf.WriteTimeout != p.conf.WriteTimeout || newConf.WriteTimeout != p.conf.WriteTimeout ||

View file

@ -74,7 +74,7 @@ type Metrics struct {
Encryption bool Encryption bool
ServerKey string ServerKey string
ServerCert string ServerCert string
AllowOrigin string AllowOrigins []string
TrustedProxies conf.IPNetworks TrustedProxies conf.IPNetworks
ReadTimeout conf.Duration ReadTimeout conf.Duration
WriteTimeout conf.Duration WriteTimeout conf.Duration
@ -98,13 +98,14 @@ func (m *Metrics) Initialize() error {
router := gin.New() router := gin.New()
router.SetTrustedProxies(m.TrustedProxies.ToTrustedProxies()) //nolint:errcheck router.SetTrustedProxies(m.TrustedProxies.ToTrustedProxies()) //nolint:errcheck
router.Use(m.middlewareOrigin) router.Use(m.middlewarePreflightRequests)
router.Use(m.middlewareAuth) router.Use(m.middlewareAuth)
router.GET("/metrics", m.onMetrics) router.GET("/metrics", m.onMetrics)
m.httpServer = &httpp.Server{ m.httpServer = &httpp.Server{
Address: m.Address, Address: m.Address,
AllowOrigins: m.AllowOrigins,
ReadTimeout: time.Duration(m.ReadTimeout), ReadTimeout: time.Duration(m.ReadTimeout),
WriteTimeout: time.Duration(m.WriteTimeout), WriteTimeout: time.Duration(m.WriteTimeout),
Encryption: m.Encryption, Encryption: m.Encryption,
@ -134,11 +135,7 @@ func (m *Metrics) Log(level logger.Level, format string, args ...any) {
m.Parent.Log(level, "[metrics] "+format, args...) m.Parent.Log(level, "[metrics] "+format, args...)
} }
func (m *Metrics) middlewareOrigin(ctx *gin.Context) { func (m *Metrics) middlewarePreflightRequests(ctx *gin.Context) {
ctx.Header("Access-Control-Allow-Origin", m.AllowOrigin)
ctx.Header("Access-Control-Allow-Credentials", "true")
// preflight requests
if ctx.Request.Method == http.MethodOptions && if ctx.Request.Method == http.MethodOptions &&
ctx.Request.Header.Get("Access-Control-Request-Method") != "" { ctx.Request.Header.Get("Access-Control-Request-Method") != "" {
ctx.Header("Access-Control-Allow-Methods", "OPTIONS, GET") ctx.Header("Access-Control-Allow-Methods", "OPTIONS, GET")

View file

@ -192,7 +192,7 @@ func (dummyWebRTCServer) APISessionsKick(uuid.UUID) error {
func TestPreflightRequest(t *testing.T) { func TestPreflightRequest(t *testing.T) {
m := Metrics{ m := Metrics{
Address: "localhost:9998", Address: "localhost:9998",
AllowOrigin: "*", AllowOrigins: []string{"*"},
ReadTimeout: conf.Duration(10 * time.Second), ReadTimeout: conf.Duration(10 * time.Second),
WriteTimeout: conf.Duration(10 * time.Second), WriteTimeout: conf.Duration(10 * time.Second),
AuthManager: test.NilAuthManager, AuthManager: test.NilAuthManager,
@ -232,7 +232,7 @@ func TestMetrics(t *testing.T) {
m := Metrics{ m := Metrics{
Address: "localhost:9998", Address: "localhost:9998",
AllowOrigin: "*", AllowOrigins: []string{"*"},
ReadTimeout: conf.Duration(10 * time.Second), ReadTimeout: conf.Duration(10 * time.Second),
WriteTimeout: conf.Duration(10 * time.Second), WriteTimeout: conf.Duration(10 * time.Second),
AuthManager: &test.AuthManager{ AuthManager: &test.AuthManager{
@ -368,7 +368,7 @@ func TestAuthError(t *testing.T) {
m := Metrics{ m := Metrics{
Address: "localhost:9998", Address: "localhost:9998",
AllowOrigin: "*", AllowOrigins: []string{"*"},
ReadTimeout: conf.Duration(10 * time.Second), ReadTimeout: conf.Duration(10 * time.Second),
WriteTimeout: conf.Duration(10 * time.Second), WriteTimeout: conf.Duration(10 * time.Second),
AuthManager: &test.AuthManager{ AuthManager: &test.AuthManager{
@ -428,7 +428,7 @@ func TestFilter(t *testing.T) {
t.Run(ca, func(t *testing.T) { t.Run(ca, func(t *testing.T) {
m := Metrics{ m := Metrics{
Address: "localhost:9998", Address: "localhost:9998",
AllowOrigin: "*", AllowOrigins: []string{"*"},
ReadTimeout: conf.Duration(10 * time.Second), ReadTimeout: conf.Duration(10 * time.Second),
WriteTimeout: conf.Duration(10 * time.Second), WriteTimeout: conf.Duration(10 * time.Second),
AuthManager: test.NilAuthManager, AuthManager: test.NilAuthManager,

View file

@ -24,7 +24,7 @@ type Server struct {
Encryption bool Encryption bool
ServerKey string ServerKey string
ServerCert string ServerCert string
AllowOrigin string AllowOrigins []string
TrustedProxies conf.IPNetworks TrustedProxies conf.IPNetworks
ReadTimeout conf.Duration ReadTimeout conf.Duration
WriteTimeout conf.Duration WriteTimeout conf.Duration
@ -41,13 +41,14 @@ func (s *Server) Initialize() error {
router := gin.New() router := gin.New()
router.SetTrustedProxies(s.TrustedProxies.ToTrustedProxies()) //nolint:errcheck router.SetTrustedProxies(s.TrustedProxies.ToTrustedProxies()) //nolint:errcheck
router.Use(s.middlewareOrigin) router.Use(s.middlewarePreflightRequests)
router.GET("/list", s.onList) router.GET("/list", s.onList)
router.GET("/get", s.onGet) router.GET("/get", s.onGet)
s.httpServer = &httpp.Server{ s.httpServer = &httpp.Server{
Address: s.Address, Address: s.Address,
AllowOrigins: s.AllowOrigins,
ReadTimeout: time.Duration(s.ReadTimeout), ReadTimeout: time.Duration(s.ReadTimeout),
WriteTimeout: time.Duration(s.WriteTimeout), WriteTimeout: time.Duration(s.WriteTimeout),
Encryption: s.Encryption, Encryption: s.Encryption,
@ -100,11 +101,7 @@ func (s *Server) safeFindPathConf(name string) (*conf.Path, error) {
return pathConf, err return pathConf, err
} }
func (s *Server) middlewareOrigin(ctx *gin.Context) { func (s *Server) middlewarePreflightRequests(ctx *gin.Context) {
ctx.Header("Access-Control-Allow-Origin", s.AllowOrigin)
ctx.Header("Access-Control-Allow-Credentials", "true")
// preflight requests
if ctx.Request.Method == http.MethodOptions && if ctx.Request.Method == http.MethodOptions &&
ctx.Request.Header.Get("Access-Control-Request-Method") != "" { ctx.Request.Header.Get("Access-Control-Request-Method") != "" {
ctx.Header("Access-Control-Allow-Methods", "OPTIONS, GET") ctx.Header("Access-Control-Allow-Methods", "OPTIONS, GET")

View file

@ -18,7 +18,7 @@ import (
func TestPreflightRequest(t *testing.T) { func TestPreflightRequest(t *testing.T) {
s := &Server{ s := &Server{
Address: "127.0.0.1:9996", Address: "127.0.0.1:9996",
AllowOrigin: "*", AllowOrigins: []string{"*"},
ReadTimeout: conf.Duration(10 * time.Second), ReadTimeout: conf.Duration(10 * time.Second),
WriteTimeout: conf.Duration(10 * time.Second), WriteTimeout: conf.Duration(10 * time.Second),
Parent: test.NilLogger, Parent: test.NilLogger,

View file

@ -29,7 +29,7 @@ type PPROF struct {
Encryption bool Encryption bool
ServerKey string ServerKey string
ServerCert string ServerCert string
AllowOrigin string AllowOrigins []string
TrustedProxies conf.IPNetworks TrustedProxies conf.IPNetworks
ReadTimeout conf.Duration ReadTimeout conf.Duration
WriteTimeout conf.Duration WriteTimeout conf.Duration
@ -44,13 +44,14 @@ func (pp *PPROF) Initialize() error {
router := gin.New() router := gin.New()
router.SetTrustedProxies(pp.TrustedProxies.ToTrustedProxies()) //nolint:errcheck router.SetTrustedProxies(pp.TrustedProxies.ToTrustedProxies()) //nolint:errcheck
router.Use(pp.middlewareOrigin) router.Use(pp.middlewarePreflightRequests)
router.Use(pp.middlewareAuth) router.Use(pp.middlewareAuth)
pprof.Register(router) pprof.Register(router)
pp.httpServer = &httpp.Server{ pp.httpServer = &httpp.Server{
Address: pp.Address, Address: pp.Address,
AllowOrigins: pp.AllowOrigins,
ReadTimeout: time.Duration(pp.ReadTimeout), ReadTimeout: time.Duration(pp.ReadTimeout),
WriteTimeout: time.Duration(pp.WriteTimeout), WriteTimeout: time.Duration(pp.WriteTimeout),
Encryption: pp.Encryption, Encryption: pp.Encryption,
@ -80,11 +81,7 @@ func (pp *PPROF) Log(level logger.Level, format string, args ...any) {
pp.Parent.Log(level, "[pprof] "+format, args...) pp.Parent.Log(level, "[pprof] "+format, args...)
} }
func (pp *PPROF) middlewareOrigin(ctx *gin.Context) { func (pp *PPROF) middlewarePreflightRequests(ctx *gin.Context) {
ctx.Header("Access-Control-Allow-Origin", pp.AllowOrigin)
ctx.Header("Access-Control-Allow-Credentials", "true")
// preflight requests
if ctx.Request.Method == http.MethodOptions && if ctx.Request.Method == http.MethodOptions &&
ctx.Request.Header.Get("Access-Control-Request-Method") != "" { ctx.Request.Header.Get("Access-Control-Request-Method") != "" {
ctx.Header("Access-Control-Allow-Methods", "OPTIONS, GET") ctx.Header("Access-Control-Allow-Methods", "OPTIONS, GET")

View file

@ -17,7 +17,7 @@ import (
func TestPreflightRequest(t *testing.T) { func TestPreflightRequest(t *testing.T) {
s := &PPROF{ s := &PPROF{
Address: "127.0.0.1:9999", Address: "127.0.0.1:9999",
AllowOrigin: "*", AllowOrigins: []string{"*"},
ReadTimeout: conf.Duration(10 * time.Second), ReadTimeout: conf.Duration(10 * time.Second),
WriteTimeout: conf.Duration(10 * time.Second), WriteTimeout: conf.Duration(10 * time.Second),
Parent: test.NilLogger, Parent: test.NilLogger,
@ -56,7 +56,7 @@ func TestPprof(t *testing.T) {
s := &PPROF{ s := &PPROF{
Address: "127.0.0.1:9999", Address: "127.0.0.1:9999",
AllowOrigin: "*", AllowOrigins: []string{"*"},
ReadTimeout: conf.Duration(10 * time.Second), ReadTimeout: conf.Duration(10 * time.Second),
WriteTimeout: conf.Duration(10 * time.Second), WriteTimeout: conf.Duration(10 * time.Second),
AuthManager: &test.AuthManager{ AuthManager: &test.AuthManager{
@ -99,7 +99,7 @@ func TestAuthError(t *testing.T) {
s := &PPROF{ s := &PPROF{
Address: "127.0.0.1:9999", Address: "127.0.0.1:9999",
AllowOrigin: "*", AllowOrigins: []string{"*"},
ReadTimeout: conf.Duration(10 * time.Second), ReadTimeout: conf.Duration(10 * time.Second),
WriteTimeout: conf.Duration(10 * time.Second), WriteTimeout: conf.Duration(10 * time.Second),
AuthManager: &test.AuthManager{ AuthManager: &test.AuthManager{

View file

@ -0,0 +1,42 @@
package httpp
import (
"net"
"net/http"
"strings"
"testing"
"time"
"github.com/bluenviron/mediamtx/internal/test"
"github.com/stretchr/testify/require"
)
func TestHandlerFilterRequests(t *testing.T) {
s := &Server{
Address: "localhost:4555",
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
Parent: test.NilLogger,
Handler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusOK)
}),
}
err := s.Initialize()
require.NoError(t, err)
defer s.Close()
conn, err := net.Dial("tcp", "localhost:4555")
require.NoError(t, err)
defer conn.Close()
_, err = conn.Write([]byte("OPTIONS / HTTP/1.1\n" +
"Host: localhost:8889\n\n"))
require.NoError(t, err)
buf := make([]byte, 200)
n, err := conn.Read(buf)
require.NoError(t, err)
res := strings.Split(string(buf[:n]), "\r\n")
require.Equal(t, "HTTP/1.1 200 OK", res[0])
}

View file

@ -0,0 +1,88 @@
package httpp
import (
"net"
"net/http"
"net/url"
"regexp"
"strings"
)
func isOriginAllowed(origin string, allowOrigins []string) (string, bool) {
if len(allowOrigins) == 0 {
return "", false
}
for _, o := range allowOrigins {
if o == "*" {
return o, true
}
}
if origin == "" {
return "", false
}
originURL, err := url.Parse(origin)
if err != nil || originURL.Scheme == "" {
return "", false
}
if originURL.Port() == "" && originURL.Scheme != "" {
switch originURL.Scheme {
case "http":
originURL.Host = net.JoinHostPort(originURL.Host, "80")
case "https":
originURL.Host = net.JoinHostPort(originURL.Host, "443")
}
}
for _, o := range allowOrigins {
allowedURL, errAllowed := url.Parse(o)
if errAllowed != nil {
continue
}
if allowedURL.Port() == "" {
switch allowedURL.Scheme {
case "http":
allowedURL.Host = net.JoinHostPort(allowedURL.Host, "80")
case "https":
allowedURL.Host = net.JoinHostPort(allowedURL.Host, "443")
}
}
if allowedURL.Scheme == originURL.Scheme &&
allowedURL.Host == originURL.Host &&
allowedURL.Port() == originURL.Port() {
return origin, true
}
if strings.Contains(allowedURL.Host, "*") {
pattern := strings.ReplaceAll(allowedURL.Host, "*.", "(.*\\.)?")
pattern = strings.ReplaceAll(pattern, "*", ".*")
matched, errMatched := regexp.MatchString("^"+pattern+"$", originURL.Host)
if errMatched == nil && matched {
return origin, true
}
}
}
return "", false
}
// add Access-Control-Allow-Origin and Access-Control-Allow-Credentials headers.
type handlerOrigin struct {
h http.Handler
allowOrigins []string
}
func (h *handlerOrigin) ServeHTTP(w http.ResponseWriter, r *http.Request) {
origin, ok := isOriginAllowed(r.Header.Get("Origin"), h.allowOrigins)
if ok {
w.Header().Set("Access-Control-Allow-Origin", origin)
w.Header().Set("Access-Control-Allow-Credentials", "true")
}
h.h.ServeHTTP(w, r)
}

View file

@ -0,0 +1,87 @@
package httpp
import (
"net/http"
"testing"
"time"
"github.com/bluenviron/mediamtx/internal/test"
"github.com/stretchr/testify/require"
)
func TestHandlerOrigin(t *testing.T) {
for _, ca := range []struct {
name string
origin string
allowedOrigins []string
expected string
}{
{
"empty",
"",
[]string{},
"",
},
{
"not allowed",
"http://another.com",
[]string{"http://example.com"},
"",
},
{
"everything allowed, no origin",
"",
[]string{"*"},
"*",
},
{
"everything allowed, with origin",
"https://example.com",
[]string{"*"},
"*",
},
{
"allowed",
"https://example.org",
[]string{"http://example.com", "https://example.org"},
"https://example.org",
},
{
"wildcard",
"https://test.example.org",
[]string{"https://*.example.org"},
"https://test.example.org",
},
} {
t.Run(ca.name, func(t *testing.T) {
s := &Server{
Address: "localhost:4555",
AllowOrigins: ca.allowedOrigins,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
Parent: test.NilLogger,
Handler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusOK)
}),
}
err := s.Initialize()
require.NoError(t, err)
defer s.Close()
tr := &http.Transport{}
defer tr.CloseIdleConnections()
hc := &http.Client{Transport: tr}
req, err := http.NewRequest(http.MethodGet, "http://localhost:4555", nil)
require.NoError(t, err)
req.Header.Set("Origin", ca.origin)
res, err := hc.Do(req)
require.NoError(t, err)
defer res.Body.Close()
require.Equal(t, ca.expected, res.Header.Get("Access-Control-Allow-Origin"))
})
}
}

View file

@ -32,6 +32,7 @@ func (nilWriter) Write(p []byte) (int, error) {
// - filtering of invalid requests // - filtering of invalid requests
type Server struct { type Server struct {
Address string Address string
AllowOrigins []string
ReadTimeout time.Duration ReadTimeout time.Duration
WriteTimeout time.Duration WriteTimeout time.Duration
Encryption bool Encryption bool
@ -100,8 +101,9 @@ func (s *Server) Initialize() error {
} }
h := s.Handler h := s.Handler
h = &handlerFilterRequests{h} h = &handlerOrigin{h, s.AllowOrigins}
h = &handlerServerHeader{h} h = &handlerServerHeader{h}
h = &handlerFilterRequests{h}
h = &handlerLogger{h, s.Parent} h = &handlerLogger{h, s.Parent}
h = &handlerExitOnPanic{h} h = &handlerExitOnPanic{h}
h = &handlerWriteTimeout{h, s.WriteTimeout} h = &handlerWriteTimeout{h, s.WriteTimeout}

View file

@ -13,36 +13,6 @@ import (
"github.com/bluenviron/mediamtx/internal/test" "github.com/bluenviron/mediamtx/internal/test"
) )
func TestFilterEmptyPath(t *testing.T) {
s := &Server{
Address: "localhost:4555",
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
Parent: test.NilLogger,
Handler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusOK)
}),
}
err := s.Initialize()
require.NoError(t, err)
defer s.Close()
conn, err := net.Dial("tcp", "localhost:4555")
require.NoError(t, err)
defer conn.Close()
_, err = conn.Write([]byte("OPTIONS / HTTP/1.1\n" +
"Host: localhost:8889\n\n"))
require.NoError(t, err)
buf := make([]byte, 200)
n, err := conn.Read(buf)
require.NoError(t, err)
res := strings.Split(string(buf[:n]), "\r\n")
require.Equal(t, "HTTP/1.1 200 OK", res[0])
}
func TestUnixSocket(t *testing.T) { func TestUnixSocket(t *testing.T) {
s := &Server{ s := &Server{
Address: "unix://http.sock", Address: "unix://http.sock",

View file

@ -39,7 +39,7 @@ type httpServer struct {
encryption bool encryption bool
serverKey string serverKey string
serverCert string serverCert string
allowOrigin string allowOrigins []string
trustedProxies conf.IPNetworks trustedProxies conf.IPNetworks
readTimeout conf.Duration readTimeout conf.Duration
writeTimeout conf.Duration writeTimeout conf.Duration
@ -53,12 +53,13 @@ func (s *httpServer) initialize() error {
router := gin.New() router := gin.New()
router.SetTrustedProxies(s.trustedProxies.ToTrustedProxies()) //nolint:errcheck router.SetTrustedProxies(s.trustedProxies.ToTrustedProxies()) //nolint:errcheck
router.Use(s.middlewareOrigin) router.Use(s.middlewarePreflightRequests)
router.Use(s.onRequest) router.Use(s.onRequest)
s.inner = &httpp.Server{ s.inner = &httpp.Server{
Address: s.address, Address: s.address,
AllowOrigins: s.allowOrigins,
ReadTimeout: time.Duration(s.readTimeout), ReadTimeout: time.Duration(s.readTimeout),
WriteTimeout: time.Duration(s.writeTimeout), WriteTimeout: time.Duration(s.writeTimeout),
Encryption: s.encryption, Encryption: s.encryption,
@ -84,11 +85,7 @@ func (s *httpServer) close() {
s.inner.Close() s.inner.Close()
} }
func (s *httpServer) middlewareOrigin(ctx *gin.Context) { func (s *httpServer) middlewarePreflightRequests(ctx *gin.Context) {
ctx.Header("Access-Control-Allow-Origin", s.allowOrigin)
ctx.Header("Access-Control-Allow-Credentials", "true")
// preflight requests
if ctx.Request.Method == http.MethodOptions && if ctx.Request.Method == http.MethodOptions &&
ctx.Request.Header.Get("Access-Control-Request-Method") != "" { ctx.Request.Header.Get("Access-Control-Request-Method") != "" {
ctx.Header("Access-Control-Allow-Methods", "OPTIONS, GET") ctx.Header("Access-Control-Allow-Methods", "OPTIONS, GET")

View file

@ -74,7 +74,7 @@ type Server struct {
Encryption bool Encryption bool
ServerKey string ServerKey string
ServerCert string ServerCert string
AllowOrigin string AllowOrigins []string
TrustedProxies conf.IPNetworks TrustedProxies conf.IPNetworks
AlwaysRemux bool AlwaysRemux bool
Variant conf.HLSVariant Variant conf.HLSVariant
@ -124,7 +124,7 @@ func (s *Server) Initialize() error {
encryption: s.Encryption, encryption: s.Encryption,
serverKey: s.ServerKey, serverKey: s.ServerKey,
serverCert: s.ServerCert, serverCert: s.ServerCert,
allowOrigin: s.AllowOrigin, allowOrigins: s.AllowOrigins,
trustedProxies: s.TrustedProxies, trustedProxies: s.TrustedProxies,
readTimeout: s.ReadTimeout, readTimeout: s.ReadTimeout,
writeTimeout: s.WriteTimeout, writeTimeout: s.WriteTimeout,

View file

@ -68,7 +68,7 @@ func (pa *dummyPath) RemoveReader(_ defs.PathRemoveReaderReq) {
func TestServerPreflightRequest(t *testing.T) { func TestServerPreflightRequest(t *testing.T) {
s := &Server{ s := &Server{
Address: "127.0.0.1:8888", Address: "127.0.0.1:8888",
AllowOrigin: "*", AllowOrigins: []string{"*"},
ReadTimeout: conf.Duration(10 * time.Second), ReadTimeout: conf.Duration(10 * time.Second),
WriteTimeout: conf.Duration(10 * time.Second), WriteTimeout: conf.Duration(10 * time.Second),
PathManager: &dummyPathManager{}, PathManager: &dummyPathManager{},
@ -131,7 +131,6 @@ func TestServerNotFound(t *testing.T) {
SegmentDuration: conf.Duration(1 * time.Second), SegmentDuration: conf.Duration(1 * time.Second),
PartDuration: conf.Duration(200 * time.Millisecond), PartDuration: conf.Duration(200 * time.Millisecond),
SegmentMaxSize: 50 * 1024 * 1024, SegmentMaxSize: 50 * 1024 * 1024,
AllowOrigin: "",
TrustedProxies: conf.IPNetworks{}, TrustedProxies: conf.IPNetworks{},
Directory: "", Directory: "",
ReadTimeout: conf.Duration(10 * time.Second), ReadTimeout: conf.Duration(10 * time.Second),
@ -433,7 +432,6 @@ func TestServerDirectory(t *testing.T) {
SegmentDuration: conf.Duration(1 * time.Second), SegmentDuration: conf.Duration(1 * time.Second),
PartDuration: conf.Duration(200 * time.Millisecond), PartDuration: conf.Duration(200 * time.Millisecond),
SegmentMaxSize: 50 * 1024 * 1024, SegmentMaxSize: 50 * 1024 * 1024,
AllowOrigin: "",
TrustedProxies: conf.IPNetworks{}, TrustedProxies: conf.IPNetworks{},
Directory: filepath.Join(dir, "mydir"), Directory: filepath.Join(dir, "mydir"),
ReadTimeout: conf.Duration(10 * time.Second), ReadTimeout: conf.Duration(10 * time.Second),

View file

@ -76,7 +76,7 @@ type httpServer struct {
encryption bool encryption bool
serverKey string serverKey string
serverCert string serverCert string
allowOrigin string allowOrigins []string
trustedProxies conf.IPNetworks trustedProxies conf.IPNetworks
readTimeout conf.Duration readTimeout conf.Duration
writeTimeout conf.Duration writeTimeout conf.Duration
@ -90,12 +90,13 @@ func (s *httpServer) initialize() error {
router := gin.New() router := gin.New()
router.SetTrustedProxies(s.trustedProxies.ToTrustedProxies()) //nolint:errcheck router.SetTrustedProxies(s.trustedProxies.ToTrustedProxies()) //nolint:errcheck
router.Use(s.middlewareOrigin) router.Use(s.middlewarePreflightRequests)
router.Use(s.onRequest) router.Use(s.onRequest)
s.inner = &httpp.Server{ s.inner = &httpp.Server{
Address: s.address, Address: s.address,
AllowOrigins: s.allowOrigins,
ReadTimeout: time.Duration(s.readTimeout), ReadTimeout: time.Duration(s.readTimeout),
WriteTimeout: time.Duration(s.writeTimeout), WriteTimeout: time.Duration(s.writeTimeout),
Encryption: s.encryption, Encryption: s.encryption,
@ -319,11 +320,7 @@ func (s *httpServer) onPage(ctx *gin.Context, pathName string, publish bool) {
} }
} }
func (s *httpServer) middlewareOrigin(ctx *gin.Context) { func (s *httpServer) middlewarePreflightRequests(ctx *gin.Context) {
ctx.Header("Access-Control-Allow-Origin", s.allowOrigin)
ctx.Header("Access-Control-Allow-Credentials", "true")
// preflight requests
if ctx.Request.Method == http.MethodOptions && if ctx.Request.Method == http.MethodOptions &&
ctx.Request.Header.Get("Access-Control-Request-Method") != "" { ctx.Request.Header.Get("Access-Control-Request-Method") != "" {
ctx.Header("Access-Control-Allow-Methods", "OPTIONS, GET, POST, PATCH, DELETE") ctx.Header("Access-Control-Allow-Methods", "OPTIONS, GET, POST, PATCH, DELETE")

View file

@ -190,7 +190,7 @@ type Server struct {
Encryption bool Encryption bool
ServerKey string ServerKey string
ServerCert string ServerCert string
AllowOrigin string AllowOrigins []string
TrustedProxies conf.IPNetworks TrustedProxies conf.IPNetworks
ReadTimeout conf.Duration ReadTimeout conf.Duration
WriteTimeout conf.Duration WriteTimeout conf.Duration
@ -254,7 +254,7 @@ func (s *Server) Initialize() error {
encryption: s.Encryption, encryption: s.Encryption,
serverKey: s.ServerKey, serverKey: s.ServerKey,
serverCert: s.ServerCert, serverCert: s.ServerCert,
allowOrigin: s.AllowOrigin, allowOrigins: s.AllowOrigins,
trustedProxies: s.TrustedProxies, trustedProxies: s.TrustedProxies,
readTimeout: s.ReadTimeout, readTimeout: s.ReadTimeout,
writeTimeout: s.WriteTimeout, writeTimeout: s.WriteTimeout,

View file

@ -66,7 +66,7 @@ func initializeTestServer(t *testing.T) *Server {
s := &Server{ s := &Server{
Address: "127.0.0.1:8886", Address: "127.0.0.1:8886",
AllowOrigin: "*", AllowOrigins: []string{"*"},
TrustedProxies: conf.IPNetworks{}, TrustedProxies: conf.IPNetworks{},
ReadTimeout: conf.Duration(10 * time.Second), ReadTimeout: conf.Duration(10 * time.Second),
WriteTimeout: conf.Duration(10 * time.Second), WriteTimeout: conf.Duration(10 * time.Second),

View file

@ -158,8 +158,9 @@ apiEncryption: no
apiServerKey: server.key apiServerKey: server.key
# Path to the server certificate. # Path to the server certificate.
apiServerCert: server.crt apiServerCert: server.crt
# Value of the Access-Control-Allow-Origin header provided in every HTTP response. # List of allowed CORS origins.
apiAllowOrigin: '*' # Supports wildcards: ['http://*.example.com']
apiAllowOrigins: ['*']
# List of IPs or CIDRs of proxies placed before the HTTP server. # List of IPs or CIDRs of proxies placed before the HTTP server.
# If the server receives a request from one of these entries, IP in logs # If the server receives a request from one of these entries, IP in logs
# will be taken from the X-Forwarded-For header. # will be taken from the X-Forwarded-For header.
@ -181,8 +182,9 @@ metricsEncryption: no
metricsServerKey: server.key metricsServerKey: server.key
# Path to the server certificate. # Path to the server certificate.
metricsServerCert: server.crt metricsServerCert: server.crt
# Value of the Access-Control-Allow-Origin header provided in every HTTP response. # List of allowed CORS origins.
metricsAllowOrigin: '*' # Supports wildcards: ['http://*.example.com']
metricsAllowOrigins: ['*']
# List of IPs or CIDRs of proxies placed before the HTTP server. # List of IPs or CIDRs of proxies placed before the HTTP server.
# If the server receives a request from one of these entries, IP in logs # If the server receives a request from one of these entries, IP in logs
# will be taken from the X-Forwarded-For header. # will be taken from the X-Forwarded-For header.
@ -204,8 +206,9 @@ pprofEncryption: no
pprofServerKey: server.key pprofServerKey: server.key
# Path to the server certificate. # Path to the server certificate.
pprofServerCert: server.crt pprofServerCert: server.crt
# Value of the Access-Control-Allow-Origin header provided in every HTTP response. # List of allowed CORS origins.
pprofAllowOrigin: '*' # Supports wildcards: ['http://*.example.com']
pprofAllowOrigins: ['*']
# List of IPs or CIDRs of proxies placed before the HTTP server. # List of IPs or CIDRs of proxies placed before the HTTP server.
# If the server receives a request from one of these entries, IP in logs # If the server receives a request from one of these entries, IP in logs
# will be taken from the X-Forwarded-For header. # will be taken from the X-Forwarded-For header.
@ -227,8 +230,9 @@ playbackEncryption: no
playbackServerKey: server.key playbackServerKey: server.key
# Path to the server certificate. # Path to the server certificate.
playbackServerCert: server.crt playbackServerCert: server.crt
# Value of the Access-Control-Allow-Origin header provided in every HTTP response. # List of allowed CORS origins.
playbackAllowOrigin: '*' # Supports wildcards: ['http://*.example.com']
playbackAllowOrigins: ['*']
# List of IPs or CIDRs of proxies placed before the HTTP server. # List of IPs or CIDRs of proxies placed before the HTTP server.
# If the server receives a request from one of these entries, IP in logs # If the server receives a request from one of these entries, IP in logs
# will be taken from the X-Forwarded-For header. # will be taken from the X-Forwarded-For header.
@ -319,9 +323,9 @@ hlsEncryption: no
hlsServerKey: server.key hlsServerKey: server.key
# Path to the server certificate. # Path to the server certificate.
hlsServerCert: server.crt hlsServerCert: server.crt
# Value of the Access-Control-Allow-Origin header provided in every HTTP response. # List of allowed CORS origins.
# This allows to play the HLS stream from an external website. # Supports wildcards: ['http://*.example.com']
hlsAllowOrigin: '*' hlsAllowOrigins: ['*']
# List of IPs or CIDRs of proxies placed before the HLS server. # List of IPs or CIDRs of proxies placed before the HLS server.
# If the server receives a request from one of these entries, IP in logs # If the server receives a request from one of these entries, IP in logs
# will be taken from the X-Forwarded-For header. # will be taken from the X-Forwarded-For header.
@ -377,9 +381,9 @@ webrtcEncryption: no
webrtcServerKey: server.key webrtcServerKey: server.key
# Path to the server certificate. # Path to the server certificate.
webrtcServerCert: server.crt webrtcServerCert: server.crt
# Value of the Access-Control-Allow-Origin header provided in every HTTP response. # List of allowed CORS origins.
# This allows to play the WebRTC stream from an external website. # Supports wildcards: ['http://*.example.com']
webrtcAllowOrigin: '*' webrtcAllowOrigins: ['*']
# List of IPs or CIDRs of proxies placed before the WebRTC server. # List of IPs or CIDRs of proxies placed before the WebRTC server.
# If the server receives a request from one of these entries, IP in logs # If the server receives a request from one of these entries, IP in logs
# will be taken from the X-Forwarded-For header. # will be taken from the X-Forwarded-For header.